GlobalISel: add generic load and store instructions.

Pretty straightforward, the only oddity is the MachineMemOperand (which it's
surprisingly difficult to share code for).

llvm-svn: 276799
This commit is contained in:
Tim Northover 2016-07-26 20:23:26 +00:00
parent 2dc08f7df8
commit ad2b717f2c
7 changed files with 162 additions and 1 deletions

View File

@ -97,6 +97,12 @@ private:
/// emitted.
bool translateBitCast(const CastInst &CI);
/// Translate an LLVM load instruction into generic IR.
bool translateLoad(const LoadInst &LI);
/// Translate an LLVM store instruction into generic IR.
bool translateStore(const StoreInst &SI);
/// Translate one of LLVM's cast instructions into MachineInstrs, with the
/// given generic Opcode.
bool translateCast(unsigned Opcode, const CastInst &CI);
@ -141,10 +147,16 @@ private:
/// If such VReg does not exist, it is created.
unsigned getOrCreateVReg(const Value &Val);
/// Get the alignment of the given memory operation instruction. This will
/// either be the explicitly specified value or the ABI-required alignment for
/// the type being accessed (according to the Module's DataLayout).
unsigned getMemOpAlignment(const Instruction &I);
/// Get the MachineBasicBlock that represents \p BB.
/// If such basic block does not exist, it is created.
MachineBasicBlock &getOrCreateBB(const BasicBlock &BB);
public:
// Ctor, nothing fancy.
IRTranslator();

View File

@ -192,6 +192,28 @@ public:
/// \return The newly created instruction.
MachineInstr *buildCopy(unsigned Res, unsigned Op);
/// Build and insert `Res<def> = G_LOAD { VTy, PTy } Addr, MMO`.
///
/// Loads the value of (sized) type \p VTy stored at \p Addr (in address space
/// given by \p PTy). Puts the result in Res.
///
/// \pre setBasicBlock or setMI must have been called.
///
/// \return The newly created instruction.
MachineInstr *buildLoad(LLT VTy, LLT PTy, unsigned Res, unsigned Addr,
MachineMemOperand &MMO);
/// Build and insert `G_STORE { VTy, PTy } Val, Addr, MMO`.
///
/// Stores the value \p Val of (sized) \p VTy to \p Addr (in address space
/// given by \p PTy).
///
/// \pre setBasicBlock or setMI must have been called.
///
/// \return The newly created instruction.
MachineInstr *buildStore(LLT VTy, LLT PTy, unsigned Val, unsigned Addr,
MachineMemOperand &MMO);
/// Build and insert `Res0<def>, ... = G_EXTRACT Ty Src, Idx0, ...`.
///
/// If \p Ty has size N bits, G_EXTRACT sets \p Res[0] to bits `[Idxs[0],

View File

