Mercurial > projects > ldc
comparison ir/irstruct.cpp @ 1228:79758fd2f48a
Added Doxygen file.
Completely seperated type and symbol generation. Should fix a lot of bugs, but is not yet 100% complete.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail.com> |
---|---|
date | Wed, 15 Apr 2009 20:06:25 +0200 |
parents | 1714836f2c0b |
children | 212ec2d9d176 |
comparison
equal
deleted
inserted
replaced
1215:08f87d8cd101 | 1228:79758fd2f48a |
---|---|
3 #include "mtype.h" | 3 #include "mtype.h" |
4 #include "aggregate.h" | 4 #include "aggregate.h" |
5 #include "declaration.h" | 5 #include "declaration.h" |
6 #include "init.h" | 6 #include "init.h" |
7 | 7 |
8 #include "ir/irstruct.h" | |
9 #include "gen/irstate.h" | 8 #include "gen/irstate.h" |
10 #include "gen/tollvm.h" | 9 #include "gen/tollvm.h" |
11 #include "gen/logger.h" | 10 #include "gen/logger.h" |
12 #include "gen/llvmhelpers.h" | 11 #include "gen/llvmhelpers.h" |
13 | 12 #include "gen/utils.h" |
14 IrInterface::IrInterface(BaseClass* b) | 13 |
15 : vtblInitTy(llvm::OpaqueType::get()) | 14 #include "ir/irstruct.h" |
16 { | 15 #include "ir/irtypeclass.h" |
17 base = b; | 16 |
18 decl = b->base; | |
19 vtblInit = NULL; | |
20 vtbl = NULL; | |
21 infoTy = NULL; | |
22 infoInit = NULL; | |
23 info = NULL; | |
24 | |
25 index = 0; | |
26 } | |
27 | |
28 ////////////////////////////////////////////////////////////////////////////// | |
29 ////////////////////////////////////////////////////////////////////////////// | |
30 ////////////////////////////////////////////////////////////////////////////// | 17 ////////////////////////////////////////////////////////////////////////////// |
31 | 18 |
32 IrStruct::IrStruct(AggregateDeclaration* aggr) | 19 IrStruct::IrStruct(AggregateDeclaration* aggr) |
33 : initOpaque(llvm::OpaqueType::get()), | 20 : diCompositeType(NULL) |
34 classInfoOpaque(llvm::OpaqueType::get()), | |
35 vtblTy(llvm::OpaqueType::get()), | |
36 vtblInitTy(llvm::OpaqueType::get()), | |
37 diCompositeType(NULL) | |
38 { | 21 { |
39 aggrdecl = aggr; | 22 aggrdecl = aggr; |
40 defaultFound = false; | |
41 anon = NULL; | |
42 index = 0; | |
43 | 23 |
44 type = aggr->type; | 24 type = aggr->type; |
45 defined = false; | 25 |
46 constinited = false; | 26 packed = false; |
47 | 27 |
48 interfaceInfos = NULL; | 28 // above still need to be looked at |
29 | |
30 init = NULL; | |
31 constInit = NULL; | |
32 | |
49 vtbl = NULL; | 33 vtbl = NULL; |
50 constVtbl = NULL; | 34 constVtbl = NULL; |
51 | |
52 init = NULL; | |
53 constInit = NULL; | |
54 | |
55 classInfo = NULL; | 35 classInfo = NULL; |
56 constClassInfo = NULL; | 36 constClassInfo = NULL; |
57 classInfoDeclared = false; | 37 |
58 classInfoDefined = false; | 38 classInterfacesArray = NULL; |
59 | 39 } |
60 packed = false; | 40 |
61 } | 41 ////////////////////////////////////////////////////////////////////////////// |
62 | 42 |
63 IrStruct::~IrStruct() | 43 LLGlobalVariable * IrStruct::getInitSymbol() |
64 { | 44 { |
65 } | 45 if (init) |
66 | 46 return init; |
67 ////////////////////////////////////////// | 47 |
68 | 48 // create the initZ symbol |
69 void IrStruct::pushAnon(bool isunion) | 49 std::string initname("_D"); |
70 { | 50 initname.append(aggrdecl->mangle()); |
71 anon = new Anon(isunion, anon); | 51 initname.append("6__initZ"); |
72 } | 52 |
73 | 53 llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); |
74 ////////////////////////////////////////// | 54 |
75 | 55 init = new llvm::GlobalVariable( |
76 void IrStruct::popAnon() | 56 type->irtype->getPA().get(), true, _linkage, NULL, initname, gIR->module); |
77 { | 57 |
78 assert(anon); | 58 return init; |
79 | 59 } |
80 const LLType* BT; | 60 |
81 | 61 ////////////////////////////////////////////////////////////////////////////// |
82 // get the anon type | 62 |
83 if (anon->isunion) | 63 llvm::Constant * IrStruct::getDefaultInit() |
84 { | 64 { |
85 // get biggest type in block | 65 if (constInit) |
86 const LLType* biggest = getBiggestType(&anon->types[0], anon->types.size()); | 66 return constInit; |
87 std::vector<const LLType*> vec(1, biggest); | 67 |
88 BT = LLStructType::get(vec, aggrdecl->ir.irStruct->packed); | 68 if (type->ty == Tstruct) |
69 { | |
70 constInit = createStructDefaultInitializer(); | |
89 } | 71 } |
90 else | 72 else |
91 { | 73 { |
92 // build a struct from the types | 74 constInit = createClassDefaultInitializer(); |
93 BT = LLStructType::get(anon->types, aggrdecl->ir.irStruct->packed); | 75 } |
94 } | 76 |
95 | 77 return constInit; |
96 // pop anon | 78 } |
97 Anon* tmp = anon; | 79 |
98 anon = anon->parent; | 80 ////////////////////////////////////////////////////////////////////////////// |
99 delete tmp; | 81 ////////////////////////////////////////////////////////////////////////////// |
100 | 82 ////////////////////////////////////////////////////////////////////////////// |
101 // is there a parent anon? | 83 |
102 if (anon) | 84 // helper function that returns the static default initializer of a variable |
103 { | 85 LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init) |
104 // make sure type gets pushed in the anon, not the main | 86 { |
105 anon->types.push_back(BT); | 87 if (init) |
106 // index is only manipulated at the top level, anons use raw offsets | 88 { |
107 } | 89 return DtoConstInitializer(init->loc, vd->type, init); |
108 // no parent anon, finally add to aggrdecl | 90 } |
91 else if (vd->init) | |
92 { | |
93 return DtoConstInitializer(vd->init->loc, vd->type, vd->init); | |
94 } | |
109 else | 95 else |
110 { | 96 { |
111 types.push_back(BT); | 97 return DtoConstExpInit(vd->loc, vd->type, vd->type->defaultInit(vd->loc)); |
112 // only advance to next position if main is not a union | 98 } |
113 if (!aggrdecl->isUnionDeclaration()) | 99 } |
114 { | 100 |
115 index++; | 101 // helper function that adds zero bytes to a vector of constants |
116 } | 102 size_t add_zeros(std::vector<llvm::Constant*>& constants, size_t diff) |
117 } | 103 { |
118 } | 104 size_t n = constants.size(); |
119 | 105 while (diff) |
120 ////////////////////////////////////////// | 106 { |
121 | 107 if (global.params.is64bit && diff % 8 == 0) |
122 void IrStruct::addVar(VarDeclaration * var) | 108 { |
123 { | 109 constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int64Ty)); |
124 TypeVector* tvec = &types; | 110 diff -= 8; |
125 if (anon) | 111 } |
126 { | 112 else if (diff % 4 == 0) |
127 // make sure type gets pushed in the anon, not the main | 113 { |
128 tvec = &anon->types; | 114 constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int32Ty)); |
129 | 115 diff -= 4; |
130 // set but don't advance index | 116 } |
131 var->ir.irField->index = index; | 117 else if (diff % 2 == 0) |
132 | 118 { |
133 // set offset in bytes from start of anon block | 119 constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int16Ty)); |
134 var->ir.irField->unionOffset = var->offset - var->offset2; | 120 diff -= 2; |
135 } | 121 } |
136 else if (aggrdecl->isUnionDeclaration()) | 122 else |
137 { | 123 { |
138 // set but don't advance index | 124 constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int8Ty)); |
139 var->ir.irField->index = index; | 125 diff -= 1; |
140 } | 126 } |
141 else | 127 } |
142 { | 128 return constants.size() - n; |
143 // set and advance index | 129 } |
144 var->ir.irField->index = index++; | 130 |
145 } | 131 // Matches the way the type is built in IrTypeStruct |
146 | 132 // maybe look at unifying the interface. |
147 // add type | 133 |
148 tvec->push_back(DtoType(var->type)); | 134 LLConstant * IrStruct::createStructDefaultInitializer() |
149 | 135 { |
150 // add var | 136 IF_LOG Logger::println("Building default initializer for %s", aggrdecl->toPrettyChars()); |
151 varDecls.push_back(var); | 137 LOG_SCOPE; |
152 } | 138 |
153 | 139 assert(type->ty == Tstruct && "cannot build struct default initializer for non struct type"); |
154 ////////////////////////////////////////// | 140 |
155 | 141 // start at offset zero |
156 const LLType* IrStruct::build() | 142 size_t offset = 0; |
157 { | 143 |
158 // if types is empty, add a byte | 144 // vector of constants |
159 if (types.empty()) | 145 std::vector<llvm::Constant*> constants; |
160 { | 146 |
161 types.push_back(LLType::Int8Ty); | 147 // go through fields |
162 } | 148 ArrayIter<VarDeclaration> it(aggrdecl->fields); |
163 | 149 for (; !it.done(); it.next()) |
164 // union type | 150 { |
165 if (aggrdecl->isUnionDeclaration()) | 151 VarDeclaration* vd = it.get(); |
166 { | 152 |
167 const LLType* biggest = getBiggestType(&types[0], types.size()); | 153 if (vd->offset < offset) |
168 std::vector<const LLType*> vec(1, biggest); | 154 { |
169 return LLStructType::get(vec, aggrdecl->ir.irStruct->packed); | 155 IF_LOG Logger::println("skipping field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); |
170 } | 156 continue; |
171 // struct/class type | 157 } |
172 else | 158 |
173 { | 159 IF_LOG Logger::println("using field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); |
174 return LLStructType::get(types, aggrdecl->ir.irStruct->packed); | 160 |
175 } | 161 // get next aligned offset for this field |
176 } | 162 size_t alignedoffset = offset; |
177 | 163 if (!packed) |
178 void addZeros(std::vector<const llvm::Type*>& inits, size_t pos, size_t offset) | 164 { |
179 { | 165 size_t alignsize = vd->type->alignsize(); |
180 assert(offset > pos); | 166 alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); |
181 size_t diff = offset - pos; | 167 } |
182 | 168 |
183 size_t sz; | 169 // insert explicit padding? |
184 | 170 if (alignedoffset < vd->offset) |
185 do | 171 { |
186 { | 172 add_zeros(constants, vd->offset - alignedoffset); |
187 if (pos%8 == 0 && diff >= 8) | 173 } |
188 sz = 8; | 174 |
189 else if (pos%4 == 0 && diff >= 4) | 175 // add initializer |
190 sz = 4; | 176 constants.push_back(get_default_initializer(vd, NULL)); |
191 else if (pos%2 == 0 && diff >= 2) | 177 |
192 sz = 2; | 178 // advance offset to right past this field |
193 else // if (pos % 1 == 0) | 179 offset = vd->offset + vd->type->size(); |
194 sz = 1; | 180 } |
195 inits.push_back(LLIntegerType::get(sz*8)); | 181 |
196 pos += sz; | 182 // tail padding? |
197 diff -= sz; | 183 if (offset < aggrdecl->structsize) |
198 } while (pos < offset); | 184 { |
199 | 185 add_zeros(constants, aggrdecl->structsize - offset); |
200 assert(pos == offset); | 186 } |
201 } | 187 |
202 | 188 // build constant struct |
203 void addZeros(std::vector<llvm::Constant*>& inits, size_t pos, size_t offset) | 189 llvm::Constant* definit = llvm::ConstantStruct::get(constants, packed); |
204 { | 190 IF_LOG Logger::cout() << "final default initializer: " << *definit << std::endl; |
205 assert(offset > pos); | 191 |
206 size_t diff = offset - pos; | 192 // sanity check |
207 | 193 assert(definit->getType() == type->irtype->get() && |
208 size_t sz; | 194 "default initializer type does not match the default struct type"); |
209 | 195 |
210 do | 196 return definit; |
211 { | 197 } |
212 if (pos%8 == 0 && diff >= 8) | 198 |
213 sz = 8; | 199 ////////////////////////////////////////////////////////////////////////////// |
214 else if (pos%4 == 0 && diff >= 4) | 200 ////////////////////////////////////////////////////////////////////////////// |
215 sz = 4; | 201 ////////////////////////////////////////////////////////////////////////////// |
216 else if (pos%2 == 0 && diff >= 2) | 202 |
217 sz = 2; | 203 // yet another rewrite of the notorious StructInitializer. |
218 else // if (pos % 1 == 0) | 204 |
219 sz = 1; | 205 // this time a bit more inspired by the DMD code. |
220 inits.push_back(LLConstant::getNullValue(LLIntegerType::get(sz*8))); | 206 |
221 pos += sz; | 207 LLConstant * IrStruct::createStructInitializer(StructInitializer * si) |
222 diff -= sz; | 208 { |
223 } while (pos < offset); | 209 IF_LOG Logger::println("Building StructInitializer of type %s", si->ad->toPrettyChars()); |
224 | 210 LOG_SCOPE; |
225 assert(pos == offset); | 211 |
226 } | 212 // sanity check |
227 | 213 assert(si->ad == aggrdecl && "struct type mismatch"); |
228 // FIXME: body is exact copy of above | 214 assert(si->vars.dim == si->value.dim && "inconsistent StructInitializer"); |
229 void addZeros(std::vector<llvm::Value*>& inits, size_t pos, size_t offset) | 215 |
230 { | 216 // array of things to build |
231 assert(offset > pos); | 217 typedef std::pair<VarDeclaration*, llvm::Constant*> VCPair; |
232 size_t diff = offset - pos; | 218 llvm::SmallVector<VCPair, 16> data(aggrdecl->fields.dim); |
233 | 219 |
234 size_t sz; | 220 // start by creating a map from initializer indices to field indices. |
235 | 221 // I have no fucking clue why dmd represents it like this :/ |
236 do | 222 size_t n = si->vars.dim; |
237 { | 223 LLSmallVector<int, 16> datamap(n, 0); |
238 if (pos%8 == 0 && diff >= 8) | 224 for (size_t i = 0; i < n; i++) |
239 sz = 8; | 225 { |
240 else if (pos%4 == 0 && diff >= 4) | 226 for (size_t j = 0; 1; j++) |
241 sz = 4; | 227 { |
242 else if (pos%2 == 0 && diff >= 2) | 228 assert(j < aggrdecl->fields.dim); |
243 sz = 2; | 229 if (aggrdecl->fields.data[j] == si->vars.data[i]) |
244 else // if (pos % 1 == 0) | |
245 sz = 1; | |
246 inits.push_back(LLConstant::getNullValue(LLIntegerType::get(sz*8))); | |
247 pos += sz; | |
248 diff -= sz; | |
249 } while (pos < offset); | |
250 | |
251 assert(pos == offset); | |
252 } | |
253 | |
254 void IrStruct::buildDefaultConstInit(std::vector<llvm::Constant*>& inits) | |
255 { | |
256 assert(!defaultFound); | |
257 defaultFound = true; | |
258 | |
259 const llvm::StructType* structtype = isaStruct(aggrdecl->type->ir.type->get()); | |
260 Logger::cout() << "struct type: " << *structtype << '\n'; | |
261 | |
262 size_t lastoffset = 0; | |
263 size_t lastsize = 0; | |
264 | |
265 { | |
266 Logger::println("Find the default fields"); | |
267 LOG_SCOPE; | |
268 | |
269 // go through all vars and find the ones that contribute to the default | |
270 size_t nvars = varDecls.size(); | |
271 for (size_t i=0; i<nvars; i++) | |
272 { | |
273 VarDeclaration* var = varDecls[i]; | |
274 | |
275 Logger::println("field %s %s = %s : +%u", var->type->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset); | |
276 | |
277 // only add vars that don't overlap | |
278 size_t offset = var->offset; | |
279 size_t size = var->type->size(); | |
280 if (offset >= lastoffset+lastsize) | |
281 { | 230 { |
282 Logger::println(" added"); | 231 datamap[i] = j; |
283 lastoffset = offset; | 232 break; |
284 lastsize = size; | |
285 defVars.push_back(var); | |
286 } | 233 } |
287 } | 234 } |
288 } | 235 } |
289 | 236 |
290 { | 237 // fill in explicit initializers |
291 Logger::println("Build the default initializer"); | 238 n = si->vars.dim; |
292 LOG_SCOPE; | 239 for (size_t i = 0; i < n; i++) |
293 | 240 { |
294 lastoffset = 0; | 241 VarDeclaration* vd = (VarDeclaration*)si->vars.data[i]; |
295 lastsize = 0; | 242 Initializer* ini = (Initializer*)si->value.data[i]; |
296 | 243 |
297 // go through the default vars and build the default constant initializer | 244 size_t idx = datamap[i]; |
298 // adding zeros along the way to live up to alignment expectations | 245 |
299 size_t nvars = defVars.size(); | 246 if (data[idx].first != NULL) |
300 for (size_t i=0; i<nvars; i++) | 247 { |
301 { | 248 Loc l = ini ? ini->loc : si->loc; |
302 VarDeclaration* var = defVars[i]; | 249 error(l, "duplicate initialization of %s", vd->toChars()); |
303 | 250 continue; |
304 Logger::println("field %s %s = %s : +%u", var->type->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset); | 251 } |
305 | 252 |
306 // get offset and size | 253 data[idx].first = vd; |
307 size_t offset = var->offset; | 254 data[idx].second = get_default_initializer(vd, ini); |
308 size_t size = var->type->size(); | 255 } |
309 | 256 |
310 // is there space in between last last offset and this one? | 257 // build array of constants and try to fill in default initializers |
311 // if so, fill it with zeros | 258 // where there is room. |
312 if (offset > lastoffset+lastsize) | 259 size_t offset = 0; |
260 std::vector<llvm::Constant*> constants; | |
261 constants.reserve(16); | |
262 | |
263 n = data.size(); | |
264 for (size_t i = 0; i < n; i++) | |
265 { | |
266 VarDeclaration* vd = data[i].first; | |
267 | |
268 // explicitly initialized? | |
269 if (vd != NULL) | |
270 { | |
271 // get next aligned offset for this field | |
272 size_t alignedoffset = offset; | |
273 if (!packed) | |
313 { | 274 { |
314 size_t pos = lastoffset + lastsize; | 275 size_t alignsize = vd->type->alignsize(); |
315 addZeros(inits, pos, offset); | 276 alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); |
316 } | 277 } |
317 | 278 |
318 // add the field | 279 // insert explicit padding? |
319 // lazily default initialize | 280 if (alignedoffset < vd->offset) |
320 if (!var->ir.irField->constInit) | 281 { |
321 var->ir.irField->constInit = DtoConstInitializer(var->loc, var->type, var->init); | 282 add_zeros(constants, vd->offset - alignedoffset); |
322 inits.push_back(var->ir.irField->constInit); | 283 } |
323 | 284 |
324 lastoffset = offset; | 285 IF_LOG Logger::println("using field: %s", vd->toChars()); |
325 lastsize = var->type->size(); | 286 constants.push_back(data[i].second); |
326 } | 287 offset = vd->offset + vd->type->size(); |
327 | 288 } |
328 // there might still be padding after the last one, make sure that is zeroed as well | 289 // not explicit! try and fit in the default initialization instead |
329 // is there space in between last last offset and this one? | 290 // make sure we don't overlap with any following explicity initialized fields |
330 size_t structsize = getTypePaddedSize(structtype); | 291 else |
331 | 292 { |
332 if (structsize > lastoffset+lastsize) | 293 vd = (VarDeclaration*)aggrdecl->fields.data[i]; |
333 { | 294 |
334 size_t pos = lastoffset + lastsize; | 295 // check all the way that we don't overlap, slow but it works! |
335 addZeros(inits, pos, structsize); | 296 for (size_t j = i+1; j <= n; j++) |
336 } | 297 { |
337 } | 298 if (j == n) // no overlap |
338 } | 299 { |
339 | 300 IF_LOG Logger::println("using field default: %s", vd->toChars()); |
340 LLConstant* IrStruct::buildDefaultConstInit() | 301 constants.push_back(get_default_initializer(vd, NULL)); |
341 { | 302 offset = vd->offset + vd->type->size(); |
342 // doesn't work for classes, they add stuff before and maybe after data fields | 303 break; |
343 assert(!aggrdecl->isClassDeclaration()); | 304 } |
344 | 305 |
345 // initializer llvm constant list | 306 VarDeclaration* vd2 = (VarDeclaration*)aggrdecl->fields.data[j]; |
346 std::vector<LLConstant*> inits; | 307 |
347 | 308 size_t o2 = vd->offset + vd->type->size(); |
348 // just start with an empty list | 309 |
349 buildDefaultConstInit(inits); | 310 if (vd2->offset < o2 && data[i].first) |
350 | 311 break; // overlaps |
351 // build the constant | 312 } |
352 // note that the type matches the initializer, not the aggregate in cases with unions | 313 } |
353 LLConstant* c = LLConstantStruct::get(inits, aggrdecl->ir.irStruct->packed); | 314 } |
354 Logger::cout() << "llvm constant: " << *c << '\n'; | 315 |
355 // assert(0); | 316 // tail padding? |
317 if (offset < aggrdecl->structsize) | |
318 { | |
319 add_zeros(constants, aggrdecl->structsize - offset); | |
320 } | |
321 | |
322 // stop if there were errors | |
323 if (global.errors) | |
324 { | |
325 fatal(); | |
326 } | |
327 | |
328 // build constant | |
329 assert(!constants.empty()); | |
330 llvm::Constant* c = llvm::ConstantStruct::get(&constants[0], constants.size(), packed); | |
331 IF_LOG Logger::cout() << "final struct initializer: " << *c << std::endl; | |
356 return c; | 332 return c; |
357 } | 333 } |
334 |