1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=jump-threading,verify < %s | FileCheck %s 3 4target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 5target triple = "x86_64-unknown-linux-gnu" 6 7@a = global i32 0, align 4 8 9; Verify that we branch (twice) on cond2 without checking ptr. 10; Verify that we eliminate "bb.file". 11 12define void @foo(i32 %cond1, i32 %cond2) { 13; CHECK-LABEL: @foo( 14; CHECK-NEXT: entry: 15; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[COND1:%.*]], 0 16; CHECK-NEXT: br i1 [[TOBOOL]], label [[BB_COND2_THREAD:%.*]], label [[BB_COND2:%.*]] 17; CHECK: bb.cond2: 18; CHECK-NEXT: call void @f1() 19; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[COND2:%.*]], 0 20; CHECK-NEXT: br i1 [[TOBOOL1]], label [[BB_F4:%.*]], label [[BB_F2:%.*]] 21; CHECK: bb.cond2.thread: 22; CHECK-NEXT: [[TOBOOL12:%.*]] = icmp eq i32 [[COND2]], 0 23; CHECK-NEXT: br i1 [[TOBOOL12]], label [[BB_F3:%.*]], label [[BB_F2]] 24; CHECK: bb.f2: 25; CHECK-NEXT: call void @f2() 26; CHECK-NEXT: br label [[EXIT:%.*]] 27; CHECK: bb.f3: 28; CHECK-NEXT: call void @f3() 29; CHECK-NEXT: br label [[EXIT]] 30; CHECK: bb.f4: 31; CHECK-NEXT: [[PTR3:%.*]] = phi ptr [ null, [[BB_COND2]] ] 32; CHECK-NEXT: call void @f4() 33; CHECK-NEXT: br label [[EXIT]] 34; CHECK: exit: 35; CHECK-NEXT: ret void 36; 37entry: 38 %tobool = icmp eq i32 %cond1, 0 39 br i1 %tobool, label %bb.cond2, label %bb.f1 40 41bb.f1: 42 call void @f1() 43 br label %bb.cond2 44 45bb.cond2: 46 %ptr = phi ptr [ null, %bb.f1 ], [ @a, %entry ] 47 %tobool1 = icmp eq i32 %cond2, 0 48 br i1 %tobool1, label %bb.file, label %bb.f2 49 50bb.f2: 51 call void @f2() 52 br label %exit 53 54bb.file: 55 %cmp = icmp eq ptr %ptr, null 56 br i1 %cmp, label %bb.f4, label %bb.f3 57 58bb.f3: 59 call void @f3() 60 br label %exit 61 62bb.f4: 63 call void @f4() 64 br label %exit 65 66exit: 67 ret void 68} 69 70declare void @f1() 71declare void @f2() 72declare void @f3() 73declare void @f4() 74 75 76; Verify that we branch (twice) on cond2 without checking tobool again. 77; Verify that we eliminate "bb.cond1again". 78 79define void @foo2(i32 %cond1, i32 %cond2) { 80; CHECK-LABEL: @foo2( 81; CHECK-NEXT: entry: 82; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[COND1:%.*]], 0 83; CHECK-NEXT: br i1 [[TOBOOL]], label [[BB_COND2:%.*]], label [[BB_COND2_THREAD:%.*]] 84; CHECK: bb.cond2: 85; CHECK-NEXT: call void @f1() 86; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[COND2:%.*]], 0 87; CHECK-NEXT: br i1 [[TOBOOL1]], label [[EXIT:%.*]], label [[BB_F3:%.*]] 88; CHECK: bb.cond2.thread: 89; CHECK-NEXT: call void @f2() 90; CHECK-NEXT: [[TOBOOL11:%.*]] = icmp eq i32 [[COND2]], 0 91; CHECK-NEXT: br i1 [[TOBOOL11]], label [[EXIT]], label [[BB_F4:%.*]] 92; CHECK: bb.f3: 93; CHECK-NEXT: call void @f3() 94; CHECK-NEXT: br label [[EXIT]] 95; CHECK: bb.f4: 96; CHECK-NEXT: call void @f4() 97; CHECK-NEXT: br label [[EXIT]] 98; CHECK: exit: 99; CHECK-NEXT: ret void 100; 101entry: 102 %tobool = icmp ne i32 %cond1, 0 103 br i1 %tobool, label %bb.f1, label %bb.f2 104 105bb.f1: 106 call void @f1() 107 br label %bb.cond2 108 109bb.f2: 110 call void @f2() 111 br label %bb.cond2 112 113bb.cond2: 114 %tobool1 = icmp eq i32 %cond2, 0 115 br i1 %tobool1, label %exit, label %bb.cond1again 116 117bb.cond1again: 118 br i1 %tobool, label %bb.f3, label %bb.f4 119 120bb.f3: 121 call void @f3() 122 br label %exit 123 124bb.f4: 125 call void @f4() 126 br label %exit 127 128exit: 129 ret void 130} 131 132 133; Verify that we thread the edge correctly. We used to evaluate constant 134; expressions like: 135; 136; icmp ugt ptr null, inttoptr (i64 4 to ptr) 137; 138; as "true", causing jump threading to a wrong destination. 139 140define void @icmp_ult_null_constexpr(ptr %arg1, ptr %arg2) { 141; CHECK-LABEL: @icmp_ult_null_constexpr( 142; CHECK-NEXT: entry: 143; CHECK-NEXT: [[CMP1:%.*]] = icmp eq ptr [[ARG1:%.*]], null 144; CHECK-NEXT: br i1 [[CMP1]], label [[BB_END_THREAD:%.*]], label [[BB_END:%.*]] 145; CHECK: bb_end: 146; CHECK-NEXT: [[CMP2:%.*]] = icmp ne ptr [[ARG2:%.*]], null 147; CHECK-NEXT: br i1 [[CMP2]], label [[BB_CONT:%.*]], label [[BB_BAR2:%.*]] 148; CHECK: bb_end.thread: 149; CHECK-NEXT: call void @bar(i32 1) 150; CHECK-NEXT: [[CMP21:%.*]] = icmp ne ptr [[ARG2]], null 151; CHECK-NEXT: br i1 [[CMP21]], label [[BB_EXIT:%.*]], label [[BB_BAR2]] 152; CHECK: bb_bar2: 153; CHECK-NEXT: call void @bar(i32 2) 154; CHECK-NEXT: br label [[BB_EXIT]] 155; CHECK: bb_cont: 156; CHECK-NEXT: [[CMP3:%.*]] = icmp ult ptr [[ARG1]], inttoptr (i64 4 to ptr) 157; CHECK-NEXT: br i1 [[CMP3]], label [[BB_EXIT]], label [[BB_BAR3:%.*]] 158; CHECK: bb_bar3: 159; CHECK-NEXT: call void @bar(i32 3) 160; CHECK-NEXT: br label [[BB_EXIT]] 161; CHECK: bb_exit: 162; CHECK-NEXT: ret void 163; 164entry: 165 %cmp1 = icmp eq ptr %arg1, null 166 br i1 %cmp1, label %bb_bar1, label %bb_end 167 168bb_bar1: 169 call void @bar(i32 1) 170 br label %bb_end 171 172bb_end: 173 %cmp2 = icmp ne ptr %arg2, null 174 br i1 %cmp2, label %bb_cont, label %bb_bar2 175 176bb_bar2: 177 call void @bar(i32 2) 178 br label %bb_exit 179 180bb_cont: 181 %cmp3 = icmp ult ptr %arg1, inttoptr (i64 4 to ptr) 182 br i1 %cmp3, label %bb_exit, label %bb_bar3 183 184bb_bar3: 185 call void @bar(i32 3) 186 br label %bb_exit 187 188bb_exit: 189 ret void 190} 191 192; This is a special-case of the above pattern: 193; Null is guaranteed to be unsigned <= all values. 194 195define void @icmp_ule_null_constexpr(ptr %arg1, ptr %arg2) { 196; CHECK-LABEL: @icmp_ule_null_constexpr( 197; CHECK-NEXT: entry: 198; CHECK-NEXT: [[CMP1:%.*]] = icmp eq ptr [[ARG1:%.*]], null 199; CHECK-NEXT: br i1 [[CMP1]], label [[BB_END_THREAD:%.*]], label [[BB_END:%.*]] 200; CHECK: bb_end: 201; CHECK-NEXT: [[CMP2:%.*]] = icmp ne ptr [[ARG2:%.*]], null 202; CHECK-NEXT: br i1 [[CMP2]], label [[BB_CONT:%.*]], label [[BB_BAR2:%.*]] 203; CHECK: bb_end.thread: 204; CHECK-NEXT: call void @bar(i32 1) 205; CHECK-NEXT: [[CMP21:%.*]] = icmp ne ptr [[ARG2]], null 206; CHECK-NEXT: br i1 [[CMP21]], label [[BB_EXIT:%.*]], label [[BB_BAR2]] 207; CHECK: bb_bar2: 208; CHECK-NEXT: call void @bar(i32 2) 209; CHECK-NEXT: br label [[BB_EXIT]] 210; CHECK: bb_cont: 211; CHECK-NEXT: [[CMP3:%.*]] = icmp ule ptr [[ARG1]], inttoptr (i64 4 to ptr) 212; CHECK-NEXT: br i1 [[CMP3]], label [[BB_EXIT]], label [[BB_BAR3:%.*]] 213; CHECK: bb_bar3: 214; CHECK-NEXT: call void @bar(i32 3) 215; CHECK-NEXT: br label [[BB_EXIT]] 216; CHECK: bb_exit: 217; CHECK-NEXT: ret void 218; 219entry: 220 %cmp1 = icmp eq ptr %arg1, null 221 br i1 %cmp1, label %bb_bar1, label %bb_end 222 223bb_bar1: 224 call void @bar(i32 1) 225 br label %bb_end 226 227bb_end: 228 %cmp2 = icmp ne ptr %arg2, null 229 br i1 %cmp2, label %bb_cont, label %bb_bar2 230 231bb_bar2: 232 call void @bar(i32 2) 233 br label %bb_exit 234 235bb_cont: 236 %cmp3 = icmp ule ptr %arg1, inttoptr (i64 4 to ptr) 237 br i1 %cmp3, label %bb_exit, label %bb_bar3 238 239bb_bar3: 240 call void @bar(i32 3) 241 br label %bb_exit 242 243bb_exit: 244 ret void 245} 246 247declare void @bar(i32) 248 249 250;; Test that we skip unconditional PredBB when threading jumps through two 251;; successive basic blocks. 252 253define i32 @foo4(ptr %0) { 254; CHECK-LABEL: @foo4( 255; CHECK-NEXT: entry: 256; CHECK-NEXT: [[SIZE:%.*]] = call i64 @get_size(ptr [[TMP0:%.*]]) 257; CHECK-NEXT: [[GOOD:%.*]] = icmp ugt i64 [[SIZE]], 3 258; CHECK-NEXT: br i1 [[GOOD]], label [[PRED_BB:%.*]], label [[PRED_PRED_BB:%.*]] 259; CHECK: pred.pred.bb: 260; CHECK-NEXT: call void @effect() 261; CHECK-NEXT: br label [[PRED_BB]] 262; CHECK: pred.bb: 263; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[TMP0]], align 4 264; CHECK-NEXT: br label [[BB:%.*]] 265; CHECK: bb: 266; CHECK-NEXT: call void @effect1(ptr blockaddress(@foo4, [[BB]])) 267; CHECK-NEXT: br i1 [[GOOD]], label [[EXIT:%.*]], label [[EXIT]] 268; CHECK: exit: 269; CHECK-NEXT: ret i32 [[V]] 270; 271entry: 272 %size = call i64 @get_size(ptr %0) 273 %good = icmp ugt i64 %size, 3 274 br i1 %good, label %pred.bb, label %pred.pred.bb 275 276pred.pred.bb: ; preds = %entry 277 call void @effect() 278 br label %pred.bb 279pred.bb: ; preds = %pred.pred.bb, %entry 280 %v = load i32, ptr %0 281 br label %bb 282 283bb: ; preds = %pred.bb 284 call void @effect1(ptr blockaddress(@foo4, %bb)) 285 br i1 %good, label %cont2, label %cont1 286 287cont1: ; preds = %bb 288 br i1 %good, label %exit, label %cont2 289cont2: ; preds = %bb 290 br label %exit 291exit: ; preds = %cont1, %cont2 292 ret i32 %v 293} 294 295declare i64 @get_size(ptr) 296declare void @effect() 297declare void @effect1(ptr) 298