1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -instsimplify -S | FileCheck %s 3 4; A == B implies A >u B is false. 5 6define void @test1(i32 %a, i32 %b) { 7; CHECK-LABEL: @test1( 8; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]] 9; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[END:%.*]] 10; CHECK: taken: 11; CHECK-NEXT: call void @foo(i32 10) 12; CHECK-NEXT: br label [[END]] 13; CHECK: end: 14; CHECK-NEXT: ret void 15; 16 %cmp1 = icmp eq i32 %a, %b 17 br i1 %cmp1, label %taken, label %end 18 19taken: 20 %cmp2 = icmp ugt i32 %a, %b 21 %c = select i1 %cmp2, i32 0, i32 10 22 call void @foo(i32 %c) 23 br label %end 24 25end: 26 ret void 27} 28 29; If A == B is false then A != B is true. 30 31define void @test2(i32 %a, i32 %b) { 32; CHECK-LABEL: @test2( 33; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]] 34; CHECK-NEXT: br i1 [[CMP1]], label [[END:%.*]], label [[TAKEN:%.*]] 35; CHECK: taken: 36; CHECK-NEXT: call void @foo(i32 20) 37; CHECK-NEXT: br label [[END]] 38; CHECK: end: 39; CHECK-NEXT: ret void 40; 41 %cmp1 = icmp eq i32 %a, %b 42 br i1 %cmp1, label %end, label %taken 43 44taken: 45 %cmp2 = icmp ne i32 %a, %b 46 %c = select i1 %cmp2, i32 20, i32 0 47 call void @foo(i32 %c) 48 br label %end 49 50end: 51 ret void 52} 53 54; A >u 10 implies A >u 10 is true. 55 56define void @test3(i32 %a) { 57; CHECK-LABEL: @test3( 58; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 10 59; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[END:%.*]] 60; CHECK: taken: 61; CHECK-NEXT: call void @foo(i32 30) 62; CHECK-NEXT: br label [[END]] 63; CHECK: end: 64; CHECK-NEXT: ret void 65; 66 %cmp1 = icmp ugt i32 %a, 10 67 br i1 %cmp1, label %taken, label %end 68 69taken: 70 %cmp2 = icmp ugt i32 %a, 10 71 %c = select i1 %cmp2, i32 30, i32 0 72 call void @foo(i32 %c) 73 br label %end 74 75end: 76 ret void 77} 78 79define i8 @PR23333(i8 addrspace(1)* %ptr) { 80; CHECK-LABEL: @PR23333( 81; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 addrspace(1)* [[PTR:%.*]], null 82; CHECK-NEXT: br i1 [[CMP]], label [[TAKEN:%.*]], label [[END:%.*]] 83; CHECK: taken: 84; CHECK-NEXT: ret i8 1 85; CHECK: end: 86; CHECK-NEXT: ret i8 0 87; 88 %cmp = icmp eq i8 addrspace(1)* %ptr, null 89 br i1 %cmp, label %taken, label %end 90 91taken: 92 %cmp2 = icmp ne i8 addrspace(1)* %ptr, null 93 %res = select i1 %cmp2, i8 2, i8 1 94 ret i8 %res 95 96end: 97 ret i8 0 98} 99 100; We know the condition of the select is true based on a dominating condition. 101; Therefore, we can replace %cond with %len. 102; TODO: len == 8 is known false in bb. This is handled by other passes, but should it be handled here? 103 104define void @test4(i32 %len) { 105; CHECK-LABEL: @test4( 106; CHECK-NEXT: entry: 107; CHECK-NEXT: [[TMP0:%.*]] = call i32 @bar(i32 [[LEN:%.*]]) 108; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LEN]], 4 109; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[B1:%.*]] 110; CHECK: bb: 111; CHECK-NEXT: [[CMP11:%.*]] = icmp eq i32 [[LEN]], 8 112; CHECK-NEXT: br i1 [[CMP11]], label [[B0:%.*]], label [[B1]] 113; CHECK: b0: 114; CHECK-NEXT: call void @foo(i32 [[LEN]]) 115; CHECK-NEXT: br label [[B1]] 116; CHECK: b1: 117; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[LEN]], [[BB]] ], [ undef, [[B0]] ], [ [[TMP0]], [[ENTRY:%.*]] ] 118; CHECK-NEXT: br label [[RET:%.*]] 119; CHECK: ret: 120; CHECK-NEXT: call void @foo(i32 [[TMP1]]) 121; CHECK-NEXT: ret void 122; 123entry: 124 %0 = call i32 @bar(i32 %len); 125 %cmp = icmp ult i32 %len, 4 126 br i1 %cmp, label %bb, label %b1 127bb: 128 %cond = select i1 %cmp, i32 %len, i32 8 129 %cmp11 = icmp eq i32 %cond, 8 130 br i1 %cmp11, label %b0, label %b1 131 132b0: 133 call void @foo(i32 %len) 134 br label %b1 135 136b1: 137 %1 = phi i32 [ %cond, %bb ], [ undef, %b0 ], [ %0, %entry ] 138 br label %ret 139 140ret: 141 call void @foo(i32 %1) 142 ret void 143} 144 145; A >u 10 implies A >u 9 is true. 146 147define void @test5(i32 %a) { 148; CHECK-LABEL: @test5( 149; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 10 150; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[END:%.*]] 151; CHECK: taken: 152; CHECK-NEXT: call void @foo(i32 30) 153; CHECK-NEXT: br label [[END]] 154; CHECK: end: 155; CHECK-NEXT: ret void 156; 157 %cmp1 = icmp ugt i32 %a, 10 158 br i1 %cmp1, label %taken, label %end 159 160taken: 161 %cmp2 = icmp ugt i32 %a, 9 162 %c = select i1 %cmp2, i32 30, i32 0 163 call void @foo(i32 %c) 164 br label %end 165 166end: 167 ret void 168} 169 170declare void @foo(i32) 171declare i32 @bar(i32) 172 173define i32 @test_and(i32 %a, i32 %b) { 174; CHECK-LABEL: @test_and( 175; CHECK-NEXT: entry: 176; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 0 177; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[B:%.*]], 0 178; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] 179; CHECK-NEXT: br i1 [[AND]], label [[TPATH:%.*]], label [[END:%.*]] 180; CHECK: tpath: 181; CHECK-NEXT: ret i32 313 182; CHECK: end: 183; CHECK-NEXT: ret i32 0 184; 185entry: 186 %cmp1 = icmp ne i32 %a, 0 187 %cmp2 = icmp ne i32 %b, 0 188 %and = and i1 %cmp1, %cmp2 189 br i1 %and, label %tpath, label %end 190 191tpath: 192 %cmp3 = icmp eq i32 %a, 0 ;; <-- implied false 193 %c = select i1 %cmp3, i32 0, i32 313 194 ret i32 %c 195 196end: 197 ret i32 0 198} 199 200; cmp1 and cmp2 are false on the 'fpath' path and thus cmp3 is true. 201 202define i32 @test_or1(i32 %a, i32 %b) { 203; CHECK-LABEL: @test_or1( 204; CHECK-NEXT: entry: 205; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 0 206; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[B:%.*]], 0 207; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]] 208; CHECK-NEXT: br i1 [[OR]], label [[END:%.*]], label [[FPATH:%.*]] 209; CHECK: fpath: 210; CHECK-NEXT: ret i32 37 211; CHECK: end: 212; CHECK-NEXT: ret i32 0 213; 214entry: 215 %cmp1 = icmp eq i32 %a, 0 216 %cmp2 = icmp eq i32 %b, 0 217 %or = or i1 %cmp1, %cmp2 218 br i1 %or, label %end, label %fpath 219 220fpath: 221 %cmp3 = icmp ne i32 %a, 0 ;; <-- implied true 222 %c = select i1 %cmp3, i32 37, i32 0 223 ret i32 %c 224 225end: 226 ret i32 0 227} 228 229; LHS ==> RHS by definition (true -> true) 230 231define void @test6(i32 %a, i32 %b) { 232; CHECK-LABEL: @test6( 233; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]] 234; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[END:%.*]] 235; CHECK: taken: 236; CHECK-NEXT: call void @foo(i32 10) 237; CHECK-NEXT: br label [[END]] 238; CHECK: end: 239; CHECK-NEXT: ret void 240; 241 %cmp1 = icmp eq i32 %a, %b 242 br i1 %cmp1, label %taken, label %end 243 244taken: 245 %c = select i1 %cmp1, i32 10, i32 0 246 call void @foo(i32 %c) 247 br label %end 248 249end: 250 ret void 251} 252 253; LHS ==> RHS by definition (false -> false) 254 255define void @test7(i32 %a, i32 %b) { 256; CHECK-LABEL: @test7( 257; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]] 258; CHECK-NEXT: br i1 [[CMP1]], label [[END:%.*]], label [[TAKEN:%.*]] 259; CHECK: taken: 260; CHECK-NEXT: call void @foo(i32 11) 261; CHECK-NEXT: br label [[END]] 262; CHECK: end: 263; CHECK-NEXT: ret void 264; 265 %cmp1 = icmp eq i32 %a, %b 266 br i1 %cmp1, label %end, label %taken 267 268taken: 269 %c = select i1 %cmp1, i32 0, i32 11 270 call void @foo(i32 %c) 271 br label %end 272 273end: 274 ret void 275} 276 277