bool X86MachineInstructionRaiser::raiseBinaryOpRegToRegMachineInstr()

in X86/X86MachineInstructionRaiser.cpp [778:1556]


bool X86MachineInstructionRaiser::raiseBinaryOpRegToRegMachineInstr(
    const MachineInstr &MI) {

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

  // Convenience variables for instructions with a dest and one or two
  // operands
  const unsigned DestOpIndex = 0, UseOp1Index = 1, UseOp2Index = 2;
  std::vector<Value *> ExplicitSrcValues;
  int MBBNo = MI.getParent()->getNumber();
  bool Success = true;
  unsigned opc = MI.getOpcode();

  // Check if this instruction is a xor reg1, reg1 instruction, and does not need
  // to look up the value of the operand values
  bool IsXorSetZeroInstruction =
      (opc == X86::XOR64rr || opc == X86::XOR32rr || opc == X86::XOR16rr ||
       opc == X86::XOR8rr || opc == X86::XORPSrr || opc == X86::XORPDrr ||
       opc == X86::PXORrr) &&
      (MI.findTiedOperandIdx(1) == 0 &&
       MI.getOperand(DestOpIndex).getReg() ==
           MI.getOperand(UseOp2Index).getReg());

  // If we are raising a xor instruction that's just zeroing-out a register,
  // we don't need to look up the register operand values
  if (!IsXorSetZeroInstruction) {
    for (const MachineOperand &MO : MI.explicit_uses()) {
      assert(MO.isReg() &&
             "Unexpected non-register operand in binary op instruction");
      auto UseOpIndex =
          MI.findRegisterUseOperandIdx(MO.getReg(), false, nullptr);
      Value *SrcValue = getRegOperandValue(MI, UseOpIndex);

      ExplicitSrcValues.push_back(SrcValue);
    }

    // Verify the instruction has 1 or 2 use operands
    assert(
        (ExplicitSrcValues.size() == 1 || ((ExplicitSrcValues.size() == 2))) &&
        "Unexpected number of operands in register binary op instruction");

    // If the instruction has two use operands, ensure that their values are
    // of the same type and non-pointer type.
    if (ExplicitSrcValues.size() == 2) {
      Value *Src1Value = ExplicitSrcValues.at(0);
      Value *Src2Value = ExplicitSrcValues.at(1);
      // The user operand values can be null if the instruction is 'xor op
      // op'. See below.
      if ((Src1Value != nullptr) && (Src2Value != nullptr)) {
        // If this is a pointer type, convert it to int type
        while (Src1Value->getType()->isPointerTy()) {
          PtrToIntInst *ConvPtrToInst = new PtrToIntInst(
              Src1Value, Src1Value->getType()->getPointerElementType());
          RaisedBB->getInstList().push_back(ConvPtrToInst);
          Src1Value = ConvPtrToInst;
        }

        // If this is a pointer type, convert it to int type
        while (Src2Value->getType()->isPointerTy()) {
          PtrToIntInst *ConvPtrToInst = new PtrToIntInst(
              Src2Value, Src2Value->getType()->getPointerElementType());
          RaisedBB->getInstList().push_back(ConvPtrToInst);
          Src2Value = ConvPtrToInst;
        }
        assert(((Src1Value->getType()->isIntegerTy() &&
                 Src2Value->getType()->isIntegerTy()) ||
                (Src1Value->getType()->isFloatingPointTy() &&
               Src2Value->getType()->isFloatingPointTy()) ||
              (Src1Value->getType()->isVectorTy() &&
               Src2Value->getType()->isVectorTy())) &&
             "Unhandled operand value types in reg-to-reg binary op "
             "instruction");
      if (Src1Value->getType() != Src2Value->getType()) {
        // Cast the second operand to the type of second.
        // NOTE : The choice of target cast type is rather arbitrary. May
        // need a closer look.
        Type *DestValueTy = Src1Value->getType();
        Instruction *CInst = CastInst::Create(
            CastInst::getCastOpcode(Src2Value, false, DestValueTy, false),
            Src2Value, DestValueTy);
        RaisedBB->getInstList().push_back(CInst);
        Src2Value = CInst;
      }
      ExplicitSrcValues[0] = Src1Value;
      ExplicitSrcValues[1] = Src2Value;
      }
    }
  }

  // Figure out the destination register, corresponding value and the
  // binary operator.
  unsigned int dstReg = X86::NoRegister;
  Value *dstValue = nullptr;
  // Construct the appropriate binary operation instruction
  switch (opc) {
  case X86::ADD8rr:
  case X86::ADD32rr:
  case X86::ADD64rr: {
    Value *Src1Value = ExplicitSrcValues.at(0);
    Value *Src2Value = ExplicitSrcValues.at(1);
    // Verify the def operand is a register.
    assert(MI.getOperand(DestOpIndex).isReg() &&
           "Expecting destination of add instruction to be a register "
           "operand");
    assert((MCID.getNumDefs() == 1) &&
           "Unexpected number of defines in an add instruction");
    assert((Src1Value != nullptr) && (Src2Value != nullptr) &&
           "Unhandled situation: register is used before initialization in "
           "add");
    dstReg = MI.getOperand(DestOpIndex).getReg();
    // Create add instruction
    Instruction *BinOpInst = BinaryOperator::CreateNSWAdd(Src1Value, Src2Value);
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(Src1Value, BinOpInst);
    raisedValues->setInstMetadataRODataIndex(Src2Value, BinOpInst);
    RaisedBB->getInstList().push_back(BinOpInst);
    dstValue = BinOpInst;
    // Set SF and ZF based on dstValue; technically OF, AF, CF and PF also
    // needs to be set but ignoring for now.
    raisedValues->testAndSetEflagSSAValue(EFLAGS::SF, MI, dstValue);
    raisedValues->testAndSetEflagSSAValue(EFLAGS::ZF, MI, dstValue);

    // Update the value of dstReg
    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, dstValue);
  } break;
  case X86::IMUL16rr:
  case X86::IMUL32rr:
  case X86::IMUL64rr: {
    Value *Src1Value = ExplicitSrcValues.at(0);
    Value *Src2Value = ExplicitSrcValues.at(1);
    // Verify the def operand is a register.
    assert(MI.getOperand(DestOpIndex).isReg() &&
           "Expecting destination of mul instruction to be a register "
           "operand");
    assert((MCID.getNumDefs() == 1) &&
           "Unexpected number of defines in a mul instruction");
    assert((Src1Value != nullptr) && (Src2Value != nullptr) &&
           "Unhandled situation: register is used before initialization in "
           "mul");
    dstReg = MI.getOperand(DestOpIndex).getReg();
    Instruction *BinOpInst = BinaryOperator::CreateNSWMul(Src1Value, Src2Value);
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(Src1Value, BinOpInst);
    raisedValues->setInstMetadataRODataIndex(Src2Value, BinOpInst);
    RaisedBB->getInstList().push_back(BinOpInst);

    dstValue = BinOpInst;
    // Setting EFLAG bits does not seem to matter, so not setting
    // Set the dstReg value
    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, dstValue);
  } break;
  case X86::IMUL16r:
  case X86::IMUL32r:
  case X86::IMUL64r:
  case X86::MUL16r:
  case X86::MUL32r:
  case X86::MUL64r: {
    bool IsSigned = instrNameStartsWith(MI, "IMUL");

    assert(MCID.getNumDefs() == 0 && MCID.getNumImplicitDefs() == 3 &&
           MCID.getNumImplicitUses() == 1 &&
           "Unexpected operands in imul instruction");
    // Find first source operand - this is the implicit operand AL/AX/EAX/RAX
    const MCPhysReg Src1Reg = MCID.ImplicitUses[0];
    assert(find64BitSuperReg(Src1Reg) == X86::RAX &&
           "Unexpected implicit register in imul instruction");
    // Find second operand - this is the explicit operand of the instruction
    std::vector<MCPhysReg> SrcRegs;
    for (const MachineOperand &MO : MI.explicit_uses()) {
      assert(MO.isReg() &&
             "Unexpected non-register operand in binary op instruction");
      SrcRegs.push_back(MO.getReg());
    }
    // Ensure that there is only one explicit source operand
    assert(SrcRegs.size() == 1 &&
           "Unexpected number of source register operands in imul instruction");
    // Check the sizes of source operands are the same
    const MCPhysReg Src2Reg = SrcRegs[0];
    unsigned int SrcOpSize = getPhysRegSizeInBits(Src1Reg);
    assert(getPhysRegSizeInBits(Src1Reg) == getPhysRegSizeInBits(Src2Reg) &&
           "Mismatched size of implicit source register and explicit source "
           "register");
    // Get the value of Src1Reg and Src2Reg
    Value *Src1Value = getRegOrArgValue(Src1Reg, MBBNo);
    Value *Src2Value = getRegOrArgValue(Src2Reg, MBBNo);
    assert((Src1Value != nullptr) && (Src2Value != nullptr) &&
           "Unexpected null source operand value in imul instruction");
    assert(Src1Value->getType()->isIntegerTy() &&
           Src2Value->getType()->isIntegerTy() &&
           "Unexpected non-integer type source operands in imul instruction");
    LLVMContext &Ctx(MF.getFunction().getContext());
    // Widen the source values since the result of the multiplication
    Type *WideTy = Type::getIntNTy(Ctx, SrcOpSize * 2);
    CastInst *Src1ValueDT = CastInst::Create(
        CastInst::getCastOpcode(Src1Value, IsSigned, WideTy, IsSigned),
        Src1Value, WideTy);
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(Src1Value, Src1ValueDT);
    RaisedBB->getInstList().push_back(Src1ValueDT);

    CastInst *Src2ValueDT = CastInst::Create(
        CastInst::getCastOpcode(Src2Value, IsSigned, WideTy, IsSigned),
        Src2Value, WideTy);
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(Src2Value, Src2ValueDT);
    RaisedBB->getInstList().push_back(Src2ValueDT);
    // Multiply the values
    Instruction *FullProductValue =
        BinaryOperator::CreateNSWMul(Src1ValueDT, Src2ValueDT);
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(Src1ValueDT, FullProductValue);
    raisedValues->setInstMetadataRODataIndex(Src2ValueDT, FullProductValue);
    RaisedBB->getInstList().push_back(FullProductValue);
    // Shift amount equal to size of source operand
    Value *ShiftAmountVal =
        ConstantInt::get(FullProductValue->getType(), SrcOpSize);

    // Split the value into ImplicitDefs[0]:ImplicitDefs[1]
    // Compute shr of FullProductValue
    Instruction *ShrDT =
        BinaryOperator::CreateLShr(FullProductValue, ShiftAmountVal);
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(FullProductValue, ShrDT);
    RaisedBB->getInstList().push_back(ShrDT);
    // Truncate ShrDT to SrcOpSize
    Type *SrcValTy = Type::getIntNTy(Ctx, SrcOpSize);
    CastInst *ProductUpperValue =
        CastInst::Create(CastInst::Trunc, ShrDT, SrcValTy);
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(ShrDT, ProductUpperValue);
    RaisedBB->getInstList().push_back(ProductUpperValue);
    // Set the value of ImplicitDef[1] as ProductLowreHalfValue
    raisedValues->setPhysRegSSAValue(MCID.ImplicitDefs[1], MBBNo,
                                     ProductUpperValue);

    // Truncate the multiplication result to get the lower half value
    CastInst *ProductLowerHalfValue =
        CastInst::Create(CastInst::Trunc, FullProductValue, SrcValTy);
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(FullProductValue,
                                             ProductLowerHalfValue);
    RaisedBB->getInstList().push_back(ProductLowerHalfValue);
    // Set the value of ImplicitDef[0] as ProductLowerHalfValue
    raisedValues->setPhysRegSSAValue(MCID.ImplicitDefs[0], MBBNo,
                                     ProductLowerHalfValue);

    if (IsSigned) {
      // For IMUL instruction, we check if the full result is equal to the
      // sign-extended lower half If they are equal, set OF and CF to 0, 1
      // otherwise
      auto LowerSExtended = CastInst::Create(
          CastInst::SExt, ProductLowerHalfValue, WideTy, "", RaisedBB);
      auto EqualToFullValue = new ICmpInst(CmpInst::Predicate::ICMP_NE,
                                           LowerSExtended, FullProductValue);
      RaisedBB->getInstList().push_back(EqualToFullValue);

      raisedValues->setPhysRegSSAValue(X86RegisterUtils::EFLAGS::OF, MBBNo,
                                       EqualToFullValue);
      raisedValues->setPhysRegSSAValue(X86RegisterUtils::EFLAGS::CF, MBBNo,
                                       EqualToFullValue);
    } else {
      // Set OF and CF flags to 0 if upper half of the result is 0; else to 1.
      Value *ZeroValue = ConstantInt::get(SrcValTy, 0, IsSigned);

      Instruction *ZFTest =
          new ICmpInst(CmpInst::Predicate::ICMP_NE, ProductUpperValue,
                       ZeroValue, "Test_Not_Zero");

      RaisedBB->getInstList().push_back(ZFTest);
      raisedValues->setPhysRegSSAValue(X86RegisterUtils::EFLAGS::OF, MBBNo,
                                       ZFTest);
      raisedValues->setPhysRegSSAValue(X86RegisterUtils::EFLAGS::CF, MBBNo,
                                       ZFTest);
    }
  } break;
  case X86::AND8rr:
  case X86::AND16rr:
  case X86::AND32rr:
  case X86::AND64rr:
  case X86::OR8rr:
  case X86::OR16rr:
  case X86::OR32rr:
  case X86::OR64rr:
  case X86::XOR8rr:
  case X86::XOR16rr:
  case X86::XOR32rr:
  case X86::XOR64rr: {
    // Verify the def operand is a register.
    const MachineOperand &DestOp = MI.getOperand(DestOpIndex);
    assert(DestOp.isReg() && "Expecting destination of xor instruction to "
                             "be a register operand");
    assert((MCID.getNumDefs() == 1) &&
           MCID.hasImplicitDefOfPhysReg(X86::EFLAGS) &&
           "Unexpected defines in a xor instruction");
    dstReg = DestOp.getReg();
    // Generate an or instruction to set the zero flag if the
    // operands are the same. An instruction such as 'xor $ecx, ecx' is
    // generated to set the register value to 0.
    if (IsXorSetZeroInstruction) {
      // No instruction to generate. Just set destReg value to 0.
      Type *DestTy = getPhysRegOperandType(MI, 0);
      Value *Val = ConstantInt::get(DestTy, 0, false /* isSigned */);
      dstValue = Val;
      // Set SF and ZF knowing that the value is 0
      raisedValues->setEflagBoolean(EFLAGS::SF, MBBNo, false);
      raisedValues->setEflagBoolean(EFLAGS::ZF, MBBNo, true);
      // Set PF knowing that the value is 0, since 0 has
      // an even number of bits set, namely, zero
      raisedValues->setEflagBoolean(EFLAGS::PF, MBBNo, true);
    } else {
      Value *Src1Value = ExplicitSrcValues.at(0);
      Value *Src2Value = ExplicitSrcValues.at(1);
      assert((Src1Value != nullptr) && (Src2Value != nullptr) &&
             "Unhandled situation: register used before initialization in "
             "xor");
      Instruction *BinOpInst = nullptr;
      switch (opc) {
      case X86::AND8rr:
      case X86::AND16rr:
      case X86::AND32rr:
      case X86::AND64rr:
        BinOpInst = BinaryOperator::CreateAnd(Src1Value, Src2Value);
        break;
      case X86::OR8rr:
      case X86::OR16rr:
      case X86::OR32rr:
      case X86::OR64rr:
        BinOpInst = BinaryOperator::CreateOr(Src1Value, Src2Value);
        break;
      case X86::XOR8rr:
      case X86::XOR16rr:
      case X86::XOR32rr:
      case X86::XOR64rr:
        BinOpInst = BinaryOperator::CreateXor(Src1Value, Src2Value);
        break;
      default:
        assert(false && "Reached unexpected location");
      }
      // Copy any necessary rodata related metadata
      raisedValues->setInstMetadataRODataIndex(Src1Value, BinOpInst);
      raisedValues->setInstMetadataRODataIndex(Src2Value, BinOpInst);

      RaisedBB->getInstList().push_back(BinOpInst);
      dstValue = BinOpInst;
      // Set SF, PF, and ZF based on dstValue.
      raisedValues->testAndSetEflagSSAValue(EFLAGS::SF, MI, dstValue);
      raisedValues->testAndSetEflagSSAValue(EFLAGS::ZF, MI, dstValue);
      raisedValues->testAndSetEflagSSAValue(EFLAGS::PF, MI, dstValue);
    }
    // Clear OF and CF
    raisedValues->setEflagBoolean(EFLAGS::OF, MBBNo, false);
    raisedValues->setEflagBoolean(EFLAGS::CF, MBBNo, false);
    // Update the value of dstReg
    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, dstValue);
  } break;
  case X86::TEST8rr:
  case X86::TEST16rr:
  case X86::TEST32rr:
  case X86::TEST64rr: {
    Value *Src1Value = ExplicitSrcValues.at(0);
    Value *Src2Value = ExplicitSrcValues.at(1);
    assert((MCID.getNumDefs() == 0) &&
           MCID.hasImplicitDefOfPhysReg(X86::EFLAGS) &&
           "Unexpected defines in a test instruction");
    assert((Src1Value != nullptr) && (Src2Value != nullptr) &&
           "Unhandled situation: register is used before initialization in "
           "test");
    dstReg = X86::EFLAGS;
    Instruction *BinOpInst = BinaryOperator::CreateAnd(Src1Value, Src2Value);
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(Src1Value, BinOpInst);
    if (Src1Value != Src2Value)
      raisedValues->setInstMetadataRODataIndex(Src2Value, BinOpInst);
    RaisedBB->getInstList().push_back(BinOpInst);
    dstValue = BinOpInst;
    // Clear OF and CF
    raisedValues->setEflagBoolean(EFLAGS::OF, MBBNo, false);
    raisedValues->setEflagBoolean(EFLAGS::CF, MBBNo, false);
    // Set SF, PF, and ZF based on dstValue.
    raisedValues->testAndSetEflagSSAValue(EFLAGS::SF, MI, dstValue);
    raisedValues->testAndSetEflagSSAValue(EFLAGS::ZF, MI, dstValue);
    raisedValues->testAndSetEflagSSAValue(EFLAGS::PF, MI, dstValue);
  } break;
  case X86::NEG8r:
  case X86::NEG16r:
  case X86::NEG32r:
  case X86::NEG64r: {
    // Verify source and dest are tied and are registers
    const MachineOperand &DestOp = MI.getOperand(DestOpIndex);
    assert(DestOp.isTied() &&
           (MI.findTiedOperandIdx(DestOpIndex) == UseOp1Index) &&
           "Expect tied operand in neg instruction");
    assert(DestOp.isReg() && "Expect reg operand in neg instruction");
    assert((MCID.getNumDefs() == 1) &&
           MCID.hasImplicitDefOfPhysReg(X86::EFLAGS) &&
           "Unexpected defines in a neg instruction");
    dstReg = DestOp.getReg();
    Value *Src1Value = ExplicitSrcValues.at(0);
    Instruction *BinOpInst = BinaryOperator::CreateNeg(Src1Value);
    dstValue = BinOpInst;
    // Set CF to 0 if source operand is 0
    // Note: Add this instruction _before_ adding the result of neg
    raisedValues->testAndSetEflagSSAValue(EFLAGS::CF, MI, dstValue);
    // Now add the neg instruction
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(Src1Value, BinOpInst);
    RaisedBB->getInstList().push_back(BinOpInst);
    // Now set up the flags according to the result
    // Set SF, PF, and ZF based on dstValue.
    raisedValues->testAndSetEflagSSAValue(EFLAGS::ZF, MI, dstValue);
    raisedValues->testAndSetEflagSSAValue(EFLAGS::SF, MI, dstValue);
    raisedValues->testAndSetEflagSSAValue(EFLAGS::PF, MI, dstValue);

    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, dstValue);
  } break;
  case X86::NOT8r:
  case X86::NOT16r:
  case X86::NOT32r:
  case X86::NOT64r: {
    // Verify source and dest are tied and are registers
    const MachineOperand &DestOp = MI.getOperand(DestOpIndex);
    assert(DestOp.isTied() &&
           (MI.findTiedOperandIdx(DestOpIndex) == UseOp1Index) &&
           "Expect tied operand in not instruction");
    assert(DestOp.isReg() && "Expect reg operand in not instruction");
    assert((MCID.getNumDefs() == 1) &&
           "Unexpected defines in a not instruction");
    dstReg = DestOp.getReg();
    Value *Src1Value = ExplicitSrcValues.at(0);
    Instruction *BinOpInst = BinaryOperator::CreateNot(Src1Value);
    // No EFLAGS are effected
    // Add the not instruction
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(Src1Value, BinOpInst);
    RaisedBB->getInstList().push_back(BinOpInst);
    dstValue = BinOpInst;

    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, dstValue);
  } break;
  case X86::SAR8rCL:
  case X86::SAR16rCL:
  case X86::SAR32rCL:
  case X86::SAR64rCL:
  case X86::SHL8rCL:
  case X86::SHL16rCL:
  case X86::SHL32rCL:
  case X86::SHL64rCL:
  case X86::SHR8rCL:
  case X86::SHR16rCL:
  case X86::SHR32rCL:
  case X86::SHR64rCL: {
    // Verify source and dest are tied and are registers
    const MachineOperand &DestOp = MI.getOperand(DestOpIndex);
    assert(DestOp.isTied() &&
           (MI.findTiedOperandIdx(DestOpIndex) == UseOp1Index) &&
           "Expect tied operand in shl instruction");
    assert(DestOp.isReg() && "Expect reg operand in shl instruction");
    assert((MCID.getNumDefs() == 1) &&
           "Unexpected defines in a shl instruction");
    dstReg = DestOp.getReg();
    Value *SrcOpValue = ExplicitSrcValues.at(0);
    assert((MCID.getNumImplicitUses() == 1) &&
           "Expect one implicit use in shl instruction");
    assert((MCID.ImplicitUses[0] == X86::CL) &&
           "Expect implicit CL regsiter operand in shl instruction");
    Value *CountValue = getPhysRegValue(MI, X86::CL);
    // Check for undefined use
    if (CountValue == nullptr)
      Success = false;
    else {
      // cast CountValue as needed
      Type *SrcOpValueTy = SrcOpValue->getType();
      CountValue =
          getRaisedValues()->castValue(CountValue, SrcOpValueTy, RaisedBB);
      // Count is masked to 5 bits (6 bits if 64-bit register)
      bool Is64Bit = (SrcOpValue->getType()->getPrimitiveSizeInBits() == 64);
      Value *CountMask = Is64Bit ? ConstantInt::get(SrcOpValueTy, 0x1f)
                                 : ConstantInt::get(SrcOpValueTy, 0x3f);
      // Generate mask
      CountValue = BinaryOperator::CreateAnd(CountValue, CountMask,
                                             "shift-cnt-msk", RaisedBB);

      Instruction *BinOpInst;
      if (instrNameStartsWith(MI, "SAR")) {
        BinOpInst =
            BinaryOperator::CreateAShr(SrcOpValue, CountValue);
      } else if (instrNameStartsWith(MI, "SHL")) {
        BinOpInst =
            BinaryOperator::CreateShl(SrcOpValue, CountValue);
      } else if (instrNameStartsWith(MI, "SHR")) {
        BinOpInst =
            BinaryOperator::CreateLShr(SrcOpValue, CountValue);
      } else {
        llvm_unreachable("unhandled shift instruction");
      }

      // Copy any necessary rodata related metadata
      raisedValues->setInstMetadataRODataIndex(SrcOpValue, BinOpInst);
      raisedValues->setInstMetadataRODataIndex(CountValue, BinOpInst);
      // Add the shl instruction
      RaisedBB->getInstList().push_back(BinOpInst);
      dstValue = BinOpInst;

      // Affected EFLAGS
      raisedValues->testAndSetEflagSSAValue(EFLAGS::CF, MI, dstValue);
      raisedValues->testAndSetEflagSSAValue(EFLAGS::ZF, MI, dstValue);
      raisedValues->testAndSetEflagSSAValue(EFLAGS::SF, MI, dstValue);

      raisedValues->setPhysRegSSAValue(dstReg, MBBNo, dstValue);
    }
  } break;
  case X86::POPCNT16rr:
  case X86::POPCNT32rr:
  case X86::POPCNT64rr: {
    const MachineOperand &DestOp = MI.getOperand(DestOpIndex);
    assert(DestOp.isReg() && "Expecting destination of popcnt instruction to "
                             "be a register operand");
    assert((MCID.getNumDefs() == 1) &&
           MCID.hasImplicitDefOfPhysReg(X86::EFLAGS) &&
           "Unexpected defines in a popcnt instruction");
    dstReg = DestOp.getReg();
    Value *SrcValue = ExplicitSrcValues.at(0);

    Module *M = MR->getModule();
    Function *IntrinsicFunc =
        Intrinsic::getDeclaration(M, Intrinsic::ctpop, SrcValue->getType());
    Value *IntrinsicCallArgs[] = {SrcValue};
    Instruction *BinOpInst =
        CallInst::Create(IntrinsicFunc, ArrayRef<Value *>(IntrinsicCallArgs));

    // Add the intrinsic call instruction
    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(SrcValue, BinOpInst);
    RaisedBB->getInstList().push_back(BinOpInst);
    dstValue = BinOpInst;

    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, dstValue);

    // OF, SF, ZF, AF, CF, PF are all cleared. ZF is set if SRC = 0, otherwise
    // ZF is cleared.
    raisedValues->setEflagBoolean(EFLAGS::OF, MBBNo, false);
    raisedValues->setEflagBoolean(EFLAGS::SF, MBBNo, false);
    raisedValues->setEflagBoolean(EFLAGS::AF, MBBNo, false);
    raisedValues->setEflagBoolean(EFLAGS::CF, MBBNo, false);
    raisedValues->setEflagBoolean(EFLAGS::PF, MBBNo, false);

    // Test if SrcValue is Zero
    Value *ZeroValue =
        ConstantInt::get(SrcValue->getType(), 0, false /* isSigned */);
    Instruction *ZFTest = new ICmpInst(CmpInst::Predicate::ICMP_EQ, SrcValue,
                                       ZeroValue, "ZeroFlag");
    RaisedBB->getInstList().push_back(ZFTest);
    // ZF = (SrcValue==0).
    raisedValues->setPhysRegSSAValue(X86RegisterUtils::EFLAGS::ZF, MBBNo,
                                     ZFTest);

  } break;
  case X86::SUBSSrr_Int:
  case X86::SUBSDrr_Int:
  case X86::ADDSSrr_Int:
  case X86::ADDSDrr_Int:
  case X86::MULSDrr_Int:
  case X86::MULSSrr_Int:
  case X86::DIVSDrr_Int:
  case X86::DIVSSrr_Int: {
    Value *Src1Value = ExplicitSrcValues.at(0);
    Value *Src2Value = ExplicitSrcValues.at(1);
    // Verify the def operand is a register.
    assert(MI.getOperand(DestOpIndex).isReg() &&
           "Expecting destination of fp op instruction to be a register "
           "operand");
    assert((MCID.getNumDefs() == 1) &&
           "Unexpected number of defines in fp op instruction");
    assert((Src1Value != nullptr) && (Src2Value != nullptr) &&
           "Unhandled situation: register is used before initialization in "
           "fp op");
    dstReg = MI.getOperand(DestOpIndex).getReg();

    Instruction *BinOpInst = nullptr;
    switch (opc) {
    case X86::ADDSSrr_Int:
    case X86::ADDSDrr_Int:
      BinOpInst = BinaryOperator::CreateFAdd(Src1Value, Src2Value);
      break;
    case X86::SUBSSrr_Int:
    case X86::SUBSDrr_Int:
      BinOpInst = BinaryOperator::CreateFSub(Src1Value, Src2Value);
      break;
    case X86::MULSDrr_Int:
    case X86::MULSSrr_Int:
      BinOpInst = BinaryOperator::CreateFMul(Src1Value, Src2Value);
      break;
    case X86::DIVSDrr_Int:
    case X86::DIVSSrr_Int:
      BinOpInst = BinaryOperator::CreateFDiv(Src1Value, Src2Value);
      break;
    default:
      llvm_unreachable("Unhandled fp instruction");
    }

    // Copy any necessary rodata related metadata
    raisedValues->setInstMetadataRODataIndex(Src1Value, BinOpInst);
    // raisedValues->setInstMetadataRODataIndex(Src2Value, BinOpInst);
    RaisedBB->getInstList().push_back(BinOpInst);
    dstValue = BinOpInst;

    // Update the value of dstReg
    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, dstValue);
  } break;
  case X86::PANDrr:
  case X86::PANDNrr:
  case X86::ANDPDrr:
  case X86::ANDPSrr:
  case X86::ANDNPDrr:
  case X86::ANDNPSrr:
  case X86::PORrr:
  case X86::ORPDrr:
  case X86::ORPSrr:
  case X86::PXORrr:
  case X86::XORPDrr:
  case X86::XORPSrr: {
    // bitwise operations on fp values do not exist in LLVM.
    // To emulate the behavior, we
    // - bitcast values to int
    // - perform the operation
    // - bitcast back to original type
    dstReg = MI.getOperand(DestOpIndex).getReg();

    if (IsXorSetZeroInstruction) {
      // No instruction to generate. Just set destReg value to 0.
      Type *DestTy = getPhysRegOperandType(MI, 0);
      if (DestTy->isFPOrFPVectorTy()) {
        dstValue = ConstantFP::get(DestTy, 0);
      } else {
        dstValue = ConstantInt::get(DestTy, 0);
      }
    } else {
      LLVMContext &Ctx(MF.getFunction().getContext());

      Value *Src1Value = ExplicitSrcValues.at(0);
      Value *Src2Value = ExplicitSrcValues.at(1);
      // Verify the def operand is a register.
      assert(MI.getOperand(DestOpIndex).isReg() &&
             "Expecting destination of fp op instruction to be a register "
             "operand");
      assert((MCID.getNumDefs() == 1) &&
             "Unexpected number of defines in fp op instruction");
      assert((Src1Value != nullptr) && (Src2Value != nullptr) &&
             "Unhandled situation: register is used before initialization in "
             "fp op");

      assert(Src1Value->getType()->getPrimitiveSizeInBits() ==
                 Src2Value->getType()->getPrimitiveSizeInBits() &&
             "Expected operand types to have same size");

      auto BitSize = std::max(Src1Value->getType()->getPrimitiveSizeInBits(),
                              Src2Value->getType()->getPrimitiveSizeInBits());

      Instruction *BitCastToInt1 =
          new BitCastInst(Src1Value, Type::getIntNTy(Ctx, BitSize),
                          "bitwise_operand", RaisedBB);
      Instruction *BitCastToInt2 =
          new BitCastInst(Src2Value, Type::getIntNTy(Ctx, BitSize),
                          "bitwise_operand", RaisedBB);

      Instruction *Result;

      switch (opc) {
      case X86::PANDrr:
      case X86::ANDPDrr:
      case X86::ANDPSrr:
        Result = BinaryOperator::CreateAnd(BitCastToInt1, BitCastToInt2,
                                           "and_result", RaisedBB);
        break;
      case X86::PANDNrr:
      case X86::ANDNPDrr:
      case X86::ANDNPSrr: {
        auto NotVal = BinaryOperator::CreateNot(BitCastToInt1, "", RaisedBB);
        Result = BinaryOperator::CreateAnd(NotVal, BitCastToInt2,
                                           "andn_result", RaisedBB);
      } break;
      case X86::PORrr:
      case X86::ORPDrr:
      case X86::ORPSrr:
        Result = BinaryOperator::CreateOr(BitCastToInt1, BitCastToInt2,
                                          "or_result", RaisedBB);
        break;
      case X86::PXORrr:
      case X86::XORPDrr:
      case X86::XORPSrr:
        Result = BinaryOperator::CreateXor(BitCastToInt1, BitCastToInt2,
                                           "xor_result", RaisedBB);
        break;
      default:
        llvm_unreachable("unhandled bitwise instruction");
      }

      Instruction *CastBackResult = new BitCastInst(
          Result, Src1Value->getType(), "bitcast_result", RaisedBB);

      dstValue = CastBackResult;
    }

    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, dstValue);
  } break;
  case X86::MAXSDrr_Int:
  case X86::MAXSSrr_Int:
  case X86::MINSDrr_Int:
  case X86::MINSSrr_Int: {
    bool isMax = instrNameStartsWith(MI, "MAX");
    std::string nameString = isMax ? "max" : "min";

    Value *Src1Value = ExplicitSrcValues.at(0);
    Value *Src2Value = ExplicitSrcValues.at(1);

    auto CmpType = isMax ? CmpInst::FCMP_OGT : CmpInst::FCMP_OLT;
    Instruction *CmpInst =
        new FCmpInst(*RaisedBB, CmpType, Src1Value, Src2Value, "cmp");

    Instruction *SelectInst =
        SelectInst::Create(CmpInst, Src1Value, Src2Value, nameString, RaisedBB);

    dstReg = MI.getOperand(DestOpIndex).getReg();
    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, SelectInst);
  } break;
  case X86::SBB16rr:
  case X86::SBB32rr:
  case X86::SBB64rr:
  case X86::SBB8rr: {
    Value *Src1Value = ExplicitSrcValues.at(0);
    Value *Src2Value = ExplicitSrcValues.at(1);
    Value *CFValue = getRegOrArgValue(EFLAGS::CF, MBBNo);
    assert(CFValue && "Expected CF to be set for sbb instruction");

    auto CFExtended = CastInst::Create(Instruction::ZExt, CFValue,
                                       Src2Value->getType(), "", RaisedBB);

    auto Src2AndCFValue =
        BinaryOperator::CreateAdd(Src2Value, CFExtended, "", RaisedBB);

    auto Result =
        BinaryOperator::CreateSub(Src1Value, Src2AndCFValue, "", RaisedBB);

    dstReg = MI.getOperand(DestOpIndex).getReg();
    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, Result);
    raisedValues->testAndSetEflagSSAValue(EFLAGS::OF, MI, Result);
    raisedValues->testAndSetEflagSSAValue(EFLAGS::CF, MI, Result);
  } break;
  case X86::SQRTSDr:
  case X86::SQRTSDr_Int:
  case X86::SQRTSSr:
  case X86::SQRTSSr_Int: {
    LLVMContext &Ctx(MF.getFunction().getContext());

    Type *InstrTy = getRaisedValues()->getSSEInstructionType(MI, Ctx);
    Value *SrcValue = getRaisedValues()->reinterpretSSERegValue(
        ExplicitSrcValues.at(0), InstrTy, RaisedBB);

    Module *M = MR->getModule();
    auto IntrinsicFunc = Intrinsic::getDeclaration(M, Intrinsic::sqrt, InstrTy);

    Value *IntrinsicCallArgs[] = {SrcValue};
    auto Result = CallInst::Create(
        IntrinsicFunc, ArrayRef<Value *>(IntrinsicCallArgs), "", RaisedBB);
    raisedValues->setInstMetadataRODataIndex(SrcValue, Result);

    dstReg = MI.getOperand(DestOpIndex).getReg();
    raisedValues->setPhysRegSSAValue(dstReg, MBBNo, Result);
  } break;
  default:
    MI.dump();
    assert(false && "Unhandled binary instruction");
  }

  return Success;
}