[RISCV] Add initial test coverage for LSR
authorPhilip Reames <preames@rivosinc.com>
Fri, 20 May 2022 17:05:55 +0000 (10:05 -0700)
committerPhilip Reames <listmail@philipreames.com>
Fri, 20 May 2022 17:23:18 +0000 (10:23 -0700)
Establish the most basic possible test coverage for LSR transformation on RISCV.

Original patch by eopXD (D123458), modified by me to cleanup/simplify tests.

llvm/test/CodeGen/RISCV/loop-strength-reduce-add-cheaper-than-mul.ll [new file with mode: 0644]
llvm/test/CodeGen/RISCV/loop-strength-reduce-loop-invar.ll [new file with mode: 0644]

diff --git a/llvm/test/CodeGen/RISCV/loop-strength-reduce-add-cheaper-than-mul.ll b/llvm/test/CodeGen/RISCV/loop-strength-reduce-add-cheaper-than-mul.ll
new file mode 100644 (file)
index 0000000..d062709
--- /dev/null
@@ -0,0 +1,95 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=riscv32 -verify-machineinstrs -mattr=+m | FileCheck %s -check-prefixes=RV32
+; RUN: llc < %s -mtriple=riscv64 -verify-machineinstrs -mattr=+m | FileCheck %s -check-prefixes=RV64
+
+; Test case:
+; - Addition should be cheaper than multiplication
+
+; The following LLVM IR simulates:
+; int8_t flag2[8193];
+; void test(int i) {
+;   int tmp = i * 2;
+;      if (i * 2 > 8192) return ;
+;   for (int j = 0; ; ++j) {
+;              int offset = j * i + tmp;
+;              flag2[offset] = 0;
+;              if (offset + i > 8192) break;
+;   }
+; }
+
+; After LSR:
+; int8_t flag2[8193];
+; void test(int i) {
+;      int j = i * 2;
+;      if (j > 8193) return ;
+;   do {
+;              flag2[j] = 0;
+;              j += i;
+;   } while (j < 8193);
+; }
+
+@flags2 = internal global [8193 x i8] zeroinitializer, align 32                ; <[8193 x i8]*> [#uses=1]
+
+define void @test(i32 signext %i) nounwind {
+; RV32-LABEL: test:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    slli a1, a0, 1
+; RV32-NEXT:    lui a3, 2
+; RV32-NEXT:    blt a3, a1, .LBB0_3
+; RV32-NEXT:  # %bb.1: # %bb.preheader
+; RV32-NEXT:    lui a2, %hi(flags2)
+; RV32-NEXT:    addi a2, a2, %lo(flags2)
+; RV32-NEXT:    addi a3, a3, 1
+; RV32-NEXT:  .LBB0_2: # %bb
+; RV32-NEXT:    # =>This Inner Loop Header: Depth=1
+; RV32-NEXT:    add a4, a1, a2
+; RV32-NEXT:    add a1, a1, a0
+; RV32-NEXT:    sb zero, 0(a4)
+; RV32-NEXT:    blt a1, a3, .LBB0_2
+; RV32-NEXT:  .LBB0_3: # %return
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    slliw a1, a0, 1
+; RV64-NEXT:    lui a4, 2
+; RV64-NEXT:    blt a4, a1, .LBB0_3
+; RV64-NEXT:  # %bb.1: # %bb.preheader
+; RV64-NEXT:    li a2, 0
+; RV64-NEXT:    lui a3, %hi(flags2)
+; RV64-NEXT:    addi a3, a3, %lo(flags2)
+; RV64-NEXT:    addiw a4, a4, 1
+; RV64-NEXT:  .LBB0_2: # %bb
+; RV64-NEXT:    # =>This Inner Loop Header: Depth=1
+; RV64-NEXT:    mulw a5, a2, a0
+; RV64-NEXT:    addw a5, a5, a1
+; RV64-NEXT:    slli a6, a5, 32
+; RV64-NEXT:    srli a6, a6, 32
+; RV64-NEXT:    add a6, a6, a3
+; RV64-NEXT:    sb zero, 0(a6)
+; RV64-NEXT:    addw a5, a5, a0
+; RV64-NEXT:    addiw a2, a2, 1
+; RV64-NEXT:    blt a5, a4, .LBB0_2
+; RV64-NEXT:  .LBB0_3: # %return
+; RV64-NEXT:    ret
+entry:
+       %k_addr.012 = shl i32 %i, 1
+       %tmp14 = icmp sgt i32 %k_addr.012, 8192
+       %tmp. = shl i32 %i, 1
+       br i1 %tmp14, label %return, label %bb
+
+bb:
+       %indvar = phi i32 [ 0, %entry ], [ %indvar.next, %bb ]
+       %tmp.15 = mul i32 %indvar, %i
+       %tmp.16 = add i32 %tmp.15, %tmp.
+       %gep.upgrd.1 = zext i32 %tmp.16 to i64
+       %tmp = getelementptr [8193 x i8], [8193 x i8]* @flags2, i32 0, i64 %gep.upgrd.1
+       store i8 0, i8* %tmp
+       %tmp.17 = add i32 %tmp.16, %i
+       %tmp.upgrd.2 = icmp sgt i32 %tmp.17, 8192
+       %indvar.next = add i32 %indvar, 1
+       br i1 %tmp.upgrd.2, label %return, label %bb
+
+return:
+       ret void
+}
diff --git a/llvm/test/CodeGen/RISCV/loop-strength-reduce-loop-invar.ll b/llvm/test/CodeGen/RISCV/loop-strength-reduce-loop-invar.ll
new file mode 100644 (file)
index 0000000..a288b4e
--- /dev/null
@@ -0,0 +1,96 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=riscv32 -verify-machineinstrs | FileCheck %s -check-prefixes=RV32
+; RUN: llc < %s -mtriple=riscv64 -verify-machineinstrs | FileCheck %s -check-prefixes=RV64
+
+; Test case:
+; - `A[row]` is loop invariant and should be hoisted up to preheader
+; FIXME: RV32 is working as expected, but RV64 doesn't
+
+; The following LLVM IR simulates:
+; int A[16][16];
+; void test(int row, int N) {
+;      for (int i=0; i<N; ++I) {
+;              A[row][i+1] = 4;
+;              A[row][i+2] = 5;
+;      }
+; }
+
+; After LSR:
+; int A[16][16];
+; void test(int row, int N) {
+;      for (int *ptr = A[row][2]; N>0; N--) {
+;              *(ptr-1) = 4;
+;              *(ptr) = 5;
+;              ++ptr;
+;      }
+; }
+
+@A = internal global [16 x [16 x i32]] zeroinitializer, align 32               ; <[16 x [16 x i32]]*> [#uses=2]
+
+define void @test(i32 signext %row, i32 signext %N.in) nounwind {
+; RV32-LABEL: test:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    blez a1, .LBB0_3
+; RV32-NEXT:  # %bb.1: # %cond_true.preheader
+; RV32-NEXT:    slli a0, a0, 6
+; RV32-NEXT:    lui a2, %hi(A)
+; RV32-NEXT:    addi a2, a2, %lo(A)
+; RV32-NEXT:    add a0, a2, a0
+; RV32-NEXT:    addi a0, a0, 8
+; RV32-NEXT:    li a2, 4
+; RV32-NEXT:    li a3, 5
+; RV32-NEXT:  .LBB0_2: # %cond_true
+; RV32-NEXT:    # =>This Inner Loop Header: Depth=1
+; RV32-NEXT:    sw a2, -4(a0)
+; RV32-NEXT:    sw a3, 0(a0)
+; RV32-NEXT:    addi a1, a1, -1
+; RV32-NEXT:    addi a0, a0, 4
+; RV32-NEXT:    bnez a1, .LBB0_2
+; RV32-NEXT:  .LBB0_3: # %return
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    blez a1, .LBB0_3
+; RV64-NEXT:  # %bb.1: # %cond_true.preheader
+; RV64-NEXT:    li a4, 0
+; RV64-NEXT:    lui a2, %hi(A)
+; RV64-NEXT:    addi a2, a2, %lo(A)
+; RV64-NEXT:    slli a0, a0, 6
+; RV64-NEXT:    add a0, a0, a2
+; RV64-NEXT:    li a2, 4
+; RV64-NEXT:    li a3, 5
+; RV64-NEXT:  .LBB0_2: # %cond_true
+; RV64-NEXT:    # =>This Inner Loop Header: Depth=1
+; RV64-NEXT:    addiw a5, a4, 1
+; RV64-NEXT:    slli a6, a5, 2
+; RV64-NEXT:    add a6, a0, a6
+; RV64-NEXT:    sw a2, 0(a6)
+; RV64-NEXT:    addiw a4, a4, 2
+; RV64-NEXT:    slli a4, a4, 2
+; RV64-NEXT:    add a4, a0, a4
+; RV64-NEXT:    sw a3, 0(a4)
+; RV64-NEXT:    mv a4, a5
+; RV64-NEXT:    bne a5, a1, .LBB0_2
+; RV64-NEXT:  .LBB0_3: # %return
+; RV64-NEXT:    ret
+entry:
+       %N = bitcast i32 %N.in to i32
+       %tmp5 = icmp sgt i32 %N.in, 0
+       br i1 %tmp5, label %cond_true, label %return
+
+cond_true:
+       %indvar = phi i32 [ 0, %entry ], [ %indvar.next, %cond_true ]
+       %tmp2 = add i32 %indvar, 1
+       %tmp = getelementptr [16 x [16 x i32]], [16 x [16 x i32]]* @A, i32 0, i32 %row, i32 %tmp2
+       store i32 4, i32* %tmp
+       %tmp5.upgrd.1 = add i32 %indvar, 2
+       %tmp7 = getelementptr [16 x [16 x i32]], [16 x [16 x i32]]* @A, i32 0, i32 %row, i32 %tmp5.upgrd.1
+       store i32 5, i32* %tmp7
+       %indvar.next = add i32 %indvar, 1
+       %exitcond = icmp eq i32 %indvar.next, %N
+       br i1 %exitcond, label %return, label %cond_true
+
+return:
+       ret void
+}