LLGlobalVariable * IrStruct::getClassInfoSymbol() { if (classInfo) return classInfo; // create the initZ symbol std::string initname("_D"); initname.append(aggrdecl->mangle()); if (aggrdecl->isInterfaceDeclaration()) initname.append("11__InterfaceZ"); else initname.append("7__ClassZ"); llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); ClassDeclaration* cinfo = ClassDeclaration::classinfo; DtoType(cinfo->type); IrTypeClass* tc = stripModifiers(cinfo->type)->irtype->isClass(); assert(tc && "invalid ClassInfo type"); // classinfos cannot be constants since they're used as locks for synchronized classInfo = new llvm::GlobalVariable( *gIR->module, tc->getMemoryLLType(), false, _linkage, NULL, initname); #if USE_METADATA // Generate some metadata on this ClassInfo if it's for a class. ClassDeclaration* classdecl = aggrdecl->isClassDeclaration(); if (classdecl && !aggrdecl->isInterfaceDeclaration()) { // Gather information LLType* type = DtoType(aggrdecl->type); LLType* bodyType = llvm::cast<LLPointerType>(type)->getElementType(); bool hasDestructor = (classdecl->dtor != NULL); bool hasCustomDelete = (classdecl->aggDelete != NULL); // Construct the fields MDNodeField* mdVals[CD_NumFields]; mdVals[CD_BodyType] = llvm::UndefValue::get(bodyType); mdVals[CD_Finalize] = LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasDestructor); mdVals[CD_CustomDelete] = LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasCustomDelete); // Construct the metadata and insert it into the module. llvm::SmallString<64> name; llvm::NamedMDNode* node = gIR->module->getOrInsertNamedMetadata( llvm::Twine(CD_PREFIX, initname).toStringRef(name)); node->addOperand(llvm::MDNode::get(gIR->context(), llvm::makeArrayRef(mdVals, CD_NumFields))); } #endif // USE_METADATA return classInfo; }
DValue* DtoCastClass(Loc& loc, DValue* val, Type* _to) { IF_LOG Logger::println("DtoCastClass(%s, %s)", val->getType()->toChars(), _to->toChars()); LOG_SCOPE; Type* to = _to->toBasetype(); // class -> pointer if (to->ty == Tpointer) { IF_LOG Logger::println("to pointer"); LLType* tolltype = DtoType(_to); LLValue* rval = DtoBitCast(val->getRVal(), tolltype); return new DImValue(_to, rval); } // class -> bool else if (to->ty == Tbool) { IF_LOG Logger::println("to bool"); LLValue* llval = val->getRVal(); LLValue* zero = LLConstant::getNullValue(llval->getType()); return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero)); } // class -> integer else if (to->isintegral()) { IF_LOG Logger::println("to %s", to->toChars()); // get class ptr LLValue* v = val->getRVal(); // cast to size_t v = gIR->ir->CreatePtrToInt(v, DtoSize_t(), ""); // cast to the final int type DImValue im(Type::tsize_t, v); return DtoCastInt(loc, &im, _to); } // must be class/interface assert(to->ty == Tclass); TypeClass* tc = static_cast<TypeClass*>(to); // from type Type* from = val->getType()->toBasetype(); TypeClass* fc = static_cast<TypeClass*>(from); // x -> interface if (InterfaceDeclaration* it = tc->sym->isInterfaceDeclaration()) { Logger::println("to interface"); // interface -> interface if (fc->sym->isInterfaceDeclaration()) { Logger::println("from interface"); return DtoDynamicCastInterface(loc, val, _to); } // class -> interface - static cast else if (it->isBaseOf(fc->sym,NULL)) { Logger::println("static down cast"); // get the from class ClassDeclaration* cd = fc->sym->isClassDeclaration(); DtoResolveClass(cd); // add this IrTypeClass* typeclass = stripModifiers(fc)->ctype->isClass(); // find interface impl size_t i_index = typeclass->getInterfaceIndex(it); assert(i_index != ~0UL && "requesting interface that is not implemented by this class"); // offset pointer LLValue* v = val->getRVal(); LLValue* orig = v; v = DtoGEPi(v, 0, i_index); LLType* ifType = DtoType(_to); IF_LOG { Logger::cout() << "V = " << *v << std::endl; Logger::cout() << "T = " << *ifType << std::endl; } v = DtoBitCast(v, ifType); // Check whether the original value was null, and return null if so. // Sure we could have jumped over the code above in this case, but // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it // should be pretty cheap and perfectly safe even if the original was null. LLValue* isNull = gIR->ir->CreateICmpEQ(orig, LLConstant::getNullValue(orig->getType()), ".nullcheck"); v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(ifType), v, ".interface"); // return r-value return new DImValue(_to, v); }
LLConstant * IrStruct::getClassInfoInterfaces() { IF_LOG Logger::println("Building ClassInfo.interfaces"); LOG_SCOPE; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd); size_t n = interfacesWithVtbls.size(); assert(stripModifiers(type)->irtype->isClass()->getNumInterfaceVtbls() == n && "inconsistent number of interface vtables in this class"); VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); if (n == 0) return getNullValue(DtoType(interfaces_idx->type)); // Build array of: // // struct Interface // { // ClassInfo classinfo; // void*[] vtbl; // ptrdiff_t offset; // } LLSmallVector<LLConstant*, 6> constants; constants.reserve(cd->vtblInterfaces->dim); LLType* classinfo_type = DtoType(ClassDeclaration::classinfo->type); LLType* voidptrptr_type = DtoType( Type::tvoid->pointerTo()->pointerTo()); VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3); LLStructType* interface_type = isaStruct(DtoType(idx->type->nextOf())); assert(interface_type); for (size_t i = 0; i < n; ++i) { BaseClass* it = interfacesWithVtbls[i]; IF_LOG Logger::println("Adding interface %s", it->base->toPrettyChars()); IrStruct* irinter = it->base->ir.irStruct; assert(irinter && "interface has null IrStruct"); IrTypeClass* itc = stripModifiers(irinter->type)->irtype->isClass(); assert(itc && "null interface IrTypeClass"); // classinfo LLConstant* ci = irinter->getClassInfoSymbol(); ci = DtoBitCast(ci, classinfo_type); // vtbl LLConstant* vtb; // interface get a null if (cd->isInterfaceDeclaration()) { vtb = DtoConstSlice(DtoConstSize_t(0), getNullValue(voidptrptr_type)); } else { ClassGlobalMap::iterator itv = interfaceVtblMap.find(it->base); assert(itv != interfaceVtblMap.end() && "interface vtbl not found"); vtb = itv->second; vtb = DtoBitCast(vtb, voidptrptr_type); vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb); } // offset LLConstant* off = DtoConstSize_t(it->offset); // create Interface struct LLConstant* inits[3] = { ci, vtb, off }; LLConstant* entry = LLConstantStruct::get(interface_type, llvm::makeArrayRef(inits, 3)); constants.push_back(entry); } // create Interface[N] LLArrayType* array_type = llvm::ArrayType::get(interface_type, n); // create and apply initializer LLConstant* arr = LLConstantArray::get(array_type, constants); classInterfacesArray->setInitializer(arr); // return null, only baseclass provide interfaces if (cd->vtblInterfaces->dim == 0) { return getNullValue(DtoType(interfaces_idx->type)); } // only the interface explicitly implemented by this class // (not super classes) should show in ClassInfo LLConstant* idxs[2] = { DtoConstSize_t(0), DtoConstSize_t(n - cd->vtblInterfaces->dim) }; LLConstant* ptr = llvm::ConstantExpr::getGetElementPtr( classInterfacesArray, idxs, true); // return as a slice return DtoConstSlice( DtoConstSize_t(cd->vtblInterfaces->dim), ptr ); }
void IrStruct::addBaseClassInits( std::vector<llvm::Constant*>& constants, ClassDeclaration* base, size_t& offset, size_t& field_index) { if (base->baseClass) { addBaseClassInits(constants, base->baseClass, offset, field_index); } IrTypeClass* tc = stripModifiers(base->type)->irtype->isClass(); assert(tc); // go through fields IrTypeAggr::iterator it; for (it = tc->def_begin(); it != tc->def_end(); ++it) { VarDeclaration* vd = *it; IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); LOG_SCOPE; assert(vd->offset >= offset && "default fields not sorted by offset"); // get next aligned offset for this type size_t alignedoffset = realignOffset(offset, vd->type); // insert explicit padding? if (alignedoffset < vd->offset) { add_zeros(constants, vd->offset - alignedoffset); } // add default type constants.push_back(get_default_initializer(vd, vd->init)); // advance offset to right past this field offset = vd->offset + vd->type->size(); } // has interface vtbls? if (base->vtblInterfaces && base->vtblInterfaces->dim > 0) { // false when it's not okay to use functions from super classes bool newinsts = (base == aggrdecl->isClassDeclaration()); size_t inter_idx = interfacesWithVtbls.size(); offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1); ArrayIter<BaseClass> it2(*base->vtblInterfaces); for (; !it2.done(); it2.next()) { BaseClass* b = it2.get(); constants.push_back(getInterfaceVtbl(b, newinsts, inter_idx)); offset += PTRSIZE; // add to the interface list interfacesWithVtbls.push_back(b); inter_idx++; } } }
void visit(ClassReferenceExp *e) override { IF_LOG Logger::print("ClassReferenceExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars()); LOG_SCOPE; ClassDeclaration *origClass = e->originalClass(); DtoResolveClass(origClass); StructLiteralExp *value = e->value; if (value->globalVar) { IF_LOG Logger::cout() << "Using existing global: " << *value->globalVar << '\n'; } else { value->globalVar = new llvm::GlobalVariable( p->module, origClass->type->ctype->isClass()->getMemoryLLType(), false, llvm::GlobalValue::InternalLinkage, nullptr, ".classref"); std::map<VarDeclaration *, llvm::Constant *> varInits; // Unfortunately, ClassReferenceExp::getFieldAt is badly broken – it // places the base class fields _after_ those of the subclass. { const size_t nexprs = value->elements->dim; std::stack<ClassDeclaration *> classHierachy; ClassDeclaration *cur = origClass; while (cur) { classHierachy.push(cur); cur = cur->baseClass; } size_t i = 0; while (!classHierachy.empty()) { cur = classHierachy.top(); classHierachy.pop(); for (size_t j = 0; j < cur->fields.dim; ++j) { if ((*value->elements)[i]) { VarDeclaration *field = cur->fields[j]; IF_LOG Logger::println("Getting initializer for: %s", field->toChars()); LOG_SCOPE; varInits[field] = toConstElem((*value->elements)[i]); } ++i; } } assert(i == nexprs); } llvm::Constant *constValue = getIrAggr(origClass)->createInitializerConstant(varInits); if (constValue->getType() != value->globalVar->getType()->getContainedType(0)) { auto finalGlobalVar = new llvm::GlobalVariable( p->module, constValue->getType(), false, llvm::GlobalValue::InternalLinkage, nullptr, ".classref"); value->globalVar->replaceAllUsesWith( DtoBitCast(finalGlobalVar, value->globalVar->getType())); value->globalVar->eraseFromParent(); value->globalVar = finalGlobalVar; } value->globalVar->setInitializer(constValue); } result = value->globalVar; if (e->type->ty == Tclass) { ClassDeclaration *targetClass = static_cast<TypeClass *>(e->type)->sym; if (InterfaceDeclaration *it = targetClass->isInterfaceDeclaration()) { assert(it->isBaseOf(origClass, NULL)); IrTypeClass *typeclass = origClass->type->ctype->isClass(); // find interface impl size_t i_index = typeclass->getInterfaceIndex(it); assert(i_index != ~0UL); // offset pointer result = DtoGEPi(result, 0, i_index); } } assert(e->type->ty == Tclass || e->type->ty == Tenum); result = DtoBitCast(result, DtoType(e->type)); }
void visit(CastExp *e) override { IF_LOG Logger::print("CastExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars()); LOG_SCOPE; LLType *lltype = DtoType(e->type); Type *tb = e->to->toBasetype(); // string literal to dyn array: // reinterpret the string data as an array, calculate the length if (e->e1->op == TOKstring && tb->ty == Tarray) { #if 0 StringExp *strexp = static_cast<StringExp*>(e1); size_t datalen = strexp->sz * strexp->len; Type* eltype = tb->nextOf()->toBasetype(); if (datalen % eltype->size() != 0) { error("the sizes don't line up"); return e1->toConstElem(p); } size_t arrlen = datalen / eltype->size(); #endif e->error("ct cast of string to dynamic array not fully implemented"); result = toConstElem(e->e1); } // pointer to pointer else if (tb->ty == Tpointer && e->e1->type->toBasetype()->ty == Tpointer) { result = llvm::ConstantExpr::getBitCast(toConstElem(e->e1), lltype); } // global variable to pointer else if (tb->ty == Tpointer && e->e1->op == TOKvar) { VarDeclaration *vd = static_cast<VarExp *>(e->e1)->var->isVarDeclaration(); assert(vd); DtoResolveVariable(vd); LLConstant *value = isIrGlobalCreated(vd) ? isaConstant(getIrGlobal(vd)->value) : nullptr; if (!value) { goto Lerr; } Type *type = vd->type->toBasetype(); if (type->ty == Tarray || type->ty == Tdelegate) { LLConstant *idxs[2] = {DtoConstSize_t(0), DtoConstSize_t(1)}; #if LDC_LLVM_VER >= 307 value = llvm::ConstantExpr::getGetElementPtr( isaPointer(value)->getElementType(), value, idxs, true); #else value = llvm::ConstantExpr::getGetElementPtr(value, idxs, true); #endif } result = DtoBitCast(value, DtoType(tb)); } else if (tb->ty == Tclass && e->e1->type->ty == Tclass && e->e1->op == TOKclassreference) { auto cd = static_cast<ClassReferenceExp *>(e->e1)->originalClass(); llvm::Constant *instance = toConstElem(e->e1); if (InterfaceDeclaration *it = static_cast<TypeClass *>(tb)->sym->isInterfaceDeclaration()) { assert(it->isBaseOf(cd, NULL)); IrTypeClass *typeclass = cd->type->ctype->isClass(); // find interface impl size_t i_index = typeclass->getInterfaceIndex(it); assert(i_index != ~0UL); // offset pointer instance = DtoGEPi(instance, 0, i_index); } result = DtoBitCast(instance, DtoType(tb)); } else { goto Lerr; } return; Lerr: e->error("cannot cast %s to %s at compile time", e->e1->type->toChars(), e->type->toChars()); if (!global.gag) { fatal(); } result = llvm::UndefValue::get(DtoType(e->type)); }