in X86/X86MachineInstructionRaiser.cpp [2864:3110]
bool X86MachineInstructionRaiser::raiseCompareMachineInstr(
const MachineInstr &MI, bool isMemCompare, Value *MemRefValue) {
// Ensure this is a compare instruction
assert(MI.isCompare() && "Compare instruction expected");
// Get index of memory reference in the instruction.
int memoryRefOpIndex = getMemoryRefOpIndex(MI);
int MBBNo = MI.getParent()->getNumber();
unsigned int DestReg = X86::NoRegister;
assert((((memoryRefOpIndex != -1) && isMemCompare) ||
((memoryRefOpIndex == -1) && !isMemCompare)) &&
"Inconsistent memory reference operand information specified for "
"compare instruction");
MCInstrDesc MCIDesc = MI.getDesc();
unsigned NumImplicitUses = MCIDesc.getNumImplicitUses();
// Get the BasicBlock corresponding to MachineBasicBlock of MI.
// Raised instruction is added to this BasicBlock.
BasicBlock *RaisedBB = getRaisedBasicBlock(MI.getParent());
// Three instructions viz., CMP*, SUB* and TEST* are classified by LLVM as
// compare instructions Is this a sub instruction?
bool isCMPInst = instrNameStartsWith(MI, "CMP");
bool isSUBInst = instrNameStartsWith(MI, "SUB");
bool isTESTInst = instrNameStartsWith(MI, "TEST");
assert((isCMPInst || isSUBInst || isTESTInst) &&
"Unhandled memory referencing compare instruction");
SmallVector<Value *, 2> OpValues{nullptr, nullptr};
// Get operand indices
if (isMemCompare) {
// This is a memory referencing instruction.
Type *NonMemRefOpTy;
const MachineOperand *NonMemRefOp;
assert(memoryRefOpIndex >= 0 &&
"Unexpected memory operand index in compare instruction");
unsigned nonMemRefOpIndex =
(memoryRefOpIndex == 0) ? X86::AddrNumOperands : 0;
NonMemRefOp = &(MI.getOperand(nonMemRefOpIndex));
if (NonMemRefOp->isReg()) {
NonMemRefOpTy = getPhysRegOperandType(MI, nonMemRefOpIndex);
} else if (NonMemRefOp->isImm()) {
LLVMContext &Ctx(MF.getFunction().getContext());
auto MemOpSize = getInstructionMemOpSize(MI.getOpcode());
assert(MemOpSize != 0 && "Expected mem op size to be > 0");
NonMemRefOpTy = Type::getIntNTy(Ctx, MemOpSize * 8);
} else {
LLVM_DEBUG(MI.dump());
assert(false && "Unhandled second operand type in compare instruction");
}
assert(MemRefValue != nullptr && "Null memory reference value encountered "
"while raising compare instruction");
// Convert it to a pointer of type of non-memory operand
if (isEffectiveAddrValue(MemRefValue)) {
PointerType *PtrTy = PointerType::get(NonMemRefOpTy, 0);
IntToPtrInst *convIntToPtr = new IntToPtrInst(MemRefValue, PtrTy);
RaisedBB->getInstList().push_back(convIntToPtr);
MemRefValue = convIntToPtr;
}
// Load the value from memory location
auto align =
MemRefValue->getPointerAlignment(MR->getModule()->getDataLayout());
LoadInst *loadInst =
new LoadInst(MemRefValue->getType()->getPointerElementType(),
MemRefValue, "", false, align, RaisedBB);
// save it at the appropriate index of operand value array
if (memoryRefOpIndex == 0) {
OpValues[0] = loadInst;
} else {
OpValues[1] = loadInst;
}
// Get value for non-memory operand of compare.
Value *NonMemRefVal = nullptr;
if (NonMemRefOp->isReg()) {
NonMemRefVal = getRegOrArgValue(NonMemRefOp->getReg(), MBBNo);
} else if (NonMemRefOp->isImm()) {
NonMemRefVal =
ConstantInt::get(MemRefValue->getType()->getPointerElementType(),
NonMemRefOp->getImm());
} else {
LLVM_DEBUG(MI.dump());
assert(false && "Unhandled first operand type in compare instruction");
}
// save non-memory reference value at the appropriate index of operand
// value array
if (memoryRefOpIndex == 0) {
OpValues[1] = NonMemRefVal;
} else {
OpValues[0] = NonMemRefVal;
}
} else {
// The instruction operands do not reference memory
unsigned Op1Index, Op2Index;
// Determine the appropriate operand indices of the instruction based on the
// usage of implicit registers. Note that a cmp instruction is translated as
// sub op1, op2 (i.e., op1 - op2).
if (NumImplicitUses == 1) {
// If an implicit operand is used, that is op1.
MCPhysReg UseReg = MCIDesc.ImplicitUses[0];
Op1Index = MI.findRegisterUseOperandIdx(UseReg, false, nullptr);
Op2Index = MCIDesc.getNumDefs() == 0 ? 0 : 1;
} else {
// Explicit operands are used
Op1Index = MCIDesc.getNumDefs() == 0 ? 0 : 1;
Op2Index = Op1Index + 1;
}
MachineOperand CmpOp1 = MI.getOperand(Op1Index);
MachineOperand CmpOp2 = MI.getOperand(Op2Index);
assert((CmpOp1.isReg() || CmpOp1.isImm()) &&
"Unhandled first operand type in compare instruction");
assert((CmpOp2.isReg() || CmpOp2.isImm()) &&
"Unhandled second operand type in compare instruction");
if (CmpOp1.isReg()) {
OpValues[0] = getRegOrArgValue(CmpOp1.getReg(), MBBNo);
}
if (CmpOp2.isReg()) {
OpValues[1] = getRegOrArgValue(CmpOp2.getReg(), MBBNo);
}
// Construct value if either of the operands is an immediate
if (CmpOp1.isImm()) {
assert((OpValues[1] != nullptr) &&
"At least one value expected while raising compare instruction");
OpValues[0] = ConstantInt::get(OpValues[1]->getType(), CmpOp1.getImm());
}
if (CmpOp2.isImm()) {
assert((OpValues[0] != nullptr) &&
"At least one value expected while raising compare instruction");
OpValues[1] = ConstantInt::get(OpValues[0]->getType(), CmpOp2.getImm());
}
}
assert(OpValues[0] != nullptr && OpValues[1] != nullptr &&
"Unable to materialize compare operand values");
// If the first operand is register, make sure the source operand value types
// are the same as destination register type.
if (MI.getOperand(0).isReg()) {
DestReg = MI.getOperand(0).getReg();
if (DestReg != X86::NoRegister) {
Type *DestTy = getPhysRegOperandType(MI, 0);
for (int i = 0; i < 2; i++) {
if (OpValues[i]->getType() != DestTy) {
CastInst *CInst = CastInst::Create(
CastInst::getCastOpcode(OpValues[i], false, DestTy, false),
OpValues[i], DestTy);
RaisedBB->getInstList().push_back(CInst);
OpValues[i] = CInst;
}
}
}
}
// If the number of implicit use operand is one, make sure the source operand
// value type is the same as the implicit use operand value type.
if (NumImplicitUses == 1) {
if (OpValues[0]->getType() != OpValues[1]->getType()) {
CastInst *CInst = CastInst::Create(
CastInst::getCastOpcode(OpValues[0], false, OpValues[1]->getType(),
false),
OpValues[0], OpValues[1]->getType());
RaisedBB->getInstList().push_back(CInst);
OpValues[0] = CInst;
}
}
assert((OpValues[0]->getType() == OpValues[1]->getType()) &&
"Mis-matched operand types encountered while raising compare "
"instruction");
raisedValues->setEflagBoolean(EFLAGS::OF, MBBNo, false);
raisedValues->setEflagBoolean(EFLAGS::CF, MBBNo, false);
// CmpInst is of type Value * to allow for a potential need to pass it to
// castValue(), if needed.
// If MI is a test instruction, the compare instruction should be an and
// instruction.
Value *CmpInst = (isTESTInst)
? BinaryOperator::CreateAnd(OpValues[0], OpValues[1])
: BinaryOperator::CreateSub(OpValues[0], OpValues[1]);
// Casting CmpInst to instruction to be added to the raised basic
// block is correct since it is known to be specifically of type Instruction.
RaisedBB->getInstList().push_back(dyn_cast<Instruction>(CmpInst));
if (isSUBInst) {
switch (MI.getOpcode()) {
case X86::SUB8mi:
case X86::SUB8mi8:
case X86::SUB8mr:
case X86::SUB16mi:
case X86::SUB16mi8:
case X86::SUB16mr:
case X86::SUB32mi:
case X86::SUB32mi8:
case X86::SUB32mr:
case X86::SUB64mi8:
case X86::SUB64mi32:
case X86::SUB64mr: {
// This instruction moves a source value to memory. So, if the types of
// the source value and that of the memory pointer content are not the
// same, it is the source value that needs to be cast to match the type of
// destination (i.e., memory). It needs to be sign extended as needed.
Type *MatchTy = MemRefValue->getType()->getPointerElementType();
if (!MatchTy->isArrayTy()) {
CmpInst = getRaisedValues()->castValue(CmpInst, MatchTy, RaisedBB);
}
// Store CmpInst to MemRefValue only if this is a sub MI or MR
// instruction. Do not update if this is a cmp instruction.
new StoreInst(CmpInst, MemRefValue, RaisedBB);
} break;
case X86::SUB32rr:
case X86::SUB64rr:
case X86::SUB8rm:
case X86::SUB32rm:
case X86::SUB64rm: {
assert(MCIDesc.getNumDefs() == 1 &&
"Unexpected number of def operands of sub instruction");
// Update the DestReg only if this is a sub instruction. Do not update
// if this is a cmp instruction
raisedValues->setPhysRegSSAValue(DestReg, MBBNo, CmpInst);
} break;
default:
assert(false && "Unhandled sub instruction found");
}
}
// Now update EFLAGS
assert(MCIDesc.getNumImplicitDefs() == 1 &&
"Compare instruction does not have exactly one implicit def");
MCPhysReg ImpDefReg = MCIDesc.ImplicitDefs[0];
assert(ImpDefReg == X86::EFLAGS &&
"Expected implicit EFLAGS def in compare instruction");
// Create instructions to set CF, ZF, SF, PF, and OF flags according to the
// result CmpInst. NOTE: Support for tracking AF not yet implemented.
raisedValues->testAndSetEflagSSAValue(EFLAGS::CF, MI, CmpInst);
raisedValues->testAndSetEflagSSAValue(EFLAGS::ZF, MI, CmpInst);
raisedValues->testAndSetEflagSSAValue(EFLAGS::SF, MI, CmpInst);
raisedValues->testAndSetEflagSSAValue(EFLAGS::OF, MI, CmpInst);
raisedValues->testAndSetEflagSSAValue(EFLAGS::PF, MI, CmpInst);
return true;
}