LLConstant *DtoConstCString(const char *str) { llvm::StringRef s(str ? str : ""); const auto it = gIR->stringLiteral1ByteCache.find(s); llvm::GlobalVariable *gvar = it == gIR->stringLiteral1ByteCache.end() ? nullptr : it->getValue(); if (gvar == nullptr) { llvm::Constant *init = llvm::ConstantDataArray::getString(gIR->context(), s, true); gvar = new llvm::GlobalVariable(gIR->module, init->getType(), true, llvm::GlobalValue::PrivateLinkage, init, ".str"); #if LDC_LLVM_VER >= 309 gvar->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); #else gvar->setUnnamedAddr(true); #endif gIR->stringLiteral1ByteCache[s] = gvar; } LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(0)}; return llvm::ConstantExpr::getGetElementPtr(gvar->getInitializer()->getType(), gvar, idxs, true); }
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, unsigned i1, const char* var, llvm::BasicBlock* bb) { LLSmallVector<LLValue*,2> v(2); v[0] = DtoConstUint(i0); v[1] = DtoConstUint(i1); return llvm::GetElementPtrInst::Create(ptr, v, var?var:"tmp", bb?bb:gIR->scopebb()); }
LLConstant* DtoConstString(const char* str) { llvm::StringRef s(str ? str : ""); llvm::GlobalVariable* gvar = (gIR->stringLiteral1ByteCache.find(s) == gIR->stringLiteral1ByteCache.end()) ? 0 : gIR->stringLiteral1ByteCache[s]; if (gvar == 0) { llvm::Constant* init = llvm::ConstantDataArray::getString(gIR->context(), s, true); gvar = new llvm::GlobalVariable(gIR->module, init->getType(), true, llvm::GlobalValue::PrivateLinkage, init, ".str"); gvar->setUnnamedAddr(true); gIR->stringLiteral1ByteCache[s] = gvar; } LLConstant* idxs[] = { DtoConstUint(0), DtoConstUint(0) }; return DtoConstSlice( DtoConstSize_t(s.size()), llvm::ConstantExpr::getGetElementPtr( #if LDC_LLVM_VER >= 307 gvar->getInitializer()->getType(), #endif gvar, idxs, true), Type::tchar->arrayOf() ); }
LLConstant *DtoGEPi(LLConstant *ptr, unsigned i0, unsigned i1) { LLPointerType *p = isaPointer(ptr); (void)p; assert(p && "GEP expects a pointer type"); LLValue *indices[] = {DtoConstUint(i0), DtoConstUint(i1)}; return llvm::ConstantExpr::getGetElementPtr( p->getElementType(), ptr, indices, /* InBounds = */ true); }
LLConstant* DtoConstStringPtr(const char* str, const char* section) { llvm::StringRef s(str); LLConstant* init = llvm::ConstantDataArray::getString(gIR->context(), s, true); llvm::GlobalVariable* gvar = new llvm::GlobalVariable( *gIR->module, init->getType(), true, llvm::GlobalValue::InternalLinkage, init, ".str"); if (section) gvar->setSection(section); gvar->setUnnamedAddr(true); LLConstant* idxs[] = { DtoConstUint(0), DtoConstUint(0) }; return llvm::ConstantExpr::getGetElementPtr(gvar, idxs, true); }
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, unsigned i1, const char* var, llvm::BasicBlock* bb) { LLPointerType* p = isaPointer(ptr); assert(p && "GEP expects a pointer type"); LLValue* v[] = { DtoConstUint(i0), DtoConstUint(i1) }; return llvm::GetElementPtrInst::Create( #if LDC_LLVM_VER >= 307 p->getElementType(), #endif ptr, v, var, bb ? bb : gIR->scopebb()); }
LLConstant* DtoGEPi(LLConstant* ptr, unsigned i0, unsigned i1) { LLPointerType* p = isaPointer(ptr); assert(p && "GEP expects a pointer type"); LLValue* v[] = { DtoConstUint(i0), DtoConstUint(i1) }; return llvm::ConstantExpr::getGetElementPtr( #if LDC_LLVM_VER >= 307 p->getElementType(), #endif ptr, v, true); }
LLConstant* DtoConstString(const char* str) { llvm::StringRef s(str ? str : ""); LLConstant* init = llvm::ConstantDataArray::getString(gIR->context(), s, true); llvm::GlobalVariable* gvar = new llvm::GlobalVariable( *gIR->module, init->getType(), true, llvm::GlobalValue::InternalLinkage, init, ".str"); gvar->setUnnamedAddr(true); LLConstant* idxs[] = { DtoConstUint(0), DtoConstUint(0) }; return DtoConstSlice( DtoConstSize_t(s.size()), llvm::ConstantExpr::getGetElementPtr(gvar, idxs, true), Type::tchar->arrayOf() ); }
static llvm::Function* build_module_function(const std::string &name, const std::list<FuncDeclaration*> &funcs, const std::list<VarDeclaration*> &gates = std::list<VarDeclaration*>()) { if (gates.empty()) { if (funcs.empty()) return NULL; if (funcs.size() == 1) return getIrFunc(funcs.front())->func; } // build ctor type LLFunctionType* fnTy = LLFunctionType::get(LLType::getVoidTy(gIR->context()), std::vector<LLType*>(), false); std::string const symbolName = gABI->mangleForLLVM(name, LINKd); assert(gIR->module.getFunction(symbolName) == NULL); llvm::Function* fn = llvm::Function::Create(fnTy, llvm::GlobalValue::InternalLinkage, symbolName, &gIR->module); fn->setCallingConv(gABI->callingConv(fn->getFunctionType(), LINKd)); llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "", fn); IRBuilder<> builder(bb); // debug info ldc::DISubprogram dis = gIR->DBuilder.EmitModuleCTor(fn, name.c_str()); if (global.params.symdebug) { // Need _some_ debug info to avoid inliner bug, see GitHub issue #998. builder.SetCurrentDebugLocation(llvm::DebugLoc::get(0, 0, dis)); } // Call ctor's typedef std::list<FuncDeclaration*>::const_iterator FuncIterator; for (FuncIterator itr = funcs.begin(), end = funcs.end(); itr != end; ++itr) { llvm::Function* f = getIrFunc(*itr)->func; #if LDC_LLVM_VER >= 307 llvm::CallInst* call = builder.CreateCall(f, {}); #else llvm::CallInst* call = builder.CreateCall(f, ""); #endif call->setCallingConv(gABI->callingConv(call-> #if LDC_LLVM_VER < 307 getCalledFunction()-> #endif getFunctionType(), LINKd)); } // Increment vgate's typedef std::list<VarDeclaration*>::const_iterator GatesIterator; for (GatesIterator itr = gates.begin(), end = gates.end(); itr != end; ++itr) { assert(getIrGlobal(*itr)); llvm::Value* val = getIrGlobal(*itr)->value; llvm::Value* rval = builder.CreateLoad(val, "vgate"); llvm::Value* res = builder.CreateAdd(rval, DtoConstUint(1), "vgate"); builder.CreateStore(res, val); } builder.CreateRetVoid(); return fn; }
void emitCoverageLinecountInc(Loc &loc) { // Only emit coverage increment for locations in the source of the current // module // (for example, 'inlined' methods from other source files should be skipped). if (!global.params.cov || !loc.linnum || !loc.filename || strcmp(gIR->dmodule->srcfile->name->toChars(), loc.filename) != 0) { return; } const unsigned line = loc.linnum - 1; // convert to 0-based line# index assert(line < gIR->dmodule->numlines); IF_LOG Logger::println("Coverage: increment _d_cover_data[%d]", line); LOG_SCOPE; // Get GEP into _d_cover_data array LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(line)}; LLValue *ptr = llvm::ConstantExpr::getGetElementPtr( #if LDC_LLVM_VER >= 307 LLArrayType::get(LLType::getInt32Ty(gIR->context()), gIR->dmodule->numlines), #endif gIR->dmodule->d_cover_data, idxs, true); // Do an atomic increment, so this works when multiple threads are executed. gIR->ir->CreateAtomicRMW(llvm::AtomicRMWInst::Add, ptr, DtoConstUint(1), #if LDC_LLVM_VER >= 309 llvm::AtomicOrdering::Monotonic #else llvm::Monotonic #endif ); unsigned num_sizet_bits = gDataLayout->getTypeSizeInBits(DtoSize_t()); unsigned idx = line / num_sizet_bits; unsigned bitidx = line % num_sizet_bits; IF_LOG Logger::println("_d_cover_valid[%d] |= (1 << %d)", idx, bitidx); gIR->dmodule->d_cover_valid_init[idx] |= (size_t(1) << bitidx); }
void DtoMemSet(LLValue* dst, LLValue* val, LLValue* nbytes) { dst = DtoBitCast(dst,getVoidPtrType()); LLType* intTy = DtoSize_t(); LLType *VoidPtrTy = getVoidPtrType(); LLType *Tys[2] ={VoidPtrTy, intTy}; llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module, llvm::Intrinsic::memset, llvm::makeArrayRef(Tys, 2)); gIR->ir->CreateCall5(fn, dst, val, nbytes, DtoConstUint(1), DtoConstBool(false), ""); }
void DtoMemCpy(LLValue* dst, LLValue* src, LLValue* nbytes, unsigned align) { dst = DtoBitCast(dst,getVoidPtrType()); src = DtoBitCast(src,getVoidPtrType()); LLType* intTy = DtoSize_t(); LLType *VoidPtrTy = getVoidPtrType(); LLType *Tys[3] ={VoidPtrTy, VoidPtrTy, intTy}; llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module, llvm::Intrinsic::memcpy, llvm::makeArrayRef(Tys, 3)); gIR->ir->CreateCall5(fn, dst, src, nbytes, DtoConstUint(align), DtoConstBool(false), ""); }
static llvm::Function* build_module_function(const std::string &name, const std::list<FuncDeclaration*> &funcs, const std::list<VarDeclaration*> &gates = std::list<VarDeclaration*>()) { if (gates.empty()) { if (funcs.empty()) return NULL; if (funcs.size() == 1) return funcs.front()->ir.irFunc->func; } std::vector<LLType*> argsTy; LLFunctionType* fnTy = LLFunctionType::get(LLType::getVoidTy(gIR->context()),argsTy,false); std::string const symbolName = gABI->mangleForLLVM(name, LINKd); assert(gIR->module->getFunction(symbolName) == NULL); llvm::Function* fn = llvm::Function::Create(fnTy, llvm::GlobalValue::InternalLinkage, symbolName, gIR->module); fn->setCallingConv(gABI->callingConv(LINKd)); llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn); IRBuilder<> builder(bb); // debug info DtoDwarfSubProgramInternal(name.c_str(), symbolName.c_str()); // Call ctor's typedef std::list<FuncDeclaration*>::const_iterator FuncIterator; for (FuncIterator itr = funcs.begin(), end = funcs.end(); itr != end; ++itr) { llvm::Function* f = (*itr)->ir.irFunc->func; llvm::CallInst* call = builder.CreateCall(f,""); call->setCallingConv(gABI->callingConv(LINKd)); } // Increment vgate's typedef std::list<VarDeclaration*>::const_iterator GatesIterator; for (GatesIterator itr = gates.begin(), end = gates.end(); itr != end; ++itr) { assert((*itr)->ir.irGlobal); llvm::Value* val = (*itr)->ir.irGlobal->value; llvm::Value* rval = builder.CreateLoad(val, "vgate"); llvm::Value* res = builder.CreateAdd(rval, DtoConstUint(1), "vgate"); builder.CreateStore(res, val); } builder.CreateRetVoid(); return fn; }
llvm::BasicBlock *CleanupScope::run(IRState &irs, llvm::BasicBlock *sourceBlock, llvm::BasicBlock *continueWith) { #if LDC_LLVM_VER >= 308 if (useMSVCEH()) return runCopying(irs, sourceBlock, continueWith); #endif if (exitTargets.empty() || (exitTargets.size() == 1 && exitTargets[0].branchTarget == continueWith)) { // We didn't need a branch selector before and still don't need one. assert(!branchSelector); // Set up the unconditional branch at the end of the cleanup if we have // not done so already. if (exitTargets.empty()) { exitTargets.emplace_back(continueWith); llvm::BranchInst::Create(continueWith, endBlock()); } exitTargets.front().sourceBlocks.push_back(sourceBlock); return beginBlock(); } // We need a branch selector if we are here... if (!branchSelector) { // ... and have not created one yet, so do so now. branchSelector = new llvm::AllocaInst(llvm::Type::getInt32Ty(irs.context()), #if LDC_LLVM_VER >= 500 irs.module.getDataLayout().getAllocaAddrSpace(), #endif llvm::Twine("branchsel.") + beginBlock()->getName(), irs.topallocapoint()); // Now we also need to store 0 to it to keep the paths that go to the // only existing branch target the same. for (auto bb : exitTargets.front().sourceBlocks) { new llvm::StoreInst(DtoConstUint(0), branchSelector, bb->getTerminator()); } // And convert the BranchInst to the existing branch target to a // SelectInst so we can append the other cases to it. endBlock()->getTerminator()->eraseFromParent(); llvm::Value *sel = new llvm::LoadInst(branchSelector, "", endBlock()); llvm::SwitchInst::Create( sel, exitTargets[0].branchTarget, 1, // Expected number of branches, only for pre-allocating. endBlock()); } // If we already know this branch target, figure out the branch selector // value and simply insert the store into the source block (prior to the // last instruction, which is the branch to the first cleanup). for (unsigned i = 0; i < exitTargets.size(); ++i) { CleanupExitTarget &t = exitTargets[i]; if (t.branchTarget == continueWith) { new llvm::StoreInst(DtoConstUint(i), branchSelector, sourceBlock->getTerminator()); // Note: Strictly speaking, keeping this up to date would not be // needed right now, because we never to any optimizations that // require changes to the source blocks after the initial conversion // from one to two branch targets. Keeping this around for now to // ease future development, but may be removed to save some work. t.sourceBlocks.push_back(sourceBlock); return beginBlock(); } } // We don't know this branch target yet, so add it to the SwitchInst... llvm::ConstantInt *const selectorVal = DtoConstUint(exitTargets.size()); llvm::cast<llvm::SwitchInst>(endBlock()->getTerminator()) ->addCase(selectorVal, continueWith); // ... insert the store into the source block... new llvm::StoreInst(selectorVal, branchSelector, sourceBlock->getTerminator()); // ... and keep track of it (again, this is unnecessary right now as // discussed in the above note). exitTargets.emplace_back(continueWith); exitTargets.back().sourceBlocks.push_back(sourceBlock); return beginBlock(); }
LLValue* DtoGEPi1(LLValue* ptr, unsigned i, const char* var, llvm::BasicBlock* bb) { return llvm::GetElementPtrInst::Create(ptr, DtoConstUint(i), var?var:"tmp", bb?bb:gIR->scopebb()); }
void RTTIBuilder::push_uint(unsigned u) { inits.push_back(DtoConstUint(u)); }
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 *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 AsmBlockStatement_toIR(AsmBlockStatement *stmt, IRState* p) { IF_LOG Logger::println("AsmBlockStatement::toIR(): %s", stmt->loc.toChars()); LOG_SCOPE; // disable inlining by default if (!p->func()->decl->allowInlining) p->func()->setNeverInline(); // create asm block structure assert(!p->asmBlock); IRAsmBlock* asmblock = new IRAsmBlock(stmt); assert(asmblock); p->asmBlock = asmblock; // do asm statements for (unsigned i=0; i < stmt->statements->dim; i++) { Statement* s = static_cast<Statement*>(stmt->statements->data[i]); if (s) { Statement_toIR(s, p); } } // build forwarder for in-asm branches to external labels // this additional asm code sets the __llvm_jump_target variable // to a unique value that will identify the jump target in // a post-asm switch // maps each goto destination to its special value std::map<LabelDsymbol*, int> gotoToVal; // location of the special value determining the goto label // will be set if post-asm dispatcher block is needed llvm::AllocaInst* jump_target = 0; { FuncDeclaration* fd = gIR->func()->decl; const char* fdmangle = mangle(fd); // we use a simple static counter to make sure the new end labels are unique static size_t uniqueLabelsId = 0; std::ostringstream asmGotoEndLabel; printLabelName(asmGotoEndLabel, fdmangle, "_llvm_asm_end"); asmGotoEndLabel << uniqueLabelsId++; // initialize the setter statement we're going to build IRAsmStmt* outSetterStmt = new IRAsmStmt; std::string asmGotoEnd = "\n\tjmp "+asmGotoEndLabel.str()+"\n"; std::ostringstream code; code << asmGotoEnd; int n_goto = 1; size_t n = asmblock->s.size(); for(size_t i=0; i<n; ++i) { IRAsmStmt* a = asmblock->s[i]; // skip non-branch statements if(!a->isBranchToLabel) continue; // if internal, no special handling is necessary, skip std::vector<Identifier*>::const_iterator it, end; end = asmblock->internalLabels.end(); bool skip = false; for(it = asmblock->internalLabels.begin(); it != end; ++it) if((*it)->equals(a->isBranchToLabel->ident)) skip = true; if(skip) continue; // if we already set things up for this branch target, skip if(gotoToVal.find(a->isBranchToLabel) != gotoToVal.end()) continue; // record that the jump needs to be handled in the post-asm dispatcher gotoToVal[a->isBranchToLabel] = n_goto; // provide an in-asm target for the branch and set value IF_LOG Logger::println("statement '%s' references outer label '%s': creating forwarder", a->code.c_str(), a->isBranchToLabel->ident->string); printLabelName(code, fdmangle, a->isBranchToLabel->ident->string); code << ":\n\t"; code << "movl $<<in" << n_goto << ">>, $<<out0>>\n"; //FIXME: Store the value -> label mapping somewhere, so it can be referenced later outSetterStmt->in.push_back(DtoConstUint(n_goto)); outSetterStmt->in_c += "i,"; code << asmGotoEnd; ++n_goto; } if(code.str() != asmGotoEnd) { // finalize code outSetterStmt->code = code.str(); outSetterStmt->code += asmGotoEndLabel.str()+":\n"; // create storage for and initialize the temporary jump_target = DtoAlloca(Type::tint32, "__llvm_jump_target"); gIR->ir->CreateStore(DtoConstUint(0), jump_target); // setup variable for output from asm outSetterStmt->out_c = "=*m,"; outSetterStmt->out.push_back(jump_target); asmblock->s.push_back(outSetterStmt); } else delete outSetterStmt; } // build a fall-off-end-properly asm statement FuncDeclaration* thisfunc = p->func()->decl; bool useabiret = false; p->asmBlock->asmBlock->abiret = NULL; if (thisfunc->fbody->endsWithAsm() == stmt && thisfunc->type->nextOf()->ty != Tvoid) { // there can't be goto forwarders in this case assert(gotoToVal.empty()); emitABIReturnAsmStmt(asmblock, stmt->loc, thisfunc); useabiret = true; } // build asm block std::vector<LLValue*> outargs; std::vector<LLValue*> inargs; std::vector<LLType*> outtypes; std::vector<LLType*> intypes; std::string out_c; std::string in_c; std::string clobbers; std::string code; size_t asmIdx = asmblock->retn; Logger::println("do outputs"); size_t n = asmblock->s.size(); for (size_t i=0; i<n; ++i) { IRAsmStmt* a = asmblock->s[i]; assert(a); size_t onn = a->out.size(); for (size_t j=0; j<onn; ++j) { outargs.push_back(a->out[j]); outtypes.push_back(a->out[j]->getType()); } if (!a->out_c.empty()) { out_c += a->out_c; } remap_outargs(a->code, onn+a->in.size(), asmIdx); asmIdx += onn; } Logger::println("do inputs"); for (size_t i=0; i<n; ++i) { IRAsmStmt* a = asmblock->s[i]; assert(a); size_t inn = a->in.size(); for (size_t j=0; j<inn; ++j) { inargs.push_back(a->in[j]); intypes.push_back(a->in[j]->getType()); } if (!a->in_c.empty()) { in_c += a->in_c; } remap_inargs(a->code, inn+a->out.size(), asmIdx); asmIdx += inn; if (!code.empty()) code += "\n\t"; code += a->code; } asmblock->s.clear(); // append inputs out_c += in_c; // append clobbers typedef std::set<std::string>::iterator clobs_it; for (clobs_it i=asmblock->clobs.begin(); i!=asmblock->clobs.end(); ++i) { out_c += *i; } // remove excessive comma if (!out_c.empty()) out_c.resize(out_c.size()-1); IF_LOG { Logger::println("code = \"%s\"", code.c_str()); Logger::println("constraints = \"%s\"", out_c.c_str()); } // build return types LLType* retty; if (asmblock->retn) retty = asmblock->retty; else retty = llvm::Type::getVoidTy(gIR->context()); // build argument types std::vector<LLType*> types; types.insert(types.end(), outtypes.begin(), outtypes.end()); types.insert(types.end(), intypes.begin(), intypes.end()); llvm::FunctionType* fty = llvm::FunctionType::get(retty, types, false); IF_LOG Logger::cout() << "function type = " << *fty << '\n'; std::vector<LLValue*> args; args.insert(args.end(), outargs.begin(), outargs.end()); args.insert(args.end(), inargs.begin(), inargs.end()); IF_LOG { Logger::cout() << "Arguments:" << '\n'; Logger::indent(); for (std::vector<LLValue*>::iterator b = args.begin(), i = b, e = args.end(); i != e; ++i) { Stream cout = Logger::cout(); cout << '$' << (i - b) << " ==> " << **i; if (!llvm::isa<llvm::Instruction>(*i) && !llvm::isa<LLGlobalValue>(*i)) cout << '\n'; } Logger::undent(); } llvm::InlineAsm* ia = llvm::InlineAsm::get(fty, code, out_c, true); llvm::CallInst* call = p->ir->CreateCall(ia, args, retty == LLType::getVoidTy(gIR->context()) ? "" : "asm"); IF_LOG Logger::cout() << "Complete asm statement: " << *call << '\n'; // capture abi return value if (useabiret) { IRAsmBlock* block = p->asmBlock; if (block->retfixup) block->asmBlock->abiret = (*block->retfixup)(p->ir, call); else if (p->asmBlock->retemu) block->asmBlock->abiret = DtoLoad(block->asmBlock->abiret); else block->asmBlock->abiret = call; } p->asmBlock = NULL; // if asm contained external branches, emit goto forwarder code if(!gotoToVal.empty()) { assert(jump_target); // make new blocks llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "afterasmgotoforwarder", p->topfunc(), oldend); llvm::LoadInst* val = p->ir->CreateLoad(jump_target, "__llvm_jump_target_value"); llvm::SwitchInst* sw = p->ir->CreateSwitch(val, bb, gotoToVal.size()); // add all cases std::map<LabelDsymbol*, int>::iterator it, end = gotoToVal.end(); for(it = gotoToVal.begin(); it != end; ++it) { llvm::BasicBlock* casebb = llvm::BasicBlock::Create(gIR->context(), "case", p->topfunc(), bb); sw->addCase(LLConstantInt::get(llvm::IntegerType::get(gIR->context(), 32), it->second), casebb); p->scope() = IRScope(casebb,bb); DtoGoto(stmt->loc, it->first, stmt->enclosingFinally); } p->scope() = IRScope(bb,oldend); } }
LLValue* DtoImagPart(DValue* val) { assert(0); return gIR->ir->CreateExtractElement(val->getRVal(), DtoConstUint(1), "tmp"); }
LLValue *DtoGEPi1(LLValue *ptr, unsigned i0, const char *name, llvm::BasicBlock *bb) { return DtoGEP(ptr, DtoConstUint(i0), /* inBounds = */ true, name, bb); }
LLConstant* DtoGEPi(LLConstant* ptr, unsigned i0, unsigned i1) { LLValue* v[] = { DtoConstUint(i0), DtoConstUint(i1) }; return llvm::ConstantExpr::getGetElementPtr(ptr, v, true); }
LLValue *DtoGEPi(LLValue *ptr, unsigned i0, unsigned i1, const char *name, llvm::BasicBlock *bb) { LLValue *indices[] = {DtoConstUint(i0), DtoConstUint(i1)}; return DtoGEP(ptr, indices, /* inBounds = */ true, name, bb); }
LLValue* DtoExtractElement(LLValue* vec, unsigned idx, const char* name) { return DtoExtractElement(vec, DtoConstUint(idx), name); }
LLValue* DtoInsertElement(LLValue* vec, LLValue* v, unsigned idx, const char* name) { return DtoInsertElement(vec, v, DtoConstUint(idx), name); }
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, unsigned i1, const char* var, llvm::BasicBlock* bb) { LLValue* v[] = { DtoConstUint(i0), DtoConstUint(i1) }; return llvm::GetElementPtrInst::Create(ptr, v, var?var:"tmp", bb?bb:gIR->scopebb()); }
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); }
void RTTIBuilder::push_uint(unsigned u) { push(DtoConstUint(u)); }