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