Skip to content

Commit 3f38f97

Browse files
committed
Get rid of special 'typeid(...)' LL types for TypeInfos
Use the real LL type representing the TypeInfo (sub)class directly and from the beginning, i.e., already for the declaration, instead of building an extra LL struct type (firstly opaque, then finalized when defining the TypeInfo via RTTIBuilder). To get this to work in all cases, the dummy TypeInfo for opaque structs is now a complete TypeInfo_Struct, with all 11/13 fields zero- initialized. Previously, it was a special TypeInfo (no extra TypeInfo_Struct fields) with TypeInfo_Struct vtable, something which DMD also emits. Also refactor the RTTIBuilder finalize() interface - e.g., don't set the linkage there (had to be reverted for ModuleInfos) and only take the global variable to be defined. Cast the field initializers if required, e.g., null pointers to appropriately typed function pointers for TypeInfo_Struct etc.
1 parent 3d0a127 commit 3f38f97

File tree

5 files changed

+97
-76
lines changed

5 files changed

+97
-76
lines changed

gen/moduleinfo.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,6 @@ llvm::GlobalVariable *genModuleInfo(Module *m) {
310310

311311
// Create a global symbol with the above initialiser.
312312
LLGlobalVariable *moduleInfoSym = getIrModule(m)->moduleInfoSymbol();
313-
b.finalize(moduleInfoSym->getType()->getPointerElementType(), moduleInfoSym);
314-
setLinkage({LLGlobalValue::ExternalLinkage, false}, moduleInfoSym);
313+
b.finalize(moduleInfoSym);
315314
return moduleInfoSym;
316315
}

gen/rttibuilder.cpp

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -150,36 +150,35 @@ void RTTIBuilder::push_funcptr(FuncDeclaration *fd, Type *castto) {
150150
}
151151
}
152152

