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)); }
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); }
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)); }