452 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 22; RUN: opt -passes=flatten-cfg -S < %s | FileCheck %s3 4 5; This test checks whether the pass completes without a crash.6; The code is not transformed in any way7define void @test_not_crash(i32 %in_a) #0 {8; CHECK-LABEL: define void @test_not_crash9; CHECK-SAME: (i32 [[IN_A:%.*]]) {10; CHECK-NEXT: entry:11; CHECK-NEXT: [[CMP0:%.*]] = icmp eq i32 [[IN_A]], -112; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[IN_A]], 013; CHECK-NEXT: [[COND0:%.*]] = and i1 [[CMP0]], [[CMP1]]14; CHECK-NEXT: br i1 [[COND0]], label [[B0:%.*]], label [[B1:%.*]]15; CHECK: b0:16; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[IN_A]], 017; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i32 [[IN_A]], 118; CHECK-NEXT: [[COND1:%.*]] = or i1 [[CMP2]], [[CMP3]]19; CHECK-NEXT: br i1 [[COND1]], label [[EXIT:%.*]], label [[B1]]20; CHECK: b1:21; CHECK-NEXT: br label [[EXIT]]22; CHECK: exit:23; CHECK-NEXT: ret void24;25entry:26 %cmp0 = icmp eq i32 %in_a, -127 %cmp1 = icmp ne i32 %in_a, 028 %cond0 = and i1 %cmp0, %cmp129 br i1 %cond0, label %b0, label %b130 31b0: ; preds = %entry32 %cmp2 = icmp eq i32 %in_a, 033 %cmp3 = icmp ne i32 %in_a, 134 %cond1 = or i1 %cmp2, %cmp335 br i1 %cond1, label %exit, label %b136 37b1: ; preds = %entry, %b038 br label %exit39 40exit: ; preds = %entry, %b0, %b141 ret void42}43 44define void @test_not_crash2(float %a, float %b) #0 {45; CHECK-LABEL: define void @test_not_crash246; CHECK-SAME: (float [[A:%.*]], float [[B:%.*]]) {47; CHECK-NEXT: entry:48; CHECK-NEXT: [[TMP0:%.*]] = fcmp ult float [[A]], 1.000000e+0049; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult float [[B]], 1.000000e+0050; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP0]], [[TMP1]]51; CHECK-NEXT: br i1 [[TMP2]], label [[BB4:%.*]], label [[BB3:%.*]]52; CHECK: bb3:53; CHECK-NEXT: br label [[BB4]]54; CHECK: bb4:55; CHECK-NEXT: ret void56;57entry:58 %0 = fcmp ult float %a, 1.000000e+0059 br i1 %0, label %bb0, label %bb160 61bb3: ; preds = %bb062 br label %bb463 64bb4: ; preds = %bb0, %bb365 ret void66 67bb1: ; preds = %entry68 br label %bb069 70bb0: ; preds = %bb1, %entry71 %1 = fcmp ult float %b, 1.000000e+0072 br i1 %1, label %bb4, label %bb373}74 75define void @test_not_crash3(i32 %a) #0 {76; CHECK-LABEL: define void @test_not_crash377; CHECK-SAME: (i32 [[A:%.*]]) {78; CHECK-NEXT: entry:79; CHECK-NEXT: [[A_EQ_0:%.*]] = icmp eq i32 [[A]], 080; CHECK-NEXT: br i1 [[A_EQ_0]], label [[BB0:%.*]], label [[BB1:%.*]]81; CHECK: bb0:82; CHECK-NEXT: br label [[BB1]]83; CHECK: bb1:84; CHECK-NEXT: [[A_EQ_1:%.*]] = icmp eq i32 [[A]], 185; CHECK-NEXT: br i1 [[A_EQ_1]], label [[BB2:%.*]], label [[BB3:%.*]]86; CHECK: bb2:87; CHECK-NEXT: br label [[BB3]]88; CHECK: bb3:89; CHECK-NEXT: [[CHECK_BADREF:%.*]] = phi i32 [ 17, [[BB1]] ], [ 11, [[BB2]] ]90; CHECK-NEXT: ret void91;92entry:93 %a_eq_0 = icmp eq i32 %a, 094 br i1 %a_eq_0, label %bb0, label %bb195 96bb0: ; preds = %entry97 br label %bb198 99bb1: ; preds = %bb0, %entry100 %a_eq_1 = icmp eq i32 %a, 1101 br i1 %a_eq_1, label %bb2, label %bb3102 103bb2: ; preds = %bb1104 br label %bb3105 106bb3: ; preds = %bb2, %bb1107 %check_badref = phi i32 [ 17, %bb1 ], [ 11, %bb2 ]108 ret void109}110 111 112@g = global i32 0, align 4113 114define void @test_then(i32 %x, i32 %y, i32 %z) {115; CHECK-LABEL: define void @test_then116; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {117; CHECK-NEXT: entry.x:118; CHECK-NEXT: [[CMP_X:%.*]] = icmp ne i32 [[X]], 0119; CHECK-NEXT: [[CMP_Y:%.*]] = icmp ne i32 [[Y]], 0120; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP_X]], [[CMP_Y]]121; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN_Y:%.*]], label [[EXIT:%.*]]122; CHECK: if.then.y:123; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4124; CHECK-NEXT: br label [[EXIT]]125; CHECK: exit:126; CHECK-NEXT: ret void127;128entry.x:129 %cmp.x = icmp ne i32 %x, 0130 br i1 %cmp.x, label %if.then.x, label %entry.y131 132if.then.x:133 store i32 %z, ptr @g, align 4134 br label %entry.y135 136entry.y:137 %cmp.y = icmp ne i32 %y, 0138 br i1 %cmp.y, label %if.then.y, label %exit139 140if.then.y:141 store i32 %z, ptr @g, align 4142 br label %exit143 144exit:145 ret void146}147 148define void @test_else(i32 %x, i32 %y, i32 %z) {149; CHECK-LABEL: define void @test_else150; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {151; CHECK-NEXT: entry.x:152; CHECK-NEXT: [[CMP_X:%.*]] = icmp eq i32 [[X]], 0153; CHECK-NEXT: [[CMP_Y:%.*]] = icmp eq i32 [[Y]], 0154; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP_X]], [[CMP_Y]]155; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT:%.*]], label [[IF_ELSE_Y:%.*]]156; CHECK: if.else.y:157; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4158; CHECK-NEXT: br label [[EXIT]]159; CHECK: exit:160; CHECK-NEXT: ret void161;162entry.x:163 %cmp.x = icmp eq i32 %x, 0164 br i1 %cmp.x, label %entry.y, label %if.else.x165 166if.else.x:167 store i32 %z, ptr @g, align 4168 br label %entry.y169 170entry.y:171 %cmp.y = icmp eq i32 %y, 0172 br i1 %cmp.y, label %exit, label %if.else.y173 174if.else.y:175 store i32 %z, ptr @g, align 4176 br label %exit177 178exit:179 ret void180}181 182define void @test_combine_and(i32 %x, i32 %y, i32 %z) {183; CHECK-LABEL: define void @test_combine_and184; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {185; CHECK-NEXT: entry.x:186; CHECK-NEXT: [[CMP_X:%.*]] = icmp eq i32 [[X]], 0187; CHECK-NEXT: [[CMP_Y:%.*]] = icmp eq i32 [[Y]], 0188; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP_X]], [[CMP_Y]]189; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT:%.*]], label [[IF_THEN_Y:%.*]]190; CHECK: if.then.y:191; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4192; CHECK-NEXT: br label [[EXIT]]193; CHECK: exit:194; CHECK-NEXT: ret void195;196entry.x:197 %cmp.x = icmp eq i32 %x, 0198 br i1 %cmp.x, label %entry.y, label %if.else.x199 200if.else.x:201 store i32 %z, ptr @g, align 4202 br label %entry.y203 204entry.y:205 %cmp.y = icmp ne i32 %y, 0206 br i1 %cmp.y, label %if.then.y, label %exit207 208if.then.y:209 store i32 %z, ptr @g, align 4210 br label %exit211 212exit:213 ret void214}215 216define void @test_combine_or(i32 %x, i32 %y, i32 %z) {217; CHECK-LABEL: define void @test_combine_or218; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {219; CHECK-NEXT: entry.x:220; CHECK-NEXT: [[CMP_X:%.*]] = icmp ne i32 [[X]], 0221; CHECK-NEXT: [[CMP_Y:%.*]] = icmp ne i32 [[Y]], 0222; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP_X]], [[CMP_Y]]223; CHECK-NEXT: br i1 [[TMP0]], label [[IF_ELSE_Y:%.*]], label [[EXIT:%.*]]224; CHECK: if.else.y:225; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4226; CHECK-NEXT: br label [[EXIT]]227; CHECK: exit:228; CHECK-NEXT: ret void229;230entry.x:231 %cmp.x = icmp ne i32 %x, 0232 br i1 %cmp.x, label %if.then.x, label %entry.y233 234if.then.x:235 store i32 %z, ptr @g, align 4236 br label %entry.y237 238entry.y:239 %cmp.y = icmp eq i32 %y, 0240 br i1 %cmp.y, label %exit, label %if.else.y241 242if.else.y:243 store i32 %z, ptr @g, align 4244 br label %exit245 246exit:247 ret void248}249 250declare i1 @llvm.smax.i1(i1, i1) #0251 252define void @PR56875(i1 %val_i1_5) {253; CHECK-LABEL: define void @PR56875254; CHECK-SAME: (i1 [[VAL_I1_5:%.*]]) {255; CHECK-NEXT: entry_1:256; CHECK-NEXT: ret void257; CHECK: bb_2:258; CHECK-NEXT: br label [[BB_4:%.*]]259; CHECK: bb_4:260; CHECK-NEXT: [[VAL_I1_46:%.*]] = call i1 @llvm.smax.i1(i1 [[VAL_I1_5]], i1 [[VAL_I1_5]])261; CHECK-NEXT: br i1 [[VAL_I1_46]], label [[BB_4]], label [[BB_2:%.*]]262;263entry_1:264 ret void265 266bb_2: ; preds = %bb_4267 br label %bb_4268 269bb_4: ; preds = %bb_4, %bb_2270 %val_i1_46 = call i1 @llvm.smax.i1(i1 %val_i1_5, i1 %val_i1_5)271 br i1 %val_i1_46, label %bb_4, label %bb_2272}273 274; cmp.y has 2 users, but should be inverted. So that a new one cmp is created instead.275; Branch condition must be replaced with a new created combined condition276; Proof of bug: https://alive2.llvm.org/ce/z/L4ps9v277; Proof of fix: https://alive2.llvm.org/ce/z/QdrG5U278define i1 @test_cond_multi_use(i32 %x, i32 %y, i32 %z) {279; CHECK-LABEL: define i1 @test_cond_multi_use280; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {281; CHECK-NEXT: entry.x:282; CHECK-NEXT: [[CMP_X:%.*]] = icmp ne i32 [[X]], 0283; CHECK-NEXT: [[CMP_Y:%.*]] = icmp eq i32 [[Y]], 0284; CHECK-NEXT: [[CMP_Y_NOT:%.*]] = xor i1 [[CMP_Y]], true285; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP_X]], [[CMP_Y_NOT]]286; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN_Y:%.*]], label [[EXIT:%.*]]287; CHECK: if.then.y:288; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4289; CHECK-NEXT: br label [[EXIT]]290; CHECK: exit:291; CHECK-NEXT: ret i1 [[CMP_Y]]292;293entry.x:294 %cmp.x = icmp ne i32 %x, 0295 br i1 %cmp.x, label %if.then.x, label %entry.y296 297if.then.x:298 store i32 %z, ptr @g, align 4299 br label %entry.y300 301entry.y:302 %cmp.y = icmp eq i32 %y, 0303 br i1 %cmp.y, label %exit, label %if.then.y304 305if.then.y:306 store i32 %z, ptr @g, align 4307 br label %exit308 309exit:310 ret i1 %cmp.y311}312 313declare void @foo()314declare void @bar() #1315 316; Test that two if-regions are not merged when there's potential aliasing317; between a store in the first if-region and a load in the second if-region's header318define i32 @test_alias(i32 %a, i32 %b, ptr %p1, ptr %p2) {319; CHECK-LABEL: define i32 @test_alias320; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]]) {321; CHECK-NEXT: entry:322; CHECK-NEXT: store i32 42, ptr [[P1]], align 4323; CHECK-NEXT: [[COND1:%.*]] = icmp eq i32 [[A]], 0324; CHECK-NEXT: br i1 [[COND1]], label [[IF_THEN1:%.*]], label [[IF_END1:%.*]]325; CHECK: if.then1:326; CHECK-NEXT: store i32 100, ptr [[P2]], align 4327; CHECK-NEXT: br label [[IF_END1]]328; CHECK: if.end1:329; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P1]], align 4330; CHECK-NEXT: [[COND2:%.*]] = icmp eq i32 [[B]], 0331; CHECK-NEXT: br i1 [[COND2]], label [[IF_THEN2:%.*]], label [[IF_END2:%.*]]332; CHECK: if.then2:333; CHECK-NEXT: store i32 100, ptr [[P2]], align 4334; CHECK-NEXT: br label [[IF_END2]]335; CHECK: if.end2:336; CHECK-NEXT: ret i32 0337;338entry:339 store i32 42, ptr %p1340 %cond1 = icmp eq i32 %a, 0341 br i1 %cond1, label %if.then1, label %if.end1342 343if.then1:344 store i32 100, ptr %p2 ; May alias with the load below345 br label %if.end1346 347if.end1:348 %val = load i32, ptr %p1 ; This load prevents merging due to potential alias349 %cond2 = icmp eq i32 %b, 0350 br i1 %cond2, label %if.then2, label %if.end2351 352if.then2:353 store i32 100, ptr %p2354 br label %if.end2355 356if.end2:357 ret i32 0358}359 360; Test that two if-regions are not merged when there's potential aliasing361; between a store in the first if-region and a function call in the second if-region's header362define i32 @test_alias_2(i32 %a, i32 %b) {363; CHECK-LABEL: define i32 @test_alias_2364; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {365; CHECK-NEXT: entry:366; CHECK-NEXT: [[P:%.*]] = alloca i32, align 4367; CHECK-NEXT: store i32 42, ptr [[P]], align 4368; CHECK-NEXT: [[COND1:%.*]] = icmp eq i32 [[A]], 0369; CHECK-NEXT: br i1 [[COND1]], label [[IF_THEN1:%.*]], label [[IF_END1:%.*]]370; CHECK: if.then1:371; CHECK-NEXT: store i32 100, ptr @g, align 4372; CHECK-NEXT: br label [[IF_END1]]373; CHECK: if.end1:374; CHECK-NEXT: call void @foo()375; CHECK-NEXT: [[COND2:%.*]] = icmp eq i32 [[B]], 0376; CHECK-NEXT: br i1 [[COND2]], label [[IF_THEN2:%.*]], label [[IF_END2:%.*]]377; CHECK: if.then2:378; CHECK-NEXT: store i32 100, ptr @g, align 4379; CHECK-NEXT: br label [[IF_END2]]380; CHECK: if.end2:381; CHECK-NEXT: ret i32 0382;383entry:384 %p = alloca i32385 store i32 42, ptr %p386 %cond1 = icmp eq i32 %a, 0387 br i1 %cond1, label %if.then1, label %if.end1388 389if.then1:390 store i32 100, ptr @g391 br label %if.end1392 393if.end1:394 call void @foo()395 %cond2 = icmp eq i32 %b, 0396 br i1 %cond2, label %if.then2, label %if.end2397 398if.then2:399 store i32 100, ptr @g400 br label %if.end2401 402if.end2:403 ret i32 0404}405 406; Test that two if-regions are merged when there's no potential aliasing407; between a store in the first if-region and a load in the second if-region's header408define i32 @test_no_alias(i32 %a, i32 %b) {409; CHECK-LABEL: define i32 @test_no_alias410; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {411; CHECK-NEXT: entry:412; CHECK-NEXT: [[P:%.*]] = alloca i32, align 4413; CHECK-NEXT: store i32 42, ptr [[P]], align 4414; CHECK-NEXT: [[COND1:%.*]] = icmp eq i32 [[A]], 0415; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr @g, align 4416; CHECK-NEXT: [[COND2:%.*]] = icmp eq i32 [[B]], 0417; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND1]], [[COND2]]418; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN2:%.*]], label [[IF_END2:%.*]]419; CHECK: if.then2:420; CHECK-NEXT: store i32 100, ptr [[P]], align 4421; CHECK-NEXT: call void @bar()422; CHECK-NEXT: br label [[IF_END2]]423; CHECK: if.end2:424; CHECK-NEXT: ret i32 0425;426entry:427 %p = alloca i32428 store i32 42, ptr %p429 %cond1 = icmp eq i32 %a, 0430 br i1 %cond1, label %if.then1, label %if.end1431 432if.then1:433 store i32 100, ptr %p ; No alias with the load below434 call void @bar() ; No alias with the load below since it's a pure function435 br label %if.end1436 437if.end1:438 %val = load i32, ptr @g439 %cond2 = icmp eq i32 %b, 0440 br i1 %cond2, label %if.then2, label %if.end2441 442if.then2:443 store i32 100, ptr %p444 call void @bar()445 br label %if.end2446 447if.end2:448 ret i32 0449}450 451attributes #1 = { readnone willreturn nounwind }452