Mercurial > projects > ldc
comparison gen/nested.cpp @ 1216:033f18ec1371
Unify %.frames_list and %.frame into a single data structure, generalizing r1212
to all frames instead of just the outer-most one.
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Wed, 15 Apr 2009 20:59:19 +0200 |
parents | 9430d4959ab4 |
children | 7977096f0e49 |
comparison
equal
deleted
inserted
replaced
1215:08f87d8cd101 | 1216:033f18ec1371 |
---|---|
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 // NOTE: This is what DMD seems to do. |
26 NCStruct, | 26 NCStruct, |
27 | 27 |
28 /// Context is a list of pointers to structs. Each function with variables | 28 /// Context is a list of pointers to structs of variables, followed by the |
29 /// accessed by nested functions puts them in a struct, and appends a | 29 /// variables of the inner-most function with variables accessed by nested |
30 /// pointer to that struct to it's local copy of the list. | 30 /// functions. The initial pointers point to similar structs for enclosing |
31 /// As an additional optimization, if the list has length one it's not | 31 /// functions. |
32 /// generated; the only element is used directly instead. | 32 /// Only functions whose variables are accessed by nested functions create |
33 /// new frames, others just pass on what got passed in. | |
33 NCHybrid | 34 NCHybrid |
34 }; | 35 }; |
35 | 36 |
36 static cl::opt<NestedCtxType> nestedCtx("nested-ctx", | 37 static cl::opt<NestedCtxType> nestedCtx("nested-ctx", |
37 cl::desc("How to construct a nested function's context:"), | 38 cl::desc("How to construct a nested function's context:"), |
47 /****************************************************************************************/ | 48 /****************************************************************************************/ |
48 /*//////////////////////////////////////////////////////////////////////////////////////// | 49 /*//////////////////////////////////////////////////////////////////////////////////////// |
49 // NESTED VARIABLE HELPERS | 50 // NESTED VARIABLE HELPERS |
50 ////////////////////////////////////////////////////////////////////////////////////////*/ | 51 ////////////////////////////////////////////////////////////////////////////////////////*/ |
51 | 52 |
52 static FuncDeclaration* getParentFunc(Dsymbol* sym) { | 53 static FuncDeclaration* getParentFunc(Dsymbol* sym, bool stopOnStatic) { |
53 if (!sym) | 54 if (!sym) |
54 return NULL; | 55 return NULL; |
55 Dsymbol* parent = sym->parent; | 56 Dsymbol* parent = sym->parent; |
56 assert(parent); | 57 assert(parent); |
57 while (parent && !parent->isFuncDeclaration()) | 58 while (parent && !parent->isFuncDeclaration()) { |
59 if (stopOnStatic) { | |
60 Declaration* decl = sym->isDeclaration(); | |
61 if (decl && decl->isStatic()) | |
62 return NULL; | |
63 } | |
58 parent = parent->parent; | 64 parent = parent->parent; |
65 } | |
59 | 66 |
60 return (parent ? parent->isFuncDeclaration() : NULL); | 67 return (parent ? parent->isFuncDeclaration() : NULL); |
61 } | 68 } |
62 | 69 |
63 DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd) | 70 DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd) |
86 { | 93 { |
87 ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration(); | 94 ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration(); |
88 LLValue* val = DtoLoad(irfunc->thisArg); | 95 LLValue* val = DtoLoad(irfunc->thisArg); |
89 ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis")); | 96 ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis")); |
90 } | 97 } |
98 else if (irfunc->nestedVar) | |
99 ctx = irfunc->nestedVar; | |
91 else | 100 else |
92 ctx = irfunc->nestArg; | 101 ctx = irfunc->nestArg; |
93 assert(ctx); | 102 assert(ctx); |
94 | 103 |
95 assert(vd->ir.irLocal); | 104 assert(vd->ir.irLocal); |
104 assert(vd->ir.irLocal->value); | 113 assert(vd->ir.irLocal->value); |
105 val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); | 114 val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); |
106 return new DVarValue(astype, vd, val); | 115 return new DVarValue(astype, vd, val); |
107 } | 116 } |
108 else if (nestedCtx == NCHybrid) { | 117 else if (nestedCtx == NCHybrid) { |
109 FuncDeclaration* parentfunc = getParentFunc(irfunc->decl); | 118 LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); |
110 assert(parentfunc && "No parent function for nested function?"); | |
111 Logger::println("Parent function: %s", parentfunc->toChars()); | |
112 | |
113 LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(parentfunc->ir.irFunc->framesType)); | |
114 Logger::cout() << "Context: " << *val << '\n'; | 119 Logger::cout() << "Context: " << *val << '\n'; |
115 | 120 Logger::cout() << "of type: " << *val->getType() << '\n'; |
116 if (!parentfunc->ir.irFunc->elidedCtxList) { | 121 |
122 unsigned vardepth = vd->ir.irLocal->nestedDepth; | |
123 unsigned funcdepth = irfunc->depth; | |
124 | |
125 Logger::cout() << "Variable: " << vd->toChars() << '\n'; | |
126 Logger::cout() << "Variable depth: " << vardepth << '\n'; | |
127 Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; | |
128 Logger::cout() << "Function depth: " << funcdepth << '\n'; | |
129 | |
130 if (vardepth == funcdepth) { | |
131 // This is not always handled above because functions without | |
132 // variables accessed by nested functions don't create new frames. | |
133 Logger::println("Same depth"); | |
134 } else { | |
135 // Load frame pointer and index that... | |
136 Logger::println("Lower depth"); | |
117 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); | 137 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); |
138 Logger::cout() << "Frame index: " << *val << '\n'; | |
118 val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); | 139 val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); |
140 Logger::cout() << "Frame: " << *val << '\n'; | |
119 } | 141 } |
120 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); | 142 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); |
121 if (vd->ir.irLocal->byref) | 143 Logger::cout() << "Addr: " << *val << '\n'; |
144 Logger::cout() << "of type: " << *val->getType() << '\n'; | |
145 if (vd->ir.irLocal->byref) { | |
122 val = DtoAlignedLoad(val); | 146 val = DtoAlignedLoad(val); |
147 Logger::cout() << "Was byref, now: " << *val << '\n'; | |
148 Logger::cout() << "of type: " << *val->getType() << '\n'; | |
149 } | |
150 | |
123 return new DVarValue(astype, vd, val); | 151 return new DVarValue(astype, vd, val); |
124 } | 152 } |
125 else { | 153 else { |
126 assert(0 && "Not implemented yet"); | 154 assert(0 && "Not implemented yet"); |
127 } | 155 } |
149 | 177 |
150 DtoAlignedStore(val, gep); | 178 DtoAlignedStore(val, gep); |
151 } | 179 } |
152 else if (nestedCtx == NCHybrid) { | 180 else if (nestedCtx == NCHybrid) { |
153 assert(vd->ir.irLocal->value && "Nested variable without storage?"); | 181 assert(vd->ir.irLocal->value && "Nested variable without storage?"); |
182 | |
154 if (!vd->isParameter() && (vd->isRef() || vd->isOut())) { | 183 if (!vd->isParameter() && (vd->isRef() || vd->isOut())) { |
155 Logger::println("Initializing non-parameter byref value"); | 184 unsigned vardepth = vd->ir.irLocal->nestedDepth; |
156 LLValue* frame; | 185 |
157 if (!irfunc->elidedCtxList) { | 186 LLValue* val = NULL; |
158 LLValue* framep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedDepth); | 187 // Retrieve frame pointer |
188 if (vardepth == irfunc->depth) { | |
189 val = nestedVar; | |
190 } else { | |
191 FuncDeclaration *parentfunc = getParentFunc(vd, true); | |
192 assert(parentfunc && "No parent function for nested variable?"); | |
159 | 193 |
160 FuncDeclaration *parentfunc = getParentFunc(vd); | 194 val = DtoGEPi(val, 0, vardepth); |
161 assert(parentfunc && "No parent function for nested variable?"); | 195 val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str()); |
162 frame = DtoAlignedLoad(framep, (std::string(".frame.") + parentfunc->toChars()).c_str()); | 196 } |
163 } else { | 197 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); |
164 frame = nestedVar; | 198 DtoAlignedStore(vd->ir.irLocal->value, val); |
165 } | |
166 LLValue* slot = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex); | |
167 DtoAlignedStore(vd->ir.irLocal->value, slot); | |
168 } else { | 199 } else { |
169 // Already initialized in DtoCreateNestedContext | 200 // Already initialized in DtoCreateNestedContext |
170 } | 201 } |
171 } | 202 } |
172 else { | 203 else { |
204 else | 235 else |
205 { | 236 { |
206 return getNullPtr(getVoidPtrType()); | 237 return getNullPtr(getVoidPtrType()); |
207 } | 238 } |
208 if (nestedCtx == NCHybrid) { | 239 if (nestedCtx == NCHybrid) { |
209 // If sym is a nested function, and its parent elided the context list but the | 240 // If sym is a nested function, and it's parent context is different than the |
210 // context we got didn't, we need to index to the first frame. | 241 // one we got, adjust it. |
211 if (FuncDeclaration* fd = getParentFunc(sym->isFuncDeclaration())) { | 242 |
243 if (FuncDeclaration* fd = getParentFunc(sym->isFuncDeclaration(), true)) { | |
212 Logger::println("For nested function, parent is %s", fd->toChars()); | 244 Logger::println("For nested function, parent is %s", fd->toChars()); |
213 FuncDeclaration* ctxfd = irfunc->decl; | 245 FuncDeclaration* ctxfd = irfunc->decl; |
214 Logger::println("Current function is %s", ctxfd->toChars()); | 246 Logger::println("Current function is %s", ctxfd->toChars()); |
215 if (fromParent) { | 247 if (fromParent) { |
216 ctxfd = getParentFunc(ctxfd); | 248 ctxfd = getParentFunc(ctxfd, true); |
217 assert(ctxfd && "Context from outer function, but no outer function?"); | 249 assert(ctxfd && "Context from outer function, but no outer function?"); |
218 } | 250 } |
219 Logger::println("Context is from %s", ctxfd->toChars()); | 251 Logger::println("Context is from %s", ctxfd->toChars()); |
220 if (fd->ir.irFunc->elidedCtxList && !ctxfd->ir.irFunc->elidedCtxList) { | 252 |
221 Logger::println("Adjusting to remove context frame list", ctxfd->toChars()); | 253 unsigned neededDepth = fd->ir.irFunc->depth; |
222 val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->framesType)); | 254 unsigned ctxDepth = ctxfd->ir.irFunc->depth; |
223 val = DtoGEPi(val, 0, 0); | 255 |
256 Logger::cout() << "Needed depth: " << neededDepth << '\n'; | |
257 Logger::cout() << "Context depth: " << ctxDepth << '\n'; | |
258 | |
259 if (neededDepth >= ctxDepth) { | |
260 assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?"); | |
261 // fd needs the same context as we do, so all is well | |
262 Logger::println("Calling sibling function or directly nested function"); | |
263 } else { | |
264 val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType)); | |
265 val = DtoGEPi(val, 0, neededDepth); | |
224 val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); | 266 val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); |
225 } | 267 } |
226 } | 268 } |
227 } | 269 } |
228 Logger::cout() << "result = " << *val << '\n'; | 270 Logger::cout() << "result = " << *val << '\n'; |
324 // construct nested variables array | 366 // construct nested variables array |
325 if (!fd->nestedVars.empty()) | 367 if (!fd->nestedVars.empty()) |
326 { | 368 { |
327 Logger::println("has nested frame"); | 369 Logger::println("has nested frame"); |
328 // start with adding all enclosing parent frames until a static parent is reached | 370 // start with adding all enclosing parent frames until a static parent is reached |
371 | |
372 const LLStructType* innerFrameType = NULL; | |
373 unsigned depth = 0; | |
374 if (!fd->isStatic()) { | |
375 if (FuncDeclaration* parfd = getParentFunc(fd, true)) { | |
376 innerFrameType = parfd->ir.irFunc->frameType; | |
377 if (innerFrameType) | |
378 depth = parfd->ir.irFunc->depth + 1; | |
379 } | |
380 } | |
381 fd->ir.irFunc->depth = depth; | |
382 | |
383 Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n'; | |
384 | |
329 typedef std::vector<const LLType*> TypeVec; | 385 typedef std::vector<const LLType*> TypeVec; |
330 TypeVec frametypes; | 386 TypeVec types; |
331 if (!fd->isStatic()) { | 387 if (depth != 0) { |
332 Dsymbol* par = fd->toParent2(); | 388 assert(innerFrameType); |
333 while (par) { | 389 // Add frame pointer types for all but last frame |
334 if (FuncDeclaration* parfd = par->isFuncDeclaration()) { | 390 if (depth > 1) { |
335 // skip functions without nested parameters | 391 for (unsigned i = 0; i < (depth - 1); ++i) { |
336 if (!parfd->nestedVars.empty()) { | 392 types.push_back(innerFrameType->getElementType(i)); |
337 const LLStructType* parft = parfd->ir.irFunc->framesType; | |
338 if (parfd->ir.irFunc->elidedCtxList) { | |
339 // This is the outermost function with a nested context. | |
340 // Its context is not a list of frames, but just the frame itself. | |
341 frametypes.push_back(LLPointerType::getUnqual(parft)); | |
342 } else { | |
343 // Copy the types of parent function frames. | |
344 frametypes.insert(frametypes.begin(), parft->element_begin(), parft->element_end()); | |
345 } | |
346 break; // That's all the info needed. | |
347 } | |
348 } else if (ClassDeclaration* parcd = par->isClassDeclaration()) { | |
349 // skip | |
350 } else { | |
351 break; | |
352 } | 393 } |
353 par = par->toParent2(); | 394 } |
354 } | 395 // Add frame pointer type for last frame |
355 } | 396 types.push_back(LLPointerType::getUnqual(innerFrameType)); |
356 unsigned depth = frametypes.size(); | 397 } |
357 | 398 |
358 if (Logger::enabled()) { | 399 if (Logger::enabled()) { |
359 Logger::println("Frame types: "); | 400 Logger::println("Frame types: "); |
360 LOG_SCOPE; | 401 LOG_SCOPE; |
361 for (TypeVec::iterator i=frametypes.begin(); i!=frametypes.end(); ++i) | 402 for (TypeVec::iterator i = types.begin(); i != types.end(); ++i) |
362 Logger::cout() << **i << '\n'; | 403 Logger::cout() << **i << '\n'; |
363 } | 404 } |
364 | 405 |
365 // Construct a struct for the direct nested variables of this function, and update their indices to match. | 406 // Add the direct nested variables of this function, and update their indices to match. |
366 // TODO: optimize ordering for minimal space usage? | 407 // TODO: optimize ordering for minimal space usage? |
367 TypeVec types; | |
368 for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) | 408 for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) |
369 { | 409 { |
370 VarDeclaration* vd = *i; | 410 VarDeclaration* vd = *i; |
371 if (!vd->ir.irLocal) | 411 if (!vd->ir.irLocal) |
372 vd->ir.irLocal = new IrLocal(vd); | 412 vd->ir.irLocal = new IrLocal(vd); |
373 | 413 |
414 vd->ir.irLocal->nestedIndex = types.size(); | |
374 vd->ir.irLocal->nestedDepth = depth; | 415 vd->ir.irLocal->nestedDepth = depth; |
375 vd->ir.irLocal->nestedIndex = types.size(); | |
376 if (vd->isParameter()) { | 416 if (vd->isParameter()) { |
377 // Parameters already have storage associated with them (to handle byref etc.), | 417 // Parameters already have storage associated with them (to handle byref etc.), |
378 // so handle specially for now by storing a pointer instead of a value. | 418 // so handle specially for now by storing a pointer instead of a value. |
379 assert(vd->ir.irLocal->value); | 419 assert(vd->ir.irLocal->value); |
380 // FIXME: don't do this for normal parameters? | 420 // FIXME: don't do this for normal parameters? |
391 } | 431 } |
392 } | 432 } |
393 | 433 |
394 // Append current frame type to frame type list | 434 // Append current frame type to frame type list |
395 const LLStructType* frameType = LLStructType::get(types); | 435 const LLStructType* frameType = LLStructType::get(types); |
396 const LLStructType* nestedVarsTy = NULL; | 436 |
397 if (!frametypes.empty()) { | 437 Logger::cout() << "frameType = " << *frameType << '\n'; |
398 assert(depth > 0); | |
399 frametypes.push_back(LLPointerType::getUnqual(frameType)); | |
400 | |
401 // make struct type for nested frame list | |
402 nestedVarsTy = LLStructType::get(frametypes); | |
403 } else { | |
404 assert(depth == 0); | |
405 // For the outer function, just use the frame as the context | |
406 // instead of alloca'ing a single-element framelist and passing | |
407 // a pointer to that. | |
408 nestedVarsTy = frameType; | |
409 fd->ir.irFunc->elidedCtxList = true; | |
410 } | |
411 | |
412 Logger::cout() << "nestedVarsTy = " << *nestedVarsTy << '\n'; | |
413 | 438 |
414 // Store type in IrFunction | 439 // Store type in IrFunction |
415 IrFunction* irfunction = fd->ir.irFunc; | 440 IrFunction* irfunction = fd->ir.irFunc; |
416 irfunction->framesType = nestedVarsTy; | 441 irfunction->frameType = frameType; |
417 | |
418 LLValue* nestedVars = NULL; | |
419 | 442 |
420 // Create frame for current function and append to frames list | 443 // Create frame for current function and append to frames list |
421 // FIXME: For D2, this should be a gc_malloc (or similar) call, not alloca | 444 // FIXME: For D2, this should be a gc_malloc (or similar) call, not alloca |
422 LLValue* frame = DtoAlloca(frameType, ".frame"); | 445 LLValue* frame = DtoAlloca(frameType, ".frame"); |
423 | 446 |
424 // copy parent frames into beginning | 447 // copy parent frames into beginning |
425 if (depth != 0) | 448 if (depth != 0) { |
426 { | |
427 // alloca frame list first | |
428 nestedVars = DtoAlloca(nestedVarsTy, ".frame_list"); | |
429 | |
430 LLValue* src = irfunction->nestArg; | 449 LLValue* src = irfunction->nestArg; |
431 if (!src) | 450 if (!src) { |
432 { | |
433 assert(irfunction->thisArg); | 451 assert(irfunction->thisArg); |
434 assert(fd->isMember2()); | 452 assert(fd->isMember2()); |
435 LLValue* thisval = DtoLoad(irfunction->thisArg); | 453 LLValue* thisval = DtoLoad(irfunction->thisArg); |
436 ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); | 454 ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); |
437 assert(cd); | 455 assert(cd); |
438 assert(cd->vthis); | 456 assert(cd->vthis); |
439 Logger::println("Indexing to 'this'"); | 457 Logger::println("Indexing to 'this'"); |
440 src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); | 458 src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); |
441 } | 459 } |
442 if (depth == 1) { | 460 if (depth > 1) { |
443 // Just copy nestArg into framelist; the outer frame is not a list of pointers | |
444 // but a direct pointer. | |
445 src = DtoBitCast(src, frametypes[0]); | |
446 LLValue* gep = DtoGEPi(nestedVars, 0, 0); | |
447 DtoAlignedStore(src, gep); | |
448 } else { | |
449 src = DtoBitCast(src, getVoidPtrType()); | 461 src = DtoBitCast(src, getVoidPtrType()); |
450 LLValue* dst = DtoBitCast(nestedVars, getVoidPtrType()); | 462 LLValue* dst = DtoBitCast(frame, getVoidPtrType()); |
451 DtoMemCpy(dst, src, DtoConstSize_t(depth * PTRSIZE), | 463 DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE), |
452 getABITypeAlign(getVoidPtrType())); | 464 getABITypeAlign(getVoidPtrType())); |
453 } | 465 } |
454 // store current frame in list | 466 // Copy nestArg into framelist; the outer frame is not in the list of pointers |
455 DtoAlignedStore(frame, DtoGEPi(nestedVars, 0, depth)); | 467 src = DtoBitCast(src, types[depth-1]); |
456 } else { | 468 LLValue* gep = DtoGEPi(frame, 0, depth-1); |
457 // Use frame as context directly | 469 DtoAlignedStore(src, gep); |
458 nestedVars = frame; | |
459 } | 470 } |
460 | 471 |
461 // store context in IrFunction | 472 // store context in IrFunction |
462 irfunction->nestedVar = nestedVars; | 473 irfunction->nestedVar = frame; |
463 | 474 |
464 // go through all nested vars and assign addresses where possible. | 475 // go through all nested vars and assign addresses where possible. |
465 for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) | 476 for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) |
466 { | 477 { |
467 VarDeclaration* vd = *i; | 478 VarDeclaration* vd = *i; |
482 assert(!vd->ir.irLocal->value); | 493 assert(!vd->ir.irLocal->value); |
483 vd->ir.irLocal->value = gep; | 494 vd->ir.irLocal->value = gep; |
484 vd->ir.irLocal->byref = false; | 495 vd->ir.irLocal->byref = false; |
485 } | 496 } |
486 } | 497 } |
487 } else if (FuncDeclaration* parFunc = getParentFunc(fd)) { | 498 } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { |
488 // Propagate context arg properties if the context arg is passed on unmodified. | 499 // Propagate context arg properties if the context arg is passed on unmodified. |
489 fd->ir.irFunc->framesType = parFunc->ir.irFunc->framesType; | 500 fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; |
490 fd->ir.irFunc->elidedCtxList = parFunc->ir.irFunc->elidedCtxList; | 501 fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; |
491 } | 502 } |
492 } | 503 } |
493 else { | 504 else { |
494 assert(0 && "Not implemented yet"); | 505 assert(0 && "Not implemented yet"); |
495 } | 506 } |