@ -40,10 +40,10 @@ def G_BITCAST : Instruction {
let hasSideEffects = 0;
}
//------------------------------------------------------------------------------
// Binary ops.
//------------------------------------------------------------------------------
// Generic addition.
def G_ADD : Instruction {
let OutOperandList = (outs unknown:$dst);
@ -76,6 +76,26 @@ def G_OR : Instruction {
let isCommutable = 1;
}
//------------------------------------------------------------------------------
// Memory ops
//------------------------------------------------------------------------------
// Generic load. Expects a MachineMemOperand in addition to explicit operands.
def G_LOAD : Instruction {
let OutOperandList = (outs unknown:$dst);
let InOperandList = (ins unknown:$addr);
let hasSideEffects = 0;
let mayLoad = 1;
}
// Generic store. Expects a MachineMemOperand in addition to explicit operands.
def G_STORE : Instruction {
let OutOperandList = (outs);
let InOperandList = (ins unknown:$src, unknown:$addr);
let hasSideEffects = 0;
let mayStore = 1;
}
//------------------------------------------------------------------------------
// Variadic ops
//------------------------------------------------------------------------------

View File

@ -190,6 +190,12 @@ HANDLE_TARGET_OPCODE(G_INTTOPTR)
/// COPY is the relevant instruction.
HANDLE_TARGET_OPCODE(G_BITCAST)
/// Generic load.
HANDLE_TARGET_OPCODE(G_LOAD)
/// Generic store.
HANDLE_TARGET_OPCODE(G_STORE)
/// Generic BRANCH instruction. This is an unconditional branch.
HANDLE_TARGET_OPCODE(G_BR)

View File

@ -52,6 +52,21 @@ unsigned IRTranslator::getOrCreateVReg(const Value &Val) {
return ValReg;
}
unsigned IRTranslator::getMemOpAlignment(const Instruction &I) {
unsigned Alignment = 0;
Type *ValTy = nullptr;
if (const StoreInst *SI = dyn_cast<StoreInst>(&I)) {
Alignment = SI->getAlignment();
ValTy = SI->getValueOperand()->getType();
} else if (const LoadInst *LI = dyn_cast<LoadInst>(&I)) {
Alignment = LI->getAlignment();
ValTy = LI->getType();
} else
llvm_unreachable("unhandled memory instruction");
return Alignment ? Alignment : DL->getABITypeAlignment(ValTy);
}
MachineBasicBlock &IRTranslator::getOrCreateBB(const BasicBlock &BB) {
MachineBasicBlock *&MBB = BBToMBB[&BB];
if (!MBB) {
@ -100,6 +115,39 @@ bool IRTranslator::translateBr(const Instruction &Inst) {
return true;
}
bool IRTranslator::translateLoad(const LoadInst &LI) {
assert(LI.isSimple() && "only simple loads are supported at the moment");
MachineFunction &MF = MIRBuilder.getMF();
unsigned Res = getOrCreateVReg(LI);
unsigned Addr = getOrCreateVReg(*LI.getPointerOperand());
LLT VTy{*LI.getType()}, PTy{*LI.getPointerOperand()->getType()};
MIRBuilder.buildLoad(
VTy, PTy, Res, Addr,
*MF.getMachineMemOperand(MachinePointerInfo(LI.getPointerOperand()),
MachineMemOperand::MOLoad,
VTy.getSizeInBits() / 8, getMemOpAlignment(LI)));
return true;
}
bool IRTranslator::translateStore(const StoreInst &SI) {
assert(SI.isSimple() && "only simple loads are supported at the moment");
MachineFunction &MF = MIRBuilder.getMF();
unsigned Val = getOrCreateVReg(*SI.getValueOperand());
unsigned Addr = getOrCreateVReg(*SI.getPointerOperand());
LLT VTy{*SI.getValueOperand()->getType()},
PTy{*SI.getPointerOperand()->getType()};
MIRBuilder.buildStore(
VTy, PTy, Val, Addr,
*MF.getMachineMemOperand(MachinePointerInfo(SI.getPointerOperand()),
MachineMemOperand::MOStore,
VTy.getSizeInBits() / 8, getMemOpAlignment(SI)));
return true;
}
bool IRTranslator::translateBitCast(const CastInst &CI) {
if (LLT{*CI.getDestTy()} == LLT{*CI.getSrcTy()}) {
MIRBuilder.buildCopy(getOrCreateVReg(CI),
@ -163,6 +211,12 @@ bool IRTranslator::translate(const Instruction &Inst) {
case Instruction::PtrToInt:
return translateCast(TargetOpcode::G_PTRTOINT, cast<CastInst>(Inst));
// Memory ops.
case Instruction::Load:
return translateLoad(cast<LoadInst>(Inst));
case Instruction::Store:
return translateStore(cast<StoreInst>(Inst));
case Instruction::Alloca:
return translateStaticAlloca(cast<AllocaInst>(Inst));

View File

@ -94,6 +94,23 @@ MachineInstr *MachineIRBuilder::buildCopy(unsigned Res, unsigned Op) {
return buildInstr(TargetOpcode::COPY, Res, Op);
}
MachineInstr *MachineIRBuilder::buildLoad(LLT VTy, LLT PTy, unsigned Res,
unsigned Addr,
MachineMemOperand &MMO) {
MachineInstr *NewMI = buildInstr(TargetOpcode::G_LOAD, {VTy, PTy}, Res, Addr);
NewMI->addMemOperand(getMF(), &MMO);
return NewMI;
}
MachineInstr *MachineIRBuilder::buildStore(LLT VTy, LLT PTy, unsigned Val,
unsigned Addr,
MachineMemOperand &MMO) {
MachineInstr *NewMI = buildInstr(TargetOpcode::G_STORE, {VTy, PTy});
NewMI->addMemOperand(getMF(), &MMO);
MachineInstrBuilder(getMF(), NewMI).addReg(Val).addReg(Addr);
return NewMI;
}
MachineInstr *MachineIRBuilder::buildExtract(LLT Ty, ArrayRef<unsigned> Results,
unsigned Src,
ArrayRef<unsigned> Indexes) {

View File

@ -165,3 +165,33 @@ define i64 @bitcast(i64 %a) {
%res2 = bitcast <2 x i32> %res1 to i64
ret i64 %res2
}
; CHECK-LABEL: name: load
; CHECK: [[ADDR:%[0-9]+]](64) = COPY %x0
; CHECK: [[ADDR42:%[0-9]+]](64) = COPY %x1
; CHECK: [[VAL1:%[0-9]+]](64) = G_LOAD { s64, p0 } [[ADDR]] :: (load 8 from %ir.addr, align 16)
; CHECK: [[VAL2:%[0-9]+]](64) = G_LOAD { s64, p42 } [[ADDR42]] :: (load 8 from %ir.addr42)
; CHECK: [[SUM:%.*]](64) = G_ADD s64 [[VAL1]], [[VAL2]]
; CHECK: %x0 = COPY [[SUM]]
; CHECK: RET_ReallyLR implicit %x0
define i64 @load(i64* %addr, i64 addrspace(42)* %addr42) {
%val1 = load i64, i64* %addr, align 16
%val2 = load i64, i64 addrspace(42)* %addr42
%sum = add i64 %val1, %val2
ret i64 %sum
}
; CHECK-LABEL: name: store
; CHECK: [[ADDR:%[0-9]+]](64) = COPY %x0
; CHECK: [[ADDR42:%[0-9]+]](64) = COPY %x1
; CHECK: [[VAL1:%[0-9]+]](64) = COPY %x2
; CHECK: [[VAL2:%[0-9]+]](64) = COPY %x3
; CHECK: G_STORE { s64, p0 } [[VAL1]], [[ADDR]] :: (store 8 into %ir.addr, align 16)
; CHECK: G_STORE { s64, p42 } [[VAL2]], [[ADDR42]] :: (store 8 into %ir.addr42)
; CHECK: RET_ReallyLR
define void @store(i64* %addr, i64 addrspace(42)* %addr42, i64 %val1, i64 %val2) {
store i64 %val1, i64* %addr, align 16
store i64 %val2, i64 addrspace(42)* %addr42
%sum = add i64 %val1, %val2
ret void
}