|  | ; 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 = !{} |