253 changes: 177 additions & 76 deletions llvm/test/Analysis/BasicAA/featuretest.ll
Original file line number Diff line number Diff line change
@@ -1,127 +1,228 @@
; This testcase tests for various features the basicaa test should be able to
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; This testcase tests for various features the basicaa test should be able to
; determine, as noted in the comments.

; RUN: opt < %s -basicaa -gvn -instcombine -dce -S | FileCheck %s
; RUN: opt < %s -basicaa -gvn -instcombine -dce -S | FileCheck %s --check-prefixes=CHECK,NO_ASSUME
; RUN: opt < %s -basicaa -gvn -instcombine -dce --enable-knowledge-retention -S | FileCheck %s --check-prefixes=CHECK,USE_ASSUME
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"

@Global = external global { i32 }

declare void @external(i32*)
declare void @llvm.assume(i1)

; Array test: Test that operations on one local array do not invalidate
; Array test: Test that operations on one local array do not invalidate
; operations on another array. Important for scientific codes.
;
define i32 @different_array_test(i64 %A, i64 %B) {
%Array1 = alloca i32, i32 100
%Array2 = alloca i32, i32 200

call void @external(i32* %Array1)
call void @external(i32* %Array2)

%pointer = getelementptr i32, i32* %Array1, i64 %A
%val = load i32, i32* %pointer

%pointer2 = getelementptr i32, i32* %Array2, i64 %B
store i32 7, i32* %pointer2

%REMOVE = load i32, i32* %pointer ; redundant with above load
%retval = sub i32 %REMOVE, %val
ret i32 %retval
; CHECK: @different_array_test
; CHECK: ret i32 0
; NO_ASSUME-LABEL: @different_array_test(
; NO_ASSUME-NEXT: [[ARRAY11:%.*]] = alloca [100 x i32], align 4
; NO_ASSUME-NEXT: [[ARRAY22:%.*]] = alloca [200 x i32], align 4
; NO_ASSUME-NEXT: [[ARRAY22_SUB:%.*]] = getelementptr inbounds [200 x i32], [200 x i32]* [[ARRAY22]], i64 0, i64 0
; NO_ASSUME-NEXT: [[ARRAY11_SUB:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY11]], i64 0, i64 0
; NO_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[ARRAY11_SUB]], i32 4) ]
; NO_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY11_SUB]])
; NO_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY22_SUB]])
; NO_ASSUME-NEXT: [[POINTER2:%.*]] = getelementptr [200 x i32], [200 x i32]* [[ARRAY22]], i64 0, i64 [[B:%.*]]
; NO_ASSUME-NEXT: store i32 7, i32* [[POINTER2]], align 4
; NO_ASSUME-NEXT: ret i32 0
;
; USE_ASSUME-LABEL: @different_array_test(
; USE_ASSUME-NEXT: [[ARRAY11:%.*]] = alloca [100 x i32], align 4
; USE_ASSUME-NEXT: [[ARRAY22:%.*]] = alloca [200 x i32], align 4
; USE_ASSUME-NEXT: [[ARRAY22_SUB:%.*]] = getelementptr inbounds [200 x i32], [200 x i32]* [[ARRAY22]], i64 0, i64 0
; USE_ASSUME-NEXT: [[ARRAY11_SUB:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY11]], i64 0, i64 0
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[ARRAY11_SUB]], i32 4) ]
; USE_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY11_SUB]])
; USE_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY22_SUB]])
; USE_ASSUME-NEXT: [[POINTER:%.*]] = getelementptr [100 x i32], [100 x i32]* [[ARRAY11]], i64 0, i64 [[A:%.*]]
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[POINTER]], i64 4), "nonnull"(i32* [[POINTER]]) ]
; USE_ASSUME-NEXT: [[POINTER2:%.*]] = getelementptr [200 x i32], [200 x i32]* [[ARRAY22]], i64 0, i64 [[B:%.*]]
; USE_ASSUME-NEXT: store i32 7, i32* [[POINTER2]], align 4
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[POINTER]], i64 4), "nonnull"(i32* [[POINTER]]) ]
; USE_ASSUME-NEXT: ret i32 0
;
%Array1 = alloca i32, i32 100
%Array2 = alloca i32, i32 200
call void @llvm.assume(i1 true) ["align"(i32* %Array1, i32 4)]

