]> granicus.if.org Git - llvm/commitdiff
[RISCV] Codegen support for memory operations
authorAlex Bradbury <asb@lowrisc.org>
Wed, 8 Nov 2017 12:20:01 +0000 (12:20 +0000)
committerAlex Bradbury <asb@lowrisc.org>
Wed, 8 Nov 2017 12:20:01 +0000 (12:20 +0000)
This required the implementation of RISCVTargetInstrInfo::copyPhysReg. Support
for lowering global addresses follow in the next patch.

Differential Revision: https://reviews.llvm.org/D29934

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317685 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/RISCV/RISCVISelLowering.cpp
lib/Target/RISCV/RISCVInstrInfo.cpp
lib/Target/RISCV/RISCVInstrInfo.h
lib/Target/RISCV/RISCVInstrInfo.td
test/CodeGen/RISCV/mem.ll [new file with mode: 0644]
test/CodeGen/RISCV/wide-mem.ll [new file with mode: 0644]

index d76170b7b78767ca083e3dd72ef7a3fda52d5ff0..70e33a25941c051078b1be38a82fdb50688d5cbf 100644 (file)
@@ -49,6 +49,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
 
   setStackPointerRegisterToSaveRestore(RISCV::X2);
 
+  for (auto N : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD})
+    setLoadExtAction(N, XLenVT, MVT::i1, Promote);
+
   // TODO: add all necessary setOperationAction calls.
 
   setBooleanContents(ZeroOrOneBooleanContent);
index 92db5358ce4d02c390897e734e1188b24828844d..ebb7174002d18f0e4259a7e286aba9af4ec039c8 100644 (file)
 using namespace llvm;
 
 RISCVInstrInfo::RISCVInstrInfo() : RISCVGenInstrInfo() {}
+
+void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
+                                 MachineBasicBlock::iterator MBBI,
+                                 const DebugLoc &DL, unsigned DstReg,
+                                 unsigned SrcReg, bool KillSrc) const {
+  assert(RISCV::GPRRegClass.contains(DstReg, SrcReg) &&
+         "Impossible reg-to-reg copy");
+
+  BuildMI(MBB, MBBI, DL, get(RISCV::ADDI), DstReg)
+      .addReg(SrcReg, getKillRegState(KillSrc))
+      .addImm(0);
+}
index 0b3cd4d2ed15ca278ab21d88a72273e4d83c32df..8f0c2c4f7eb3580300b2d2f181c9f13edc607441 100644 (file)
@@ -26,6 +26,10 @@ class RISCVInstrInfo : public RISCVGenInstrInfo {
 
 public:
   RISCVInstrInfo();
+
+  void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+                   const DebugLoc &DL, unsigned DstReg, unsigned SrcReg,
+                   bool KillSrc) const override;
 };
 }
 
index a19a636bdece215f61419ed37dd1ecc667fe3634..7dfdd5b044dee686f20f8682002873d082324047 100644 (file)
@@ -311,3 +311,31 @@ def : PatGprSimm12<setult, SLTIU>;
 let isBarrier = 1, isReturn = 1, isTerminator = 1 in
 def PseudoRET : Pseudo<(outs), (ins), [(RetFlag)]>,
                 PseudoInstExpansion<(JALR X0, X1, 0)>;
