forked from OSchip/llvm-project
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:
parent
2dc08f7df8
commit
ad2b717f2c
|
@ -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();
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue