Mercurial > projects > ldc
comparison ir/irtypeclass.cpp @ 1270:dd135ff697fa
Fixed class default initializers and type generation. Bug #260 is fixed.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail com> |
---|---|
date | Mon, 27 Apr 2009 03:40:40 +0200 |
parents | bbe6d2b87842 |
children | 8fb39f7f1a7c |
comparison
equal
deleted
inserted
replaced
1269:b8a51aa44d4c | 1270:dd135ff697fa |
---|---|
12 #include "ir/irtypeclass.h" | 12 #include "ir/irtypeclass.h" |
13 | 13 |
14 ////////////////////////////////////////////////////////////////////////////// | 14 ////////////////////////////////////////////////////////////////////////////// |
15 | 15 |
16 extern size_t add_zeros(std::vector<const llvm::Type*>& defaultTypes, size_t diff); | 16 extern size_t add_zeros(std::vector<const llvm::Type*>& defaultTypes, size_t diff); |
17 extern bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2); | |
17 | 18 |
18 ////////////////////////////////////////////////////////////////////////////// | 19 ////////////////////////////////////////////////////////////////////////////// |
19 | 20 |
20 IrTypeClass::IrTypeClass(ClassDeclaration* cd) | 21 IrTypeClass::IrTypeClass(ClassDeclaration* cd) |
21 : IrTypeAggr(cd), | 22 : IrTypeAggr(cd), |
38 if (base->baseClass) | 39 if (base->baseClass) |
39 { | 40 { |
40 addBaseClassData(defaultTypes, base->baseClass, offset, field_index); | 41 addBaseClassData(defaultTypes, base->baseClass, offset, field_index); |
41 } | 42 } |
42 | 43 |
43 ArrayIter<VarDeclaration> it(base->fields); | 44 // FIXME: merge code with structs in IrTypeAggr |
44 for (; !it.done(); it.next()) | 45 |
45 { | 46 // mirror the sd->fields array but only fill in contributors |
46 VarDeclaration* vd = it.get(); | 47 size_t n = base->fields.dim; |
47 | 48 LLSmallVector<VarDeclaration*, 16> data(n, NULL); |
48 // skip if offset moved backwards | 49 default_fields.reserve(n); |
49 if (vd->offset < offset) | 50 |
50 { | 51 // first fill in the fields with explicit initializers |
51 IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset); | 52 VarDeclarationIter field_it(base->fields); |
52 if (vd->ir.irField == NULL) | 53 for (; field_it.more(); field_it.next()) |
54 { | |
55 // init is !null for explicit inits | |
56 if (field_it->init != NULL) | |
57 { | |
58 IF_LOG Logger::println("adding explicit initializer for struct field %s", | |
59 field_it->toChars()); | |
60 | |
61 data[field_it.index] = *field_it; | |
62 | |
63 size_t f_begin = field_it->offset; | |
64 size_t f_end = f_begin + field_it->type->size(); | |
65 | |
66 // make sure there is no overlap | |
67 for (size_t i = 0; i < field_it.index; i++) | |
53 { | 68 { |
54 new IrField(vd, 2, vd->offset - PTRSIZE * 2); | 69 if (data[i] != NULL) |
70 { | |
71 VarDeclaration* vd = data[i]; | |
72 size_t v_begin = vd->offset; | |
73 size_t v_end = v_begin + vd->type->size(); | |
74 | |
75 if (v_begin >= f_end || v_end <= f_begin) | |
76 continue; | |
77 | |
78 base->error(vd->loc, "has overlapping initialization for %s and %s", | |
79 field_it->toChars(), vd->toChars()); | |
80 } | |
55 } | 81 } |
82 } | |
83 } | |
84 | |
85 if (global.errors) | |
86 { | |
87 fatal(); | |
88 } | |
89 | |
90 // fill in default initializers | |
91 field_it = VarDeclarationIter(base->fields); | |
92 for (;field_it.more(); field_it.next()) | |
93 { | |
94 if (data[field_it.index]) | |
56 continue; | 95 continue; |
57 } | 96 |
58 | 97 size_t f_begin = field_it->offset; |
59 IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); | 98 size_t f_end = f_begin + field_it->type->size(); |
99 | |
100 // make sure it doesn't overlap anything explicit | |
101 bool overlaps = false; | |
102 for (size_t i = 0; i < n; i++) | |
103 { | |
104 if (data[i]) | |
105 { | |
106 size_t v_begin = data[i]->offset; | |
107 size_t v_end = v_begin + data[i]->type->size(); | |
108 | |
109 if (v_begin >= f_end || v_end <= f_begin) | |
110 continue; | |
111 | |
112 overlaps = true; | |
113 break; | |
114 } | |
115 } | |
116 | |
117 // if no overlap was found, add the default initializer | |
118 if (!overlaps) | |
119 { | |
120 IF_LOG Logger::println("adding default initializer for struct field %s", | |
121 field_it->toChars()); | |
122 data[field_it.index] = *field_it; | |
123 } | |
124 } | |
125 | |
126 // ok. now we can build a list of llvm types. and make sure zeros are inserted if necessary. | |
127 | |
128 // first we sort the list by offset | |
129 std::sort(data.begin(), data.end(), var_offset_sort_cb); | |
130 | |
131 // add types to list | |
132 for (size_t i = 0; i < n; i++) | |
133 { | |
134 VarDeclaration* vd = data[i]; | |
135 | |
136 if (vd == NULL) | |
137 continue; | |
138 | |
139 assert(vd->offset >= offset && "it's a bug..."); | |
140 | |
141 // add to default field list | |
142 if (cd == base) | |
143 default_fields.push_back(vd); | |
60 | 144 |
61 // get next aligned offset for this type | 145 // get next aligned offset for this type |
62 size_t alignsize = vd->type->alignsize(); | 146 size_t alignsize = vd->type->alignsize(); |
63 size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); | 147 size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); |
64 | 148 |
65 // do we need to insert explicit padding before the field? | 149 // insert explicit padding? |
66 if (alignedoffset < vd->offset) | 150 if (alignedoffset < vd->offset) |
67 { | 151 { |
68 field_index += add_zeros(defaultTypes, vd->offset - alignedoffset); | 152 field_index += add_zeros(defaultTypes, vd->offset - alignedoffset); |
69 } | 153 } |
70 | 154 |
72 defaultTypes.push_back(DtoType(vd->type)); | 156 defaultTypes.push_back(DtoType(vd->type)); |
73 | 157 |
74 // advance offset to right past this field | 158 // advance offset to right past this field |
75 offset = vd->offset + vd->type->size(); | 159 offset = vd->offset + vd->type->size(); |
76 | 160 |
77 // give field index | 161 // create ir field |
78 // the IrField creation doesn't really belong here, but it's a trivial operation | |
79 // and it save yet another of these loops. | |
80 IF_LOG Logger::println("Field index: %zu", field_index); | |
81 if (vd->ir.irField == NULL) | 162 if (vd->ir.irField == NULL) |
82 { | |
83 new IrField(vd, field_index); | 163 new IrField(vd, field_index); |
84 } | 164 else |
165 assert(vd->ir.irField->index == field_index && | |
166 vd->ir.irField->unionOffset == 0 && | |
167 "inconsistent field data"); | |
85 field_index++; | 168 field_index++; |
86 } | 169 } |
87 | 170 |
171 // make sure all fields really get their ir field | |
172 ArrayIter<VarDeclaration> it(base->fields); | |
173 for (; !it.done(); it.next()) | |
174 { | |
175 VarDeclaration* vd = it.get(); | |
176 if (vd->ir.irField == NULL) | |
177 new IrField(vd, 0, vd->offset); | |
178 } | |
179 | |
88 // any interface implementations? | 180 // any interface implementations? |
89 if (base->vtblInterfaces) | 181 if (base->vtblInterfaces && base->vtblInterfaces->dim > 0) |
90 { | 182 { |
91 bool new_instances = (base == cd); | 183 bool new_instances = (base == cd); |
92 | 184 |
93 ArrayIter<BaseClass> it2(*base->vtblInterfaces); | 185 ArrayIter<BaseClass> it2(*base->vtblInterfaces); |
94 | 186 |
95 VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); | 187 VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); |
96 Type* first = interfaces_idx->type->next->pointerTo(); | 188 Type* first = interfaces_idx->type->next->pointerTo(); |
189 | |
190 // align offset | |
191 offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1); | |
97 | 192 |
98 for (; !it2.done(); it2.next()) | 193 for (; !it2.done(); it2.next()) |
99 { | 194 { |
100 BaseClass* b = it2.get(); | 195 BaseClass* b = it2.get(); |
101 IF_LOG Logger::println("Adding interface vtbl for %s", b->base->toPrettyChars()); | 196 IF_LOG Logger::println("Adding interface vtbl for %s", b->base->toPrettyChars()); |
115 // inc count | 210 // inc count |
116 num_interface_vtbls++; | 211 num_interface_vtbls++; |
117 } | 212 } |
118 } | 213 } |
119 | 214 |
215 #if 0 | |
120 // tail padding? | 216 // tail padding? |
121 if (offset < base->structsize) | 217 if (offset < base->structsize) |
122 { | 218 { |
123 field_index += add_zeros(defaultTypes, base->structsize - offset); | 219 field_index += add_zeros(defaultTypes, base->structsize - offset); |
124 offset = base->structsize; | 220 offset = base->structsize; |
125 } | 221 } |
222 #endif | |
126 } | 223 } |
127 | 224 |
128 ////////////////////////////////////////////////////////////////////////////// | 225 ////////////////////////////////////////////////////////////////////////////// |
129 | 226 |
130 const llvm::Type* IrTypeClass::buildType() | 227 const llvm::Type* IrTypeClass::buildType() |
157 size_t offset = PTRSIZE * 2; | 254 size_t offset = PTRSIZE * 2; |
158 size_t field_index = 2; | 255 size_t field_index = 2; |
159 | 256 |
160 // add data members recursively | 257 // add data members recursively |
161 addBaseClassData(defaultTypes, cd, offset, field_index); | 258 addBaseClassData(defaultTypes, cd, offset, field_index); |
259 | |
260 #if 1 | |
261 // tail padding? | |
262 if (offset < cd->structsize) | |
263 { | |
264 field_index += add_zeros(defaultTypes, cd->structsize - offset); | |
265 offset = cd->structsize; | |
266 } | |
267 #endif | |
162 } | 268 } |
163 | 269 |
164 // errors are fatal during codegen | 270 // errors are fatal during codegen |
165 if (global.errors) | 271 if (global.errors) |
166 fatal(); | 272 fatal(); |