call void @external(i32* %Array1)
call void @external(i32* %Array2)

%pointer = getelementptr i32, i32* %Array1, i64 %A
%val = load i32, i32* %pointer

%pointer2 = getelementptr i32, i32* %Array2, i64 %B
store i32 7, i32* %pointer2

%REMOVE = load i32, i32* %pointer ; redundant with above load
%retval = sub i32 %REMOVE, %val
ret i32 %retval
}

; Constant index test: Constant indexes into the same array should not
; Constant index test: Constant indexes into the same array should not
; interfere with each other. Again, important for scientific codes.
;
define i32 @constant_array_index_test() {
%Array = alloca i32, i32 100
call void @external(i32* %Array)

%P1 = getelementptr i32, i32* %Array, i64 7
%P2 = getelementptr i32, i32* %Array, i64 6

%A = load i32, i32* %P1
store i32 1, i32* %P2 ; Should not invalidate load
%BREMOVE = load i32, i32* %P1
%Val = sub i32 %A, %BREMOVE
ret i32 %Val
; CHECK: @constant_array_index_test
; CHECK: ret i32 0
; NO_ASSUME-LABEL: @constant_array_index_test(
; NO_ASSUME-NEXT: [[ARRAY1:%.*]] = alloca [100 x i32], align 4
; NO_ASSUME-NEXT: [[ARRAY1_SUB:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 0
; NO_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY1_SUB]])
; NO_ASSUME-NEXT: [[P2:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 6
; NO_ASSUME-NEXT: store i32 1, i32* [[P2]], align 4
; NO_ASSUME-NEXT: ret i32 0
;
; USE_ASSUME-LABEL: @constant_array_index_test(
; USE_ASSUME-NEXT: [[ARRAY1:%.*]] = alloca [100 x i32], align 4
; USE_ASSUME-NEXT: [[ARRAY1_SUB:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 0
; USE_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY1_SUB]])
; USE_ASSUME-NEXT: [[P1:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 7
; USE_ASSUME-NEXT: [[P2:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 6
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
; USE_ASSUME-NEXT: store i32 1, i32* [[P2]], align 4
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
; USE_ASSUME-NEXT: ret i32 0
;
%Array = alloca i32, i32 100
call void @external(i32* %Array)

%P1 = getelementptr i32, i32* %Array, i64 7
%P2 = getelementptr i32, i32* %Array, i64 6

%A = load i32, i32* %P1
store i32 1, i32* %P2 ; Should not invalidate load
%BREMOVE = load i32, i32* %P1
%Val = sub i32 %A, %BREMOVE
ret i32 %Val
}

; Test that if two pointers are spaced out by a constant getelementptr, that
; Test that if two pointers are spaced out by a constant getelementptr, that
; they cannot alias.
define i32 @gep_distance_test(i32* %A) {
%REMOVEu = load i32, i32* %A
%B = getelementptr i32, i32* %A, i64 2 ; Cannot alias A
store i32 7, i32* %B
%REMOVEv = load i32, i32* %A
%r = sub i32 %REMOVEu, %REMOVEv
ret i32 %r
; CHECK: @gep_distance_test
; CHECK: ret i32 0
; NO_ASSUME-LABEL: @gep_distance_test(
; NO_ASSUME-NEXT: [[B:%.*]] = getelementptr i32, i32* [[A:%.*]], i64 2
; NO_ASSUME-NEXT: store i32 7, i32* [[B]], align 4
; NO_ASSUME-NEXT: ret i32 0
;
; USE_ASSUME-LABEL: @gep_distance_test(
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A:%.*]], i64 4), "nonnull"(i32* [[A]]) ]
; USE_ASSUME-NEXT: [[B:%.*]] = getelementptr i32, i32* [[A]], i64 2
; USE_ASSUME-NEXT: store i32 7, i32* [[B]], align 4
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A]], i64 4), "nonnull"(i32* [[A]]) ]
; USE_ASSUME-NEXT: ret i32 0
;
%REMOVEu = load i32, i32* %A
%B = getelementptr i32, i32* %A, i64 2 ; Cannot alias A
store i32 7, i32* %B
%REMOVEv = load i32, i32* %A
%r = sub i32 %REMOVEu, %REMOVEv
ret i32 %r
}

