//===-- typinf.cpp --------------------------------------------------------===// // // LDC – the LLVM D compiler // // This file mostly consists of code under the BSD-style LDC license, but some // parts have been derived from DMD as noted below. See the LICENSE file for // details. // //===----------------------------------------------------------------------===// // Copyright (c) 1999-2004 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com // License for redistribution is by either the Artistic License // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. // Modifications for LDC: // Copyright (c) 2007 by Tomas Lindquist Olsen // tomas at famolsen dk #include "aggregate.h" #include "attrib.h" #include "declaration.h" #include "enum.h" #include "expression.h" #include "id.h" #include "import.h" #include "init.h" #include "mars.h" #include "module.h" #include "mtype.h" #include "scope.h" #include "template.h" #include "gen/arrays.h" #include "gen/classes.h" #include "gen/irstate.h" #include "gen/linkage.h" #include "gen/llvm.h" #include "gen/llvmhelpers.h" #include "gen/logger.h" #include "gen/metadata.h" #include "gen/rttibuilder.h" #include "gen/runtime.h" #include "gen/structs.h" #include "gen/tollvm.h" #include "ir/irtype.h" #include "ir/irvar.h" #include #include #include Expression *getTypeInfo(Type *t, Scope *sc); TypeInfoDeclaration *getTypeInfoDeclaration(Type *t); static bool builtinTypeInfo(Type *t); FuncDeclaration *search_toString(StructDeclaration *sd); /**************************************************** * Get the exact TypeInfo. */ void genTypeInfo(Type *torig, Scope *sc) { IF_LOG Logger::println("Type::getTypeInfo(): %s", torig->toChars()); LOG_SCOPE if (!Type::dtypeinfo) { torig->error(Loc(), "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); fatal(); } Type *t = torig->merge2(); // do this since not all Type's are merge'd if (!t->vtinfo) { if (t->isShared()) // does both 'shared' and 'shared const' t->vtinfo = new TypeInfoSharedDeclaration(t); else if (t->isConst()) t->vtinfo = new TypeInfoConstDeclaration(t); else if (t->isImmutable()) t->vtinfo = new TypeInfoInvariantDeclaration(t); else if (t->isWild()) t->vtinfo = new TypeInfoWildDeclaration(t); else t->vtinfo = getTypeInfoDeclaration(t); assert(t->vtinfo); torig->vtinfo = t->vtinfo; /* If this has a custom implementation in std/typeinfo, then * do not generate a COMDAT for it. */ if (!builtinTypeInfo(t)) { // Generate COMDAT if (sc) // if in semantic() pass { // Find module that will go all the way to an object file Module *m = sc->module->importedFrom; m->members->push(t->vtinfo); semanticTypeInfo(sc, t); } else // if in obj generation pass { Declaration_codegen(t->vtinfo); } } } if (!torig->vtinfo) torig->vtinfo = t->vtinfo; // Types aren't merged, but we can share the vtinfo's assert(torig->vtinfo); } Expression *getTypeInfo(Type *t, Scope *sc) { assert(t->ty != Terror); genTypeInfo(t, sc); Expression *e = VarExp::create(Loc(), t->vtinfo); e = e->addressOf(); e->type = t->vtinfo->type; // do this so we don't get redundant dereference return e; } TypeInfoDeclaration *getTypeInfoDeclaration(Type *t) { //printf("Type::getTypeInfoDeclaration() %s\n", t->toChars()); switch (t->ty) { case Tpointer: return TypeInfoPointerDeclaration::create(t); case Tarray: return TypeInfoArrayDeclaration::create(t); case Tsarray: return TypeInfoStaticArrayDeclaration::create(t); case Taarray: return TypeInfoAssociativeArrayDeclaration::create(t); case Tstruct: return TypeInfoStructDeclaration::create(t); case Tvector: return TypeInfoVectorDeclaration::create(t); case Tenum: return TypeInfoEnumDeclaration::create(t); case Tfunction: return TypeInfoFunctionDeclaration::create(t); case Tdelegate: return TypeInfoDelegateDeclaration::create(t); case Ttuple: return TypeInfoTupleDeclaration::create(t); case Tclass: if (((TypeClass *)t)->sym->isInterfaceDeclaration()) return TypeInfoInterfaceDeclaration::create(t); else return TypeInfoClassDeclaration::create(t); default: return TypeInfoDeclaration::create(t, 0); } } /* ========================================================================= */ /* These decide if there's an instance for them already in std.typeinfo, * because then the compiler doesn't need to build one. */ static bool builtinTypeInfo(Type *t) { #if 0 // FIXME if I enable for Tclass, the way LDC does typeinfo will cause a // bunch of linker errors to missing class typeinfo definitions. if (t->isTypeBasic() || t->ty == Tclass) return !t->mod; #else if (t->isTypeBasic()) return !t->mod; #endif if (t->ty == Tarray) { Type *next = t->nextOf(); return !t->mod && ((next->isTypeBasic() != NULL && !next->mod) || // strings are so common, make them builtin (next->ty == Tchar && next->mod == MODimmutable) || (next->ty == Tchar && next->mod == MODconst)); } return false; } /* ========================================================================= */ ////////////////////////////////////////////////////////////////////////////// // MAGIC PLACE // (wut?) ////////////////////////////////////////////////////////////////////////////// static void emitTypeMetadata(TypeInfoDeclaration *tid) { // We don't want to generate metadata for non-concrete types (such as tuple // types, slice types, typeof(expr), etc.), void and function types (without // an indirection), as there must be a valid LLVM undef value of that type. // As those types cannot appear as LLVM values, they are not interesting for // the optimizer passes anyway. Type* t = tid->tinfo->toBasetype(); if (t->ty < Terror && t->ty != Tvoid && t->ty != Tfunction && t->ty != Tident) { // Add some metadata for use by optimization passes. std::string metaname(TD_PREFIX); metaname += mangle(tid); llvm::NamedMDNode* meta = gIR->module.getNamedMetadata(metaname); if (!meta) { // Construct the fields #if LDC_LLVM_VER >= 306 llvm::Metadata* mdVals[TD_NumFields]; mdVals[TD_TypeInfo] = llvm::ValueAsMetadata::get(getIrGlobal(tid)->value); mdVals[TD_Type] = llvm::ConstantAsMetadata::get(llvm::UndefValue::get(DtoType(tid->tinfo))); #else MDNodeField* mdVals[TD_NumFields]; mdVals[TD_TypeInfo] = llvm::cast(getIrGlobal(tid)->value); mdVals[TD_Type] = llvm::UndefValue::get(DtoType(tid->tinfo)); #endif // Construct the metadata and insert it into the module. llvm::NamedMDNode* node = gIR->module.getOrInsertNamedMetadata(metaname); node->addOperand(llvm::MDNode::get(gIR->context(), llvm::makeArrayRef(mdVals, TD_NumFields))); } } } void DtoResolveTypeInfo(TypeInfoDeclaration* tid) { if (tid->ir.isResolved()) return; tid->ir.setResolved(); // TypeInfo instances (except ClassInfo ones) are always emitted as weak // symbols when they are used. Declaration_codegen(tid); } /* ========================================================================= */ class LLVMDefineVisitor : public Visitor { public: // Import all functions from class Visitor using Visitor::visit; /* ========================================================================= */ void visit(TypeInfoDeclaration *decl) { IF_LOG Logger::println("TypeInfoDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; RTTIBuilder b(Type::dtypeinfo); b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoEnumDeclaration *decl) { IF_LOG Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; RTTIBuilder b(Type::typeinfoenum); assert(decl->tinfo->ty == Tenum); TypeEnum *tc = static_cast(decl->tinfo); EnumDeclaration *sd = tc->sym; // TypeInfo base b.push_typeinfo(sd->memtype); // char[] name b.push_string(sd->toPrettyChars()); // void[] init // emit void[] with the default initialier, the array is null if the default // initializer is zero if (!sd->members || decl->tinfo->isZeroInit(decl->loc)) { b.push_null_void_array(); } // otherwise emit a void[] with the default initializer else { Type *memtype = sd->memtype; LLType *memty = DtoType(memtype); LLConstant *C; Expression *defaultval = sd->getDefaultValue(decl->loc); if (memtype->isintegral()) C = LLConstantInt::get(memty, defaultval->toInteger(), !isLLVMUnsigned(memtype)); else if (memtype->isString()) C = DtoConstString(static_cast(defaultval->toStringExp()->string)); else if (memtype->isfloating()) C = LLConstantFP::get(memty, defaultval->toReal()); else llvm_unreachable("Unsupported type"); b.push_void_array(C, memtype, sd); } // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoPointerDeclaration *decl) { IF_LOG Logger::println("TypeInfoPointerDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; RTTIBuilder b(Type::typeinfopointer); // TypeInfo base b.push_typeinfo(decl->tinfo->nextOf()); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoArrayDeclaration *decl) { IF_LOG Logger::println("TypeInfoArrayDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; RTTIBuilder b(Type::typeinfoarray); // TypeInfo base b.push_typeinfo(decl->tinfo->nextOf()); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoStaticArrayDeclaration *decl) { IF_LOG Logger::println("TypeInfoStaticArrayDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; assert(decl->tinfo->ty == Tsarray); TypeSArray *tc = static_cast(decl->tinfo); RTTIBuilder b(Type::typeinfostaticarray); // value typeinfo b.push_typeinfo(tc->nextOf()); // length b.push(DtoConstSize_t(static_cast(tc->dim->toUInteger()))); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoAssociativeArrayDeclaration *decl) { IF_LOG Logger::println("TypeInfoAssociativeArrayDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; assert(decl->tinfo->ty == Taarray); TypeAArray *tc = static_cast(decl->tinfo); RTTIBuilder b(Type::typeinfoassociativearray); // value typeinfo b.push_typeinfo(tc->nextOf()); // key typeinfo b.push_typeinfo(tc->index); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoFunctionDeclaration *decl) { IF_LOG Logger::println("TypeInfoFunctionDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; RTTIBuilder b(Type::typeinfofunction); // TypeInfo base b.push_typeinfo(decl->tinfo->nextOf()); // string deco b.push_string(decl->tinfo->deco); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoDelegateDeclaration *decl) { IF_LOG Logger::println("TypeInfoDelegateDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; assert(decl->tinfo->ty == Tdelegate); Type* ret_type = decl->tinfo->nextOf()->nextOf(); RTTIBuilder b(Type::typeinfodelegate); // TypeInfo base b.push_typeinfo(ret_type); // string deco b.push_string(decl->tinfo->deco); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoStructDeclaration *decl) { IF_LOG Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; // make sure struct is resolved assert(decl->tinfo->ty == Tstruct); TypeStruct *tc = static_cast(decl->tinfo); StructDeclaration *sd = tc->sym; // handle opaque structs if (!sd->members) { RTTIBuilder b(Type::typeinfostruct); b.finalize(getIrGlobal(decl)); return; } // can't emit typeinfo for forward declarations if (sd->sizeok != SIZEOKdone) { sd->error("cannot emit TypeInfo for forward declaration"); fatal(); } DtoResolveStruct(sd); IrAggr* iraggr = getIrAggr(sd); RTTIBuilder b(Type::typeinfostruct); // char[] name b.push_string(sd->toPrettyChars()); // void[] init // The protocol is to write a null pointer for zero-initialized arrays. The // length field is always needed for tsize(). llvm::Constant *initPtr; if (tc->isZeroInit(Loc())) initPtr = getNullValue(getVoidPtrType()); else initPtr = iraggr->getInitSymbol(); b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr); // well use this module for all overload lookups // toHash FuncDeclaration* fd = sd->xhash; b.push_funcptr(fd); // opEquals fd = sd->xeq; b.push_funcptr(fd); // opCmp fd = sd->xcmp; b.push_funcptr(fd); // toString fd = search_toString(sd); b.push_funcptr(fd); // uint m_flags; unsigned hasptrs = tc->hasPointers() ? 1 : 0; b.push_uint(hasptrs); // On x86_64, class TypeInfo_Struct contains 2 additional fields // (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs // implementation. They are not present on any other cpu/os. assert((global.params.targetTriple.getArch() != llvm::Triple::x86_64 && Type::typeinfostruct->fields.dim == 11) || (global.params.targetTriple.getArch() == llvm::Triple::x86_64 && Type::typeinfostruct->fields.dim == 13)); //void function(void*) xdtor; b.push_funcptr(sd->dtor); //void function(void*) xpostblit; FuncDeclaration *xpostblit = sd->postblit; if (xpostblit && sd->postblit->storage_class & STCdisable) xpostblit = 0; b.push_funcptr(xpostblit); //uint m_align; b.push_uint(tc->alignsize()); if (global.params.is64bit) { // TypeInfo m_arg1; // TypeInfo m_arg2; Type *t = sd->arg1type; for (unsigned i = 0; i < 2; i++) { if (t) { t = t->merge(); b.push_typeinfo(t); } else b.push_null(Type::dtypeinfo->type); t = sd->arg2type; } } // immutable(void)* m_RTInfo; // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. if (sd->getRTInfo) b.push(toConstElem(sd->getRTInfo, gIR)); else if (!tc->hasPointers()) b.push_size_as_vp(0); // no pointers else b.push_size_as_vp(1); // has pointers // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoClassDeclaration *decl) { llvm_unreachable("TypeInfoClassDeclaration::llvmDefine() should not be called, " "as a custom Dsymbol::codegen() override is used"); } /* ========================================================================= */ void visit(TypeInfoInterfaceDeclaration *decl) { IF_LOG Logger::println("TypeInfoInterfaceDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; // make sure interface is resolved assert(decl->tinfo->ty == Tclass); TypeClass *tc = static_cast(decl->tinfo); DtoResolveClass(tc->sym); RTTIBuilder b(Type::typeinfointerface); // TypeInfo base b.push_classinfo(tc->sym); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoTupleDeclaration *decl) { IF_LOG Logger::println("TypeInfoTupleDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; // create elements array assert(decl->tinfo->ty == Ttuple); TypeTuple *tu = static_cast(decl->tinfo); size_t dim = tu->arguments->dim; std::vector arrInits; arrInits.reserve(dim); LLType* tiTy = DtoType(Type::dtypeinfo->type); for (size_t i = 0; i < dim; i++) { Parameter *arg = static_cast(tu->arguments->data[i]); arrInits.push_back(DtoTypeInfoOf(arg->type, true)); } // build array LLArrayType* arrTy = LLArrayType::get(tiTy, dim); LLConstant* arrC = LLConstantArray::get(arrTy, arrInits); RTTIBuilder b(Type::typeinfotypelist); // push TypeInfo[] b.push_array(arrC, dim, Type::dtypeinfo->type, NULL); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoConstDeclaration *decl) { IF_LOG Logger::println("TypeInfoConstDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; RTTIBuilder b(Type::typeinfoconst); // TypeInfo base b.push_typeinfo(decl->tinfo->mutableOf()->merge()); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoInvariantDeclaration *decl) { IF_LOG Logger::println("TypeInfoInvariantDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; RTTIBuilder b(Type::typeinfoinvariant); // TypeInfo base b.push_typeinfo(decl->tinfo->mutableOf()->merge()); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoSharedDeclaration *decl) { IF_LOG Logger::println("TypeInfoSharedDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; RTTIBuilder b(Type::typeinfoshared); // TypeInfo base b.push_typeinfo(decl->tinfo->unSharedOf()->merge()); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoWildDeclaration *decl) { IF_LOG Logger::println("TypeInfoWildDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; RTTIBuilder b(Type::typeinfowild); // TypeInfo base b.push_typeinfo(decl->tinfo->mutableOf()->merge()); // finish b.finalize(getIrGlobal(decl)); } /* ========================================================================= */ void visit(TypeInfoVectorDeclaration *decl) { IF_LOG Logger::println("TypeInfoVectorDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; assert(decl->tinfo->ty == Tvector); TypeVector *tv = static_cast(decl->tinfo); RTTIBuilder b(Type::typeinfovector); // TypeInfo base b.push_typeinfo(tv->basetype); // finish b.finalize(getIrGlobal(decl)); } }; /* ========================================================================= */ void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl, IRState* p) { IF_LOG Logger::println("TypeInfoDeclaration::codegen(%s)", decl->toPrettyChars()); LOG_SCOPE; if (decl->ir.isDefined()) return; decl->ir.setDefined(); std::string mangled(mangle(decl)); IF_LOG { Logger::println("type = '%s'", decl->tinfo->toChars()); Logger::println("typeinfo mangle: %s", mangled.c_str()); } IrGlobal* irg = getIrGlobal(decl, true); irg->value = gIR->module.getGlobalVariable(mangled); if (irg->value) { irg->type = irg->value->getType()->getContainedType(0); assert(irg->type->isStructTy()); } else { if (builtinTypeInfo(decl->tinfo)) // this is a declaration of a builtin __initZ var irg->type = Type::dtypeinfo->type->ctype->isClass()->getMemoryLLType(); else irg->type = LLStructType::create(gIR->context(), decl->toPrettyChars()); irg->value = new llvm::GlobalVariable(gIR->module, irg->type, true, llvm::GlobalValue::ExternalLinkage, NULL, mangled); } emitTypeMetadata(decl); // this is a declaration of a builtin __initZ var if (builtinTypeInfo(decl->tinfo)) { LLGlobalVariable* g = isaGlobalVar(irg->value); g->setLinkage(llvm::GlobalValue::ExternalLinkage); return; } // define custom typedef LLVMDefineVisitor v; decl->accept(&v); } /* ========================================================================= */ void TypeInfoClassDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p) { // For classes, the TypeInfo is in fact a ClassInfo instance and emitted // as a __ClassZ symbol. For interfaces, the __InterfaceZ symbol is // referenced as "info" member in a (normal) TypeInfo_Interface instance. IrGlobal *irg = getIrGlobal(decl, true); assert(decl->tinfo->ty == Tclass); TypeClass *tc = static_cast(decl->tinfo); DtoResolveClass(tc->sym); irg->value = getIrAggr(tc->sym)->getClassInfoSymbol(); irg->type = irg->value->getType()->getContainedType(0); if (!tc->sym->isInterfaceDeclaration()) { emitTypeMetadata(decl); } }