| ; RUN: opt -instcombine -S < %s | FileCheck %s |
| |
| @gp = global i32* null, align 8 |
| |
| declare i8* @malloc(i64) #1 |
| |
| define i1 @compare_global_trivialeq() { |
| %m = call i8* @malloc(i64 4) |
| %bc = bitcast i8* %m to i32* |
| %lgp = load i32*, i32** @gp, align 8 |
| %cmp = icmp eq i32* %bc, %lgp |
| ret i1 %cmp |
| ; CHECK-LABEL: compare_global_trivialeq |
| ; CHECK: ret i1 false |
| } |
| |
| define i1 @compare_global_trivialne() { |
| %m = call i8* @malloc(i64 4) |
| %bc = bitcast i8* %m to i32* |
| %lgp = load i32*, i32** @gp, align 8 |
| %cmp = icmp ne i32* %bc, %lgp |
| ret i1 %cmp |
| ; CHECK-LABEL: compare_global_trivialne |
| ; CHECK: ret i1 true |
| } |
| |
| |
| ; Although the %m is marked nocapture in the deopt operand in call to function f, |
| ; we cannot remove the alloc site: call to malloc |
| ; The comparison should fold to false irrespective of whether the call to malloc can be elided or not |
| declare void @f() |
| define i1 @compare_and_call_with_deopt() { |
| ; CHECK-LABEL: compare_and_call_with_deopt |
| %m = call i8* @malloc(i64 24) |
| %bc = bitcast i8* %m to i32* |
| %lgp = load i32*, i32** @gp, align 8, !nonnull !0 |
| %cmp = icmp eq i32* %lgp, %bc |
| tail call void @f() [ "deopt"(i8* %m) ] |
| ret i1 %cmp |
| ; CHECK: ret i1 false |
| } |
| |
| ; Same functon as above with deopt operand in function f, but comparison is NE |
| define i1 @compare_ne_and_call_with_deopt() { |
| ; CHECK-LABEL: compare_ne_and_call_with_deopt |
| %m = call i8* @malloc(i64 24) |
| %bc = bitcast i8* %m to i32* |
| %lgp = load i32*, i32** @gp, align 8, !nonnull !0 |
| %cmp = icmp ne i32* %lgp, %bc |
| tail call void @f() [ "deopt"(i8* %m) ] |
| ret i1 %cmp |
| ; CHECK: ret i1 true |
| } |
| |
| ; Same function as above, but global not marked nonnull, and we cannot fold the comparison |
| define i1 @compare_ne_global_maybe_null() { |
| ; CHECK-LABEL: compare_ne_global_maybe_null |
| %m = call i8* @malloc(i64 24) |
| %bc = bitcast i8* %m to i32* |
| %lgp = load i32*, i32** @gp |
| %cmp = icmp ne i32* %lgp, %bc |
| tail call void @f() [ "deopt"(i8* %m) ] |
| ret i1 %cmp |
| ; CHECK: ret i1 %cmp |
| } |
| |
| ; FIXME: The comparison should fold to false since %m escapes (call to function escape) |
| ; after the comparison. |
| declare void @escape(i8*) |
| define i1 @compare_and_call_after() { |
| ; CHECK-LABEL: compare_and_call_after |
| %m = call i8* @malloc(i64 24) |
| %bc = bitcast i8* %m to i32* |
| %lgp = load i32*, i32** @gp, align 8, !nonnull !0 |
| %cmp = icmp eq i32* %bc, %lgp |
| br i1 %cmp, label %escape_call, label %just_return |
| |
| escape_call: |
| call void @escape(i8* %m) |
| ret i1 true |
| |
| just_return: |
| ret i1 %cmp |
| } |
| |
| define i1 @compare_distinct_mallocs() { |
| %m = call i8* @malloc(i64 4) |
| %n = call i8* @malloc(i64 4) |
| %cmp = icmp eq i8* %m, %n |
| ret i1 %cmp |
| ; CHECK-LABEL: compare_distinct_mallocs |
| ; CHECK: ret i1 false |
| } |
| |
| ; the compare is folded to true since the folding compare looks through bitcasts. |
| ; call to malloc and the bitcast instructions are elided after that since there are no uses of the malloc |
| define i1 @compare_samepointer_under_bitcast() { |
| %m = call i8* @malloc(i64 4) |
| %bc = bitcast i8* %m to i32* |
| %bcback = bitcast i32* %bc to i8* |
| %cmp = icmp eq i8* %m, %bcback |
| ret i1 %cmp |
| ; CHECK-LABEL: compare_samepointer_under_bitcast |
| ; CHECK: ret i1 true |
| } |
| |
| ; the compare is folded to true since the folding compare looks through bitcasts. |
| ; The malloc call for %m cannot be elided since it is used in the call to function f. |
| define i1 @compare_samepointer_escaped() { |
| %m = call i8* @malloc(i64 4) |
| %bc = bitcast i8* %m to i32* |
| %bcback = bitcast i32* %bc to i8* |
| %cmp = icmp eq i8* %m, %bcback |
| call void @f() [ "deopt"(i8* %m) ] |
| ret i1 %cmp |
| ; CHECK-LABEL: compare_samepointer_escaped |
| ; CHECK-NEXT: %m = call i8* @malloc(i64 4) |
| ; CHECK-NEXT: call void @f() [ "deopt"(i8* %m) ] |
| ; CHECK: ret i1 true |
| } |
| |
| ; Technically, we can fold the %cmp2 comparison, even though %m escapes through |
| ; the ret statement since `ret` terminates the function and we cannot reach from |
| ; the ret to cmp. |
| ; FIXME: Folding this %cmp2 when %m escapes through ret could be an issue with |
| ; cross-threading data dependencies since we do not make the distinction between |
| ; atomic and non-atomic loads in capture tracking. |
| define i8* @compare_ret_escape(i8* %c) { |
| %m = call i8* @malloc(i64 4) |
| %n = call i8* @malloc(i64 4) |
| %cmp = icmp eq i8* %n, %c |
| br i1 %cmp, label %retst, label %chk |
| |
| retst: |
| ret i8* %m |
| |
| chk: |
| %bc = bitcast i8* %m to i32* |
| %lgp = load i32*, i32** @gp, align 8, !nonnull !0 |
| %cmp2 = icmp eq i32* %bc, %lgp |
| br i1 %cmp2, label %retst, label %chk2 |
| |
| chk2: |
| ret i8* %n |
| ; CHECK-LABEL: compare_ret_escape |
| ; CHECK: %cmp = icmp eq i8* %n, %c |
| ; CHECK: %cmp2 = icmp eq i32* %lgp, %bc |
| } |
| |
| ; The malloc call for %m cannot be elided since it is used in the call to function f. |
| ; However, the cmp can be folded to true as %n doesnt escape and %m, %n are distinct allocations |
| define i1 @compare_distinct_pointer_escape() { |
| %m = call i8* @malloc(i64 4) |
| %n = call i8* @malloc(i64 4) |
| tail call void @f() [ "deopt"(i8* %m) ] |
| %cmp = icmp ne i8* %m, %n |
| ret i1 %cmp |
| ; CHECK-LABEL: compare_distinct_pointer_escape |
| ; CHECK-NEXT: %m = call i8* @malloc(i64 4) |
| ; CHECK-NEXT: tail call void @f() [ "deopt"(i8* %m) ] |
| ; CHECK-NEXT: ret i1 true |
| } |
| |
| !0 = !{} |