/// buildCFICheck - emits __cfi_check for the current module. void CrossDSOCFI::buildCFICheck() { // FIXME: verify that __cfi_check ends up near the end of the code section, // but before the jump slots created in LowerBitSets. llvm::DenseSet<uint64_t> BitSetIds; NamedMDNode *BitSetNM = M->getNamedMetadata("llvm.bitsets"); if (BitSetNM) for (unsigned I = 0, E = BitSetNM->getNumOperands(); I != E; ++I) if (ConstantInt *TypeId = extractBitSetTypeId(BitSetNM->getOperand(I))) BitSetIds.insert(TypeId->getZExtValue()); LLVMContext &Ctx = M->getContext(); Constant *C = M->getOrInsertFunction( "__cfi_check", FunctionType::get( Type::getVoidTy(Ctx), {Type::getInt64Ty(Ctx), PointerType::getUnqual(Type::getInt8Ty(Ctx))}, false)); Function *F = dyn_cast<Function>(C); F->setAlignment(4096); auto args = F->arg_begin(); Argument &CallSiteTypeId = *(args++); CallSiteTypeId.setName("CallSiteTypeId"); Argument &Addr = *(args++); Addr.setName("Addr"); assert(args == F->arg_end()); BasicBlock *BB = BasicBlock::Create(Ctx, "entry", F); BasicBlock *TrapBB = BasicBlock::Create(Ctx, "trap", F); IRBuilder<> IRBTrap(TrapBB); Function *TrapFn = Intrinsic::getDeclaration(M, Intrinsic::trap); llvm::CallInst *TrapCall = IRBTrap.CreateCall(TrapFn); TrapCall->setDoesNotReturn(); TrapCall->setDoesNotThrow(); IRBTrap.CreateUnreachable(); BasicBlock *ExitBB = BasicBlock::Create(Ctx, "exit", F); IRBuilder<> IRBExit(ExitBB); IRBExit.CreateRetVoid(); IRBuilder<> IRB(BB); SwitchInst *SI = IRB.CreateSwitch(&CallSiteTypeId, TrapBB, BitSetIds.size()); for (uint64_t TypeId : BitSetIds) { ConstantInt *CaseTypeId = ConstantInt::get(Type::getInt64Ty(Ctx), TypeId); BasicBlock *TestBB = BasicBlock::Create(Ctx, "test", F); IRBuilder<> IRBTest(TestBB); Function *BitsetTestFn = Intrinsic::getDeclaration(M, Intrinsic::bitset_test); Value *Test = IRBTest.CreateCall( BitsetTestFn, {&Addr, MetadataAsValue::get( Ctx, ConstantAsMetadata::get(CaseTypeId))}); BranchInst *BI = IRBTest.CreateCondBr(Test, ExitBB, TrapBB); BI->setMetadata(LLVMContext::MD_prof, VeryLikelyWeights); SI->addCase(CaseTypeId, TestBB); ++TypeIds; } }
static Value* adjustFpuPrecision(BasicBlock *&b, Value *fpuval) { // We only expect to be called on native FPU types that need to be // adjusted. NASSERT(fpuval->getType()->isX86_FP80Ty()); // Read precision flag. // switch (pc) // case 0: single precision // case 2: double precision // default: double extended (native x86) Value *pc = F_READ(b, "FPU_PC"); CREATE_BLOCK(native_precision, b); CREATE_BLOCK(single_precision, b); CREATE_BLOCK(double_precision, b); CREATE_BLOCK(done_adjusting, b); SwitchInst *pcSwitch = SwitchInst::Create(pc, block_native_precision, 3, b); pcSwitch->addCase(CONST_V<2>(b, 0), block_single_precision); pcSwitch->addCase(CONST_V<2>(b, 2), block_double_precision); pcSwitch->addCase(CONST_V<2>(b, 3), block_native_precision); // Populate native block - no adjustment needed. BranchInst::Create(block_done_adjusting, block_native_precision); // Populate single precision - convert to single precision type, // convert back to native precision, return. Value *singlep = new FPTruncInst(fpuval, llvm::Type::getFloatTy(block_single_precision->getContext()), "", block_single_precision); Value *single_ton = new FPExtInst(singlep, llvm::Type::getX86_FP80Ty(block_single_precision->getContext()), "", block_single_precision); BranchInst::Create(block_done_adjusting, block_single_precision); // Populate double precision - convert to double and then back to native. Value *doublep = new FPTruncInst(fpuval, llvm::Type::getDoubleTy(block_double_precision->getContext()), "", block_double_precision); Value *double_ton = new FPExtInst(doublep, llvm::Type::getX86_FP80Ty(block_double_precision->getContext()), "", block_double_precision); BranchInst::Create(block_done_adjusting, block_double_precision); // Populate done_adjusting block. PHINode *adjustedVal = PHINode::Create(Type::getX86_FP80Ty(block_done_adjusting->getContext()), 3, "fpu_precision_adjust", block_done_adjusting); adjustedVal->addIncoming(fpuval, block_native_precision); adjustedVal->addIncoming(single_ton, block_single_precision); adjustedVal->addIncoming(double_ton, block_double_precision); b = block_done_adjusting; return adjustedVal; }
/* * Instrument switch instructions to log the index of the taken branch. */ void PandaInstrumentVisitor::visitSwitchInst(SwitchInst &I){ SExtInst *SEI; CallInst *CI; std::vector<Value*> argValues; Function *F = mod->getFunction("log_dynval"); if (!F) { printf("Instrumentation function not found\n"); assert(1==0); } if (I.getCondition()->getType() != wordType){ SEI = static_cast<SExtInst*>(IRB.CreateSExt(I.getCondition(), wordType)); argValues.push_back(ConstantInt::get(ptrType, (uintptr_t)dynval_buffer)); argValues.push_back(ConstantInt::get(intType, SWITCHENTRY)); argValues.push_back(ConstantInt::get(intType, SWITCH)); argValues.push_back(static_cast<Value*>(SEI)); CI = IRB.CreateCall(F, ArrayRef<Value*>(argValues)); CI->insertBefore(static_cast<Instruction*>(&I)); SEI->insertBefore(static_cast<Instruction*>(CI)); } else { argValues.push_back(ConstantInt::get(ptrType, (uintptr_t)dynval_buffer)); argValues.push_back(ConstantInt::get(intType, SWITCHENTRY)); argValues.push_back(ConstantInt::get(intType, SWITCH)); argValues.push_back(static_cast<Value*>(I.getCondition())); CI = IRB.CreateCall(F, ArrayRef<Value*>(argValues)); CI->insertBefore(static_cast<Instruction*>(&I)); } }
bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) { // We model unconditional switches as free, see the comments on handling // branches. return isa<ConstantInt>(SI.getCondition()) || dyn_cast_or_null<ConstantInt>( SimplifiedValues.lookup(SI.getCondition())); }
void doJumpIndexTableViaSwitch( BasicBlock *&block, InstPtr ip) { Function *F = block->getParent(); Module *M = F->getParent(); // we know this conforms to // movzx reg32, [base+disp] // sanity check const MCInst &inst = ip->get_inst(); const MCOperand& dest = OP(0); const MCOperand& base = OP(1); TASSERT(base.isReg(), "Conformant jump index tables need base to be a register"); TASSERT(dest.isReg(), "Conformant jump index tables need to write to a register"); JumpIndexTablePtr idxptr = ip->get_jump_index_table(); // to ensure no negative entries Value *adjustment = CONST_V<32>(block, idxptr->getInitialEntry()); Value *reg_val = R_READ<32>(block, base.getReg()); Value *real_index = BinaryOperator::Create(Instruction::Add, adjustment, reg_val, "", block); BasicBlock *continueBlock = BasicBlock::Create(block->getContext(), "", F, 0); // create a default block that just traps BasicBlock *defaultBlock = BasicBlock::Create(block->getContext(), "", F, 0); Function *trapFn = Intrinsic::getDeclaration(M, Intrinsic::trap); CallInst::Create(trapFn, "", defaultBlock); BranchInst::Create(continueBlock, defaultBlock); // end default block const std::vector<uint8_t> &idxblocks = idxptr->getJumpIndexTable(); // create a switch inst SwitchInst *theSwitch = SwitchInst::Create( real_index, defaultBlock, idxblocks.size(), block); // populate switch int myindex = 0; for(std::vector<uint8_t>::const_iterator itr = idxblocks.begin(); itr != idxblocks.end(); itr++) { BasicBlock *writeBl = emitJumpIndexWrite(F, *itr, dest.getReg(), continueBlock ); theSwitch->addCase(CONST_V<32>(block, myindex), writeBl); ++myindex; } // new block to write to is continue block block = continueBlock; }
bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) { // We model unconditional switches as free, see the comments on handling // branches. if (isa<ConstantInt>(SI.getCondition())) return true; if (Value *V = SimplifiedValues.lookup(SI.getCondition())) if (isa<ConstantInt>(V)) return true; // Otherwise, we need to accumulate a cost proportional to the number of // distinct successor blocks. This fan-out in the CFG cannot be represented // for free even if we can represent the core switch as a jumptable that // takes a single instruction. // // NB: We convert large switches which are just used to initialize large phi // nodes to lookup tables instead in simplify-cfg, so this shouldn't prevent // inlining those. It will prevent inlining in cases where the optimization // does not (yet) fire. SmallPtrSet<BasicBlock *, 8> SuccessorBlocks; SuccessorBlocks.insert(SI.getDefaultDest()); for (auto I = SI.case_begin(), E = SI.case_end(); I != E; ++I) SuccessorBlocks.insert(I.getCaseSuccessor()); // Add cost corresponding to the number of distinct destinations. The first // we model as free because of fallthrough. Cost += (SuccessorBlocks.size() - 1) * InlineConstants::InstrCost; return false; }
void doJumpTableViaSwitch( NativeModulePtr natM, BasicBlock *& block, InstPtr ip, MCInst &inst) { llvm::dbgs() << __FUNCTION__ << ": Doing jumpt table via switch\n"; Function *F = block->getParent(); Module *M = F->getParent(); // we know this conforms to // jmp [reg*4+displacement] // sanity check const MCOperand& scale = OP(1); const MCOperand& index = OP(2); TASSERT(index.isReg(), "Conformant jump tables need index to be a register"); TASSERT(scale.isImm() && scale.getImm() == 4, "Conformant jump tables have scale == 4"); MCSJumpTablePtr jmpptr = ip->get_jump_table(); // to ensure no negative entries Value *adjustment = CONST_V<32>(block, jmpptr->getInitialEntry()); Value *reg_val = R_READ<32>(block, index.getReg()); Value *real_index = BinaryOperator::Create(Instruction::Add, adjustment, reg_val, "", block); // create a default block that just traps BasicBlock *defaultBlock = BasicBlock::Create(block->getContext(), "", block->getParent(), 0); Function *trapFn = Intrinsic::getDeclaration(M, Intrinsic::trap); CallInst::Create(trapFn, "", defaultBlock); ReturnInst::Create(defaultBlock->getContext(), defaultBlock); // end default block const std::vector<VA> &jmpblocks = jmpptr->getJumpTable(); // create a switch inst SwitchInst *theSwitch = SwitchInst::Create( real_index, defaultBlock, jmpblocks.size(), block); // populate switch int myindex = 0; for(std::vector<VA>::const_iterator itr = jmpblocks.begin(); itr != jmpblocks.end(); itr++) { std::string bbname = "block_0x"+to_string<VA>(*itr, std::hex); BasicBlock *toBlock = bbFromStrName(bbname, F); TASSERT(toBlock != NULL, "Could not find block: "+bbname); theSwitch->addCase(CONST_V<32>(block, myindex), toBlock); ++myindex; } }
void cgs_sisd::switch_to( multi_value const& cond, std::vector< std::pair<multi_value, insert_point_t> > const& cases, insert_point_t const& default_branch ) { assert(parallel_factor_ == 1); Value* v = cond.load()[0]; SwitchInst* inst = builder().CreateSwitch( v, default_branch.block, static_cast<unsigned>(cases.size()) ); for( size_t i_case = 0; i_case < cases.size(); ++i_case ){ inst->addCase( llvm::cast<ConstantInt>( cases[i_case].first.load()[0] ), cases[i_case].second.block ); } }
void CfgCodeSelector::genSwitchEdges(U_32 tailNodeId, U_32 numTargets, U_32 *targets, double *probs, U_32 defaultTarget) { // // Switch structure: // // origBlock switchBlock // =========== Fallthrough ============= // .... =======> ....... // if (switchVar >= numTargets) swTarget= jmp [switchVar + swTableBase] // jmp defaultTarget // Node * origBlock = nodes[tailNodeId]; const Edges& outEdges=origBlock->getOutEdges(); assert(outEdges.size() == 1); Node * switchBlock= outEdges.front()->getTargetNode(); assert(switchBlock->isBlockNode()); assert(((Inst*)switchBlock->getLastInst())->hasKind(Inst::Kind_SwitchInst)); SwitchInst * swInst = (SwitchInst *)switchBlock->getLastInst(); double defaultEdgeProb = 1.0; defaultEdgeProb = 1.0; for (U_32 i = 0; i < numTargets; i++) { U_32 targetId = targets[i]; if ( targetId == defaultTarget) { defaultEdgeProb = probs[i]; break; } if (std::find(targets, targets+i, targetId)!=targets+i) { continue; //repeated target } if (probs[i] < 0) { defaultEdgeProb = 0; break; } defaultEdgeProb -= 1.0/(numTargets+1); } genTrueEdge(tailNodeId, defaultTarget, defaultEdgeProb); // Fix probability of fallthrough edge if (defaultEdgeProb!=0) { origBlock->getOutEdges().front()->setEdgeProb(1.0 - defaultEdgeProb); } // Generate edges from switchBlock to switch targets for (U_32 i = 0; i < numTargets; i++) { Node * targetNode = nodes[targets[i]]; // Avoid generating duplicate edges. Jump table however needs all entries if (! switchBlock->isConnectedTo(true, targetNode)) { irManager.getFlowGraph()->addEdge(switchBlock, targetNode, probs[i]); } swInst->setTarget(i, targetNode); } }
void LLVM_General_GetSwitchCases( LLVMValueRef v, LLVMValueRef *values, LLVMBasicBlockRef *dests ) { SwitchInst *s = unwrap<SwitchInst>(v); for(SwitchInst::CaseIt i = s->case_begin(); i != s->case_end(); ++i, ++values, ++dests) { *values = wrap(i.getCaseValue()); *dests = wrap(i.getCaseSuccessor()); } }
Function* PrepareCSI::switchIndirect(Function* F, GlobalVariable* switcher, vector<Function*>& replicas){ F->dropAllReferences(); BasicBlock* newEntry = BasicBlock::Create(*Context, "newEntry", F); vector<Value*> callArgs; for(Function::arg_iterator k = F->arg_begin(), ke = F->arg_end(); k != ke; ++k) callArgs.push_back(k); // set up the switch LoadInst* whichCall = new LoadInst(switcher, "chooseCall", true, newEntry); SwitchInst* callSwitch = NULL; // stuff we need IntegerType* tInt = Type::getInt32Ty(*Context); // create one bb for each possible call (instrumentation scheme) bool aZero = false; for(unsigned int i = 0; i < replicas.size(); ++i){ Function* newF = replicas[i]; BasicBlock* bb = BasicBlock::Create(*Context, "call", F); if(callSwitch == NULL){ callSwitch = SwitchInst::Create(whichCall, bb, replicas.size(), newEntry); } string funcName = newF->getName().str(); if(funcName.length() > 5 && funcName.substr(funcName.length()-5, 5) == "$none"){ callSwitch->addCase(ConstantInt::get(tInt, 0), bb); if(aZero) report_fatal_error("multiple defaults for function '" + F->getName() + "'"); aZero = true; } else callSwitch->addCase(ConstantInt::get(tInt, i+1), bb); CallInst* oneCall = CallInst::Create(newF, callArgs, (F->getReturnType()->isVoidTy()) ? "" : "theCall", bb); oneCall->setTailCall(true); if(F->getReturnType()->isVoidTy()) ReturnInst::Create(*Context, bb); else ReturnInst::Create(*Context, oneCall, bb); } // note that we intentionally started numbering the cases from 1 so that the // zero case is reserved for the uninstrumented variant (if there is one) if(!aZero) switcher->setInitializer(ConstantInt::get(tInt, 1)); return(F); }
/// expandCaseRange - Expand case range into explicit case values within the /// range bool WriteBitcodePass::expandCaseRange(Function &F) { bool Changed = false; for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { SwitchInst *SI = dyn_cast<SwitchInst>(BB->getTerminator()); if (SI == NULL) { continue; } for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e; ++i) { IntegersSubset& CaseRanges = i.getCaseValueEx(); // All case ranges are already in single case values if (CaseRanges.isSingleNumbersOnly()) { continue; } // Create a new case Type *IntTy = SI->getCondition()->getType(); IntegersSubsetToBB CaseBuilder; Changed = true; for (unsigned ri = 0, rn = CaseRanges.getNumItems(); ri != rn; ++ri) { IntegersSubset::Range r = CaseRanges.getItem(ri); bool IsSingleNumber = CaseRanges.isSingleNumber(ri); if (IsSingleNumber) { CaseBuilder.add(r); } else { const APInt &Low = r.getLow(); const APInt &High = r.getHigh(); for (APInt V = Low; V != High; V++) { assert(r.isInRange(V) && "Unexpected out-of-range case value!"); CaseBuilder.add(IntItem::fromType(IntTy, V)); } } IntegersSubset Case = CaseBuilder.getCase(); i.setValueEx(Case); } } } return Changed; }
void TestInstVisitor::visitSwitchInst(SwitchInst &I){ if (except){ return; } DynValEntry entry; size_t n = fread(&entry, sizeof(DynValEntry), 1, dlog); if (entry.entrytype == EXCEPTIONENTRY){ except = true; return; } assert(entry.entrytype == SWITCHENTRY); //printf("switch %d\n", entry.entry.switchstmt.cond); IntegerType *intType = IntegerType::get(getGlobalContext(), sizeof(int)*8); ConstantInt *caseVal = ConstantInt::get(intType, entry.entry.switchstmt.cond); SwitchInst::CaseIt caseIndex = I.findCaseValue(caseVal); TFP->setNextBB(I.getSuccessor(caseIndex.getSuccessorIndex())); }
void doJumpTableViaSwitchReg( BasicBlock *& block, InstPtr ip, Value *regVal, BasicBlock *&default_block) { llvm::dbgs() << __FUNCTION__ << ": Doing jumpt table via switch(reg)\n"; Function *F = block->getParent(); Module *M = F->getParent(); MCSJumpTablePtr jmpptr = ip->get_jump_table(); // create a default block that just traps default_block = BasicBlock::Create(block->getContext(), "", block->getParent(), 0); // end default block const std::vector<VA> &jmpblocks = jmpptr->getJumpTable(); std::unordered_set<VA> uniq_blocks(jmpblocks.begin(), jmpblocks.end()); // create a switch inst SwitchInst *theSwitch = SwitchInst::Create( regVal, default_block, uniq_blocks.size(), block); // populate switch for(auto blockVA : uniq_blocks) { std::string bbname = "block_0x"+to_string<VA>(blockVA, std::hex); BasicBlock *toBlock = bbFromStrName(bbname, F); llvm::dbgs() << __FUNCTION__ << ": Mapping from " << to_string<VA>(blockVA, std::hex) << " => " << bbname << "\n"; TASSERT(toBlock != NULL, "Could not find block: "+bbname); theSwitch->addCase(CONST_V<32>(block, blockVA), toBlock); } }
void Interpreter::visitSwitchInst(SwitchInst &I) { ExecutionContext &SF = ECStack.back(); GenericValue CondVal = getOperandValue(I.getOperand(0), SF); const Type *ElTy = I.getOperand(0)->getType(); // Check to see if any of the cases match... BasicBlock *Dest = 0; for (unsigned i = 2, e = I.getNumOperands(); i != e; i += 2) if (executeSetEQInst(CondVal, getOperandValue(I.getOperand(i), SF), ElTy).BoolVal) { Dest = cast<BasicBlock>(I.getOperand(i+1)); break; } if (!Dest) Dest = I.getDefaultDest(); // No cases matched: use default SwitchToNewBasicBlock(Dest, SF); }
Value* LoopTripCount::insertTripCount(Loop* L, Instruction* InsertPos) { // inspired from Loop::getCanonicalInductionVariable BasicBlock *H = L->getHeader(); BasicBlock* LoopPred = L->getLoopPredecessor(); BasicBlock* startBB = NULL;//which basicblock stores start value int OneStep = 0;// the extra add or plus step for calc Assert(LoopPred, "Require Loop has a Pred"); DEBUG(errs()<<"loop depth:"<<L->getLoopDepth()<<"\n"); /** whats difference on use of predecessor and preheader??*/ //RET_ON_FAIL(self->getLoopLatch()&&self->getLoopPreheader()); //assert(self->getLoopLatch() && self->getLoopPreheader() && "need loop simplify form" ); ret_null_fail(L->getLoopLatch(), "need loop simplify form"); BasicBlock* TE = NULL;//True Exit SmallVector<BasicBlock*,4> Exits; L->getExitingBlocks(Exits); if(Exits.size()==1) TE = Exits.front(); else{ if(std::find(Exits.begin(),Exits.end(),L->getLoopLatch())!=Exits.end()) TE = L->getLoopLatch(); else{ SmallVector<llvm::Loop::Edge,4> ExitEdges; L->getExitEdges(ExitEdges); //stl 用法,先把所有满足条件的元素(出口的结束符是不可到达)移动到数组的末尾,再统一删除 ExitEdges.erase(std::remove_if(ExitEdges.begin(), ExitEdges.end(), [](llvm::Loop::Edge& I){ return isa<UnreachableInst>(I.second->getTerminator()); }), ExitEdges.end()); if(ExitEdges.size()==1) TE = const_cast<BasicBlock*>(ExitEdges.front().first); } } //process true exit ret_null_fail(TE, "need have a true exit"); Instruction* IndOrNext = NULL; Value* END = NULL; //终止块的终止指令:分情况讨论branchinst,switchinst; //跳转指令br bool a1,a2;condition<-->bool if(isa<BranchInst>(TE->getTerminator())){ const BranchInst* EBR = cast<BranchInst>(TE->getTerminator()); Assert(EBR->isConditional(), "end branch is not conditional"); ICmpInst* EC = dyn_cast<ICmpInst>(EBR->getCondition()); if(EC->getPredicate() == EC->ICMP_SGT){ Assert(!L->contains(EBR->getSuccessor(0)), *EBR<<":abnormal exit with great than");//终止块的终止指令---->跳出执行循环外的指令 OneStep += 1; } else if(EC->getPredicate() == EC->ICMP_EQ) Assert(!L->contains(EBR->getSuccessor(0)), *EBR<<":abnormal exit with great than"); else if(EC->getPredicate() == EC->ICMP_SLT) { ret_null_fail(!L->contains(EBR->getSuccessor(1)), *EBR<<":abnormal exit with less than"); } else { ret_null_fail(0, *EC<<" unknow combination of end condition"); } IndOrNext = dyn_cast<Instruction>(castoff(EC->getOperand(0)));//去掉类型转化 END = EC->getOperand(1); DEBUG(errs()<<"end value:"<<*EC<<"\n"); }else if(isa<SwitchInst>(TE->getTerminator())){ SwitchInst* ESW = const_cast<SwitchInst*>(cast<SwitchInst>(TE->getTerminator())); IndOrNext = dyn_cast<Instruction>(castoff(ESW->getCondition())); for(auto I = ESW->case_begin(),E = ESW->case_end();I!=E;++I){ if(!L->contains(I.getCaseSuccessor())){ ret_null_fail(!END,""); assert(!END && "shouldn't have two ends"); END = I.getCaseValue(); } } DEBUG(errs()<<"end value:"<<*ESW<<"\n"); }else{ assert(0 && "unknow terminator type"); } ret_null_fail(L->isLoopInvariant(END), "end value should be loop invariant");//至此得END值 Value* start = NULL; Value* ind = NULL; Instruction* next = NULL; bool addfirst = false;//add before icmp ed DISABLE(errs()<<*IndOrNext<<"\n"); if(isa<LoadInst>(IndOrNext)){ //memory depend analysis Value* PSi = IndOrNext->getOperand(0);//point type Step.i int SICount[2] = {0};//store in predecessor count,store in loop body count for( auto I = PSi->use_begin(),E = PSi->use_end();I!=E;++I){ DISABLE(errs()<<**I<<"\n"); StoreInst* SI = dyn_cast<StoreInst>(*I); if(!SI || SI->getOperand(1) != PSi) continue; if(!start&&L->isLoopInvariant(SI->getOperand(0))) { if(SI->getParent() != LoopPred) if(std::find(pred_begin(LoopPred),pred_end(LoopPred),SI->getParent()) == pred_end(LoopPred)) continue; start = SI->getOperand(0); startBB = SI->getParent(); ++SICount[0]; } Instruction* SI0 = dyn_cast<Instruction>(SI->getOperand(0)); if(L->contains(SI) && SI0 && SI0->getOpcode() == Instruction::Add){ next = SI0; ++SICount[1]; } } Assert(SICount[0]==1 && SICount[1]==1, ""); ind = IndOrNext; }else{ if(isa<PHINode>(IndOrNext)){ PHINode* PHI = cast<PHINode>(IndOrNext); ind = IndOrNext; if(castoff(PHI->getIncomingValue(0)) == castoff(PHI->getIncomingValue(1)) && PHI->getParent() != H) ind = castoff(PHI->getIncomingValue(0)); addfirst = false; }else if(IndOrNext->getOpcode() == Instruction::Add){ next = IndOrNext; addfirst = true; }else{ Assert(0 ,"unknow how to analysis"); } for(auto I = H->begin();isa<PHINode>(I);++I){ PHINode* P = cast<PHINode>(I); if(ind && P == ind){ //start = P->getIncomingValueForBlock(L->getLoopPredecessor()); start = tryFindStart(P, L, startBB); next = dyn_cast<Instruction>(P->getIncomingValueForBlock(L->getLoopLatch())); }else if(next && P->getIncomingValueForBlock(L->getLoopLatch()) == next){ //start = P->getIncomingValueForBlock(L->getLoopPredecessor()); start = tryFindStart(P, L, startBB); ind = P; } } } Assert(start ,"couldn't find a start value"); //process complex loops later //DEBUG(if(L->getLoopDepth()>1 || !L->getSubLoops().empty()) return NULL); DEBUG(errs()<<"start value:"<<*start<<"\n"); DEBUG(errs()<<"ind value:"<<*ind<<"\n"); DEBUG(errs()<<"next value:"<<*next<<"\n"); //process non add later unsigned next_phi_idx = 0; ConstantInt* Step = NULL,*PrevStep = NULL;/*only used if next is phi node*/ ret_null_fail(next, ""); PHINode* next_phi = dyn_cast<PHINode>(next); do{ if(next_phi) { next = dyn_cast<Instruction>(next_phi->getIncomingValue(next_phi_idx)); ret_null_fail(next, ""); DEBUG(errs()<<"next phi "<<next_phi_idx<<":"<<*next<<"\n"); if(Step&&PrevStep){ Assert(Step->getSExtValue() == PrevStep->getSExtValue(),""); } PrevStep = Step; } Assert(next->getOpcode() == Instruction::Add , "why induction increment is not Add"); Assert(next->getOperand(0) == ind ,"why induction increment is not add it self"); Step = dyn_cast<ConstantInt>(next->getOperand(1)); Assert(Step,""); }while(next_phi && ++next_phi_idx<next_phi->getNumIncomingValues()); //RET_ON_FAIL(Step->equalsInt(1)); //assert(VERBOSE(Step->equalsInt(1),Step) && "why induction increment number is not 1"); Value* RES = NULL; //if there are no predecessor, we can insert code into start value basicblock IRBuilder<> Builder(InsertPos); Assert(start->getType()->isIntegerTy() && END->getType()->isIntegerTy() , " why increment is not integer type"); if(start->getType() != END->getType()){ start = Builder.CreateCast(CastInst::getCastOpcode(start, false, END->getType(), false),start,END->getType()); } if(Step->getType() != END->getType()){ //Because Step is a Constant, so it casted is constant Step = dyn_cast<ConstantInt>(Builder.CreateCast(CastInst::getCastOpcode(Step, false, END->getType(), false),Step,END->getType())); AssertRuntime(Step); } if(Step->isMinusOne()) RES = Builder.CreateSub(start,END); else//Step Couldn't be zero RES = Builder.CreateSub(END, start); if(addfirst) OneStep -= 1; if(Step->isMinusOne()) OneStep*=-1; assert(OneStep<=1 && OneStep>=-1); RES = (OneStep==1)?Builder.CreateAdd(RES,Step):(OneStep==-1)?Builder.CreateSub(RES, Step):RES; if(!Step->isMinusOne()&&!Step->isOne()) RES = Builder.CreateSDiv(RES, Step); RES->setName(H->getName()+".tc"); return RES; }
/// buildCFICheck - emits __cfi_check for the current module. void CrossDSOCFI::buildCFICheck(Module &M) { // FIXME: verify that __cfi_check ends up near the end of the code section, // but before the jump slots created in LowerTypeTests. llvm::DenseSet<uint64_t> TypeIds; SmallVector<MDNode *, 2> Types; for (GlobalObject &GO : M.global_objects()) { Types.clear(); GO.getMetadata(LLVMContext::MD_type, Types); for (MDNode *Type : Types) { // Sanity check. GO must not be a function declaration. assert(!isa<Function>(&GO) || !cast<Function>(&GO)->isDeclaration()); if (ConstantInt *TypeId = extractNumericTypeId(Type)) TypeIds.insert(TypeId->getZExtValue()); } } LLVMContext &Ctx = M.getContext(); Constant *C = M.getOrInsertFunction( "__cfi_check", Type::getVoidTy(Ctx), Type::getInt64Ty(Ctx), Type::getInt8PtrTy(Ctx), Type::getInt8PtrTy(Ctx), nullptr); Function *F = dyn_cast<Function>(C); F->setAlignment(4096); auto args = F->arg_begin(); Value &CallSiteTypeId = *(args++); CallSiteTypeId.setName("CallSiteTypeId"); Value &Addr = *(args++); Addr.setName("Addr"); Value &CFICheckFailData = *(args++); CFICheckFailData.setName("CFICheckFailData"); assert(args == F->arg_end()); BasicBlock *BB = BasicBlock::Create(Ctx, "entry", F); BasicBlock *ExitBB = BasicBlock::Create(Ctx, "exit", F); BasicBlock *TrapBB = BasicBlock::Create(Ctx, "fail", F); IRBuilder<> IRBFail(TrapBB); Constant *CFICheckFailFn = M.getOrInsertFunction( "__cfi_check_fail", Type::getVoidTy(Ctx), Type::getInt8PtrTy(Ctx), Type::getInt8PtrTy(Ctx), nullptr); IRBFail.CreateCall(CFICheckFailFn, {&CFICheckFailData, &Addr}); IRBFail.CreateBr(ExitBB); IRBuilder<> IRBExit(ExitBB); IRBExit.CreateRetVoid(); IRBuilder<> IRB(BB); SwitchInst *SI = IRB.CreateSwitch(&CallSiteTypeId, TrapBB, TypeIds.size()); for (uint64_t TypeId : TypeIds) { ConstantInt *CaseTypeId = ConstantInt::get(Type::getInt64Ty(Ctx), TypeId); BasicBlock *TestBB = BasicBlock::Create(Ctx, "test", F); IRBuilder<> IRBTest(TestBB); Function *BitsetTestFn = Intrinsic::getDeclaration(&M, Intrinsic::type_test); Value *Test = IRBTest.CreateCall( BitsetTestFn, {&Addr, MetadataAsValue::get( Ctx, ConstantAsMetadata::get(CaseTypeId))}); BranchInst *BI = IRBTest.CreateCondBr(Test, ExitBB, TrapBB); BI->setMetadata(LLVMContext::MD_prof, VeryLikelyWeights); SI->addCase(CaseTypeId, TestBB); ++NumTypeIds; } }
void vSSA::createSigmasIfNeeded(BasicBlock *BB) { TerminatorInst *ti = BB->getTerminator(); // If the condition used in the terminator instruction is a Comparison instruction: //for each operand of the CmpInst, create sigmas, depending on some conditions /* if(isa<BranchInst>(ti)){ BranchInst * bc = cast<BranchInst>(ti); if(bc->isConditional()){ Value * cond = bc->getCondition(); CmpInst *comparison = dyn_cast<CmpInst>(cond); for (User::const_op_iterator it = comparison->op_begin(), e = comparison->op_end(); it != e; ++it) { Value *operand = *it; if (isa<Instruction>(operand) || isa<Argument>(operand)) { insertSigmas(ti, operand); } } } } */ // CASE 1: Branch Instruction BranchInst *bi = NULL; SwitchInst *si = NULL; if ((bi = dyn_cast<BranchInst>(ti))) { if (bi->isConditional()) { Value *condition = bi->getCondition(); ICmpInst *comparison = dyn_cast<ICmpInst>(condition); if (comparison) { // Create sigmas for ICmp operands for (User::const_op_iterator opit = comparison->op_begin(), opend = comparison->op_end(); opit != opend; ++opit) { Value *operand = *opit; if (isa<Instruction>(operand) || isa<Argument>(operand)) { insertSigmas(ti, operand); // If the operand is a result of a indirect instruction (e.g. ZExt, SExt, Trunc), // Create sigmas for the operands of the operands too CastInst *cinst = NULL; if ((cinst = dyn_cast<CastInst>(operand))) { insertSigmas(ti, cinst->getOperand(0)); } } } } } } // CASE 2: Switch Instruction else if ((si = dyn_cast<SwitchInst>(ti))) { Value *condition = si->getCondition(); if (isa<Instruction>(condition) || isa<Argument>(condition)) { insertSigmas(ti, condition); // If the operand is a result of a indirect instruction (e.g. ZExt, SExt, Trunc), // Create sigmas for the operands of the operands too CastInst *cinst = NULL; if ((cinst = dyn_cast<CastInst>(condition))) { insertSigmas(ti, cinst->getOperand(0)); } } } }
Node * JavaFlowGraphBuilder::edgesForBlock(Node* block) { // // find if this block has any region that could catch the exception // Node *dispatch = NULL; ExceptionInfo *exceptionInfo = (CatchBlock*)((LabelInst*)block->getFirstInst())->getState(); if (exceptionInfo != NULL) { dispatch = exceptionInfo->getLabelInst()->getNode(); }else{ dispatch = fg->getUnwindNode(); } assert(dispatch->isDispatchNode()); // // split the block so that // each potentially-exceptional instruction ends a block // Inst* first = (Inst*)block->getFirstInst(); Inst* last = (Inst*)block->getLastInst(); Inst* lastExceptionalInstSeen = NULL; for (Inst* inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) { if (lastExceptionalInstSeen != NULL) { // start a new basic block LabelInst* label = irBuilder.getInstFactory()->makeLabel(); Node *newblock = createBlockNodeAfter(block, label); uint16 bcOffset = ILLEGAL_BC_MAPPING_VALUE; for (Inst *ins = lastExceptionalInstSeen->getNextInst(), *nextIns = NULL; ins!=NULL; ins = nextIns) { nextIns = ins->getNextInst(); ins->unlink(); newblock->appendInst(ins); if (bcOffset == ILLEGAL_BC_MAPPING_VALUE) { bcOffset = ins->getBCOffset(); } } label->setBCOffset(bcOffset); // now fix up the CFG, duplicating edges if (!lastExceptionalInstSeen->isThrow()) fg->addEdge(block,newblock); // // add an edge to handler entry node // assert(!block->findTargetEdge(dispatch)); fg->addEdge(block,dispatch); block = newblock; lastExceptionalInstSeen = NULL; } if (inst->getOperation().canThrow()) { lastExceptionalInstSeen = inst; } } // // examine the last instruction and create appropriate CFG edges // switch(last->getOpcode()) { case Op_Jump: { fg->addEdge(block,((BranchInst*)last)->getTargetLabel()->getNode()); last->unlink(); } break; case Op_Branch: case Op_JSR: addEdge(block, ((BranchInst*)last)->getTargetLabel()->getNode()); edgeForFallthrough(block); break; case Op_Throw: case Op_ThrowSystemException: case Op_ThrowLinkingException: // throw/rethrow creates an edge to a handler that catches the exception assert(dispatch != NULL); assert(lastExceptionalInstSeen == last); break; case Op_Return: addEdge(block, fg->getReturnNode()); break; case Op_Ret: break; // do not do anything case Op_Switch: { SwitchInst *sw = (SwitchInst*)last; U_32 num = sw->getNumTargets(); for (U_32 i = 0; i < num; i++) { Node* target = sw->getTarget(i)->getNode(); // two switch values may go to the same block if (!block->findTargetEdge(target)) { fg->addEdge(block,target); } } Node* target = sw->getDefaultTarget()->getNode(); if (!block->findTargetEdge(target)) { fg->addEdge(block,target); } } break; default:; if (block != fg->getReturnNode()) { // a fallthrough edge is needed // if the basic block does not have any outgoing edge, add one fall through edge if (block->getOutEdges().empty()) edgeForFallthrough(block); } } // // add an edge to handler entry node // if (lastExceptionalInstSeen != NULL) addEdge(block,dispatch); return block; }
static BasicBlock *doCmpsV(BasicBlock *pred) { Value *lhsRegVal = R_READ<32>(pred, X86::ESI); Value *lhsFromMem = M_READ_0<width>(pred, lhsRegVal); Value *rhsRegVal = R_READ<32>(pred, X86::EDI); Value *rhsFromMem = M_READ_0<width>(pred, rhsRegVal); //perform a subtraction Value *res = BinaryOperator::CreateSub(lhsFromMem, rhsFromMem, "", pred); //set flags according to this result WritePF<width>(pred, res); WriteZF<width>(pred, res); WriteSF<width>(pred, res); WriteCFSub(pred, lhsFromMem, rhsFromMem); WriteAFAddSub<width>(pred, res, lhsFromMem, rhsFromMem); WriteOFSub<width>(pred, res, lhsFromMem, rhsFromMem); //now, either increment or decrement EDI based on the DF flag CREATE_BLOCK(df_zero, pred); CREATE_BLOCK(df_one, pred); CREATE_BLOCK(post_write, pred); Value *df = F_READ(pred, DF); SwitchInst *dfSwitch = SwitchInst::Create(df, block_df_zero, 2, pred); dfSwitch->addCase(CONST_V<1>(pred, 0), block_df_zero); dfSwitch->addCase(CONST_V<1>(pred, 1), block_df_one); uint32_t disp; switch(width) { case 8: disp = 1; break; case 16: disp = 2; break; case 32: disp = 4; break; case 64: disp = 8; break; default: throw TErr(__LINE__, __FILE__, "Invalid width"); } //if zero, then add to src and dst registers Value *add_lhs = BinaryOperator::CreateAdd( lhsRegVal, CONST_V<32>(block_df_zero, disp), "", block_df_zero); Value *add_rhs = BinaryOperator::CreateAdd( rhsRegVal, CONST_V<32>(block_df_zero, disp), "", block_df_zero); R_WRITE<32>(block_df_zero, X86::ESI, add_lhs); R_WRITE<32>(block_df_zero, X86::EDI, add_rhs); // return to a single block, to which we will add new instructions BranchInst::Create(block_post_write, block_df_zero); //if one, then sub to src and dst registers Value *sub_lhs = BinaryOperator::CreateSub( lhsRegVal, CONST_V<32>(block_df_one, disp), "", block_df_one); Value *sub_rhs = BinaryOperator::CreateSub( rhsRegVal, CONST_V<32>(block_df_one, disp), "", block_df_one); R_WRITE<32>(block_df_one, X86::ESI, sub_lhs); R_WRITE<32>(block_df_one, X86::EDI, sub_rhs); // return to a single block, to which we will add new instructions BranchInst::Create(block_post_write, block_df_one); return block_post_write; }
// Set outgoing edges alive dependent on the terminator instruction SI. // If the terminator is an Invoke instruction, the call has already been run. // Return true if anything changed. bool IntegrationAttempt::checkBlockOutgoingEdges(ShadowInstruction* SI) { // TOCHECK: I think this only returns false if the block ends with an Unreachable inst? switch(SI->invar->I->getOpcode()) { case Instruction::Br: case Instruction::Switch: case Instruction::Invoke: case Instruction::Resume: break; default: return false; } if(inst_is<InvokeInst>(SI)) { InlineAttempt* IA = getInlineAttempt(SI); bool changed = false; // !localStore indicates the invoke instruction doesn't return normally if(SI->parent->localStore) { changed |= !SI->parent->succsAlive[0]; SI->parent->succsAlive[0] = true; } // I mark the exceptional edge reachable here if the call is disabled, even though // we might have proved it isn't feasible. This could be improved by converting the // invoke into a call in the final program. if((!IA) || (!IA->isEnabled()) || IA->mayUnwind) { changed |= !SI->parent->succsAlive[1]; SI->parent->succsAlive[1] = true; } return changed; } else if(inst_is<ResumeInst>(SI)) { bool changed = !mayUnwind; mayUnwind = true; return changed; } else if(BranchInst* BI = dyn_cast_inst<BranchInst>(SI)) { if(BI->isUnconditional()) { bool changed = !SI->parent->succsAlive[0]; SI->parent->succsAlive[0] = true; return changed; } } // Both switches and conditional branches use operand 0 for the condition. ShadowValue Condition = SI->getOperand(0); bool changed = false; ConstantInt* ConstCondition = dyn_cast_or_null<ConstantInt>(getConstReplacement(Condition)); if(!ConstCondition) { if(Condition.t == SHADOWVAL_INST || Condition.t == SHADOWVAL_ARG) { // Switch statements can operate on a ptrtoint operand, of which only ptrtoint(null) is useful: if(ImprovedValSetSingle* IVS = dyn_cast_or_null<ImprovedValSetSingle>(getIVSRef(Condition))) { if(IVS->onlyContainsNulls()) { ConstCondition = cast<ConstantInt>(Constant::getNullValue(SI->invar->I->getOperand(0)->getType())); } } } } if(!ConstCondition) { std::pair<ValSetType, ImprovedVal> PathVal; if(tryGetPathValue(Condition, SI->parent, PathVal)) ConstCondition = dyn_cast_val<ConstantInt>(PathVal.second.V); } TerminatorInst* TI = cast_inst<TerminatorInst>(SI); const unsigned NumSucc = TI->getNumSuccessors(); if(ConstCondition) { BasicBlock* takenTarget = 0; if(BranchInst* BI = dyn_cast_inst<BranchInst>(SI)) { // This ought to be a boolean. if(ConstCondition->isZero()) takenTarget = BI->getSuccessor(1); else takenTarget = BI->getSuccessor(0); } else { SwitchInst* SwI = cast_inst<SwitchInst>(SI); SwitchInst::CaseIt targetidx = SwI->findCaseValue(ConstCondition); takenTarget = targetidx.getCaseSuccessor(); } if(takenTarget) { // We know where the instruction is going -- remove this block as a predecessor for its other targets. LPDEBUG("Branch or switch instruction given known target: " << takenTarget->getName() << "\n"); return setEdgeAlive(TI, SI->parent, takenTarget); } // Else fall through to set all alive. } SwitchInst* Switch; ImprovedValSetSingle* IVS; if((Switch = dyn_cast_inst<SwitchInst>(SI)) && (IVS = dyn_cast<ImprovedValSetSingle>(getIVSRef(Condition))) && IVS->SetType == ValSetTypeScalar && !IVS->Values.empty()) { // A set of values feeding a switch. Set each corresponding edge alive. bool changed = false; for (unsigned i = 0, ilim = IVS->Values.size(); i != ilim; ++i) { SwitchInst::CaseIt targetit = Switch->findCaseValue(cast<ConstantInt>(getConstReplacement(IVS->Values[i].V))); BasicBlock* target = targetit.getCaseSuccessor(); changed |= setEdgeAlive(TI, SI->parent, target); } return changed; } // Condition unknown -- set all successors alive. for (unsigned I = 0; I != NumSucc; ++I) { // Mark outgoing edge alive if(!SI->parent->succsAlive[I]) changed = true; SI->parent->succsAlive[I] = true; } return changed; }
llvm::Function* compile(PyCodeObject* co, int inlineopcodes = 1) { using namespace llvm; std::string fname = make_function_name(co); // XXX check if function already exists Function* func = Function::Create(ty_jitted_function, Function::ExternalLinkage, fname.c_str(), the_module); Function::arg_iterator func_args = func->arg_begin(); Value* func_f = func_args++; func_f->setName("f"); Value* func_tstate = func_args++; func_tstate->setName("tstate"); Value* func_throwflag = func_args++; // XXX func_throwflag->setName("throwflag"); std::vector<CallInst*> to_inline; const uint8_t* bytecode = (const uint8_t*) PyString_AS_STRING(co->co_code); Py_ssize_t codelen = PyString_Size(co->co_code); BasicBlock* entry = BasicBlock::Create("entry", func); BasicBlock* gen_throw_block = BasicBlock::Create("gen_throw", func); IRBuilder<> builder(entry); Value* st_var = builder.CreateAlloca(the_module->getTypeByName("struct.interpreter_state"), 0, "st"); CallInst* init_st = builder.CreateCall3(the_module->getFunction("init_interpreter_state"), st_var, func_f, func_tstate); to_inline.push_back(init_st); Value* dispatch_var = builder.CreateAlloca(Type::Int32Ty, 0, "dispatch_to_instr"); BasicBlock* end_block = BasicBlock::Create("end", func); { builder.SetInsertPoint(end_block); CallInst* retvalval = builder.CreateCall(the_module->getFunction("get_retval"), st_var); to_inline.push_back(retvalval); builder.CreateRet(retvalval); } // create the opcode blocks BasicBlock* dispatch_block = BasicBlock::Create("dispatch", func); builder.SetInsertPoint(dispatch_block); Value* dispatch_val = builder.CreateLoad(dispatch_var); SwitchInst* dispatch_switch = builder.CreateSwitch(dispatch_val, end_block); std::vector<BasicBlock*> opblocks(codelen); for (const uint8_t* cur_instr = bytecode; *cur_instr; ++cur_instr) { int line = cur_instr - bytecode; unsigned int opcode = *cur_instr; if (HAS_ARG(opcode)) cur_instr += 2; char opblockname[20]; sprintf(opblockname, "__op_%d", line); BasicBlock* opblock = BasicBlock::Create(std::string(opblockname), func); opblocks[line] = opblock; dispatch_switch->addCase(constant(line), opblock); } BasicBlock* block_end_block = BasicBlock::Create("block_end", func); // if throwflag goto block_end else dispatch to opblocks[f_lasti+1] builder.SetInsertPoint(entry); CallInst* gli = builder.CreateCall(the_module->getFunction("get_lasti"), func_f); to_inline.push_back(gli); Value* lastipp = builder.CreateAdd(gli, constant(1)); builder.CreateStore(lastipp, dispatch_var); builder.CreateCondBr(is_zero(builder, func_throwflag), dispatch_block, gen_throw_block); builder.SetInsertPoint(gen_throw_block); to_inline.push_back(builder.CreateCall2(the_module->getFunction("set_why"), st_var, constant(WHY_EXCEPTION))); builder.CreateBr(block_end_block); // fill in the opcode blocks for (const uint8_t* cur_instr = bytecode; *cur_instr; ++cur_instr) { int line = cur_instr - bytecode; unsigned int opcode = *cur_instr; unsigned int oparg = 0; if (HAS_ARG(opcode)) { unsigned int arg1 = *++cur_instr; unsigned int arg2 = *++cur_instr; oparg = (arg2 << 8) + arg1; } builder.SetInsertPoint(opblocks[line]); std::vector<Value*> opcode_args = vector_of (st_var) (constant(line)) (constant(opcode)) (constant(oparg)) .move(); Function* ophandler; CallInst* opret; # define DEFAULT_HANDLER \ if (opcode_funcs.count(opcode)) ophandler = opcode_funcs[opcode]; \ else ophandler = opcode_unimplemented; \ assert(ophandler); \ opret = builder.CreateCall(ophandler, opcode_args.begin(), opcode_args.end()); \ opret->setCallingConv(CallingConv::Fast); \ if (!fat_opcode[opcode]) to_inline.push_back(opret); \ /**/ switch(opcode) { case YIELD_VALUE: // XXX this will have to change (trace?) case RETURN_VALUE: DEFAULT_HANDLER; builder.CreateBr(block_end_block); break; case JUMP_FORWARD: { int next_line = line + 3 + oparg; // 3 is JUMP_FORWARD + oparg assert(next_line < codelen); builder.CreateBr(opblocks[next_line]); break; } case JUMP_ABSOLUTE: { builder.CreateBr(opblocks[oparg]); break; } case JUMP_IF_TRUE: case JUMP_IF_FALSE: { int true_line = line + 3; int false_line = line + 3 + oparg; if (opcode == JUMP_IF_TRUE) std::swap(true_line, false_line); CallInst* cond = builder.CreateCall(is_top_true, st_var); cond->setCallingConv(CallingConv::Fast); to_inline.push_back(cond); builder.CreateCondBr(is_zero(builder, cond), opblocks[false_line], opblocks[true_line]); break; } case FOR_ITER: { opret = builder.CreateCall(opcode_funcs[opcode], opcode_args.begin(), opcode_args.end()); opret->setCallingConv(CallingConv::Fast); to_inline.push_back(opret); SwitchInst* sw = builder.CreateSwitch(opret, block_end_block); sw->addCase(constant(1), block_end_block); // error sw->addCase(constant(0), opblocks[line + 3]); // continue loop sw->addCase(constant(2), opblocks[line + 3 + oparg]); // end loop break; } default: { DEFAULT_HANDLER; int next_line = line + (HAS_ARG(opcode) ? 3 : 1); if (next_line < codelen) builder.CreateCondBr(is_zero(builder, opret), opblocks[next_line], block_end_block); else builder.CreateBr(block_end_block); break; } } } builder.SetInsertPoint(block_end_block); CallInst* do_jump = builder.CreateCall2(unwind_stack, st_var, dispatch_var); do_jump->setCallingConv(CallingConv::Fast); //to_inline.push_back(do_jump); builder.CreateCondBr(is_zero(builder, do_jump), dispatch_block, end_block); //verify_function(func); if (inlineopcodes) { for (size_t i = 0; i < to_inline.size(); ++i) { InlineFunction(to_inline[i]); } } FPM->run(*func); return func; }
bool LowerEmSetjmp::runOnModule(Module &M) { TheModule = &M; Function *Setjmp = TheModule->getFunction("setjmp"); Function *Longjmp = TheModule->getFunction("longjmp"); if (!Setjmp && !Longjmp) return false; Type *i32 = Type::getInt32Ty(M.getContext()); Type *Void = Type::getVoidTy(M.getContext()); // Add functions Function *EmSetjmp = NULL; if (Setjmp) { SmallVector<Type*, 2> EmSetjmpTypes; EmSetjmpTypes.push_back(Setjmp->getFunctionType()->getParamType(0)); EmSetjmpTypes.push_back(i32); // extra param that says which setjmp in the function it is FunctionType *EmSetjmpFunc = FunctionType::get(i32, EmSetjmpTypes, false); EmSetjmp = Function::Create(EmSetjmpFunc, GlobalValue::ExternalLinkage, "emscripten_setjmp", TheModule); } Function *EmLongjmp = Longjmp ? Function::Create(Longjmp->getFunctionType(), GlobalValue::ExternalLinkage, "emscripten_longjmp", TheModule) : NULL; SmallVector<Type*, 1> IntArgTypes; IntArgTypes.push_back(i32); FunctionType *IntIntFunc = FunctionType::get(i32, IntArgTypes, false); Function *CheckLongjmp = Function::Create(IntIntFunc, GlobalValue::ExternalLinkage, "emscripten_check_longjmp", TheModule); // gets control flow Function *GetLongjmpResult = Function::Create(IntIntFunc, GlobalValue::ExternalLinkage, "emscripten_get_longjmp_result", TheModule); // gets int value longjmp'd FunctionType *VoidFunc = FunctionType::get(Void, false); Function *PrepSetjmp = Function::Create(VoidFunc, GlobalValue::ExternalLinkage, "emscripten_prep_setjmp", TheModule); Function *CleanupSetjmp = Function::Create(VoidFunc, GlobalValue::ExternalLinkage, "emscripten_cleanup_setjmp", TheModule); Function *PreInvoke = TheModule->getFunction("emscripten_preinvoke"); if (!PreInvoke) PreInvoke = Function::Create(VoidFunc, GlobalValue::ExternalLinkage, "emscripten_preinvoke", TheModule); FunctionType *IntFunc = FunctionType::get(i32, false); Function *PostInvoke = TheModule->getFunction("emscripten_postinvoke"); if (!PostInvoke) PostInvoke = Function::Create(IntFunc, GlobalValue::ExternalLinkage, "emscripten_postinvoke", TheModule); // Process all callers of setjmp and longjmp. Start with setjmp. typedef std::vector<PHINode*> Phis; typedef std::map<Function*, Phis> FunctionPhisMap; FunctionPhisMap SetjmpOutputPhis; std::vector<Instruction*> ToErase; if (Setjmp) { for (Instruction::user_iterator UI = Setjmp->user_begin(), UE = Setjmp->user_end(); UI != UE; ++UI) { User *U = *UI; if (CallInst *CI = dyn_cast<CallInst>(U)) { BasicBlock *SJBB = CI->getParent(); // The tail is everything right after the call, and will be reached once when setjmp is // called, and later when longjmp returns to the setjmp BasicBlock *Tail = SplitBlock(SJBB, CI->getNextNode()); // Add a phi to the tail, which will be the output of setjmp, which indicates if this is the // first call or a longjmp back. The phi directly uses the right value based on where we // arrive from PHINode *SetjmpOutput = PHINode::Create(i32, 2, "", Tail->getFirstNonPHI()); SetjmpOutput->addIncoming(ConstantInt::get(i32, 0), SJBB); // setjmp initial call returns 0 CI->replaceAllUsesWith(SetjmpOutput); // The proper output is now this, not the setjmp call itself // longjmp returns to the setjmp will add themselves to this phi Phis& P = SetjmpOutputPhis[SJBB->getParent()]; P.push_back(SetjmpOutput); // fix call target SmallVector<Value *, 2> Args; Args.push_back(CI->getArgOperand(0)); Args.push_back(ConstantInt::get(i32, P.size())); // our index in the function is our place in the array + 1 CallInst::Create(EmSetjmp, Args, "", CI); ToErase.push_back(CI); } else { errs() << **UI << "\n"; report_fatal_error("bad use of setjmp, should only call it"); } } } // Update longjmp FIXME: we could avoid throwing in longjmp as an optimization when longjmping back into the current function perhaps? if (Longjmp) Longjmp->replaceAllUsesWith(EmLongjmp); // Update all setjmping functions for (FunctionPhisMap::iterator I = SetjmpOutputPhis.begin(); I != SetjmpOutputPhis.end(); I++) { Function *F = I->first; Phis& P = I->second; CallInst::Create(PrepSetjmp, "", F->begin()->begin()); // Update each call that can longjmp so it can return to a setjmp where relevant for (Function::iterator BBI = F->begin(), E = F->end(); BBI != E; ) { BasicBlock *BB = BBI++; for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); Iter != E; ) { Instruction *I = Iter++; CallInst *CI; if ((CI = dyn_cast<CallInst>(I))) { Value *V = CI->getCalledValue(); if (V == PrepSetjmp || V == EmSetjmp || V == CheckLongjmp || V == GetLongjmpResult || V == PreInvoke || V == PostInvoke) continue; if (Function *CF = dyn_cast<Function>(V)) if (CF->isIntrinsic()) continue; // TODO: proper analysis of what can actually longjmp. Currently we assume anything but setjmp can. // This may longjmp, so we need to check if it did. Split at that point, and // envelop the call in pre/post invoke, if we need to CallInst *After; Instruction *Check = NULL; if (Iter != E && (After = dyn_cast<CallInst>(Iter)) && After->getCalledValue() == PostInvoke) { // use the pre|postinvoke that exceptions lowering already made Check = Iter++; } BasicBlock *Tail = SplitBlock(BB, Iter); // Iter already points to the next instruction, as we need TerminatorInst *TI = BB->getTerminator(); if (!Check) { // no existing pre|postinvoke, create our own CallInst::Create(PreInvoke, "", CI); Check = CallInst::Create(PostInvoke, "", TI); // CI is at the end of the block // If we are calling a function that is noreturn, we must remove that attribute. The code we // insert here does expect it to return, after we catch the exception. if (CI->doesNotReturn()) { if (Function *F = dyn_cast<Function>(CI->getCalledValue())) { F->removeFnAttr(Attribute::NoReturn); } CI->setAttributes(CI->getAttributes().removeAttribute(TheModule->getContext(), AttributeSet::FunctionIndex, Attribute::NoReturn)); assert(!CI->doesNotReturn()); } } // We need to replace the terminator in Tail - SplitBlock makes BB go straight to Tail, we need to check if a longjmp occurred, and // go to the right setjmp-tail if so SmallVector<Value *, 1> Args; Args.push_back(Check); Instruction *LongjmpCheck = CallInst::Create(CheckLongjmp, Args, "", BB); Instruction *LongjmpResult = CallInst::Create(GetLongjmpResult, Args, "", BB); SwitchInst *SI = SwitchInst::Create(LongjmpCheck, Tail, 2, BB); // -1 means no longjmp happened, continue normally (will hit the default switch case). 0 means a longjmp that is not ours to handle, needs a rethrow. Otherwise // the index mean is the same as the index in P+1 (to avoid 0). for (unsigned i = 0; i < P.size(); i++) { SI->addCase(cast<ConstantInt>(ConstantInt::get(i32, i+1)), P[i]->getParent()); P[i]->addIncoming(LongjmpResult, BB); } ToErase.push_back(TI); // new terminator is now the switch // we are splitting the block here, and must continue to find other calls in the block - which is now split. so continue // to traverse in the Tail BB = Tail; Iter = BB->begin(); E = BB->end(); } else if (InvokeInst *CI = dyn_cast<InvokeInst>(I)) { // XXX check if target is setjmp (void)CI; report_fatal_error("TODO: invoke inside setjmping functions"); } } } // add a cleanup before each return for (Function::iterator BBI = F->begin(), E = F->end(); BBI != E; ) { BasicBlock *BB = BBI++; TerminatorInst *TI = BB->getTerminator(); if (isa<ReturnInst>(TI)) { CallInst::Create(CleanupSetjmp, "", TI); } } } for (unsigned i = 0; i < ToErase.size(); i++) { ToErase[i]->eraseFromParent(); } // Finally, our modifications to the cfg can break dominance of SSA variables. For example, // if (x()) { .. setjmp() .. } // if (y()) { .. longjmp() .. } // We must split the longjmp block, and it can jump into the setjmp one. But that means that when // we split the setjmp block, it's first part no longer dominates its second part - there is // a theoretically possible control flow path where x() is false, then y() is true and we // reach the second part of the setjmp block, without ever reaching the first part. So, // we recalculate regs vs. mem for (FunctionPhisMap::iterator I = SetjmpOutputPhis.begin(); I != SetjmpOutputPhis.end(); I++) { Function *F = I->first; doRegToMem(*F); doMemToReg(*F); } return true; }
// RewriteLoopBodyWithConditionConstant - We know either that the value LIC has // the value specified by Val in the specified loop, or we know it does NOT have // that value. Rewrite any uses of LIC or of properties correlated to it. void LoopUnswitch::RewriteLoopBodyWithConditionConstant(Loop *L, Value *LIC, Constant *Val, bool IsEqual) { assert(!isa<Constant>(LIC) && "Why are we unswitching on a constant?"); // FIXME: Support correlated properties, like: // for (...) // if (li1 < li2) // ... // if (li1 > li2) // ... // FOLD boolean conditions (X|LIC), (X&LIC). Fold conditional branches, // selects, switches. std::vector<User*> Users(LIC->use_begin(), LIC->use_end()); std::vector<Instruction*> Worklist; LLVMContext &Context = Val->getContext(); // If we know that LIC == Val, or that LIC == NotVal, just replace uses of LIC // in the loop with the appropriate one directly. if (IsEqual || (isa<ConstantInt>(Val) && Val->getType()->isIntegerTy(1))) { Value *Replacement; if (IsEqual) Replacement = Val; else Replacement = ConstantInt::get(Type::getInt1Ty(Val->getContext()), !cast<ConstantInt>(Val)->getZExtValue()); for (unsigned i = 0, e = Users.size(); i != e; ++i) if (Instruction *U = cast<Instruction>(Users[i])) { if (!L->contains(U)) continue; U->replaceUsesOfWith(LIC, Replacement); Worklist.push_back(U); } SimplifyCode(Worklist, L); return; } // Otherwise, we don't know the precise value of LIC, but we do know that it // is certainly NOT "Val". As such, simplify any uses in the loop that we // can. This case occurs when we unswitch switch statements. for (unsigned i = 0, e = Users.size(); i != e; ++i) { Instruction *U = cast<Instruction>(Users[i]); if (!L->contains(U)) continue; Worklist.push_back(U); // TODO: We could do other simplifications, for example, turning // 'icmp eq LIC, Val' -> false. // If we know that LIC is not Val, use this info to simplify code. SwitchInst *SI = dyn_cast<SwitchInst>(U); if (SI == 0 || !isa<ConstantInt>(Val)) continue; unsigned DeadCase = SI->findCaseValue(cast<ConstantInt>(Val)); if (DeadCase == 0) continue; // Default case is live for multiple values. // Found a dead case value. Don't remove PHI nodes in the // successor if they become single-entry, those PHI nodes may // be in the Users list. // FIXME: This is a hack. We need to keep the successor around // and hooked up so as to preserve the loop structure, because // trying to update it is complicated. So instead we preserve the // loop structure and put the block on a dead code path. BasicBlock *Switch = SI->getParent(); SplitEdge(Switch, SI->getSuccessor(DeadCase), this); // Compute the successors instead of relying on the return value // of SplitEdge, since it may have split the switch successor // after PHI nodes. BasicBlock *NewSISucc = SI->getSuccessor(DeadCase); BasicBlock *OldSISucc = *succ_begin(NewSISucc); // Create an "unreachable" destination. BasicBlock *Abort = BasicBlock::Create(Context, "us-unreachable", Switch->getParent(), OldSISucc); new UnreachableInst(Context, Abort); // Force the new case destination to branch to the "unreachable" // block while maintaining a (dead) CFG edge to the old block. NewSISucc->getTerminator()->eraseFromParent(); BranchInst::Create(Abort, OldSISucc, ConstantInt::getTrue(Context), NewSISucc); // Release the PHI operands for this edge. for (BasicBlock::iterator II = NewSISucc->begin(); PHINode *PN = dyn_cast<PHINode>(II); ++II) PN->setIncomingValue(PN->getBasicBlockIndex(Switch), UndefValue::get(PN->getType())); // Tell the domtree about the new block. We don't fully update the // domtree here -- instead we force it to do a full recomputation // after the pass is complete -- but we do need to inform it of // new blocks. if (DT) DT->addNewBlock(Abort, NewSISucc); } SimplifyCode(Worklist, L); }
BasicBlock * cpu_translate_all(cpu_t *cpu, BasicBlock *bb_ret, BasicBlock *bb_trap) { // find all instructions that need labels and create basic blocks for them int bbs = 0; addr_t pc; pc = cpu->code_start; while (pc < cpu->code_end) { // Do not create the basic block if it is already present in some other function. if (is_start_of_basicblock(cpu, pc) && !(get_tag(cpu, pc) & TAG_TRANSLATED)) { create_basicblock(cpu, pc, cpu->cur_func, BB_TYPE_NORMAL); bbs++; } pc++; } LOG("bbs: %d\n", bbs); // create dispatch basicblock BasicBlock* bb_dispatch = BasicBlock::Create(_CTX(), "dispatch", cpu->cur_func, 0); Value *v_pc = new LoadInst(cpu->ptr_PC, "", false, bb_dispatch); SwitchInst* sw = SwitchInst::Create(v_pc, bb_ret, bbs, bb_dispatch); // translate basic blocks bbaddr_map &bb_addr = cpu->func_bb[cpu->cur_func]; bbaddr_map::const_iterator it; for (it = bb_addr.begin(); it != bb_addr.end(); it++) { pc = it->first; BasicBlock *cur_bb = it->second; tag_t tag; BasicBlock *bb_target = NULL, *bb_next = NULL, *bb_cont = NULL; // Tag the function as translated. or_tag(cpu, pc, TAG_TRANSLATED); LOG("basicblock: L%08llx\n", (unsigned long long)pc); // Add dispatch switch case for basic block. ConstantInt* c = ConstantInt::get(getIntegerType(cpu->info.address_size), pc); sw->addCase(c, cur_bb); do { tag_t dummy1; if (LOGGING) disasm_instr(cpu, pc); tag = get_tag(cpu, pc); /* get address of the following instruction */ addr_t new_pc, next_pc; cpu->f.tag_instr(cpu, pc, &dummy1, &new_pc, &next_pc); /* get target basic block */ if (tag & TAG_RET) bb_target = bb_dispatch; if (tag & (TAG_CALL|TAG_BRANCH)) { if (new_pc == NEW_PC_NONE) /* translate_instr() will set PC */ bb_target = bb_dispatch; else bb_target = (BasicBlock*)lookup_basicblock(cpu, cpu->cur_func, new_pc, bb_ret, BB_TYPE_NORMAL); } /* get not-taken basic block */ if (tag & TAG_CONDITIONAL) bb_next = (BasicBlock*)lookup_basicblock(cpu, cpu->cur_func, next_pc, bb_ret, BB_TYPE_NORMAL); bb_cont = translate_instr(cpu, pc, tag, bb_target, bb_trap, bb_next, cur_bb); pc = next_pc; } while ( /* new basic block starts here (and we haven't translated it yet)*/ (!is_start_of_basicblock(cpu, pc)) && /* end of code section */ //XXX no: this is whether it's TAG_CODE is_code(cpu, pc) && /* last intruction jumped away */ bb_cont ); /* link with next basic block if there isn't a control flow instr. already */ if (bb_cont) { BasicBlock *target = (BasicBlock*)lookup_basicblock(cpu, cpu->cur_func, pc, bb_ret, BB_TYPE_NORMAL); LOG("info: linking continue $%04llx!\n", (unsigned long long)pc); BranchInst::Create(target, bb_cont); } } return bb_dispatch; }
static bool convertFunction(Function *Func) { bool Changed = false; IntegerType *I32 = Type::getInt32Ty(Func->getContext()); // Skip zero in case programs treat a null pointer as special. uint32_t NextNum = 1; DenseMap<BasicBlock *, ConstantInt *> LabelNums; BasicBlock *DefaultBB = NULL; // Replace each indirectbr with a switch. // // If there are multiple indirectbr instructions in the function, // this could be expensive. While an indirectbr is usually // converted to O(1) machine instructions, the switch we generate // here will be O(n) in the number of target labels. // // However, Clang usually generates just a single indirectbr per // function anyway when compiling C computed gotos. // // We could try to generate one switch to handle all the indirectbr // instructions in the function, but that would be complicated to // implement given that variables that are live at one indirectbr // might not be live at others. for (llvm::Function::iterator BB = Func->begin(), E = Func->end(); BB != E; ++BB) { if (IndirectBrInst *Br = dyn_cast<IndirectBrInst>(BB->getTerminator())) { Changed = true; if (!DefaultBB) { DefaultBB = BasicBlock::Create(Func->getContext(), "indirectbr_default", Func); new UnreachableInst(Func->getContext(), DefaultBB); } // An indirectbr can list the same target block multiple times. // Keep track of the basic blocks we've handled to avoid adding // the same case multiple times. DenseSet<BasicBlock *> BlocksSeen; Value *Cast = new PtrToIntInst(Br->getAddress(), I32, "indirectbr_cast", Br); unsigned Count = Br->getNumSuccessors(); SwitchInst *Switch = SwitchInst::Create(Cast, DefaultBB, Count, Br); for (unsigned I = 0; I < Count; ++I) { BasicBlock *Dest = Br->getSuccessor(I); if (!BlocksSeen.insert(Dest).second) { // Remove duplicated entries from phi nodes. for (BasicBlock::iterator Inst = Dest->begin(); ; ++Inst) { PHINode *Phi = dyn_cast<PHINode>(Inst); if (!Phi) break; Phi->removeIncomingValue(Br->getParent()); } continue; } ConstantInt *Val; if (LabelNums.count(Dest) == 0) { Val = ConstantInt::get(I32, NextNum++); LabelNums[Dest] = Val; BlockAddress *BA = BlockAddress::get(Func, Dest); Value *ValAsPtr = ConstantExpr::getIntToPtr(Val, BA->getType()); BA->replaceAllUsesWith(ValAsPtr); BA->destroyConstant(); } else { Val = LabelNums[Dest]; } Switch->addCase(Val, Br->getSuccessor(I)); } Br->eraseFromParent(); } } // If there are any blockaddresses that are never used by an // indirectbr, replace them with dummy values. SmallVector<Value *, 20> Users(Func->user_begin(), Func->user_end()); for (auto U : Users) { if (BlockAddress *BA = dyn_cast<BlockAddress>(U)) { Changed = true; Value *DummyVal = ConstantExpr::getIntToPtr(ConstantInt::get(I32, ~0L), BA->getType()); BA->replaceAllUsesWith(DummyVal); BA->destroyConstant(); } } return Changed; }
bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) { Module &M = *F.getParent(); LLVMContext &C = F.getContext(); IRBuilder<> IRB(C); SmallVector<Instruction *, 64> ToErase; // Vector of %setjmpTable values std::vector<Instruction *> SetjmpTableInsts; // Vector of %setjmpTableSize values std::vector<Instruction *> SetjmpTableSizeInsts; // Setjmp preparation // This instruction effectively means %setjmpTableSize = 4. // We create this as an instruction intentionally, and we don't want to fold // this instruction to a constant 4, because this value will be used in // SSAUpdater.AddAvailableValue(...) later. BasicBlock &EntryBB = F.getEntryBlock(); BinaryOperator *SetjmpTableSize = BinaryOperator::Create( Instruction::Add, IRB.getInt32(4), IRB.getInt32(0), "setjmpTableSize", &*EntryBB.getFirstInsertionPt()); // setjmpTable = (int *) malloc(40); Instruction *SetjmpTable = CallInst::CreateMalloc( SetjmpTableSize, IRB.getInt32Ty(), IRB.getInt32Ty(), IRB.getInt32(40), nullptr, nullptr, "setjmpTable"); // setjmpTable[0] = 0; IRB.SetInsertPoint(SetjmpTableSize); IRB.CreateStore(IRB.getInt32(0), SetjmpTable); SetjmpTableInsts.push_back(SetjmpTable); SetjmpTableSizeInsts.push_back(SetjmpTableSize); // Setjmp transformation std::vector<PHINode *> SetjmpRetPHIs; Function *SetjmpF = M.getFunction("setjmp"); for (User *U : SetjmpF->users()) { auto *CI = dyn_cast<CallInst>(U); if (!CI) report_fatal_error("Does not support indirect calls to setjmp"); BasicBlock *BB = CI->getParent(); if (BB->getParent() != &F) // in other function continue; // The tail is everything right after the call, and will be reached once // when setjmp is called, and later when longjmp returns to the setjmp BasicBlock *Tail = SplitBlock(BB, CI->getNextNode()); // Add a phi to the tail, which will be the output of setjmp, which // indicates if this is the first call or a longjmp back. The phi directly // uses the right value based on where we arrive from IRB.SetInsertPoint(Tail->getFirstNonPHI()); PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2, "setjmp.ret"); // setjmp initial call returns 0 SetjmpRet->addIncoming(IRB.getInt32(0), BB); // The proper output is now this, not the setjmp call itself CI->replaceAllUsesWith(SetjmpRet); // longjmp returns to the setjmp will add themselves to this phi SetjmpRetPHIs.push_back(SetjmpRet); // Fix call target // Our index in the function is our place in the array + 1 to avoid index // 0, because index 0 means the longjmp is not ours to handle. IRB.SetInsertPoint(CI); Value *Args[] = {CI->getArgOperand(0), IRB.getInt32(SetjmpRetPHIs.size()), SetjmpTable, SetjmpTableSize}; Instruction *NewSetjmpTable = IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable"); Instruction *NewSetjmpTableSize = IRB.CreateLoad(TempRet0GV, "setjmpTableSize"); SetjmpTableInsts.push_back(NewSetjmpTable); SetjmpTableSizeInsts.push_back(NewSetjmpTableSize); ToErase.push_back(CI); } // Update each call that can longjmp so it can return to a setjmp where // relevant. // Because we are creating new BBs while processing and don't want to make // all these newly created BBs candidates again for longjmp processing, we // first make the vector of candidate BBs. std::vector<BasicBlock *> BBs; for (BasicBlock &BB : F) BBs.push_back(&BB); // BBs.size() will change within the loop, so we query it every time for (unsigned i = 0; i < BBs.size(); i++) { BasicBlock *BB = BBs[i]; for (Instruction &I : *BB) { assert(!isa<InvokeInst>(&I)); auto *CI = dyn_cast<CallInst>(&I); if (!CI) continue; const Value *Callee = CI->getCalledValue(); if (!canLongjmp(M, Callee)) continue; Value *Threw = nullptr; BasicBlock *Tail; if (Callee->getName().startswith(InvokePrefix)) { // If invoke wrapper has already been generated for this call in // previous EH phase, search for the load instruction // %__THREW__.val = __THREW__; // in postamble after the invoke wrapper call LoadInst *ThrewLI = nullptr; StoreInst *ThrewResetSI = nullptr; for (auto I = std::next(BasicBlock::iterator(CI)), IE = BB->end(); I != IE; ++I) { if (auto *LI = dyn_cast<LoadInst>(I)) if (auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand())) if (GV == ThrewGV) { Threw = ThrewLI = LI; break; } } // Search for the store instruction after the load above // __THREW__ = 0; for (auto I = std::next(BasicBlock::iterator(ThrewLI)), IE = BB->end(); I != IE; ++I) { if (auto *SI = dyn_cast<StoreInst>(I)) if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand())) if (GV == ThrewGV && SI->getValueOperand() == IRB.getInt32(0)) { ThrewResetSI = SI; break; } } assert(Threw && ThrewLI && "Cannot find __THREW__ load after invoke"); assert(ThrewResetSI && "Cannot find __THREW__ store after invoke"); Tail = SplitBlock(BB, ThrewResetSI->getNextNode()); } else { // Wrap call with invoke wrapper and generate preamble/postamble Threw = wrapInvoke(CI); ToErase.push_back(CI); Tail = SplitBlock(BB, CI->getNextNode()); } // We need to replace the terminator in Tail - SplitBlock makes BB go // straight to Tail, we need to check if a longjmp occurred, and go to the // right setjmp-tail if so ToErase.push_back(BB->getTerminator()); // Generate a function call to testSetjmp function and preamble/postamble // code to figure out (1) whether longjmp occurred (2) if longjmp // occurred, which setjmp it corresponds to Value *Label = nullptr; Value *LongjmpResult = nullptr; BasicBlock *EndBB = nullptr; wrapTestSetjmp(BB, CI, Threw, SetjmpTable, SetjmpTableSize, Label, LongjmpResult, EndBB); assert(Label && LongjmpResult && EndBB); // Create switch instruction IRB.SetInsertPoint(EndBB); SwitchInst *SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.size()); // -1 means no longjmp happened, continue normally (will hit the default // switch case). 0 means a longjmp that is not ours to handle, needs a // rethrow. Otherwise the index is the same as the index in P+1 (to avoid // 0). for (unsigned i = 0; i < SetjmpRetPHIs.size(); i++) { SI->addCase(IRB.getInt32(i + 1), SetjmpRetPHIs[i]->getParent()); SetjmpRetPHIs[i]->addIncoming(LongjmpResult, EndBB); } // We are splitting the block here, and must continue to find other calls // in the block - which is now split. so continue to traverse in the Tail BBs.push_back(Tail); } } // Erase everything we no longer need in this function for (Instruction *I : ToErase) I->eraseFromParent(); // Free setjmpTable buffer before each return instruction for (BasicBlock &BB : F) { TerminatorInst *TI = BB.getTerminator(); if (isa<ReturnInst>(TI)) CallInst::CreateFree(SetjmpTable, TI); } // Every call to saveSetjmp can change setjmpTable and setjmpTableSize // (when buffer reallocation occurs) // entry: // setjmpTableSize = 4; // setjmpTable = (int *) malloc(40); // setjmpTable[0] = 0; // ... // somebb: // setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize); // setjmpTableSize = __tempRet0; // So we need to make sure the SSA for these variables is valid so that every // saveSetjmp and testSetjmp calls have the correct arguments. SSAUpdater SetjmpTableSSA; SSAUpdater SetjmpTableSizeSSA; SetjmpTableSSA.Initialize(Type::getInt32PtrTy(C), "setjmpTable"); SetjmpTableSizeSSA.Initialize(Type::getInt32Ty(C), "setjmpTableSize"); for (Instruction *I : SetjmpTableInsts) SetjmpTableSSA.AddAvailableValue(I->getParent(), I); for (Instruction *I : SetjmpTableSizeInsts) SetjmpTableSizeSSA.AddAvailableValue(I->getParent(), I); for (auto UI = SetjmpTable->use_begin(), UE = SetjmpTable->use_end(); UI != UE;) { // Grab the use before incrementing the iterator. Use &U = *UI; // Increment the iterator before removing the use from the list. ++UI; if (Instruction *I = dyn_cast<Instruction>(U.getUser())) if (I->getParent() != &EntryBB) SetjmpTableSSA.RewriteUse(U); } for (auto UI = SetjmpTableSize->use_begin(), UE = SetjmpTableSize->use_end(); UI != UE;) { Use &U = *UI; ++UI; if (Instruction *I = dyn_cast<Instruction>(U.getUser())) if (I->getParent() != &EntryBB) SetjmpTableSizeSSA.RewriteUse(U); } // Finally, our modifications to the cfg can break dominance of SSA variables. // For example, in this code, // if (x()) { .. setjmp() .. } // if (y()) { .. longjmp() .. } // We must split the longjmp block, and it can jump into the block splitted // from setjmp one. But that means that when we split the setjmp block, it's // first part no longer dominates its second part - there is a theoretically // possible control flow path where x() is false, then y() is true and we // reach the second part of the setjmp block, without ever reaching the first // part. So, we rebuild SSA form here. rebuildSSA(F); return true; }
// This is the equivalent of return fpuregs[regslot]; // FPU registers are referenced as ST(i) where i [0-7], and references a // register slot based on the value of the TOP flag. // So if TOP == 5, then ST(0) references register slot 5, and ST(3) references // register slot 0. static Value *FPUR_READV(BasicBlock *&b, Value *regslot) { // Check TAG register // If TAG(regslot) != 0, then we have a problem. Value *tagval = GetFPUTagV(b, regslot); Function *F = b->getParent(); BasicBlock *read_normal_block = BasicBlock::Create(b->getContext(), "fpu_read_normal", F); //BasicBlock *read_zero_block = // BasicBlock::Create(b->getContext(), "fpu_read_zero", F); //BasicBlock *read_special_block = // BasicBlock::Create(b->getContext(), "fpu_read_special", F); BasicBlock *read_empty_block = BasicBlock::Create(b->getContext(), "fpu_read_empty", F); BasicBlock *fpu_read_continue = BasicBlock::Create(b->getContext(), "fpu_read_continue", F); // The default case should never be hit. Use LLVM Switch Node. SwitchInst *tagSwitch = SwitchInst::Create(tagval, read_empty_block, 4, b); tagSwitch->addCase(CONST_V<2>(b, FPU_TAG_VALID), read_normal_block); tagSwitch->addCase(CONST_V<2>(b, FPU_TAG_ZERO), read_normal_block); tagSwitch->addCase(CONST_V<2>(b, FPU_TAG_SPECIAL), read_normal_block); //tagSwitch->addCase(CONST_V<2>(b, 1), read_zero_block); //tagSwitch->addCase(CONST_V<2>(b, 2), read_special_block); //tagSwitch->addCase(CONST_V<2>(b, 3), read_empty_block); Value *streg = GetFPURegV(read_normal_block, regslot); Value *loadVal = new LoadInst(streg, "", read_normal_block); // C1 is set load needs to round up and cleared otherwise. FPUF_CLEAR(read_normal_block, "C1"); BranchInst::Create(fpu_read_continue, read_normal_block); // Populate read zero block. // This is the zero block. Return zero. // But there are two zeros - negative and positive. // Check the sign of the number, then return +0 or -0. //Value *streg_z = GetFPURegV(read_zero_block, regslot); //Value *loadVal_z = new LoadInst(streg_z, "", read_zero_block); //Value *neg_zero = ConstantFP::getNegativeZero(Type::getX86_FP80Ty(read_zero_block->getContext())); // Is the value we loaded less than or equal to -0.0? //Value *fcmp_inst = new FCmpInst(*read_zero_block, FCmpInst::FCMP_OLE, loadVal_z, neg_zero, ""); // if val <= -0.0, return -0.0. Otherwise, return +0.0. //Value *zval = SelectInst::Create(fcmp_inst, neg_zero, // CONSTFP_V(read_zero_block, 0.0), "", read_zero_block); //BranchInst::Create(fpu_read_continue, read_zero_block); // Populate read special block. // TODO: Check if we need special NaN handling. //BranchInst::Create(fpu_read_continue, read_special_block); //Value *streg_s = GetFPURegV(read_special_block, regslot); //Value *loadVal_s = new LoadInst(streg_s, "", read_special_block); //BranchInst::Create(fpu_read_continue, read_special_block); // Populate read empty block. // For now, just branch to fpu_read_continue and clear C1 to indicate stack // underflow. // TODO: Throw an exception. FPUF_CLEAR(read_empty_block, "C1"); Value *zval = CONSTFP_V(read_empty_block, 0.0); BranchInst::Create(fpu_read_continue, read_empty_block); // Populate continue block. // Use phi instruction to determine value that was loaded. PHINode *whichval = PHINode::Create(Type::getX86_FP80Ty(F->getContext()), 2, "fpu_switch_phinode", fpu_read_continue); whichval->addIncoming(loadVal, read_normal_block); //whichval->addIncoming(zval, read_zero_block); //whichval->addIncoming(loadVal_s, read_special_block); // Would not get here, but throw exception? whichval->addIncoming(zval, read_empty_block); b = fpu_read_continue; // Read PC flag and adjust precision based on its value. Value *precision_adjusted = adjustFpuPrecision(b, whichval); return precision_adjusted; }
static void convertInstruction(Instruction *Inst, ConversionState &State) { if (SExtInst *Sext = dyn_cast<SExtInst>(Inst)) { Value *Op = Sext->getOperand(0); Value *NewInst = NULL; // If the operand to be extended is illegal, we first need to fill its // upper bits (which are zero) with its sign bit. if (shouldConvert(Op)) { NewInst = getSignExtend(State.getConverted(Op), Op, Sext); } // If the converted type of the operand is the same as the converted // type of the result, we won't actually be changing the type of the // variable, just its value. if (getPromotedType(Op->getType()) != getPromotedType(Sext->getType())) { NewInst = new SExtInst( NewInst ? NewInst : State.getConverted(Op), getPromotedType(cast<IntegerType>(Sext->getType())), Sext->getName() + ".sext", Sext); } // Now all the bits of the result are correct, but we need to restore // the bits above its type to zero. if (shouldConvert(Sext)) { NewInst = getClearUpper(NewInst, Sext->getType(), Sext); } assert(NewInst && "Failed to convert sign extension"); State.recordConverted(Sext, NewInst); } else if (ZExtInst *Zext = dyn_cast<ZExtInst>(Inst)) { Value *Op = Zext->getOperand(0); Value *NewInst = NULL; // TODO(dschuff): Some of these zexts could be no-ops. if (shouldConvert(Op)) { NewInst = getClearUpper(State.getConverted(Op), Op->getType(), Zext); } // If the converted type of the operand is the same as the converted // type of the result, we won't actually be changing the type of the // variable, just its value. if (getPromotedType(Op->getType()) != getPromotedType(Zext->getType())) { NewInst = CastInst::CreateZExtOrBitCast( NewInst ? NewInst : State.getConverted(Op), getPromotedType(cast<IntegerType>(Zext->getType())), "", Zext); } assert(NewInst); State.recordConverted(Zext, NewInst); } else if (TruncInst *Trunc = dyn_cast<TruncInst>(Inst)) { Value *Op = Trunc->getOperand(0); Value *NewInst = NULL; // If the converted type of the operand is the same as the converted // type of the result, we won't actually be changing the type of the // variable, just its value. if (getPromotedType(Op->getType()) != getPromotedType(Trunc->getType())) { NewInst = new TruncInst( State.getConverted(Op), getPromotedType(cast<IntegerType>(Trunc->getType())), State.getConverted(Op)->getName() + ".trunc", Trunc); } // Restoring the upper-bits-are-zero invariant effectively truncates the // value. if (shouldConvert(Trunc)) { NewInst = getClearUpper(NewInst ? NewInst : Op, Trunc->getType(), Trunc); } assert(NewInst); State.recordConverted(Trunc, NewInst); } else if (AllocaInst *Alloc = dyn_cast<AllocaInst>(Inst)) { // Don't handle arrays of illegal types, but we could handle an array // with size specified as an illegal type, as unlikely as that seems. if (shouldConvert(Alloc) && Alloc->isArrayAllocation()) report_fatal_error("Can't convert arrays of illegal type"); AllocaInst *NewInst = new AllocaInst( getPromotedType(Alloc->getAllocatedType()), State.getConverted(Alloc->getArraySize()), "", Alloc); NewInst->setAlignment(Alloc->getAlignment()); State.recordConverted(Alloc, NewInst); } else if (BitCastInst *BCInst = dyn_cast<BitCastInst>(Inst)) { // Only handle pointers. Ints can't be casted to/from other ints Type *DestType = shouldConvert(BCInst) ? getPromotedType(BCInst->getDestTy()) : BCInst->getDestTy(); BitCastInst *NewInst = new BitCastInst( State.getConverted(BCInst->getOperand(0)), DestType, "", BCInst); State.recordConverted(BCInst, NewInst); } else if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) { if (shouldConvert(Load)) { splitLoad(Load, State); } } else if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) { if (shouldConvert(Store->getValueOperand())) { splitStore(Store, State); } } else if (isa<CallInst>(Inst)) { report_fatal_error("can't convert calls with illegal types"); } else if (BinaryOperator *Binop = dyn_cast<BinaryOperator>(Inst)) { Value *NewInst = NULL; if (Binop->getOpcode() == Instruction::AShr) { // The AShr operand needs to be sign-extended to the promoted size // before shifting. Because the sign-extension is implemented with // with AShr, it can be combined with the original operation. Value *Op = Binop->getOperand(0); Value *ShiftAmount = NULL; APInt SignShiftAmt = APInt( getPromotedType(Op->getType())->getIntegerBitWidth(), getPromotedType(Op->getType())->getIntegerBitWidth() - Op->getType()->getIntegerBitWidth()); NewInst = BinaryOperator::Create( Instruction::Shl, State.getConverted(Op), ConstantInt::get(getPromotedType(Op->getType()), SignShiftAmt), State.getConverted(Op)->getName() + ".getsign", Binop); if (ConstantInt *C = dyn_cast<ConstantInt>( State.getConverted(Binop->getOperand(1)))) { ShiftAmount = ConstantInt::get(getPromotedType(Op->getType()), SignShiftAmt + C->getValue()); } else { ShiftAmount = BinaryOperator::Create( Instruction::Add, State.getConverted(Binop->getOperand(1)), ConstantInt::get( getPromotedType(Binop->getOperand(1)->getType()), SignShiftAmt), State.getConverted(Op)->getName() + ".shamt", Binop); } NewInst = BinaryOperator::Create( Instruction::AShr, NewInst, ShiftAmount, Binop->getName() + ".result", Binop); } else { // If the original operation is not AShr, just recreate it as usual. NewInst = BinaryOperator::Create( Binop->getOpcode(), State.getConverted(Binop->getOperand(0)), State.getConverted(Binop->getOperand(1)), Binop->getName() + ".result", Binop); if (isa<OverflowingBinaryOperator>(NewInst)) { cast<BinaryOperator>(NewInst)->setHasNoUnsignedWrap (Binop->hasNoUnsignedWrap()); cast<BinaryOperator>(NewInst)->setHasNoSignedWrap( Binop->hasNoSignedWrap()); } } // Now restore the invariant if necessary. // This switch also sanity-checks the operation. switch (Binop->getOpcode()) { case Instruction::And: case Instruction::Or: case Instruction::Xor: case Instruction::LShr: // These won't change the upper bits. break; // These can change the upper bits, unless we are sure they never // overflow. So clear them now. case Instruction::Add: case Instruction::Sub: if (!(Binop->hasNoUnsignedWrap() && Binop->hasNoSignedWrap())) NewInst = getClearUpper(NewInst, Binop->getType(), Binop); break; case Instruction::Shl: if (!Binop->hasNoUnsignedWrap()) NewInst = getClearUpper(NewInst, Binop->getType(), Binop); break; // We modified the upper bits ourselves when implementing AShr case Instruction::AShr: NewInst = getClearUpper(NewInst, Binop->getType(), Binop); break; // We should not see FP operators here. // We don't handle mul/div. case Instruction::FAdd: case Instruction::FSub: case Instruction::Mul: case Instruction::FMul: case Instruction::UDiv: case Instruction::SDiv: case Instruction::FDiv: case Instruction::URem: case Instruction::SRem: case Instruction::FRem: case Instruction::BinaryOpsEnd: errs() << *Inst << "\n"; llvm_unreachable("Cannot handle binary operator"); break; } State.recordConverted(Binop, NewInst); } else if (ICmpInst *Cmp = dyn_cast<ICmpInst>(Inst)) { Value *Op0, *Op1; // For signed compares, operands are sign-extended to their // promoted type. For unsigned or equality compares, the comparison // is equivalent with the larger type because they are already // zero-extended. if (Cmp->isSigned()) { Op0 = getSignExtend(State.getConverted(Cmp->getOperand(0)), Cmp->getOperand(0), Cmp); Op1 = getSignExtend(State.getConverted(Cmp->getOperand(1)), Cmp->getOperand(1), Cmp); } else { Op0 = State.getConverted(Cmp->getOperand(0)); Op1 = State.getConverted(Cmp->getOperand(1)); } ICmpInst *NewInst = new ICmpInst( Cmp, Cmp->getPredicate(), Op0, Op1, ""); State.recordConverted(Cmp, NewInst); } else if (SelectInst *Select = dyn_cast<SelectInst>(Inst)) { SelectInst *NewInst = SelectInst::Create( Select->getCondition(), State.getConverted(Select->getTrueValue()), State.getConverted(Select->getFalseValue()), "", Select); State.recordConverted(Select, NewInst); } else if (PHINode *Phi = dyn_cast<PHINode>(Inst)) { PHINode *NewPhi = PHINode::Create( getPromotedType(Phi->getType()), Phi->getNumIncomingValues(), "", Phi); for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; ++I) { NewPhi->addIncoming(State.getConverted(Phi->getIncomingValue(I)), Phi->getIncomingBlock(I)); } State.recordConverted(Phi, NewPhi); } else if (SwitchInst *Switch = dyn_cast<SwitchInst>(Inst)) { SwitchInst *NewInst = SwitchInst::Create( State.getConverted(Switch->getCondition()), Switch->getDefaultDest(), Switch->getNumCases(), Switch); for (SwitchInst::CaseIt I = Switch->case_begin(), E = Switch->case_end(); I != E; ++I) { // Build a new case from the ranges that map to the successor BB. Each // range consists of a high and low value which are typed, so the ranges // must be rebuilt and a new case constructed from them. IntegersSubset CaseRanges = I.getCaseValueEx(); IntegersSubsetToBB CaseBuilder; for (unsigned RI = 0, RE = CaseRanges.getNumItems(); RI < RE; ++RI) { CaseBuilder.add( IntItem::fromConstantInt(cast<ConstantInt>(convertConstant( CaseRanges.getItem(RI).getLow().toConstantInt()))), IntItem::fromConstantInt(cast<ConstantInt>(convertConstant( CaseRanges.getItem(RI).getHigh().toConstantInt())))); } IntegersSubset Case = CaseBuilder.getCase(); NewInst->addCase(Case, I.getCaseSuccessor()); } Switch->eraseFromParent(); } else { errs() << *Inst<<"\n"; llvm_unreachable("unhandled instruction"); } }