18
18
#include " ConstantBuilder.h"
19
19
#include " Explosion.h"
20
20
#include " GenClass.h"
21
+ #include " GenDecl.h"
21
22
#include " GenMeta.h"
23
+ #include " GenProto.h"
22
24
#include " GenStruct.h"
23
25
#include " GenericRequirement.h"
24
26
#include " IRGenDebugInfo.h"
27
29
#include " ProtocolInfo.h"
28
30
#include " StructLayout.h"
29
31
#include " llvm/ADT/SetVector.h"
32
+ #include " llvm/IR/Module.h"
30
33
#include " swift/SIL/SILInstruction.h"
31
34
#include " swift/SIL/SILLocation.h"
32
35
#include " swift/SIL/TypeLowering.h"
37
40
#include " swift/AST/DiagnosticsIRGen.h"
38
41
#include " swift/AST/GenericEnvironment.h"
39
42
#include " swift/AST/Types.h"
43
+ #include " swift/IRGen/Linking.h"
40
44
41
45
using namespace swift ;
42
46
using namespace irgen ;
43
47
48
+ enum GetterOrSetter {
49
+ Getter,
50
+ Setter,
51
+ };
52
+
53
+ static llvm::Function *
54
+ getAccessorForComputedComponent (IRGenModule &IGM,
55
+ const KeyPathPatternComponent &component,
56
+ GetterOrSetter whichAccessor,
57
+ GenericEnvironment *genericEnv,
58
+ ArrayRef<GenericRequirement> requirements) {
59
+ SILFunction *accessor;
60
+ switch (whichAccessor) {
61
+ case Getter:
62
+ accessor = component.getComputedPropertyGetter ();
63
+ break ;
64
+ case Setter:
65
+ accessor = component.getComputedPropertySetter ();
66
+ break ;
67
+ }
68
+
69
+ auto accessorFn = IGM.getAddrOfSILFunction (accessor, NotForDefinition);
70
+
71
+ // If the accessor is not generic, we can use it as is.
72
+ if (requirements.empty ()) {
73
+ return accessorFn;
74
+ }
75
+
76
+ auto accessorFnTy = accessorFn->getType ()->getPointerElementType ();
77
+
78
+ // Otherwise, we need a thunk to unmarshal the generic environment from the
79
+ // argument area. It'd be nice to have a good way to represent this
80
+ // directly in SIL, of course...
81
+ auto thunkType = llvm::FunctionType::get (
82
+ IGM.VoidTy ,
83
+ { /* sret or newValue*/ accessorFnTy->getFunctionParamType (0 ),
84
+ /* base*/ accessorFnTy->getFunctionParamType (1 ),
85
+ /* arg*/ IGM.Int8PtrTy },
86
+ /* vararg*/ false );
87
+ const char *thunkName;
88
+ unsigned numArgsToForward = 2 ;
89
+ switch (whichAccessor) {
90
+ case Getter:
91
+ thunkName = " keypath_get" ;
92
+ break ;
93
+ case Setter:
94
+ thunkName = " keypath_set" ;
95
+ break ;
96
+ }
97
+
98
+ auto accessorThunk = llvm::Function::Create (thunkType,
99
+ llvm::GlobalValue::PrivateLinkage, thunkName, IGM.getModule ());
100
+ accessorThunk->setAttributes (IGM.constructInitialAttributes ());
101
+ // Original accessor's args should be @in or @out, meaning they won't be
102
+ // captured or aliased.
103
+ accessorThunk->addAttribute (1 , llvm::Attribute::NoCapture);
104
+ accessorThunk->addAttribute (1 , llvm::Attribute::NoAlias);
105
+ accessorThunk->addAttribute (2 , llvm::Attribute::NoCapture);
106
+ accessorThunk->addAttribute (2 , llvm::Attribute::NoAlias);
107
+ // Getter's output is sret.
108
+ if (whichAccessor == Getter)
109
+ accessorThunk->addAttribute (1 , llvm::Attribute::StructRet);
110
+ accessorThunk->setCallingConv (IGM.SwiftCC );
111
+
112
+ {
113
+ IRGenFunction IGF (IGM, accessorThunk);
114
+ if (IGM.DebugInfo )
115
+ IGM.DebugInfo ->emitArtificialFunction (IGF, accessorThunk);
116
+
117
+ auto params = IGF.collectParameters ();
118
+ Explosion forwardedArgs;
119
+ forwardedArgs.add (params.claim (numArgsToForward));
120
+
121
+ // The generic environment is marshaled into the beginning of the component
122
+ // argument area inside the instance. Bind the generic information out of
123
+ // the buffer, and advance past it.
124
+ auto componentArgsBuf = params.claimNext ();
125
+ bindFromGenericRequirementsBuffer (IGF, requirements,
126
+ Address (componentArgsBuf, IGM.getPointerAlignment ()),
127
+ [&](CanType t) {
128
+ if (!genericEnv)
129
+ return t;
130
+ return genericEnv->mapTypeIntoContext (t)->getCanonicalType ();
131
+ });
132
+
133
+ /* TODO: If the underlying accessor wants index arguments, advance the
134
+ * pointer past the generic requirements here to pass down. */
135
+
136
+ // Use the bound generic metadata to form a call to the original generic
137
+ // accessor.
138
+ WitnessMetadata witnessMetadata;
139
+ auto forwardingSubs = genericEnv->getGenericSignature ()->getSubstitutionMap (
140
+ genericEnv->getForwardingSubstitutions ());
141
+ emitPolymorphicArguments (IGF, accessor->getLoweredFunctionType (),
142
+ forwardingSubs,
143
+ &witnessMetadata,
144
+ forwardedArgs);
145
+ auto call = IGF.Builder .CreateCall (accessorFn, forwardedArgs.claimAll ());
146
+ if (whichAccessor == Getter)
147
+ call->addAttribute (1 , llvm::Attribute::StructRet);
148
+
149
+ IGF.Builder .CreateRetVoid ();
150
+ }
151
+
152
+ return accessorThunk;
153
+ }
154
+
155
+ static llvm::Constant *
156
+ getLayoutFunctionForComputedComponent (IRGenModule &IGM,
157
+ const KeyPathPatternComponent &component,
158
+ GenericEnvironment *genericEnv,
159
+ ArrayRef<GenericRequirement> requirements) {
160
+ // Generate a function that returns the expected size and alignment necessary
161
+ // to store captured generic context and subscript index arguments.
162
+ auto retTy = llvm::StructType::get (IGM.getLLVMContext (),
163
+ {IGM.SizeTy , IGM.SizeTy });
164
+ auto fnTy = llvm::FunctionType::get (
165
+ retTy, { IGM.Int8PtrTy }, /* vararg*/ false );
166
+
167
+ auto layoutFn = llvm::Function::Create (fnTy,
168
+ llvm::GlobalValue::PrivateLinkage, " keypath_get_arg_layout" , IGM.getModule ());
169
+
170
+ {
171
+ IRGenFunction IGF (IGM, layoutFn);
172
+ // TODO: We would need to unmarshal generic arguments to be able to
173
+ // compute the layout of dependent subscript indexes.
174
+ (void )IGF.collectParameters ().claimNext ();
175
+
176
+ // Base size is one pointer for each generic requirement; base alignment
177
+ // is pointer alignment.
178
+ llvm::Value *size = llvm::ConstantInt::get (IGM.SizeTy ,
179
+ IGM.getPointerSize ().getValue () * requirements.size ());
180
+ llvm::Value *alignMask = llvm::ConstantInt::get (IGM.SizeTy ,
181
+ IGM.getPointerAlignment ().getValue () - 1 );
182
+
183
+ // TODO: Combine layout of captured index values
184
+
185
+ llvm::Value *retValue = IGF.Builder .CreateInsertValue (
186
+ llvm::UndefValue::get (retTy), size, 0 );
187
+ retValue = IGF.Builder .CreateInsertValue (
188
+ retValue, alignMask, 1 );
189
+
190
+ IGF.Builder .CreateRet (retValue);
191
+ }
192
+
193
+ return layoutFn;
194
+ }
195
+
196
+ static llvm::Constant *
197
+ getWitnessTableForComputedComponent (IRGenModule &IGM,
198
+ const KeyPathPatternComponent &component,
199
+ GenericEnvironment *genericEnv,
200
+ ArrayRef<GenericRequirement> requirements) {
201
+ // If the only thing we're capturing is generic environment, then we can
202
+ // use a prefab witness table from the runtime.
203
+ // TODO: If there were subscript indexes, we'd need to generate something.
204
+ if (auto existing =
205
+ IGM.Module .getNamedGlobal (" swift_keyPathGenericWitnessTable" ))
206
+ return existing;
207
+
208
+ auto linkInfo = LinkInfo::get (IGM, " swift_keyPathGenericWitnessTable" ,
209
+ SILLinkage::PublicExternal,
210
+ /* fragile*/ false ,
211
+ /* sil only*/ false ,
212
+ NotForDefinition,
213
+ /* weak imported*/ false );
214
+
215
+ return createVariable (IGM, linkInfo,
216
+ IGM.Int8PtrTy , IGM.getPointerAlignment ());
217
+ }
218
+
219
+ static llvm::Constant *
220
+ getInitializerForComputedComponent (IRGenModule &IGM,
221
+ const KeyPathPatternComponent &component,
222
+ GenericEnvironment *genericEnv,
223
+ ArrayRef<GenericRequirement> requirements) {
224
+ auto fnTy = llvm::FunctionType::get (IGM.VoidTy ,
225
+ { /* src*/ IGM.Int8PtrTy ,
226
+ /* dest*/ IGM.Int8PtrTy }, /* vararg*/ false );
227
+
228
+ auto initFn = llvm::Function::Create (fnTy,
229
+ llvm::GlobalValue::PrivateLinkage, " keypath_arg_init" , IGM.getModule ());
230
+
231
+ {
232
+ IRGenFunction IGF (IGM, initFn);
233
+ auto params = IGF.collectParameters ();
234
+ auto src = params.claimNext ();
235
+ auto dest = params.claimNext ();
236
+
237
+ // Transfer all of the requirements into the destination instance.
238
+ IGF.Builder .CreateMemCpy (dest, src,
239
+ IGM.getPointerSize ().getValue () * requirements.size (),
240
+ IGM.getPointerAlignment ().getValue ());
241
+
242
+ // TODO: Copy over subscript index values.
243
+
244
+ IGF.Builder .CreateRetVoid ();
245
+ }
246
+ return initFn;
247
+ }
248
+
44
249
llvm::Constant *
45
250
IRGenModule::getAddrOfKeyPathPattern (KeyPathPattern *pattern,
46
251
SILLocation diagLoc) {
@@ -365,7 +570,8 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern,
365
570
fields.add (idValue);
366
571
367
572
if (isInstantiableInPlace) {
368
- // No generic arguments, so we can invoke the getter/setter as is.
573
+ // No generic arguments or indexes, so we can invoke the
574
+ // getter/setter as is.
369
575
fields.add (getAddrOfSILFunction (component.getComputedPropertyGetter (),
370
576
NotForDefinition));
371
577
if (settable)
@@ -375,10 +581,31 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern,
375
581
// If there's generic context (TODO: or subscript indexes), embed as
376
582
// arguments in the component. Thunk the SIL-level accessors to give the
377
583
// runtime implementation a polymorphically-callable interface.
378
- Context.Diags .diagnose (diagLoc.getSourceLoc (),
379
- diag::not_implemented,
380
- " generic computed key paths" );
381
- return llvm::UndefValue::get (Int8PtrTy);
584
+
585
+ // Push the accessors, possibly thunked to marshal generic environment.
586
+ fields.add (getAccessorForComputedComponent (*this , component, Getter,
587
+ genericEnv, requirements));
588
+ if (settable)
589
+ fields.add (getAccessorForComputedComponent (*this , component, Setter,
590
+ genericEnv, requirements));
591
+
592
+ fields.add (getLayoutFunctionForComputedComponent (*this , component,
593
+ genericEnv, requirements));
594
+
595
+ // Set up a "witness table" for the component that handles copying,
596
+ // destroying, equating, and hashing the captured contents of the
597
+ // component.
598
+ // If there are only generic parameters, we can use a prefab witness
599
+ // table from the runtime.
600
+ // TODO: For subscripts we'd generate functions that dispatch out to
601
+ // the copy/destroy/equals/hash functionality of the subscript indexes.
602
+ fields.add (getWitnessTableForComputedComponent (*this , component,
603
+ genericEnv, requirements));
604
+
605
+ // Add an initializer function that copies generic arguments out of the
606
+ // pattern argument buffer into the instantiated object.
607
+ fields.add (getInitializerForComputedComponent (*this , component,
608
+ genericEnv, requirements));
382
609
}
383
610
break ;
384
611
}
0 commit comments