Skip to content

Commit a719091

Browse files
authored
[InstCombine] Set flags when canonicalizing GEP indices (#151516)
When truncating set nsw/nuw based on nusw/nuw. When extending, use zext nneg if nusw+nuw. Proof: https://alive2.llvm.org/ce/z/JA2Yzr
1 parent 9ddbb47 commit a719091

File tree

8 files changed

+117
-20
lines changed

8 files changed

+117
-20
lines changed

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3184,7 +3184,16 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
31843184
// If we are using a wider index than needed for this platform, shrink
31853185
// it to what we need. If narrower, sign-extend it to what we need.
31863186
// This explicit cast can make subsequent optimizations more obvious.
3187-
*I = Builder.CreateIntCast(*I, NewIndexType, true);
3187+
if (IndexTy->getScalarSizeInBits() <
3188+
NewIndexType->getScalarSizeInBits()) {
3189+
if (GEP.hasNoUnsignedWrap() && GEP.hasNoUnsignedSignedWrap())
3190+
*I = Builder.CreateZExt(*I, NewIndexType, "", /*IsNonNeg=*/true);
3191+
else
3192+
*I = Builder.CreateSExt(*I, NewIndexType);
3193+
} else {
3194+
*I = Builder.CreateTrunc(*I, NewIndexType, "", GEP.hasNoUnsignedWrap(),
3195+
GEP.hasNoUnsignedSignedWrap());
3196+
}
31883197
MadeChange = true;
31893198
}
31903199
}

