Mercurial > projects > ldc
comparison gen/nested.cpp @ 1209:8699c450a1a0
Implement -nested-ctx=hybrid
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Sun, 12 Apr 2009 20:23:00 +0200 |
parents | 2a37f4745ddd |
children | 3d4581761b4c |
comparison
equal
deleted
inserted
replaced
1208:2a37f4745ddd | 1209:8699c450a1a0 |
---|---|
20 /// a pointer to its context. (linked-list style) | 20 /// a pointer to its context. (linked-list style) |
21 // FIXME: implement | 21 // FIXME: implement |
22 // TODO: Functions without any variables accessed by nested functions, but | 22 // TODO: Functions without any variables accessed by nested functions, but |
23 // with a parent whose variables are accessed, can use the parent's | 23 // with a parent whose variables are accessed, can use the parent's |
24 // context. | 24 // context. |
25 // NOTE: This is what DMD seems to do. | |
25 NCStruct, | 26 NCStruct, |
26 | 27 |
27 /// Context is an array of pointers to nested contexts. Each function with variables | 28 /// Context is a list of pointers to structs. Each function with variables |
28 /// accessed by nested functions puts them in a struct, and appends a pointer to that | 29 /// accessed by nested functions puts them in a struct, and appends a |
29 /// struct to the array. | 30 /// pointer to that struct to it's local copy of the list. |
30 // FIXME: implement | |
31 NCHybrid | 31 NCHybrid |
32 }; | 32 }; |
33 | 33 |
34 static cl::opt<NestedCtxType> nestedCtx("nested-ctx", | 34 static cl::opt<NestedCtxType> nestedCtx("nested-ctx", |
35 cl::desc("How to construct a nested function's context:"), | 35 cl::desc("How to construct a nested function's context:"), |
36 cl::ZeroOrMore, | 36 cl::ZeroOrMore, |
37 cl::values( | 37 cl::values( |
38 clEnumValN(NCArray, "array", "Array of pointers to variables (including multi-level)"), | 38 clEnumValN(NCArray, "array", "Array of pointers to variables (including multi-level)"), |
39 //clEnumValN(NCStruct, "struct", "Struct of variables (with multi-level via linked list)"), | 39 //clEnumValN(NCStruct, "struct", "Struct of variables (with multi-level via linked list)"), |
40 //clEnumValN(NCHybrid, "hybrid", "Array of pointers to structs of variables"), | 40 clEnumValN(NCHybrid, "hybrid", "List of pointers to structs of variables, one per level."), |
41 clEnumValEnd), | 41 clEnumValEnd), |
42 cl::init(NCArray)); | 42 cl::init(NCHybrid)); |
43 | 43 |
44 | 44 |
45 /****************************************************************************************/ | 45 /****************************************************************************************/ |
46 /*//////////////////////////////////////////////////////////////////////////////////////// | 46 /*//////////////////////////////////////////////////////////////////////////////////////// |
47 // NESTED VARIABLE HELPERS | 47 // NESTED VARIABLE HELPERS |
48 ////////////////////////////////////////////////////////////////////////////////////////*/ | 48 ////////////////////////////////////////////////////////////////////////////////////////*/ |
49 | 49 |
50 static FuncDeclaration* getParentFunc(Dsymbol* sym) { | |
51 Dsymbol* parent = sym->parent; | |
52 assert(parent); | |
53 while (parent && !parent->isFuncDeclaration()) | |
54 parent = parent->parent; | |
55 | |
56 return (parent ? parent->isFuncDeclaration() : NULL); | |
57 } | |
58 | |
50 DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd) | 59 DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd) |
51 { | 60 { |
61 Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars()); | |
62 LOG_SCOPE; | |
63 | |
52 //////////////////////////////////// | 64 //////////////////////////////////// |
53 // Locate context value | 65 // Locate context value |
54 | 66 |
55 Dsymbol* vdparent = vd->toParent2(); | 67 Dsymbol* vdparent = vd->toParent2(); |
56 assert(vdparent); | 68 assert(vdparent); |
87 val = DtoLoad(val); | 99 val = DtoLoad(val); |
88 assert(vd->ir.irLocal->value); | 100 assert(vd->ir.irLocal->value); |
89 val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); | 101 val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); |
90 return new DVarValue(astype, vd, val); | 102 return new DVarValue(astype, vd, val); |
91 } | 103 } |
104 else if (nestedCtx == NCHybrid) { | |
105 FuncDeclaration *parentfunc = getParentFunc(vd); | |
106 assert(parentfunc && "No parent function for nested variable?"); | |
107 | |
108 LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(parentfunc->ir.irFunc->framesType)); | |
109 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); | |
110 val = DtoLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str()); | |
111 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); | |
112 if (vd->ir.irLocal->byref) | |
113 val = DtoLoad(val); | |
114 return new DVarValue(astype, vd, val); | |
115 } | |
92 else { | 116 else { |
93 assert(0 && "Not implemented yet"); | 117 assert(0 && "Not implemented yet"); |
94 } | 118 } |
95 } | 119 } |
96 | 120 |
97 void DtoNestedInit(VarDeclaration* vd) | 121 void DtoNestedInit(VarDeclaration* vd) |
98 { | 122 { |
123 Logger::println("DtoNestedInit for %s", vd->toChars()); | |
124 LOG_SCOPE | |
125 | |
126 LLValue* nestedVar = gIR->func()->decl->ir.irFunc->nestedVar; | |
127 | |
99 if (nestedCtx == NCArray) { | 128 if (nestedCtx == NCArray) { |
100 // alloca as usual if no value already | 129 // alloca as usual if no value already |
101 if (!vd->ir.irLocal->value) | 130 if (!vd->ir.irLocal->value) |
102 vd->ir.irLocal->value = DtoAlloca(DtoType(vd->type), vd->toChars()); | 131 vd->ir.irLocal->value = DtoAlloca(DtoType(vd->type), vd->toChars()); |
103 | 132 |
104 // store the address into the nested vars array | 133 // store the address into the nested vars array |
105 assert(vd->ir.irLocal->nestedIndex >= 0); | 134 assert(vd->ir.irLocal->nestedIndex >= 0); |
106 LLValue* gep = DtoGEPi(gIR->func()->decl->ir.irFunc->nestedVar, 0, vd->ir.irLocal->nestedIndex); | 135 LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex); |
107 | 136 |
108 assert(isaPointer(vd->ir.irLocal->value)); | 137 assert(isaPointer(vd->ir.irLocal->value)); |
109 LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); | 138 LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); |
110 | 139 |
111 DtoStore(val, gep); | 140 DtoStore(val, gep); |
141 } | |
142 else if (nestedCtx == NCHybrid) { | |
143 assert(vd->ir.irLocal->value && "Nested variable without storage?"); | |
144 if (!vd->isParameter() && (vd->isRef() || vd->isOut())) { | |
145 Logger::println("Initializing non-parameter byref value"); | |
146 LLValue* framep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedDepth); | |
147 | |
148 FuncDeclaration *parentfunc = getParentFunc(vd); | |
149 assert(parentfunc && "No parent function for nested variable?"); | |
150 LLValue* frame = DtoLoad(framep, (std::string(".frame.") + parentfunc->toChars()).c_str()); | |
151 | |
152 LLValue* slot = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex); | |
153 DtoStore(vd->ir.irLocal->value, slot); | |
154 } else { | |
155 // Already initialized in DtoCreateNestedContext | |
156 } | |
112 } | 157 } |
113 else { | 158 else { |
114 assert(0 && "Not implemented yet"); | 159 assert(0 && "Not implemented yet"); |
115 } | 160 } |
116 } | 161 } |
143 return getNullPtr(getVoidPtrType()); | 188 return getNullPtr(getVoidPtrType()); |
144 } | 189 } |
145 } | 190 } |
146 | 191 |
147 void DtoCreateNestedContext(FuncDeclaration* fd) { | 192 void DtoCreateNestedContext(FuncDeclaration* fd) { |
193 Logger::println("DtoCreateNestedContext for %s", fd->toChars()); | |
194 LOG_SCOPE | |
195 | |
148 if (nestedCtx == NCArray) { | 196 if (nestedCtx == NCArray) { |
149 // construct nested variables array | 197 // construct nested variables array |
150 if (!fd->nestedVars.empty()) | 198 if (!fd->nestedVars.empty()) |
151 { | 199 { |
152 Logger::println("has nested frame"); | 200 Logger::println("has nested frame"); |
226 Logger::println("nested var: %s", vd->toChars()); | 274 Logger::println("nested var: %s", vd->toChars()); |
227 } | 275 } |
228 | 276 |
229 vd->ir.irLocal->nestedIndex = idx++; | 277 vd->ir.irLocal->nestedIndex = idx++; |
230 } | 278 } |
231 | 279 } |
232 // fixup nested result variable | 280 } |
233 #if DMDV2 | 281 else if (nestedCtx == NCHybrid) { |
234 if (fd->vresult && fd->vresult->nestedrefs.dim) | 282 // construct nested variables array |
235 #else | 283 if (!fd->nestedVars.empty()) |
236 if (fd->vresult && fd->vresult->nestedref) | 284 { |
237 #endif | 285 Logger::println("has nested frame"); |
238 { | 286 // start with adding all enclosing parent frames until a static parent is reached |
239 Logger::println("nested vresult value: %s", fd->vresult->toChars()); | 287 typedef std::vector<const LLType*> TypeVec; |
240 LLValue* gep = DtoGEPi(nestedVars, 0, fd->vresult->ir.irLocal->nestedIndex); | 288 TypeVec frametypes; |
241 LLValue* val = DtoBitCast(fd->vresult->ir.irLocal->value, getVoidPtrType()); | 289 if (!fd->isStatic()) { |
242 DtoStore(val, gep); | 290 Dsymbol* par = fd->toParent2(); |
291 while (par) { | |
292 if (FuncDeclaration* parfd = par->isFuncDeclaration()) { | |
293 // skip functions without nested parameters | |
294 if (!parfd->nestedVars.empty()) { | |
295 // Copy the types of parent function frames. | |
296 const LLStructType* parft = parfd->ir.irFunc->framesType; | |
297 frametypes.insert(frametypes.begin(), parft->element_begin(), parft->element_end()); | |
298 break; // That's all the info needed. | |
299 } | |
300 } else if (ClassDeclaration* parcd = par->isClassDeclaration()) { | |
301 // skip | |
302 } else { | |
303 break; | |
304 } | |
305 par = par->toParent2(); | |
306 } | |
307 } | |
308 unsigned depth = frametypes.size(); | |
309 | |
310 // Construct a struct for the direct nested variables of this function, and update their indices to match. | |
311 // TODO: optimize ordering for minimal space usage? | |
312 TypeVec types; | |
313 for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) | |
314 { | |
315 VarDeclaration* vd = *i; | |
316 if (!vd->ir.irLocal) | |
317 vd->ir.irLocal = new IrLocal(vd); | |
318 | |
319 vd->ir.irLocal->nestedDepth = depth; | |
320 vd->ir.irLocal->nestedIndex = types.size(); | |
321 if (vd->isParameter()) { | |
322 // Parameters already have storage associated with them (to handle byref etc.), | |
323 // so handle specially for now by storing a pointer instead of a value. | |
324 assert(vd->ir.irLocal->value); | |
325 // FIXME: don't do this for normal parameters? | |
326 types.push_back(vd->ir.irLocal->value->getType()); | |
327 } else if (vd->isRef() || vd->isOut()) { | |
328 // Foreach variables can also be by reference, for instance. | |
329 types.push_back(DtoType(vd->type->pointerTo())); | |
330 } else { | |
331 types.push_back(DtoType(vd->type)); | |
332 } | |
333 if (Logger::enabled()) { | |
334 Logger::println("Nested var: %s", vd->toChars()); | |
335 Logger::cout() << "of type: " << *types.back() << '\n'; | |
336 } | |
337 } | |
338 // Append current frame type to frame type list | |
339 const LLType* frameType = LLStructType::get(types); | |
340 frametypes.push_back(LLPointerType::getUnqual(frameType)); | |
341 | |
342 // make struct type for nested frame list | |
343 const LLStructType* nestedVarsTy = LLStructType::get(frametypes); | |
344 | |
345 // Store type in IrFunction | |
346 IrFunction* irfunction = fd->ir.irFunc; | |
347 irfunction->framesType = nestedVarsTy; | |
348 | |
349 // alloca it | |
350 // FIXME: For D2, this should be a gc_malloc (or similar) call, not alloca | |
351 LLValue* nestedVars = DtoAlloca(nestedVarsTy, ".frame_list"); | |
352 | |
353 // copy parent frames into beginning | |
354 if (depth != 0) | |
355 { | |
356 LLValue* src = irfunction->nestArg; | |
357 if (!src) | |
358 { | |
359 assert(irfunction->thisArg); | |
360 assert(fd->isMember2()); | |
361 LLValue* thisval = DtoLoad(irfunction->thisArg); | |
362 ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); | |
363 assert(cd); | |
364 assert(cd->vthis); | |
365 Logger::println("Indexing to 'this'"); | |
366 src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); | |
367 } | |
368 src = DtoBitCast(src, getVoidPtrType()); | |
369 LLValue* dst = DtoBitCast(nestedVars, getVoidPtrType()); | |
370 DtoMemCpy(dst, src, DtoConstSize_t(depth * PTRSIZE)); | |
371 } | |
372 | |
373 // Create frame for current function and append to frames list | |
374 LLValue* frame = DtoAlloca(frameType, ".frame"); | |
375 // store current frame in list | |
376 DtoStore(frame, DtoGEPi(nestedVars, 0, depth)); | |
377 | |
378 // store context in IrFunction | |
379 irfunction->nestedVar = nestedVars; | |
380 | |
381 // go through all nested vars and assign addresses where possible. | |
382 for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) | |
383 { | |
384 VarDeclaration* vd = *i; | |
385 | |
386 LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); | |
387 if (vd->isParameter()) { | |
388 Logger::println("nested param: %s", vd->toChars()); | |
389 DtoStore(vd->ir.irLocal->value, gep); | |
390 vd->ir.irLocal->byref = true; | |
391 } else if (vd->isRef() || vd->isOut()) { | |
392 // This slot is initialized in DtoNestedInit, to handle things like byref foreach variables | |
393 // which move around in memory. | |
394 vd->ir.irLocal->byref = true; | |
395 } else { | |
396 Logger::println("nested var: %s", vd->toChars()); | |
397 if (vd->ir.irLocal->value) | |
398 Logger::cout() << "Pre-existing value: " << *vd->ir.irLocal->value << '\n'; | |
399 assert(!vd->ir.irLocal->value); | |
400 vd->ir.irLocal->value = gep; | |
401 vd->ir.irLocal->byref = false; | |
402 } | |
243 } | 403 } |
244 } | 404 } |
245 } | 405 } |
246 else { | 406 else { |
247 assert(0 && "Not implemented yet"); | 407 assert(0 && "Not implemented yet"); |