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; }
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); }
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; }
/// 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; } }
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 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); } }
// 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 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; }
/// 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; } }
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; }
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; }
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; }
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; }
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"); } }