Mercurial > projects > ldc
comparison gen/nested.cpp @ 1208:2a37f4745ddd
Add an option to change the way nested variables are handled.
Only one value is implemented, which is the old way.
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Sun, 12 Apr 2009 16:22:21 +0200 |
parents | 83d3b25c2213 |
children | 8699c450a1a0 |
comparison
equal
deleted
inserted
replaced
1207:83d3b25c2213 | 1208:2a37f4745ddd |
---|---|
4 #include "gen/irstate.h" | 4 #include "gen/irstate.h" |
5 #include "gen/llvmhelpers.h" | 5 #include "gen/llvmhelpers.h" |
6 #include "gen/logger.h" | 6 #include "gen/logger.h" |
7 #include "gen/tollvm.h" | 7 #include "gen/tollvm.h" |
8 | 8 |
9 #include "llvm/Support/CommandLine.h" | |
10 namespace cl = llvm::cl; | |
11 | |
12 /// What the context pointer for a nested function looks like | |
13 enum NestedCtxType { | |
14 /// Context is void*[] of pointers to variables. | |
15 /// Variables from higher levels are at the front. | |
16 NCArray, | |
17 | |
18 /// Context is a struct containing variables belonging to the parent function. | |
19 /// If the parent function itself has a parent function, one of the members is | |
20 /// a pointer to its context. (linked-list style) | |
21 // FIXME: implement | |
22 // TODO: Functions without any variables accessed by nested functions, but | |
23 // with a parent whose variables are accessed, can use the parent's | |
24 // context. | |
25 NCStruct, | |
26 | |
27 /// Context is an array of pointers to nested contexts. Each function with variables | |
28 /// accessed by nested functions puts them in a struct, and appends a pointer to that | |
29 /// struct to the array. | |
30 // FIXME: implement | |
31 NCHybrid | |
32 }; | |
33 | |
34 static cl::opt<NestedCtxType> nestedCtx("nested-ctx", | |
35 cl::desc("How to construct a nested function's context:"), | |
36 cl::ZeroOrMore, | |
37 cl::values( | |
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)"), | |
40 //clEnumValN(NCHybrid, "hybrid", "Array of pointers to structs of variables"), | |
41 clEnumValEnd), | |
42 cl::init(NCArray)); | |
43 | |
44 | |
9 /****************************************************************************************/ | 45 /****************************************************************************************/ |
10 /*//////////////////////////////////////////////////////////////////////////////////////// | 46 /*//////////////////////////////////////////////////////////////////////////////////////// |
11 // NESTED VARIABLE HELPERS | 47 // NESTED VARIABLE HELPERS |
12 ////////////////////////////////////////////////////////////////////////////////////////*/ | 48 ////////////////////////////////////////////////////////////////////////////////////////*/ |
13 | 49 |
14 DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd) | 50 DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd) |
15 { | 51 { |
52 //////////////////////////////////// | |
53 // Locate context value | |
54 | |
16 Dsymbol* vdparent = vd->toParent2(); | 55 Dsymbol* vdparent = vd->toParent2(); |
17 assert(vdparent); | 56 assert(vdparent); |
18 | 57 |
19 IrFunction* irfunc = gIR->func(); | 58 IrFunction* irfunc = gIR->func(); |
20 | 59 |
23 { | 62 { |
24 LLValue* val = vd->ir.getIrValue(); | 63 LLValue* val = vd->ir.getIrValue(); |
25 return new DVarValue(astype, vd, val); | 64 return new DVarValue(astype, vd, val); |
26 } | 65 } |
27 | 66 |
28 // get it from the nested context | 67 // get the nested context |
29 LLValue* ctx = 0; | 68 LLValue* ctx = 0; |
30 if (irfunc->decl->isMember2()) | 69 if (irfunc->decl->isMember2()) |
31 { | 70 { |
32 ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration(); | 71 ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration(); |
33 LLValue* val = DtoLoad(irfunc->thisArg); | 72 LLValue* val = DtoLoad(irfunc->thisArg); |
36 else | 75 else |
37 ctx = irfunc->nestArg; | 76 ctx = irfunc->nestArg; |
38 assert(ctx); | 77 assert(ctx); |
39 | 78 |
40 assert(vd->ir.irLocal); | 79 assert(vd->ir.irLocal); |
41 LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType())); | 80 |
42 val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex); | 81 //////////////////////////////////// |
43 val = DtoLoad(val); | 82 // Extract variable from nested context |
44 assert(vd->ir.irLocal->value); | 83 |
45 val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); | 84 if (nestedCtx == NCArray) { |
46 return new DVarValue(astype, vd, val); | 85 LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType())); |
86 val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex); | |
87 val = DtoLoad(val); | |
88 assert(vd->ir.irLocal->value); | |
89 val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); | |
90 return new DVarValue(astype, vd, val); | |
91 } | |
92 else { | |
93 assert(0 && "Not implemented yet"); | |
94 } | |
47 } | 95 } |
48 | 96 |
49 void DtoNestedInit(VarDeclaration* vd) | 97 void DtoNestedInit(VarDeclaration* vd) |
50 { | 98 { |
51 // alloca as usual if no value already | 99 if (nestedCtx == NCArray) { |
52 if (!vd->ir.irLocal->value) | 100 // alloca as usual if no value already |
53 vd->ir.irLocal->value = DtoAlloca(DtoType(vd->type), vd->toChars()); | 101 if (!vd->ir.irLocal->value) |
54 | 102 vd->ir.irLocal->value = DtoAlloca(DtoType(vd->type), vd->toChars()); |
55 // store the address into the nested vars array | 103 |
56 assert(vd->ir.irLocal->nestedIndex >= 0); | 104 // store the address into the nested vars array |
57 LLValue* gep = DtoGEPi(gIR->func()->decl->ir.irFunc->nestedVar, 0, vd->ir.irLocal->nestedIndex); | 105 assert(vd->ir.irLocal->nestedIndex >= 0); |
58 | 106 LLValue* gep = DtoGEPi(gIR->func()->decl->ir.irFunc->nestedVar, 0, vd->ir.irLocal->nestedIndex); |
59 assert(isaPointer(vd->ir.irLocal->value)); | 107 |
60 LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); | 108 assert(isaPointer(vd->ir.irLocal->value)); |
61 | 109 LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); |
62 DtoStore(val, gep); | 110 |
111 DtoStore(val, gep); | |
112 } | |
113 else { | |
114 assert(0 && "Not implemented yet"); | |
115 } | |
63 } | 116 } |
64 | 117 |
65 LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) | 118 LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) |
66 { | 119 { |
67 Logger::println("DtoNestedContext for %s", sym->toPrettyChars()); | 120 Logger::println("DtoNestedContext for %s", sym->toPrettyChars()); |
90 return getNullPtr(getVoidPtrType()); | 143 return getNullPtr(getVoidPtrType()); |
91 } | 144 } |
92 } | 145 } |
93 | 146 |
94 void DtoCreateNestedContext(FuncDeclaration* fd) { | 147 void DtoCreateNestedContext(FuncDeclaration* fd) { |
95 // construct nested variables array | 148 if (nestedCtx == NCArray) { |
96 if (!fd->nestedVars.empty()) | 149 // construct nested variables array |
97 { | 150 if (!fd->nestedVars.empty()) |
98 Logger::println("has nested frame"); | |
99 // start with adding all enclosing parent frames until a static parent is reached | |
100 int nparelems = 0; | |
101 if (!fd->isStatic()) | |
102 { | 151 { |
103 Dsymbol* par = fd->toParent2(); | 152 Logger::println("has nested frame"); |
104 while (par) | 153 // start with adding all enclosing parent frames until a static parent is reached |
105 { | 154 int nparelems = 0; |
106 if (FuncDeclaration* parfd = par->isFuncDeclaration()) | 155 if (!fd->isStatic()) |
107 { | 156 { |
108 nparelems += parfd->nestedVars.size(); | 157 Dsymbol* par = fd->toParent2(); |
109 // stop at first static | 158 while (par) |
110 if (parfd->isStatic()) | 159 { |
160 if (FuncDeclaration* parfd = par->isFuncDeclaration()) | |
161 { | |
162 nparelems += parfd->nestedVars.size(); | |
163 // stop at first static | |
164 if (parfd->isStatic()) | |
165 break; | |
166 } | |
167 else if (ClassDeclaration* parcd = par->isClassDeclaration()) | |
168 { | |
169 // nothing needed | |
170 } | |
171 else | |
172 { | |
111 break; | 173 break; |
112 } | 174 } |
113 else if (ClassDeclaration* parcd = par->isClassDeclaration()) | 175 |
114 { | 176 par = par->toParent2(); |
115 // nothing needed | 177 } |
178 } | |
179 int nelems = fd->nestedVars.size() + nparelems; | |
180 | |
181 // make array type for nested vars | |
182 const LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems); | |
183 | |
184 // alloca it | |
185 LLValue* nestedVars = DtoAlloca(nestedVarsTy, ".nested_vars"); | |
186 | |
187 IrFunction* irfunction = fd->ir.irFunc; | |
188 | |
189 // copy parent frame into beginning | |
190 if (nparelems) | |
191 { | |
192 LLValue* src = irfunction->nestArg; | |
193 if (!src) | |
194 { | |
195 assert(irfunction->thisArg); | |
196 assert(fd->isMember2()); | |
197 LLValue* thisval = DtoLoad(irfunction->thisArg); | |
198 ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); | |
199 assert(cd); | |
200 assert(cd->vthis); | |
201 src = DtoLoad(DtoGEPi(thisval, 0,cd->vthis->ir.irField->index, ".vthis")); | |
202 } | |
203 DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE)); | |
204 } | |
205 | |
206 // store in IrFunction | |
207 irfunction->nestedVar = nestedVars; | |
208 | |
209 // go through all nested vars and assign indices | |
210 int idx = nparelems; | |
211 for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) | |
212 { | |
213 VarDeclaration* vd = *i; | |
214 if (!vd->ir.irLocal) | |
215 vd->ir.irLocal = new IrLocal(vd); | |
216 | |
217 if (vd->isParameter()) | |
218 { | |
219 Logger::println("nested param: %s", vd->toChars()); | |
220 LLValue* gep = DtoGEPi(nestedVars, 0, idx); | |
221 LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); | |
222 DtoStore(val, gep); | |
116 } | 223 } |
117 else | 224 else |
118 { | 225 { |
119 break; | 226 Logger::println("nested var: %s", vd->toChars()); |
120 } | 227 } |
121 | 228 |
122 par = par->toParent2(); | 229 vd->ir.irLocal->nestedIndex = idx++; |
230 } | |
231 | |
232 // fixup nested result variable | |
233 #if DMDV2 | |
234 if (fd->vresult && fd->vresult->nestedrefs.dim) | |
235 #else | |
236 if (fd->vresult && fd->vresult->nestedref) | |
237 #endif | |
238 { | |
239 Logger::println("nested vresult value: %s", fd->vresult->toChars()); | |
240 LLValue* gep = DtoGEPi(nestedVars, 0, fd->vresult->ir.irLocal->nestedIndex); | |
241 LLValue* val = DtoBitCast(fd->vresult->ir.irLocal->value, getVoidPtrType()); | |
242 DtoStore(val, gep); | |
123 } | 243 } |
124 } | 244 } |
125 int nelems = fd->nestedVars.size() + nparelems; | 245 } |
126 | 246 else { |
127 // make array type for nested vars | 247 assert(0 && "Not implemented yet"); |
128 const LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems); | 248 } |
129 | 249 } |
130 // alloca it | |
131 LLValue* nestedVars = DtoAlloca(nestedVarsTy, ".nested_vars"); | |
132 | |
133 IrFunction* irfunction = fd->ir.irFunc; | |
134 | |
135 // copy parent frame into beginning | |
136 if (nparelems) | |
137 { | |
138 LLValue* src = irfunction->nestArg; | |
139 if (!src) | |
140 { | |
141 assert(irfunction->thisArg); | |
142 assert(fd->isMember2()); | |
143 LLValue* thisval = DtoLoad(irfunction->thisArg); | |
144 ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); | |
145 assert(cd); | |
146 assert(cd->vthis); | |
147 src = DtoLoad(DtoGEPi(thisval, 0,cd->vthis->ir.irField->index, ".vthis")); | |
148 } | |
149 DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE)); | |
150 } | |
151 | |
152 // store in IrFunction | |
153 irfunction->nestedVar = nestedVars; | |
154 | |
155 // go through all nested vars and assign indices | |
156 int idx = nparelems; | |
157 for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) | |
158 { | |
159 VarDeclaration* vd = *i; | |
160 if (!vd->ir.irLocal) | |
161 vd->ir.irLocal = new IrLocal(vd); | |
162 | |
163 if (vd->isParameter()) | |
164 { | |
165 Logger::println("nested param: %s", vd->toChars()); | |
166 LLValue* gep = DtoGEPi(nestedVars, 0, idx); | |
167 LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); | |
168 DtoStore(val, gep); | |
169 } | |
170 else | |
171 { | |
172 Logger::println("nested var: %s", vd->toChars()); | |
173 } | |
174 | |
175 vd->ir.irLocal->nestedIndex = idx++; | |
176 } | |
177 | |
178 // fixup nested result variable | |
179 #if DMDV2 | |
180 if (fd->vresult && fd->vresult->nestedrefs.dim) { | |
181 #else | |
182 if (fd->vresult && fd->vresult->nestedref) { | |
183 #endif | |
184 Logger::println("nested vresult value: %s", fd->vresult->toChars()); | |
185 LLValue* gep = DtoGEPi(nestedVars, 0, fd->vresult->ir.irLocal->nestedIndex); | |
186 LLValue* val = DtoBitCast(fd->vresult->ir.irLocal->value, getVoidPtrType()); | |
187 DtoStore(val, gep); | |
188 } | |
189 } | |
190 } |