; Test that if two pointers are spaced out by a constant offset, that they
; cannot alias, even if there is a variable offset between them...
define i32 @gep_distance_test2({i32,i32}* %A, i64 %distance) {
%A1 = getelementptr {i32,i32}, {i32,i32}* %A, i64 0, i32 0
%REMOVEu = load i32, i32* %A1
%B = getelementptr {i32,i32}, {i32,i32}* %A, i64 %distance, i32 1
store i32 7, i32* %B ; B cannot alias A, it's at least 4 bytes away
%REMOVEv = load i32, i32* %A1
%r = sub i32 %REMOVEu, %REMOVEv
ret i32 %r
; CHECK: @gep_distance_test2
; CHECK: ret i32 0
; NO_ASSUME-LABEL: @gep_distance_test2(
; NO_ASSUME-NEXT: [[B:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[A:%.*]], i64 [[DISTANCE:%.*]], i32 1
; NO_ASSUME-NEXT: store i32 7, i32* [[B]], align 4
; NO_ASSUME-NEXT: ret i32 0
;
; USE_ASSUME-LABEL: @gep_distance_test2(
; USE_ASSUME-NEXT: [[A1:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[A:%.*]], i64 0, i32 0
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A1]], i64 4), "nonnull"(i32* [[A1]]) ]
; USE_ASSUME-NEXT: [[B:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[A]], i64 [[DISTANCE:%.*]], i32 1
; USE_ASSUME-NEXT: store i32 7, i32* [[B]], align 4
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A1]], i64 4), "nonnull"(i32* [[A1]]) ]
; USE_ASSUME-NEXT: ret i32 0
;
%A1 = getelementptr {i32,i32}, {i32,i32}* %A, i64 0, i32 0
%REMOVEu = load i32, i32* %A1
%B = getelementptr {i32,i32}, {i32,i32}* %A, i64 %distance, i32 1
store i32 7, i32* %B ; B cannot alias A, it's at least 4 bytes away
%REMOVEv = load i32, i32* %A1
%r = sub i32 %REMOVEu, %REMOVEv
ret i32 %r
}

; Test that we can do funny pointer things and that distance calc will still
; Test that we can do funny pointer things and that distance calc will still
; work.
define i32 @gep_distance_test3(i32 * %A) {
%X = load i32, i32* %A
%B = bitcast i32* %A to i8*
%C = getelementptr i8, i8* %B, i64 4
store i8 42, i8* %C
%Y = load i32, i32* %A
%R = sub i32 %X, %Y
ret i32 %R
; CHECK: @gep_distance_test3
; CHECK: ret i32 0
; NO_ASSUME-LABEL: @gep_distance_test3(
; NO_ASSUME-NEXT: [[C1:%.*]] = getelementptr i32, i32* [[A:%.*]], i64 1
; NO_ASSUME-NEXT: [[C:%.*]] = bitcast i32* [[C1]] to i8*
; NO_ASSUME-NEXT: store i8 42, i8* [[C]], align 1
; NO_ASSUME-NEXT: ret i32 0
;
; USE_ASSUME-LABEL: @gep_distance_test3(
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A:%.*]], i64 4), "nonnull"(i32* [[A]]) ]
; USE_ASSUME-NEXT: [[C1:%.*]] = getelementptr i32, i32* [[A]], i64 1
; USE_ASSUME-NEXT: [[C:%.*]] = bitcast i32* [[C1]] to i8*
; USE_ASSUME-NEXT: store i8 42, i8* [[C]], align 1
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A]], i64 4), "nonnull"(i32* [[A]]) ]
; USE_ASSUME-NEXT: ret i32 0
;
%X = load i32, i32* %A
%B = bitcast i32* %A to i8*
%C = getelementptr i8, i8* %B, i64 4
store i8 42, i8* %C
%Y = load i32, i32* %A
%R = sub i32 %X, %Y
ret i32 %R
}

