From ad2b717f2c8fcc279cf13aa51349012c3710c987 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Tue, 26 Jul 2016 20:23:26 +0000 Subject: [PATCH] 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 --- .../llvm/CodeGen/GlobalISel/IRTranslator.h | 12 +++++ .../CodeGen/GlobalISel/MachineIRBuilder.h | 22 ++++++++ llvm/include/llvm/Target/GenericOpcodes.td | 22 +++++++- llvm/include/llvm/Target/TargetOpcodes.def | 6 +++ llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 54 +++++++++++++++++++ .../CodeGen/GlobalISel/MachineIRBuilder.cpp | 17 ++++++ .../AArch64/GlobalISel/arm64-irtranslator.ll | 30 +++++++++++ 7 files changed, 162 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h index 656e327fedce..d539607ce709 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -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(); diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index df52127087a0..795b813d4277 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -192,6 +192,28 @@ public: /// \return The newly created instruction. MachineInstr *buildCopy(unsigned Res, unsigned Op); + /// Build and insert `Res = 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, ... = G_EXTRACT Ty Src, Idx0, ...`. /// /// If \p Ty has size N bits, G_EXTRACT sets \p Res[0] to bits `[Idxs[0], diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index 0f846e743c3e..615c63e8df00 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -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 //------------------------------------------------------------------------------ diff --git a/llvm/include/llvm/Target/TargetOpcodes.def b/llvm/include/llvm/Target/TargetOpcodes.def index 616687703292..bc52fe0c84c8 100644 --- a/llvm/include/llvm/Target/TargetOpcodes.def +++ b/llvm/include/llvm/Target/TargetOpcodes.def @@ -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) diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 9ce7fe4a2ccb..6a8712e184b3 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -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(&I)) { + Alignment = SI->getAlignment(); + ValTy = SI->getValueOperand()->getType(); + } else if (const LoadInst *LI = dyn_cast(&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(Inst)); + // Memory ops. + case Instruction::Load: + return translateLoad(cast(Inst)); + case Instruction::Store: + return translateStore(cast(Inst)); + case Instruction::Alloca: return translateStaticAlloca(cast(Inst)); diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 30971e72f7d9..be4cafc575bf 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -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 Results, unsigned Src, ArrayRef Indexes) { diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll index 2ea360cf0be0..ac2e744426b2 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll @@ -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 +}