in X86/X86MachineInstructionRaiser.cpp [2211:2486]
bool X86MachineInstructionRaiser::raiseMoveToMemInstr(const MachineInstr &MI,
Value *MemRefVal) {
unsigned int SrcOpIndex = getMemoryRefOpIndex(MI) + X86::AddrNumOperands;
// If the source operand is neither an immediate or a register, check for an
// implicit register use
if (!MI.getOperand(SrcOpIndex).isImm() && !MI.getOperand(SrcOpIndex).isReg()) {
MCInstrDesc Desc = MI.getDesc();
assert(Desc.getNumImplicitUses() == 1 && "Expected one implicit use");
for (unsigned int i = SrcOpIndex + 1; i < MI.getNumOperands(); ++i) {
if (MI.getOperand(i).isUse() && MI.getOperand(i).isReg()) {
SrcOpIndex = i;
break;
}
}
}
const MachineOperand &SrcOp = MI.getOperand(SrcOpIndex);
// Is this a mov instruction?
bool isMovInst = instrNameStartsWith(MI, "MOV");
assert((SrcOp.isImm() || SrcOp.isReg()) &&
"Register or immediate value source expected in a move to mem "
"instruction");
// Get the BasicBlock corresponding to MachineBasicBlock of MI.
// Raised instruction is added to this BasicBlock.
BasicBlock *RaisedBB = getRaisedBasicBlock(MI.getParent());
Value *SrcValue = nullptr;
Type *SrcOpTy = nullptr;
// If Source op is immediate, create a constant int value
// of type memory location.
if (SrcOp.isImm()) {
SrcOpTy = getImmOperandType(MI, SrcOpIndex);
int64_t SrcImm = SrcOp.getImm();
if (isMovInst) {
if (SrcImm > 0) {
// Check if the immediate value corresponds to a global variable.
Value *GV = getGlobalVariableValueAt(MI, SrcImm);
if (GV != nullptr)
SrcValue = GV;
else {
SrcValue = ConstantInt::get(SrcOpTy, SrcImm);
}
} else
SrcValue = ConstantInt::get(SrcOpTy, SrcImm);
} else
SrcValue = ConstantInt::get(SrcOpTy, SrcImm);
} else {
// If it is not an immediate value, get source value
SrcValue = getRegOperandValue(MI, SrcOpIndex);
SrcOpTy = getPhysRegOperandType(MI, SrcOpIndex);
}
assert(SrcValue != nullptr &&
"Unable to get source value while raising move to mem instruction");
// Load the value from memory location of memRefValue.
// memRefVal is either an AllocaInst (stack access) or GlobalValue (global
// data access) or an effective address value.
assert((isa<AllocaInst>(MemRefVal) || isEffectiveAddrValue(MemRefVal) ||
isa<GlobalValue>(MemRefVal) || isa<GetElementPtrInst>(MemRefVal) ||
MemRefVal->getType()->isPointerTy()) &&
"Unexpected type of memory reference in mem-to-reg instruction");
// If memory reference is not a pointer type, cast it to a pointer
Type *DstMemTy = MemRefVal->getType();
LLVMContext &Ctx(MF.getFunction().getContext());
if (!DstMemTy->isPointerTy()) {
// Cast it as pointer to SrcOpTy
PointerType *PtrTy = nullptr;
auto Opc = MI.getOpcode();
auto MemSzInBits = getInstructionMemOpSize(Opc) * 8;
if (isSSE2Instruction(Opc)) {
PtrTy = getRaisedValues()->getSSEInstructionType(MI, Ctx)->getPointerTo();
} else {
assert(MemSzInBits > 0 && "Unexpected memory access size of instruction");
PtrTy = Type::getIntNPtrTy(Ctx, MemSzInBits);
}
IntToPtrInst *convIntToPtr = new IntToPtrInst(MemRefVal, PtrTy);
RaisedBB->getInstList().push_back(convIntToPtr);
MemRefVal = convIntToPtr;
}
// This instruction moves a source value to memory. So, if the types of
// the source value and that of the memory pointer element are not the
// same as that of the store size of the instruction, cast them as needed.
unsigned int memSzInBits = getInstructionMemOpSize(MI.getOpcode()) * 8;
// Consider store value type to be the same as source value type, by default.
Type *StoreTy = SrcValue->getType();
if (SrcValue->getType()->isIntegerTy())
StoreTy = Type::getIntNTy(Ctx, memSzInBits);
else if (SrcValue->getType()->isFloatingPointTy()) {
if (memSzInBits == 32)
StoreTy = Type::getFloatTy(Ctx);
else if (memSzInBits == 64)
StoreTy = Type::getDoubleTy(Ctx);
}
bool SignExtend = MI.getOpcode() == X86::MOV64mi32;
// Cast SrcValue and MemRefVal as needed.
MemRefVal = getRaisedValues()->castValue(MemRefVal, StoreTy->getPointerTo(),
RaisedBB);
SrcValue = getRaisedValues()->castValue(SrcValue, StoreTy, RaisedBB, SignExtend);
if (!isMovInst) {
// If this is not an instruction that just moves SrcValue, load from memory,
// generate the instruction that performs the appropriate operation.
// Load the value from memory location
auto align =
MemRefVal->getPointerAlignment(MR->getModule()->getDataLayout());
LoadInst *LdInst =
new LoadInst(MemRefVal->getType()->getPointerElementType(), MemRefVal,
"", false, align, RaisedBB);
assert((LdInst != nullptr) && "Memory value expected to be loaded while "
"raising binary mem op instruction");
assert((SrcValue != nullptr) && "Source value expected to be loaded while "
"raising binary mem op instruction");
std::set<unsigned> AffectedEFlags;
Instruction *BinOpInst = nullptr;
// Generate instruction to perform appropriate operation to produce the
// value be stored.
switch (MI.getOpcode()) {
case X86::ADD8mi:
case X86::ADD8mi8:
case X86::ADD8mr:
case X86::ADD16mi:
case X86::ADD16mi8:
case X86::ADD16mr:
case X86::ADD32mi:
case X86::ADD32mi8:
case X86::ADD32mr:
case X86::ADD64mi8:
case X86::ADD64i32:
case X86::ADD64mr:
case X86::INC8m:
case X86::INC16m:
case X86::INC32m:
case X86::INC64m: {
// Generate Add instruction
BinOpInst = BinaryOperator::CreateAdd(LdInst, SrcValue);
AffectedEFlags.insert(EFLAGS::PF);
} break;
case X86::AND8mi:
case X86::AND8mi8:
case X86::AND8mr:
case X86::AND16mi:
case X86::AND16mi8:
case X86::AND16mr:
case X86::AND32mi:
case X86::AND32mi8:
case X86::AND32mr:
case X86::AND64mi8:
case X86::AND64mi32:
case X86::AND64mr: {
BinOpInst = BinaryOperator::CreateAnd(LdInst, SrcValue);
AffectedEFlags.insert(EFLAGS::PF);
} break;
case X86::OR8mi:
case X86::OR8mi8:
case X86::OR8mr:
case X86::OR16mi:
case X86::OR16mi8:
case X86::OR16mr:
case X86::OR32mi:
case X86::OR32mi8:
case X86::OR32mr:
case X86::OR64mi8:
case X86::OR64mi32:
case X86::OR64mr: {
BinOpInst = BinaryOperator::CreateOr(LdInst, SrcValue);
AffectedEFlags.insert(EFLAGS::PF);
} break;
case X86::XOR8mi:
case X86::XOR8mi8:
case X86::XOR8mr:
case X86::XOR16mi:
case X86::XOR16mi8:
case X86::XOR16mr:
case X86::XOR32mi:
case X86::XOR32mi8:
case X86::XOR32mr:
case X86::XOR64mi8:
case X86::XOR64mi32:
case X86::XOR64mr: {
BinOpInst = BinaryOperator::CreateXor(LdInst, SrcValue);
AffectedEFlags.insert(EFLAGS::PF);
} break;
case X86::DEC8m:
case X86::DEC16m:
case X86::DEC32m:
case X86::DEC64m: {
BinOpInst = BinaryOperator::CreateSub(LdInst, SrcValue);
AffectedEFlags.insert(EFLAGS::PF);
} break;
case X86::SAR8mCL:
case X86::SAR16mCL:
case X86::SAR32mCL:
case X86::SAR64mCL:
case X86::SHL8mCL:
case X86::SHL16mCL:
case X86::SHL32mCL:
case X86::SHL64mCL:
case X86::SHR8mCL:
case X86::SHR16mCL:
case X86::SHR32mCL:
case X86::SHR64mCL: {
Type *LdInstTy = LdInst->getType();
// SrcValue is masked to 5 bits (6 bits if 64-bit register)
bool Is64Bit = (LdInstTy->getPrimitiveSizeInBits() == 64);
Value *CountMask = Is64Bit ? ConstantInt::get(LdInstTy, 0x1f)
: ConstantInt::get(LdInstTy, 0x3f);
// Generate mask
auto CountValue = BinaryOperator::CreateAnd(SrcValue, CountMask,
"shift-cnt-msk", RaisedBB);
if (instrNameStartsWith(MI, "SAR")) {
BinOpInst =
BinaryOperator::CreateAShr(LdInst, CountValue);
} else if (instrNameStartsWith(MI, "SHL")) {
BinOpInst =
BinaryOperator::CreateShl(LdInst, CountValue);
} else if (instrNameStartsWith(MI, "SHR")) {
BinOpInst =
BinaryOperator::CreateLShr(LdInst, CountValue);
} else {
llvm_unreachable("unhandled shift instruction");
}
} break;
case X86::SAR8mi:
case X86::SAR16mi:
case X86::SAR32mi:
case X86::SAR64mi: {
BinOpInst = BinaryOperator::CreateLShr(LdInst, SrcValue);
} break;
case X86::SHL8mi:
case X86::SHL16mi:
case X86::SHL32mi:
case X86::SHL64mi: {
BinOpInst = BinaryOperator::CreateShl(LdInst, SrcValue);
} break;
case X86::SHR8mi:
case X86::SHR16mi:
case X86::SHR32mi:
case X86::SHR64mi: {
BinOpInst = BinaryOperator::CreateLShr(LdInst, SrcValue);
} break;
default:
assert(false && "Unhandled non-move mem op instruction");
}
RaisedBB->getInstList().push_back(BinOpInst);
SrcValue = BinOpInst;
// Test and set affected flags
for (auto Flag : AffectedEFlags)
raisedValues->testAndSetEflagSSAValue(Flag, MI, BinOpInst);
}
assert((SrcValue != nullptr) && "Unexpected null value to be stored while "
"raising binary mem op instruction");
// Store resultant value
new StoreInst(SrcValue, MemRefVal, false, Align(), RaisedBB);
return true;
}