1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -jump-threading -S -verify | 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 i32* [ 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 i32* [ 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 i32* %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 do *not* thread any edge. We used to evaluate 134; constant expressions like: 135; 136; icmp ugt i8* null, inttoptr (i64 4 to i8*) 137; 138; as "true", causing jump threading to a wrong destination. 139 140define void @icmp_ult_null_constexpr(i8* %arg1, i8* %arg2) { 141; CHECK-LABEL: @icmp_ult_null_constexpr( 142; CHECK-NEXT: entry: 143; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8* [[ARG1:%.*]], null 144; CHECK-NEXT: br i1 [[CMP1]], label [[BB_BAR1:%.*]], label [[BB_END:%.*]] 145; CHECK: bb_bar1: 146; CHECK-NEXT: call void @bar(i32 1) 147; CHECK-NEXT: br label [[BB_END]] 148; CHECK: bb_end: 149; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8* [[ARG2:%.*]], null 150; CHECK-NEXT: br i1 [[CMP2]], label [[BB_CONT:%.*]], label [[BB_BAR2:%.*]] 151; CHECK: bb_bar2: 152; CHECK-NEXT: call void @bar(i32 2) 153; CHECK-NEXT: br label [[BB_EXIT:%.*]] 154; CHECK: bb_cont: 155; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i8* [[ARG1]], inttoptr (i64 4 to i8*) 156; CHECK-NEXT: br i1 [[CMP3]], label [[BB_EXIT]], label [[BB_BAR3:%.*]] 157; CHECK: bb_bar3: 158; CHECK-NEXT: call void @bar(i32 3) 159; CHECK-NEXT: br label [[BB_EXIT]] 160; CHECK: bb_exit: 161; CHECK-NEXT: ret void 162; 163entry: 164 %cmp1 = icmp eq i8* %arg1, null 165 br i1 %cmp1, label %bb_bar1, label %bb_end 166 167bb_bar1: 168 call void @bar(i32 1) 169 br label %bb_end 170 171bb_end: 172 %cmp2 = icmp ne i8* %arg2, null 173 br i1 %cmp2, label %bb_cont, label %bb_bar2 174 175bb_bar2: 176 call void @bar(i32 2) 177 br label %bb_exit 178 179bb_cont: 180 %cmp3 = icmp ult i8* %arg1, inttoptr (i64 4 to i8*) 181 br i1 %cmp3, label %bb_exit, label %bb_bar3 182 183bb_bar3: 184 call void @bar(i32 3) 185 br label %bb_exit 186 187bb_exit: 188 ret void 189} 190 191; This is a special-case of the above pattern: 192; Null is guaranteed to be unsigned <= all values. 193 194define void @icmp_ule_null_constexpr(i8* %arg1, i8* %arg2) { 195; CHECK-LABEL: @icmp_ule_null_constexpr( 196; CHECK-NEXT: entry: 197; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8* [[ARG1:%.*]], null 198; CHECK-NEXT: br i1 [[CMP1]], label [[BB_END_THREAD:%.*]], label [[BB_END:%.*]] 199; CHECK: bb_end: 200; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8* [[ARG2:%.*]], null 201; CHECK-NEXT: br i1 [[CMP2]], label [[BB_CONT:%.*]], label [[BB_BAR2:%.*]] 202; CHECK: bb_end.thread: 203; CHECK-NEXT: call void @bar(i32 1) 204; CHECK-NEXT: [[CMP21:%.*]] = icmp ne i8* [[ARG2]], null 205; CHECK-NEXT: br i1 [[CMP21]], label [[BB_EXIT:%.*]], label [[BB_BAR2]] 206; CHECK: bb_bar2: 207; CHECK-NEXT: call void @bar(i32 2) 208; CHECK-NEXT: br label [[BB_EXIT]] 209; CHECK: bb_cont: 210; CHECK-NEXT: [[CMP3:%.*]] = icmp ule i8* [[ARG1]], inttoptr (i64 4 to i8*) 211; CHECK-NEXT: br i1 [[CMP3]], label [[BB_EXIT]], label [[BB_BAR3:%.*]] 212; CHECK: bb_bar3: 213; CHECK-NEXT: call void @bar(i32 3) 214; CHECK-NEXT: br label [[BB_EXIT]] 215; CHECK: bb_exit: 216; CHECK-NEXT: ret void 217; 218entry: 219 %cmp1 = icmp eq i8* %arg1, null 220 br i1 %cmp1, label %bb_bar1, label %bb_end 221 222bb_bar1: 223 call void @bar(i32 1) 224 br label %bb_end 225 226bb_end: 227 %cmp2 = icmp ne i8* %arg2, null 228 br i1 %cmp2, label %bb_cont, label %bb_bar2 229 230bb_bar2: 231 call void @bar(i32 2) 232 br label %bb_exit 233 234bb_cont: 235 %cmp3 = icmp ule i8* %arg1, inttoptr (i64 4 to i8*) 236 br i1 %cmp3, label %bb_exit, label %bb_bar3 237 238bb_bar3: 239 call void @bar(i32 3) 240 br label %bb_exit 241 242bb_exit: 243 ret void 244} 245 246declare void @bar(i32) 247 248 249;; Test that we skip unconditional PredBB when threading jumps through two 250;; successive basic blocks. 251 252define i32 @foo4(i32* %0) { 253; CHECK-LABEL: @foo4( 254; CHECK-NEXT: entry: 255; CHECK-NEXT: [[SIZE:%.*]] = call i64 @get_size(i32* [[TMP0:%.*]]) 256; CHECK-NEXT: [[GOOD:%.*]] = icmp ugt i64 [[SIZE]], 3 257; CHECK-NEXT: br i1 [[GOOD]], label [[PRED_BB:%.*]], label [[PRED_PRED_BB:%.*]] 258; CHECK: pred.pred.bb: 259; CHECK-NEXT: call void @effect() 260; CHECK-NEXT: br label [[PRED_BB]] 261; CHECK: pred.bb: 262; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[TMP0]], align 4 263; CHECK-NEXT: br label [[BB:%.*]] 264; CHECK: bb: 265; CHECK-NEXT: call void @effect1(i8* blockaddress(@foo4, [[BB]])) 266; CHECK-NEXT: br i1 [[GOOD]], label [[EXIT:%.*]], label [[EXIT]] 267; CHECK: exit: 268; CHECK-NEXT: ret i32 [[V]] 269; 270entry: 271 %size = call i64 @get_size(i32* %0) 272 %good = icmp ugt i64 %size, 3 273 br i1 %good, label %pred.bb, label %pred.pred.bb 274 275pred.pred.bb: ; preds = %entry 276 call void @effect() 277 br label %pred.bb 278pred.bb: ; preds = %pred.pred.bb, %entry 279 %v = load i32, i32* %0 280 br label %bb 281 282bb: ; preds = %pred.bb 283 call void @effect1(i8* blockaddress(@foo4, %bb)) 284 br i1 %good, label %cont2, label %cont1 285 286cont1: ; preds = %bb 287 br i1 %good, label %exit, label %cont2 288cont2: ; preds = %bb 289 br label %exit 290exit: ; preds = %cont1, %cont2 291 ret i32 %v 292} 293 294declare i64 @get_size(i32*) 295declare void @effect() 296declare void @effect1(i8*) 297