コード例 #1
0
ファイル: x86Instrs_fpu.cpp プロジェクト: Sineaggi/mcsema
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;
}
コード例 #2
0
ファイル: PrepareCSI.cpp プロジェクト: chubbymaggie/csi-cc
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);
}
コード例 #3
0
ファイル: JumpTables.cpp プロジェクト: Sineaggi/mcsema
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;
}
コード例 #4
0
ファイル: CrossDSOCFI.cpp プロジェクト: 2asoft/freebsd
/// 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;
  }
}
コード例 #5
0
ファイル: JumpTables.cpp プロジェクト: IDA-RE-things/mcsema
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;
    }

}
コード例 #6
0
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 );
	}
}
コード例 #7
0
ファイル: JumpTables.cpp プロジェクト: IDA-RE-things/mcsema
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);
    }

}
コード例 #8
0
ファイル: x86Instrs_fpu.cpp プロジェクト: Sineaggi/mcsema
// 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;
}
コード例 #9
0
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;
}
コード例 #10
0
ファイル: CrossDSOCFI.cpp プロジェクト: CSI-LLVM/llvm
/// 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;
  }
}
コード例 #11
0
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;
}
コード例 #12
0
ファイル: translate_all.cpp プロジェクト: cgerum/libcpu
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;
}
コード例 #13
0
ファイル: JitCompiler.cpp プロジェクト: ot/python-llvm-jit
    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;
    }
コード例 #14
0
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;
}
コード例 #15
0
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;
}
コード例 #16
0
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");
  }
}