@@ -827,6 +827,53 @@ static CanType getSingleTupleElement(CanType type) {
827
827
}
828
828
829
829
namespace {
830
+ class TranslateIndirect : public Cleanup {
831
+ AbstractionPattern InputOrigType, OutputOrigType;
832
+ CanType InputSubstType, OutputSubstType;
833
+ SILValue Input, Output;
834
+
835
+ public:
836
+ TranslateIndirect (AbstractionPattern inputOrigType, CanType inputSubstType,
837
+ AbstractionPattern outputOrigType, CanType outputSubstType,
838
+ SILValue input, SILValue output)
839
+ : InputOrigType(inputOrigType), OutputOrigType(outputOrigType),
840
+ InputSubstType (inputSubstType), OutputSubstType(outputSubstType),
841
+ Input(input), Output(output) {
842
+ assert (input->getType ().isAddress ());
843
+ assert (output->getType ().isAddress ());
844
+ }
845
+
846
+ void emit (SILGenFunction &SGF, CleanupLocation loc,
847
+ ForUnwind_t forUnwind) override {
848
+ FullExpr scope (SGF.Cleanups , loc);
849
+
850
+ // Re-assert ownership of the input value.
851
+ auto inputMV = SGF.emitManagedBufferWithCleanup (Input);
852
+
853
+ // Set up an initialization of the output buffer.
854
+ auto &outputTL = SGF.getTypeLowering (Output->getType ());
855
+ auto outputInit = SGF.useBufferAsTemporary (Output, outputTL);
856
+
857
+ // Transform into the output buffer.
858
+ auto mv = SGF.emitTransformedValue (loc, inputMV,
859
+ InputOrigType, InputSubstType,
860
+ OutputOrigType, OutputSubstType,
861
+ SGFContext (outputInit.get ()));
862
+ emitForceInto (SGF, loc, mv, *outputInit);
863
+
864
+ // Disable the cleanup; we've kept our promise to leave the inout
865
+ // initialized.
866
+ outputInit->getManagedAddress ().forward (SGF);
867
+ }
868
+
869
+ void dump (SILGenFunction &SGF) const override {
870
+ llvm::errs () << " TranslateIndirect("
871
+ << InputOrigType << " , " << InputSubstType << " , "
872
+ << OutputOrigType << " , " << OutputSubstType << " , "
873
+ << Output << " , " << Input << " )\n " ;
874
+ }
875
+ };
876
+
830
877
class TranslateArguments {
831
878
SILGenFunction &SGF;
832
879
SILLocation Loc;
@@ -1356,13 +1403,49 @@ namespace {
1356
1403
outputSubstType, input);
1357
1404
return ;
1358
1405
case ParameterConvention::Indirect_Inout: {
1359
- // If it's inout, we need writeback.
1360
- llvm::errs () << " inout writeback in abstraction difference thunk "
1361
- " not yet implemented\n " ;
1362
- llvm::errs () << " input value " ;
1363
- input.getValue ()->dump ();
1364
- llvm::errs () << " output type " << SGF.getSILType (result) << " \n " ;
1365
- abort ();
1406
+ inputOrigType = inputOrigType.getWithoutSpecifierType ();
1407
+ inputSubstType = inputSubstType.getWithoutSpecifierType ();
1408
+ outputOrigType = outputOrigType.getWithoutSpecifierType ();
1409
+ outputSubstType = outputSubstType.getWithoutSpecifierType ();
1410
+
1411
+ // Create a temporary of the right type.
1412
+ auto &temporaryTL = SGF.getTypeLowering (result.getType ());
1413
+ auto temporary = SGF.emitTemporary (Loc, temporaryTL);
1414
+
1415
+ // Take ownership of the input value. This leaves the input l-value
1416
+ // effectively uninitialized, but we'll push a cleanup that will put
1417
+ // a value back into it.
1418
+ FullExpr scope (SGF.Cleanups , CleanupLocation::get (Loc));
1419
+ auto ownedInput =
1420
+ SGF.emitManagedBufferWithCleanup (input.getLValueAddress ());
1421
+
1422
+ // Translate the input value into the temporary.
1423
+ translateSingleInto (inputOrigType, inputSubstType,
1424
+ outputOrigType, outputSubstType,
1425
+ ownedInput, *temporary);
1426
+
1427
+ // Forward the cleanup on the temporary. We're about to push a new
1428
+ // cleanup that will re-assert ownership of this value.
1429
+ auto temporaryAddr = temporary->getManagedAddress ().forward (SGF);
1430
+
1431
+ // Leave the scope in which we did the forward translation. This
1432
+ // ensures that the value in the input buffer is destroyed
1433
+ // immediately rather than (potentially) arbitrarily later
1434
+ // at a point where we want to put new values in the input buffer.
1435
+ scope.pop ();
1436
+
1437
+ // Push the cleanup to perform the reverse translation. This cleanup
1438
+ // asserts ownership of the value of the temporary.
1439
+ SGF.Cleanups .pushCleanup <TranslateIndirect>(outputOrigType,
1440
+ outputSubstType,
1441
+ inputOrigType,
1442
+ inputSubstType,
1443
+ temporaryAddr,
1444
+ input.getLValueAddress ());
1445
+
1446
+ // Add the temporary as an l-value argument.
1447
+ Outputs.push_back (ManagedValue::forLValue (temporaryAddr));
1448
+ return ;
1366
1449
}
1367
1450
case ParameterConvention::Indirect_In: {
1368
1451
if (SGF.silConv .useLoweredAddresses ()) {
0 commit comments