bool X86MachineInstructionRaiser::raiseDirectBranchMachineInstr()

in X86/X86MachineInstructionRaiser.cpp [4017:4326]


bool X86MachineInstructionRaiser::raiseDirectBranchMachineInstr(
    ControlTransferInfo *CTRec) {
  const MachineInstr *MI = CTRec->CandidateMachineInstr;
  BasicBlock *CandBB = CTRec->CandidateBlock;

  const MCInstrDesc &MCID = MI->getDesc();

  // Make sure this function was called on a direct branch instruction.
  assert(X86II::isImmPCRel(MCID.TSFlags) &&
         "PC-Relative control transfer expected");

  // Get branch offset of the branch instruction
  const MachineOperand &MO = MI->getOperand(0);
  assert(MO.isImm() && "Expected immediate operand not found");
  int64_t BranchOffset = MO.getImm();
  MCInstRaiser *MCIR = getMCInstRaiser();
  // Get MCInst offset - the offset of machine instruction in the binary
  uint64_t MCInstOffset = MCIR->getMCInstIndex(*MI);

  assert(MCIR != nullptr && "MCInstRaiser not initialized");
  int64_t BranchTargetOffset =
      MCInstOffset + MCIR->getMCInstSize(MCInstOffset) + BranchOffset;
  const int64_t TgtMBBNo =
      MCIR->getMBBNumberOfMCInstOffset(BranchTargetOffset, MF);
  assert((TgtMBBNo != -1) && "No branch target found");
  auto iter = mbbToBBMap.find(TgtMBBNo);
  assert(iter != mbbToBBMap.end() &&
         "BasicBlock corresponding to MachineInstr branch not found");
  BasicBlock *TgtBB = (*iter).second;
  if (MI->isUnconditionalBranch()) {
    // Just create a branch instruction targeting TgtBB
    BranchInst *UncondBr = BranchInst::Create(TgtBB);
    CandBB->getInstList().push_back(UncondBr);
    CTRec->Raised = true;
  } else if (MI->isConditionalBranch()) {
    // Find the fall through basic block
    MCInstRaiser::const_mcinst_iter MCIter = MCIR->getMCInstAt(MCInstOffset);
    LLVMContext &Ctx(MF.getFunction().getContext());
    // Go to next non-nop instruction on the fall-through path.
    bool isNop = true;
    while (isNop) {
      MCIter++;
      isNop = isNoop(MCIter->second.getMCInst().getOpcode());
      assert(MCIter != MCIR->const_mcinstr_end() &&
             "Attempt to go past MCInstr stream");
    }
    // Get MBB number whose lead instruction is at the offset of fall-through
    // non-nop instruction. This is the fall-through MBB.
    int64_t FTMBBNum = MCIR->getMBBNumberOfMCInstOffset((*MCIter).first, MF);
    assert((FTMBBNum != -1) && "No fall-through target found");
    if (MF.getBlockNumbered(FTMBBNum)->empty())
      assert(false && "Fall-through empty");
    // Find raised BasicBlock corresponding to fall-through MBB
    auto mapIter = mbbToBBMap.find(FTMBBNum);
    assert(mapIter != mbbToBBMap.end() &&
           "Fall-through BasicBlock corresponding to MachineInstr branch not "
           "found");
    BasicBlock *FTBB = (*mapIter).second;
    // Get the condition value
    assert(CTRec->RegValues.size() == EFlagBits.size() &&
           "Unexpected number of EFLAGS bit values in conditional branch not "
           "handled");

    // Branch condition value
    Value *BranchCond = nullptr;
    // Predicate operation to be performed
    Value *TrueValue = ConstantInt::getTrue(Ctx);
    Value *FalseValue = ConstantInt::getFalse(Ctx);
    auto Opcode = MI->getOpcode();
    assert(((Opcode == X86::JCC_1) || (Opcode == X86::JCC_2) ||
            (Opcode == X86::JCC_4)) &&
           "Conditional branch instruction expected");
    X86::CondCode CC = X86::COND_INVALID;

    // Unfortunately X86::getCondFromBranch(MI) only looks at JCC_1. We need
    // to handle JCC_2 and JCC_4 as well.
    switch (MI->getOpcode()) {
    default:
      CC = X86::COND_INVALID;
      break;
    case X86::JCC_1:
    case X86::JCC_2:
    case X86::JCC_4:
      CC = static_cast<X86::CondCode>(
          MI->getOperand(MI->getDesc().getNumOperands() - 1).getImm());
    }

    switch (CC) {
    case X86::COND_B: {
      // Test CF == 1
      int CFIndex = getEflagBitIndex(EFLAGS::CF);
      Value *CFValue = CTRec->RegValues[CFIndex];
      assert(CFValue != nullptr &&
             "Failed to get EFLAGS value while raising JB");
      // Construct a compare instruction
      BranchCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, CFValue, TrueValue,
                                "CmpCF_JB");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_E: {
      // Test ZF == 1
      int ZFIndex = getEflagBitIndex(EFLAGS::ZF);
      Value *ZFValue = CTRec->RegValues[ZFIndex];
      assert(ZFValue != nullptr &&
             "Failed to get EFLAGS value while raising JE");
      // Construct a compare instruction
      BranchCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, ZFValue, TrueValue,
                                "CmpZF_JE");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_NE: {
      // Test ZF == 0
      int ZFIndex = getEflagBitIndex(EFLAGS::ZF);
      Value *ZFValue = CTRec->RegValues[ZFIndex];
      assert(ZFValue != nullptr &&
             "Failed to get EFLAGS value while raising JNE");
      // Construct a compare instruction
      BranchCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, ZFValue,
                                FalseValue, "CmpZF_JNE");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_S: {
      // Test SF == 1
      int SFIndex = getEflagBitIndex(EFLAGS::SF);
      Value *SFValue = CTRec->RegValues[SFIndex];
      assert(SFValue != nullptr &&
             "Failed to get EFLAGS value while raising JS");
      // Construct a compare instruction
      BranchCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, SFValue, TrueValue,
                                "CmpSF_JS");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_NS: {
      // Test SF == 0
      int SFIndex = getEflagBitIndex(EFLAGS::SF);
      Value *SFValue = CTRec->RegValues[SFIndex];
      assert(SFValue != nullptr &&
             "Failed to get EFLAGS value while raising JNS");
      // Construct a compare instruction
      BranchCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, SFValue,
                                FalseValue, "CmpSF_JNS");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_A: {
      // CF == 0 and ZF == 0
      int CFIndex = getEflagBitIndex(EFLAGS::CF);
      int ZFIndex = getEflagBitIndex(EFLAGS::ZF);
      Value *CFValue = CTRec->RegValues[CFIndex];
      Value *ZFValue = CTRec->RegValues[ZFIndex];

      assert((CFValue != nullptr) && (ZFValue != nullptr) &&
             "Failed to get EFLAGS value while raising JA");
      // Test CF == 0
      Instruction *CFCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, CFValue,
                                         FalseValue, "CFCmp_JA");
      CandBB->getInstList().push_back(CFCond);
      // Test ZF == 0
      Instruction *ZFCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, ZFValue,
                                         FalseValue, "ZFCmp_JA");
      CandBB->getInstList().push_back(ZFCond);
      BranchCond = BinaryOperator::CreateAnd(ZFCond, CFCond, "CFAndZF_JA");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_AE: {
      // CF == 0
      int CFIndex = getEflagBitIndex(EFLAGS::CF);
      Value *CFValue = CTRec->RegValues[CFIndex];
      assert(CFValue != nullptr &&
             "Failed to get EFLAGS value while raising JAE");
      // Compare CF == 0
      BranchCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, CFValue,
                                FalseValue, "CFCmp_JAE");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_BE: {
      // CF == 1 or ZF == 1
      int CFIndex = getEflagBitIndex(EFLAGS::CF);
      int ZFIndex = getEflagBitIndex(EFLAGS::ZF);
      Value *CFValue = CTRec->RegValues[CFIndex];
      Value *ZFValue = CTRec->RegValues[ZFIndex];
      assert((CFValue != nullptr) && (ZFValue != nullptr) &&
             "Failed to get EFLAGS value while raising JBE");
      // Compare CF == 1
      Instruction *CFCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, CFValue,
                                         TrueValue, "CFCmp_JBE");
      CandBB->getInstList().push_back(CFCond);
      // Compare ZF == 1
      Instruction *ZFCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, ZFValue,
                                         TrueValue, "ZFCmp_JBE");
      CandBB->getInstList().push_back(ZFCond);
      BranchCond = BinaryOperator::CreateOr(ZFCond, CFCond, "CFAndZF_JBE");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_G: {
      // ZF == 0 and (SF == OF)
      int ZFIndex = getEflagBitIndex(EFLAGS::ZF);
      int SFIndex = getEflagBitIndex(EFLAGS::SF);
      int OFIndex = getEflagBitIndex(EFLAGS::OF);
      Value *ZFValue = CTRec->RegValues[ZFIndex];
      Value *SFValue = CTRec->RegValues[SFIndex];
      Value *OFValue = CTRec->RegValues[OFIndex];
      Instruction *ZFCond = nullptr;
      Instruction *SFOFCond = nullptr;
      assert(((ZFValue != nullptr) && (SFValue != nullptr) &&
              (OFValue != nullptr)) &&
             "Failed to get EFLAGS value while raising JG");
      // Compare ZF and 0
      ZFCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, ZFValue, FalseValue,
                            "ZFCmp_JG");
      CandBB->getInstList().push_back(ZFCond);
      // Test SF == OF
      SFOFCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, SFValue, OFValue,
                              "SFOFCmp_JG");
      CandBB->getInstList().push_back(SFOFCond);
      BranchCond = BinaryOperator::CreateAnd(ZFCond, SFOFCond, "ZFAndSFOF_JG");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_GE: {
      // SF == OF
      int SFIndex = getEflagBitIndex(EFLAGS::SF);
      int OFIndex = getEflagBitIndex(EFLAGS::OF);
      Value *SFValue = CTRec->RegValues[SFIndex];
      Value *OFValue = CTRec->RegValues[OFIndex];
      assert(SFValue != nullptr && OFValue != nullptr &&
             "Failed to get EFLAGS value while raising JGE");
      // Compare SF and OF
      BranchCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, SFValue, OFValue,
                                "CmpSFOF_JGE");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_L: {
      // SF != OF
      int SFIndex = getEflagBitIndex(EFLAGS::SF);
      int OFIndex = getEflagBitIndex(EFLAGS::OF);
      Value *SFValue = CTRec->RegValues[SFIndex];
      Value *OFValue = CTRec->RegValues[OFIndex];
      assert(((SFValue != nullptr) && (OFValue != nullptr)) &&
             "Failed to get EFLAGS value while raising JL");
      // Test SF != OF
      BranchCond = new ICmpInst(CmpInst::Predicate::ICMP_NE, SFValue, OFValue,
                                "SFAndOF_JL");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_LE: {
      // ZF == 1 or (SF != OF)
      int ZFIndex = getEflagBitIndex(EFLAGS::ZF);
      int SFIndex = getEflagBitIndex(EFLAGS::SF);
      int OFIndex = getEflagBitIndex(EFLAGS::OF);
      Value *ZFValue = CTRec->RegValues[ZFIndex];
      Value *SFValue = CTRec->RegValues[SFIndex];
      Value *OFValue = CTRec->RegValues[OFIndex];
      Instruction *ZFCond = nullptr;
      Instruction *SFOFCond = nullptr;
      assert(((ZFValue != nullptr) && (SFValue != nullptr) &&
              (OFValue != nullptr)) &&
             "Failed to get EFLAGS value while raising JLE");
      // Compare ZF and 1
      ZFCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, ZFValue, TrueValue,
                            "CmpZF_JLE");
      CandBB->getInstList().push_back(ZFCond);
      // Test SF != OF
      SFOFCond = new ICmpInst(CmpInst::Predicate::ICMP_NE, SFValue, OFValue,
                              "CmpOF_JLE");
      CandBB->getInstList().push_back(SFOFCond);
      BranchCond = BinaryOperator::CreateOr(ZFCond, SFOFCond, "ZFOrSF_JLE");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    // Parity flag is set by instructions that abstract unordered
    // result of SSE compare instructions.
    // NOTE: Setting of PF is not modeled while abstracting non-SSE2
    // instructions
    case X86::COND_P: {
      // Test PF == 1
      int PFIndex = getEflagBitIndex(EFLAGS::PF);
      Value *PFValue = CTRec->RegValues[PFIndex];
      assert(PFValue != nullptr &&
             "Failed to get EFLAGS value while raising JP");
      // Construct a compare instruction
      BranchCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, PFValue, TrueValue,
                                "CmpPF_JP");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_NP: {
      // Test PF == 0
      int PFIndex = getEflagBitIndex(EFLAGS::PF);
      Value *PFValue = CTRec->RegValues[PFIndex];
      assert(PFValue != nullptr &&
             "Failed to get EFLAGS value while raising JNP");
      // Construct a compare instruction
      BranchCond = new ICmpInst(CmpInst::Predicate::ICMP_EQ, PFValue,
                                FalseValue, "CmpPF_JNP");
      CandBB->getInstList().push_back(dyn_cast<Instruction>(BranchCond));
    } break;
    case X86::COND_INVALID:
      assert(false && "Invalid condition on branch");
      break;
    default:
      LLVM_DEBUG(MI->dump());
      assert(false && "Unhandled conditional branch");
    }

    // Create branch instruction
    BranchInst *CondBr = BranchInst::Create(TgtBB, FTBB, BranchCond);
    CandBB->getInstList().push_back(CondBr);
    CTRec->Raised = true;
  } else {
    assert(false && "Unhandled type of branch instruction");
  }
  return true;
}