[pkg-d-commits] [ldc] 154/211: Use opaque [N x i8*] for vtables
Matthias Klumpp
mak at moszumanska.debian.org
Sun Apr 23 22:36:19 UTC 2017
This is an automated email from the git hooks/post-receive script.
mak pushed a commit to annotated tag v1.1.0
in repository ldc.
commit 16d15e01cb94d86c357e4b0350f6117794ad9672
Author: Martin <noone at nowhere.com>
Date: Sat Nov 5 19:14:46 2016 +0100
Use opaque [N x i8*] for vtables
This fixes the forward-referencing issue #1741.
---
gen/classes.cpp | 5 +-
gen/toir.cpp | 6 ++-
ir/irclass.cpp | 45 +++++++-----------
ir/irtypeclass.cpp | 87 ++--------------------------------
ir/irtypeclass.h | 17 +------
tests/codegen/in_place_construct_asm.d | 1 +
tests/compilable/gh1741.d | 13 +++++
tests/compilable/inputs/gh1741b.d | 3 ++
8 files changed, 46 insertions(+), 131 deletions(-)
diff --git a/gen/classes.cpp b/gen/classes.cpp
index 6fef7a6..2fc6b32 100644
--- a/gen/classes.cpp
+++ b/gen/classes.cpp
@@ -390,7 +390,6 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl,
LLValue *funcval = vthis;
// get the vtbl for objects
- stripModifiers(inst->type->toBasetype())->ctype->isClass()->getVtblType(true);
funcval = DtoGEPi(funcval, 0, 0);
// load vtbl ptr
funcval = DtoLoad(funcval);
@@ -398,12 +397,12 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl,
std::string vtblname = name;
vtblname.append("@vtbl");
funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, vtblname.c_str());
- // load funcptr
+ // load opaque pointer
funcval = DtoAlignedLoad(funcval);
IF_LOG Logger::cout() << "funcval: " << *funcval << '\n';
- // cast to final funcptr type
+ // cast to funcptr type
funcval = DtoBitCast(funcval, getPtrToType(DtoFunctionType(fdecl)));
// postpone naming until after casting to get the name in call instructions
diff --git a/gen/toir.cpp b/gen/toir.cpp
index 22402bf..c6ecd29 100644
--- a/gen/toir.cpp
+++ b/gen/toir.cpp
@@ -2664,13 +2664,12 @@ public:
LLValue *val = DtoRVal(ex);
// Get and load vtbl pointer.
- stripModifiers(t)->ctype->isClass()->getVtblType(true);
llvm::Value *vtbl = DtoLoad(DtoGEPi(val, 0, 0));
// TypeInfo ptr is first vtbl entry.
llvm::Value *typinf = DtoGEPi(vtbl, 0, 0);
- Type *resultType = Type::typeinfoclass->type;
+ Type *resultType;
if (static_cast<TypeClass *>(t)->sym->isInterfaceDeclaration()) {
// For interfaces, the first entry in the vtbl is actually a pointer
// to an Interface instance, which has the type info as its first
@@ -2678,6 +2677,9 @@ public:
resultType = Type::typeinfointerface->type;
typinf = DtoLoad(
DtoBitCast(typinf, DtoType(resultType->pointerTo()->pointerTo())));
+ } else {
+ resultType = Type::typeinfoclass->type;
+ typinf = DtoBitCast(typinf, DtoType(resultType->pointerTo()));
}
result = new DLValue(resultType, typinf);
diff --git a/ir/irclass.cpp b/ir/irclass.cpp
index aaab098..42fb198 100644
--- a/ir/irclass.cpp
+++ b/ir/irclass.cpp
@@ -49,7 +49,7 @@ LLGlobalVariable *IrAggr::getVtblSymbol() {
// create the vtblZ symbol
auto initname = getMangledVTableSymbolName(aggrdecl);
- LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtblType(false);
+ LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtblType();
vtbl =
getOrCreateGlobal(aggrdecl->loc, gIR->module, vtblTy, true,
@@ -165,11 +165,13 @@ LLConstant *IrAggr::getVtblInit() {
std::vector<llvm::Constant *> constants;
constants.reserve(cd->vtbl.dim);
+ const auto voidPtrType = getVoidPtrType();
+
// start with the classinfo
llvm::Constant *c;
if (!cd->isCPPclass()) {
c = getClassInfoSymbol();
- c = DtoBitCast(c, DtoType(Type::typeinfoclass->type));
+ c = DtoBitCast(c, voidPtrType);
constants.push_back(c);
}
@@ -220,26 +222,12 @@ LLConstant *IrAggr::getVtblInit() {
}
}
}
- constants.push_back(c);
+ constants.push_back(DtoBitCast(c, voidPtrType));
}
- // build the constant struct
- LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtblType(true);
-#ifndef NDEBUG
- size_t nc = constants.size();
-
- for (size_t i = 0; i < nc; ++i) {
- if (constants[i]->getType() != vtblTy->getContainedType(i)) {
- llvm::errs() << "type mismatch for entry # " << i
- << " in vtbl initializer\n";
-
- constants[i]->getType()->dump();
- vtblTy->getContainedType(i)->dump();
- }
- }
-
-#endif
- constVtbl = LLConstantStruct::get(isaStruct(vtblTy), constants);
+ // build the constant array
+ LLArrayType *vtblTy = LLArrayType::get(voidPtrType, constants.size());
+ constVtbl = LLConstantArray::get(vtblTy, constants);
return constVtbl;
}
@@ -277,6 +265,8 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
std::vector<llvm::Constant *> constants;
constants.reserve(vtbl_array.dim);
+ const auto voidPtrTy = getVoidPtrType();
+
if (!b->sym->isCPPinterface()) { // skip interface info for CPP interfaces
// index into the interfaces array
llvm::Constant *idxs[2] = {DtoConstSize_t(0),
@@ -289,7 +279,7 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
#endif
interfaceInfosZ, idxs, true);
- constants.push_back(c);
+ constants.push_back(DtoBitCast(c, voidPtrTy));
}
// Thunk prefix
@@ -306,7 +296,7 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
// FIXME
// why is this null?
// happens for mini/s.d
- constants.push_back(getNullValue(getVoidPtrType()));
+ constants.push_back(getNullValue(voidPtrTy));
continue;
}
@@ -327,7 +317,7 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
if (fd->interfaceVirtual)
thunkOffset -= fd->interfaceVirtual->offset;
if (thunkOffset == 0) {
- constants.push_back(irFunc->func);
+ constants.push_back(DtoBitCast(irFunc->func, voidPtrTy));
continue;
}
@@ -434,12 +424,12 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
gIR->funcGenStates.pop_back();
}
- constants.push_back(thunk);
+ constants.push_back(DtoBitCast(thunk, voidPtrTy));
}
// build the vtbl constant
- llvm::Constant *vtbl_constant =
- LLConstantStruct::getAnon(gIR->context(), constants, false);
+ llvm::Constant *vtbl_constant = LLConstantArray::get(
+ LLArrayType::get(voidPtrTy, constants.size()), constants);
std::string mangledName("_D");
mangledName.append(mangle(cd));
@@ -526,7 +516,8 @@ LLConstant *IrAggr::getClassInfoInterfaces() {
assert(itv != interfaceVtblMap.end() && "interface vtbl not found");
vtb = itv->second;
vtb = DtoBitCast(vtb, voidptrptr_type);
- vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb);
+ auto vtblSize = itc->getVtblType()->getNumContainedTypes();
+ vtb = DtoConstSlice(DtoConstSize_t(vtblSize), vtb);
}
// offset
diff --git a/ir/irtypeclass.cpp b/ir/irtypeclass.cpp
index 0e37d61..ef6b5a2 100644
--- a/ir/irtypeclass.cpp
+++ b/ir/irtypeclass.cpp
@@ -25,10 +25,7 @@
IrTypeClass::IrTypeClass(ClassDeclaration *cd)
: IrTypeAggr(cd), cd(cd), tc(static_cast<TypeClass *>(cd->type)) {
- std::string vtbl_name(cd->toPrettyChars());
- vtbl_name.append(".__vtbl");
- vtbl_type = LLStructType::create(gIR->context(), vtbl_name);
- vtbl_size = cd->vtbl.dim;
+ vtbl_type = LLArrayType::get(getVoidPtrType(), cd->vtbl.dim);
}
void IrTypeClass::addClassData(AggrTypeBuilder &builder,
@@ -52,15 +49,10 @@ void IrTypeClass::addClassData(AggrTypeBuilder &builder,
IF_LOG Logger::println("Adding interface vtbl for %s",
b->sym->toPrettyChars());
- FuncDeclarations arr;
- b->fillVtbl(cd, &arr, currCd == cd);
-
// add to the interface map
addInterfaceToMap(b->sym, builder.currentFieldIndex());
- Type* first = b->sym->isCPPinterface() ? nullptr : interfacePtrType;
- const auto ivtblType =
- llvm::StructType::get(gIR->context(), buildVtblType(first, &arr));
- builder.addType(llvm::PointerType::get(ivtblType, 0), Target::ptrsize);
+ auto vtblTy = LLArrayType::get(getVoidPtrType(), b->sym->vtbl.dim);
+ builder.addType(llvm::PointerType::get(vtblTy, 0), Target::ptrsize);
++num_interface_vtbls;
}
@@ -122,83 +114,10 @@ IrTypeClass *IrTypeClass::get(ClassDeclaration *cd) {
return t;
}
-std::vector<llvm::Type *>
-IrTypeClass::buildVtblType(Type *first, FuncDeclarations *vtbl_array) {
- IF_LOG Logger::println("Building vtbl type for class %s",
- cd->toPrettyChars());
- LOG_SCOPE;
-
- std::vector<llvm::Type *> types;
- types.reserve(vtbl_array->dim);
-
- auto I = vtbl_array->begin();
- // first comes the classinfo for D interfaces
- if (first) {
- types.push_back(DtoType(first));
- ++I;
- }
-
- // then come the functions
- for (auto E = vtbl_array->end(); I != E; ++I) {
- FuncDeclaration *fd = *I;
- if (fd == nullptr) {
- // FIXME: This stems from the ancient D1 days – can it still happen?
- types.push_back(getVoidPtrType());
- continue;
- }
-
- IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars());
-
- // If inferring return type and semantic3 has not been run, do it now.
- // This pops up in some other places in the frontend as well, however
- // it is probably a bug that it still occurs that late.
- if (!fd->type->nextOf() && fd->inferRetType) {
- Logger::println("Running late functionSemantic to infer return type.");
- TemplateInstance *spec = fd->isSpeculative();
- unsigned int olderrs = global.errors;
- fd->functionSemantic();
- if (spec && global.errors != olderrs) {
- spec->errors = global.errors - olderrs;
- }
- }
-
- if (!fd->type->nextOf()) {
- // Return type of the function has not been inferred. This seems to
- // happen with virtual functions and is probably a frontend bug.
- IF_LOG Logger::println("Broken function type, semanticRun: %d",
- fd->semanticRun);
- types.push_back(getVoidPtrType());
- continue;
- }
-
- types.push_back(getPtrToType(DtoFunctionType(fd)));
- }
-
- return types;
-}
-
llvm::Type *IrTypeClass::getLLType() { return llvm::PointerType::get(type, 0); }
llvm::Type *IrTypeClass::getMemoryLLType() { return type; }
-llvm::StructType *IrTypeClass::getVtblType(bool notOpaque) {
- if (notOpaque && vtbl_type->isOpaque()) {
- FuncDeclarations vtbl;
- vtbl.reserve(cd->vtbl.dim);
- if (!cd->isCPPclass())
- vtbl.push(nullptr);
- for (size_t i = cd->vtblOffset(); i < cd->vtbl.dim; ++i) {
- FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration();
- assert(fd);
- vtbl.push(fd);
- }
- Type* first = cd->isCPPclass() ? nullptr : Type::typeinfoclass->type;
- vtbl_type->setBody(buildVtblType(first, &vtbl));
- }
-
- return vtbl_type;
-}
-
size_t IrTypeClass::getInterfaceIndex(ClassDeclaration *inter) {
auto it = interfaceMap.find(inter);
if (it == interfaceMap.end()) {
diff --git a/ir/irtypeclass.h b/ir/irtypeclass.h
index 829ad83..91633c3 100644
--- a/ir/irtypeclass.h
+++ b/ir/irtypeclass.h
@@ -37,16 +37,13 @@ public:
llvm::Type *getMemoryLLType();
/// Returns the vtable type for this class.
- llvm::StructType *getVtblType(bool notOpaque);
+ llvm::ArrayType *getVtblType() { return vtbl_type; }
/// Get index to interface implementation.
/// Returns the index of a specific interface implementation in this
/// class or ~0 if not found.
size_t getInterfaceIndex(ClassDeclaration *inter);
- /// Returns the total number of pointers in the vtable.
- unsigned getVtblSize() { return vtbl_size; }
-
/// Returns the number of interface implementations (vtables) in this
/// class.
unsigned getNumInterfaceVtbls() { return num_interface_vtbls; }
@@ -61,10 +58,7 @@ protected:
TypeClass *tc = nullptr;
/// Vtable type.
- llvm::StructType *vtbl_type = nullptr;
-
- /// Number of pointers in vtable.
- unsigned vtbl_size = 0;
+ llvm::ArrayType *vtbl_type = nullptr;
/// Number of interface implementations (vtables) in this class.
unsigned num_interface_vtbls = 0;
@@ -78,13 +72,6 @@ protected:
//////////////////////////////////////////////////////////////////////////
- /// Builds a vtable type given the type of the first entry and an array
- /// of all entries.
- /// If first is nullptr for C++ interfaces, the vtbl_array will be added
- /// as is without replacing the first entry.
- std::vector<llvm::Type *> buildVtblType(Type *first,
- FuncDeclarations *vtbl_array);
-
/// Adds the data members for the given class to the type builder, including
/// those inherited from base classes/interfaces.
void addClassData(AggrTypeBuilder &builder, ClassDeclaration *currCd);
diff --git a/tests/codegen/in_place_construct_asm.d b/tests/codegen/in_place_construct_asm.d
index bd9c970..dab0bb8 100644
--- a/tests/codegen/in_place_construct_asm.d
+++ b/tests/codegen/in_place_construct_asm.d
@@ -1,6 +1,7 @@
// Tests in-place construction of structs returned by inline assembly (issue #1823).
// Target Win64 for simplicity (e.g., 4x32-bit struct not returned in memory for non-Windows x64).
+// REQUIRES: target_X86
// RUN: %ldc -mtriple=x86_64-pc-windows-msvc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
import ldc.llvmasm;
diff --git a/tests/compilable/gh1741.d b/tests/compilable/gh1741.d
new file mode 100644
index 0000000..af01e18
--- /dev/null
+++ b/tests/compilable/gh1741.d
@@ -0,0 +1,13 @@
+// Explicitly target Linux x86_64.
+// REQUIRES: target_X86
+// RUN: %ldc -mtriple=x86_64-pc-linux-gnu -c %s %S/inputs/gh1741b.d
+
+struct S
+{
+ C c;
+}
+
+class C
+{
+ @property s() { return S(); }
+}
diff --git a/tests/compilable/inputs/gh1741b.d b/tests/compilable/inputs/gh1741b.d
new file mode 100644
index 0000000..4606cdd
--- /dev/null
+++ b/tests/compilable/inputs/gh1741b.d
@@ -0,0 +1,3 @@
+import gh1741;
+
+S s;
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-d/ldc.git
More information about the pkg-d-commits
mailing list