; Test that we can disambiguate globals reached through constantexpr geps
define i32 @constexpr_test() {
%X = alloca i32
call void @external(i32* %X)

%Y = load i32, i32* %X
store i32 5, i32* getelementptr ({ i32 }, { i32 }* @Global, i64 0, i32 0)
%REMOVE = load i32, i32* %X
%retval = sub i32 %Y, %REMOVE
ret i32 %retval
; CHECK: @constexpr_test
; CHECK: ret i32 0
; NO_ASSUME-LABEL: @constexpr_test(
; NO_ASSUME-NEXT: [[X:%.*]] = alloca i32, align 4
; NO_ASSUME-NEXT: call void @external(i32* nonnull [[X]])
; NO_ASSUME-NEXT: store i32 5, i32* getelementptr inbounds ({ i32 }, { i32 }* @Global, i64 0, i32 0), align 4
; NO_ASSUME-NEXT: ret i32 0
;
; USE_ASSUME-LABEL: @constexpr_test(
; USE_ASSUME-NEXT: [[X:%.*]] = alloca i32, align 4
; USE_ASSUME-NEXT: call void @external(i32* nonnull [[X]])
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[X]], i64 4), "nonnull"(i32* [[X]]) ]
; USE_ASSUME-NEXT: store i32 5, i32* getelementptr inbounds ({ i32 }, { i32 }* @Global, i64 0, i32 0), align 4
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[X]], i64 4), "nonnull"(i32* [[X]]) ]
; USE_ASSUME-NEXT: ret i32 0
;
%X = alloca i32
call void @external(i32* %X)

%Y = load i32, i32* %X
store i32 5, i32* getelementptr ({ i32 }, { i32 }* @Global, i64 0, i32 0)
%REMOVE = load i32, i32* %X
%retval = sub i32 %Y, %REMOVE
ret i32 %retval
}



