in X86/X86MachineInstructionRaiser.cpp [1558:1821]
bool X86MachineInstructionRaiser::raiseBinaryOpMemToRegInstr(
const MachineInstr &MI, Value *MemRefValue) {
unsigned int Opcode = MI.getOpcode();
const MCInstrDesc &MIDesc = MI.getDesc();
std::set<unsigned> AffectedEFlags;
std::set<unsigned> ClearedEFlags;
assert((MIDesc.getNumDefs() == 1) &&
"Encountered memory load instruction with more than 1 defs");
unsigned int DestIndex = 0;
const MachineOperand &DestOp = MI.getOperand(DestIndex);
assert(DestOp.isReg() &&
"Expect destination register operand in binary reg/mem instruction");
// Get the BasicBlock corresponding to MachineBasicBlock of MI.
// Raised instruction is added to this BasicBlock.
BasicBlock *RaisedBB = getRaisedBasicBlock(MI.getParent());
unsigned int DestPReg = DestOp.getReg();
unsigned int MemAlignment = getInstructionMemOpSize(Opcode);
Type *DestopTy = getPhysRegOperandType(MI, DestIndex);
Value *DestValue = getRegOrArgValue(DestPReg, MI.getParent()->getNumber());
// Verify sanity of the instruction.
// SSE2 registers are always of a fixed size and might not be equal to
// MemAlignment
assert((isSSE2Reg(DestOp.getReg()) ||
getPhysRegOperandSize(MI, DestIndex) == MemAlignment) &&
"Mismatched destination register size and instruction size of binary "
"op instruction");
unsigned int MemoryRefOpIndex = getMemoryRefOpIndex(MI);
Value *LoadValue =
loadMemoryRefValue(MI, MemRefValue, MemoryRefOpIndex, DestopTy);
if (DestValue != nullptr) {
// Cast DestValue to the DestopTy, as for single-precision FP ops
// DestValue type and DestopTy might be different.
if (isSSE2Reg(DestPReg)) {
DestValue = getRaisedValues()->reinterpretSSERegValue(DestValue, DestopTy,
RaisedBB);
} else {
DestValue = getRaisedValues()->castValue(DestValue, DestopTy, RaisedBB);
}
}
Instruction *BinOpInst = nullptr;
switch (Opcode) {
case X86::ADD64rm:
case X86::ADD32rm:
case X86::ADD16rm:
case X86::ADD8rm: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
// Create add instruction
BinOpInst = BinaryOperator::CreateAdd(DestValue, LoadValue);
AffectedEFlags.insert(EFLAGS::PF);
} break;
case X86::AND64rm:
case X86::AND32rm:
case X86::AND16rm:
case X86::AND8rm: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
// Create and instruction
BinOpInst = BinaryOperator::CreateAnd(DestValue, LoadValue);
AffectedEFlags.insert(EFLAGS::PF);
} break;
case X86::OR32rm: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
// Create or instruction
BinOpInst = BinaryOperator::CreateOr(DestValue, LoadValue);
AffectedEFlags.insert(EFLAGS::PF);
} break;
case X86::IMUL16rm:
case X86::IMUL32rm:
case X86::IMUL64rm: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
// One-operand form of IMUL
// Create mul instruction
BinOpInst = BinaryOperator::CreateMul(DestValue, LoadValue);
} break;
case X86::IMUL16rmi:
case X86::IMUL16rmi8:
case X86::IMUL32rmi:
case X86::IMUL32rmi8:
case X86::IMUL64rmi8:
case X86::IMUL64rmi32: {
// We don't read from DestValue, so we don't need to check if it is null
// Three-operand form of IMUL
// Get index of memory reference in the instruction.
int MemoryRefOpIndex = getMemoryRefOpIndex(MI);
// The index of the memory reference operand should be 1
assert(MemoryRefOpIndex == 1 &&
"Unexpected memory reference operand index in imul instruction");
const MachineOperand &SecondSourceOp =
MI.getOperand(MemoryRefOpIndex + X86::AddrNumOperands);
// Second source should be an immediate.
assert(SecondSourceOp.isImm() &&
"Expect immediate operand in imul instruction");
// Construct the value corresponding to immediate operand
Value *SecondSourceVal =
ConstantInt::get(LoadValue->getType(), SecondSourceOp.getImm());
// Create mul instruction
BinOpInst = BinaryOperator::CreateMul(SecondSourceVal, LoadValue);
} break;
case X86::XOR8rm:
case X86::XOR16rm:
case X86::XOR32rm:
case X86::XOR64rm: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
// Create xor instruction
BinOpInst = BinaryOperator::CreateXor(DestValue, LoadValue);
ClearedEFlags.insert(EFLAGS::OF);
ClearedEFlags.insert(EFLAGS::CF);
AffectedEFlags.insert(EFLAGS::SF);
AffectedEFlags.insert(EFLAGS::ZF);
AffectedEFlags.insert(EFLAGS::PF);
} break;
case X86::ADDSSrm_Int:
case X86::ADDSDrm_Int: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
BinOpInst = BinaryOperator::CreateFAdd(DestValue, LoadValue);
} break;
case X86::SUBSSrm_Int:
case X86::SUBSDrm_Int: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
BinOpInst = BinaryOperator::CreateFSub(DestValue, LoadValue);
} break;
case X86::MULSDrm_Int:
case X86::MULSSrm_Int: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
BinOpInst = BinaryOperator::CreateFMul(DestValue, LoadValue);
} break;
case X86::DIVSDrm_Int:
case X86::DIVSSrm_Int: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
BinOpInst = BinaryOperator::CreateFDiv(DestValue, LoadValue);
} break;
case X86::MAXSDrm_Int:
case X86::MAXSSrm_Int:
case X86::MINSDrm_Int:
case X86::MINSSrm_Int: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
bool isMax = instrNameStartsWith(MI, "MAX");
std::string nameString = isMax ? "max" : "min";
auto CmpType = isMax ? CmpInst::FCMP_OGT : CmpInst::FCMP_OLT;
Instruction *CmpInst =
new FCmpInst(*RaisedBB, CmpType, DestValue, LoadValue, "cmp");
BinOpInst = SelectInst::Create(CmpInst, DestValue, LoadValue, nameString);
} break;
case X86::ANDPDrm:
case X86::ANDPSrm:
case X86::ANDNPDrm:
case X86::ANDNPSrm:
case X86::ORPDrm:
case X86::ORPSrm:
case X86::XORPDrm:
case X86::XORPSrm: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
LLVMContext &Ctx(MF.getFunction().getContext());
auto Int128Ty = Type::getInt128Ty(Ctx);
// BitCast operands to integer types to perform and/or/xor operation
auto DestValueInt = new BitCastInst(DestValue, Int128Ty, "", RaisedBB);
auto LoadValueInt = new BitCastInst(LoadValue, Int128Ty, "", RaisedBB);
Value *Result;
switch (Opcode) {
case X86::ANDPDrm:
case X86::ANDPSrm:
Result = BinaryOperator::CreateAnd(DestValueInt, LoadValueInt, "", RaisedBB);
break;
case X86::ANDNPDrm:
case X86::ANDNPSrm: {
auto NotVal = BinaryOperator::CreateNot(DestValueInt, "", RaisedBB);
Result = BinaryOperator::CreateAnd(NotVal, LoadValueInt, "", RaisedBB);
} break;
case X86::ORPDrm:
case X86::ORPSrm:
Result = BinaryOperator::CreateOr(DestValueInt, LoadValueInt, "", RaisedBB);
break;
case X86::XORPDrm:
case X86::XORPSrm:
Result = BinaryOperator::CreateXor(DestValueInt, LoadValueInt, "", RaisedBB);
break;
default:
llvm_unreachable("Unhandled opcode for packed bitwise instruction");
}
// Cast back to operand type
BinOpInst = new BitCastInst(Result, DestopTy);
} break;
case X86::PANDrm: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
BinOpInst = BinaryOperator::CreateAnd(DestValue, LoadValue);
} break;
case X86::PANDNrm: {
DestValue = BinaryOperator::CreateNot(DestValue, "", RaisedBB);
BinOpInst = BinaryOperator::CreateAnd(DestValue, LoadValue);
} break;
case X86::PORrm: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
BinOpInst = BinaryOperator::CreateOr(DestValue, LoadValue);
} break;
case X86::PXORrm: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
BinOpInst = BinaryOperator::CreateXor(DestValue, LoadValue);
} break;
case X86::SBB16rm:
case X86::SBB32rm:
case X86::SBB64rm:
case X86::SBB8rm: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
auto CFValue = getRegOrArgValue(EFLAGS::CF, MI.getParent()->getNumber());
assert(CFValue && "Expected CF to be set for sbb instruction");
auto CFExtended = CastInst::Create(Instruction::ZExt, CFValue,
LoadValue->getType(), "", RaisedBB);
auto LoadAndCFValue =
BinaryOperator::CreateAdd(LoadValue, CFExtended, "", RaisedBB);
BinOpInst = BinaryOperator::CreateSub(DestValue, LoadAndCFValue);
AffectedEFlags.insert(EFLAGS::OF);
AffectedEFlags.insert(EFLAGS::CF);
} break;
case X86::SQRTSDm:
case X86::SQRTSDm_Int:
case X86::SQRTSSm:
case X86::SQRTSSm_Int: {
assert(DestValue != nullptr && "Encountered instruction with undefined register");
LLVMContext &Ctx(MF.getFunction().getContext());
Type *InstrTy = getRaisedValues()->getSSEInstructionType(MI, Ctx);
assert(LoadValue->getType() == InstrTy &&
"Unexpected value type for sqrtsd/sqrtss instruction");
Module *M = MR->getModule();
auto IntrinsicFunc = Intrinsic::getDeclaration(M, Intrinsic::sqrt, InstrTy);
Value *IntrinsicCallArgs[] = {LoadValue};
BinOpInst = CallInst::Create(
IntrinsicFunc, ArrayRef<Value *>(IntrinsicCallArgs));
} break;
default:
assert(false && "Unhandled binary op mem to reg instruction ");
}
// Add instruction to block
getRaisedValues()->setInstMetadataRODataIndex(LoadValue, BinOpInst);
RaisedBB->getInstList().push_back(BinOpInst);
// Clear EFLAGS if any
int MMBNo = MI.getParent()->getNumber();
for (auto F : ClearedEFlags)
raisedValues->setEflagBoolean(F, MMBNo, false);
// Test and set affected flags
for (auto Flag : AffectedEFlags)
raisedValues->testAndSetEflagSSAValue(Flag, MI, BinOpInst);
// Update PhysReg to Value map
raisedValues->setPhysRegSSAValue(DestPReg, MI.getParent()->getNumber(),
BinOpInst);
return true;
}