bool X86MachineInstructionRaiser::raiseBinaryOpImmToRegMachineInstr()

in X86/X86MachineInstructionRaiser.cpp [3497:3959]


bool X86MachineInstructionRaiser::raiseBinaryOpImmToRegMachineInstr(
    const MachineInstr &MI) {
  unsigned int DstIndex = 0, SrcOp1Index = 1, SrcOp2Index = 2;
  const MCInstrDesc &MIDesc = MI.getDesc();
  int MBBNo = MI.getParent()->getNumber();

  // Get the BasicBlock corresponding to MachineBasicBlock of MI.
  // Raised instruction is added to this BasicBlock.
  BasicBlock *RaisedBB = getRaisedBasicBlock(MI.getParent());

  // A binary operation instruction with encoding I specifies one operand -
  // using AL/AX/EAX/RAX as implicit register operand.
  // A binary operation instruction with encoding RI specifies two operands
  // - the first operand is a register and the second the immediate value
  //
  // The first operand is also as the destination operand.
  // X86::EFLAGS is the implicit def operand.
  unsigned NumOperands = MI.getNumExplicitOperands() +
                         MIDesc.getNumImplicitUses() +
                         MIDesc.getNumImplicitDefs();
  assert(((NumOperands == 3) || (NumOperands == 4)) &&
         "Unexpected number of operands of BinOp instruction with RI/I "
         "operand format");

  // Create a stack alloc slot corresponding to the adjusted sp value, if the
  // operands reference SP.
  if ((MIDesc.getNumDefs() == 1) &&
      (find64BitSuperReg(MI.getOperand(DstIndex).getReg()) == X86::RSP) &&
      (find64BitSuperReg(MI.getOperand(SrcOp1Index).getReg()) == X86::RSP) &&
      MI.getOperand(SrcOp2Index).isImm() &&
      MIDesc.hasImplicitDefOfPhysReg(X86::EFLAGS)) {

    // Find the stack allocation, if any, associated with the stack index
    // being changed to.
    X86AddressMode AdjSPRef;
    AdjSPRef.Base.Reg = X86::RSP;
    uint64_t Imm = MI.getOperand(SrcOp2Index).getImm();

    switch (MI.getOpcode()) {
    case X86::ADD8i8:
    case X86::ADD16i16:
    case X86::ADD32i32:
    case X86::ADD64i32:
    case X86::ADD8ri:
    case X86::ADD16ri:
    case X86::ADD16ri8:
    case X86::ADD32ri:
    case X86::ADD32ri8:
    case X86::ADD64ri8:
    case X86::ADD64ri32:
      AdjSPRef.Disp = Imm;
      break;
    case X86::SUB32i32:
    case X86::SUB32ri:
    case X86::SUB32ri8:
    case X86::SUB64ri8:
    case X86::SUB64ri32:
    case X86::SUB64i32:
      AdjSPRef.Disp = -Imm;
      break;
    default:
      assert(false && "SP computation - unhandled binary opcode instruction");
    }

    Value *StackRefVal = getStackAllocatedValue(MI, AdjSPRef, true);
    assert((StackRefVal != nullptr) && "Reference to unallocated stack slot");
    raisedValues->setPhysRegSSAValue(X86::RSP, MI.getParent()->getNumber(),
                                     StackRefVal);
  } else {
    // Values need to be discovered to form the appropriate instruction.
    Value *SrcOp1Value = nullptr;
    Value *SrcOp2Value = nullptr;
    unsigned int DstPReg = X86::NoRegister;

    // Ensure that the instruction defines EFLAGS as implicit define register.
    assert(MIDesc.hasImplicitDefOfPhysReg(X86::EFLAGS) &&
           "Expected implicit def operand EFLAGS not found");

    // A vector holding source operand values.
    SmallVector<Value *, 2> OpValues = {nullptr, nullptr};
    unsigned NumImplicitDefs = MIDesc.getNumImplicitDefs();
    assert(((NumImplicitDefs == 1) || (NumImplicitDefs == 2)) &&
           "Encountered instruction unexpected number of implicit defs");
    // Index of the instruction operand being read.
    unsigned CurExplicitOpIndex = 0;
    // Keep a count of the number of instruction operands evaluated. A count of
    // NumOperands need to be evaluated. The value is 1 because we have already
    // checked that EFLAGS is an implicit def.
    unsigned NumOperandsEval = 1;
    // Find destination register of the instruction
    // If the instruction has an explicit dest operand, get the DstPreg from
    // dest operand.
    if (MIDesc.getNumDefs() != 0) {
      // Get destination reg
      const MachineOperand &DstOp = MI.getOperand(CurExplicitOpIndex);
      assert(DstOp.isReg() && "Not found expected register to be the "
                              "destination operand of BinOp instruction with "
                              "RI/I operand format");
      DstPReg = DstOp.getReg();
      // Go to next explicit operand index
      CurExplicitOpIndex++;
      // Increment the number of operands evaluated
      NumOperandsEval++;
    }
    // If there is no explicit dst register in the instruction, find if there is
    // an implicit physical register defined by the instruction.
    if ((NumImplicitDefs == 2) && (DstPReg == X86::NoRegister)) {
      // Find the implicit dest reg. Register at index 0 is the implicit def
      // physical register. That at index 1 is EFLAGS.
      DstPReg = MIDesc.ImplicitDefs[0];
      assert(((DstPReg == X86::AL) || (DstPReg == X86::AX) ||
              (DstPReg == X86::EAX) || (DstPReg == X86::RAX)) &&
             "Expected implicit use of operand AL/AX/EAX/RAX not found");
      // Increment the number of operands evaluated
      NumOperandsEval++;
    }

    // Now, find source operand values.
    // First check if there are any implicit use operands of the instruction.
    unsigned NumImplicitUses = MIDesc.getNumImplicitUses();
    assert((NumImplicitUses < 3) &&
           "More than two implicit use operands found in BinOp instruction "
           "with RI/I format operands");
    unsigned SrcValIdx = 0;
    for (; SrcValIdx < NumImplicitUses; SrcValIdx++) {
      OpValues[SrcValIdx] = getPhysRegValue(MI, MIDesc.ImplicitUses[SrcValIdx]);
      // Check for undefined use
      if (OpValues[SrcValIdx] == nullptr)
        return false;
      NumOperandsEval++;
    }

    // Get the explicit source operand values.
    while (NumOperandsEval < NumOperands) {
      assert((SrcValIdx < 2) && "Unexpected operand index while raising BinOp "
                                "instruction with RI/I operand format");
      const MachineOperand &SrcOp = MI.getOperand(CurExplicitOpIndex);
      if (SrcValIdx == 0) {
        assert(SrcOp.isReg() &&
               "Not found expected register to be the first "
               "operand of BinOp instruction with RI/I operand format");

        // Get value of SrcOp appropriately sized.
        OpValues[0] = getRegOperandValue(MI, CurExplicitOpIndex);
        // Check for undefined use
        if (OpValues[0] == nullptr)
          return false;
        CurExplicitOpIndex++;
        NumOperandsEval++;
      }

      // Get the second source operand value if the instruction has at least two
      // operands.
      if (SrcValIdx == 1) {
        // If the instruction has an explicit second operand
        // Get value of SrcOp
        assert(SrcOp.isImm() && "Expect immediate operand in a BinOp "
                                "instruction with RI/I operand format");
        assert(OpValues[0] != nullptr &&
               "Undefined first source value encountered in BinOp instruction "
               "with RI/I operand format");
        // Create constant of type that matches that of the dest register
        // If the instruction has no dest operand (such as TEST) set the type of
        // immediate value to be that of first operand value.
        Type *Ty = (DstPReg == X86::NoRegister) ? OpValues[0]->getType()
                                                : getPhysRegType(DstPReg);
        OpValues[1] = ConstantInt::get(Ty, SrcOp.getImm());
        CurExplicitOpIndex++;
        NumOperandsEval++;
      }
      SrcValIdx++;
    }

    assert((NumOperandsEval == NumOperands) &&
           "Failed to evaluate operands of BinOp instruction correctly");

    // Set up the source values to be used by BinOp instruction.

    SrcOp1Value = OpValues[0];
    SrcOp2Value = OpValues[1];

    // Check validity of source operand values. Both source operands need to be
    // non null values. The only exception is when the instruction has 3
    // operands indicating that there is an implicit constant value encoded by
    // the instruction such as SHR81. Such operands are constructed in an
    // instruction-specific way before the generating the appropriate IR
    // instruction.
    assert((SrcOp1Value != nullptr) &&
           ((SrcOp2Value != nullptr) ||
            ((NumOperands == 3) && (SrcOp2Value == nullptr))) &&
           "Unexpected source values encountered in BinOp instruction with "
           "RI/I operand format");

    Instruction *BinOpInstr = nullptr;
    // EFLAGS that are affected by the result of the binary operation
    std::set<unsigned> AffectedEFlags;

    switch (MI.getOpcode()) {
    case X86::ADD8i8:
    case X86::ADD16i16:
    case X86::ADD8ri:
    case X86::ADD16ri:
    case X86::ADD16ri8:
    case X86::ADD32ri:
    case X86::ADD32ri8:
    case X86::ADD32i32:
    case X86::ADD64ri8:
    case X86::ADD64ri32:
    case X86::ADD64i32: {
      // Generate add instruction
      BinOpInstr = BinaryOperator::CreateAdd(SrcOp1Value, SrcOp2Value);
      // Clear OF and CF
      AffectedEFlags.insert(EFLAGS::CF);
      AffectedEFlags.insert(EFLAGS::OF);
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      AffectedEFlags.insert(EFLAGS::PF);
    } break;
    case X86::SUB32i32:
    case X86::SUB32ri:
    case X86::SUB32ri8:
    case X86::SUB64ri8:
    case X86::SUB64ri32:
    case X86::SUB64i32:
      // Generate sub instruction
      BinOpInstr = BinaryOperator::CreateSub(SrcOp1Value, SrcOp2Value);
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      AffectedEFlags.insert(EFLAGS::CF);
      AffectedEFlags.insert(EFLAGS::OF);
      AffectedEFlags.insert(EFLAGS::PF);
      break;
    case X86::AND8i8:
    case X86::AND8ri:
    case X86::AND16i16:
    case X86::AND16ri:
    case X86::AND16ri8:
    case X86::AND32i32:
    case X86::AND32ri:
    case X86::AND32ri8:
    case X86::AND64i32:
    case X86::AND64ri8:
    case X86::AND64ri32:
      // Generate and instruction
      BinOpInstr = BinaryOperator::CreateAnd(SrcOp1Value, SrcOp2Value);
      // Clear OF and CF
      raisedValues->setEflagBoolean(EFLAGS::OF, MBBNo, false);
      raisedValues->setEflagBoolean(EFLAGS::CF, MBBNo, false);
      // Test and set EFLAGs
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      AffectedEFlags.insert(EFLAGS::PF);
      break;
    case X86::OR8i8:
    case X86::OR8ri:
    case X86::OR16ri8:
    case X86::OR16i16:
    case X86::OR16ri:
    case X86::OR32i32:
    case X86::OR32ri:
    case X86::OR32ri8:
    case X86::OR64i32:
    case X86::OR64ri32:
    case X86::OR64ri8:
      // Generate or instruction
      BinOpInstr = BinaryOperator::CreateOr(SrcOp1Value, SrcOp2Value);
      // Clear OF and CF
      raisedValues->setEflagBoolean(EFLAGS::OF, MBBNo, false);
      raisedValues->setEflagBoolean(EFLAGS::CF, MBBNo, false);
      // Test and set EFLAGs
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      AffectedEFlags.insert(EFLAGS::PF);
      break;
    case X86::ROL8r1:
    case X86::ROL16r1:
    case X86::ROL32r1:
    case X86::ROL64r1:
      SrcOp2Value = ConstantInt::get(SrcOp1Value->getType(), 1);
      // Mark affected EFLAGs. Note OF is affected only for 1-bit rotates.
      AffectedEFlags.insert(EFLAGS::OF);
      LLVM_FALLTHROUGH;
    case X86::ROL8ri:
    case X86::ROL16ri:
    case X86::ROL32ri:
    case X86::ROL64ri: {
      // Generate the call to instrinsic
      auto IntrinsicKind = Intrinsic::fshl;
      Module *M = MR->getModule();
      Function *IntrinsicFunc =
          Intrinsic::getDeclaration(M, IntrinsicKind, SrcOp1Value->getType());
      Value *IntrinsicCallArgs[] = {SrcOp1Value, SrcOp1Value, SrcOp2Value};
      BinOpInstr =
          CallInst::Create(IntrinsicFunc, ArrayRef<Value *>(IntrinsicCallArgs));
      // Mark affected EFLAGs
      AffectedEFlags.insert(EFLAGS::CF);
      // The SF, ZF, AF, and PF flags are not affected.
    } break;
    case X86::ROR8r1:
    case X86::ROR16r1:
    case X86::ROR32r1:
    case X86::ROR64r1:
      SrcOp2Value = ConstantInt::get(SrcOp1Value->getType(), 1);
      // Mark affected EFLAGs. Note OF is affected only for 1-bit rotates.
      AffectedEFlags.insert(EFLAGS::OF);
      // The SF, ZF, AF, and PF flags are not affected.
      LLVM_FALLTHROUGH;
    case X86::ROR8ri:
    case X86::ROR16ri:
    case X86::ROR32ri:
    case X86::ROR64ri: {
      // Generate the call to instrinsic
      auto IntrinsicKind = Intrinsic::fshr;
      Module *M = MR->getModule();
      Function *IntrinsicFunc =
          Intrinsic::getDeclaration(M, IntrinsicKind, SrcOp1Value->getType());
      Value *IntrinsicCallArgs[] = {SrcOp1Value, SrcOp1Value, SrcOp2Value};
      BinOpInstr =
          CallInst::Create(IntrinsicFunc, ArrayRef<Value *>(IntrinsicCallArgs));
      // Mark affected EFLAGs
      AffectedEFlags.insert(EFLAGS::CF);
      // The SF, ZF, AF, and PF flags are not affected.
    } break;
    case X86::XOR8ri:
    case X86::XOR16ri:
    case X86::XOR32ri:
    case X86::XOR8i8:
    case X86::XOR16i16:
    case X86::XOR32i32:
    case X86::XOR8ri8:
    case X86::XOR16ri8:
    case X86::XOR32ri8:
    case X86::XOR64ri8:
    case X86::XOR64ri32:
      // Generate xor instruction
      BinOpInstr = BinaryOperator::CreateXor(SrcOp1Value, SrcOp2Value);
      // Clear OF and CF
      raisedValues->setEflagBoolean(EFLAGS::OF, MBBNo, false);
      raisedValues->setEflagBoolean(EFLAGS::CF, MBBNo, false);
      // Test and set EFLAGs
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      AffectedEFlags.insert(EFLAGS::PF);
      break;
    case X86::IMUL16rri:
    case X86::IMUL32rri:
    case X86::IMUL32rri8:
    case X86::IMUL64rri8:
    case X86::IMUL64rri32:
      BinOpInstr = BinaryOperator::CreateMul(SrcOp1Value, SrcOp2Value);
      // OF is also affected, but is set to be the same as CF. Setting of OF for
      // IMUL is handled along with setting of CF. So, there is no need to add
      // OF as affected flag.
      AffectedEFlags.insert(EFLAGS::CF);
      break;
    case X86::SHR8r1:
    case X86::SHR16r1:
    case X86::SHR32r1:
    case X86::SHR64r1:
      SrcOp2Value = ConstantInt::get(SrcOp1Value->getType(), 1);
      LLVM_FALLTHROUGH;
    case X86::SHR8ri:
    case X86::SHR16ri:
    case X86::SHR32ri:
    case X86::SHR64ri:
      // Generate shr instruction
      BinOpInstr = BinaryOperator::CreateLShr(SrcOp1Value, SrcOp2Value);
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      break;
    case X86::SHL8r1:
    case X86::SHL16r1:
    case X86::SHL32r1:
    case X86::SHL64r1:
      // Create SrcOp2 value of constant int value of 1
      SrcOp2Value = ConstantInt::get(SrcOp1Value->getType(), 1);
      LLVM_FALLTHROUGH;
    case X86::SHL8ri:
    case X86::SHL16ri:
    case X86::SHL32ri:
    case X86::SHL64ri:
      // Generate shl instruction
      BinOpInstr = BinaryOperator::CreateShl(SrcOp1Value, SrcOp2Value);
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      break;
    case X86::SAR8r1:
    case X86::SAR16r1:
    case X86::SAR32r1:
    case X86::SAR64r1:
      // Create SrcOp2 value of constant int value of 1
      SrcOp2Value = ConstantInt::get(SrcOp1Value->getType(), 1);
      LLVM_FALLTHROUGH;
    case X86::SAR8ri:
    case X86::SAR16ri:
    case X86::SAR32ri:
    case X86::SAR64ri:
      // Generate sar instruction
      BinOpInstr = BinaryOperator::CreateLShr(SrcOp1Value, SrcOp2Value);
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      break;
    case X86::TEST8i8:
    case X86::TEST16i16:
    case X86::TEST32i32:
    case X86::TEST64i32:
    case X86::TEST8ri:
    case X86::TEST16ri:
    case X86::TEST32ri:
      BinOpInstr = BinaryOperator::CreateAnd(SrcOp1Value, SrcOp2Value);
      // Clear OF and CF
      raisedValues->setEflagBoolean(EFLAGS::OF, MBBNo, false);
      raisedValues->setEflagBoolean(EFLAGS::CF, MBBNo, false);
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      AffectedEFlags.insert(EFLAGS::PF);
      break;
    case X86::INC8r:
    case X86::INC16r:
    case X86::INC16r_alt:
    case X86::INC32r:
    case X86::INC32r_alt:
    case X86::INC64r:
      SrcOp2Value = ConstantInt::get(SrcOp1Value->getType(), 1);
      BinOpInstr = BinaryOperator::CreateAdd(SrcOp1Value, SrcOp2Value);
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      AffectedEFlags.insert(EFLAGS::PF);
      break;
    case X86::DEC8r:
    case X86::DEC16r:
    case X86::DEC16r_alt:
    case X86::DEC32r:
    case X86::DEC32r_alt:
    case X86::DEC64r:
      SrcOp2Value = ConstantInt::get(SrcOp1Value->getType(), 1);
      BinOpInstr = BinaryOperator::CreateSub(SrcOp1Value, SrcOp2Value);
      AffectedEFlags.insert(EFLAGS::SF);
      AffectedEFlags.insert(EFLAGS::ZF);
      AffectedEFlags.insert(EFLAGS::PF);
      break;
    default:
      LLVM_DEBUG(MI.dump());
      assert(false && "Unhandled reg to imm binary operator instruction");
      break;
    }

    // propagate rodata metadata
    raisedValues->setInstMetadataRODataIndex(SrcOp1Value, BinOpInstr);
    raisedValues->setInstMetadataRODataIndex(SrcOp2Value, BinOpInstr);
    // Insert the binary operation instruction
    RaisedBB->getInstList().push_back(BinOpInstr);
    // Test and set affected flags
    for (auto Flag : AffectedEFlags)
      raisedValues->testAndSetEflagSSAValue(Flag, MI, BinOpInstr);

    // Update PhysReg to Value map
    if (DstPReg != X86::NoRegister)
      raisedValues->setPhysRegSSAValue(DstPReg, MI.getParent()->getNumber(),
                                       BinOpInstr);
  }
  return true;
}