; PR7589
; These two index expressions are different, this cannot be CSE'd.
define i16 @zext_sext_confusion(i16* %row2col, i5 %j) nounwind{
; CHECK-LABEL: @zext_sext_confusion(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SUM5_CAST:%.*]] = zext i5 [[J:%.*]] to i64
; CHECK-NEXT: [[P1:%.*]] = getelementptr i16, i16* [[ROW2COL:%.*]], i64 [[SUM5_CAST]]
; CHECK-NEXT: [[ROW2COL_LOAD_1_2:%.*]] = load i16, i16* [[P1]], align 1
; CHECK-NEXT: [[SUM13_CAST31:%.*]] = sext i5 [[J]] to i6
; CHECK-NEXT: [[SUM13_CAST:%.*]] = zext i6 [[SUM13_CAST31]] to i64
; CHECK-NEXT: [[P2:%.*]] = getelementptr i16, i16* [[ROW2COL]], i64 [[SUM13_CAST]]
; CHECK-NEXT: [[ROW2COL_LOAD_1_6:%.*]] = load i16, i16* [[P2]], align 1
; CHECK-NEXT: [[DOTRET:%.*]] = sub i16 [[ROW2COL_LOAD_1_6]], [[ROW2COL_LOAD_1_2]]
; CHECK-NEXT: ret i16 [[DOTRET]]
;
entry:
%sum5.cast = zext i5 %j to i64 ; <i64> [#uses=1]
%P1 = getelementptr i16, i16* %row2col, i64 %sum5.cast
%row2col.load.1.2 = load i16, i16* %P1, align 1 ; <i16> [#uses=1]

%sum13.cast31 = sext i5 %j to i6 ; <i6> [#uses=1]
%sum13.cast = zext i6 %sum13.cast31 to i64 ; <i64> [#uses=1]
%P2 = getelementptr i16, i16* %row2col, i64 %sum13.cast
%row2col.load.1.6 = load i16, i16* %P2, align 1 ; <i16> [#uses=1]

%.ret = sub i16 %row2col.load.1.6, %row2col.load.1.2 ; <i16> [#uses=1]
ret i16 %.ret
; CHECK: @zext_sext_confusion
; CHECK: ret i16 %.ret
}
11 changes: 11 additions & 0 deletions llvm/test/Transforms/DCE/basic-preservation.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -dce -S --enable-knowledge-retention < %s | FileCheck %s

define void @test(i32* %P) {
; CHECK-LABEL: @test(
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P:%.*]], i64 4), "nonnull"(i32* [[P]]) ]
; CHECK-NEXT: ret void
;
%a = load i32, i32* %P
ret void
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -aa-pipeline=basic-aa -passes=dse -enable-dse-memoryssa -enable-knowledge-retention -S | FileCheck %s

target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"

define void @test1(i32* %Q, i32* %P) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[Q:%.*]], i64 4), "nonnull"(i32* [[Q]]) ]
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P:%.*]], i64 4), "nonnull"(i32* [[P]]) ]
; CHECK-NEXT: store i32 0, i32* [[P]]
; CHECK-NEXT: ret void
;
%DEAD = load i32, i32* %Q
store i32 %DEAD, i32* %P
store i32 0, i32* %P
ret void
}
63 changes: 60 additions & 3 deletions llvm/test/Transforms/LICM/pr23608.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
; RUN: opt -S -licm %s | FileCheck %s
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -licm %s | FileCheck %s --check-prefixes=CHECK,NO_ASSUME
; RUN: opt -S -licm --enable-knowledge-retention %s | FileCheck %s --check-prefixes=CHECK,USE_ASSUME
; ModuleID = '../pr23608.ll'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
Expand All @@ -9,6 +11,63 @@ target triple = "x86_64-unknown-linux-gnu"
@__msan_origin_tls = external thread_local(initialexec) global i32

