GlobalISel: add generic load and store instructions.
authorTim Northover <tnorthover@apple.com>
Tue, 26 Jul 2016 20:23:26 +0000 (20:23 +0000)
committerTim Northover <tnorthover@apple.com>
Tue, 26 Jul 2016 20:23:26 +0000 (20:23 +0000)
Pretty straightforward, the only oddity is the MachineMemOperand (which it's
surprisingly difficult to share code for).

llvm-svn: 276799

llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
llvm/include/llvm/Target/GenericOpcodes.td
llvm/include/llvm/Target/TargetOpcodes.def
llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
llvm/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll

index 656e327..d539607 100644 (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();
index df52127..795b813 100644 (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],
index 0f846e7..615c63e 100644 (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);
@@ -77,6 +77,26 @@ def G_OR : Instruction {
 }
 
 //------------------------------------------------------------------------------
+// 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
 //------------------------------------------------------------------------------
 
index 6166877..bc52fe0 100644 (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)
 
index 9ce7fe4..6a8712e 100644 (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));
 
index 30971e7..be4cafc 100644 (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) {
index 2ea360c..ac2e744 100644 (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
+}