LLType* getBiggestType(LLType** begin, size_t n) { LLType* bigTy = 0; size_t bigSize = 0; size_t bigAlign = 0; LLType** end = begin+n; while (begin != end) { LLType* T = *begin; size_t sz = getTypePaddedSize(T); size_t ali = getABITypeAlign(T); if (sz > bigSize || (sz == bigSize && ali > bigAlign)) { bigTy = T; bigSize = sz; bigAlign = ali; } ++begin; } // will be null for n==0 return bigTy; }
void RTTIBuilder::push_void_array(llvm::Constant* CI, Type* valtype, Dsymbol* mangle_sym) { std::string initname(mangle_sym->mangle()); initname.append(".rtti.voidarr.data"); LLGlobalVariable* G = new llvm::GlobalVariable( *gIR->module, CI->getType(), true, TYPEINFO_LINKAGE_TYPE, CI, initname); G->setAlignment(valtype->alignsize()); push_void_array(getTypePaddedSize(CI->getType()), G); }
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; // 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), "tmp"); }
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)); }
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); }
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); }
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; }
LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) { // The layout is: // { // void **vptr; // monitor_t monitor; // byte[] initializer; // static initialization data // char[] name; // class name // void *[] vtbl; // Interface[] interfaces; // ClassInfo *base; // base class // void *destructor; // void *invariant; // class invariant // uint flags; // void *deallocator; // OffsetTypeInfo[] offTi; // void *defaultConstructor; // version(D_Version2) // immutable(void)* m_RTInfo; // else // TypeInfo typeinfo; // since dmd 1.045 // } Logger::println("DtoDefineClassInfo(%s)", cd->toChars()); LOG_SCOPE; assert(cd->type->ty == Tclass); TypeClass* cdty = static_cast<TypeClass*>(cd->type); IrStruct* ir = cd->ir.irStruct; assert(ir); ClassDeclaration* cinfo = ClassDeclaration::classinfo; if (cinfo->fields.dim != 12) { error("object.d ClassInfo class is incorrect"); fatal(); } // use the rtti builder RTTIBuilder b(ClassDeclaration::classinfo); LLConstant* c; LLType* voidPtr = getVoidPtrType(); LLType* voidPtrPtr = getPtrToType(voidPtr); // byte[] init if (cd->isInterfaceDeclaration()) { b.push_null_void_array(); } else { LLType* cd_type = cdty->irtype->isClass()->getMemoryLLType(); size_t initsz = getTypePaddedSize(cd_type); b.push_void_array(initsz, ir->getInitSymbol()); } // class name // code from dmd const char *name = cd->ident->toChars(); size_t namelen = strlen(name); if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) { name = cd->toPrettyChars(); namelen = strlen(name); } b.push_string(name); // vtbl array if (cd->isInterfaceDeclaration()) { b.push_array(0, getNullValue(voidPtrPtr)); } else { c = DtoBitCast(ir->getVtblSymbol(), voidPtrPtr); b.push_array(cd->vtbl.dim, c); } // interfaces array b.push(ir->getClassInfoInterfaces()); // base classinfo // interfaces never get a base , just the interfaces[] if (cd->baseClass && !cd->isInterfaceDeclaration()) b.push_classinfo(cd->baseClass); else b.push_null(cinfo->type); // destructor if (cd->isInterfaceDeclaration()) b.push_null_vp(); else b.push(build_class_dtor(cd)); // invariant VarDeclaration* invVar = static_cast<VarDeclaration*>(cinfo->fields.data[6]); b.push_funcptr(cd->inv, invVar->type); // uint flags unsigned flags; if (cd->isInterfaceDeclaration()) flags = 4 | cd->isCOMinterface() | 32; else flags = build_classinfo_flags(cd); b.push_uint(flags); // deallocator b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo()); // offset typeinfo VarDeclaration* offTiVar = static_cast<VarDeclaration*>(cinfo->fields.data[9]); #if GENERATE_OFFTI if (cd->isInterfaceDeclaration()) b.push_null(offTiVar->type); else b.push(build_offti_array(cd, DtoType(offTiVar->type))); #else // GENERATE_OFFTI b.push_null(offTiVar->type); #endif // GENERATE_OFFTI // default constructor VarDeclaration* defConstructorVar = static_cast<VarDeclaration*>(cinfo->fields.data[10]); b.push_funcptr(cd->defaultCtor, defConstructorVar->type); #if DMDV2 // immutable(void)* m_RTInfo; // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. if (cd->getRTInfo) b.push(cd->getRTInfo->toConstElem(gIR)); else if (flags & 2) b.push_size_as_vp(0); // no pointers else b.push_size_as_vp(1); // has pointers #else // typeinfo - since 1.045 b.push_typeinfo(cd->type); #endif /*size_t n = inits.size(); for (size_t i=0; i<n; ++i) { Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n'; }*/ // build the initializer LLType *initType = ir->classInfo->getType()->getContainedType(0); LLConstant* finalinit = b.get_constant(isaStruct(initType)); //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; ir->constClassInfo = finalinit; // sanity check assert(finalinit->getType() == initType && "__ClassZ initializer does not match the ClassInfo type"); // return initializer return finalinit; }