[llvm] [RISCV] Implement RISCVTTIImpl::shouldConsiderAddressTypePromotion for RISCV (PR #102560)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 8 23:51:24 PDT 2024


https://github.com/LiqinWeng updated https://github.com/llvm/llvm-project/pull/102560

>From d8f902d9387c535f2ee07cfe14c014347e59a375 Mon Sep 17 00:00:00 2001
From: LiqinWeng <liqin.weng at spacemit.com>
Date: Mon, 5 Aug 2024 17:52:00 +0800
Subject: [PATCH 1/3] [InstCombine] Remove the canonicalise SextADD + GEP

---
 .../InstCombine/InstructionCombining.cpp      |  21 --
 llvm/test/Transforms/InstCombine/array.ll     | 270 ------------------
 .../Transforms/InstCombine/gepofconstgepi8.ll |   6 +-
 3 files changed, 3 insertions(+), 294 deletions(-)
 delete mode 100644 llvm/test/Transforms/InstCombine/array.ll

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 0fb8b639c97b95..5b43aaf9104c9e 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3026,27 +3026,6 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
           GEP, Builder.CreateGEP(GEP.getSourceElementType(), NewPtr, Idx2, "",
                                  IsInBounds));
     }
-    ConstantInt *C;
-    if (match(GEP.getOperand(1), m_OneUse(m_SExtLike(m_OneUse(m_NSWAdd(
-                                     m_Value(Idx1), m_ConstantInt(C))))))) {
-      // %add = add nsw i32 %idx1, idx2
-      // %sidx = sext i32 %add to i64
-      // %gep = getelementptr i32, ptr %ptr, i64 %sidx
-      // as:
-      // %newptr = getelementptr i32, ptr %ptr, i32 %idx1
-      // %newgep = getelementptr i32, ptr %newptr, i32 idx2
-      bool IsInBounds = CanPreserveInBounds(
-          /*IsNSW=*/true, Idx1, C);
-      auto *NewPtr = Builder.CreateGEP(
-          GEP.getSourceElementType(), GEP.getPointerOperand(),
-          Builder.CreateSExt(Idx1, GEP.getOperand(1)->getType()), "",
-          IsInBounds);
-      return replaceInstUsesWith(
-          GEP,
-          Builder.CreateGEP(GEP.getSourceElementType(), NewPtr,
-                            Builder.CreateSExt(C, GEP.getOperand(1)->getType()),
-                            "", IsInBounds));
-    }
   }
 
   if (!GEP.isInBounds()) {
diff --git a/llvm/test/Transforms/InstCombine/array.ll b/llvm/test/Transforms/InstCombine/array.ll
deleted file mode 100644
index 4f4ae17bebc503..00000000000000
--- a/llvm/test/Transforms/InstCombine/array.ll
+++ /dev/null
@@ -1,270 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
-; RUN: opt < %s -passes=instcombine -S | FileCheck %s
-
-define void @test(ptr %ptr, i32 %a, i32 %b) {
-; CHECK-LABEL: define void @test(
-; CHECK-SAME: ptr [[PTR:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[A]] to i64
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[TMP0]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[TMP1]], i64 40
-; CHECK-NEXT:    store i32 [[B]], ptr [[GEP]], align 4
-; CHECK-NEXT:    ret void
-;
-entry:
-  %add = add nsw i32 %a, 10
-  %idx = sext i32 %add to i64
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %idx
-  store i32 %b, ptr %gep
-  ret void
-}
-
-define  i32 @test_add_res_moreoneuse(ptr %ptr, i32 %a, i32 %b) {
-; CHECK-LABEL: define i32 @test_add_res_moreoneuse(
-; CHECK-SAME: ptr [[PTR:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[A]], 5
-; CHECK-NEXT:    [[IDX:%.*]] = sext i32 [[ADD]] to i64
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[IDX]]
-; CHECK-NEXT:    store i32 [[B]], ptr [[GEP]], align 4
-; CHECK-NEXT:    ret i32 [[ADD]]
-;
-entry:
-  %add = add nsw i32 %a, 5
-  %idx = sext i32 %add to i64
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %idx
-  store i32 %b, ptr %gep
-  ret i32 %add
-}
-
-define void @test_addop_nonsw_flag(ptr %ptr, i32 %a, i32 %b) {
-; CHECK-LABEL: define void @test_addop_nonsw_flag(
-; CHECK-SAME: ptr [[PTR:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[A]], 10
-; CHECK-NEXT:    [[IDX:%.*]] = sext i32 [[ADD]] to i64
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[IDX]]
-; CHECK-NEXT:    store i32 [[B]], ptr [[GEP]], align 4
-; CHECK-NEXT:    ret void
-;
-entry:
-  %add = add i32 %a, 10
-  %idx = sext i32 %add to i64
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %idx
-  store i32 %b, ptr %gep
-  ret void
-}
-
-define void @test_add_op2_not_constant(ptr %ptr, i32 %a, i32 %b) {
-; CHECK-LABEL: define void @test_add_op2_not_constant(
-; CHECK-SAME: ptr [[PTR:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[A]], [[B]]
-; CHECK-NEXT:    [[IDX:%.*]] = sext i32 [[ADD]] to i64
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[IDX]]
-; CHECK-NEXT:    store i32 [[B]], ptr [[GEP]], align 4
-; CHECK-NEXT:    ret void
-;
-entry:
-  %add = add i32 %a, %b
-  %idx = sext i32 %add to i64
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %idx
-  store i32 %b, ptr %gep
-  ret void
-}
-
-define void @test_zext_nneg(ptr %ptr, i32 %a, i32 %b) {
-; CHECK-LABEL: define void @test_zext_nneg(
-; CHECK-SAME: ptr [[PTR:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[A]] to i64
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[TMP0]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[TMP1]], i64 40
-; CHECK-NEXT:    store i32 [[B]], ptr [[GEP]], align 4
-; CHECK-NEXT:    ret void
-;
-entry:
-  %add = add nsw i32 %a, 10
-  %idx = zext nneg i32 %add to i64
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %idx
-  store i32 %b, ptr %gep
-  ret void
-}
-
-define void @test_zext_missing_nneg(ptr %ptr, i32 %a, i32 %b) {
-; CHECK-LABEL: define void @test_zext_missing_nneg(
-; CHECK-SAME: ptr [[PTR:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[A]], 10
-; CHECK-NEXT:    [[IDX:%.*]] = zext i32 [[ADD]] to i64
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[IDX]]
-; CHECK-NEXT:    store i32 [[B]], ptr [[GEP]], align 4
-; CHECK-NEXT:    ret void
-;
-entry:
-  %add = add nsw i32 %a, 10
-  %idx = zext i32 %add to i64
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %idx
-  store i32 %b, ptr %gep
-  ret void
-}
-
-define ptr @gep_inbounds_add_nsw_nonneg(ptr %ptr, i64 %a, i64 %b) {
-; CHECK-LABEL: define ptr @gep_inbounds_add_nsw_nonneg(
-; CHECK-SAME: ptr [[PTR:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT:    [[A_NNEG:%.*]] = icmp sgt i64 [[A]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[A_NNEG]])
-; CHECK-NEXT:    [[B_NNEG:%.*]] = icmp sgt i64 [[B]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[B_NNEG]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[A]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[B]]
-; CHECK-NEXT:    ret ptr [[GEP]]
-;
-  %a.nneg = icmp sgt i64 %a, -1
-  call void @llvm.assume(i1 %a.nneg)
-  %b.nneg = icmp sgt i64 %b, -1
-  call void @llvm.assume(i1 %b.nneg)
-  %add = add nsw i64 %a, %b
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %add
-  ret ptr %gep
-}
-
-define ptr @gep_inbounds_add_nsw_not_nonneg1(ptr %ptr, i64 %a, i64 %b) {
-; CHECK-LABEL: define ptr @gep_inbounds_add_nsw_not_nonneg1(
-; CHECK-SAME: ptr [[PTR:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT:    [[A_NNEG:%.*]] = icmp sgt i64 [[A]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[A_NNEG]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[A]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[TMP1]], i64 [[B]]
-; CHECK-NEXT:    ret ptr [[GEP]]
-;
-  %a.nneg = icmp sgt i64 %a, -1
-  call void @llvm.assume(i1 %a.nneg)
-  %add = add nsw i64 %a, %b
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %add
-  ret ptr %gep
-}
-
-define ptr @gep_inbounds_add_nsw_not_nonneg2(ptr %ptr, i64 %a, i64 %b) {
-; CHECK-LABEL: define ptr @gep_inbounds_add_nsw_not_nonneg2(
-; CHECK-SAME: ptr [[PTR:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT:    [[B_NNEG:%.*]] = icmp sgt i64 [[B]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[B_NNEG]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[A]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[TMP1]], i64 [[B]]
-; CHECK-NEXT:    ret ptr [[GEP]]
-;
-  %b.nneg = icmp sgt i64 %b, -1
-  call void @llvm.assume(i1 %b.nneg)
-  %add = add nsw i64 %a, %b
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %add
-  ret ptr %gep
-}
-
-define ptr @gep_not_inbounds_add_nsw_nonneg(ptr %ptr, i64 %a, i64 %b) {
-; CHECK-LABEL: define ptr @gep_not_inbounds_add_nsw_nonneg(
-; CHECK-SAME: ptr [[PTR:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT:    [[A_NNEG:%.*]] = icmp sgt i64 [[A]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[A_NNEG]])
-; CHECK-NEXT:    [[B_NNEG:%.*]] = icmp sgt i64 [[B]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[B_NNEG]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[A]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[TMP1]], i64 [[B]]
-; CHECK-NEXT:    ret ptr [[GEP]]
-;
-  %a.nneg = icmp sgt i64 %a, -1
-  call void @llvm.assume(i1 %a.nneg)
-  %b.nneg = icmp sgt i64 %b, -1
-  call void @llvm.assume(i1 %b.nneg)
-  %add = add nsw i64 %a, %b
-  %gep = getelementptr i32, ptr %ptr, i64 %add
-  ret ptr %gep
-}
-
-define ptr @gep_inbounds_add_not_nsw_nonneg(ptr %ptr, i64 %a, i64 %b) {
-; CHECK-LABEL: define ptr @gep_inbounds_add_not_nsw_nonneg(
-; CHECK-SAME: ptr [[PTR:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT:    [[A_NNEG:%.*]] = icmp sgt i64 [[A]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[A_NNEG]])
-; CHECK-NEXT:    [[B_NNEG:%.*]] = icmp sgt i64 [[B]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[B_NNEG]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[A]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[TMP1]], i64 [[B]]
-; CHECK-NEXT:    ret ptr [[GEP]]
-;
-  %a.nneg = icmp sgt i64 %a, -1
-  call void @llvm.assume(i1 %a.nneg)
-  %b.nneg = icmp sgt i64 %b, -1
-  call void @llvm.assume(i1 %b.nneg)
-  %add = add i64 %a, %b
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %add
-  ret ptr %gep
-}
-
-define ptr @gep_inbounds_sext_add_nonneg(ptr %ptr, i32 %a) {
-; CHECK-LABEL: define ptr @gep_inbounds_sext_add_nonneg(
-; CHECK-SAME: ptr [[PTR:%.*]], i32 [[A:%.*]]) {
-; CHECK-NEXT:    [[A_NNEG:%.*]] = icmp sgt i32 [[A]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[A_NNEG]])
-; CHECK-NEXT:    [[TMP1:%.*]] = zext nneg i32 [[A]] to i64
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[TMP1]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 40
-; CHECK-NEXT:    ret ptr [[GEP]]
-;
-  %a.nneg = icmp sgt i32 %a, -1
-  call void @llvm.assume(i1 %a.nneg)
-  %add = add nsw i32 %a, 10
-  %idx = sext i32 %add to i64
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %idx
-  ret ptr %gep
-}
-
-define ptr @gep_inbounds_sext_add_not_nonneg_1(ptr %ptr, i32 %a) {
-; CHECK-LABEL: define ptr @gep_inbounds_sext_add_not_nonneg_1(
-; CHECK-SAME: ptr [[PTR:%.*]], i32 [[A:%.*]]) {
-; CHECK-NEXT:    [[A_NNEG:%.*]] = icmp sgt i32 [[A]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[A_NNEG]])
-; CHECK-NEXT:    [[TMP1:%.*]] = zext nneg i32 [[A]] to i64
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[TMP1]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[TMP2]], i64 -40
-; CHECK-NEXT:    ret ptr [[GEP]]
-;
-  %a.nneg = icmp sgt i32 %a, -1
-  call void @llvm.assume(i1 %a.nneg)
-  %add = add nsw i32 %a, -10
-  %idx = sext i32 %add to i64
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %idx
-  ret ptr %gep
-}
-
-define ptr @gep_inbounds_sext_add_not_nonneg_2(ptr %ptr, i32 %a) {
-; CHECK-LABEL: define ptr @gep_inbounds_sext_add_not_nonneg_2(
-; CHECK-SAME: ptr [[PTR:%.*]], i32 [[A:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[A]] to i64
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[TMP1]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[TMP2]], i64 40
-; CHECK-NEXT:    ret ptr [[GEP]]
-;
-  %add = add nsw i32 %a, 10
-  %idx = sext i32 %add to i64
-  %gep = getelementptr inbounds i32, ptr %ptr, i64 %idx
-  ret ptr %gep
-}
-
-define ptr @gep_not_inbounds_sext_add_nonneg(ptr %ptr, i32 %a) {
-; CHECK-LABEL: define ptr @gep_not_inbounds_sext_add_nonneg(
-; CHECK-SAME: ptr [[PTR:%.*]], i32 [[A:%.*]]) {
-; CHECK-NEXT:    [[A_NNEG:%.*]] = icmp sgt i32 [[A]], -1
-; CHECK-NEXT:    call void @llvm.assume(i1 [[A_NNEG]])
-; CHECK-NEXT:    [[TMP1:%.*]] = zext nneg i32 [[A]] to i64
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[TMP1]]
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[TMP2]], i64 40
-; CHECK-NEXT:    ret ptr [[GEP]]
-;
-  %a.nneg = icmp sgt i32 %a, -1
-  call void @llvm.assume(i1 %a.nneg)
-  %add = add nsw i32 %a, 10
-  %idx = sext i32 %add to i64
-  %gep = getelementptr i32, ptr %ptr, i64 %idx
-  ret ptr %gep
-}
diff --git a/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll b/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
index 4c8c56a9262e34..4bc9bd85df76f7 100644
--- a/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
+++ b/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
@@ -86,10 +86,10 @@ define ptr @test_zero_sext_add_nsw(ptr %base, i32 %a) {
 ; CHECK-SAME: ptr [[BASE:%.*]], i32 [[A:%.*]]) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[P1:%.*]] = getelementptr i8, ptr [[BASE]], i64 -4
-; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[A]] to i64
+; CHECK-NEXT:    [[INDEX:%.*]] = add nsw i32 [[A]], 1
+; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[INDEX]] to i64
 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[P1]], i64 [[TMP0]]
-; CHECK-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[TMP1]], i64 4
-; CHECK-NEXT:    ret ptr [[P2]]
+; CHECK-NEXT:    ret ptr [[TMP1]]
 ;
 entry:
   %p1 = getelementptr i8, ptr %base, i64 -4

>From 0f77a56d4379bb7f96f999c9ed56e256362099b4 Mon Sep 17 00:00:00 2001
From: LiqinWeng <liqin.weng at spacemit.com>
Date: Mon, 5 Aug 2024 17:54:05 +0800
Subject: [PATCH 2/3] [Test] add test to implement
 'RISCVTTIImpl::shouldConsiderAddressTypePromotion' for RISCV

---
 .../RISCV/riscv-codegen-prepare-atp.ll        | 95 +++++++++++++++++++
 1 file changed, 95 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/riscv-codegen-prepare-atp.ll

diff --git a/llvm/test/CodeGen/RISCV/riscv-codegen-prepare-atp.ll b/llvm/test/CodeGen/RISCV/riscv-codegen-prepare-atp.ll
new file mode 100644
index 00000000000000..06d95366e3f83b
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/riscv-codegen-prepare-atp.ll
@@ -0,0 +1,95 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt -passes='require<profile-summary>,function(codegenprepare)' < %s -S | FileCheck %s
+
+target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "riscv64"
+
+%struct.match_state = type { i64, i64  }
+
+; %add is also promoted by forking an extra sext.
+define void @promoteTwoOne(i32 %i, i32 %j, ptr %P1, ptr %P2 ) {
+; CHECK-LABEL: define void @promoteTwoOne(
+; CHECK-SAME: i32 [[I:%.*]], i32 [[J:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I]], [[J]]
+; CHECK-NEXT:    [[S:%.*]] = sext i32 [[ADD]] to i64
+; CHECK-NEXT:    [[ADDR1:%.*]] = getelementptr inbounds i64, ptr [[P1]], i64 [[S]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[ADDR1]], align 8
+; CHECK-NEXT:    [[S2:%.*]] = sext i32 [[I]] to i64
+; CHECK-NEXT:    [[ADDR2:%.*]] = getelementptr inbounds i64, ptr [[P2]], i64 [[S2]]
+; CHECK-NEXT:    store i64 [[S2]], ptr [[ADDR2]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  %add = add nsw i32 %i, %j
+  %s = sext i32 %add to i64
+  %addr1 = getelementptr inbounds i64, ptr %P1, i64 %s
+  store i64 %s, ptr %addr1
+  %s2 = sext i32 %i to i64
+  %addr2 = getelementptr inbounds i64, ptr %P2, i64 %s2
+  store i64 %s2, ptr %addr2
+  ret void
+}
+
+; Both %add1 and %add2 are promoted by forking extra sexts.
+define void @promoteTwoTwo(i32 %i, i32 %j, i32 %k, ptr %P1, ptr %P2) {
+; CHECK-LABEL: define void @promoteTwoTwo(
+; CHECK-SAME: i32 [[I:%.*]], i32 [[J:%.*]], i32 [[K:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ADD1:%.*]] = add nsw i32 [[J]], [[I]]
+; CHECK-NEXT:    [[S:%.*]] = sext i32 [[ADD1]] to i64
+; CHECK-NEXT:    [[ADDR1:%.*]] = getelementptr inbounds i64, ptr [[P1]], i64 [[S]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[ADDR1]], align 8
+; CHECK-NEXT:    [[ADD2:%.*]] = add nsw i32 [[J]], [[K]]
+; CHECK-NEXT:    [[S2:%.*]] = sext i32 [[ADD2]] to i64
+; CHECK-NEXT:    [[ADDR2:%.*]] = getelementptr inbounds i64, ptr [[P2]], i64 [[S2]]
+; CHECK-NEXT:    store i64 [[S2]], ptr [[ADDR2]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  %add1 = add nsw i32 %j, %i
+  %s = sext i32 %add1 to i64
+  %addr1 = getelementptr inbounds i64, ptr %P1, i64 %s
+  store i64 %s, ptr %addr1
+  %add2 = add nsw i32 %j, %k
+  %s2 = sext i32 %add2 to i64
+  %addr2 = getelementptr inbounds i64, ptr %P2, i64 %s2
+  store i64 %s2, ptr %addr2
+  ret void
+}
+
+define i64 @promoteGEPSunk(i1 %cond, ptr %base, i32 %i) {
+; CHECK-LABEL: define i64 @promoteGEPSunk(
+; CHECK-SAME: i1 [[COND:%.*]], ptr [[BASE:%.*]], i32 [[I:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I]], 1
+; CHECK-NEXT:    [[S:%.*]] = sext i32 [[ADD]] to i64
+; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr inbounds i64, ptr [[BASE]], i64 [[S]]
+; CHECK-NEXT:    [[ADD2:%.*]] = add nsw i32 [[I]], 2
+; CHECK-NEXT:    [[S2:%.*]] = sext i32 [[ADD2]] to i64
+; CHECK-NEXT:    [[ADDR2:%.*]] = getelementptr inbounds i64, ptr [[BASE]], i64 [[S2]]
+; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_THEN2:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[V:%.*]] = load i64, ptr [[ADDR]], align 8
+; CHECK-NEXT:    [[V2:%.*]] = load i64, ptr [[ADDR2]], align 8
+; CHECK-NEXT:    [[R:%.*]] = add i64 [[V]], [[V2]]
+; CHECK-NEXT:    ret i64 [[R]]
+; CHECK:       if.then2:
+; CHECK-NEXT:    ret i64 0
+;
+entry:
+  %add = add nsw i32 %i, 1
+  %s = sext i32 %add to i64
+  %addr = getelementptr inbounds i64, ptr %base, i64 %s
+  %add2 = add nsw i32 %i,  2
+  %s2 = sext i32 %add2 to i64
+  %addr2 = getelementptr inbounds i64, ptr %base, i64 %s2
+  br i1 %cond, label %if.then, label %if.then2
+if.then:
+  %v = load i64, ptr %addr
+  %v2 = load i64, ptr %addr2
+  %r = add i64 %v, %v2
+  ret i64 %r
+if.then2:
+  ret i64 0;
+}

>From f82230ad863527b5456a0b37baffdc0c1d660bab Mon Sep 17 00:00:00 2001
From: LiqinWeng <liqin.weng at spacemit.com>
Date: Tue, 6 Aug 2024 14:26:50 +0800
Subject: [PATCH 3/3] [RISCV] Implement
 RISCVTTIImpl::shouldConsiderAddressTypePromotion for RISCV

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  1 +
 .../Target/RISCV/RISCVTargetTransformInfo.cpp | 32 +++++++++++++++++++
 .../Target/RISCV/RISCVTargetTransformInfo.h   |  4 ++-
 .../RISCV/riscv-codegen-prepare-atp.ll        | 22 ++++++-------
 4 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 72aec12158f2c1..c0ec62819f866c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -1507,6 +1507,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
 
   // Disable strict node mutation.
   IsStrictFPEnabled = true;
+  EnableExtLdPromotion = true;
 
   // Let the subtarget decide if a predictable select is more expensive than the
   // corresponding branch. This information is used in CGP/SelectOpt to decide
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index 4cd904c039a984..b8e9c26e1513d5 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -1989,3 +1989,35 @@ bool RISCVTTIImpl::areInlineCompatible(const Function *Caller,
   // target-features.
   return (CallerBits & CalleeBits) == CalleeBits;
 }
+
+/// See if \p I should be considered for address type promotion. We check if \p
+/// I is a sext with right type and used in memory accesses. If it used in a
+/// "complex" getelementptr, we allow it to be promoted without finding other
+/// sext instructions that sign extended the same initial value. A getelementptr
+/// is considered as "complex" if it has more than 2 operands.
+bool RISCVTTIImpl::shouldConsiderAddressTypePromotion(
+    const Instruction &I, bool &AllowPromotionWithoutCommonHeader) {
+  bool Considerable = false;
+  AllowPromotionWithoutCommonHeader = false;
+  if (!isa<SExtInst>(&I))
+    return false;
+  Type *ConsideredSExtType =
+      Type::getInt64Ty(I.getParent()->getParent()->getContext());
+  if (I.getType() != ConsideredSExtType)
+    return false;
+  // See if the sext is the one with the right type and used in at least one
+  // GetElementPtrInst.
+  for (const User *U : I.users()) {
+    if (const GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(U)) {
+      Considerable = true;
+      // A getelementptr is considered as "complex" if it has more than 2
+      // operands. We will promote a SExt used in such complex GEP as we
+      // expect some computation to be merged if they are done on 64 bits.
+      if (GEPInst->getNumOperands() > 2) {
+        AllowPromotionWithoutCommonHeader = true;
+        break;
+      }
+    }
+  }
+  return Considerable;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
index 9c37a4f6ec2d04..f5eca2839acd05 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
@@ -397,7 +397,9 @@ class RISCVTTIImpl : public BasicTTIImplBase<RISCVTTIImpl> {
   bool shouldFoldTerminatingConditionAfterLSR() const {
     return true;
   }
-
+  bool
+  shouldConsiderAddressTypePromotion(const Instruction &I,
+                                     bool &AllowPromotionWithoutCommonHeader);
   std::optional<unsigned> getMinPageSize() const { return 4096; }
 };
 
diff --git a/llvm/test/CodeGen/RISCV/riscv-codegen-prepare-atp.ll b/llvm/test/CodeGen/RISCV/riscv-codegen-prepare-atp.ll
index 06d95366e3f83b..b733c6a1c787ba 100644
--- a/llvm/test/CodeGen/RISCV/riscv-codegen-prepare-atp.ll
+++ b/llvm/test/CodeGen/RISCV/riscv-codegen-prepare-atp.ll
@@ -11,11 +11,11 @@ define void @promoteTwoOne(i32 %i, i32 %j, ptr %P1, ptr %P2 ) {
 ; CHECK-LABEL: define void @promoteTwoOne(
 ; CHECK-SAME: i32 [[I:%.*]], i32 [[J:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I]], [[J]]
-; CHECK-NEXT:    [[S:%.*]] = sext i32 [[ADD]] to i64
+; CHECK-NEXT:    [[S2:%.*]] = sext i32 [[I]] to i64
+; CHECK-NEXT:    [[PROMOTED2:%.*]] = sext i32 [[J]] to i64
+; CHECK-NEXT:    [[S:%.*]] = add nsw i64 [[S2]], [[PROMOTED2]]
 ; CHECK-NEXT:    [[ADDR1:%.*]] = getelementptr inbounds i64, ptr [[P1]], i64 [[S]]
 ; CHECK-NEXT:    store i64 [[S]], ptr [[ADDR1]], align 8
-; CHECK-NEXT:    [[S2:%.*]] = sext i32 [[I]] to i64
 ; CHECK-NEXT:    [[ADDR2:%.*]] = getelementptr inbounds i64, ptr [[P2]], i64 [[S2]]
 ; CHECK-NEXT:    store i64 [[S2]], ptr [[ADDR2]], align 8
 ; CHECK-NEXT:    ret void
@@ -36,12 +36,13 @@ define void @promoteTwoTwo(i32 %i, i32 %j, i32 %k, ptr %P1, ptr %P2) {
 ; CHECK-LABEL: define void @promoteTwoTwo(
 ; CHECK-SAME: i32 [[I:%.*]], i32 [[J:%.*]], i32 [[K:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[ADD1:%.*]] = add nsw i32 [[J]], [[I]]
-; CHECK-NEXT:    [[S:%.*]] = sext i32 [[ADD1]] to i64
+; CHECK-NEXT:    [[PROMOTED3:%.*]] = sext i32 [[J]] to i64
+; CHECK-NEXT:    [[PROMOTED4:%.*]] = sext i32 [[I]] to i64
+; CHECK-NEXT:    [[S:%.*]] = add nsw i64 [[PROMOTED3]], [[PROMOTED4]]
 ; CHECK-NEXT:    [[ADDR1:%.*]] = getelementptr inbounds i64, ptr [[P1]], i64 [[S]]
 ; CHECK-NEXT:    store i64 [[S]], ptr [[ADDR1]], align 8
-; CHECK-NEXT:    [[ADD2:%.*]] = add nsw i32 [[J]], [[K]]
-; CHECK-NEXT:    [[S2:%.*]] = sext i32 [[ADD2]] to i64
+; CHECK-NEXT:    [[PROMOTED2:%.*]] = sext i32 [[K]] to i64
+; CHECK-NEXT:    [[S2:%.*]] = add nsw i64 [[PROMOTED3]], [[PROMOTED2]]
 ; CHECK-NEXT:    [[ADDR2:%.*]] = getelementptr inbounds i64, ptr [[P2]], i64 [[S2]]
 ; CHECK-NEXT:    store i64 [[S2]], ptr [[ADDR2]], align 8
 ; CHECK-NEXT:    ret void
@@ -62,11 +63,10 @@ define i64 @promoteGEPSunk(i1 %cond, ptr %base, i32 %i) {
 ; CHECK-LABEL: define i64 @promoteGEPSunk(
 ; CHECK-SAME: i1 [[COND:%.*]], ptr [[BASE:%.*]], i32 [[I:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I]], 1
-; CHECK-NEXT:    [[S:%.*]] = sext i32 [[ADD]] to i64
+; CHECK-NEXT:    [[PROMOTED1:%.*]] = sext i32 [[I]] to i64
+; CHECK-NEXT:    [[S:%.*]] = add nsw i64 [[PROMOTED1]], 1
 ; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr inbounds i64, ptr [[BASE]], i64 [[S]]
-; CHECK-NEXT:    [[ADD2:%.*]] = add nsw i32 [[I]], 2
-; CHECK-NEXT:    [[S2:%.*]] = sext i32 [[ADD2]] to i64
+; CHECK-NEXT:    [[S2:%.*]] = add nsw i64 [[PROMOTED1]], 2
 ; CHECK-NEXT:    [[ADDR2:%.*]] = getelementptr inbounds i64, ptr [[BASE]], i64 [[S2]]
 ; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_THEN2:%.*]]
 ; CHECK:       if.then:



More information about the llvm-commits mailing list