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.
|
/// emitted.
|
||||||
bool translateBitCast(const CastInst &CI);
|
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
|
/// Translate one of LLVM's cast instructions into MachineInstrs, with the
|
||||||
/// given generic Opcode.
|
/// given generic Opcode.
|
||||||
bool translateCast(unsigned Opcode, const CastInst &CI);
|
bool translateCast(unsigned Opcode, const CastInst &CI);
|
||||||
|
@ -141,10 +147,16 @@ private:
|
||||||
/// If such VReg does not exist, it is created.
|
/// If such VReg does not exist, it is created.
|
||||||
unsigned getOrCreateVReg(const Value &Val);
|
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.
|
/// Get the MachineBasicBlock that represents \p BB.
|
||||||
/// If such basic block does not exist, it is created.
|
/// If such basic block does not exist, it is created.
|
||||||
MachineBasicBlock &getOrCreateBB(const BasicBlock &BB);
|
MachineBasicBlock &getOrCreateBB(const BasicBlock &BB);
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Ctor, nothing fancy.
|
// Ctor, nothing fancy.
|
||||||
IRTranslator();
|
IRTranslator();
|
||||||
|
|
|
@ -192,6 +192,28 @@ public:
|
||||||
/// \return The newly created instruction.
|
/// \return The newly created instruction.
|
||||||
MachineInstr *buildCopy(unsigned Res, unsigned Op);
|
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, ...`.
|
/// 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],
|
/// 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;
|
let hasSideEffects = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Binary ops.
|
// Binary ops.
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Generic addition.
|
// Generic addition.
|
||||||
def G_ADD : Instruction {
|
def G_ADD : Instruction {
|
||||||
let OutOperandList = (outs unknown:$dst);
|
let OutOperandList = (outs unknown:$dst);
|
||||||
|
@ -76,6 +76,26 @@ def G_OR : Instruction {
|
||||||
let isCommutable = 1;
|
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
|
// Variadic ops
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
|
@ -190,6 +190,12 @@ HANDLE_TARGET_OPCODE(G_INTTOPTR)
|
||||||
/// COPY is the relevant instruction.
|
/// COPY is the relevant instruction.
|
||||||
HANDLE_TARGET_OPCODE(G_BITCAST)
|
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.
|
/// Generic BRANCH instruction. This is an unconditional branch.
|
||||||
HANDLE_TARGET_OPCODE(G_BR)
|
HANDLE_TARGET_OPCODE(G_BR)
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,21 @@ unsigned IRTranslator::getOrCreateVReg(const Value &Val) {
|
||||||
return ValReg;
|
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 &IRTranslator::getOrCreateBB(const BasicBlock &BB) {
|
||||||
MachineBasicBlock *&MBB = BBToMBB[&BB];
|
MachineBasicBlock *&MBB = BBToMBB[&BB];
|
||||||
if (!MBB) {
|
if (!MBB) {
|
||||||
|
@ -100,6 +115,39 @@ bool IRTranslator::translateBr(const Instruction &Inst) {
|
||||||
return true;
|
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) {
|
bool IRTranslator::translateBitCast(const CastInst &CI) {
|
||||||
if (LLT{*CI.getDestTy()} == LLT{*CI.getSrcTy()}) {
|
if (LLT{*CI.getDestTy()} == LLT{*CI.getSrcTy()}) {
|
||||||
MIRBuilder.buildCopy(getOrCreateVReg(CI),
|
MIRBuilder.buildCopy(getOrCreateVReg(CI),
|
||||||
|
@ -163,6 +211,12 @@ bool IRTranslator::translate(const Instruction &Inst) {
|
||||||
case Instruction::PtrToInt:
|
case Instruction::PtrToInt:
|
||||||
return translateCast(TargetOpcode::G_PTRTOINT, cast<CastInst>(Inst));
|
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:
|
case Instruction::Alloca:
|
||||||
return translateStaticAlloca(cast<AllocaInst>(Inst));
|
return translateStaticAlloca(cast<AllocaInst>(Inst));
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,23 @@ MachineInstr *MachineIRBuilder::buildCopy(unsigned Res, unsigned Op) {
|
||||||
return buildInstr(TargetOpcode::COPY, Res, 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,
|
MachineInstr *MachineIRBuilder::buildExtract(LLT Ty, ArrayRef<unsigned> Results,
|
||||||
unsigned Src,
|
unsigned Src,
|
||||||
ArrayRef<unsigned> Indexes) {
|
ArrayRef<unsigned> Indexes) {
|
||||||
|
|
|
@ -165,3 +165,33 @@ define i64 @bitcast(i64 %a) {
|
||||||
%res2 = bitcast <2 x i32> %res1 to i64
|
%res2 = bitcast <2 x i32> %res1 to i64
|
||||||
ret i64 %res2
|
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