1 ; RUN: opt < %s -jump-threading -dce -S | FileCheck %s 2 3 declare void @llvm.experimental.guard(i1, ...) 4 5 declare i32 @f1() 6 declare i32 @f2() 7 8 define i32 @branch_implies_guard(i32 %a) { 9 ; CHECK-LABEL: @branch_implies_guard( 10 %cond = icmp slt i32 %a, 10 11 br i1 %cond, label %T1, label %F1 12 13 T1: 14 ; CHECK: T1.split 15 ; CHECK: %v1 = call i32 @f1() 16 ; CHECK-NEXT: %retVal 17 ; CHECK-NEXT: br label %Merge 18 %v1 = call i32 @f1() 19 br label %Merge 20 21 F1: 22 ; CHECK: F1.split 23 ; CHECK: %v2 = call i32 @f2() 24 ; CHECK-NEXT: %retVal 25 ; CHECK-NEXT: %condGuard 26 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard 27 ; CHECK-NEXT: br label %Merge 28 %v2 = call i32 @f2() 29 br label %Merge 30 31 Merge: 32 ; CHECK: Merge 33 ; CHECK-NOT: call void(i1, ...) @llvm.experimental.guard( 34 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 35 %retVal = add i32 %retPhi, 10 36 %condGuard = icmp slt i32 %a, 20 37 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 38 ret i32 %retVal 39 } 40 41 define i32 @not_branch_implies_guard(i32 %a) { 42 ; CHECK-LABEL: @not_branch_implies_guard( 43 %cond = icmp slt i32 %a, 20 44 br i1 %cond, label %T1, label %F1 45 46 T1: 47 ; CHECK: T1.split: 48 ; CHECK-NEXT: %v1 = call i32 @f1() 49 ; CHECK-NEXT: %retVal 50 ; CHECK-NEXT: %condGuard 51 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard 52 ; CHECK-NEXT: br label %Merge 53 %v1 = call i32 @f1() 54 br label %Merge 55 56 F1: 57 ; CHECK: F1.split: 58 ; CHECK-NEXT: %v2 = call i32 @f2() 59 ; CHECK-NEXT: %retVal 60 ; CHECK-NEXT: br label %Merge 61 %v2 = call i32 @f2() 62 br label %Merge 63 64 Merge: 65 ; CHECK: Merge 66 ; CHECK-NOT: call void(i1, ...) @llvm.experimental.guard( 67 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 68 %retVal = add i32 %retPhi, 10 69 %condGuard = icmp sgt i32 %a, 10 70 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 71 ret i32 %retVal 72 } 73 74 define i32 @branch_overlaps_guard(i32 %a) { 75 ; CHECK-LABEL: @branch_overlaps_guard( 76 %cond = icmp slt i32 %a, 20 77 br i1 %cond, label %T1, label %F1 78 79 T1: 80 ; CHECK: T1: 81 ; CHECK-NEXT: %v1 = call i32 @f1() 82 ; CHECK-NEXT: br label %Merge 83 %v1 = call i32 @f1() 84 br label %Merge 85 86 F1: 87 ; CHECK: F1: 88 ; CHECK-NEXT: %v2 = call i32 @f2() 89 ; CHECK-NEXT: br label %Merge 90 %v2 = call i32 @f2() 91 br label %Merge 92 93 Merge: 94 ; CHECK: Merge 95 ; CHECK: %condGuard = icmp slt i32 %a, 10 96 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 97 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 98 %retVal = add i32 %retPhi, 10 99 %condGuard = icmp slt i32 %a, 10 100 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 101 ret i32 %retVal 102 } 103 104 define i32 @branch_doesnt_overlap_guard(i32 %a) { 105 ; CHECK-LABEL: @branch_doesnt_overlap_guard( 106 %cond = icmp slt i32 %a, 10 107 br i1 %cond, label %T1, label %F1 108 109 T1: 110 ; CHECK: T1: 111 ; CHECK-NEXT: %v1 = call i32 @f1() 112 ; CHECK-NEXT: br label %Merge 113 %v1 = call i32 @f1() 114 br label %Merge 115 116 F1: 117 ; CHECK: F1: 118 ; CHECK-NEXT: %v2 = call i32 @f2() 119 ; CHECK-NEXT: br label %Merge 120 %v2 = call i32 @f2() 121 br label %Merge 122 123 Merge: 124 ; CHECK: Merge 125 ; CHECK: %condGuard = icmp sgt i32 %a, 20 126 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 127 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 128 %retVal = add i32 %retPhi, 10 129 %condGuard = icmp sgt i32 %a, 20 130 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 131 ret i32 %retVal 132 } 133 134 define i32 @not_a_diamond1(i32 %a, i1 %cond1) { 135 ; CHECK-LABEL: @not_a_diamond1( 136 br i1 %cond1, label %Pred, label %Exit 137 138 Pred: 139 ; CHECK: Pred: 140 ; CHECK-NEXT: switch i32 %a, label %Exit 141 switch i32 %a, label %Exit [ 142 i32 10, label %Merge 143 i32 20, label %Merge 144 ] 145 146 Merge: 147 ; CHECK: Merge: 148 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] 149 ; CHECK-NEXT: br label %Exit 150 call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] 151 br label %Exit 152 153 Exit: 154 ; CHECK: Exit: 155 ; CHECK-NEXT: ret i32 %a 156 ret i32 %a 157 } 158 159 define void @not_a_diamond2(i32 %a, i1 %cond1) { 160 ; CHECK-LABEL: @not_a_diamond2( 161 br label %Parent 162 163 Merge: 164 call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ] 165 ret void 166 167 Pred: 168 ; CHECK-NEXT: Pred: 169 ; CHECK-NEXT: switch i32 %a, label %Exit 170 switch i32 %a, label %Exit [ 171 i32 10, label %Merge 172 i32 20, label %Merge 173 ] 174 175 Parent: 176 br label %Pred 177 178 Exit: 179 ; CHECK: Merge: 180 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] 181 ; CHECK-NEXT: ret void 182 ret void 183 } 184 185 declare void @never_called(i1) 186 187 ; LVI uses guard to identify value of %c2 in branch as true, we cannot replace that 188 ; guard with guard(true & c1). 189 define void @dont_fold_guard(i8* %addr, i32 %i, i32 %length) { 190 ; CHECK-LABEL: dont_fold_guard 191 ; CHECK: %wide.chk = and i1 %c1, %c2 192 ; CHECK-NEXT: experimental.guard(i1 %wide.chk) 193 ; CHECK-NEXT: call void @never_called(i1 true) 194 ; CHECK-NEXT: ret void 195 %c1 = icmp ult i32 %i, %length 196 %c2 = icmp eq i32 %i, 0 197 %wide.chk = and i1 %c1, %c2 198 call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ] 199 br i1 %c2, label %BB1, label %BB2 200 201 BB1: 202 call void @never_called(i1 %c2) 203 ret void 204 205 BB2: 206 ret void 207 } 208 209 declare void @dummy(i1) nounwind argmemonly 210 ; same as dont_fold_guard1 but there's a use immediately after guard and before 211 ; branch. We can fold that use. 212 define void @dont_fold_guard2(i8* %addr, i32 %i, i32 %length) { 213 ; CHECK-LABEL: dont_fold_guard2 214 ; CHECK: %wide.chk = and i1 %c1, %c2 215 ; CHECK-NEXT: experimental.guard(i1 %wide.chk) 216 ; CHECK-NEXT: dummy(i1 true) 217 ; CHECK-NEXT: call void @never_called(i1 true) 218 ; CHECK-NEXT: ret void 219 %c1 = icmp ult i32 %i, %length 220 %c2 = icmp eq i32 %i, 0 221 %wide.chk = and i1 %c1, %c2 222 call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ] 223 call void @dummy(i1 %c2) 224 br i1 %c2, label %BB1, label %BB2 225 226 BB1: 227 call void @never_called(i1 %c2) 228 ret void 229 230 BB2: 231 ret void 232 } 233 234 ; same as dont_fold_guard1 but condition %cmp is not an instruction. 235 ; We cannot fold the guard under any circumstance. 236 ; FIXME: We can merge unreachableBB2 into not_zero. 237 define void @dont_fold_guard3(i8* %addr, i1 %cmp, i32 %i, i32 %length) { 238 ; CHECK-LABEL: dont_fold_guard3 239 ; CHECK: guard(i1 %cmp) 240 call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] 241 br i1 %cmp, label %BB1, label %BB2 242 243 BB1: 244 call void @never_called(i1 %cmp) 245 ret void 246 247 BB2: 248 ret void 249 } 250 251 declare void @f(i1) 252 ; Same as dont_fold_guard1 but use switch instead of branch. 253 ; triggers source code `ProcessThreadableEdges`. 254 define void @dont_fold_guard4(i1 %cmp1, i32 %i) nounwind { 255 ; CHECK-LABEL: dont_fold_guard4 256 ; CHECK-LABEL: L2: 257 ; CHECK-NEXT: %cmp = icmp eq i32 %i, 0 258 ; CHECK-NEXT: guard(i1 %cmp) 259 ; CHECK-NEXT: dummy(i1 true) 260 ; CHECK-NEXT: @f(i1 true) 261 ; CHECK-NEXT: ret void 262 entry: 263 br i1 %cmp1, label %L0, label %L3 264 L0: 265 %cmp = icmp eq i32 %i, 0 266 call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] 267 call void @dummy(i1 %cmp) 268 switch i1 %cmp, label %L3 [ 269 i1 false, label %L1 270 i1 true, label %L2 271 ] 272 273 L1: 274 ret void 275 L2: 276 call void @f(i1 %cmp) 277 ret void 278 L3: 279 ret void 280 } 281 282 ; Make sure that we don't PRE a non-speculable load across a guard. 283 define void @unsafe_pre_across_guard(i8* %p, i1 %load.is.valid) { 284 285 ; CHECK-LABEL: @unsafe_pre_across_guard( 286 ; CHECK-NOT: loaded.pr 287 ; CHECK: entry: 288 ; CHECK-NEXT: br label %loop 289 ; CHECK: loop: 290 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ] 291 ; CHECK-NEXT: %loaded = load i8, i8* %p 292 ; CHECK-NEXT: %continue = icmp eq i8 %loaded, 0 293 ; CHECK-NEXT: br i1 %continue, label %exit, label %loop 294 entry: 295 br label %loop 296 297 loop: ; preds = %loop, %entry 298 call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ] 299 %loaded = load i8, i8* %p 300 %continue = icmp eq i8 %loaded, 0 301 br i1 %continue, label %exit, label %loop 302 303 exit: ; preds = %loop 304 ret void 305 } 306 307 ; Make sure that we can safely PRE a speculable load across a guard. 308 define void @safe_pre_across_guard(i8* noalias nocapture readonly dereferenceable(8) %p, i1 %load.is.valid) { 309 310 ; CHECK-LABEL: @safe_pre_across_guard( 311 ; CHECK: entry: 312 ; CHECK-NEXT: %loaded.pr = load i8, i8* %p 313 ; CHECK-NEXT: br label %loop 314 ; CHECK: loop: 315 ; CHECK-NEXT: %loaded = phi i8 [ %loaded, %loop ], [ %loaded.pr, %entry ] 316 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ] 317 ; CHECK-NEXT: %continue = icmp eq i8 %loaded, 0 318 ; CHECK-NEXT: br i1 %continue, label %exit, label %loop 319 320 entry: 321 br label %loop 322 323 loop: ; preds = %loop, %entry 324 call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ] 325 %loaded = load i8, i8* %p 326 %continue = icmp eq i8 %loaded, 0 327 br i1 %continue, label %exit, label %loop 328 329 exit: ; preds = %loop 330 ret void 331 } 332 333 ; Make sure that we don't PRE a non-speculable load across a call which may 334 ; alias with the load. 335 define void @unsafe_pre_across_call(i8* %p) { 336 337 ; CHECK-LABEL: @unsafe_pre_across_call( 338 ; CHECK-NOT: loaded.pr 339 ; CHECK: entry: 340 ; CHECK-NEXT: br label %loop 341 ; CHECK: loop: 342 ; CHECK-NEXT: call i32 @f1() 343 ; CHECK-NEXT: %loaded = load i8, i8* %p 344 ; CHECK-NEXT: %continue = icmp eq i8 %loaded, 0 345 ; CHECK-NEXT: br i1 %continue, label %exit, label %loop 346 entry: 347 br label %loop 348 349 loop: ; preds = %loop, %entry 350 call i32 @f1() 351 %loaded = load i8, i8* %p 352 %continue = icmp eq i8 %loaded, 0 353 br i1 %continue, label %exit, label %loop 354 355 exit: ; preds = %loop 356 ret void 357 } 358 359 ; Make sure that we can safely PRE a speculable load across a call. 360 define void @safe_pre_across_call(i8* noalias nocapture readonly dereferenceable(8) %p) { 361 362 ; CHECK-LABEL: @safe_pre_across_call( 363 ; CHECK: entry: 364 ; CHECK-NEXT: %loaded.pr = load i8, i8* %p 365 ; CHECK-NEXT: br label %loop 366 ; CHECK: loop: 367 ; CHECK-NEXT: %loaded = phi i8 [ %loaded, %loop ], [ %loaded.pr, %entry ] 368 ; CHECK-NEXT: call i32 @f1() 369 ; CHECK-NEXT: %continue = icmp eq i8 %loaded, 0 370 ; CHECK-NEXT: br i1 %continue, label %exit, label %loop 371 372 entry: 373 br label %loop 374 375 loop: ; preds = %loop, %entry 376 call i32 @f1() 377 %loaded = load i8, i8* %p 378 %continue = icmp eq i8 %loaded, 0 379 br i1 %continue, label %exit, label %loop 380 381 exit: ; preds = %loop 382 ret void 383 } 384