1 ; RUN: opt -instcombine -S < %s | FileCheck %s 2 3 @gp = global i32* null, align 8 4 5 declare i8* @malloc(i64) #1 6 7 define i1 @compare_global_trivialeq() { 8 %m = call i8* @malloc(i64 4) 9 %bc = bitcast i8* %m to i32* 10 %lgp = load i32*, i32** @gp, align 8 11 %cmp = icmp eq i32* %bc, %lgp 12 ret i1 %cmp 13 ; CHECK-LABEL: compare_global_trivialeq 14 ; CHECK: ret i1 false 15 } 16 17 define i1 @compare_global_trivialne() { 18 %m = call i8* @malloc(i64 4) 19 %bc = bitcast i8* %m to i32* 20 %lgp = load i32*, i32** @gp, align 8 21 %cmp = icmp ne i32* %bc, %lgp 22 ret i1 %cmp 23 ; CHECK-LABEL: compare_global_trivialne 24 ; CHECK: ret i1 true 25 } 26 27 28 ; Although the %m is marked nocapture in the deopt operand in call to function f, 29 ; we cannot remove the alloc site: call to malloc 30 ; The comparison should fold to false irrespective of whether the call to malloc can be elided or not 31 declare void @f() 32 define i1 @compare_and_call_with_deopt() { 33 ; CHECK-LABEL: compare_and_call_with_deopt 34 %m = call i8* @malloc(i64 24) 35 %bc = bitcast i8* %m to i32* 36 %lgp = load i32*, i32** @gp, align 8, !nonnull !0 37 %cmp = icmp eq i32* %lgp, %bc 38 tail call void @f() [ "deopt"(i8* %m) ] 39 ret i1 %cmp 40 ; CHECK: ret i1 false 41 } 42 43 ; Same functon as above with deopt operand in function f, but comparison is NE 44 define i1 @compare_ne_and_call_with_deopt() { 45 ; CHECK-LABEL: compare_ne_and_call_with_deopt 46 %m = call i8* @malloc(i64 24) 47 %bc = bitcast i8* %m to i32* 48 %lgp = load i32*, i32** @gp, align 8, !nonnull !0 49 %cmp = icmp ne i32* %lgp, %bc 50 tail call void @f() [ "deopt"(i8* %m) ] 51 ret i1 %cmp 52 ; CHECK: ret i1 true 53 } 54 55 ; Same function as above, but global not marked nonnull, and we cannot fold the comparison 56 define i1 @compare_ne_global_maybe_null() { 57 ; CHECK-LABEL: compare_ne_global_maybe_null 58 %m = call i8* @malloc(i64 24) 59 %bc = bitcast i8* %m to i32* 60 %lgp = load i32*, i32** @gp 61 %cmp = icmp ne i32* %lgp, %bc 62 tail call void @f() [ "deopt"(i8* %m) ] 63 ret i1 %cmp 64 ; CHECK: ret i1 %cmp 65 } 66 67 ; FIXME: The comparison should fold to false since %m escapes (call to function escape) 68 ; after the comparison. 69 declare void @escape(i8*) 70 define i1 @compare_and_call_after() { 71 ; CHECK-LABEL: compare_and_call_after 72 %m = call i8* @malloc(i64 24) 73 %bc = bitcast i8* %m to i32* 74 %lgp = load i32*, i32** @gp, align 8, !nonnull !0 75 %cmp = icmp eq i32* %bc, %lgp 76 br i1 %cmp, label %escape_call, label %just_return 77 78 escape_call: 79 call void @escape(i8* %m) 80 ret i1 true 81 82 just_return: 83 ret i1 %cmp 84 } 85 86 define i1 @compare_distinct_mallocs() { 87 %m = call i8* @malloc(i64 4) 88 %n = call i8* @malloc(i64 4) 89 %cmp = icmp eq i8* %m, %n 90 ret i1 %cmp 91 ; CHECK-LABEL: compare_distinct_mallocs 92 ; CHECK: ret i1 false 93 } 94 95 ; the compare is folded to true since the folding compare looks through bitcasts. 96 ; call to malloc and the bitcast instructions are elided after that since there are no uses of the malloc 97 define i1 @compare_samepointer_under_bitcast() { 98 %m = call i8* @malloc(i64 4) 99 %bc = bitcast i8* %m to i32* 100 %bcback = bitcast i32* %bc to i8* 101 %cmp = icmp eq i8* %m, %bcback 102 ret i1 %cmp 103 ; CHECK-LABEL: compare_samepointer_under_bitcast 104 ; CHECK: ret i1 true 105 } 106 107 ; the compare is folded to true since the folding compare looks through bitcasts. 108 ; The malloc call for %m cannot be elided since it is used in the call to function f. 109 define i1 @compare_samepointer_escaped() { 110 %m = call i8* @malloc(i64 4) 111 %bc = bitcast i8* %m to i32* 112 %bcback = bitcast i32* %bc to i8* 113 %cmp = icmp eq i8* %m, %bcback 114 call void @f() [ "deopt"(i8* %m) ] 115 ret i1 %cmp 116 ; CHECK-LABEL: compare_samepointer_escaped 117 ; CHECK-NEXT: %m = call i8* @malloc(i64 4) 118 ; CHECK-NEXT: call void @f() [ "deopt"(i8* %m) ] 119 ; CHECK: ret i1 true 120 } 121 122 ; Technically, we can fold the %cmp2 comparison, even though %m escapes through 123 ; the ret statement since `ret` terminates the function and we cannot reach from 124 ; the ret to cmp. 125 ; FIXME: Folding this %cmp2 when %m escapes through ret could be an issue with 126 ; cross-threading data dependencies since we do not make the distinction between 127 ; atomic and non-atomic loads in capture tracking. 128 define i8* @compare_ret_escape(i8* %c) { 129 %m = call i8* @malloc(i64 4) 130 %n = call i8* @malloc(i64 4) 131 %cmp = icmp eq i8* %n, %c 132 br i1 %cmp, label %retst, label %chk 133 134 retst: 135 ret i8* %m 136 137 chk: 138 %bc = bitcast i8* %m to i32* 139 %lgp = load i32*, i32** @gp, align 8, !nonnull !0 140 %cmp2 = icmp eq i32* %bc, %lgp 141 br i1 %cmp2, label %retst, label %chk2 142 143 chk2: 144 ret i8* %n 145 ; CHECK-LABEL: compare_ret_escape 146 ; CHECK: %cmp = icmp eq i8* %n, %c 147 ; CHECK: %cmp2 = icmp eq i32* %bc, %lgp 148 } 149 150 ; The malloc call for %m cannot be elided since it is used in the call to function f. 151 ; However, the cmp can be folded to true as %n doesnt escape and %m, %n are distinct allocations 152 define i1 @compare_distinct_pointer_escape() { 153 %m = call i8* @malloc(i64 4) 154 %n = call i8* @malloc(i64 4) 155 tail call void @f() [ "deopt"(i8* %m) ] 156 %cmp = icmp ne i8* %m, %n 157 ret i1 %cmp 158 ; CHECK-LABEL: compare_distinct_pointer_escape 159 ; CHECK-NEXT: %m = call i8* @malloc(i64 4) 160 ; CHECK-NEXT: tail call void @f() [ "deopt"(i8* %m) ] 161 ; CHECK-NEXT: ret i1 true 162 } 163 164 !0 = !{} 165