// build ModuleReference and register function, to register the module info in the global linked list static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo) { // build ctor type LLFunctionType* fty = LLFunctionType::get(LLType::getVoidTy(gIR->context()), std::vector<LLType*>(), false); // build ctor name std::string fname = "_D"; fname += gIR->dmodule->mangle(); fname += "16__moduleinfoCtorZ"; // build a function that registers the moduleinfo in the global moduleinfo linked list LLFunction* ctor = LLFunction::Create(fty, LLGlobalValue::InternalLinkage, fname, gIR->module); // provide the default initializer LLStructType* modulerefTy = DtoModuleReferenceType(); LLConstant* mrefvalues[] = { LLConstant::getNullValue(modulerefTy->getContainedType(0)), llvm::ConstantExpr::getBitCast(moduleinfo, modulerefTy->getContainedType(1)) }; LLConstant* thismrefinit = LLConstantStruct::get(modulerefTy, llvm::ArrayRef<LLConstant*>(mrefvalues)); // create the ModuleReference node for this module std::string thismrefname = "_D"; thismrefname += gIR->dmodule->mangle(); thismrefname += "11__moduleRefZ"; Loc loc; LLGlobalVariable* thismref = getOrCreateGlobal(loc, *gIR->module, modulerefTy, false, LLGlobalValue::InternalLinkage, thismrefinit, thismrefname); // make sure _Dmodule_ref is declared LLConstant* mref = gIR->module->getNamedGlobal("_Dmodule_ref"); LLType *modulerefPtrTy = getPtrToType(modulerefTy); if (!mref) mref = new LLGlobalVariable(*gIR->module, modulerefPtrTy, false, LLGlobalValue::ExternalLinkage, NULL, "_Dmodule_ref"); mref = DtoBitCast(mref, getPtrToType(modulerefPtrTy)); // make the function insert this moduleinfo as the beginning of the _Dmodule_ref linked list llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "moduleinfoCtorEntry", ctor); IRBuilder<> builder(bb); // debug info gIR->DBuilder.EmitSubProgramInternal(fname.c_str(), fname.c_str()); // get current beginning LLValue* curbeg = builder.CreateLoad(mref, "current"); // put current beginning as the next of this one LLValue* gep = builder.CreateStructGEP(thismref, 0, "next"); builder.CreateStore(curbeg, gep); // replace beginning builder.CreateStore(thismref, mref); // return builder.CreateRetVoid(); return ctor; }
static LLConstant* build_offti_array(ClassDeclaration* cd, LLType* arrayT) { IrStruct* irstruct = cd->ir.irStruct; size_t nvars = irstruct->varDecls.size(); std::vector<LLConstant*> arrayInits(nvars); for (size_t i=0; i<nvars; i++) { arrayInits[i] = build_offti_entry(cd, irstruct->varDecls[i]); } LLConstant* size = DtoConstSize_t(nvars); LLConstant* ptr; if (nvars == 0) return LLConstant::getNullValue( arrayT ); // array type LLArrayType* arrTy = llvm::ArrayType::get(arrayInits[0]->getType(), nvars); LLConstant* arrInit = LLConstantArray::get(arrTy, arrayInits); // mangle std::string name(cd->type->vtinfo->toChars()); name.append("__OffsetTypeInfos"); // create symbol llvm::GlobalVariable* gvar = new llvm::GlobalVariable(arrTy,true,DtoInternalLinkage(cd),arrInit,name,gIR->module); ptr = DtoBitCast(gvar, getPtrToType(arrTy->getElementType())); return DtoConstSlice(size, ptr); }
IRLandingPadInfo::IRLandingPadInfo(Catch* catchstmt, llvm::BasicBlock* end) : finallyBody(NULL) { target = llvm::BasicBlock::Create(gIR->context(), "catch", gIR->topfunc(), end); gIR->scope() = IRScope(target,end); DtoDwarfBlockStart(catchstmt->loc); // 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); DtoDwarfBlockEnd(); } 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)); }
void vaCopy(LLValue* pDest, LLValue* src) { // Analog to va_start, we need to allocate a new __va_list struct on the stack, // fill it with a bitcopy of the source struct... src = DtoLoad(DtoBitCast(src, getValistType()->getPointerTo())); // *(__va_list*)src LLValue* valistmem = DtoAllocaDump(src, 0, "__va_list_mem"); // ... and finally set the passed 'dest' char* pointer to the new struct's address. DtoStore(DtoBitCast(valistmem, getVoidPtrType()), DtoBitCast(pDest, getPtrToType(getVoidPtrType()))); }
LLValue *prepareVaStart(DLValue *ap) override { // Since the user only created a char* pointer (ap) on the stack before // invoking va_start, we first need to allocate the actual __va_list struct // and set `ap` to its address. LLValue *valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem"); DtoStore(valistmem, DtoBitCast(DtoLVal(ap), getPtrToType(valistmem->getType()))); // Pass a i8* pointer to the actual struct to LLVM's va_start intrinsic. return DtoBitCast(valistmem, getVoidPtrType()); }
void vaCopy(DLValue *dest, DValue *src) override { // Analog to va_start, we first need to allocate a new __va_list struct on // the stack and set `dest` to its address. LLValue *valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem"); DtoStore(valistmem, DtoBitCast(DtoLVal(dest), getPtrToType(valistmem->getType()))); // Then fill the new struct with a bitcopy of the source struct. // `src` is a char* pointer to the source struct. DtoMemCpy(valistmem, DtoRVal(src)); }
static LLConstant* build_class_dtor(ClassDeclaration* cd) { FuncDeclaration* dtor = cd->dtor; // if no destructor emit a null if (!dtor) return getNullPtr(getVoidPtrType()); dtor->codegen(Type::sir); return llvm::ConstantExpr::getBitCast(dtor->ir.irFunc->func, getPtrToType(LLType::getInt8Ty(gIR->context()))); }
std::vector<llvm::Type *> IrTypeClass::buildVtblType(Type *first, FuncDeclarations *vtbl_array) { IF_LOG Logger::println("Building vtbl type for class %s", cd->toPrettyChars()); LOG_SCOPE; std::vector<llvm::Type *> types; types.reserve(vtbl_array->dim); auto I = vtbl_array->begin(); // first comes the classinfo for D interfaces if (first) { types.push_back(DtoType(first)); ++I; } // then come the functions for (auto E = vtbl_array->end(); I != E; ++I) { FuncDeclaration *fd = *I; if (fd == nullptr) { // FIXME: This stems from the ancient D1 days – can it still happen? types.push_back(getVoidPtrType()); continue; } IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); // If inferring return type and semantic3 has not been run, do it now. // This pops up in some other places in the frontend as well, however // it is probably a bug that it still occurs that late. if (!fd->type->nextOf() && fd->inferRetType) { Logger::println("Running late semantic3 to infer return type."); TemplateInstance *spec = fd->isSpeculative(); unsigned int olderrs = global.errors; fd->semantic3(fd->_scope); if (spec && global.errors != olderrs) { spec->errors = global.errors - olderrs; } } if (!fd->type->nextOf()) { // Return type of the function has not been inferred. This seems to // happen with virtual functions and is probably a frontend bug. IF_LOG Logger::println("Broken function type, semanticRun: %d", fd->semanticRun); types.push_back(getVoidPtrType()); continue; } types.push_back(getPtrToType(DtoFunctionType(fd))); } return types; }
LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd) { Logger::println("indexing struct field %s:", vd->toPrettyChars()); LOG_SCOPE; DtoResolveStruct(sd); // vd must be a field IrField* field = vd->ir.irField; assert(field); // get the start pointer LLType* st = getPtrToType(DtoType(sd->type)); // cast to the formal struct type src = DtoBitCast(src, st); // gep to the index LLValue* val = DtoGEPi(src, 0, field->index); // do we need to offset further? (union area) if (field->unionOffset) { // cast to void* val = DtoBitCast(val, getVoidPtrType()); // offset val = DtoGEPi1(val, field->unionOffset); } // cast it to the right type val = DtoBitCast(val, getPtrToType(i1ToI8(DtoType(vd->type)))); if (Logger::enabled()) Logger::cout() << "value: " << *val << '\n'; return val; }
// Get struct from ABI-mangled representation LLValue* get(Type* dty, DValue* v) { LLValue* lval; if (v->isLVal()) { lval = v->getLVal(); } else { // No memory location, create one. LLValue* rval = v->getRVal(); lval = DtoRawAlloca(rval->getType(), 0); DtoStore(rval, lval); } LLType* pTy = getPtrToType(DtoType(dty)); return DtoLoad(DtoBitCast(lval, pTy), "get-result"); }
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; }
LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* cd, VarDeclaration* vd) { Logger::println("indexing class field %s:", vd->toPrettyChars()); LOG_SCOPE; if (Logger::enabled()) Logger::cout() << "src: " << *src << '\n'; // make sure class is resolved DtoResolveClass(cd); // vd must be a field IrField* field = vd->ir.irField; assert(field); // get the start pointer LLType* st = DtoType(cd->type); // cast to the struct type src = DtoBitCast(src, st); // gep to the index #if 0 if (Logger::enabled()) { Logger::cout() << "src2: " << *src << '\n'; Logger::cout() << "index: " << field->index << '\n'; Logger::cout() << "srctype: " << *src->getType() << '\n'; } #endif LLValue* val = DtoGEPi(src, 0, field->index); // do we need to offset further? (union area) if (field->unionOffset) { // cast to void* val = DtoBitCast(val, getVoidPtrType()); // offset val = DtoGEPi1(val, field->unionOffset); } // cast it to the right type val = DtoBitCast(val, getPtrToType(DtoType(vd->type))); if (Logger::enabled()) Logger::cout() << "value: " << *val << '\n'; return val; }
// Turn a struct into an ABI-mangled representation LLValue* put(Type* dty, DValue* v) { LLValue* lval; if (v->isLVal()) { lval = v->getLVal(); } else { // No memory location, create one. LLValue* rval = v->getRVal(); lval = DtoRawAlloca(rval->getType(), 0); DtoStore(rval, lval); } LLType* abiTy = getAbiType(dty); assert(abiTy && "Why are we rewriting a non-rewritten type?"); LLType* pTy = getPtrToType(abiTy); return DtoLoad(DtoBitCast(lval, pTy), "put-result"); }
// routines for constructing the llvm types for MS RTTI structs. llvm::StructType *getTypeDescriptorType(IRState &irs, llvm::Constant *classInfoPtr, llvm::StringRef TypeInfoString) { llvm::SmallString<256> TDTypeName("rtti.TypeDescriptor"); TDTypeName += llvm::utostr(TypeInfoString.size()); llvm::StructType *&TypeDescriptorType = irs.TypeDescriptorTypeMap[TypeInfoString.size()]; if (TypeDescriptorType) return TypeDescriptorType; auto int8Ty = LLType::getInt8Ty(gIR->context()); llvm::Type *FieldTypes[] = { classInfoPtr->getType(), // CGM.Int8PtrPtrTy, getPtrToType(int8Ty), // CGM.Int8PtrTy, llvm::ArrayType::get(int8Ty, TypeInfoString.size() + 1)}; TypeDescriptorType = llvm::StructType::create(gIR->context(), FieldTypes, TDTypeName); return TypeDescriptorType; }
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; }
static void build_module_ref(std::string moduleMangle, llvm::Constant* thisModuleInfo) { // Build the ModuleInfo reference and bracketing symbols. llvm::Type* const moduleInfoPtrTy = getPtrToType(DtoType(Module::moduleinfo->type)); std::string thismrefname = "_D"; thismrefname += moduleMangle; thismrefname += "11__moduleRefZ"; llvm::GlobalVariable* thismref = new llvm::GlobalVariable( gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, DtoBitCast(thisModuleInfo, moduleInfoPtrTy), thismrefname ); thismref->setSection(".minfo"); gIR->usedArray.push_back(thismref); }
// helper function that returns the static default initializer of a variable LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init) { if (init) { return DtoConstInitializer(init->loc, vd->type, init); } if (vd->init) { return DtoConstInitializer(vd->init->loc, vd->type, vd->init); } if (vd->type->size(vd->loc) == 0) { // We need to be able to handle void[0] struct members even if void has // no default initializer. return llvm::ConstantPointerNull::get(getPtrToType(DtoType(vd->type))); } return DtoConstExpInit(vd->loc, vd->type, vd->type->defaultInit(vd->loc)); }
IrTypeDelegate* IrTypeDelegate::get(Type* t) { assert(!t->irtype); assert(t->ty == Tdelegate); assert(t->nextOf()->ty == Tfunction); TypeDelegate *dt = (TypeDelegate*)t; if (!dt->irtype) { TypeFunction* tf = static_cast<TypeFunction*>(dt->nextOf()); llvm::Type* ltf = DtoFunctionType(tf, dt->irFty, NULL, Type::tvoid->pointerTo()); llvm::Type *types[] = { getVoidPtrType(), getPtrToType(ltf) }; LLStructType* lt = LLStructType::get(gIR->context(), types, false); dt->irtype = new IrTypeDelegate(dt, lt); } return dt->irtype->isDelegate(); }
void IRLandingPadInfo::toIR() { if (!catchstmt) return; gIR->scope() = IRScope(target, target); DtoDwarfBlockStart(catchstmt->loc); // assign storage to catch var if(catchstmt->var) { // use the same storage for all exceptions that are not accessed in // nested functions if(!catchstmt->var->nestedrefs.dim) { 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); DtoDwarfBlockEnd(); }
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; }
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; }
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 std::vector<LLType*> types; types.push_back(getPtrToType(st)); #if DMDV1 types.push_back(DtoType(Module::moduleinfo->type)); #else types.push_back(DtoType(Module::moduleinfo->type->pointerTo())); #endif // resolve type st->setBody(types); // done gIR->moduleRefType = st; return st; }
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); }
LLStructType* DtoMutexType() { if (gIR->mutexType) return gIR->mutexType; // The structures defined here must be the same as in druntime/src/rt/critical.c // Windows if (global.params.targetTriple.isOSWindows()) { llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(gIR->context()); llvm::Type *Int32Ty = llvm::Type::getInt32Ty(gIR->context()); // Build RTL_CRITICAL_SECTION; size is 24 (32bit) or 40 (64bit) LLType *rtl_types[] = { VoidPtrTy, // Pointer to DebugInfo Int32Ty, // LockCount Int32Ty, // RecursionCount VoidPtrTy, // Handle of OwningThread VoidPtrTy, // Handle of LockSemaphore VoidPtrTy // SpinCount }; LLStructType* rtl = LLStructType::create(gIR->context(), rtl_types, "RTL_CRITICAL_SECTION"); // Build D_CRITICAL_SECTION; size is 28 (32bit) or 48 (64bit) LLStructType *mutex = LLStructType::create(gIR->context(), "D_CRITICAL_SECTION"); LLType *types[] = { getPtrToType(mutex), rtl }; mutex->setBody(types); // Cache type gIR->mutexType = mutex; return mutex; } // FreeBSD else if (global.params.targetTriple.getOS() == llvm::Triple::FreeBSD) { // Just a pointer return LLStructType::get(gIR->context(), DtoSize_t()); } // pthread_fastlock LLType *types2[] = { DtoSize_t(), LLType::getInt32Ty(gIR->context()) }; LLStructType* fastlock = LLStructType::get(gIR->context(), types2, false); // pthread_mutex LLType *types1[] = { LLType::getInt32Ty(gIR->context()), LLType::getInt32Ty(gIR->context()), getVoidPtrType(), LLType::getInt32Ty(gIR->context()), fastlock }; LLStructType* pmutex = LLStructType::get(gIR->context(), types1, false); // D_CRITICAL_SECTION LLStructType* mutex = LLStructType::create(gIR->context(), "D_CRITICAL_SECTION"); LLType *types[] = { getPtrToType(mutex), pmutex }; mutex->setBody(types); // Cache type gIR->mutexType = mutex; return pmutex; }
LLPointerType* getVoidPtrType() { return getPtrToType(LLType::getInt8Ty(gIR->context())); }
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; }
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); }
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; }
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'; } }
// Get struct from ABI-mangled representation, and store in the provided location. void getL(Type* dty, DValue* v, llvm::Value* lval) { LLValue* rval = v->getRVal(); LLType* pTy = getPtrToType(rval->getType()); DtoStore(rval, DtoBitCast(lval, pTy)); }