DValue *binMin(Loc &loc, Type *type, DValue *lhs, Expression *rhs, bool loadLhsAfterRhs) { Type *lhsType = lhs->type->toBasetype(); Type *rhsType = rhs->type->toBasetype(); if (lhsType != rhsType && lhsType->ty == Tpointer && rhsType->isintegral()) { Logger::println("Subtracting integer from pointer"); return emitPointerOffset(loc, lhs, rhs, true, type, loadLhsAfterRhs); } auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); if (lhsType->ty == Tpointer && rhsType->ty == Tpointer) { LLValue *l = DtoRVal(rvals.lhs); LLValue *r = DtoRVal(rvals.rhs); LLType *llSizeT = DtoSize_t(); l = gIR->ir->CreatePtrToInt(l, llSizeT); r = gIR->ir->CreatePtrToInt(r, llSizeT); LLValue *diff = gIR->ir->CreateSub(l, r); LLType *llType = DtoType(type); if (diff->getType() != llType) diff = gIR->ir->CreateIntToPtr(diff, llType); return new DImValue(type, diff); } if (type->ty == Tnull) return DtoNullValue(type, loc); if (type->iscomplex()) return DtoComplexMin(loc, type, rvals.lhs, rvals.rhs); LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); if (auto aa = isAssociativeArrayAndNull(type, l, r)) return aa; LLValue *res = (type->isfloating() ? gIR->ir->CreateFSub(l, r) : gIR->ir->CreateSub(l, r)); return new DImValue(type, res); }
LLValue* DtoStructEquals(TOK op, DValue* lhs, DValue* rhs) { Type* t = lhs->getType()->toBasetype(); assert(t->ty == Tstruct); // set predicate llvm::ICmpInst::Predicate cmpop; if (op == TOKequal || op == TOKidentity) cmpop = llvm::ICmpInst::ICMP_EQ; else cmpop = llvm::ICmpInst::ICMP_NE; // empty struct? EQ always true, NE always false if (static_cast<TypeStruct*>(t)->sym->fields.dim == 0) return DtoConstBool(cmpop == llvm::ICmpInst::ICMP_EQ); // call memcmp size_t sz = getTypePaddedSize(DtoType(t)); LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz)); return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false)); }
LLStructType* DtoModuleReferenceType() { if (gIR->moduleRefType) return gIR->moduleRefType; // this is a recursive type so start out with a struct without body LLStructType* st = LLStructType::create(gIR->context(), "ModuleReference"); // add members LLType *types[] = { getPtrToType(st), DtoType(Module::moduleinfo->type->pointerTo()) }; // resolve type st->setBody(types); // done gIR->moduleRefType = st; return st; }
LLValue *DtoBinFloatsEquals(Loc &loc, DValue *lhs, DValue *rhs, TOK op) { LLValue *res = nullptr; if (op == TOKequal || op == TOKnotequal) { LLValue *l = DtoRVal(lhs); LLValue *r = DtoRVal(rhs); res = (op == TOKequal ? gIR->ir->CreateFCmpOEQ(l, r) : gIR->ir->CreateFCmpUNE(l, r)); if (lhs->type->toBasetype()->ty == Tvector) { res = mergeVectorEquals(res, op); } } else { const auto cmpop = op == TOKidentity ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE; LLValue *sz = DtoConstSize_t(getTypeStoreSize(DtoType(lhs->type))); LLValue *val = DtoMemCmp(makeLValue(loc, lhs), makeLValue(loc, rhs), sz); res = gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false)); } assert(res); return res; }
void RTTIBuilder::push_array(llvm::Constant *CI, uint64_t dim, Type *valtype, Dsymbol *mangle_sym) { std::string tmpStr(valtype->arrayOf()->toChars()); tmpStr.erase(remove(tmpStr.begin(), tmpStr.end(), '['), tmpStr.end()); tmpStr.erase(remove(tmpStr.begin(), tmpStr.end(), ']'), tmpStr.end()); tmpStr.append("arr"); std::string initname(mangle_sym ? mangle(mangle_sym) : ".ldc"); initname.append(".rtti."); initname.append(tmpStr); initname.append(".data"); const LinkageWithCOMDAT lwc(TYPEINFO_LINKAGE_TYPE, supportsCOMDAT()); auto G = new LLGlobalVariable(gIR->module, CI->getType(), true, lwc.first, CI, initname); setLinkage(lwc, G); G->setAlignment(DtoAlignment(valtype)); push_array(dim, DtoBitCast(G, DtoType(valtype->pointerTo()))); }
llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl) { // handle for C vararg intrinsics if (DtoIsVaIntrinsic(fdecl)) return DtoVaFunctionType(fdecl); Type *dthis=0, *dnest=0; if (fdecl->ident == Id::ensure || fdecl->ident == Id::require) { FuncDeclaration *p = fdecl->parent->isFuncDeclaration(); assert(p); AggregateDeclaration *ad = p->isMember2(); assert(ad); dnest = Type::tvoid->pointerTo(); } else if (fdecl->needThis()) { if (AggregateDeclaration* ad = fdecl->isMember2()) { IF_LOG Logger::println("isMember = this is: %s", ad->type->toChars()); dthis = ad->type; LLType* thisty = DtoType(dthis); //Logger::cout() << "this llvm type: " << *thisty << '\n'; if (ad->isStructDeclaration()) thisty = getPtrToType(thisty); } else { IF_LOG Logger::println("chars: %s type: %s kind: %s", fdecl->toChars(), fdecl->type->toChars(), fdecl->kind()); llvm_unreachable("needThis, but invalid parent declaration."); } } else if (fdecl->isNested()) { dnest = Type::tvoid->pointerTo(); } LLFunctionType* functype = DtoFunctionType(fdecl->type, getIrFunc(fdecl, true)->irFty, dthis, dnest, fdecl->isMain(), fdecl->isCtorDeclaration(), fdecl->llvmInternal == LLVMintrinsic); return functype; }
void TypeInfoEnumDeclaration::llvmDefine() { Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", toChars()); LOG_SCOPE; RTTIBuilder b(Type::typeinfoenum); assert(tinfo->ty == Tenum); TypeEnum *tc = static_cast<TypeEnum *>(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->defaultval || tinfo->isZeroInit(0)) { b.push_null_void_array(); } // otherwise emit a void[] with the default initializer else { LLType* memty = DtoType(sd->memtype); #if DMDV2 LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !isLLVMUnsigned(sd->memtype)); #else LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !isLLVMUnsigned(sd->memtype)); #endif b.push_void_array(C, sd->memtype, sd); } // finish b.finalize(ir.irGlobal); }
LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl, char* name) { // sanity checks assert(fdecl->isVirtual()); assert(!fdecl->isFinal()); assert(fdecl->vtblIndex > 0); // 0 is always ClassInfo/Interface* assert(inst->getType()->toBasetype()->ty == Tclass); // get instance LLValue* vthis = inst->getRVal(); if (Logger::enabled()) Logger::cout() << "vthis: " << *vthis << '\n'; LLValue* funcval = vthis; // get the vtbl for objects funcval = DtoGEPi(funcval, 0, 0, "tmp"); // load vtbl ptr funcval = DtoLoad(funcval); // index vtbl std::string vtblname = name; vtblname.append("@vtbl"); funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, vtblname.c_str()); // load funcptr funcval = DtoAlignedLoad(funcval); if (Logger::enabled()) Logger::cout() << "funcval: " << *funcval << '\n'; // cast to final funcptr type funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type))); // postpone naming until after casting to get the name in call instructions funcval->setName(name); if (Logger::enabled()) Logger::cout() << "funcval casted: " << *funcval << '\n'; return funcval; }
DValue* DtoCastInterfaceToObject(DValue* val, Type* to) { // call: // Object _d_toObject(void* p) llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_toObject"); LLFunctionType* funcTy = func->getFunctionType(); // void* p LLValue* tmp = val->getRVal(); tmp = DtoBitCast(tmp, funcTy->getParamType(0)); // call it LLValue* ret = gIR->CreateCallOrInvoke(func, tmp, "tmp").getInstruction(); // cast return value if (to != NULL) ret = DtoBitCast(ret, DtoType(to)); else to = ClassDeclaration::object->type; return new DImValue(to, ret); }
LLStructType* DtoInterfaceInfoType() { if (gIR->interfaceInfoType) return gIR->interfaceInfoType; // build interface info type LLSmallVector<LLType*, 3> types; // ClassInfo classinfo ClassDeclaration* cd2 = ClassDeclaration::classinfo; DtoResolveClass(cd2); types.push_back(DtoType(cd2->type)); // void*[] vtbl LLSmallVector<LLType*, 2> vtbltypes; vtbltypes.push_back(DtoSize_t()); LLType* byteptrptrty = getPtrToType(getPtrToType(LLType::getInt8Ty(gIR->context()))); vtbltypes.push_back(byteptrptrty); types.push_back(LLStructType::get(gIR->context(), vtbltypes)); // int offset types.push_back(LLType::getInt32Ty(gIR->context())); // create type gIR->interfaceInfoType = LLStructType::get(gIR->context(), types); return gIR->interfaceInfoType; }
LLConstant *DtoConstFP(Type *t, longdouble value) { LLType *llty = DtoType(t); assert(llty->isFloatingPointTy()); if (llty == LLType::getFloatTy(gIR->context()) || llty == LLType::getDoubleTy(gIR->context())) { return LLConstantFP::get(llty, value); } if (llty == LLType::getX86_FP80Ty(gIR->context())) { uint64_t bits[] = {0, 0}; bits[0] = *reinterpret_cast<uint64_t *>(&value); bits[1] = *reinterpret_cast<uint16_t *>(reinterpret_cast<uint64_t *>(&value) + 1); return LLConstantFP::get(gIR->context(), APFloat(APFloat::x87DoubleExtended, APInt(80, 2, bits))); } if (llty == LLType::getFP128Ty(gIR->context())) { union { longdouble ld; uint64_t bits[2]; } t; t.ld = value; return LLConstantFP::get(gIR->context(), APFloat(APFloat::IEEEquad, APInt(128, 2, t.bits))); } if (llty == LLType::getPPC_FP128Ty(gIR->context())) { uint64_t bits[] = {0, 0}; bits[0] = *reinterpret_cast<uint64_t *>(&value); bits[1] = *reinterpret_cast<uint16_t *>(reinterpret_cast<uint64_t *>(&value) + 1); return LLConstantFP::get( gIR->context(), APFloat(APFloat::PPCDoubleDouble, APInt(128, 2, bits))); } llvm_unreachable("Unknown floating point type encountered"); }
void DtoResolveClass(ClassDeclaration *cd) { if (cd->ir->isResolved()) { return; } cd->ir->setResolved(); IF_LOG Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; // make sure the base classes are processed first for (auto bc : *cd->baseclasses) { DtoResolveClass(bc->sym); } // make sure type exists DtoType(cd->type); // create IrAggr IrAggr *irAggr = getIrAggr(cd, true); // make sure all fields really get their ir field for (auto vd : cd->fields) { IF_LOG { if (isIrFieldCreated(vd)) { Logger::println("class field already exists"); } } getIrField(vd, true); } // interface only emit typeinfo and classinfo if (cd->isInterfaceDeclaration()) { irAggr->initializeInterface(); } }
IrTypePointer* IrTypePointer::get(Type* dt) { assert(!dt->ctype); assert((dt->ty == Tpointer || dt->ty == Tnull) && "not pointer/null type"); LLType* elemType; if (dt->ty == Tnull) { elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext()); } else { elemType = i1ToI8(voidToI8(DtoType(dt->nextOf()))); // DtoType could have already created the same type, e.g. for // dt == Node* in struct Node { Node* n; }. if (dt->ctype) return dt->ctype->isPointer(); } IrTypePointer* t = new IrTypePointer(dt, llvm::PointerType::get(elemType, 0)); dt->ctype = t; return t; }
DValue* DtoDynamicCastObject(DValue* val, Type* _to) { // call: // Object _d_dynamic_cast(Object o, ClassInfo c) ClassDeclaration::object->codegen(Type::sir); ClassDeclaration::classinfo->codegen(Type::sir); llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast"); LLFunctionType* funcTy = func->getFunctionType(); std::vector<LLValue*> args; // Object o LLValue* obj = val->getRVal(); obj = DtoBitCast(obj, funcTy->getParamType(0)); assert(funcTy->getParamType(0) == obj->getType()); // ClassInfo c TypeClass* to = static_cast<TypeClass*>(_to->toBasetype()); to->sym->codegen(Type::sir); LLValue* cinfo = to->sym->ir.irStruct->getClassInfoSymbol(); // unfortunately this is needed as the implementation of object differs somehow from the declaration // this could happen in user code as well :/ cinfo = DtoBitCast(cinfo, funcTy->getParamType(1)); assert(funcTy->getParamType(1) == cinfo->getType()); // call it LLValue* ret = gIR->CreateCallOrInvoke2(func, obj, cinfo, "tmp").getInstruction(); // cast return value ret = DtoBitCast(ret, DtoType(_to)); return new DImValue(_to, ret); }
DValue* DtoNestedVariable(Loc& loc, Type* astype, VarDeclaration* vd, bool byref) { IF_LOG Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars()); LOG_SCOPE; //////////////////////////////////// // Locate context value Dsymbol* vdparent = vd->toParent2(); assert(vdparent); IrFunction* irfunc = gIR->func(); // Check whether we can access the needed frame FuncDeclaration *fd = irfunc->decl; while (fd != vdparent) { if (fd->isStatic()) { error(loc, "function %s cannot access frame of function %s", irfunc->decl->toPrettyChars(), vdparent->toPrettyChars()); return new DVarValue(astype, vd, llvm::UndefValue::get(getPtrToType(DtoType(astype)))); } fd = getParentFunc(fd, false); assert(fd); } // is the nested variable in this scope? if (vdparent == irfunc->decl) { LLValue* val = vd->ir.getIrValue(); return new DVarValue(astype, vd, val); } LLValue *dwarfValue = 0; std::vector<LLValue*> dwarfAddr; // get the nested context LLValue* ctx = 0; if (irfunc->nestedVar) { // If this function has its own nested context struct, always load it. ctx = irfunc->nestedVar; dwarfValue = ctx; } else if (irfunc->decl->isMember2()) { // If this is a member function of a nested class without its own // context, load the vthis member. AggregateDeclaration* cd = irfunc->decl->isMember2(); LLValue* val = irfunc->thisArg; if (cd->isClassDeclaration()) val = DtoLoad(val); ctx = DtoLoad(DtoGEPi(val, 0, cd->vthis->ir.irField->index, ".vthis")); } else { // Otherwise, this is a simple nested function, load from the context // argument. ctx = DtoLoad(irfunc->nestArg); dwarfValue = irfunc->nestArg; if (global.params.symdebug) gIR->DBuilder.OpDeref(dwarfAddr); } assert(ctx); DtoCreateNestedContextType(vdparent->isFuncDeclaration()); assert(vd->ir.irLocal); //////////////////////////////////// // Extract variable from nested context LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); IF_LOG { Logger::cout() << "Context: " << *val << '\n'; Logger::cout() << "of type: " << *irfunc->frameType << '\n'; } unsigned vardepth = vd->ir.irLocal->nestedDepth; unsigned funcdepth = irfunc->depth; IF_LOG { Logger::cout() << "Variable: " << vd->toChars() << '\n'; Logger::cout() << "Variable depth: " << vardepth << '\n'; Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; Logger::cout() << "Function depth: " << funcdepth << '\n'; } if (vardepth == funcdepth) { // This is not always handled above because functions without // variables accessed by nested functions don't create new frames. IF_LOG Logger::println("Same depth"); } else { // Load frame pointer and index that... if (dwarfValue && global.params.symdebug) { gIR->DBuilder.OpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth); gIR->DBuilder.OpDeref(dwarfAddr); } IF_LOG Logger::println("Lower depth"); val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); IF_LOG Logger::cout() << "Frame index: " << *val << '\n'; val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); IF_LOG Logger::cout() << "Frame: " << *val << '\n'; } int idx = vd->ir.irLocal->nestedIndex; assert(idx != -1 && "Nested context not yet resolved for variable."); if (dwarfValue && global.params.symdebug) gIR->DBuilder.OpOffset(dwarfAddr, val, idx); val = DtoGEPi(val, 0, idx, vd->toChars()); IF_LOG { Logger::cout() << "Addr: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; } if (byref || (vd->isParameter() && vd->ir.irParam->arg->byref)) { val = DtoAlignedLoad(val); //dwarfOpDeref(dwarfAddr); IF_LOG { Logger::cout() << "Was byref, now: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; } }
void IrTypeClass::addBaseClassData( std::vector<llvm::Type *> & defaultTypes, ClassDeclaration * base, size_t & offset, size_t & field_index) { if (base->baseClass) { addBaseClassData(defaultTypes, base->baseClass, offset, field_index); } // FIXME: merge code with structs in IrTypeAggr // mirror the sd->fields array but only fill in contributors size_t n = base->fields.dim; LLSmallVector<VarDeclaration*, 16> data(n, NULL); default_fields.reserve(n); // first fill in the fields with explicit initializers VarDeclarationIter field_it(base->fields); for (; field_it.more(); field_it.next()) { // init is !null for explicit inits if (field_it->init != NULL) { IF_LOG Logger::println("adding explicit initializer for struct field %s", field_it->toChars()); data[field_it.index] = *field_it; size_t f_begin = field_it->offset; size_t f_end = f_begin + field_it->type->size(); // make sure there is no overlap for (size_t i = 0; i < field_it.index; i++) { if (data[i] != NULL) { VarDeclaration* vd = data[i]; size_t v_begin = vd->offset; size_t v_end = v_begin + vd->type->size(); if (v_begin >= f_end || v_end <= f_begin) continue; base->error(vd->loc, "has overlapping initialization for %s and %s", field_it->toChars(), vd->toChars()); } } } } if (global.errors) { fatal(); } // fill in default initializers field_it = VarDeclarationIter(base->fields); for (;field_it.more(); field_it.next()) { if (data[field_it.index]) continue; size_t f_begin = field_it->offset; size_t f_end = f_begin + field_it->type->size(); // make sure it doesn't overlap anything explicit bool overlaps = false; for (size_t i = 0; i < n; i++) { if (data[i]) { size_t v_begin = data[i]->offset; size_t v_end = v_begin + data[i]->type->size(); if (v_begin >= f_end || v_end <= f_begin) continue; overlaps = true; break; } } // if no overlap was found, add the default initializer if (!overlaps) { IF_LOG Logger::println("adding default initializer for struct field %s", field_it->toChars()); data[field_it.index] = *field_it; } } // ok. now we can build a list of llvm types. and make sure zeros are inserted if necessary. // first we sort the list by offset std::sort(data.begin(), data.end(), var_offset_sort_cb); // add types to list for (size_t i = 0; i < n; i++) { VarDeclaration* vd = data[i]; if (vd == NULL) continue; assert(vd->offset >= offset && "it's a bug... most likely DMD bug 2481"); // add to default field list if (cd == base) default_fields.push_back(vd); // get next aligned offset for this type size_t alignedoffset = realignOffset(offset, vd->type); // insert explicit padding? if (alignedoffset < vd->offset) { field_index += add_zeros(defaultTypes, vd->offset - alignedoffset); } // add default type defaultTypes.push_back(DtoType(vd->type)); // advance offset to right past this field offset = vd->offset + vd->type->size(); // create ir field vd->aggrIndex = (unsigned)field_index; ++field_index; } // any interface implementations? if (base->vtblInterfaces && base->vtblInterfaces->dim > 0) { bool new_instances = (base == cd); ArrayIter<BaseClass> it2(*base->vtblInterfaces); VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); Type* first = interfaces_idx->type->nextOf()->pointerTo(); // align offset offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1); for (; !it2.done(); it2.next()) { BaseClass* b = it2.get(); IF_LOG Logger::println("Adding interface vtbl for %s", b->base->toPrettyChars()); FuncDeclarations arr; b->fillVtbl(cd, &arr, new_instances); llvm::Type* ivtbl_type = llvm::StructType::get(gIR->context(), buildVtblType(first, &arr)); defaultTypes.push_back(llvm::PointerType::get(ivtbl_type, 0)); offset += PTRSIZE; // add to the interface map addInterfaceToMap(b->base, field_index); field_index++; // inc count num_interface_vtbls++; } } #if 0 // tail padding? if (offset < base->structsize) { field_index += add_zeros(defaultTypes, base->structsize - offset); offset = base->structsize; } #endif }
std::vector<llvm::Value*> DtoStructLiteralValues(const StructDeclaration* sd, const std::vector<llvm::Value*>& inits, bool isConst) { // get arrays size_t nvars = sd->fields.dim; VarDeclaration** vars = (VarDeclaration**)sd->fields.data; assert(inits.size() == nvars); // first locate all explicit initializers std::vector<VarDeclaration*> explicitInits; for (size_t i=0; i < nvars; i++) { if (inits[i]) { explicitInits.push_back(vars[i]); } } // vector of values to build aggregate from std::vector<llvm::Value*> values; // offset trackers size_t lastoffset = 0; size_t lastsize = 0; // index of next explicit init size_t exidx = 0; // number of explicit inits size_t nex = explicitInits.size(); // for through each field and build up the struct, padding with zeros size_t i; for (i=0; i<nvars; i++) { VarDeclaration* var = vars[i]; // get var info size_t os = var->offset; size_t sz = var->type->size(); // get next explicit VarDeclaration* nextVar = NULL; size_t nextOs = 0; if (exidx < nex) { nextVar = explicitInits[exidx]; nextOs = nextVar->offset; } // none, rest is defaults else { break; } // not explicit initializer, default initialize if there is room, otherwise skip if (!inits[i]) { // default init if there is room // (past current offset) and (small enough to fit before next explicit) if ((os >= lastoffset + lastsize) && (os+sz <= nextOs)) { // add any 0 padding needed before this field if (os > lastoffset + lastsize) { //printf("1added %lu zeros\n", os - lastoffset - lastsize); add_zeros(values, os - lastoffset - lastsize); } // get field default init IrField* f = var->ir.irField; assert(f); values.push_back(f->getDefaultInit()); lastoffset = os; lastsize = sz; //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz); } // skip continue; } assert(nextVar == var); // add any 0 padding needed before this field if (!isConst && os > lastoffset + lastsize) { //printf("added %lu zeros\n", os - lastoffset - lastsize); add_zeros(values, os - lastoffset - lastsize); } // add the expression value values.push_back(inits[i]); // update offsets lastoffset = os; #if DMDV2 // sometimes size of the initializer is less than size of the variable, // so make sure that lastsize is correct if (inits[i]->getType()->isSized()) lastsize = ceil(gTargetData->getTypeSizeInBits(inits[i]->getType()) / 8.0); else #endif lastsize = sz; // go to next explicit init exidx++; //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz); } // fill out rest with default initializers LLType* structtype = DtoType(sd->type); size_t structsize = getTypePaddedSize(structtype); // FIXME: this could probably share some code with the above if (structsize > lastoffset+lastsize) { for (/*continue from first loop*/; i < nvars; i++) { VarDeclaration* var = vars[i]; // get var info size_t os = var->offset; size_t sz = var->type->size(); // skip? if (os < lastoffset + lastsize) continue; // add any 0 padding needed before this field if (os > lastoffset + lastsize) { //printf("2added %lu zeros\n", os - lastoffset - lastsize); add_zeros(values, os - lastoffset - lastsize); } // get field default init IrField* f = var->ir.irField; assert(f); values.push_back(f->getDefaultInit()); lastoffset = os; lastsize = sz; //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz); } } // add any 0 padding needed at the end of the literal if (structsize > lastoffset+lastsize) { //printf("3added %lu zeros\n", structsize - lastoffset - lastsize); add_zeros(values, structsize - lastoffset - lastsize); } return values; }
IRLandingPadInfo::IRLandingPadInfo(Catch* catchstmt, llvm::BasicBlock* end) : finallyBody(NULL) { target = llvm::BasicBlock::Create(gIR->context(), "catch", gIR->topfunc(), end); gIR->scope() = IRScope(target,end); // assign storage to catch var if(catchstmt->var) { // use the same storage for all exceptions that are not accessed in // nested functions #if DMDV2 if(!catchstmt->var->nestedrefs.dim) { #else if(!catchstmt->var->nestedref) { #endif assert(!catchstmt->var->ir.irLocal); catchstmt->var->ir.irLocal = new IrLocal(catchstmt->var); LLValue* catch_var = gIR->func()->gen->landingPadInfo.getExceptionStorage(); catchstmt->var->ir.irLocal->value = gIR->ir->CreateBitCast(catch_var, getPtrToType(DtoType(catchstmt->var->type))); } // this will alloca if we haven't already and take care of nested refs DtoDeclarationExp(catchstmt->var); // the exception will only be stored in catch_var. copy it over if necessary if(catchstmt->var->ir.irLocal->value != gIR->func()->gen->landingPadInfo.getExceptionStorage()) { LLValue* exc = gIR->ir->CreateBitCast(DtoLoad(gIR->func()->gen->landingPadInfo.getExceptionStorage()), DtoType(catchstmt->var->type)); DtoStore(exc, catchstmt->var->ir.irLocal->value); } } // emit handler, if there is one // handler is zero for instance for 'catch { debug foo(); }' if(catchstmt->handler) catchstmt->handler->toIR(gIR); if (!gIR->scopereturned()) gIR->ir->CreateBr(end); assert(catchstmt->type); catchType = catchstmt->type->toBasetype()->isClassHandle(); assert(catchType); catchType->codegen(Type::sir); } IRLandingPadInfo::IRLandingPadInfo(Statement* finallystmt) : target(NULL), finallyBody(finallystmt), catchType(NULL) { } void IRLandingPad::addCatch(Catch* catchstmt, llvm::BasicBlock* end) { unpushed_infos.push_front(IRLandingPadInfo(catchstmt, end)); }
DValue* DtoNewClass(Loc& loc, TypeClass* tc, NewExp* newexp) { // resolve type DtoResolveClass(tc->sym); // allocate LLValue* mem; if (newexp->onstack) { // FIXME align scope class to its largest member mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), 0, ".newclass_alloca"); } // custom allocator else if (newexp->allocator) { DtoResolveFunction(newexp->allocator); DFuncValue dfn(newexp->allocator, getIrFunc(newexp->allocator)->func); DValue* res = DtoCallFunction(newexp->loc, NULL, &dfn, newexp->newargs); mem = DtoBitCast(res->getRVal(), DtoType(tc), ".newclass_custom"); } // default allocator else { llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_newclass"); LLConstant* ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(), DtoType(Type::typeinfoclass->type)); mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction(); mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc"); } // init DtoInitClass(tc, mem); // init inner-class outer reference if (newexp->thisexp) { Logger::println("Resolving outer class"); LOG_SCOPE; DValue* thisval = toElem(newexp->thisexp); unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis); LLValue* src = thisval->getRVal(); LLValue* dst = DtoGEPi(mem, 0, idx); IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType()))); } // set the context for nested classes else if (tc->sym->isNested() && tc->sym->vthis) { DtoResolveNestedContext(loc, tc->sym, mem); } // call constructor if (newexp->member) { Logger::println("Calling constructor"); assert(newexp->arguments != NULL); DtoResolveFunction(newexp->member); DFuncValue dfn(newexp->member, getIrFunc(newexp->member)->func, mem); return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); } // return default constructed class return new DImValue(tc, mem); }
DValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue) { // D2: // call: // extern(C) void* _aaGetY(AA* aa, TypeInfo aati, size_t valuesize, void* // pkey) // or // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function llvm::Function *func = getRuntimeFunction( loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX"); LLFunctionType *funcTy = func->getFunctionType(); // aa param LLValue *aaval = lvalue ? aa->getLVal() : aa->getRVal(); aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // pkey param LLValue *pkey = makeLValue(loc, key); pkey = DtoBitCast(pkey, funcTy->getParamType(lvalue ? 3 : 2)); // call runtime LLValue *ret; if (lvalue) { LLValue *rawAATI = DtoTypeInfoOf(aa->type->unSharedOf()->mutableOf(), false); LLValue *castedAATI = DtoBitCast(rawAATI, funcTy->getParamType(1)); LLValue *valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type))); ret = gIR->CreateCallOrInvoke(func, aaval, castedAATI, valsize, pkey, "aa.index") .getInstruction(); } else { LLValue *keyti = DtoBitCast(to_keyti(aa), funcTy->getParamType(1)); ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index") .getInstruction(); } // cast return value LLType *targettype = DtoPtrToType(type); if (ret->getType() != targettype) { ret = DtoBitCast(ret, targettype); } // Only check bounds for rvalues ('aa[key]'). // Lvalue use ('aa[key] = value') auto-adds an element. if (!lvalue && gIR->emitArrayBoundsChecks()) { llvm::BasicBlock *failbb = llvm::BasicBlock::Create( gIR->context(), "aaboundscheckfail", gIR->topfunc()); llvm::BasicBlock *okbb = llvm::BasicBlock::Create(gIR->context(), "aaboundsok", gIR->topfunc()); LLValue *nullaa = LLConstant::getNullValue(ret->getType()); LLValue *cond = gIR->ir->CreateICmpNE(nullaa, ret, "aaboundscheck"); gIR->ir->CreateCondBr(cond, okbb, failbb); // set up failbb to call the array bounds error runtime function gIR->scope() = IRScope(failbb); llvm::Function *errorfn = getRuntimeFunction(loc, gIR->module, "_d_arraybounds"); gIR->CreateCallOrInvoke( errorfn, DtoModuleFileName(gIR->func()->decl->getModule(), loc), DtoConstUint(loc.linnum)); // the function does not return gIR->ir->CreateUnreachable(); // if ok, proceed in okbb gIR->scope() = IRScope(okbb); } return new DVarValue(type, ret); }
void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB) { // save and rewrite scope IRScope savedscope = gIR->scope(); gIR->scope() = IRScope(inBB,savedscope.end); // personality fn llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality"); // create landingpad LLType *retType = LLStructType::get(LLType::getInt8PtrTy(gIR->context()), LLType::getInt32Ty(gIR->context()), NULL); llvm::LandingPadInst *landingPad = gIR->ir->CreateLandingPad(retType, personality_fn, 0); LLValue* eh_ptr = DtoExtractValue(landingPad, 0); LLValue* eh_sel = DtoExtractValue(landingPad, 1); // add landingpad clauses, emit finallys and 'if' chain to catch the exception llvm::Function* eh_typeid_for_fn = GET_INTRINSIC_DECL(eh_typeid_for); std::deque<IRLandingPadInfo> infos = this->infos; std::stack<size_t> nInfos = this->nInfos; std::deque<IRLandingPadInfo>::reverse_iterator rit, rend = infos.rend(); bool isFirstCatch = true; for(rit = infos.rbegin(); rit != rend; ++rit) { // if it's a finally, emit its code if(rit->finallyBody) { size_t n = this->nInfos.top(); this->infos.resize(n); this->nInfos.pop(); rit->finallyBody->toIR(gIR); landingPad->setCleanup(true); } // otherwise it's a catch and we'll add a if-statement else { // if it is a first catch and some catch allocated storage, store exception object if(isFirstCatch && catch_var) { LLType* objectTy = DtoType(ClassDeclaration::object->type); gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var); isFirstCatch = false; } // create next block llvm::BasicBlock *next = llvm::BasicBlock::Create(gIR->context(), "eh.next", gIR->topfunc(), gIR->scopeend()); // get class info symbol LLValue *classInfo = rit->catchType->ir.irStruct->getClassInfoSymbol(); // add that symbol as landing pad clause landingPad->addClause(classInfo); // call llvm.eh.typeid.for to get class info index in the exception table classInfo = DtoBitCast(classInfo, getPtrToType(DtoType(Type::tint8))); LLValue *eh_id = gIR->ir->CreateCall(eh_typeid_for_fn, classInfo); // check exception selector (eh_sel) against the class info index gIR->ir->CreateCondBr(gIR->ir->CreateICmpEQ(eh_sel, eh_id), rit->target, next); gIR->scope() = IRScope(next, gIR->scopeend()); } } // restore landing pad infos this->infos = infos; this->nInfos = nInfos; // no catch matched and all finallys executed - resume unwind llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind"); gIR->ir->CreateCall(unwind_resume_fn, eh_ptr); gIR->ir->CreateUnreachable(); // restore scope gIR->scope() = savedscope; }
LLConstant * IrStruct::getVtblInit() { if (constVtbl) return constVtbl; IF_LOG Logger::println("Building vtbl initializer"); LOG_SCOPE; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd && "not class"); std::vector<llvm::Constant*> constants; constants.reserve(cd->vtbl.dim); // start with the classinfo llvm::Constant* c = getClassInfoSymbol(); c = DtoBitCast(c, DtoType(ClassDeclaration::classinfo->type)); constants.push_back(c); // add virtual function pointers size_t n = cd->vtbl.dim; for (size_t i = 1; i < n; i++) { Dsymbol* dsym = static_cast<Dsymbol*>(cd->vtbl.data[i]); assert(dsym && "null vtbl member"); FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); if (cd->isAbstract() || (fd->isAbstract() && !fd->fbody)) { c = getNullValue(DtoType(fd->type->pointerTo())); } else { fd->codegen(Type::sir); assert(fd->ir.irFunc && "invalid vtbl function"); c = fd->ir.irFunc->func; #if DMDV2 if (cd->isFuncHidden(fd)) { /* fd is hidden from the view of this class. * If fd overlaps with any function in the vtbl[], then * issue 'hidden' error. */ for (size_t j = 1; j < n; j++) { if (j == i) continue; FuncDeclaration *fd2 = static_cast<Dsymbol *>(cd->vtbl.data[j])->isFuncDeclaration(); if (!fd2->ident->equals(fd->ident)) continue; if (fd->leastAsSpecialized(fd2) || fd2->leastAsSpecialized(fd)) { if (global.params.warnings) { TypeFunction *tf = static_cast<TypeFunction *>(fd->type); if (tf->ty == Tfunction) error("%s%s is hidden by %s\n", fd->toPrettyChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), toChars()); else error("%s is hidden by %s\n", fd->toPrettyChars(), toChars()); } c = DtoBitCast(LLVM_D_GetRuntimeFunction(gIR->module, "_d_hidden_func"), c->getType()); break; } } } #endif } constants.push_back(c); } // build the constant struct LLType* vtblTy = stripModifiers(type)->irtype->isClass()->getVtbl(); constVtbl = LLConstantStruct::get(isaStruct(vtblTy), constants); #if 0 IF_LOG Logger::cout() << "constVtbl type: " << *constVtbl->getType() << std::endl; IF_LOG Logger::cout() << "vtbl type: " << *stripModifiers(type)->irtype->isClass()->getVtbl() << std::endl; #endif #if 0 size_t nc = constants.size(); for (size_t i = 0; i < nc; ++i) { if (constVtbl->getOperand(i)->getType() != vtblTy->getContainedType(i)) { Logger::cout() << "type mismatch for entry # " << i << " in vtbl initializer" << std::endl; constVtbl->getOperand(i)->dump(); vtblTy->getContainedType(i)->dump(); } } #endif assert(constVtbl->getType() == stripModifiers(type)->irtype->isClass()->getVtbl() && "vtbl initializer type mismatch"); return constVtbl; }
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 IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB) { // save and rewrite scope IRScope savedscope = gIR->scope(); gIR->scope() = IRScope(inBB,savedscope.end); // eh_ptr = llvm.eh.exception(); llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception); LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn); // build selector arguments LLSmallVector<LLValue*, 6> selectorargs; // put in classinfos in the right order bool hasFinally = false; bool hasCatch = false; std::deque<IRLandingPadInfo>::iterator it = infos.begin(), end = infos.end(); for(; it != end; ++it) { if(it->finallyBody) hasFinally = true; else { hasCatch = true; assert(it->catchType); assert(it->catchType->ir.irStruct); selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->getClassInfoSymbol()); } } // if there's a finally, the eh table has to have a 0 action if(hasFinally) selectorargs.push_back(DtoConstUint(0)); // personality fn llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality"); LLValue* personality_fn_arg = gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::getInt8Ty(gIR->context()))); selectorargs.insert(selectorargs.begin(), personality_fn_arg); // eh storage target selectorargs.insert(selectorargs.begin(), eh_ptr); // if there is a catch and some catch allocated storage, store exception object if(hasCatch && catch_var) { const LLType* objectTy = DtoType(ClassDeclaration::object->type); gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var); } // eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, <selectorargs>); llvm::Function* eh_selector_fn = GET_INTRINSIC_DECL(eh_selector); LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, selectorargs.begin(), selectorargs.end()); // emit finallys and 'if' chain to catch the exception llvm::Function* eh_typeid_for_fn = GET_INTRINSIC_DECL(eh_typeid_for); std::deque<IRLandingPadInfo> infos = this->infos; std::stack<size_t> nInfos = this->nInfos; std::deque<IRLandingPadInfo>::reverse_iterator rit, rend = infos.rend(); for(rit = infos.rbegin(); rit != rend; ++rit) { // if it's a finally, emit its code if(rit->finallyBody) { size_t n = this->nInfos.top(); this->infos.resize(n); this->nInfos.pop(); rit->finallyBody->toIR(gIR); } // otherwise it's a catch and we'll add a if-statement else { llvm::BasicBlock *next = llvm::BasicBlock::Create(gIR->context(), "eh.next", gIR->topfunc(), gIR->scopeend()); LLValue *classInfo = DtoBitCast(rit->catchType->ir.irStruct->getClassInfoSymbol(), getPtrToType(DtoType(Type::tint8))); LLValue *eh_id = gIR->ir->CreateCall(eh_typeid_for_fn, classInfo); gIR->ir->CreateCondBr(gIR->ir->CreateICmpEQ(eh_sel, eh_id), rit->target, next); gIR->scope() = IRScope(next, gIR->scopeend()); } } // restore landing pad infos this->infos = infos; this->nInfos = nInfos; // no catch matched and all finallys executed - resume unwind llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind"); gIR->ir->CreateCall(unwind_resume_fn, eh_ptr); gIR->ir->CreateUnreachable(); gIR->scope() = savedscope; }
void DtoResolveStruct(StructDeclaration* sd) { // don't do anything if already been here if (sd->ir.resolved) return; // make sure above works :P sd->ir.resolved = true; // log what we're doing Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->loc.toChars()); LOG_SCOPE; // make sure type exists DtoType(sd->type); // if it's a forward declaration, all bets are off. The type should be enough if (sd->sizeok != 1) return; // create the IrStruct IrStruct* irstruct = new IrStruct(sd); sd->ir.irStruct = irstruct; // make sure all fields really get their ir field ArrayIter<VarDeclaration> it(sd->fields); for (; !it.done(); it.next()) { VarDeclaration* vd = it.get(); if (vd->ir.irField == NULL) { new IrField(vd); } else { IF_LOG Logger::println("struct field already exists!!!"); } } // perform definition bool needs_def = mustDefineSymbol(sd); if (needs_def) { // emit the initZ symbol LLGlobalVariable* initZ = irstruct->getInitSymbol(); // set initZ initializer initZ->setInitializer(irstruct->getDefaultInit()); } // emit members if (sd->members) { ArrayIter<Dsymbol> it(*sd->members); while (!it.done()) { Dsymbol* member = it.get(); if (member) member->codegen(Type::sir); it.next(); } } if (needs_def) { // emit typeinfo DtoTypeInfoOf(sd->type); } }
LLType* DtoType(Type* t) { t = stripModifiers( t ); if (t->ctype) { return t->ctype->getLLType(); } IF_LOG Logger::println("Building type: %s", t->toChars()); LOG_SCOPE; assert(t); switch (t->ty) { // basic types case Tvoid: case Tint8: case Tuns8: case Tint16: case Tuns16: case Tint32: case Tuns32: case Tint64: case Tuns64: case Tint128: case Tuns128: case Tfloat32: case Tfloat64: case Tfloat80: case Timaginary32: case Timaginary64: case Timaginary80: case Tcomplex32: case Tcomplex64: case Tcomplex80: //case Tbit: case Tbool: case Tchar: case Twchar: case Tdchar: { return IrTypeBasic::get(t)->getLLType(); } // pointers case Tnull: case Tpointer: { return IrTypePointer::get(t)->getLLType(); } // arrays case Tarray: { return IrTypeArray::get(t)->getLLType(); } case Tsarray: { return IrTypeSArray::get(t)->getLLType(); } // aggregates case Tstruct: { TypeStruct* ts = static_cast<TypeStruct*>(t); if (ts->sym->type->ctype) { // This should not happen, but the frontend seems to be buggy. Not // sure if this is the best way to handle the situation, but we // certainly don't want to override ts->sym->type->ctype. IF_LOG Logger::cout() << "Struct with multiple Types detected: " << ts->toChars() << " (" << ts->sym->locToChars() << ")" << std::endl; return ts->sym->type->ctype->getLLType(); } return IrTypeStruct::get(ts->sym)->getLLType(); } case Tclass: { TypeClass* tc = static_cast<TypeClass*>(t); if (tc->sym->type->ctype) { // See Tstruct case. IF_LOG Logger::cout() << "Class with multiple Types detected: " << tc->toChars() << " (" << tc->sym->locToChars() << ")" << std::endl; return tc->sym->type->ctype->getLLType(); } return IrTypeClass::get(tc->sym)->getLLType(); } // functions case Tfunction: { return IrTypeFunction::get(t)->getLLType(); } // delegates case Tdelegate: { return IrTypeDelegate::get(t)->getLLType(); } // typedefs // enum // FIXME: maybe just call toBasetype first ? case Tenum: { Type* bt = t->toBasetype(); assert(bt); return DtoType(bt); } // associative arrays case Taarray: return getVoidPtrType(); case Tvector: { return IrTypeVector::get(t)->getLLType(); } /* Not needed atm as VarDecls for tuples are rewritten as a string of VarDecls for the fields (u -> _u_field_0, ...) case Ttuple: { TypeTuple* ttupl = static_cast<TypeTuple*>(t); return DtoStructTypeFromArguments(ttupl->arguments); } */ default: llvm_unreachable("Unknown class of D Type!"); } return 0; }
static void buildRuntimeModule() { Logger::println("building runtime module"); M = new llvm::Module("ldc internal runtime", gIR->context()); Type *voidTy = Type::tvoid; Type *boolTy = Type::tbool; Type *ubyteTy = Type::tuns8; Type *intTy = Type::tint32; Type *uintTy = Type::tuns32; Type *ulongTy = Type::tuns64; Type *sizeTy = Type::tsize_t; Type *dcharTy = Type::tdchar; Type *voidPtrTy = Type::tvoidptr; Type *voidArrayTy = Type::tvoid->arrayOf(); Type *voidArrayPtrTy = voidArrayTy->pointerTo(); Type *stringTy = Type::tchar->arrayOf(); Type *wstringTy = Type::twchar->arrayOf(); Type *dstringTy = Type::tdchar->arrayOf(); // Ensure that the declarations exist before creating llvm types for them. ensureDecl(ClassDeclaration::object, "Object"); ensureDecl(Type::typeinfoclass, "TypeInfo_Class"); ensureDecl(Type::dtypeinfo, "DTypeInfo"); ensureDecl(Type::typeinfoassociativearray, "TypeInfo_AssociativeArray"); ensureDecl(Module::moduleinfo, "ModuleInfo"); Type *objectTy = ClassDeclaration::object->type; Type *classInfoTy = Type::typeinfoclass->type; Type *typeInfoTy = Type::dtypeinfo->type; Type *aaTypeInfoTy = Type::typeinfoassociativearray->type; Type *moduleInfoPtrTy = Module::moduleinfo->type->pointerTo(); // The AA type is a struct that only contains a ptr Type *aaTy = voidPtrTy; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Construct some attribute lists used below (possibly multiple times) AttrSet NoAttrs, Attr_NoAlias(NoAttrs, 0, llvm::Attribute::NoAlias), Attr_NoUnwind(NoAttrs, ~0U, llvm::Attribute::NoUnwind), Attr_ReadOnly(NoAttrs, ~0U, llvm::Attribute::ReadOnly), Attr_ReadOnly_NoUnwind(Attr_ReadOnly, ~0U, llvm::Attribute::NoUnwind), Attr_ReadOnly_1_NoCapture(Attr_ReadOnly, 1, llvm::Attribute::NoCapture), Attr_ReadOnly_1_3_NoCapture(Attr_ReadOnly_1_NoCapture, 3, llvm::Attribute::NoCapture), Attr_ReadOnly_NoUnwind_1_NoCapture(Attr_ReadOnly_1_NoCapture, ~0U, llvm::Attribute::NoUnwind), Attr_ReadNone(NoAttrs, ~0U, llvm::Attribute::ReadNone), Attr_1_NoCapture(NoAttrs, 1, llvm::Attribute::NoCapture), Attr_NoAlias_1_NoCapture(Attr_1_NoCapture, 0, llvm::Attribute::NoAlias), Attr_1_2_NoCapture(Attr_1_NoCapture, 2, llvm::Attribute::NoCapture), Attr_1_3_NoCapture(Attr_1_NoCapture, 3, llvm::Attribute::NoCapture), Attr_1_4_NoCapture(Attr_1_NoCapture, 4, llvm::Attribute::NoCapture); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void _d_assert(string file, uint line) // void _d_arraybounds(string file, uint line) createFwdDecl(LINKc, Type::tvoid, {"_d_assert", "_d_arraybounds"}, {stringTy, uintTy}); // void _d_assert_msg(string msg, string file, uint line) createFwdDecl(LINKc, voidTy, {"_d_assert_msg"}, {stringTy, stringTy, uintTy}); // void _d_assertm(immutable(ModuleInfo)* m, uint line) // void _d_array_bounds(immutable(ModuleInfo)* m, uint line) // void _d_switch_error(immutable(ModuleInfo)* m, uint line) createFwdDecl(LINKc, voidTy, {"_d_assertm", "_d_array_bounds", "_d_switch_error"}, {moduleInfoPtrTy, uintTy}, {STCimmutable, 0}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void* _d_allocmemory(size_t sz) createFwdDecl(LINKc, voidPtrTy, {"_d_allocmemory"}, {sizeTy}, {}, Attr_NoAlias); // void* _d_allocmemoryT(TypeInfo ti) createFwdDecl(LINKc, voidPtrTy, {"_d_allocmemoryT"}, {typeInfoTy}, {}, Attr_NoAlias); // void[] _d_newarrayT (const TypeInfo ti, size_t length) // void[] _d_newarrayiT(const TypeInfo ti, size_t length) // void[] _d_newarrayU (const TypeInfo ti, size_t length) createFwdDecl(LINKc, voidArrayTy, {"_d_newarrayT", "_d_newarrayiT", "_d_newarrayU"}, {typeInfoTy, sizeTy}, {STCconst, 0}); // void[] _d_newarraymTX (const TypeInfo ti, size_t[] dims) // void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) createFwdDecl(LINKc, voidArrayTy, {"_d_newarraymTX", "_d_newarraymiTX"}, {typeInfoTy, sizeTy->arrayOf()}, {STCconst, 0}); // void[] _d_arraysetlengthT (const TypeInfo ti, size_t newlength, void[]* p) // void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p) createFwdDecl(LINKc, voidArrayTy, {"_d_arraysetlengthT", "_d_arraysetlengthiT"}, {typeInfoTy, sizeTy, voidArrayPtrTy}, {STCconst, 0, 0}); // byte[] _d_arrayappendcTX(const TypeInfo ti, ref byte[] px, size_t n) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendcTX"}, {typeInfoTy, voidArrayTy, sizeTy}, {STCconst, STCref, 0}); // void[] _d_arrayappendT(const TypeInfo ti, ref byte[] x, byte[] y) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendT"}, {typeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, STCref, 0}); // void[] _d_arrayappendcd(ref byte[] x, dchar c) // void[] _d_arrayappendwd(ref byte[] x, dchar c) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendcd", "_d_arrayappendwd"}, {voidArrayTy, dcharTy}, {STCref, 0}); // byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y) createFwdDecl(LINKc, voidArrayTy, {"_d_arraycatT"}, {typeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, 0, 0}); // void[] _d_arraycatnTX(const TypeInfo ti, byte[][] arrs) createFwdDecl(LINKc, voidArrayTy, {"_d_arraycatnTX"}, {typeInfoTy, voidArrayTy->arrayOf()}, {STCconst, 0}); // Object _d_newclass(const ClassInfo ci) createFwdDecl(LINKc, objectTy, {"_d_newclass"}, {classInfoTy}, {STCconst}, Attr_NoAlias); // void* _d_newitemT (TypeInfo ti) // void* _d_newitemiT(TypeInfo ti) createFwdDecl(LINKc, voidPtrTy, {"_d_newitemT", "_d_newitemiT"}, {typeInfoTy}, {0}, Attr_NoAlias); // void _d_delarray_t(void[]* p, const TypeInfo_Struct ti) createFwdDecl(LINKc, voidTy, {"_d_delarray_t"}, {voidArrayPtrTy, Type::typeinfostruct->type}, {0, STCconst}); // void _d_delmemory(void** p) // void _d_delinterface(void** p) createFwdDecl(LINKc, voidTy, {"_d_delmemory", "_d_delinterface"}, {voidPtrTy->pointerTo()}); // void _d_callfinalizer(void* p) createFwdDecl(LINKc, voidTy, {"_d_callfinalizer"}, {voidPtrTy}); // D2: void _d_delclass(Object* p) createFwdDecl(LINKc, voidTy, {"_d_delclass"}, {objectTy->pointerTo()}); // void _d_delstruct(void** p, TypeInfo_Struct inf) createFwdDecl(LINKc, voidTy, {"_d_delstruct"}, {voidPtrTy->pointerTo(), Type::typeinfostruct->type}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // array slice copy when assertions are on! // void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t // srclen) createFwdDecl(LINKc, voidTy, {"_d_array_slice_copy"}, {voidPtrTy, sizeTy, voidPtrTy, sizeTy}, {}, Attr_1_3_NoCapture); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // int _aApplycd1(in char[] aa, dg_t dg) // int _aApplyRcd1(in char[] aa, dg_t dg) #define STR_APPLY1(TY, a, b) \ { \ const std::string prefix = "_aApply"; \ std::string fname1 = prefix + (a) + '1', fname2 = prefix + (b) + '1', \ fname3 = prefix + 'R' + (a) + '1', \ fname4 = prefix + 'R' + (b) + '1'; \ createFwdDecl(LINKc, sizeTy, {fname1, fname2, fname3, fname4}, \ {TY, rt_dg1()}); \ } STR_APPLY1(stringTy, "cw", "cd") STR_APPLY1(wstringTy, "wc", "wd") STR_APPLY1(dstringTy, "dc", "dw") #undef STR_APPLY1 // int _aApplycd2(in char[] aa, dg2_t dg) // int _aApplyRcd2(in char[] aa, dg2_t dg) #define STR_APPLY2(TY, a, b) \ { \ const std::string prefix = "_aApply"; \ std::string fname1 = prefix + (a) + '2', fname2 = prefix + (b) + '2', \ fname3 = prefix + 'R' + (a) + '2', \ fname4 = prefix + 'R' + (b) + '2'; \ createFwdDecl(LINKc, sizeTy, {fname1, fname2, fname3, fname4}, \ {TY, rt_dg2()}); \ } STR_APPLY2(stringTy, "cw", "cd") STR_APPLY2(wstringTy, "wc", "wd") STR_APPLY2(dstringTy, "dc", "dw") #undef STR_APPLY2 ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // fixes the length for dynamic array casts // size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz) createFwdDecl(LINKc, sizeTy, {"_d_array_cast_len"}, {sizeTy, sizeTy, sizeTy}, {}, Attr_ReadNone); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp) // void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayassign_l", "_d_arrayassign_r"}, {typeInfoTy, voidArrayTy, voidArrayTy, voidPtrTy}); // void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayctor"}, {typeInfoTy, voidArrayTy, voidArrayTy}); // void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti) // void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti) createFwdDecl(LINKc, voidPtrTy, {"_d_arraysetassign", "_d_arraysetctor"}, {voidPtrTy, voidPtrTy, intTy, typeInfoTy}, {}, Attr_NoAlias); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // cast interface // void* _d_interface_cast(void* p, ClassInfo c) createFwdDecl(LINKc, voidPtrTy, {"_d_interface_cast"}, {voidPtrTy, classInfoTy}, {}, Attr_ReadOnly_NoUnwind); // dynamic cast // void* _d_dynamic_cast(Object o, ClassInfo c) createFwdDecl(LINKc, voidPtrTy, {"_d_dynamic_cast"}, {objectTy, classInfoTy}, {}, Attr_ReadOnly_NoUnwind); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // char[] _adReverseChar(char[] a) // char[] _adSortChar(char[] a) createFwdDecl(LINKc, stringTy, {"_adReverseChar", "_adSortChar"}, {stringTy}); // wchar[] _adReverseWchar(wchar[] a) // wchar[] _adSortWchar(wchar[] a) createFwdDecl(LINKc, wstringTy, {"_adReverseWchar", "_adSortWchar"}, {wstringTy}); // void[] _adReverse(void[] a, size_t szelem) createFwdDecl(LINKc, wstringTy, {"_adReverse"}, {voidArrayTy, sizeTy}, {}, Attr_NoUnwind); // int _adEq2(void[] a1, void[] a2, TypeInfo ti) // int _adCmp2(void[] a1, void[] a2, TypeInfo ti) createFwdDecl(LINKc, intTy, {"_adEq2", "_adCmp2"}, {voidArrayTy, voidArrayTy, typeInfoTy}, {}, Attr_ReadOnly); // int _adCmpChar(void[] a1, void[] a2) createFwdDecl(LINKc, intTy, {"_adCmpChar"}, {voidArrayTy, voidArrayTy}, {}, Attr_ReadOnly_NoUnwind); // void[] _adSort(void[] a, TypeInfo ti) createFwdDecl(LINKc, voidArrayTy, {"_adSort"}, {voidArrayTy, typeInfoTy}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // size_t _aaLen(in AA aa) createFwdDecl(LINKc, sizeTy, {"_aaLen"}, {aaTy}, {STCin}, Attr_ReadOnly_NoUnwind_1_NoCapture); // void* _aaGetY(AA* aa, const TypeInfo aati, in size_t valuesize, // in void* pkey) createFwdDecl(LINKc, voidPtrTy, {"_aaGetY"}, {aaTy->pointerTo(), aaTypeInfoTy, sizeTy, voidPtrTy}, {0, STCconst, STCin, STCin}, Attr_1_4_NoCapture); // inout(void)* _aaInX(inout AA aa, in TypeInfo keyti, in void* pkey) // FIXME: "inout" storageclass is not applied to return type createFwdDecl(LINKc, voidPtrTy, {"_aaInX"}, {aaTy, typeInfoTy, voidPtrTy}, {STCin | STCout, STCin, STCin}, Attr_ReadOnly_1_3_NoCapture); // bool _aaDelX(AA aa, in TypeInfo keyti, in void* pkey) createFwdDecl(LINKc, boolTy, {"_aaDelX"}, {aaTy, typeInfoTy, voidPtrTy}, {0, STCin, STCin}, Attr_1_3_NoCapture); // inout(void[]) _aaValues(inout AA aa, in size_t keysize, // in size_t valuesize, const TypeInfo tiValueArray) createFwdDecl( LINKc, voidArrayTy, {"_aaValues"}, {aaTy, sizeTy, sizeTy, typeInfoTy}, {STCin | STCout, STCin, STCin, STCconst}, Attr_ReadOnly_1_3_NoCapture); // void* _aaRehash(AA* paa, in TypeInfo keyti) createFwdDecl(LINKc, voidPtrTy, {"_aaRehash"}, {aaTy->pointerTo(), typeInfoTy}, {0, STCin}); // inout(void[]) _aaKeys(inout AA aa, in size_t keysize, // const TypeInfo tiKeyArray) createFwdDecl(LINKc, voidArrayTy, {"_aaKeys"}, {aaTy, sizeTy, typeInfoTy}, {STCin | STCout, STCin, STCconst}, Attr_NoAlias_1_NoCapture); // int _aaApply(AA aa, in size_t keysize, dg_t dg) createFwdDecl(LINKc, intTy, {"_aaApply"}, {aaTy, sizeTy, rt_dg1()}, {0, STCin, 0}, Attr_1_NoCapture); // int _aaApply2(AA aa, in size_t keysize, dg2_t dg) createFwdDecl(LINKc, intTy, {"_aaApply2"}, {aaTy, sizeTy, rt_dg2()}, {0, STCin, 0}, Attr_1_NoCapture); // int _aaEqual(in TypeInfo tiRaw, in AA e1, in AA e2) createFwdDecl(LINKc, intTy, {"_aaEqual"}, {typeInfoTy, aaTy, aaTy}, {STCin, STCin, STCin}, Attr_1_2_NoCapture); // AA _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, // void[] keys, void[] values) createFwdDecl(LINKc, aaTy, {"_d_assocarrayliteralTX"}, {aaTypeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, 0, 0}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void _moduleCtor() // void _moduleDtor() createFwdDecl(LINKc, voidTy, {"_moduleCtor", "_moduleDtor"}, {}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void _d_throw_exception(Object e) createFwdDecl(LINKc, voidTy, {"_d_throw_exception"}, {objectTy}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // int _d_switch_string(char[][] table, char[] ca) createFwdDecl(LINKc, intTy, {"_d_switch_string"}, {stringTy->arrayOf(), stringTy}, {}, Attr_ReadOnly); // int _d_switch_ustring(wchar[][] table, wchar[] ca) createFwdDecl(LINKc, intTy, {"_d_switch_ustring"}, {wstringTy->arrayOf(), wstringTy}, {}, Attr_ReadOnly); // int _d_switch_dstring(dchar[][] table, dchar[] ca) createFwdDecl(LINKc, intTy, {"_d_switch_dstring"}, {dstringTy->arrayOf(), dstringTy}, {}, Attr_ReadOnly); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // int _d_eh_personality(...) { if (global.params.targetTriple.isWindowsMSVCEnvironment()) { // (ptr ExceptionRecord, ptr EstablisherFrame, ptr ContextRecord, // ptr DispatcherContext) createFwdDecl(LINKc, intTy, {"_d_eh_personality"}, {voidPtrTy, voidPtrTy, voidPtrTy, voidPtrTy}); } else if (global.params.targetTriple.getArch() == llvm::Triple::arm) { // (int state, ptr ucb, ptr context) createFwdDecl(LINKc, intTy, {"_d_eh_personality"}, {intTy, voidPtrTy, voidPtrTy}); } else { // (int ver, int actions, ulong eh_class, ptr eh_info, ptr context) createFwdDecl(LINKc, intTy, {"_d_eh_personality"}, {intTy, intTy, ulongTy, voidPtrTy, voidPtrTy}); } } // void _d_eh_resume_unwind(ptr) createFwdDecl(LINKc, voidTy, {"_d_eh_resume_unwind"}, {voidPtrTy}); // Object _d_eh_enter_catch(ptr) createFwdDecl(LINKc, objectTy, {"_d_eh_enter_catch"}, {voidPtrTy}, {}, Attr_NoUnwind); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void invariant._d_invariant(Object o) createFwdDecl( LINKd, voidTy, {gABI->mangleForLLVM("_D9invariant12_d_invariantFC6ObjectZv", LINKd)}, {objectTy}); // void _d_dso_registry(CompilerDSOData* data) llvm::StringRef fname("_d_dso_registry"); LLType *LLvoidTy = LLType::getVoidTy(gIR->context()); LLType *LLvoidPtrPtrTy = getPtrToType(getPtrToType(LLvoidTy)); LLType *moduleInfoPtrPtrTy = getPtrToType(getPtrToType(DtoType(Module::moduleinfo->type))); llvm::StructType *dsoDataTy = llvm::StructType::get(DtoSize_t(), // version LLvoidPtrPtrTy, // slot moduleInfoPtrPtrTy, // _minfo_beg moduleInfoPtrPtrTy, // _minfo_end NULL); llvm::Type *types[] = {getPtrToType(dsoDataTy)}; llvm::FunctionType *fty = llvm::FunctionType::get(LLvoidTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // extern (C) void _d_cover_register2(string filename, size_t[] valid, // uint[] data, ubyte minPercent) if (global.params.cov) { createFwdDecl(LINKc, voidTy, {"_d_cover_register2"}, {stringTy, sizeTy->arrayOf(), uintTy->arrayOf(), ubyteTy}); } }
DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue) { // D1: // call: // extern(C) void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey) // or // extern(C) void* _aaIn(AA aa*, TypeInfo keyti, void* pkey) // D2: // call: // extern(C) void* _aaGetX(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey) // or // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, lvalue?"_aaGetX":"_aaInX"); LLFunctionType* funcTy = func->getFunctionType(); // aa param LLValue* aaval = lvalue ? aa->getLVal() : aa->getRVal(); aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param LLValue* keyti = to_keyti(aa); keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param LLValue* pkey = makeLValue(loc, key); pkey = DtoBitCast(pkey, funcTy->getParamType(lvalue ? 3 : 2)); // call runtime LLValue* ret; if (lvalue) { // valuesize param LLValue* valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type))); ret = gIR->CreateCallOrInvoke4(func, aaval, keyti, valsize, pkey, "aa.index").getInstruction(); } else { ret = gIR->CreateCallOrInvoke3(func, aaval, keyti, pkey, "aa.index").getInstruction(); } // cast return value LLType* targettype = getPtrToType(DtoType(type)); if (ret->getType() != targettype) ret = DtoBitCast(ret, targettype); // Only check bounds for rvalues ('aa[key]'). // Lvalue use ('aa[key] = value') auto-adds an element. if (!lvalue && global.params.useArrayBounds) { llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* failbb = llvm::BasicBlock::Create(gIR->context(), "aaboundscheckfail", gIR->topfunc(), oldend); llvm::BasicBlock* okbb = llvm::BasicBlock::Create(gIR->context(), "aaboundsok", gIR->topfunc(), oldend); LLValue* nullaa = LLConstant::getNullValue(ret->getType()); LLValue* cond = gIR->ir->CreateICmpNE(nullaa, ret, "aaboundscheck"); gIR->ir->CreateCondBr(cond, okbb, failbb); // set up failbb to call the array bounds error runtime function gIR->scope() = IRScope(failbb, okbb); std::vector<LLValue*> args; // module param LLValue *moduleInfoSymbol = gIR->func()->decl->getModule()->moduleInfoSymbol(); LLType *moduleInfoType = DtoType(Module::moduleinfo->type); args.push_back(DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType))); // line param LLConstant* c = DtoConstUint(loc.linnum); args.push_back(c); // call llvm::Function* errorfn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_array_bounds"); gIR->CreateCallOrInvoke(errorfn, args); // the function does not return gIR->ir->CreateUnreachable(); // if ok, proceed in okbb gIR->scope() = IRScope(okbb, oldend); } return new DVarValue(type, ret); }
bool X86_64TargetABI::passByVal(Type* t) { t = t->toBasetype(); if (linkage() == LINKd) { return t->toBasetype()->ty == Tstruct; } else { // This implements the C calling convention for x86-64. // It might not be correct for other calling conventions. Classification cl = classify(t); if (cl.isMemory) return true; // Figure out how many registers we want for this arg: RegCount wanted = { 0, 0 }; for (int i = 0 ; i < 2; i++) { if (cl.classes[i] == Integer) wanted.int_regs++; else if (cl.classes[i] == Sse) wanted.sse_regs++; } // See if they're available: RegCount& state = this->state(); if (wanted.int_regs <= state.int_regs && wanted.sse_regs <= state.sse_regs) { state.int_regs -= wanted.int_regs; state.sse_regs -= wanted.sse_regs; } else { if (keepUnchanged(t)) { // Not enough registers available, but this is passed as if it's // multiple arguments. Just use the registers there are, // automatically spilling the rest to memory. if (wanted.int_regs > state.int_regs) state.int_regs = 0; else state.int_regs -= wanted.int_regs; if (wanted.sse_regs > state.sse_regs) state.sse_regs = 0; else state.sse_regs -= wanted.sse_regs; } else if (t->iscomplex() || t->ty == Tstruct) { // Spill entirely to memory, even if some of the registers are // available. // FIXME: Don't do this if *none* of the wanted registers are available, // (i.e. only when absolutely necessary for abi-compliance) // so it gets alloca'd by the callee and -scalarrepl can // more easily break it up? // Note: this won't be necessary if the following LLVM bug gets fixed: // http://llvm.org/bugs/show_bug.cgi?id=3741 return true; } else { assert(t == Type::tfloat80 || t == Type::timaginary80 || t->ty == Tsarray || t->size() <= 8 && "What other big types are there?"); // In any case, they shouldn't be represented as structs in LLVM: assert(!isaStruct(DtoType(t))); } } // Everything else that's passed in memory is handled by LLVM. return false; } }