+
+/// Loads
+
+multiclass LdPat<PatFrag LoadOp, RVInst Inst> {
+  def : Pat<(LoadOp GPR:$rs1), (Inst GPR:$rs1, 0)>;
+  def : Pat<(LoadOp (add GPR:$rs1, simm12:$imm12)),
+            (Inst GPR:$rs1, simm12:$imm12)>;
+}
+
+defm : LdPat<sextloadi8, LB>;
+defm : LdPat<extloadi8, LB>;
+defm : LdPat<sextloadi16, LH>;
+defm : LdPat<extloadi16, LH>;
+defm : LdPat<load, LW>;
+defm : LdPat<zextloadi8, LBU>;
+defm : LdPat<zextloadi16, LHU>;
+
+/// Stores
+
+multiclass StPat<PatFrag StoreOp, RVInst Inst> {
+  def : Pat<(StoreOp GPR:$rs2, GPR:$rs1), (Inst GPR:$rs2, GPR:$rs1, 0)>;
+  def : Pat<(StoreOp GPR:$rs2, (add GPR:$rs1, simm12:$imm12)),
+            (Inst GPR:$rs2, GPR:$rs1, simm12:$imm12)>;
+}
+
+defm : StPat<truncstorei8, SB>;
+defm : StPat<truncstorei16, SH>;
+defm : StPat<store, SW>;
diff --git a/test/CodeGen/RISCV/mem.ll b/test/CodeGen/RISCV/mem.ll
new file mode 100644 (file)
index 0000000..ef3c376
--- /dev/null
@@ -0,0 +1,177 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV32I
+
+; Check indexed and unindexed, sext, zext and anyext loads
+
+define i32 @lb(i8 *%a) nounwind {
+; RV32I-LABEL: lb:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    lb a1, 0(a0)
+; RV32I-NEXT:    lb a0, 1(a0)
+; RV32I-NEXT:    jalr zero, ra, 0
+  %1 = getelementptr i8, i8* %a, i32 1
+  %2 = load i8, i8* %1
+  %3 = sext i8 %2 to i32
+  ; the unused load will produce an anyext for selection
+  %4 = load volatile i8, i8* %a
+  ret i32 %3
+}
+
+define i32 @lh(i16 *%a) nounwind {
+; RV32I-LABEL: lh:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    lh a1, 0(a0)
+; RV32I-NEXT:    lh a0, 4(a0)
+; RV32I-NEXT:    jalr zero, ra, 0
+  %1 = getelementptr i16, i16* %a, i32 2
+  %2 = load i16, i16* %1
+  %3 = sext i16 %2 to i32
+  ; the unused load will produce an anyext for selection
+  %4 = load volatile i16, i16* %a
+  ret i32 %3
+}
+
+define i32 @lw(i32 *%a) nounwind {
+; RV32I-LABEL: lw:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    lw a1, 0(a0)
+; RV32I-NEXT:    lw a0, 12(a0)
+; RV32I-NEXT:    jalr zero, ra, 0
+  %1 = getelementptr i32, i32* %a, i32 3
+  %2 = load i32, i32* %1
+  %3 = load volatile i32, i32* %a
+  ret i32 %2
+}
+
+define i32 @lbu(i8 *%a) nounwind {
+; RV32I-LABEL: lbu:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    lbu a1, 0(a0)
+; RV32I-NEXT:    lbu a0, 4(a0)
+; RV32I-NEXT:    add a0, a0, a1
+; RV32I-NEXT:    jalr zero, ra, 0
+  %1 = getelementptr i8, i8* %a, i32 4
+  %2 = load i8, i8* %1
+  %3 = zext i8 %2 to i32
+  %4 = load volatile i8, i8* %a
+  %5 = zext i8 %4 to i32
+  %6 = add i32 %3, %5
+  ret i32 %6
+}
+
+define i32 @lhu(i16 *%a) nounwind {
+; RV32I-LABEL: lhu:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    lhu a1, 0(a0)
+; RV32I-NEXT:    lhu a0, 10(a0)
+; RV32I-NEXT:    add a0, a0, a1
+; RV32I-NEXT:    jalr zero, ra, 0
+  %1 = getelementptr i16, i16* %a, i32 5
+  %2 = load i16, i16* %1
+  %3 = zext i16 %2 to i32
+  %4 = load volatile i16, i16* %a
+  %5 = zext i16 %4 to i32
+  %6 = add i32 %3, %5
+  ret i32 %6
+}
+
+; Check indexed and unindexed stores
+
+define void @sb(i8 *%a, i8 %b) nounwind {
+; RV32I-LABEL: sb:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    sb a1, 6(a0)
+; RV32I-NEXT:    sb a1, 0(a0)
+; RV32I-NEXT:    jalr zero, ra, 0
+  store i8 %b, i8* %a
+  %1 = getelementptr i8, i8* %a, i32 6
+  store i8 %b, i8* %1
+  ret void
+}
+
+define void @sh(i16 *%a, i16 %b) nounwind {
+; RV32I-LABEL: sh:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    sh a1, 14(a0)
+; RV32I-NEXT:    sh a1, 0(a0)
+; RV32I-NEXT:    jalr zero, ra, 0
+  store i16 %b, i16* %a
+  %1 = getelementptr i16, i16* %a, i32 7
+  store i16 %b, i16* %1
+  ret void
+}
+
+define void @sw(i32 *%a, i32 %b) nounwind {
+; RV32I-LABEL: sw:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    sw a1, 32(a0)
+; RV32I-NEXT:    sw a1, 0(a0)
+; RV32I-NEXT:    jalr zero, ra, 0
+  store i32 %b, i32* %a
+  %1 = getelementptr i32, i32* %a, i32 8
+  store i32 %b, i32* %1
+  ret void
+}
+
+; Check load and store to an i1 location
+define i32 @load_sext_zext_anyext_i1(i1 *%a) nounwind {
+; RV32I-LABEL: load_sext_zext_anyext_i1:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    lb a1, 0(a0)
+; RV32I-NEXT:    lbu a1, 1(a0)
+; RV32I-NEXT:    lbu a0, 2(a0)
+; RV32I-NEXT:    sub a0, a0, a1
+; RV32I-NEXT:    jalr zero, ra, 0
+  ; sextload i1
+  %1 = getelementptr i1, i1* %a, i32 1
+  %2 = load i1, i1* %1
+  %3 = sext i1 %2 to i32
+  ; zextload i1
+  %4 = getelementptr i1, i1* %a, i32 2
+  %5 = load i1, i1* %4
+  %6 = zext i1 %5 to i32
+  %7 = add i32 %3, %6
+  ; extload i1 (anyext). Produced as the load is unused.
+  %8 = load volatile i1, i1* %a
+  ret i32 %7
+}
+
+define i16 @load_sext_zext_anyext_i1_i16(i1 *%a) nounwind {
+; RV32I-LABEL: load_sext_zext_anyext_i1_i16:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    lb a1, 0(a0)
+; RV32I-NEXT:    lbu a1, 1(a0)
+; RV32I-NEXT:    lbu a0, 2(a0)
+; RV32I-NEXT:    sub a0, a0, a1
+; RV32I-NEXT:    jalr zero, ra, 0
+  ; sextload i1
+  %1 = getelementptr i1, i1* %a, i32 1
+  %2 = load i1, i1* %1
+  %3 = sext i1 %2 to i16
+  ; zextload i1
+  %4 = getelementptr i1, i1* %a, i32 2
+  %5 = load i1, i1* %4
+  %6 = zext i1 %5 to i16
+  %7 = add i16 %3, %6
+  ; extload i1 (anyext). Produced as the load is unused.
+  %8 = load volatile i1, i1* %a
+  ret i16 %7
+}
+
+; Ensure that 1 is added to the high 20 bits if bit 11 of the low part is 1
+define i32 @lw_sw_constant(i32 %a) nounwind {
+; TODO: the addi should be folded in to the lw/sw
+; RV32I-LABEL: lw_sw_constant:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    lui a1, 912092
+; RV32I-NEXT:    addi a2, a1, -273
+; RV32I-NEXT:    lw a1, 0(a2)
+; RV32I-NEXT:    sw a0, 0(a2)
+; RV32I-NEXT:    addi a0, a1, 0
+; RV32I-NEXT:    jalr zero, ra, 0
+  %1 = inttoptr i32 3735928559 to i32*
+  %2 = load volatile i32, i32* %1
+  store i32 %a, i32* %1
+  ret i32 %2
+}
diff --git a/test/CodeGen/RISCV/wide-mem.ll b/test/CodeGen/RISCV/wide-mem.ll
new file mode 100644 (file)
index 0000000..917b214
--- /dev/null
@@ -0,0 +1,16 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV32I
+
+; Check load/store operations on values wider than what is natively supported
+
+define i64 @load_i64(i64 *%a) nounwind {
+; RV32I-LABEL: load_i64:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    lw a2, 0(a0)
+; RV32I-NEXT:    lw a1, 4(a0)
+; RV32I-NEXT:    addi a0, a2, 0
+; RV32I-NEXT:    jalr zero, ra, 0
+  %1 = load i64, i64* %a
+  ret i64 %1
+}