From d235e4cc28ab227c43f91ee88af794947ad5dca3 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sat, 7 Dec 2013 18:05:02 +0400 Subject: [PATCH 01/12] Fix DMD Issue 10425 - Link error with templates. Merged dmdfe changes in typeinf.c --- gen/typinf.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/gen/typinf.cpp b/gen/typinf.cpp index cbe7e00d..361685a6 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -109,6 +109,11 @@ Expression *Type::getInternalTypeInfo(Scope *sc) return t->getTypeInfo(sc); } + +bool inNonRoot(Dsymbol *s); +FuncDeclaration *search_toHash(StructDeclaration *sd); +FuncDeclaration *search_toString(StructDeclaration *sd); + /**************************************************** * Get the exact TypeInfo. */ @@ -146,9 +151,23 @@ Expression *Type::getTypeInfo(Scope *sc) if (!t->builtinTypeInfo()) { // Generate COMDAT if (sc) // if in semantic() pass - { // Find module that will go all the way to an object file + { + // Find module that will go all the way to an object file Module *m = sc->module->importedFrom; m->members->push(t->vtinfo); + + if (ty == Tstruct) + { + StructDeclaration *sd = ((TypeStruct *)this)->sym; + if ((sd->xeq && sd->xeq != sd->xerreq || + sd->xcmp && sd->xcmp != sd->xerrcmp || + search_toHash(sd) || + search_toString(sd) + ) && inNonRoot(sd)) + { + Module::addDeferredSemantic3(sd); + } + } } else // if in obj generation pass { From 5a181d93127b1693f55c109036238e69650b19d8 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sat, 7 Dec 2013 18:05:02 +0400 Subject: [PATCH 02/12] Update struct type info generation to reflect changes in dmd frontend --- gen/typinf.cpp | 52 +++----------------------------------------------- 1 file changed, 3 insertions(+), 49 deletions(-) diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 361685a6..1148c5df 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -591,21 +591,6 @@ void TypeInfoDelegateDeclaration::llvmDefine() /* ========================================================================= */ -static FuncDeclaration* find_method_overload(AggregateDeclaration* ad, Identifier* id, TypeFunction* tf) -{ - Dsymbol *s = search_function(ad, id); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - if (fdx) - { - FuncDeclaration *fd = fdx->overloadExactMatch(tf); - if (fd) - { - return fd; - } - } - return NULL; -} - void TypeInfoStructDeclaration::llvmDefine() { Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars()); @@ -641,41 +626,10 @@ void TypeInfoStructDeclaration::llvmDefine() initPtr = iraggr->getInitSymbol(); b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr); - // toX functions ground work - static TypeFunction *tftohash; - static TypeFunction *tftostring; - - if (!tftohash) - { - Scope sc; - tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); - tftohash ->mod = MODconst; - tftohash = static_cast(tftohash->semantic(Loc(), &sc)); - - Type *retType = Type::tchar->immutableOf()->arrayOf(); - tftostring = new TypeFunction(NULL, retType, 0, LINKd); - tftostring = static_cast(tftostring->semantic(Loc(), &sc)); - } - - // this one takes a parameter, so we need to build a new one each time - // to get the right type. can we avoid this? - TypeFunction *tfcmpptr; - { - Scope sc; - Parameters *arguments = new Parameters; - - // arg type is ref const T - Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); - arguments->push(arg); - tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); - tfcmpptr->mod = MODconst; - tfcmpptr = static_cast(tfcmpptr->semantic(Loc(), &sc)); - } - // well use this module for all overload lookups // toHash - FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash); + FuncDeclaration* fd = search_toHash(sd); b.push_funcptr(fd); // opEquals @@ -683,11 +637,11 @@ void TypeInfoStructDeclaration::llvmDefine() b.push_funcptr(fd); // opCmp - fd = find_method_overload(sd, Id::cmp, tfcmpptr); + fd = sd->xcmp; b.push_funcptr(fd); // toString - fd = find_method_overload(sd, Id::tostring, tftostring); + fd = search_toString(sd); b.push_funcptr(fd); // uint m_flags; From 5a10a23cefffbb52583e1ef7c1d6cac28a406ff8 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sat, 7 Dec 2013 19:19:49 +0400 Subject: [PATCH 03/12] Remove redundant FuncDeclaration::nestedVars. The change not only makes the code cleaner but also fixes compilation of multiple files at once. Previously, fd->nestedVars may have been filled twice if fd was a template function instantiated in two modules simultaneously. --- dmd2/declaration.h | 5 ----- gen/nested.cpp | 26 +++++++++----------------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 687b14db..6551ea54 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -930,11 +930,6 @@ public: /// Codegen traversal void codegen(IRState* ir); - // vars declared in this function that nested funcs reference - // is this is not empty, nestedFrameRef is set and these VarDecls - // probably have nestedref set too, see VarDeclaration::checkNestedReference - std::set nestedVars; - std::string intrinsicName; uint32_t priority; diff --git a/gen/nested.cpp b/gen/nested.cpp index 41d5ad12..753d2c8c 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -15,6 +15,7 @@ #include "gen/llvmhelpers.h" #include "gen/logger.h" #include "gen/tollvm.h" +#include "gen/utils.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Support/CommandLine.h" namespace cl = llvm::cl; @@ -285,17 +286,8 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { return; fd->ir.irFunc->nestedContextCreated = true; - // fill nestedVars - assert(fd->nestedVars.empty() && "nestedVars should only be filled here"); - size_t nnest = fd->closureVars.dim; - for (size_t i = 0; i < nnest; ++i) - { - VarDeclaration* vd = static_cast(fd->closureVars.data[i]); - fd->nestedVars.insert(vd); - } - // construct nested variables array - if (!fd->nestedVars.empty()) + if (fd->closureVars.dim != 0) { Logger::println("has nested frame"); // start with adding all enclosing parent frames until a static parent is reached @@ -345,9 +337,9 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { // Add the direct nested variables of this function, and update their indices to match. // TODO: optimize ordering for minimal space usage? - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; + VarDeclarationIter closureVarsIter(fd->closureVars); + for (; closureVarsIter.more(); closureVarsIter.next()) { + VarDeclaration* vd = *closureVarsIter; if (!vd->ir.irLocal) vd->ir.irLocal = new IrLocal(vd); @@ -404,7 +396,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { DtoCreateNestedContextType(fd); // construct nested variables array - if (!fd->nestedVars.empty()) + if (fd->closureVars.dim != 0) { IrFunction* irfunction = fd->ir.irFunc; unsigned depth = irfunction->depth; @@ -451,9 +443,9 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { irfunction->nestedVar = frame; // go through all nested vars and assign addresses where possible. - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; + VarDeclarationIter closureVarsIter(fd->closureVars); + for (; closureVarsIter.more(); closureVarsIter.next()) { + VarDeclaration* vd = *closureVarsIter; LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); if (vd->isParameter()) { From dcf005213b9bb6482271bcb04ef2a0032ce1b566 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sun, 8 Dec 2013 13:13:43 +0400 Subject: [PATCH 04/12] Implement cast to void --- gen/llvmhelpers.cpp | 8 -------- gen/toir.cpp | 10 +++------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 99309520..54df6b63 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -576,14 +576,6 @@ DValue* DtoCastInt(Loc& loc, DValue* val, Type* _to) return new DImValue(_to, rval); } - // Check for special DMD hack to avoid "has no effect" error. - // See expression.c, method AssignExp::semantic(), around line 11499 - llvm::ConstantInt* isConstInt = isaConstantInt(rval); - if (from == Type::tint32 && to == Type::tvoid && isConstInt->isNullValue()) - { - return val; - } - size_t fromsz = from->size(); size_t tosz = to->size(); diff --git a/gen/toir.cpp b/gen/toir.cpp index 537d5495..59db9692 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1140,13 +1140,9 @@ DValue* CastExp::toElem(IRState* p) // get the value to cast DValue* u = e1->toElem(p); - // a constructor expression is casted to void in order to mark - // the value as unused. See expression.d, method AssignExp::semantic(), - // around line 11681 - if (to == Type::tvoid && e1->op == TOKconstruct) - { - return new DNullValue(Type::tvoid, 0); - } + // handle cast to void (usually created by frontend to avoid "has no effect" error) + if (to == Type::tvoid) + return new DImValue(Type::tvoid, llvm::UndefValue::get(voidToI8(DtoType(Type::tvoid)))); // cast it to the 'to' type, if necessary DValue* v = u; From 9e724b3f9a70512abdbccacd58cf3a23032b70fb Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sun, 8 Dec 2013 13:57:46 +0400 Subject: [PATCH 05/12] Implement ClassReferenceExp::toElem --- gen/toir.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index 59db9692..8bdf9f8d 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -3180,9 +3180,7 @@ DValue* ClassReferenceExp::toElem(IRState* p) toChars(), type->toChars()); LOG_SCOPE; - error("ClassReferenceExp::toElem is not yet implemented"); - fatal(); - return 0; + return new DImValue(type, toConstElem(p)); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -3257,21 +3255,23 @@ llvm::Constant* ClassReferenceExp::toConstElem(IRState *p) llvm::Constant* result = value->globalVar; - assert(type->ty == Tclass); - ClassDeclaration* targetClass = static_cast(type)->sym; - if (InterfaceDeclaration* it = targetClass->isInterfaceDeclaration()) { - assert(it->isBaseOf(origClass, NULL)); + if (type->ty == Tclass) { + ClassDeclaration* targetClass = static_cast(type)->sym; + if (InterfaceDeclaration* it = targetClass->isInterfaceDeclaration()) { + assert(it->isBaseOf(origClass, NULL)); - IrTypeClass* typeclass = origClass->type->irtype->isClass(); + IrTypeClass* typeclass = origClass->type->irtype->isClass(); - // find interface impl - size_t i_index = typeclass->getInterfaceIndex(it); - assert(i_index != ~0UL); + // find interface impl + size_t i_index = typeclass->getInterfaceIndex(it); + assert(i_index != ~0UL); - // offset pointer - result = DtoGEPi(result, 0, i_index); + // offset pointer + result = DtoGEPi(result, 0, i_index); + } } + assert(type->ty == Tclass || type->ty == Tenum); return DtoBitCast(result, DtoType(type)); } From 89573a731a435719fab52eca3ab6df753b50eccc Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sun, 8 Dec 2013 14:43:27 +0400 Subject: [PATCH 06/12] Fix DMD Issue 10451 - Array of pointers to opaque struct gives forward reference errors. --- gen/typinf.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 1148c5df..3695c789 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -601,6 +601,13 @@ void TypeInfoStructDeclaration::llvmDefine() TypeStruct *tc = static_cast(tinfo); StructDeclaration *sd = tc->sym; + // handle opaque structs + if (!sd->members) { + RTTIBuilder b(Type::typeinfostruct); + b.finalize(ir.irGlobal); + return; + } + // can't emit typeinfo for forward declarations if (sd->sizeok != SIZEOKdone) { From ffe26e4ccc5e2a864453759eb3a8472227a9f545 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sun, 8 Dec 2013 14:56:40 +0400 Subject: [PATCH 07/12] Fix DMD Issue 11238 - Codegen error when this is a ref parameter to the method --- gen/toir.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/gen/toir.cpp b/gen/toir.cpp index 8bdf9f8d..b9d6f34e 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -520,6 +520,7 @@ DValue* AssignExp::toElem(IRState* p) if (se->lwr == NULL && ta->ty == Tsarray && e2->op == TOKarrayliteral && + op == TOKconstruct && // DMD Bugzilla 11238: avoid aliasing issue t2->nextOf()->mutableOf()->implicitConvTo(ta->nextOf())) { ArrayLiteralExp * const ale = static_cast(e2); From 0628a1f9f3b189fceafaa2e370e72d2b9710def6 Mon Sep 17 00:00:00 2001 From: Kai Nacke Date: Sun, 8 Dec 2013 15:24:42 +0100 Subject: [PATCH 08/12] Exclude threadasm.S from build if CMake version is less than 2.8.5. Assembler support was rewritten in CMake 2.8.5. The new functionality is required to assemble the file, otherwise a bunch of error messages is generated. The solution is to exclude the file from the build. This is only a problem for non-x86 platforms (PPC, Mips). General advise is to use at least CMake 2.8.5. This fixes #464. --- runtime/CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index f5fd158f..e10d9de2 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -102,7 +102,18 @@ if(UNIX) if(${CMAKE_SYSTEM} MATCHES "Linux") list(APPEND CORE_D_SYS ${CORE_D_LINUX}) endif() - list(APPEND DCRT_ASM ${RUNTIME_DIR}/src/core/threadasm.S) + # Assembler support was rewritten in CMake 2.8.5. + # The assembler file must be passed to gcc but prior to this + # version it is passed to as. This results in a bunch of + # error message. This is only critical for non-x86 platforms. + # On x86/x86-64 the file can safely be ignored. + if("${CMAKE_VERSION}" MATCHES "^2\\.8\\.[01234]($|\\..*)") + message(WARNING "Excluding core/threadasm.S from build because of missing CMake support.") + message(WARNING "This file is required for certain non-x86 platforms.") + message(WARNING "Please consider updating CMake to at least 2.8.5.") + else() + list(APPEND DCRT_ASM ${RUNTIME_DIR}/src/core/threadasm.S) + endif() if(APPLE) list(APPEND CORE_D_SYS ${CORE_D_OSX}) endif() From a2d7c9f3ed680f774685e25016574defd3bfda6d Mon Sep 17 00:00:00 2001 From: Kai Nacke Date: Sun, 8 Dec 2013 15:29:10 +0100 Subject: [PATCH 09/12] Only define version Android if compiling for this environment. Android is a variant of Linux. In order to simplify the version coding, only version Android is defined (version linux and version Posix are not). --- driver/main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/driver/main.cpp b/driver/main.cpp index 38fe9236..b18be485 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -568,14 +568,17 @@ static void registerPredefinedTargetVersions() { VersionCondition::addPredefinedGlobalIdent("Cygwin"); break; case llvm::Triple::Linux: - VersionCondition::addPredefinedGlobalIdent("linux"); - VersionCondition::addPredefinedGlobalIdent("Posix"); #if LDC_LLVM_VER >= 302 if (global.params.targetTriple.getEnvironment() == llvm::Triple::Android) { VersionCondition::addPredefinedGlobalIdent("Android"); } + else #endif + { + VersionCondition::addPredefinedGlobalIdent("linux"); + VersionCondition::addPredefinedGlobalIdent("Posix"); + } break; case llvm::Triple::Haiku: VersionCondition::addPredefinedGlobalIdent("Haiku"); @@ -620,8 +623,6 @@ static void registerPredefinedTargetVersions() { #if LDC_LLVM_VER >= 302 case llvm::Triple::Android: VersionCondition::addPredefinedGlobalIdent("Android"); - VersionCondition::addPredefinedGlobalIdent("linux"); - VersionCondition::addPredefinedGlobalIdent("Posix"); break; #endif default: From 43acc1f9c87f21d1aed8725d9d591977c3be5ae6 Mon Sep 17 00:00:00 2001 From: Kai Nacke Date: Sun, 8 Dec 2013 17:30:02 +0100 Subject: [PATCH 10/12] Check if basic types are read from object.di before usage. If object.di was not read or is incomplete then basic types may be missing. This results in a crash if they are used during runtime initialization. This fixes #551. --- gen/runtime.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 60b748f1..57d76ad8 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -168,6 +168,18 @@ static LLType* rt_dg2() return LLStructType::get(gIR->context(), types, false); } +template +static void ensureDecl(DECL *decl, const char *msg) +{ + if (!decl || !decl->type) + { + Logger::println("Missing class declaration: %s\n", msg); + error(Loc(), "Missing class declaration: %s", msg); + errorSupplemental(Loc(), "Please check that object.di is included and valid"); + fatal(); + } +} + static void LLVM_D_BuildRuntimeModule() { Logger::println("building runtime module"); @@ -187,10 +199,16 @@ static void LLVM_D_BuildRuntimeModule() LLType* wstringTy = DtoType(Type::twchar->arrayOf()); LLType* dstringTy = DtoType(Type::tdchar->arrayOf()); + ensureDecl(ClassDeclaration::object, "Object"); LLType* objectTy = DtoType(ClassDeclaration::object->type); + ensureDecl(ClassDeclaration::classinfo, "ClassInfo"); LLType* classInfoTy = DtoType(ClassDeclaration::classinfo->type); + ensureDecl(Type::typeinfo, "TypeInfo"); LLType* typeInfoTy = DtoType(Type::typeinfo->type); + ensureDecl(Type::typeinfoassociativearray, "TypeInfo_AssociativeArray"); LLType* aaTypeInfoTy = DtoType(Type::typeinfoassociativearray->type); + ensureDecl(Module::moduleinfo, "ModuleInfo"); + LLType* moduleInfoPtr = getPtrToType(DtoType(Module::moduleinfo->type)); LLType* aaTy = rt_ptr(LLStructType::get(gIR->context())); @@ -306,7 +324,7 @@ static void LLVM_D_BuildRuntimeModule() llvm::StringRef fname("_d_array_bounds"); llvm::StringRef fname2("_d_switch_error"); LLType *types[] = { - getPtrToType(DtoType(Module::moduleinfo->type)), + moduleInfoPtr, intTy }; LLFunctionType* fty = llvm::FunctionType::get(voidTy, types, false); From 669319b924e35c34533651b056b3a3e809b76a8d Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sun, 8 Dec 2013 15:50:54 +0400 Subject: [PATCH 11/12] Fix DMD Issue 8360 - Destruction of uninitialized temporary struct with assert --- gen/toir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index b9d6f34e..777ab052 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -2291,7 +2291,7 @@ DValue* AssertExp::toElem(IRState* p) // call assert runtime functions p->scope() = IRScope(assertbb,endbb); - DtoAssert(p->func()->decl->getModule(), loc, msg ? msg->toElem(p) : NULL); + DtoAssert(p->func()->decl->getModule(), loc, msg ? msg->toElemDtor(p) : NULL); // rewrite the scope p->scope() = IRScope(endbb,oldend); From aeba90b9f935418fd1d5dba3312041346baab618 Mon Sep 17 00:00:00 2001 From: Kai Nacke Date: Sun, 8 Dec 2013 18:59:17 +0100 Subject: [PATCH 12/12] Fix a clang warning --- gen/nested.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/nested.cpp b/gen/nested.cpp index 41d5ad12..ee21459c 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -223,7 +223,7 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) return llvm::ConstantPointerNull::get(getVoidPtrType()); } - struct FuncDeclaration* frameToPass = 0; + FuncDeclaration* frameToPass = 0; if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) { // If sym is a nested struct or a nested class, pass the frame // of the function where sym is declared.