define void @fn1() {
; NO_ASSUME-LABEL: @fn1(
; NO_ASSUME-NEXT: entry:
; NO_ASSUME-NEXT: br label [[INDIRECTGOTO:%.*]]
; NO_ASSUME: while.cond:
; NO_ASSUME-NEXT: [[TMP:%.*]] = load %struct.PyFrameObject*, %struct.PyFrameObject** @a, align 8
; NO_ASSUME-NEXT: [[F_IBLOCK:%.*]] = getelementptr inbounds [[STRUCT_PYFRAMEOBJECT:%.*]], %struct.PyFrameObject* [[TMP]], i64 0, i32 0
; NO_ASSUME-NEXT: br label [[BB2:%.*]]
; NO_ASSUME: bb:
; NO_ASSUME-NEXT: call void @__msan_warning_noreturn()
; NO_ASSUME-NEXT: unreachable
; NO_ASSUME: bb2:
; NO_ASSUME-NEXT: [[TMP4:%.*]] = ptrtoint i32* [[F_IBLOCK]] to i64
; NO_ASSUME-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[TMP4]], 0
; NO_ASSUME-NEXT: br i1 [[TOBOOL]], label [[BB13:%.*]], label [[BB15:%.*]]
; NO_ASSUME: bb13:
; NO_ASSUME-NEXT: [[F_IBLOCK_LCSSA:%.*]] = phi i32* [ [[F_IBLOCK]], [[BB2]] ]
; NO_ASSUME-NEXT: [[TMP4_LE:%.*]] = ptrtoint i32* [[F_IBLOCK_LCSSA]] to i64
; NO_ASSUME-NEXT: [[TMP8_LE:%.*]] = inttoptr i64 [[TMP4_LE]] to i32*
; NO_ASSUME-NEXT: call void @__msan_warning_noreturn()
; NO_ASSUME-NEXT: unreachable
; NO_ASSUME: bb15:
; NO_ASSUME-NEXT: br i1 [[TOBOOL]], label [[WHILE_END:%.*]], label [[WHILE_COND:%.*]]
; NO_ASSUME: while.end:
; NO_ASSUME-NEXT: ret void
; NO_ASSUME: indirectgoto:
; NO_ASSUME-NEXT: indirectbr i8* null, [label [[INDIRECTGOTO]], label %while.cond]
;
; USE_ASSUME-LABEL: @fn1(
; USE_ASSUME-NEXT: entry:
; USE_ASSUME-NEXT: br label [[INDIRECTGOTO:%.*]]
; USE_ASSUME: while.cond:
; USE_ASSUME-NEXT: [[TMP:%.*]] = load %struct.PyFrameObject*, %struct.PyFrameObject** @a, align 8
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i64* inttoptr (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665) to i64*), i64 8), "dereferenceable"(i64* inttoptr (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665) to i64*), i64 8), "nonnull"(i64* inttoptr (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665) to i64*)) ]
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* inttoptr (i64 add (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665), i64 35184372088832) to i32*), i64 8), "dereferenceable"(i32* inttoptr (i64 add (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665), i64 35184372088832) to i32*), i64 4), "nonnull"(i32* inttoptr (i64 add (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665), i64 35184372088832) to i32*)) ]
; USE_ASSUME-NEXT: [[F_IBLOCK:%.*]] = getelementptr inbounds [[STRUCT_PYFRAMEOBJECT:%.*]], %struct.PyFrameObject* [[TMP]], i64 0, i32 0
; USE_ASSUME-NEXT: br label [[BB2:%.*]]
; USE_ASSUME: bb:
; USE_ASSUME-NEXT: call void @__msan_warning_noreturn()
; USE_ASSUME-NEXT: unreachable
; USE_ASSUME: bb2:
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[F_IBLOCK]], i64 4), "dereferenceable"(i32* [[F_IBLOCK]], i64 4), "nonnull"(i32* [[F_IBLOCK]]) ]
; USE_ASSUME-NEXT: [[TMP4:%.*]] = ptrtoint i32* [[F_IBLOCK]] to i64
; USE_ASSUME-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[TMP4]], 0
; USE_ASSUME-NEXT: br i1 [[TOBOOL]], label [[BB13:%.*]], label [[BB15:%.*]]
; USE_ASSUME: bb13:
; USE_ASSUME-NEXT: [[F_IBLOCK_LCSSA:%.*]] = phi i32* [ [[F_IBLOCK]], [[BB2]] ]
; USE_ASSUME-NEXT: [[TMP4_LE:%.*]] = ptrtoint i32* [[F_IBLOCK_LCSSA]] to i64
; USE_ASSUME-NEXT: [[TMP8_LE:%.*]] = inttoptr i64 [[TMP4_LE]] to i32*
; USE_ASSUME-NEXT: call void @__msan_warning_noreturn()
; USE_ASSUME-NEXT: unreachable
; USE_ASSUME: bb15:
; USE_ASSUME-NEXT: br i1 [[TOBOOL]], label [[WHILE_END:%.*]], label [[WHILE_COND:%.*]]
; USE_ASSUME: while.end:
; USE_ASSUME-NEXT: ret void
; USE_ASSUME: indirectgoto:
; USE_ASSUME-NEXT: indirectbr i8* null, [label [[INDIRECTGOTO]], label %while.cond]
;
entry:
br label %indirectgoto

