[llvm] [TypePromotion] Do not zero-extend getelementptr indexes since signed (PR #134281)
Antonio Frighetto via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 4 07:33:32 PDT 2025
https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/134281
>From 6eedf99def3bdbba5835a9583263357cf2d533d9 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 4 Apr 2025 11:35:23 +0200
Subject: [PATCH 1/3] [TypePromotion] Introduce test for PR134281 (NFC)
---
.../test/CodeGen/AArch64/typepromotion-gep.ll | 44 +++++++++++++++++++
1 file changed, 44 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/typepromotion-gep.ll
diff --git a/llvm/test/CodeGen/AArch64/typepromotion-gep.ll b/llvm/test/CodeGen/AArch64/typepromotion-gep.ll
new file mode 100644
index 0000000000000..41421df12b22d
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/typepromotion-gep.ll
@@ -0,0 +1,44 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -p typepromotion %s -o - | FileCheck %s
+
+target triple = "arm64-apple-macosx15.0.0"
+
+; FIXME: This is a miscompilation, unused trunc is converted to used zext for gep offset,
+; which is to be treated as signed.
+define i4 @gep_offset_signedness(ptr %ptr, i8 %offset, i1 %cond) {
+; CHECK-LABEL: define i4 @gep_offset_signedness(
+; CHECK-SAME: ptr [[PTR:%.*]], i8 [[OFFSET:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[TMP0:%.*]] = zext i8 [[OFFSET]] to i32
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 15
+; CHECK-NEXT: [[PTR_IDX:%.*]] = getelementptr i8, ptr [[PTR]], i32 [[TMP0]]
+; CHECK-NEXT: [[COND_2:%.*]] = icmp uge ptr [[PTR_IDX]], [[PTR]]
+; CHECK-NEXT: br i1 [[COND_2]], label %[[RETURN:.*]], label %[[ELSE:.*]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[RET_VAL:%.*]] = phi i4 [ 0, %[[ELSE_RET:.*]] ], [ 1, %[[ENTRY]] ], [ 0, %[[ELSE]] ]
+; CHECK-NEXT: ret i4 [[RET_VAL]]
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 0, 0
+; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[ADD]], [[TMP0]]
+; CHECK-NEXT: br i1 [[COND]], label %[[RETURN]], label %[[ELSE_RET]]
+; CHECK: [[ELSE_RET]]:
+; CHECK-NEXT: br label %[[RETURN]]
+;
+entry:
+ %unused_trunc = trunc i8 %offset to i4
+ %ptr.idx = getelementptr i8, ptr %ptr, i8 %offset
+ %cond.2 = icmp uge ptr %ptr.idx, %ptr
+ br i1 %cond.2, label %return, label %else
+
+return: ; preds = %else.ret, %else, %entry
+ %ret.val = phi i4 [ 0, %else.ret ], [ 1, %entry ], [ 0, %else ]
+ ret i4 %ret.val
+
+else: ; preds = %entry
+ %add = add nuw i8 0, 0
+ %cond.3 = icmp ult i8 %add, %offset
+ br i1 %cond, label %return, label %else.ret
+
+else.ret: ; preds = %else
+ br label %return
+}
>From 5eef24da4ce125a78dd3065fe67ba4a04c74b07e Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 4 Apr 2025 15:05:05 +0200
Subject: [PATCH 2/3] [TypePromotion] Do not zero-extend getelementptr indexes
since signed
A miscompilation issue has been addressed with improved handling.
Fixes: https://github.com/llvm/llvm-project/issues/133928.
Alive2: https://alive2.llvm.org/ce/z/gcMNvS.
---
llvm/lib/CodeGen/TypePromotion.cpp | 6 ++--
.../test/CodeGen/AArch64/typepromotion-gep.ll | 9 ++----
.../CodeGen/AArch64/typepromotion-phisret.ll | 22 ++++++++-------
.../Transforms/TypePromotion/ARM/phis-ret.ll | 18 +++++-------
.../Transforms/TypePromotion/ARM/pointers.ll | 28 ++++++++-----------
5 files changed, 36 insertions(+), 47 deletions(-)
diff --git a/llvm/lib/CodeGen/TypePromotion.cpp b/llvm/lib/CodeGen/TypePromotion.cpp
index b1f99094daa4a..e9fa78eabff7c 100644
--- a/llvm/lib/CodeGen/TypePromotion.cpp
+++ b/llvm/lib/CodeGen/TypePromotion.cpp
@@ -806,10 +806,10 @@ bool TypePromotionImpl::TryToPromote(Value *V, unsigned PromotedWidth,
if (CurrentVisited.count(V))
return true;
- // Ignore GEPs because they don't need promoting and the constant indices
- // will prevent the transformation.
+ // Skip promoting GEPs as their indices should have already been
+ // canonicalized to pointer width.
if (isa<GetElementPtrInst>(V))
- return true;
+ return false;
if (!isSupportedValue(V) || (shouldPromote(V) && !isLegalToPromote(V))) {
LLVM_DEBUG(dbgs() << "IR Promotion: Can't handle: " << *V << "\n");
diff --git a/llvm/test/CodeGen/AArch64/typepromotion-gep.ll b/llvm/test/CodeGen/AArch64/typepromotion-gep.ll
index 41421df12b22d..73b9653ca0589 100644
--- a/llvm/test/CodeGen/AArch64/typepromotion-gep.ll
+++ b/llvm/test/CodeGen/AArch64/typepromotion-gep.ll
@@ -3,23 +3,18 @@
target triple = "arm64-apple-macosx15.0.0"
-; FIXME: This is a miscompilation, unused trunc is converted to used zext for gep offset,
-; which is to be treated as signed.
define i4 @gep_offset_signedness(ptr %ptr, i8 %offset, i1 %cond) {
; CHECK-LABEL: define i4 @gep_offset_signedness(
; CHECK-SAME: ptr [[PTR:%.*]], i8 [[OFFSET:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[TMP0:%.*]] = zext i8 [[OFFSET]] to i32
-; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 15
-; CHECK-NEXT: [[PTR_IDX:%.*]] = getelementptr i8, ptr [[PTR]], i32 [[TMP0]]
+; CHECK-NEXT: [[PTR_IDX:%.*]] = getelementptr i8, ptr [[PTR]], i8 [[OFFSET]]
; CHECK-NEXT: [[COND_2:%.*]] = icmp uge ptr [[PTR_IDX]], [[PTR]]
; CHECK-NEXT: br i1 [[COND_2]], label %[[RETURN:.*]], label %[[ELSE:.*]]
; CHECK: [[RETURN]]:
; CHECK-NEXT: [[RET_VAL:%.*]] = phi i4 [ 0, %[[ELSE_RET:.*]] ], [ 1, %[[ENTRY]] ], [ 0, %[[ELSE]] ]
; CHECK-NEXT: ret i4 [[RET_VAL]]
; CHECK: [[ELSE]]:
-; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 0, 0
-; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[ADD]], [[TMP0]]
+; CHECK-NEXT: [[ADD:%.*]] = add nuw i8 0, 0
; CHECK-NEXT: br i1 [[COND]], label %[[RETURN]], label %[[ELSE_RET]]
; CHECK: [[ELSE_RET]]:
; CHECK-NEXT: br label %[[RETURN]]
diff --git a/llvm/test/CodeGen/AArch64/typepromotion-phisret.ll b/llvm/test/CodeGen/AArch64/typepromotion-phisret.ll
index d60578b7bafe4..a9164312b99cc 100644
--- a/llvm/test/CodeGen/AArch64/typepromotion-phisret.ll
+++ b/llvm/test/CodeGen/AArch64/typepromotion-phisret.ll
@@ -237,25 +237,27 @@ define i16 @promote_arg_return(i16 zeroext %arg1, i16 zeroext %arg2, ptr %res) {
define i16 @signext_bitcast_phi_select(i16 signext %start, ptr %in) {
; CHECK-LABEL: signext_bitcast_phi_select:
; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: mov w8, #-1 // =0xffffffff
-; CHECK-NEXT: and w9, w0, #0xffff
-; CHECK-NEXT: cmp w8, w9, sxth
+; CHECK-NEXT: mov w9, #-1 // =0xffffffff
+; CHECK-NEXT: mov w10, #32768 // =0x8000
+; CHECK-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT: cmp w9, w0, sxth
; CHECK-NEXT: b.lt .LBB6_3
; CHECK-NEXT: .LBB6_1: // %if.then
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
-; CHECK-NEXT: ldrh w0, [x1, w9, sxtw #1]
-; CHECK-NEXT: cmp w0, w9
+; CHECK-NEXT: sxth x8, w0
+; CHECK-NEXT: ldrh w8, [x1, x8, lsl #1]
+; CHECK-NEXT: cmp w8, w0, uxth
; CHECK-NEXT: b.eq .LBB6_4
; CHECK-NEXT: // %bb.2: // %if.else
; CHECK-NEXT: // in Loop: Header=BB6_1 Depth=1
-; CHECK-NEXT: lsr w10, w9, #15
-; CHECK-NEXT: eor w10, w10, #0x1
-; CHECK-NEXT: add w9, w10, w9
-; CHECK-NEXT: cmp w8, w9, sxth
+; CHECK-NEXT: bic w8, w10, w0
+; CHECK-NEXT: add w0, w0, w8, lsr #15
+; CHECK-NEXT: cmp w9, w0, sxth
; CHECK-NEXT: b.ge .LBB6_1
; CHECK-NEXT: .LBB6_3:
-; CHECK-NEXT: mov w0, wzr
+; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: .LBB6_4: // %exit
+; CHECK-NEXT: mov w0, w8
; CHECK-NEXT: ret
entry:
%const = bitcast i16 -1 to i16
diff --git a/llvm/test/Transforms/TypePromotion/ARM/phis-ret.ll b/llvm/test/Transforms/TypePromotion/ARM/phis-ret.ll
index 6f41742e66e53..d3ba82460a18a 100644
--- a/llvm/test/Transforms/TypePromotion/ARM/phis-ret.ll
+++ b/llvm/test/Transforms/TypePromotion/ARM/phis-ret.ll
@@ -293,28 +293,24 @@ define i16 @promote_arg_return(i16 zeroext %arg1, i16 zeroext %arg2, ptr %res) {
define i16 @signext_bitcast_phi_select(i16 signext %start, ptr %in) {
; CHECK-LABEL: @signext_bitcast_phi_select(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[TMP0:%.*]] = zext i16 [[START:%.*]] to i32
; CHECK-NEXT: [[CONST:%.*]] = bitcast i16 -1 to i16
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
-; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[SELECT:%.*]], [[IF_ELSE:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[IDX]] to i16
+; CHECK-NEXT: [[TMP1:%.*]] = phi i16 [ [[SELECT:%.*]], [[IF_ELSE:%.*]] ], [ [[START:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[CMP_I:%.*]] = icmp sgt i16 [[TMP1]], [[CONST]]
; CHECK-NEXT: br i1 [[CMP_I]], label [[EXIT:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: [[IDX_NEXT:%.*]] = getelementptr i16, ptr [[IN:%.*]], i32 [[IDX]]
+; CHECK-NEXT: [[IDX_NEXT:%.*]] = getelementptr i16, ptr [[IN:%.*]], i16 [[TMP1]]
; CHECK-NEXT: [[LD:%.*]] = load i16, ptr [[IDX_NEXT]], align 2
-; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[LD]] to i32
-; CHECK-NEXT: [[CMP1_I:%.*]] = icmp eq i32 [[TMP2]], [[IDX]]
+; CHECK-NEXT: [[CMP1_I:%.*]] = icmp eq i16 [[LD]], [[TMP1]]
; CHECK-NEXT: br i1 [[CMP1_I]], label [[EXIT]], label [[IF_ELSE]]
; CHECK: if.else:
-; CHECK-NEXT: [[LOBIT:%.*]] = lshr i32 [[IDX]], 15
-; CHECK-NEXT: [[LOBIT_NOT:%.*]] = xor i32 [[LOBIT]], 1
-; CHECK-NEXT: [[SELECT]] = add nuw i32 [[LOBIT_NOT]], [[IDX]]
+; CHECK-NEXT: [[LOBIT:%.*]] = lshr i16 [[TMP1]], 15
+; CHECK-NEXT: [[LOBIT_NOT:%.*]] = xor i16 [[LOBIT]], 1
+; CHECK-NEXT: [[SELECT]] = add nuw i16 [[LOBIT_NOT]], [[TMP1]]
; CHECK-NEXT: br label [[FOR_BODY]]
; CHECK: exit:
-; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[TMP2]], [[IF_THEN]] ], [ 0, [[FOR_BODY]] ]
-; CHECK-NEXT: [[TMP3:%.*]] = trunc i32 [[RES]] to i16
+; CHECK-NEXT: [[TMP3:%.*]] = phi i16 [ [[LD]], [[IF_THEN]] ], [ 0, [[FOR_BODY]] ]
; CHECK-NEXT: ret i16 [[TMP3]]
;
entry:
diff --git a/llvm/test/Transforms/TypePromotion/ARM/pointers.ll b/llvm/test/Transforms/TypePromotion/ARM/pointers.ll
index 362b4ec73401c..187fc8b7267b8 100644
--- a/llvm/test/Transforms/TypePromotion/ARM/pointers.ll
+++ b/llvm/test/Transforms/TypePromotion/ARM/pointers.ll
@@ -4,20 +4,18 @@
define void @phi_pointers(ptr %a, ptr %b, i8 zeroext %M, i8 zeroext %N) {
; CHECK-LABEL: @phi_pointers(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[TMP0:%.*]] = zext i8 [[M:%.*]] to i32
-; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[N:%.*]] to i32
-; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[TMP0]], 1
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[ADD]], [[TMP1]]
+; CHECK-NEXT: [[ADD:%.*]] = add nuw i8 [[M:%.*]], 1
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[ADD]], 1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[ADD]], [[N:%.*]]
; CHECK-NEXT: [[BASE:%.*]] = select i1 [[CMP]], ptr [[A:%.*]], ptr [[B:%.*]]
; CHECK-NEXT: [[OTHER:%.*]] = select i1 [[CMP]], ptr [[B]], ptr [[B]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[BASE]], [[ENTRY:%.*]] ], [ [[GEP:%.*]], [[LOOP]] ]
-; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[AND]], [[ENTRY]] ], [ [[INC:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[AND]], [[ENTRY]] ], [ [[INC:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[LOAD:%.*]] = load i16, ptr [[PTR]], align 2
-; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IDX]], 1
-; CHECK-NEXT: [[GEP]] = getelementptr inbounds i16, ptr [[PTR]], i32 [[INC]]
+; CHECK-NEXT: [[INC]] = add nuw nsw i8 [[IDX]], 1
+; CHECK-NEXT: [[GEP]] = getelementptr inbounds i16, ptr [[PTR]], i8 [[INC]]
; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr [[GEP]], [[OTHER]]
; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
; CHECK: exit:
@@ -47,11 +45,9 @@ exit:
define void @phi_pointers_null(ptr %a, ptr %b, i8 zeroext %M, i8 zeroext %N) {
; CHECK-LABEL: @phi_pointers_null(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[TMP0:%.*]] = zext i8 [[M:%.*]] to i32
-; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[N:%.*]] to i32
-; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[TMP0]], 1
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[ADD]], [[TMP1]]
+; CHECK-NEXT: [[ADD:%.*]] = add nuw i8 [[M:%.*]], 1
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[ADD]], 1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[ADD]], [[N:%.*]]
; CHECK-NEXT: [[BASE:%.*]] = select i1 [[CMP]], ptr [[A:%.*]], ptr [[B:%.*]]
; CHECK-NEXT: [[OTHER:%.*]] = select i1 [[CMP]], ptr [[B]], ptr [[B]]
; CHECK-NEXT: [[CMP_1:%.*]] = icmp eq ptr [[BASE]], [[OTHER]]
@@ -60,13 +56,13 @@ define void @phi_pointers_null(ptr %a, ptr %b, i8 zeroext %M, i8 zeroext %N) {
; CHECK-NEXT: br label [[LOOP]]
; CHECK: loop:
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[BASE]], [[ENTRY:%.*]] ], [ null, [[FAIL]] ], [ [[GEP:%.*]], [[IF_THEN:%.*]] ]
-; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[AND]], [[ENTRY]] ], [ 0, [[FAIL]] ], [ [[INC:%.*]], [[IF_THEN]] ]
+; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[AND]], [[ENTRY]] ], [ 0, [[FAIL]] ], [ [[INC:%.*]], [[IF_THEN]] ]
; CHECK-NEXT: [[UNDEF:%.*]] = icmp eq ptr [[PTR]], undef
; CHECK-NEXT: br i1 [[UNDEF]], label [[EXIT:%.*]], label [[IF_THEN]]
; CHECK: if.then:
; CHECK-NEXT: [[LOAD:%.*]] = load i16, ptr [[PTR]], align 2
-; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IDX]], 1
-; CHECK-NEXT: [[GEP]] = getelementptr inbounds i16, ptr [[PTR]], i32 [[INC]]
+; CHECK-NEXT: [[INC]] = add nuw nsw i8 [[IDX]], 1
+; CHECK-NEXT: [[GEP]] = getelementptr inbounds i16, ptr [[PTR]], i8 [[INC]]
; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr [[GEP]], [[OTHER]]
; CHECK-NEXT: br i1 [[COND]], label [[EXIT]], label [[LOOP]]
; CHECK: exit:
>From dd582b683df20ed454b977c16c416a77bd8e8d2f Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 4 Apr 2025 16:32:23 +0200
Subject: [PATCH 3/3] !fixup fix test
---
llvm/test/CodeGen/AArch64/typepromotion-gep.ll | 2 ++
1 file changed, 2 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/typepromotion-gep.ll b/llvm/test/CodeGen/AArch64/typepromotion-gep.ll
index 73b9653ca0589..760a913e46b31 100644
--- a/llvm/test/CodeGen/AArch64/typepromotion-gep.ll
+++ b/llvm/test/CodeGen/AArch64/typepromotion-gep.ll
@@ -7,6 +7,7 @@ define i4 @gep_offset_signedness(ptr %ptr, i8 %offset, i1 %cond) {
; CHECK-LABEL: define i4 @gep_offset_signedness(
; CHECK-SAME: ptr [[PTR:%.*]], i8 [[OFFSET:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[UNUSED_TRUNC:%.*]] = trunc i8 [[OFFSET]] to i4
; CHECK-NEXT: [[PTR_IDX:%.*]] = getelementptr i8, ptr [[PTR]], i8 [[OFFSET]]
; CHECK-NEXT: [[COND_2:%.*]] = icmp uge ptr [[PTR_IDX]], [[PTR]]
; CHECK-NEXT: br i1 [[COND_2]], label %[[RETURN:.*]], label %[[ELSE:.*]]
@@ -15,6 +16,7 @@ define i4 @gep_offset_signedness(ptr %ptr, i8 %offset, i1 %cond) {
; CHECK-NEXT: ret i4 [[RET_VAL]]
; CHECK: [[ELSE]]:
; CHECK-NEXT: [[ADD:%.*]] = add nuw i8 0, 0
+; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i8 [[ADD]], [[OFFSET]]
; CHECK-NEXT: br i1 [[COND]], label %[[RETURN]], label %[[ELSE_RET]]
; CHECK: [[ELSE_RET]]:
; CHECK-NEXT: br label %[[RETURN]]
More information about the llvm-commits
mailing list