@@ -91,6 +91,80 @@ static void lowerAssignInstruction(SILBuilderWithScope &b, AssignInst *inst) {
9191 inst->eraseFromParent ();
9292}
9393
94+ // / Construct the argument list for the assign_by_wrapper initializer or setter.
95+ // /
96+ // / Usually this is only a single value and a single argument, but in case of
97+ // / a tuple, the initializer/setter expect the tuple elements as separate
98+ // / arguments. The purpose of this function is to recursively visit tuple
99+ // / elements and add them to the argument list \p arg.
100+ static void getAssignByWrapperArgsRecursively (SmallVectorImpl<SILValue> &args,
101+ SILValue src, unsigned &argIdx, const SILFunctionConventions &convention,
102+ SILBuilder &forProjections, SILBuilder &forCleanup) {
103+
104+ SILLocation loc = (*forProjections.getInsertionPoint ()).getLoc ();
105+ SILType srcTy = src->getType ();
106+ if (auto tupleTy = srcTy.getAs <TupleType>()) {
107+ // In case the source is a tuple, we have to destructure the tuple and pass
108+ // the tuple elements separately.
109+ if (srcTy.isAddress ()) {
110+ for (unsigned idx = 0 , n = tupleTy->getNumElements (); idx < n; ++idx) {
111+ auto *TEA = forProjections.createTupleElementAddr (loc, src, idx);
112+ getAssignByWrapperArgsRecursively (args, TEA, argIdx, convention,
113+ forProjections, forCleanup);
114+ }
115+ } else {
116+ auto *DTI = forProjections.createDestructureTuple (loc, src);
117+ for (SILValue elmt : DTI->getAllResults ()) {
118+ getAssignByWrapperArgsRecursively (args, elmt, argIdx, convention,
119+ forProjections, forCleanup);
120+ }
121+ }
122+ return ;
123+ }
124+ assert (argIdx < convention.getNumSILArguments () &&
125+ " initializer or setter has too few arguments" );
126+
127+ SILArgumentConvention argConv = convention.getSILArgumentConvention (argIdx);
128+ if (srcTy.isAddress () && !argConv.isIndirectConvention ()) {
129+ // In case of a tuple where one element is loadable, but the other is
130+ // address only, we get the whole tuple as address.
131+ // For the loadable element, the argument is passed directly, but the
132+ // tuple element is in memory. For this case we have to insert a load.
133+ src = forProjections.createTrivialLoadOr (loc, src,
134+ LoadOwnershipQualifier::Take);
135+ }
136+ switch (argConv) {
137+ case SILArgumentConvention::Indirect_In_Guaranteed:
138+ forCleanup.createDestroyAddr (loc, src);
139+ break ;
140+ case SILArgumentConvention::Direct_Guaranteed:
141+ forCleanup.createDestroyValue (loc, src);
142+ break ;
143+ case SILArgumentConvention::Direct_Unowned:
144+ case SILArgumentConvention::Indirect_In:
145+ case SILArgumentConvention::Indirect_In_Constant:
146+ case SILArgumentConvention::Direct_Owned:
147+ break ;
148+ case SILArgumentConvention::Indirect_Inout:
149+ case SILArgumentConvention::Indirect_InoutAliasable:
150+ case SILArgumentConvention::Indirect_Out:
151+ case SILArgumentConvention::Direct_Deallocating:
152+ llvm_unreachable (" wrong convention for setter/initializer src argument" );
153+ }
154+ args.push_back (src);
155+ ++argIdx;
156+ }
157+
158+ static void getAssignByWrapperArgs (SmallVectorImpl<SILValue> &args,
159+ SILValue src, const SILFunctionConventions &convention,
160+ SILBuilder &forProjections, SILBuilder &forCleanup) {
161+ unsigned argIdx = convention.getSILArgIndexOfFirstParam ();
162+ getAssignByWrapperArgsRecursively (args, src, argIdx, convention,
163+ forProjections, forCleanup);
164+ assert (argIdx == convention.getNumSILArguments () &&
165+ " initializer or setter has too many arguments" );
166+ }
167+
94168static void lowerAssignByWrapperInstruction (SILBuilderWithScope &b,
95169 AssignByWrapperInst *inst,
96170 SmallVectorImpl<BeginAccessInst *> &accessMarkers) {
@@ -103,21 +177,24 @@ static void lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
103177 SILValue src = inst->getSrc ();
104178 SILValue dest = inst->getDest ();
105179 SILLocation loc = inst->getLoc ();
106- SILArgumentConvention srcConvention (SILArgumentConvention::Indirect_Inout );
180+ SILBuilderWithScope forCleanup ( std::next (inst-> getIterator ()) );
107181
108182 switch (inst->getOwnershipQualifier ()) {
109183 case AssignOwnershipQualifier::Init: {
110184 SILValue initFn = inst->getInitializer ();
111185 CanSILFunctionType fTy = initFn->getType ().castTo <SILFunctionType>();
112186 SILFunctionConventions convention (fTy , inst->getModule ());
187+ SmallVector<SILValue, 4 > args;
113188 if (convention.hasIndirectSILResults ()) {
114- b.createApply (loc, initFn, SubstitutionMap (), { dest, src });
115- srcConvention = convention.getSILArgumentConvention (1 );
189+ args.push_back (dest);
190+ getAssignByWrapperArgs (args, src, convention, b, forCleanup);
191+ b.createApply (loc, initFn, SubstitutionMap (), args);
116192 } else {
193+ getAssignByWrapperArgs (args, src, convention, b, forCleanup);
117194 SILValue wrappedSrc = b.createApply (loc, initFn, SubstitutionMap (),
118- { src } );
119- b.createTrivialStoreOr (loc, wrappedSrc, dest, StoreOwnershipQualifier::Init);
120- srcConvention = convention. getSILArgumentConvention ( 0 );
195+ args );
196+ b.createTrivialStoreOr (loc, wrappedSrc, dest,
197+ StoreOwnershipQualifier::Init );
121198 }
122199 // TODO: remove the unused setter function, which usually is a dead
123200 // partial_apply.
@@ -129,8 +206,9 @@ static void lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
129206 CanSILFunctionType fTy = setterFn->getType ().castTo <SILFunctionType>();
130207 SILFunctionConventions convention (fTy , inst->getModule ());
131208 assert (!convention.hasIndirectSILResults ());
132- srcConvention = convention.getSILArgumentConvention (0 );
133- b.createApply (loc, setterFn, SubstitutionMap (), { src });
209+ SmallVector<SILValue, 4 > args;
210+ getAssignByWrapperArgs (args, src, convention, b, forCleanup);
211+ b.createApply (loc, setterFn, SubstitutionMap (), args);
134212
135213 // The destination address is not used. Remove it if it is a dead access
136214 // marker. This is important, because also the setter function contains
@@ -145,24 +223,6 @@ static void lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
145223 case AssignOwnershipQualifier::Reinit:
146224 llvm_unreachable (" wrong qualifier for assign_by_wrapper" );
147225 }
148- switch (srcConvention) {
149- case SILArgumentConvention::Indirect_In_Guaranteed:
150- b.createDestroyAddr (loc, src);
151- break ;
152- case SILArgumentConvention::Direct_Guaranteed:
153- b.createDestroyValue (loc, src);
154- break ;
155- case SILArgumentConvention::Direct_Unowned:
156- case SILArgumentConvention::Indirect_In:
157- case SILArgumentConvention::Indirect_In_Constant:
158- case SILArgumentConvention::Direct_Owned:
159- break ;
160- case SILArgumentConvention::Indirect_Inout:
161- case SILArgumentConvention::Indirect_InoutAliasable:
162- case SILArgumentConvention::Indirect_Out:
163- case SILArgumentConvention::Direct_Deallocating:
164- llvm_unreachable (" wrong convention for setter/initializer src argument" );
165- }
166226 inst->eraseFromParent ();
167227}
168228
0 commit comments