Wiki Roadmap Timeline Tickets New Ticket Source Search Help / Guide About Trac Login

root/gen/structs.cpp

Revision 1571:8d086d552909, 12.0 kB (checked in by Benjamin Kramer <benny.kra@gmail.com>, 3 years ago)

IntegerType? is now contextifed.

Requires llvm >= 78969. resistor says this will be the last context API change :)

Line 
1 #include <algorithm>
2
3 #include "gen/llvm.h"
4 #include "llvm/AbstractTypeUser.h"
5 #include "llvm/ADT/DenseMap.h"
6
7 #include "mtype.h"
8 #include "aggregate.h"
9 #include "init.h"
10 #include "declaration.h"
11
12 #include "gen/irstate.h"
13 #include "gen/tollvm.h"
14 #include "gen/llvmhelpers.h"
15 #include "gen/arrays.h"
16 #include "gen/logger.h"
17 #include "gen/structs.h"
18 #include "gen/dvalue.h"
19 #include "gen/functions.h"
20 #include "gen/utils.h"
21
22 #include "ir/irstruct.h"
23 #include "ir/irtypestruct.h"
24
25 //////////////////////////////////////////////////////////////////////////////////////////
26
27 void DtoResolveStruct(StructDeclaration* sd)
28 {
29     // don't do anything if already been here
30     if (sd->ir.resolved) return;
31     // make sure above works :P
32     sd->ir.resolved = true;
33
34     // log what we're doing
35     Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->loc.toChars());
36     LOG_SCOPE;
37
38     // make sure type exists
39     DtoType(sd->type);
40
41     // if it's a forward declaration, all bets are off. The type should be enough
42     if (sd->sizeok != 1)
43         return;
44
45     // create the IrStruct
46     IrStruct* irstruct = new IrStruct(sd);
47     sd->ir.irStruct = irstruct;
48
49     // make sure all fields really get their ir field
50     ArrayIter<VarDeclaration> it(sd->fields);
51     for (; !it.done(); it.next())
52     {
53         VarDeclaration* vd = it.get();
54         if (vd->ir.irField == NULL) {
55             new IrField(vd);
56         } else {
57             IF_LOG Logger::println("struct field already exists!!!");
58         }
59     }
60
61     // perform definition
62     bool needs_def = mustDefineSymbol(sd);
63     if (needs_def)
64     {
65         // emit the initZ symbol
66         LLGlobalVariable* initZ = irstruct->getInitSymbol();
67
68         // set initZ initializer
69         initZ->setInitializer(irstruct->getDefaultInit());
70     }
71
72     // emit members
73     if (sd->members)
74     {
75         ArrayIter<Dsymbol> it(*sd->members);
76         while (!it.done())
77         {
78             Dsymbol* member = it.get();
79             if (member)
80                 member->codegen(Type::sir);
81             it.next();
82         }
83     }
84
85     if (needs_def)
86     {
87         // emit typeinfo
88         DtoTypeInfoOf(sd->type);
89     }
90 }
91
92 //////////////////////////////////////////////////////////////////////////////////////////
93 ////////////////////////////   D STRUCT UTILITIES     ////////////////////////////////////
94 //////////////////////////////////////////////////////////////////////////////////////////
95
96 LLValue* DtoStructEquals(TOK op, DValue* lhs, DValue* rhs)
97 {
98     Type* t = lhs->getType()->toBasetype();
99     assert(t->ty == Tstruct);
100
101     // set predicate
102     llvm::ICmpInst::Predicate cmpop;
103     if (op == TOKequal || op == TOKidentity)
104         cmpop = llvm::ICmpInst::ICMP_EQ;
105     else
106         cmpop = llvm::ICmpInst::ICMP_NE;
107
108     // call memcmp
109     size_t sz = getTypePaddedSize(DtoType(t));
110     LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz));
111     return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp");
112 }
113
114 //////////////////////////////////////////////////////////////////////////////////////////
115
116 LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd)
117 {
118     Logger::println("indexing struct field %s:", vd->toPrettyChars());
119     LOG_SCOPE;
120
121     DtoResolveStruct(sd);
122
123     // vd must be a field
124     IrField* field = vd->ir.irField;
125     assert(field);
126
127     // get the start pointer
128     const LLType* st = getPtrToType(DtoType(sd->type));
129
130     // cast to the formal struct type
131     src = DtoBitCast(src, st);
132
133     // gep to the index
134     LLValue* val = DtoGEPi(src, 0, field->index);
135
136     // do we need to offset further? (union area)
137     if (field->unionOffset)
138     {
139         // cast to void*
140         val = DtoBitCast(val, getVoidPtrType());
141         // offset
142         val = DtoGEPi1(val, field->unionOffset);
143     }
144
145     // cast it to the right type
146     val = DtoBitCast(val, getPtrToType(DtoType(vd->type)));
147
148     if (Logger::enabled())
149         Logger::cout() << "value: " << *val << '\n';
150
151     return val;
152 }
153
154 //////////////////////////////////////////////////////////////////////////////////////////
155
156 // helper function that adds zero bytes to a vector of constants
157 size_t add_zeros(std::vector<llvm::Value*>& values, size_t diff)
158 {
159     size_t n = values.size();
160     bool is64 = global.params.is64bit;
161     while (diff)
162     {
163         if (is64 && diff % 8 == 0)
164         {
165             values.push_back(LLConstant::getNullValue(llvm::Type::getInt64Ty(gIR->context())));
166             diff -= 8;
167         }
168         else if (diff % 4 == 0)
169         {
170             values.push_back(LLConstant::getNullValue(llvm::Type::getInt32Ty(gIR->context())));
171             diff -= 4;
172         }
173         else if (diff % 2 == 0)
174         {
175             values.push_back(LLConstant::getNullValue(llvm::Type::getInt16Ty(gIR->context())));
176             diff -= 2;
177         }
178         else
179         {
180             values.push_back(LLConstant::getNullValue(llvm::Type::getInt8Ty(gIR->context())));
181             diff -= 1;
182         }
183     }
184     return values.size() - n;
185 }
186
187 std::vector<llvm::Value*> DtoStructLiteralValues(const StructDeclaration* sd, const std::vector<llvm::Value*>& inits)
188 {
189     // get arrays
190     size_t nvars = sd->fields.dim;
191     VarDeclaration** vars = (VarDeclaration**)sd->fields.data;
192
193     assert(inits.size() == nvars);
194
195     // first locate all explicit initializers
196     std::vector<VarDeclaration*> explicitInits;
197     for (size_t i=0; i < nvars; i++)
198     {
199         if (inits[i])
200         {
201             explicitInits.push_back(vars[i]);
202         }
203     }
204
205     // vector of values to build aggregate from
206     std::vector<llvm::Value*> values;
207
208     // offset trackers
209     size_t lastoffset = 0;
210     size_t lastsize = 0;
211
212     // index of next explicit init
213     size_t exidx = 0;
214     // number of explicit inits
215     size_t nex = explicitInits.size();
216
217     // for through each field and build up the struct, padding with zeros
218     size_t i;
219     for (i=0; i<nvars; i++)
220     {
221         VarDeclaration* var = vars[i];
222
223         // get var info
224         size_t os = var->offset;
225         size_t sz = var->type->size();
226
227         // get next explicit
228         VarDeclaration* nextVar = NULL;
229         size_t nextOs = 0;
230         if (exidx < nex)
231         {
232             nextVar = explicitInits[exidx];
233             nextOs = nextVar->offset;
234         }
235         // none, rest is defaults
236         else
237         {
238             break;
239         }
240
241         // not explicit initializer, default initialize if there is room, otherwise skip
242         if (!inits[i])
243         {
244             // default init if there is room
245             // (past current offset) and (small enough to fit before next explicit)
246             if ((os >= lastoffset + lastsize) && (os+sz <= nextOs))
247             {
248                 // add any 0 padding needed before this field
249                 if (os > lastoffset + lastsize)
250                 {
251                     //printf("1added %lu zeros\n", os - lastoffset - lastsize);
252                     add_zeros(values, os - lastoffset - lastsize);
253                 }
254
255                 // get field default init
256                 IrField* f = var->ir.irField;
257                 assert(f);
258                 values.push_back(f->getDefaultInit());
259
260                 lastoffset = os;
261                 lastsize = sz;
262                 //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
263             }
264             // skip
265             continue;
266         }
267
268         assert(nextVar == var);
269
270         // add any 0 padding needed before this field
271         if (os > lastoffset + lastsize)
272         {
273             //printf("added %lu zeros\n", os - lastoffset - lastsize);
274             add_zeros(values, os - lastoffset - lastsize);
275         }
276
277         // add the expression value
278         values.push_back(inits[i]);
279
280         // update offsets
281         lastoffset = os;
282         lastsize = sz;
283
284         // go to next explicit init
285         exidx++;
286
287         //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz);
288     }
289
290     // fill out rest with default initializers
291     const LLType* structtype = DtoType(sd->type);
292     size_t structsize = getTypePaddedSize(structtype);
293
294     // FIXME: this could probably share some code with the above
295     if (structsize > lastoffset+lastsize)
296     {
297         for (/*continue from first loop*/; i < nvars; i++)
298         {
299             VarDeclaration* var = vars[i];
300
301             // get var info
302             size_t os = var->offset;
303             size_t sz = var->type->size();
304
305             // skip?
306             if (os < lastoffset + lastsize)
307                 continue;
308
309             // add any 0 padding needed before this field
310             if (os > lastoffset + lastsize)
311             {
312                 //printf("2added %lu zeros\n", os - lastoffset - lastsize);
313                 add_zeros(values, os - lastoffset - lastsize);
314             }
315
316             // get field default init
317             IrField* f = var->ir.irField;
318             assert(f);
319             values.push_back(f->getDefaultInit());
320
321             lastoffset = os;
322             lastsize = sz;
323             //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
324         }
325     }
326
327     // add any 0 padding needed at the end of the literal
328     if (structsize > lastoffset+lastsize)
329     {
330         //printf("3added %lu zeros\n", structsize - lastoffset - lastsize);
331         add_zeros(values, structsize - lastoffset - lastsize);
332     }
333
334     return values;
335 }
336
337 /// Return the type returned by DtoUnpaddedStruct called on a value of the
338 /// specified type.
339 /// Union types will get expanded into a struct, with a type for each member.
340 LLType* DtoUnpaddedStructType(Type* dty) {
341     assert(dty->ty == Tstruct);
342    
343     typedef llvm::DenseMap<Type*, llvm::PATypeHolder> CacheT;
344     static CacheT cache;
345     CacheT::iterator it = cache.find(dty);
346     if (it != cache.end())
347         return it->second;
348    
349     TypeStruct* sty = (TypeStruct*) dty;
350     Array& fields = sty->sym->fields;
351
352     std::vector<const LLType*> types;
353
354     for (unsigned i = 0; i < fields.dim; i++) {
355         VarDeclaration* vd = (VarDeclaration*) fields.data[i];
356         const LLType* fty;
357         if (vd->type->ty == Tstruct) {
358             // Nested structs are the only members that can contain padding
359             fty = DtoUnpaddedStructType(vd->type);
360         } else {
361             fty = DtoType(vd->type);
362         }
363         types.push_back(fty);
364     }
365     LLType* Ty = LLStructType::get(gIR->context(), types);
366     cache.insert(std::make_pair(dty, Ty));
367     return Ty;
368 }
369
370 /// Return the struct value represented by v without the padding fields.
371 /// Unions will be expanded, with a value for each member.
372 /// Note: v must be a pointer to a struct, but the return value will be a
373 ///       first-class struct value.
374 LLValue* DtoUnpaddedStruct(Type* dty, LLValue* v) {
375     assert(dty->ty == Tstruct);
376     TypeStruct* sty = (TypeStruct*) dty;
377     Array& fields = sty->sym->fields;
378    
379     LLValue* newval = llvm::UndefValue::get(DtoUnpaddedStructType(dty));
380    
381     for (unsigned i = 0; i < fields.dim; i++) {
382         VarDeclaration* vd = (VarDeclaration*) fields.data[i];
383         LLValue* fieldptr = DtoIndexStruct(v, sty->sym, vd);
384         LLValue* fieldval;
385         if (vd->type->ty == Tstruct) {
386             // Nested structs are the only members that can contain padding
387             fieldval = DtoUnpaddedStruct(vd->type, fieldptr);
388         } else {
389             fieldval = DtoLoad(fieldptr);
390         }
391         newval = DtoInsertValue(newval, fieldval, i);
392     }
393     return newval;
394 }
395
396 /// Undo the transformation performed by DtoUnpaddedStruct, writing to lval.
397 void DtoPaddedStruct(Type* dty, LLValue* v, LLValue* lval) {
398     assert(dty->ty == Tstruct);
399     TypeStruct* sty = (TypeStruct*) dty;
400     Array& fields = sty->sym->fields;
401    
402     for (unsigned i = 0; i < fields.dim; i++) {
403         VarDeclaration* vd = (VarDeclaration*) fields.data[i];
404         LLValue* fieldptr = DtoIndexStruct(lval, sty->sym, vd);
405         LLValue* fieldval = DtoExtractValue(v, i);
406         if (vd->type->ty == Tstruct) {
407             // Nested structs are the only members that can contain padding
408             DtoPaddedStruct(vd->type, fieldval, fieldptr);
409         } else {
410             DtoStore(fieldval, fieldptr);
411         }
412     }
413 }
Note: See TracBrowser for help on using the browser.
Copyright © 2008, LDC Development Team.