| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes=instcombine -S < %s | FileCheck %s |
| |
| target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32:32-p3:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" |
| |
| declare ptr @getptr() |
| declare void @use(ptr) |
| |
| define i1 @eq_base(ptr %x, i64 %y) { |
| ; CHECK-LABEL: @eq_base( |
| ; CHECK-NEXT: [[R:%.*]] = icmp eq i64 [[Y:%.*]], 0 |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %g = getelementptr i8, ptr %x, i64 %y |
| %r = icmp eq ptr %g, %x |
| ret i1 %r |
| } |
| |
| define i1 @ne_base_commute(i64 %y) { |
| ; CHECK-LABEL: @ne_base_commute( |
| ; CHECK-NEXT: [[X:%.*]] = call ptr @getptr() |
| ; CHECK-NEXT: [[R:%.*]] = icmp ne i64 [[Y:%.*]], 0 |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %x = call ptr @getptr() ; thwart complexity-based canonicalization |
| %g = getelementptr i8, ptr %x, i64 %y |
| %r = icmp ne ptr %x, %g |
| ret i1 %r |
| } |
| |
| define i1 @ne_base_inbounds(ptr %x, i64 %y) { |
| ; CHECK-LABEL: @ne_base_inbounds( |
| ; CHECK-NEXT: [[R:%.*]] = icmp ne i64 [[Y:%.*]], 0 |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %g = getelementptr inbounds i8, ptr %x, i64 %y |
| %r = icmp ne ptr %g, %x |
| ret i1 %r |
| } |
| |
| define i1 @eq_base_inbounds_commute(i64 %y) { |
| ; CHECK-LABEL: @eq_base_inbounds_commute( |
| ; CHECK-NEXT: [[X:%.*]] = call ptr @getptr() |
| ; CHECK-NEXT: [[R:%.*]] = icmp eq i64 [[Y:%.*]], 0 |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %x = call ptr @getptr() ; thwart complexity-based canonicalization |
| %g = getelementptr inbounds i8, ptr %x, i64 %y |
| %r = icmp eq ptr %x, %g |
| ret i1 %r |
| } |
| |
| define i1 @slt_base(ptr %x, i64 %y) { |
| ; CHECK-LABEL: @slt_base( |
| ; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[X:%.*]], i64 [[Y:%.*]] |
| ; CHECK-NEXT: [[R:%.*]] = icmp slt ptr [[G]], [[X]] |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %g = getelementptr i8, ptr %x, i64 %y |
| %r = icmp slt ptr %g, %x |
| ret i1 %r |
| } |
| |
| define i1 @sgt_base_commute(i64 %y) { |
| ; CHECK-LABEL: @sgt_base_commute( |
| ; CHECK-NEXT: [[X:%.*]] = call ptr @getptr() |
| ; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[X]], i64 [[Y:%.*]] |
| ; CHECK-NEXT: [[R:%.*]] = icmp sgt ptr [[X]], [[G]] |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %x = call ptr @getptr() ; thwart complexity-based canonicalization |
| %g = getelementptr i8, ptr %x, i64 %y |
| %r = icmp sgt ptr %x, %g |
| ret i1 %r |
| } |
| |
| define i1 @slt_base_inbounds(ptr %x, i64 %y) { |
| ; CHECK-LABEL: @slt_base_inbounds( |
| ; CHECK-NEXT: [[G:%.*]] = getelementptr inbounds i8, ptr [[X:%.*]], i64 [[Y:%.*]] |
| ; CHECK-NEXT: [[R:%.*]] = icmp slt ptr [[G]], [[X]] |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %g = getelementptr inbounds i8, ptr %x, i64 %y |
| %r = icmp slt ptr %g, %x |
| ret i1 %r |
| } |
| |
| define i1 @sgt_base_inbounds_commute(i64 %y) { |
| ; CHECK-LABEL: @sgt_base_inbounds_commute( |
| ; CHECK-NEXT: [[X:%.*]] = call ptr @getptr() |
| ; CHECK-NEXT: [[G:%.*]] = getelementptr inbounds i8, ptr [[X]], i64 [[Y:%.*]] |
| ; CHECK-NEXT: [[R:%.*]] = icmp sgt ptr [[X]], [[G]] |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %x = call ptr @getptr() ; thwart complexity-based canonicalization |
| %g = getelementptr inbounds i8, ptr %x, i64 %y |
| %r = icmp sgt ptr %x, %g |
| ret i1 %r |
| } |
| |
| define i1 @ult_base(ptr %x, i64 %y) { |
| ; CHECK-LABEL: @ult_base( |
| ; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[X:%.*]], i64 [[Y:%.*]] |
| ; CHECK-NEXT: [[R:%.*]] = icmp ult ptr [[G]], [[X]] |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %g = getelementptr i8, ptr %x, i64 %y |
| %r = icmp ult ptr %g, %x |
| ret i1 %r |
| } |
| |
| define i1 @ugt_base_commute(i64 %y) { |
| ; CHECK-LABEL: @ugt_base_commute( |
| ; CHECK-NEXT: [[X:%.*]] = call ptr @getptr() |
| ; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[X]], i64 [[Y:%.*]] |
| ; CHECK-NEXT: [[R:%.*]] = icmp ugt ptr [[X]], [[G]] |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %x = call ptr @getptr() ; thwart complexity-based canonicalization |
| %g = getelementptr i8, ptr %x, i64 %y |
| %r = icmp ugt ptr %x, %g |
| ret i1 %r |
| } |
| |
| define i1 @ult_base_inbounds(ptr %x, i64 %y) { |
| ; CHECK-LABEL: @ult_base_inbounds( |
| ; CHECK-NEXT: [[R:%.*]] = icmp slt i64 [[Y:%.*]], 0 |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %g = getelementptr inbounds i8, ptr %x, i64 %y |
| %r = icmp ult ptr %g, %x |
| ret i1 %r |
| } |
| |
| define i1 @ugt_base_inbounds_commute(i64 %y) { |
| ; CHECK-LABEL: @ugt_base_inbounds_commute( |
| ; CHECK-NEXT: [[X:%.*]] = call ptr @getptr() |
| ; CHECK-NEXT: [[R:%.*]] = icmp slt i64 [[Y:%.*]], 0 |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %x = call ptr @getptr() ; thwart complexity-based canonicalization |
| %g = getelementptr inbounds i8, ptr %x, i64 %y |
| %r = icmp ugt ptr %x, %g |
| ret i1 %r |
| } |
| |
| define i1 @ne_base_inbounds_use(ptr %x, i64 %y) { |
| ; CHECK-LABEL: @ne_base_inbounds_use( |
| ; CHECK-NEXT: [[G:%.*]] = getelementptr inbounds i8, ptr [[X:%.*]], i64 [[Y:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[G]]) |
| ; CHECK-NEXT: [[R:%.*]] = icmp ne i64 [[Y]], 0 |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %g = getelementptr inbounds i8, ptr %x, i64 %y |
| call void @use(ptr %g) |
| %r = icmp ne ptr %g, %x |
| ret i1 %r |
| } |
| |
| define i1 @eq_base_inbounds_commute_use(i64 %y) { |
| ; CHECK-LABEL: @eq_base_inbounds_commute_use( |
| ; CHECK-NEXT: [[X:%.*]] = call ptr @getptr() |
| ; CHECK-NEXT: [[G:%.*]] = getelementptr inbounds i8, ptr [[X]], i64 [[Y:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[G]]) |
| ; CHECK-NEXT: [[R:%.*]] = icmp eq i64 [[Y]], 0 |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %x = call ptr @getptr() ; thwart complexity-based canonicalization |
| %g = getelementptr inbounds i8, ptr %x, i64 %y |
| call void @use(ptr %g) |
| %r = icmp eq ptr %x, %g |
| ret i1 %r |
| } |
| |
| define i1 @eq_bitcast_base(ptr %p, i64 %x) { |
| ; CHECK-LABEL: @eq_bitcast_base( |
| ; CHECK-NEXT: [[GEP_IDX_MASK:%.*]] = and i64 [[X:%.*]], 9223372036854775807 |
| ; CHECK-NEXT: [[R:%.*]] = icmp eq i64 [[GEP_IDX_MASK]], 0 |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %gep = getelementptr [2 x i8], ptr %p, i64 %x, i64 0 |
| %r = icmp eq ptr %gep, %p |
| ret i1 %r |
| } |
| |
| define i1 @eq_bitcast_base_inbounds(ptr %p, i64 %x) { |
| ; CHECK-LABEL: @eq_bitcast_base_inbounds( |
| ; CHECK-NEXT: [[R:%.*]] = icmp eq i64 [[X:%.*]], 0 |
| ; CHECK-NEXT: ret i1 [[R]] |
| ; |
| %gep = getelementptr inbounds [2 x i8], ptr %p, i64 %x, i64 0 |
| %r = icmp eq ptr %gep, %p |
| ret i1 %r |
| } |
| |
| @X = global [1000 x i32] zeroinitializer |
| |
| define i1 @PR8882(i64 %i) { |
| ; CHECK-LABEL: @PR8882( |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[I:%.*]], 1000 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %p1 = getelementptr inbounds i32, ptr @X, i64 %i |
| %cmp = icmp eq ptr %p1, getelementptr inbounds ([1000 x i32], ptr @X, i64 1, i64 0) |
| ret i1 %cmp |
| } |
| |
| @X_as1 = addrspace(1) global [1000 x i32] zeroinitializer |
| |
| define i1 @test24_as1(i64 %i) { |
| ; CHECK-LABEL: @test24_as1( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[I:%.*]], 65535 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[TMP1]], 1000 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %p1 = getelementptr inbounds i32, ptr addrspace(1) @X_as1, i64 %i |
| %cmp = icmp eq ptr addrspace(1) %p1, getelementptr inbounds ([1000 x i32], ptr addrspace(1) @X_as1, i64 1, i64 0) |
| ret i1 %cmp |
| } |
| |
| ; PR16244 |
| define i1 @test71(ptr %x) { |
| ; CHECK-LABEL: @test71( |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %a = getelementptr i8, ptr %x, i64 8 |
| %b = getelementptr inbounds i8, ptr %x, i64 8 |
| %c = icmp ugt ptr %a, %b |
| ret i1 %c |
| } |
| |
| define i1 @test71_as1(ptr addrspace(1) %x) { |
| ; CHECK-LABEL: @test71_as1( |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %a = getelementptr i8, ptr addrspace(1) %x, i64 8 |
| %b = getelementptr inbounds i8, ptr addrspace(1) %x, i64 8 |
| %c = icmp ugt ptr addrspace(1) %a, %b |
| ret i1 %c |
| } |
| |
| declare i32 @test58_d(i64) |
| |
| define i1 @test59(ptr %foo) { |
| ; CHECK-LABEL: @test59( |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i32, ptr [[FOO:%.*]], i64 2 |
| ; CHECK-NEXT: [[USE:%.*]] = ptrtoint ptr [[GEP1]] to i64 |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @test58_d(i64 [[USE]]) |
| ; CHECK-NEXT: ret i1 true |
| ; |
| %gep1 = getelementptr inbounds i32, ptr %foo, i64 2 |
| %gep2 = getelementptr inbounds i8, ptr %foo, i64 10 |
| %cmp = icmp ult ptr %gep1, %gep2 |
| %use = ptrtoint ptr %gep1 to i64 |
| %call = call i32 @test58_d(i64 %use) |
| ret i1 %cmp |
| } |
| |
| define i1 @test59_as1(ptr addrspace(1) %foo) { |
| ; CHECK-LABEL: @test59_as1( |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i32, ptr addrspace(1) [[FOO:%.*]], i16 2 |
| ; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr addrspace(1) [[GEP1]] to i16 |
| ; CHECK-NEXT: [[USE:%.*]] = zext i16 [[TMP1]] to i64 |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @test58_d(i64 [[USE]]) |
| ; CHECK-NEXT: ret i1 true |
| ; |
| %gep1 = getelementptr inbounds i32, ptr addrspace(1) %foo, i64 2 |
| %gep2 = getelementptr inbounds i8, ptr addrspace(1) %foo, i64 10 |
| %cmp = icmp ult ptr addrspace(1) %gep1, %gep2 |
| %use = ptrtoint ptr addrspace(1) %gep1 to i64 |
| %call = call i32 @test58_d(i64 %use) |
| ret i1 %cmp |
| } |
| |
| define i1 @test60(ptr %foo, i64 %i, i64 %j) { |
| ; CHECK-LABEL: @test60( |
| ; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i64 [[I:%.*]], 2 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[GEP1_IDX]], [[J:%.*]] |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %gep1 = getelementptr inbounds i32, ptr %foo, i64 %i |
| %gep2 = getelementptr inbounds i8, ptr %foo, i64 %j |
| %cmp = icmp ult ptr %gep1, %gep2 |
| ret i1 %cmp |
| } |
| |
| define i1 @test_gep_ult_no_inbounds(ptr %foo, i64 %i, i64 %j) { |
| ; CHECK-LABEL: @test_gep_ult_no_inbounds( |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr [[FOO:%.*]], i64 [[I:%.*]] |
| ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[FOO]], i64 [[J:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult ptr [[GEP1]], [[GEP2]] |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %gep1 = getelementptr i32, ptr %foo, i64 %i |
| %gep2 = getelementptr i8, ptr %foo, i64 %j |
| %cmp = icmp ult ptr %gep1, %gep2 |
| ret i1 %cmp |
| } |
| |
| define i1 @test_gep_eq_no_inbounds(ptr %foo, i64 %i, i64 %j) { |
| ; CHECK-LABEL: @test_gep_eq_no_inbounds( |
| ; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl i64 [[I:%.*]], 2 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[GEP1_IDX]], [[J:%.*]] |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %gep1 = getelementptr i32, ptr %foo, i64 %i |
| %gep2 = getelementptr i8, ptr %foo, i64 %j |
| %cmp = icmp eq ptr %gep1, %gep2 |
| ret i1 %cmp |
| } |
| |
| define i1 @test60_as1(ptr addrspace(1) %foo, i64 %i, i64 %j) { |
| ; CHECK-LABEL: @test60_as1( |
| ; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[I:%.*]] to i16 |
| ; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[J:%.*]] to i16 |
| ; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i16 [[TMP1]], 2 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[GEP1_IDX]], [[TMP2]] |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %gep1 = getelementptr inbounds i32, ptr addrspace(1) %foo, i64 %i |
| %gep2 = getelementptr inbounds i8, ptr addrspace(1) %foo, i64 %j |
| %cmp = icmp ult ptr addrspace(1) %gep1, %gep2 |
| ret i1 %cmp |
| } |
| |
| ; Same as test60, but look through an addrspacecast instead of a |
| ; bitcast. This uses the same sized addrspace. |
| define i1 @test60_addrspacecast(ptr %foo, i64 %i, i64 %j) { |
| ; CHECK-LABEL: @test60_addrspacecast( |
| ; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i64 [[I:%.*]], 2 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[GEP1_IDX]], [[J:%.*]] |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %bit = addrspacecast ptr %foo to ptr addrspace(3) |
| %gep1 = getelementptr inbounds i32, ptr addrspace(3) %bit, i64 %i |
| %gep2 = getelementptr inbounds i8, ptr %foo, i64 %j |
| %cast1 = addrspacecast ptr addrspace(3) %gep1 to ptr |
| %cmp = icmp ult ptr %cast1, %gep2 |
| ret i1 %cmp |
| } |
| |
| define i1 @test60_addrspacecast_smaller(ptr %foo, i16 %i, i64 %j) { |
| ; CHECK-LABEL: @test60_addrspacecast_smaller( |
| ; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i16 [[I:%.*]], 2 |
| ; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[J:%.*]] to i16 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[GEP1_IDX]], [[TMP1]] |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %bit = addrspacecast ptr %foo to ptr addrspace(1) |
| %gep1 = getelementptr inbounds i32, ptr addrspace(1) %bit, i16 %i |
| %gep2 = getelementptr inbounds i8, ptr %foo, i64 %j |
| %cast1 = addrspacecast ptr addrspace(1) %gep1 to ptr |
| %cmp = icmp ult ptr %cast1, %gep2 |
| ret i1 %cmp |
| } |
| |
| define i1 @test60_addrspacecast_larger(ptr addrspace(1) %foo, i32 %i, i16 %j) { |
| ; CHECK-LABEL: @test60_addrspacecast_larger( |
| ; CHECK-NEXT: [[I_TR:%.*]] = trunc i32 [[I:%.*]] to i16 |
| ; CHECK-NEXT: [[TMP1:%.*]] = shl i16 [[I_TR]], 2 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[TMP1]], [[J:%.*]] |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %bit = addrspacecast ptr addrspace(1) %foo to ptr addrspace(2) |
| %gep1 = getelementptr inbounds i32, ptr addrspace(2) %bit, i32 %i |
| %gep2 = getelementptr inbounds i8, ptr addrspace(1) %foo, i16 %j |
| %cast1 = addrspacecast ptr addrspace(2) %gep1 to ptr addrspace(1) |
| %cmp = icmp ult ptr addrspace(1) %cast1, %gep2 |
| ret i1 %cmp |
| } |
| |
| define i1 @test61(ptr %foo, i64 %i, i64 %j) { |
| ; CHECK-LABEL: @test61( |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr [[FOO:%.*]], i64 [[I:%.*]] |
| ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[FOO]], i64 [[J:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult ptr [[GEP1]], [[GEP2]] |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %gep1 = getelementptr i32, ptr %foo, i64 %i |
| %gep2 = getelementptr i8, ptr %foo, i64 %j |
| %cmp = icmp ult ptr %gep1, %gep2 |
| ret i1 %cmp |
| ; Don't transform non-inbounds GEPs. |
| } |
| |
| define i1 @test61_as1(ptr addrspace(1) %foo, i16 %i, i16 %j) { |
| ; CHECK-LABEL: @test61_as1( |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr addrspace(1) [[FOO:%.*]], i16 [[I:%.*]] |
| ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr addrspace(1) [[FOO]], i16 [[J:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult ptr addrspace(1) [[GEP1]], [[GEP2]] |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %gep1 = getelementptr i32, ptr addrspace(1) %foo, i16 %i |
| %gep2 = getelementptr i8, ptr addrspace(1) %foo, i16 %j |
| %cmp = icmp ult ptr addrspace(1) %gep1, %gep2 |
| ret i1 %cmp |
| ; Don't transform non-inbounds GEPs. |
| } |