llvm/test/Transforms/InstCombine/getelementptr.ll

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ define i1 @test13_i16(i16 %X, ptr %P) {
356356

357357
define i1 @test13_i128(i128 %X, ptr %P) {
358358
; CHECK-LABEL: @test13_i128(
359-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i128 [[X:%.*]] to i64
359+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i128 [[X:%.*]] to i64
360360
; CHECK-NEXT: [[C:%.*]] = icmp eq i64 [[TMP1]], -1
361361
; CHECK-NEXT: ret i1 [[C]]
362362
;
@@ -412,7 +412,7 @@ define ptr @test_index_canon_inbounds(ptr %X, i32 %Idx) {
412412

413413
define ptr @test_index_canon_nusw_nuw(ptr %X, i32 %Idx) {
414414
; CHECK-LABEL: @test_index_canon_nusw_nuw(
415-
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[IDX:%.*]] to i64
415+
; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[IDX:%.*]] to i64
416416
; CHECK-NEXT: [[R:%.*]] = getelementptr nusw nuw i32, ptr [[X:%.*]], i64 [[TMP1]]
417417
; CHECK-NEXT: ret ptr [[R]]
418418
;
@@ -568,7 +568,7 @@ define i32 @test20(ptr %P, i32 %A, i32 %B) {
568568

569569
define i32 @test20_as1(ptr addrspace(1) %P, i32 %A, i32 %B) {
570570
; CHECK-LABEL: @test20_as1(
571-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[A:%.*]] to i16
571+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i32 [[A:%.*]] to i16
572572
; CHECK-NEXT: [[T6:%.*]] = icmp eq i16 [[TMP1]], 0
573573
; CHECK-NEXT: [[T7:%.*]] = zext i1 [[T6]] to i32
574574
; CHECK-NEXT: ret i32 [[T7]]
@@ -1978,4 +1978,94 @@ define ptr @gep_merge_nusw_const(ptr %p, i64 %idx, i64 %idx2) {
19781978
ret ptr %gep
19791979
}
19801980

1981+
define ptr @gep_index_trunc_nothing(ptr %p, i128 %idx) {
1982+
; CHECK-LABEL: @gep_index_trunc_nothing(
1983+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i128 [[IDX:%.*]] to i64
1984+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[TMP1]]
1985+
; CHECK-NEXT: ret ptr [[GEP]]
1986+
;
1987+
%gep = getelementptr i8, ptr %p, i128 %idx
1988+
ret ptr %gep
1989+
}
1990+
1991+
define ptr @gep_index_trunc_nuw(ptr %p, i128 %idx) {
1992+
; CHECK-LABEL: @gep_index_trunc_nuw(
1993+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nuw i128 [[IDX:%.*]] to i64
1994+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P:%.*]], i64 [[TMP1]]
1995+
; CHECK-NEXT: ret ptr [[GEP]]
1996+
;
1997+
%gep = getelementptr nuw i8, ptr %p, i128 %idx
1998+
ret ptr %gep
1999+
}
2000+
2001+
define ptr @gep_index_trunc_nusw(ptr %p, i128 %idx) {
2002+
; CHECK-LABEL: @gep_index_trunc_nusw(
2003+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i128 [[IDX:%.*]] to i64
2004+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw i8, ptr [[P:%.*]], i64 [[TMP1]]
2005+
; CHECK-NEXT: ret ptr [[GEP]]
2006+
;
2007+
%gep = getelementptr nusw i8, ptr %p, i128 %idx
2008+
ret ptr %gep
2009+
}
2010+
2011+
define ptr @gep_index_trunc_inbounds(ptr %p, i128 %idx) {
2012+
; CHECK-LABEL: @gep_index_trunc_inbounds(
2013+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i128 [[IDX:%.*]] to i64
2014+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 [[TMP1]]
2015+
; CHECK-NEXT: ret ptr [[GEP]]
2016+
;
2017+
%gep = getelementptr inbounds i8, ptr %p, i128 %idx
2018+
ret ptr %gep
2019+
}
2020+
2021+
define ptr @gep_index_trunc_nusw_nuw(ptr %p, i128 %idx) {
2022+
; CHECK-LABEL: @gep_index_trunc_nusw_nuw(
2023+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nuw nsw i128 [[IDX:%.*]] to i64
2024+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw nuw i8, ptr [[P:%.*]], i64 [[TMP1]]
2025+
; CHECK-NEXT: ret ptr [[GEP]]
2026+
;
2027+
%gep = getelementptr nusw nuw i8, ptr %p, i128 %idx
2028+
ret ptr %gep
2029+
}
2030+
2031+
define ptr @gep_index_ext_nothing(ptr %p, i32 %idx) {
2032+
; CHECK-LABEL: @gep_index_ext_nothing(
2033+
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[IDX:%.*]] to i64
2034+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[TMP1]]
2035+
; CHECK-NEXT: ret ptr [[GEP]]
2036+
;
2037+
%gep = getelementptr i8, ptr %p, i32 %idx
2038+
ret ptr %gep
2039+
}
2040+
2041+
define ptr @gep_index_ext_nuw(ptr %p, i32 %idx) {
2042+
; CHECK-LABEL: @gep_index_ext_nuw(
2043+
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[IDX:%.*]] to i64
2044+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P:%.*]], i64 [[TMP1]]
2045+
; CHECK-NEXT: ret ptr [[GEP]]
2046+
;
2047+
%gep = getelementptr nuw i8, ptr %p, i32 %idx
2048+
ret ptr %gep
2049+
}
2050+
2051+
define ptr @gep_index_ext_nusw(ptr %p, i32 %idx) {
2052+
; CHECK-LABEL: @gep_index_ext_nusw(
2053+
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[IDX:%.*]] to i64
2054+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P:%.*]], i64 [[TMP1]]
2055+
; CHECK-NEXT: ret ptr [[GEP]]
2056+
;
2057+
%gep = getelementptr nuw i8, ptr %p, i32 %idx
2058+
ret ptr %gep
2059+
}
2060+
2061+
define ptr @gep_index_ext_nusw_nuw(ptr %p, i32 %idx) {
2062+
; CHECK-LABEL: @gep_index_ext_nusw_nuw(
2063+
; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[IDX:%.*]] to i64
2064+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw nuw i8, ptr [[P:%.*]], i64 [[TMP1]]
2065+
; CHECK-NEXT: ret ptr [[GEP]]
2066+
;
2067+
%gep = getelementptr nusw nuw i8, ptr %p, i32 %idx
2068+
ret ptr %gep
2069+
}
2070+
19812071
!0 = !{!"branch_weights", i32 2, i32 10}

llvm/test/Transforms/InstCombine/icmp-custom-dl.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ define i1 @test59_as1(ptr addrspace(1) %foo) {
3939

4040
define i1 @test60(ptr %foo, i64 %i, i64 %j) {
4141
; CHECK-LABEL: @test60(
42-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i32
42+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i64 [[I:%.*]] to i32
4343
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i32 [[TMP1]], 2
44-
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i32
44+
; CHECK-NEXT: [[TMP2:%.*]] = trunc nsw i64 [[J:%.*]] to i32
4545
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[GEP1_IDX]], [[TMP2]]
4646
; CHECK-NEXT: ret i1 [[CMP]]
4747
;
@@ -53,9 +53,9 @@ define i1 @test60(ptr %foo, i64 %i, i64 %j) {
5353

5454
define i1 @test60_as1(ptr addrspace(1) %foo, i64 %i, i64 %j) {
5555
; CHECK-LABEL: @test60_as1(
56-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i16
56+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i64 [[I:%.*]] to i16
5757
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i16 [[TMP1]], 2
58-
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i16
58+
; CHECK-NEXT: [[TMP2:%.*]] = trunc nsw i64 [[J:%.*]] to i16
5959
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[GEP1_IDX]], [[TMP2]]
6060
; CHECK-NEXT: ret i1 [[CMP]]
6161
;
@@ -69,7 +69,7 @@ define i1 @test60_as1(ptr addrspace(1) %foo, i64 %i, i64 %j) {
6969
; bitcast. This uses the same sized addrspace.
7070
define i1 @test60_addrspacecast(ptr %foo, i64 %i, i64 %j) {
7171
; CHECK-LABEL: @test60_addrspacecast(
72-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[J:%.*]] to i32
72+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i64 [[J:%.*]] to i32
7373
; CHECK-NEXT: [[I_TR:%.*]] = trunc i64 [[I:%.*]] to i32
7474
; CHECK-NEXT: [[TMP2:%.*]] = shl i32 [[I_TR]], 2
7575
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP2]], [[TMP1]]

llvm/test/Transforms/InstCombine/icmp-gep.ll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,7 @@ define i1 @PR8882(i64 %i) {
286286

287287
define i1 @test24_as1(i64 %i) {
288288
; CHECK-LABEL: @test24_as1(
289-
; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[I:%.*]], 65535
290-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[TMP1]], 1000
289+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[TMP1:%.*]], 1000
291290
; CHECK-NEXT: ret i1 [[CMP]]
292291
;
293292
%p1 = getelementptr inbounds i32, ptr addrspace(1) @X_as1, i64 %i
@@ -449,9 +448,9 @@ define i1 @test_gep_eq_no_inbounds(ptr %foo, i64 %i, i64 %j) {
449448

450449
define i1 @test60_as1(ptr addrspace(1) %foo, i64 %i, i64 %j) {
451450
; CHECK-LABEL: @test60_as1(
452-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i16
451+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i64 [[I:%.*]] to i16
453452
; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i16 [[TMP1]], 2
454-
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i16
453+
; CHECK-NEXT: [[TMP2:%.*]] = trunc nsw i64 [[J:%.*]] to i16
455454
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[GEP1_IDX]], [[TMP2]]
456455
; CHECK-NEXT: ret i1 [[CMP]]
457456
;

llvm/test/Transforms/InstCombine/indexed-gep-compares.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ define i1 @test8(ptr %in, i64 %offset) {
376376
; CHECK-NEXT: [[LD:%.*]] = load i64, ptr [[IN:%.*]], align 8
377377
; CHECK-NEXT: [[TMP0:%.*]] = trunc i64 [[LD]] to i32
378378
; CHECK-NEXT: [[CASTI8:%.*]] = inttoptr i32 [[TMP0]] to ptr
379-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[OFFSET:%.*]] to i32
379+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i64 [[OFFSET:%.*]] to i32
380380
; CHECK-NEXT: [[GEPI8:%.*]] = getelementptr inbounds i8, ptr [[CASTI8]], i32 [[TMP1]]
381381
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[LD]] to i32
382382
; CHECK-NEXT: [[PTRCAST:%.*]] = inttoptr i32 [[TMP2]] to ptr

llvm/test/Transforms/InstCombine/load-cmp.ll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,7 @@ define i1 @test10_struct_arr_i16(i16 %x) {
293293

294294
define i1 @test10_struct_arr_i64(i64 %x) {
295295
; CHECK-LABEL: @test10_struct_arr_i64(
296-
; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[X:%.*]], 4294967295
297-
; CHECK-NEXT: [[R:%.*]] = icmp ne i64 [[TMP1]], 1
296+
; CHECK-NEXT: [[R:%.*]] = icmp ne i64 [[TMP1:%.*]], 1
298297
; CHECK-NEXT: ret i1 [[R]]
299298
;
300299
%p = getelementptr inbounds [4 x %Foo], ptr @GStructArr, i64 0, i64 %x, i32 2
@@ -331,7 +330,7 @@ define i1 @test10_struct_arr_noinbounds_i64(i64 %x) {
331330

332331
define i1 @pr93017(i64 %idx) {
333332
; CHECK-LABEL: @pr93017(
334-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[IDX:%.*]] to i32
333+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i64 [[IDX:%.*]] to i32
335334
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @table, i32 0, i32 [[TMP1]]
336335
; CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[GEP]], align 4
337336
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[V]], null

llvm/test/Transforms/InstCombine/pr39908.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ define i1 @test(ptr %p, i32 %n) {
1919
; Same test using 64-bit indices.
2020
define i1 @test64(ptr %p, i64 %n) {
2121
; CHECK-LABEL: @test64(
22-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[N:%.*]] to i32
22+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i64 [[N:%.*]] to i32
2323
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 1
2424
; CHECK-NEXT: ret i1 [[CMP]]
2525
;
@@ -32,7 +32,7 @@ define i1 @test64(ptr %p, i64 %n) {
3232
; Here the offset overflows and is treated modulo 2^32. This is UB.
3333
define i1 @test64_overflow(ptr %p, i64 %n) {
3434
; CHECK-LABEL: @test64_overflow(
35-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[N:%.*]] to i32
35+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i64 [[N:%.*]] to i32
3636
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 1
3737
; CHECK-NEXT: ret i1 [[CMP]]
3838
;

llvm/test/Transforms/InstCombine/sub-gep.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ define i64 @negative_ptrtoint_sub_zext_ptrtoint(ptr %p, i32 %offset) {
394394

395395
define i16 @test25_as1(ptr addrspace(1) %P, i64 %A) {
396396
; CHECK-LABEL: @test25_as1(
397-
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[A:%.*]] to i16
397+
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i64 [[A:%.*]] to i16
398398
; CHECK-NEXT: [[B_IDX:%.*]] = shl nsw i16 [[TMP1]], 1
399399
; CHECK-NEXT: [[GEPDIFF:%.*]] = add nsw i16 [[B_IDX]], -84
400400
; CHECK-NEXT: ret i16 [[GEPDIFF]]

0 commit comments

Comments
 (0)