153-
void RTTIBuilder::finalize(IrGlobal *tid) {
154-
finalize(tid->getType(), tid->value);
155-
}
156-
157-
void RTTIBuilder::finalize(LLType *type, LLValue *value) {
158-
llvm::ArrayRef<LLConstant *> inits = llvm::makeArrayRef(this->inits);
159-
LLStructType *st = isaStruct(type);
153+
void RTTIBuilder::finalize(LLGlobalVariable *gvar) {
154+
LLStructType *st = isaStruct(gvar->getType()->getPointerElementType());
160155
assert(st);
161156

162-
// set struct body
157+
// finalize the type if opaque (e.g., for ModuleInfos)
163158
if (st->isOpaque()) {
164-
const int n = inits.size();
165-
std::vector<LLType *> types;
166-
types.reserve(n);
167-
for (int i = 0; i < n; ++i) {
168-
types.push_back(inits[i]->getType());
159+
std::vector<LLType *> fieldTypes;
160+
fieldTypes.reserve(inits.size());
161+
for (auto c : inits) {
162+
fieldTypes.push_back(c->getType());
169163
}
170-
st->setBody(types);
164+
st->setBody(fieldTypes);
171165
}
172166

173-
// create the inititalizer
174-
LLConstant *tiInit = LLConstantStruct::get(st, inits);
167+
// create the initializer
168+
LLConstant *tiInit = get_constant(st);
175169

176170
// set the initializer
177-
llvm::GlobalVariable *gvar = llvm::cast<llvm::GlobalVariable>(value);
178171
gvar->setInitializer(tiInit);
179-
setLinkage({TYPEINFO_LINKAGE_TYPE, supportsCOMDAT()}, gvar);
180172
}
181173

182174
LLConstant *RTTIBuilder::get_constant(LLStructType *initType) {
183-
// just return the inititalizer
184-
return LLConstantStruct::get(initType, inits);
175+
assert(initType->getNumElements() == inits.size());
176+
177+
std::vector<LLConstant *> castInits;
178+
castInits.reserve(inits.size());
179+
for (unsigned i = 0; i < inits.size(); ++i) {
180+
castInits.push_back(DtoBitCast(inits[i], initType->getElementType(i)));
181+
}
182+
183+
return LLConstantStruct::get(initType, castInits);
185184
}

gen/rttibuilder.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class Type;
2828
class TypeClass;
2929
namespace llvm {
3030
class StructType;
31+
class GlobalVariable;
3132
}
3233

3334
class RTTIBuilder {
@@ -79,8 +80,7 @@ class RTTIBuilder {
7980
Dsymbol *mangle_sym);
8081

8182
/// Creates the initializer constant and assigns it to the global.
82-
void finalize(IrGlobal *tid);
83-
void finalize(llvm::Type *type, llvm::Value *value);
83+
void finalize(llvm::GlobalVariable *gvar);
8484

8585
/// Creates the initializer constant and assigns it to the global.
8686
llvm::Constant *get_constant(llvm::StructType *initType);

gen/typinf.cpp

Lines changed: 69 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,11 @@ void DtoResolveTypeInfo(TypeInfoDeclaration *tid) {
128128
/* ========================================================================= */
129129

130130
class LLVMDefineVisitor : public Visitor {
131+
LLGlobalVariable *const gvar;
132+
131133
public:
134+
LLVMDefineVisitor(LLGlobalVariable *gvar) : gvar(gvar) {}
135+
132136
// Import all functions from class Visitor
133137
using Visitor::visit;
134138

@@ -140,7 +144,7 @@ class LLVMDefineVisitor : public Visitor {
140144
LOG_SCOPE;
141145

142146
RTTIBuilder b(Type::dtypeinfo);
143-
b.finalize(getIrGlobal(decl));
147+
b.finalize(gvar);
144148
}
145149

146150
/* ======================================================================= */
@@ -175,7 +179,7 @@ class LLVMDefineVisitor : public Visitor {
175179
}
176180

177181
// finish
178-
b.finalize(getIrGlobal(decl));
182+
b.finalize(gvar);
179183
}
180184

181185
/* ======================================================================= */
@@ -189,7 +193,7 @@ class LLVMDefineVisitor : public Visitor {
189193
// TypeInfo base
190194
b.push_typeinfo(decl->tinfo->nextOf());
191195
// finish
192-
b.finalize(getIrGlobal(decl));
196+
b.finalize(gvar);
193197
}
194198

195199
/* ======================================================================= */
@@ -203,7 +207,7 @@ class LLVMDefineVisitor : public Visitor {
203207
// TypeInfo base
204208
b.push_typeinfo(decl->tinfo->nextOf());
205209
// finish
206-
b.finalize(getIrGlobal(decl));
210+
b.finalize(gvar);
207211
}
208212

209213
/* ======================================================================= */
@@ -225,7 +229,7 @@ class LLVMDefineVisitor : public Visitor {
225229
b.push(DtoConstSize_t(static_cast<size_t>(tc->dim->toUInteger())));
226230

227231
// finish
228-
b.finalize(getIrGlobal(decl));
232+
b.finalize(gvar);
229233
}
230234

231235
/* ======================================================================= */
@@ -248,7 +252,7 @@ class LLVMDefineVisitor : public Visitor {
248252
b.push_typeinfo(tc->index);
249253

250254
// finish
251-
b.finalize(getIrGlobal(decl));
255+
b.finalize(gvar);
252256
}
253257

254258
/* ======================================================================= */
@@ -264,7 +268,7 @@ class LLVMDefineVisitor : public Visitor {
264268
// string deco
265269
b.push_string(decl->tinfo->deco);
266270
// finish
267-
b.finalize(getIrGlobal(decl));
271+
b.finalize(gvar);
268272
}
269273

270274
/* ======================================================================= */
@@ -283,7 +287,7 @@ class LLVMDefineVisitor : public Visitor {
283287
// string deco
284288
b.push_string(decl->tinfo->deco);
285289
// finish
286-
b.finalize(getIrGlobal(decl));
290+
b.finalize(gvar);
287291
}
288292

289293
/* ======================================================================= */
@@ -298,10 +302,44 @@ class LLVMDefineVisitor : public Visitor {
298302
TypeStruct *tc = static_cast<TypeStruct *>(decl->tinfo);
299303
StructDeclaration *sd = tc->sym;
300304

305+
// On x86_64, class TypeInfo_Struct contains 2 additional fields
306+
// (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs
307+
// implementation. They are not present on any other cpu/os.
308+
const bool isX86_64 =
309+
global.params.targetTriple->getArch() == llvm::Triple::x86_64;
310+
const unsigned expectedFields = 11 + (isX86_64 ? 2 : 0);
311+
const unsigned actualFields =
312+
Type::typeinfostruct->fields.dim -
313+
1; // union of xdtor/xdtorti counts as 2 overlapping fields
314+
if (actualFields != expectedFields) {
315+
error(Loc(), "Unexpected number of `object.TypeInfo_Struct` fields; "
316+
"druntime version does not match compiler");
317+
fatal();
318+
}
319+
320+
RTTIBuilder b(Type::typeinfostruct);
321+
301322
// handle opaque structs
302323
if (!sd->members) {
303-
RTTIBuilder b(Type::typeinfostruct);
304-
b.finalize(getIrGlobal(decl));
324+
Logger::println("is opaque struct, emitting dummy TypeInfo_Struct");
325+
326+
b.push_null_void_array(); // name
327+
b.push_null_void_array(); // m_init
328+
b.push_null_vp(); // xtoHash
329+
b.push_null_vp(); // xopEquals
330+
b.push_null_vp(); // xopCmp
331+
b.push_null_vp(); // xtoString
332+
b.push_uint(0); // m_flags
333+
b.push_null_vp(); // xdtor/xdtorti
334+
b.push_null_vp(); // xpostblit
335+
b.push_uint(0); // m_align
336+
if (isX86_64) {
337+
b.push_null_vp(); // m_arg1
338+
b.push_null_vp(); // m_arg2
339+
}
340+
b.push_null_vp(); // m_RTInfo
341+
342+
b.finalize(gvar);
305343
return;
306344
}
307345

@@ -343,19 +381,6 @@ class LLVMDefineVisitor : public Visitor {
343381
}
344382

345383
IrAggr *iraggr = getIrAggr(sd);
346-
RTTIBuilder b(Type::typeinfostruct);
347-
348-
// On x86_64, class TypeInfo_Struct contains 2 additional fields
349-
// (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs
350-
// implementation. They are not present on any other cpu/os.
351-
const bool isX86_64 =
352-
global.params.targetTriple->getArch() == llvm::Triple::x86_64;
353-
const unsigned expectedFields = 12 + (isX86_64 ? 2 : 0);
354-
if (Type::typeinfostruct->fields.dim != expectedFields) {
355-
error(Loc(), "Unexpected number of `object.TypeInfo_Struct` fields; "
356-
"druntime version does not match compiler");
357-
fatal();
358-
}
359384

360385
// string name
361386
b.push_string(sd->toPrettyChars());
@@ -432,7 +457,7 @@ class LLVMDefineVisitor : public Visitor {
432457
}
433458

434459
// finish
435-
b.finalize(getIrGlobal(decl));
460+
b.finalize(gvar);
436461
}
437462

438463
/* ======================================================================= */
@@ -461,7 +486,7 @@ class LLVMDefineVisitor : public Visitor {
461486
b.push_classinfo(tc->sym);
462487

463488
// finish
464-
b.finalize(getIrGlobal(decl));
489+
b.finalize(gvar);
465490
}
466491

467492
/* ======================================================================= */
@@ -495,7 +520,7 @@ class LLVMDefineVisitor : public Visitor {
495520
b.push_array(arrC, dim, Type::dtypeinfo->type, nullptr);
496521

497522
// finish
498-
b.finalize(getIrGlobal(decl));
523+
b.finalize(gvar);
499524
}
500525

501526
/* ======================================================================= */
@@ -509,7 +534,7 @@ class LLVMDefineVisitor : public Visitor {
509534
// TypeInfo base
510535
b.push_typeinfo(decl->tinfo->mutableOf()->merge());
511536
// finish
512-
b.finalize(getIrGlobal(decl));
537+
b.finalize(gvar);
513538
}
514539

515540
/* ======================================================================= */
@@ -523,7 +548,7 @@ class LLVMDefineVisitor : public Visitor {
523548
// TypeInfo base
524549
b.push_typeinfo(decl->tinfo->mutableOf()->merge());
525550
// finish
526-
b.finalize(getIrGlobal(decl));
551+
b.finalize(gvar);
527552
}
528553

529554
/* ======================================================================= */
@@ -537,7 +562,7 @@ class LLVMDefineVisitor : public Visitor {
537562
// TypeInfo base
538563
b.push_typeinfo(decl->tinfo->unSharedOf()->merge());
539564
// finish
540-
b.finalize(getIrGlobal(decl));
565+
b.finalize(gvar);
541566
}
542567

543568
/* ======================================================================= */
@@ -551,7 +576,7 @@ class LLVMDefineVisitor : public Visitor {
551576
// TypeInfo base
552577
b.push_typeinfo(decl->tinfo->mutableOf()->merge());
553578
// finish
554-
b.finalize(getIrGlobal(decl));
579+
b.finalize(gvar);
555580
}
556581

557582
/* ======================================================================= */
@@ -568,7 +593,7 @@ class LLVMDefineVisitor : public Visitor {
568593
// TypeInfo base
569594
b.push_typeinfo(tv->basetype);
570595
// finish
571-
b.finalize(getIrGlobal(decl));
596+
b.finalize(gvar);
572597
}
573598
};
574599

@@ -594,29 +619,22 @@ void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p) {
594619
}
595620

596621
const auto irMangle = getIRMangledVarName(mangled, LINKd);
597-
IrGlobal *irg = getIrGlobal(decl, true);
598-
const LinkageWithCOMDAT lwc(LLGlobalValue::ExternalLinkage, false);
599-
600-
irg->value = gIR->module.getGlobalVariable(irMangle);
601-
if (irg->value) {
602-
assert(irg->getType()->isStructTy());
622+
LLGlobalVariable *gvar = gIR->module.getGlobalVariable(irMangle);
623+
if (gvar) {
624+
assert(gvar->getType()->getContainedType(0)->isStructTy());
603625
} else {
604-
LLType *type;
605-
if (builtinTypeInfo(
606-
decl->tinfo)) { // this is a declaration of a builtin __initZ var
607-
type = Type::dtypeinfo->type->ctype->isClass()->getMemoryLLType();
608-
} else {
609-
type = LLStructType::create(gIR->context(), decl->toPrettyChars());
610-
}
626+
LLType *type = DtoType(decl->type)->getPointerElementType();
611627
// Create the symbol. We need to keep it mutable as the type is not declared
612628
// as immutable on the D side, and e.g. synchronized() can be used on the
613629
// implicit monitor.
614-
auto g = new LLGlobalVariable(gIR->module, type, false, lwc.first,
615-
nullptr, irMangle);
616-
setLinkage(lwc, g);
617-
irg->value = g;
630+
gvar =
631+
new LLGlobalVariable(gIR->module, type, false,
632+
LLGlobalValue::ExternalLinkage, nullptr, irMangle);
618633
}
619634

635+
IrGlobal *irg = getIrGlobal(decl, true);
636+
irg->value = gvar;
637+
620638
emitTypeMetadata(decl);
621639

622640
// check if the definition can be elided
@@ -626,8 +644,10 @@ void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p) {
626644
}
627645

628646
// define the TypeInfo global
629-
LLVMDefineVisitor v;
647+
LLVMDefineVisitor v(gvar);
630648
decl->accept(&v);
649+
650+
setLinkage({TYPEINFO_LINKAGE_TYPE, supportsCOMDAT()}, gvar);
631651
}
632652

633653
/* ========================================================================= */

tests/codegen/static_typeid_gh1540.d

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ struct S
1515
{
1616
}
1717

18-
// CHECK: _D{{.*}}classvarC14TypeInfo_Class{{\"?}} = thread_local global %object.TypeInfo_Class* {{.*}}1C7__ClassZ
18+
// CHECK-DAG: _D{{.*}}1C7__ClassZ{{\"?}} = global %object.TypeInfo_Class
19+
// CHECK-DAG: _D{{.*}}classvarC14TypeInfo_Class{{\"?}} = thread_local global %object.TypeInfo_Class* {{.*}}1C7__ClassZ
1920
auto classvar = typeid(C);
2021

21-
// CHECK: _D{{.*}}interfacevarC18TypeInfo_Interface{{\"?}} = thread_local global %object.TypeInfo_Interface* {{.*}}TypeInfo_C{{.*}}1I6__initZ
22+
// CHECK-DAG: _D{{.*}}TypeInfo_C{{.*}}1I6__initZ{{\"?}} = linkonce_odr global %object.TypeInfo_Interface
23+
// CHECK-DAG: _D{{.*}}interfacevarC18TypeInfo_Interface{{\"?}} = thread_local global %object.TypeInfo_Interface* {{.*}}TypeInfo_C{{.*}}1I6__initZ
2224
auto interfacevar = typeid(I);
2325

24-
// CHECK: _D{{.*}}structvarC15TypeInfo_Struct{{\"?}} = thread_local global %object.TypeInfo_Struct* {{.*}}TypeInfo_S{{.*}}1S6__initZ
26+
// CHECK-DAG: _D{{.*}}TypeInfo_S{{.*}}1S6__initZ{{\"?}} = linkonce_odr global %object.TypeInfo_Struct
27+
// CHECK-DAG: _D{{.*}}structvarC15TypeInfo_Struct{{\"?}} = thread_local global %object.TypeInfo_Struct* {{.*}}TypeInfo_S{{.*}}1S6__initZ
2528
auto structvar = typeid(S);

0 commit comments

Comments
 (0)