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;
}