| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 | |
| ; RUN: opt -S -passes=sccp < %s | FileCheck %s --check-prefixes=CHECK,SCCP | |
| ; RUN: opt -S -passes=ipsccp < %s | FileCheck %s --check-prefixes=CHECK,IPSCCP | |
| declare ptr @get() | |
| define i1 @test_no_attr(ptr %p) { | |
| ; CHECK-LABEL: define i1 @test_no_attr( | |
| ; CHECK-SAME: ptr [[P:%.*]]) { | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[P]], null | |
| ; CHECK-NEXT: ret i1 [[CMP]] | |
| ; | |
| %cmp = icmp ne ptr %p, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_nonnull(ptr nonnull %p) { | |
| ; CHECK-LABEL: define i1 @test_nonnull( | |
| ; CHECK-SAME: ptr nonnull [[P:%.*]]) { | |
| ; CHECK-NEXT: ret i1 true | |
| ; | |
| %cmp = icmp ne ptr %p, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_nonnull_eq(ptr nonnull %p) { | |
| ; CHECK-LABEL: define i1 @test_nonnull_eq( | |
| ; CHECK-SAME: ptr nonnull [[P:%.*]]) { | |
| ; CHECK-NEXT: ret i1 false | |
| ; | |
| %cmp = icmp eq ptr %p, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_dereferenceable(ptr dereferenceable(4) %p) { | |
| ; CHECK-LABEL: define i1 @test_dereferenceable( | |
| ; CHECK-SAME: ptr dereferenceable(4) [[P:%.*]]) { | |
| ; CHECK-NEXT: ret i1 true | |
| ; | |
| %cmp = icmp ne ptr %p, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_alloca() { | |
| ; CHECK-LABEL: define i1 @test_alloca() { | |
| ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 | |
| ; CHECK-NEXT: ret i1 true | |
| ; | |
| %a = alloca i32 | |
| %cmp = icmp ne ptr %a, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_alloca_addrspace() { | |
| ; CHECK-LABEL: define i1 @test_alloca_addrspace() { | |
| ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4, addrspace(1) | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr addrspace(1) [[A]], null | |
| ; CHECK-NEXT: ret i1 [[CMP]] | |
| ; | |
| %a = alloca i32, addrspace(1) | |
| %cmp = icmp ne ptr addrspace(1) %a, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_alloca_null_pointer_valid() null_pointer_is_valid { | |
| ; CHECK-LABEL: define i1 @test_alloca_null_pointer_valid( | |
| ; CHECK-SAME: ) #[[ATTR0:[0-9]+]] { | |
| ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[A]], null | |
| ; CHECK-NEXT: ret i1 [[CMP]] | |
| ; | |
| %a = alloca i32 | |
| %cmp = icmp ne ptr %a, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_load_nonnull(ptr %p) { | |
| ; CHECK-LABEL: define i1 @test_load_nonnull( | |
| ; CHECK-SAME: ptr [[P:%.*]]) { | |
| ; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P]], align 8, !nonnull [[META0:![0-9]+]] | |
| ; CHECK-NEXT: ret i1 true | |
| ; | |
| %p2 = load ptr, ptr %p, !nonnull !{} | |
| %cmp = icmp ne ptr %p2, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_call_nonnull() { | |
| ; CHECK-LABEL: define i1 @test_call_nonnull() { | |
| ; CHECK-NEXT: [[P:%.*]] = call nonnull ptr @get() | |
| ; CHECK-NEXT: ret i1 true | |
| ; | |
| %p = call nonnull ptr @get() | |
| %cmp = icmp ne ptr %p, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_call_dereferenceable() { | |
| ; CHECK-LABEL: define i1 @test_call_dereferenceable() { | |
| ; CHECK-NEXT: [[P:%.*]] = call dereferenceable(4) ptr @get() | |
| ; CHECK-NEXT: ret i1 true | |
| ; | |
| %p = call dereferenceable(4) ptr @get() | |
| %cmp = icmp ne ptr %p, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_gep_no_flags(ptr nonnull %p, i64 %x) { | |
| ; CHECK-LABEL: define i1 @test_gep_no_flags( | |
| ; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) { | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[GEP]], null | |
| ; CHECK-NEXT: ret i1 [[CMP]] | |
| ; | |
| %gep = getelementptr i8, ptr %p, i64 %x | |
| %cmp = icmp ne ptr %gep, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_gep_nuw(ptr nonnull %p, i64 %x) { | |
| ; CHECK-LABEL: define i1 @test_gep_nuw( | |
| ; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) { | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[X]] | |
| ; CHECK-NEXT: ret i1 true | |
| ; | |
| %gep = getelementptr nuw i8, ptr %p, i64 %x | |
| %cmp = icmp ne ptr %gep, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_gep_inbounds(ptr nonnull %p, i64 %x) { | |
| ; CHECK-LABEL: define i1 @test_gep_inbounds( | |
| ; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) { | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 [[X]] | |
| ; CHECK-NEXT: ret i1 true | |
| ; | |
| %gep = getelementptr inbounds i8, ptr %p, i64 %x | |
| %cmp = icmp ne ptr %gep, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_gep_inbounds_null_pointer_valid(ptr nonnull %p, i64 %x) null_pointer_is_valid { | |
| ; CHECK-LABEL: define i1 @test_gep_inbounds_null_pointer_valid( | |
| ; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) #[[ATTR0]] { | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 [[X]] | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[GEP]], null | |
| ; CHECK-NEXT: ret i1 [[CMP]] | |
| ; | |
| %gep = getelementptr inbounds i8, ptr %p, i64 %x | |
| %cmp = icmp ne ptr %gep, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_select(i1 %c, ptr nonnull %p, i64 %x) { | |
| ; CHECK-LABEL: define i1 @test_select( | |
| ; CHECK-SAME: i1 [[C:%.*]], ptr nonnull [[P:%.*]], i64 [[X:%.*]]) { | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[X]] | |
| ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C]], ptr [[P]], ptr [[GEP]] | |
| ; CHECK-NEXT: ret i1 true | |
| ; | |
| %gep = getelementptr nuw i8, ptr %p, i64 %x | |
| %sel = select i1 %c, ptr %p, ptr %gep | |
| %cmp = icmp ne ptr %sel, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_select_not_nuw(i1 %c, ptr nonnull %p, i64 %x) { | |
| ; CHECK-LABEL: define i1 @test_select_not_nuw( | |
| ; CHECK-SAME: i1 [[C:%.*]], ptr nonnull [[P:%.*]], i64 [[X:%.*]]) { | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] | |
| ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C]], ptr [[P]], ptr [[GEP]] | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[SEL]], null | |
| ; CHECK-NEXT: ret i1 [[CMP]] | |
| ; | |
| %gep = getelementptr i8, ptr %p, i64 %x | |
| %sel = select i1 %c, ptr %p, ptr %gep | |
| %cmp = icmp ne ptr %sel, null | |
| ret i1 %cmp | |
| } | |
| define i1 @test_phi(i1 %c, ptr nonnull %p, i64 %x) { | |
| ; CHECK-LABEL: define i1 @test_phi( | |
| ; CHECK-SAME: i1 [[C:%.*]], ptr nonnull [[P:%.*]], i64 [[X:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*]]: | |
| ; CHECK-NEXT: br i1 [[C]], label %[[IF:.*]], label %[[JOIN:.*]] | |
| ; CHECK: [[IF]]: | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[X]] | |
| ; CHECK-NEXT: br label %[[JOIN]] | |
| ; CHECK: [[JOIN]]: | |
| ; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[P]], %[[ENTRY]] ], [ [[GEP]], %[[IF]] ] | |
| ; CHECK-NEXT: ret i1 true | |
| ; | |
| entry: | |
| br i1 %c, label %if, label %join | |
| if: | |
| %gep = getelementptr nuw i8, ptr %p, i64 %x | |
| br label %join | |
| join: | |
| %phi = phi ptr [ %p, %entry ], [ %gep, %if ] | |
| %cmp = icmp ne ptr %phi, null | |
| ret i1 %cmp | |
| } | |
| define internal i1 @ip_test_nonnull_callee(ptr nonnull %p) { | |
| ; SCCP-LABEL: define internal i1 @ip_test_nonnull_callee( | |
| ; SCCP-SAME: ptr nonnull [[P:%.*]]) { | |
| ; SCCP-NEXT: ret i1 true | |
| ; | |
| ; IPSCCP-LABEL: define internal i1 @ip_test_nonnull_callee( | |
| ; IPSCCP-SAME: ptr nonnull [[P:%.*]]) { | |
| ; IPSCCP-NEXT: ret i1 poison | |
| ; | |
| %cmp = icmp ne ptr %p, null | |
| ret i1 %cmp | |
| } | |
| define i1 @ip_test_nonnull_caller(ptr %p) { | |
| ; SCCP-LABEL: define i1 @ip_test_nonnull_caller( | |
| ; SCCP-SAME: ptr [[P:%.*]]) { | |
| ; SCCP-NEXT: [[RES:%.*]] = call i1 @ip_test_nonnull_callee(ptr [[P]]) | |
| ; SCCP-NEXT: ret i1 [[RES]] | |
| ; | |
| ; IPSCCP-LABEL: define i1 @ip_test_nonnull_caller( | |
| ; IPSCCP-SAME: ptr [[P:%.*]]) { | |
| ; IPSCCP-NEXT: [[RES:%.*]] = call i1 @ip_test_nonnull_callee(ptr [[P]]) | |
| ; IPSCCP-NEXT: ret i1 true | |
| ; | |
| %res = call i1 @ip_test_nonnull_callee(ptr %p) | |
| ret i1 %res | |
| } | |
| define ptr @ret_nonnull_pointer(ptr nonnull %p) { | |
| ; CHECK-LABEL: define nonnull ptr @ret_nonnull_pointer( | |
| ; CHECK-SAME: ptr nonnull [[P:%.*]]) { | |
| ; CHECK-NEXT: ret ptr [[P]] | |
| ; | |
| ret ptr %p | |
| } | |
| define ptr @ret_maybe_null_pointer(ptr %p) { | |
| ; CHECK-LABEL: define ptr @ret_maybe_null_pointer( | |
| ; CHECK-SAME: ptr [[P:%.*]]) { | |
| ; CHECK-NEXT: ret ptr [[P]] | |
| ; | |
| ret ptr %p | |
| } | |
| define internal void @ip_nonnull_arg_callee(ptr %p) { | |
| ; SCCP-LABEL: define internal void @ip_nonnull_arg_callee( | |
| ; SCCP-SAME: ptr [[P:%.*]]) { | |
| ; SCCP-NEXT: ret void | |
| ; | |
| ; IPSCCP-LABEL: define internal void @ip_nonnull_arg_callee( | |
| ; IPSCCP-SAME: ptr nonnull [[P:%.*]]) { | |
| ; IPSCCP-NEXT: ret void | |
| ; | |
| ret void | |
| } | |
| define internal void @ip_not_nonnull_arg_callee(ptr %p) { | |
| ; CHECK-LABEL: define internal void @ip_not_nonnull_arg_callee( | |
| ; CHECK-SAME: ptr [[P:%.*]]) { | |
| ; CHECK-NEXT: ret void | |
| ; | |
| ret void | |
| } | |
| define void @ip_nonnull_arg_caller(ptr nonnull %p) { | |
| ; CHECK-LABEL: define void @ip_nonnull_arg_caller( | |
| ; CHECK-SAME: ptr nonnull [[P:%.*]]) { | |
| ; CHECK-NEXT: call void @ip_nonnull_arg_callee(ptr [[P]]) | |
| ; CHECK-NEXT: call void @ip_not_nonnull_arg_callee(ptr [[P]]) | |
| ; CHECK-NEXT: call void @ip_not_nonnull_arg_callee(ptr null) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| call void @ip_nonnull_arg_callee(ptr %p) | |
| call void @ip_not_nonnull_arg_callee(ptr %p) | |
| call void @ip_not_nonnull_arg_callee(ptr null) | |
| ret void | |
| } | |
| ;. | |
| ; SCCP: [[META0]] = !{} | |
| ;. | |
| ; IPSCCP: [[META0]] = !{} | |
| ;. |