298 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -S -passes=jump-threading,verify < %s | FileCheck %s3 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 48 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:%.*]], 016; 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:%.*]], 020; CHECK-NEXT: br i1 [[TOBOOL1]], label [[BB_F4:%.*]], label [[BB_F2:%.*]]21; CHECK: bb.cond2.thread:22; CHECK-NEXT: [[TOBOOL12:%.*]] = icmp eq i32 [[COND2]], 023; 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 void36;37entry:38 %tobool = icmp eq i32 %cond1, 039 br i1 %tobool, label %bb.cond2, label %bb.f140 41bb.f1:42 call void @f1()43 br label %bb.cond244 45bb.cond2:46 %ptr = phi ptr [ null, %bb.f1 ], [ @a, %entry ]47 %tobool1 = icmp eq i32 %cond2, 048 br i1 %tobool1, label %bb.file, label %bb.f249 50bb.f2:51 call void @f2()52 br label %exit53 54bb.file:55 %cmp = icmp eq ptr %ptr, null56 br i1 %cmp, label %bb.f4, label %bb.f357 58bb.f3:59 call void @f3()60 br label %exit61 62bb.f4:63 call void @f4()64 br label %exit65 66exit:67 ret void68}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:%.*]], 083; 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:%.*]], 087; 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]], 091; 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 void100;101entry:102 %tobool = icmp ne i32 %cond1, 0103 br i1 %tobool, label %bb.f1, label %bb.f2104 105bb.f1:106 call void @f1()107 br label %bb.cond2108 109bb.f2:110 call void @f2()111 br label %bb.cond2112 113bb.cond2:114 %tobool1 = icmp eq i32 %cond2, 0115 br i1 %tobool1, label %exit, label %bb.cond1again116 117bb.cond1again:118 br i1 %tobool, label %bb.f3, label %bb.f4119 120bb.f3:121 call void @f3()122 br label %exit123 124bb.f4:125 call void @f4()126 br label %exit127 128exit:129 ret void130}131 132 133; Verify that we thread the edge correctly. We used to evaluate constant134; 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:%.*]], null144; CHECK-NEXT: br i1 [[CMP1]], label [[BB_END_THREAD:%.*]], label [[BB_END:%.*]]145; CHECK: bb_end:146; CHECK-NEXT: [[CMP2:%.*]] = icmp ne ptr [[ARG2:%.*]], null147; 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]], null151; 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 void163;164entry:165 %cmp1 = icmp eq ptr %arg1, null166 br i1 %cmp1, label %bb_bar1, label %bb_end167 168bb_bar1:169 call void @bar(i32 1)170 br label %bb_end171 172bb_end:173 %cmp2 = icmp ne ptr %arg2, null174 br i1 %cmp2, label %bb_cont, label %bb_bar2175 176bb_bar2:177 call void @bar(i32 2)178 br label %bb_exit179 180bb_cont:181 %cmp3 = icmp ult ptr %arg1, inttoptr (i64 4 to ptr)182 br i1 %cmp3, label %bb_exit, label %bb_bar3183 184bb_bar3:185 call void @bar(i32 3)186 br label %bb_exit187 188bb_exit:189 ret void190}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:%.*]], null199; CHECK-NEXT: br i1 [[CMP1]], label [[BB_END_THREAD:%.*]], label [[BB_END:%.*]]200; CHECK: bb_end:201; CHECK-NEXT: [[CMP2:%.*]] = icmp ne ptr [[ARG2:%.*]], null202; 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]], null206; 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 void218;219entry:220 %cmp1 = icmp eq ptr %arg1, null221 br i1 %cmp1, label %bb_bar1, label %bb_end222 223bb_bar1:224 call void @bar(i32 1)225 br label %bb_end226 227bb_end:228 %cmp2 = icmp ne ptr %arg2, null229 br i1 %cmp2, label %bb_cont, label %bb_bar2230 231bb_bar2:232 call void @bar(i32 2)233 br label %bb_exit234 235bb_cont:236 %cmp3 = icmp ule ptr %arg1, inttoptr (i64 4 to ptr)237 br i1 %cmp3, label %bb_exit, label %bb_bar3238 239bb_bar3:240 call void @bar(i32 3)241 br label %bb_exit242 243bb_exit:244 ret void245}246 247declare void @bar(i32)248 249 250;; Test that we skip unconditional PredBB when threading jumps through two251;; 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]], 3258; 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 4264; 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, 3274 br i1 %good, label %pred.bb, label %pred.pred.bb275 276pred.pred.bb: ; preds = %entry277 call void @effect()278 br label %pred.bb279pred.bb: ; preds = %pred.pred.bb, %entry280 %v = load i32, ptr %0281 br label %bb282 283bb: ; preds = %pred.bb284 call void @effect1(ptr blockaddress(@foo4, %bb))285 br i1 %good, label %cont2, label %cont1286 287cont1: ; preds = %bb288 br i1 %good, label %exit, label %cont2289cont2: ; preds = %bb290 br label %exit291exit: ; preds = %cont1, %cont2292 ret i32 %v293}294 295declare i64 @get_size(ptr)296declare void @effect()297declare void @effect1(ptr)298