comparison gen/nested.cpp @ 1212:df2227fdc860

For the outermost function needing a context frame, use the address of that frame as the nest argument instead of the address of a single-element list containing only that frame address. This saves some stack space and reduces memory accesses.
author Frits van Bommel <fvbommel wxs.nl>
date Mon, 13 Apr 2009 04:09:08 +0200
parents 3d4581761b4c
children 9430d4959ab4
comparison
equal deleted inserted replaced
1211:50dc0db06238 1212:df2227fdc860
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. Each function with variables
29 /// accessed by nested functions puts them in a struct, and appends a 29 /// accessed by nested functions puts them in a struct, and appends a
30 /// pointer to that struct to it's local copy of the list. 30 /// pointer to that struct to it's local copy of the list.
31 /// As an additional optimization, if the list has length one it's not
32 /// generated; the only element is used directly instead.
31 NCHybrid 33 NCHybrid
32 }; 34 };
33 35
34 static cl::opt<NestedCtxType> nestedCtx("nested-ctx", 36 static cl::opt<NestedCtxType> nestedCtx("nested-ctx",
35 cl::desc("How to construct a nested function's context:"), 37 cl::desc("How to construct a nested function's context:"),
100 assert(vd->ir.irLocal->value); 102 assert(vd->ir.irLocal->value);
101 val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); 103 val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars());
102 return new DVarValue(astype, vd, val); 104 return new DVarValue(astype, vd, val);
103 } 105 }
104 else if (nestedCtx == NCHybrid) { 106 else if (nestedCtx == NCHybrid) {
105 FuncDeclaration *parentfunc = getParentFunc(vd); 107 FuncDeclaration* parentfunc = getParentFunc(irfunc->decl);
106 assert(parentfunc && "No parent function for nested variable?"); 108 assert(parentfunc && "No parent function for nested function?");
109 Logger::println("Parent function: %s", parentfunc->toChars());
107 110
108 LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(parentfunc->ir.irFunc->framesType)); 111 LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(parentfunc->ir.irFunc->framesType));
109 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); 112 Logger::cout() << "Context: " << *val << '\n';
110 val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str()); 113
114 if (!parentfunc->ir.irFunc->elidedCtxList) {
115 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth);
116 val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str());
117 }
111 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); 118 val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
112 if (vd->ir.irLocal->byref) 119 if (vd->ir.irLocal->byref)
113 val = DtoAlignedLoad(val); 120 val = DtoAlignedLoad(val);
114 return new DVarValue(astype, vd, val); 121 return new DVarValue(astype, vd, val);
115 } 122 }
121 void DtoNestedInit(VarDeclaration* vd) 128 void DtoNestedInit(VarDeclaration* vd)
122 { 129 {
123 Logger::println("DtoNestedInit for %s", vd->toChars()); 130 Logger::println("DtoNestedInit for %s", vd->toChars());
124 LOG_SCOPE 131 LOG_SCOPE
125 132
126 LLValue* nestedVar = gIR->func()->decl->ir.irFunc->nestedVar; 133 IrFunction* irfunc = gIR->func()->decl->ir.irFunc;
134 LLValue* nestedVar = irfunc->nestedVar;
127 135
128 if (nestedCtx == NCArray) { 136 if (nestedCtx == NCArray) {
129 // alloca as usual if no value already 137 // alloca as usual if no value already
130 if (!vd->ir.irLocal->value) 138 if (!vd->ir.irLocal->value)
131 vd->ir.irLocal->value = DtoAlloca(DtoType(vd->type), vd->toChars()); 139 vd->ir.irLocal->value = DtoAlloca(DtoType(vd->type), vd->toChars());
141 } 149 }
142 else if (nestedCtx == NCHybrid) { 150 else if (nestedCtx == NCHybrid) {
143 assert(vd->ir.irLocal->value && "Nested variable without storage?"); 151 assert(vd->ir.irLocal->value && "Nested variable without storage?");
144 if (!vd->isParameter() && (vd->isRef() || vd->isOut())) { 152 if (!vd->isParameter() && (vd->isRef() || vd->isOut())) {
145 Logger::println("Initializing non-parameter byref value"); 153 Logger::println("Initializing non-parameter byref value");
146 LLValue* framep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedDepth); 154 LLValue* frame;
147 155 if (!irfunc->elidedCtxList) {
148 FuncDeclaration *parentfunc = getParentFunc(vd); 156 LLValue* framep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedDepth);
149 assert(parentfunc && "No parent function for nested variable?"); 157
150 LLValue* frame = DtoAlignedLoad(framep, (std::string(".frame.") + parentfunc->toChars()).c_str()); 158 FuncDeclaration *parentfunc = getParentFunc(vd);
151 159 assert(parentfunc && "No parent function for nested variable?");
160 frame = DtoAlignedLoad(framep, (std::string(".frame.") + parentfunc->toChars()).c_str());
161 } else {
162 frame = nestedVar;
163 }
152 LLValue* slot = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex); 164 LLValue* slot = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex);
153 DtoAlignedStore(vd->ir.irLocal->value, slot); 165 DtoAlignedStore(vd->ir.irLocal->value, slot);
154 } else { 166 } else {
155 // Already initialized in DtoCreateNestedContext 167 // Already initialized in DtoCreateNestedContext
156 } 168 }
291 Dsymbol* par = fd->toParent2(); 303 Dsymbol* par = fd->toParent2();
292 while (par) { 304 while (par) {
293 if (FuncDeclaration* parfd = par->isFuncDeclaration()) { 305 if (FuncDeclaration* parfd = par->isFuncDeclaration()) {
294 // skip functions without nested parameters 306 // skip functions without nested parameters
295 if (!parfd->nestedVars.empty()) { 307 if (!parfd->nestedVars.empty()) {
296 // Copy the types of parent function frames.
297 const LLStructType* parft = parfd->ir.irFunc->framesType; 308 const LLStructType* parft = parfd->ir.irFunc->framesType;
298 frametypes.insert(frametypes.begin(), parft->element_begin(), parft->element_end()); 309 if (parfd->ir.irFunc->elidedCtxList) {
310 // This is the outermost function with a nested context.
311 // Its context is not a list of frames, but just the frame itself.
312 frametypes.push_back(LLPointerType::getUnqual(parft));
313 } else {
314 // Copy the types of parent function frames.
315 frametypes.insert(frametypes.begin(), parft->element_begin(), parft->element_end());
316 }
299 break; // That's all the info needed. 317 break; // That's all the info needed.
300 } 318 }
301 } else if (ClassDeclaration* parcd = par->isClassDeclaration()) { 319 } else if (ClassDeclaration* parcd = par->isClassDeclaration()) {
302 // skip 320 // skip
303 } else { 321 } else {
305 } 323 }
306 par = par->toParent2(); 324 par = par->toParent2();
307 } 325 }
308 } 326 }
309 unsigned depth = frametypes.size(); 327 unsigned depth = frametypes.size();
328
329 if (Logger::enabled()) {
330 Logger::println("Frame types: ");
331 LOG_SCOPE;
332 for (TypeVec::iterator i=frametypes.begin(); i!=frametypes.end(); ++i)
333 Logger::cout() << **i << '\n';
334 }
310 335
311 // Construct a struct for the direct nested variables of this function, and update their indices to match. 336 // Construct a struct for the direct nested variables of this function, and update their indices to match.
312 // TODO: optimize ordering for minimal space usage? 337 // TODO: optimize ordering for minimal space usage?
313 TypeVec types; 338 TypeVec types;
314 for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) 339 for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
334 if (Logger::enabled()) { 359 if (Logger::enabled()) {
335 Logger::println("Nested var: %s", vd->toChars()); 360 Logger::println("Nested var: %s", vd->toChars());
336 Logger::cout() << "of type: " << *types.back() << '\n'; 361 Logger::cout() << "of type: " << *types.back() << '\n';
337 } 362 }
338 } 363 }
364
339 // Append current frame type to frame type list 365 // Append current frame type to frame type list
340 const LLType* frameType = LLStructType::get(types); 366 const LLStructType* frameType = LLStructType::get(types);
341 frametypes.push_back(LLPointerType::getUnqual(frameType)); 367 const LLStructType* nestedVarsTy = NULL;
342 368 if (!frametypes.empty()) {
343 // make struct type for nested frame list 369 assert(depth > 0);
344 const LLStructType* nestedVarsTy = LLStructType::get(frametypes); 370 frametypes.push_back(LLPointerType::getUnqual(frameType));
371
372 // make struct type for nested frame list
373 nestedVarsTy = LLStructType::get(frametypes);
374 } else {
375 assert(depth == 0);
376 // For the outer function, just use the frame as the context
377 // instead of alloca'ing a single-element framelist and passing
378 // a pointer to that.
379 nestedVarsTy = frameType;
380 fd->ir.irFunc->elidedCtxList = true;
381 }
382
383 Logger::cout() << "nestedVarsTy = " << *nestedVarsTy << '\n';
345 384
346 // Store type in IrFunction 385 // Store type in IrFunction
347 IrFunction* irfunction = fd->ir.irFunc; 386 IrFunction* irfunction = fd->ir.irFunc;
348 irfunction->framesType = nestedVarsTy; 387 irfunction->framesType = nestedVarsTy;
349 388
350 // alloca it 389 LLValue* nestedVars = NULL;
390
391 // Create frame for current function and append to frames list
351 // FIXME: For D2, this should be a gc_malloc (or similar) call, not alloca 392 // FIXME: For D2, this should be a gc_malloc (or similar) call, not alloca
352 LLValue* nestedVars = DtoAlloca(nestedVarsTy, ".frame_list"); 393 LLValue* frame = DtoAlloca(frameType, ".frame");
353 394
354 // copy parent frames into beginning 395 // copy parent frames into beginning
355 if (depth != 0) 396 if (depth != 0)
356 { 397 {
398 // alloca frame list first
399 nestedVars = DtoAlloca(nestedVarsTy, ".frame_list");
400
357 LLValue* src = irfunction->nestArg; 401 LLValue* src = irfunction->nestArg;
358 if (!src) 402 if (!src)
359 { 403 {
360 assert(irfunction->thisArg); 404 assert(irfunction->thisArg);
361 assert(fd->isMember2()); 405 assert(fd->isMember2());
364 assert(cd); 408 assert(cd);
365 assert(cd->vthis); 409 assert(cd->vthis);
366 Logger::println("Indexing to 'this'"); 410 Logger::println("Indexing to 'this'");
367 src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); 411 src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis"));
368 } 412 }
369 src = DtoBitCast(src, getVoidPtrType()); 413 if (depth == 1) {
370 LLValue* dst = DtoBitCast(nestedVars, getVoidPtrType()); 414 // Just copy nestArg into framelist; the outer frame is not a list of pointers
371 DtoMemCpy(dst, src, DtoConstSize_t(depth * PTRSIZE), 415 // but a direct pointer.
372 getABITypeAlign(getVoidPtrType())); 416 src = DtoBitCast(src, frametypes[0]);
373 } 417 LLValue* gep = DtoGEPi(nestedVars, 0, 0);
374 418 DtoAlignedStore(src, gep);
375 // Create frame for current function and append to frames list 419 } else {
376 LLValue* frame = DtoAlloca(frameType, ".frame"); 420 src = DtoBitCast(src, getVoidPtrType());
377 // store current frame in list 421 LLValue* dst = DtoBitCast(nestedVars, getVoidPtrType());
378 DtoAlignedStore(frame, DtoGEPi(nestedVars, 0, depth)); 422 DtoMemCpy(dst, src, DtoConstSize_t(depth * PTRSIZE),
423 getABITypeAlign(getVoidPtrType()));
424 }
425 // store current frame in list
426 DtoAlignedStore(frame, DtoGEPi(nestedVars, 0, depth));
427 } else {
428 // Use frame as context directly
429 nestedVars = frame;
430 }
379 431
380 // store context in IrFunction 432 // store context in IrFunction
381 irfunction->nestedVar = nestedVars; 433 irfunction->nestedVar = nestedVars;
382 434
383 // go through all nested vars and assign addresses where possible. 435 // go through all nested vars and assign addresses where possible.
401 assert(!vd->ir.irLocal->value); 453 assert(!vd->ir.irLocal->value);
402 vd->ir.irLocal->value = gep; 454 vd->ir.irLocal->value = gep;
403 vd->ir.irLocal->byref = false; 455 vd->ir.irLocal->byref = false;
404 } 456 }
405 } 457 }
458 } else if (FuncDeclaration* parFunc = getParentFunc(fd)) {
459 // Propagate context arg properties if the context arg is passed on unmodified.
460 fd->ir.irFunc->framesType = parFunc->ir.irFunc->framesType;
461 fd->ir.irFunc->elidedCtxList = parFunc->ir.irFunc->elidedCtxList;
406 } 462 }
407 } 463 }
408 else { 464 else {
409 assert(0 && "Not implemented yet"); 465 assert(0 && "Not implemented yet");
410 } 466 }