Expand All @@ -31,8 +90,6 @@ bb2: ; preds = %while.cond
br i1 %tobool, label %bb13, label %bb15

bb13: ; preds = %bb2
; CHECK-LABEL: bb13:
; CHECK: %tmp8.le = inttoptr
%.lcssa7 = phi i32* [ %tmp8, %bb2 ]
call void @__msan_warning_noreturn()
unreachable
Expand Down
41 changes: 28 additions & 13 deletions llvm/test/Transforms/NewGVN/2007-07-26-PhiErasure.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -newgvn -S | FileCheck %s
; RUN: opt < %s -newgvn -S | FileCheck %s --check-prefixes=CHECK,NO_ASSUME
; RUN: opt < %s -newgvn --enable-knowledge-retention -S | FileCheck %s --check-prefixes=CHECK,USE_ASSUME

%struct..0anon = type { i32 }
%struct.FILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, %struct.__sFILEX*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64 }
Expand All @@ -9,18 +10,32 @@
@n_spills = external global i32 ; <i32*> [#uses=2]

define i32 @reload(%struct.rtx_def* %first, i32 %global, %struct.FILE* %dumpfile) {
; CHECK-LABEL: @reload(
; CHECK-NEXT: cond_next2835.1:
; CHECK-NEXT: br label [[BB2928:%.*]]
; CHECK: bb2928:
; CHECK-NEXT: br i1 false, label [[COND_NEXT2943:%.*]], label [[COND_TRUE2935:%.*]]
; CHECK: cond_true2935:
; CHECK-NEXT: br label [[COND_NEXT2943]]
; CHECK: cond_next2943:
; CHECK-NEXT: br i1 false, label [[BB2982_PREHEADER:%.*]], label [[BB2928]]
; CHECK: bb2982.preheader:
; CHECK-NEXT: store i8 undef, i8* null
; CHECK-NEXT: ret i32 undef
; NO_ASSUME-LABEL: @reload(
; NO_ASSUME-NEXT: cond_next2835.1:
; NO_ASSUME-NEXT: br label [[BB2928:%.*]]
; NO_ASSUME: bb2928:
; NO_ASSUME-NEXT: br i1 false, label [[COND_NEXT2943:%.*]], label [[COND_TRUE2935:%.*]]
; NO_ASSUME: cond_true2935:
; NO_ASSUME-NEXT: br label [[COND_NEXT2943]]
; NO_ASSUME: cond_next2943:
; NO_ASSUME-NEXT: br i1 false, label [[BB2982_PREHEADER:%.*]], label [[BB2928]]
; NO_ASSUME: bb2982.preheader:
; NO_ASSUME-NEXT: store i8 undef, i8* null
; NO_ASSUME-NEXT: ret i32 undef
;
; USE_ASSUME-LABEL: @reload(
; USE_ASSUME-NEXT: cond_next2835.1:
; USE_ASSUME-NEXT: br label [[BB2928:%.*]]
; USE_ASSUME: bb2928:
; USE_ASSUME-NEXT: br i1 false, label [[COND_NEXT2943:%.*]], label [[COND_TRUE2935:%.*]]
; USE_ASSUME: cond_true2935:
; USE_ASSUME-NEXT: br label [[COND_NEXT2943]]
; USE_ASSUME: cond_next2943:
; USE_ASSUME-NEXT: br i1 false, label [[BB2982_PREHEADER:%.*]], label [[BB2928]]
; USE_ASSUME: bb2982.preheader:
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* @n_spills, i64 4), "dereferenceable"(i32* @n_spills, i64 4), "nonnull"(i32* @n_spills) ]
; USE_ASSUME-NEXT: store i8 undef, i8* null
; USE_ASSUME-NEXT: ret i32 undef
;
cond_next2835.1: ; preds = %cond_next2861
%tmp2922 = load i32, i32* @n_spills, align 4 ; <i32> [#uses=0]
Expand Down