1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S -hoist-common-insts=true | FileCheck %s 3 4declare void @bar(i32) 5 6define void @test(i1 %P, ptr %Q) { 7; CHECK-LABEL: @test( 8; CHECK-NEXT: common.ret: 9; CHECK-NEXT: store i32 1, ptr [[Q:%.*]], align 4 10; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[Q]], align 4 11; CHECK-NEXT: call void @bar(i32 [[A]]) 12; CHECK-NEXT: ret void 13; 14 br i1 %P, label %T, label %F 15T: ; preds = %0 16 store i32 1, ptr %Q 17 %A = load i32, ptr %Q ; <i32> [#uses=1] 18 call void @bar( i32 %A ) 19 ret void 20F: ; preds = %0 21 store i32 1, ptr %Q 22 %B = load i32, ptr %Q ; <i32> [#uses=1] 23 call void @bar( i32 %B ) 24 ret void 25} 26 27define void @test_switch(i64 %i, ptr %Q) { 28; CHECK-LABEL: @test_switch( 29; CHECK-NEXT: common.ret: 30; CHECK-NEXT: store i32 1, ptr [[Q:%.*]], align 4 31; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[Q]], align 4 32; CHECK-NEXT: call void @bar(i32 [[A]]) 33; CHECK-NEXT: ret void 34; 35 switch i64 %i, label %bb0 [ 36 i64 1, label %bb1 37 i64 2, label %bb2 38 ] 39bb0: ; preds = %0 40 store i32 1, ptr %Q 41 %A = load i32, ptr %Q ; <i32> [#uses=1] 42 call void @bar( i32 %A ) 43 ret void 44bb1: ; preds = %0 45 store i32 1, ptr %Q 46 %B = load i32, ptr %Q ; <i32> [#uses=1] 47 call void @bar( i32 %B ) 48 ret void 49bb2: ; preds = %0 50 store i32 1, ptr %Q 51 %C = load i32, ptr %Q ; <i32> [#uses=1] 52 call void @bar( i32 %C ) 53 ret void 54} 55 56; We ensure that we examine all instructions during each iteration to confirm the presence of a terminating one. 57define void @test_switch_reach_terminator(i64 %i, ptr %p) { 58; CHECK-LABEL: @test_switch_reach_terminator( 59; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [ 60; CHECK-NEXT: i64 1, label [[BB1:%.*]] 61; CHECK-NEXT: i64 2, label [[COMMON_RET:%.*]] 62; CHECK-NEXT: ] 63; CHECK: common.ret: 64; CHECK-NEXT: ret void 65; CHECK: bb0: 66; CHECK-NEXT: store i32 1, ptr [[P:%.*]], align 4 67; CHECK-NEXT: br label [[COMMON_RET]] 68; CHECK: bb1: 69; CHECK-NEXT: store i32 2, ptr [[P]], align 4 70; CHECK-NEXT: br label [[COMMON_RET]] 71; 72 switch i64 %i, label %bb0 [ 73 i64 1, label %bb1 74 i64 2, label %bb2 75 ] 76bb0: ; preds = %0 77 store i32 1, ptr %p 78 ret void 79bb1: ; preds = %0 80 store i32 2, ptr %p 81 ret void 82bb2: ; preds = %0 83 ret void 84} 85 86define i1 @common_instr_on_switch(i64 %a, i64 %b, i64 %c) unnamed_addr { 87; CHECK-LABEL: @common_instr_on_switch( 88; CHECK-NEXT: start: 89; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]] 90; CHECK-NEXT: ret i1 [[TMP0]] 91; 92start: 93 switch i64 %a, label %bb0 [ 94 i64 1, label %bb1 95 i64 2, label %bb2 96 ] 97 98bb0: ; preds = %start 99 %0 = icmp eq i64 %b, %c 100 br label %exit 101 102bb1: ; preds = %start 103 %1 = icmp eq i64 %b, %c 104 br label %exit 105 106bb2: ; preds = %start 107 %2 = icmp eq i64 %b, %c 108 br label %exit 109 110exit: ; preds = %bb2, %bb1, %bb0 111 %result = phi i1 [ %0, %bb0 ], [ %1, %bb1 ], [ %2, %bb2 ] 112 ret i1 %result 113} 114 115define i1 @partial_common_instr_on_switch(i64 %a, i64 %b, i64 %c) unnamed_addr { 116; CHECK-LABEL: @partial_common_instr_on_switch( 117; CHECK-NEXT: start: 118; CHECK-NEXT: switch i64 [[A:%.*]], label [[BB0:%.*]] [ 119; CHECK-NEXT: i64 1, label [[BB1:%.*]] 120; CHECK-NEXT: i64 2, label [[BB2:%.*]] 121; CHECK-NEXT: ] 122; CHECK: bb0: 123; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]] 124; CHECK-NEXT: br label [[EXIT:%.*]] 125; CHECK: bb1: 126; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[B]], [[C]] 127; CHECK-NEXT: br label [[EXIT]] 128; CHECK: bb2: 129; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[B]], [[C]] 130; CHECK-NEXT: br label [[EXIT]] 131; CHECK: exit: 132; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ [[TMP0]], [[BB0]] ], [ [[TMP1]], [[BB1]] ], [ [[TMP2]], [[BB2]] ] 133; CHECK-NEXT: ret i1 [[RESULT]] 134; 135start: 136 switch i64 %a, label %bb0 [ 137 i64 1, label %bb1 138 i64 2, label %bb2 139 ] 140 141bb0: ; preds = %start 142 %0 = icmp eq i64 %b, %c 143 br label %exit 144 145bb1: ; preds = %start 146 %1 = icmp ne i64 %b, %c 147 br label %exit 148 149bb2: ; preds = %start 150 %2 = icmp eq i64 %b, %c 151 br label %exit 152 153exit: ; preds = %bb2, %bb1, %bb0 154 %result = phi i1 [ %0, %bb0 ], [ %1, %bb1 ], [ %2, %bb2 ] 155 ret i1 %result 156} 157 158declare void @foo() 159 160define i1 @test_icmp_simple(i1 %c, i32 %a, i32 %b) { 161; CHECK-LABEL: @test_icmp_simple( 162; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], [[B:%.*]] 163; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 164; CHECK: common.ret: 165; CHECK-NEXT: ret i1 [[CMP1]] 166; CHECK: if: 167; CHECK-NEXT: call void @foo() 168; CHECK-NEXT: br label [[COMMON_RET:%.*]] 169; CHECK: else: 170; CHECK-NEXT: call void @bar() 171; CHECK-NEXT: br label [[COMMON_RET]] 172; 173 br i1 %c, label %if, label %else 174 175if: 176 %cmp1 = icmp ult i32 %a, %b 177 call void @foo() 178 ret i1 %cmp1 179 180else: 181 %cmp2 = icmp ugt i32 %b, %a 182 call void @bar() 183 ret i1 %cmp2 184} 185 186define void @test_icmp_complex(i1 %c, i32 %a, i32 %b) { 187; CHECK-LABEL: @test_icmp_complex( 188; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], [[B:%.*]] 189; CHECK-NEXT: br i1 [[CMP1]], label [[IF2:%.*]], label [[ELSE2:%.*]] 190; CHECK: common.ret: 191; CHECK-NEXT: ret void 192; CHECK: if2: 193; CHECK-NEXT: call void @foo() 194; CHECK-NEXT: br label [[COMMON_RET:%.*]] 195; CHECK: else2: 196; CHECK-NEXT: call void @bar() 197; CHECK-NEXT: br label [[COMMON_RET]] 198; 199 br i1 %c, label %if, label %else 200 201if: 202 %cmp1 = icmp ult i32 %a, %b 203 br i1 %cmp1, label %if2, label %else2 204 205else: 206 %cmp2 = icmp ugt i32 %b, %a 207 br i1 %cmp2, label %if2, label %else2 208 209if2: 210 call void @foo() 211 ret void 212 213else2: 214 call void @bar() 215 ret void 216} 217 218define i1 @test_icmp_wrong_operands(i1 %c, i32 %a, i32 %b) { 219; CHECK-LABEL: @test_icmp_wrong_operands( 220; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 221; CHECK: common.ret: 222; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i1 [ [[CMP1:%.*]], [[IF]] ], [ [[CMP2:%.*]], [[ELSE]] ] 223; CHECK-NEXT: ret i1 [[COMMON_RET_OP]] 224; CHECK: if: 225; CHECK-NEXT: [[CMP1]] = icmp ult i32 [[A:%.*]], [[B:%.*]] 226; CHECK-NEXT: call void @foo() 227; CHECK-NEXT: br label [[COMMON_RET:%.*]] 228; CHECK: else: 229; CHECK-NEXT: [[CMP2]] = icmp ugt i32 [[A]], [[B]] 230; CHECK-NEXT: call void @bar() 231; CHECK-NEXT: br label [[COMMON_RET]] 232; 233 br i1 %c, label %if, label %else 234 235if: 236 %cmp1 = icmp ult i32 %a, %b 237 call void @foo() 238 ret i1 %cmp1 239 240else: 241 %cmp2 = icmp ugt i32 %a, %b 242 call void @bar() 243 ret i1 %cmp2 244} 245 246define i1 @test_icmp_wrong_pred(i1 %c, i32 %a, i32 %b) { 247; CHECK-LABEL: @test_icmp_wrong_pred( 248; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 249; CHECK: common.ret: 250; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i1 [ [[CMP1:%.*]], [[IF]] ], [ [[CMP2:%.*]], [[ELSE]] ] 251; CHECK-NEXT: ret i1 [[COMMON_RET_OP]] 252; CHECK: if: 253; CHECK-NEXT: [[CMP1]] = icmp ult i32 [[A:%.*]], [[B:%.*]] 254; CHECK-NEXT: call void @foo() 255; CHECK-NEXT: br label [[COMMON_RET:%.*]] 256; CHECK: else: 257; CHECK-NEXT: [[CMP2]] = icmp uge i32 [[B]], [[A]] 258; CHECK-NEXT: call void @bar() 259; CHECK-NEXT: br label [[COMMON_RET]] 260; 261 br i1 %c, label %if, label %else 262 263if: 264 %cmp1 = icmp ult i32 %a, %b 265 call void @foo() 266 ret i1 %cmp1 267 268else: 269 %cmp2 = icmp uge i32 %b, %a 270 call void @bar() 271 ret i1 %cmp2 272} 273 274define i32 @test_binop(i1 %c, i32 %a, i32 %b) { 275; CHECK-LABEL: @test_binop( 276; CHECK-NEXT: [[OP1:%.*]] = add i32 [[A:%.*]], [[B:%.*]] 277; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 278; CHECK: common.ret: 279; CHECK-NEXT: ret i32 [[OP1]] 280; CHECK: if: 281; CHECK-NEXT: call void @foo() 282; CHECK-NEXT: br label [[COMMON_RET:%.*]] 283; CHECK: else: 284; CHECK-NEXT: call void @bar() 285; CHECK-NEXT: br label [[COMMON_RET]] 286; 287 br i1 %c, label %if, label %else 288 289if: 290 %op1 = add i32 %a, %b 291 call void @foo() 292 ret i32 %op1 293 294else: 295 %op2 = add i32 %b, %a 296 call void @bar() 297 ret i32 %op2 298} 299 300define i32 @test_binop_flags(i1 %c, i32 %a, i32 %b) { 301; CHECK-LABEL: @test_binop_flags( 302; CHECK-NEXT: [[OP1:%.*]] = add nsw i32 [[A:%.*]], [[B:%.*]] 303; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 304; CHECK: common.ret: 305; CHECK-NEXT: ret i32 [[OP1]] 306; CHECK: if: 307; CHECK-NEXT: call void @foo() 308; CHECK-NEXT: br label [[COMMON_RET:%.*]] 309; CHECK: else: 310; CHECK-NEXT: call void @bar() 311; CHECK-NEXT: br label [[COMMON_RET]] 312; 313 br i1 %c, label %if, label %else 314 315if: 316 %op1 = add nuw nsw i32 %a, %b 317 call void @foo() 318 ret i32 %op1 319 320else: 321 %op2 = add nsw i32 %b, %a 322 call void @bar() 323 ret i32 %op2 324} 325 326define i32 @test_binop_not_commutative(i1 %c, i32 %a, i32 %b) { 327; CHECK-LABEL: @test_binop_not_commutative( 328; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 329; CHECK: common.ret: 330; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ] 331; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] 332; CHECK: if: 333; CHECK-NEXT: [[OP1]] = sub i32 [[A:%.*]], [[B:%.*]] 334; CHECK-NEXT: call void @foo() 335; CHECK-NEXT: br label [[COMMON_RET:%.*]] 336; CHECK: else: 337; CHECK-NEXT: [[OP2]] = sub i32 [[B]], [[A]] 338; CHECK-NEXT: call void @bar() 339; CHECK-NEXT: br label [[COMMON_RET]] 340; 341 br i1 %c, label %if, label %else 342 343if: 344 %op1 = sub i32 %a, %b 345 call void @foo() 346 ret i32 %op1 347 348else: 349 %op2 = sub i32 %b, %a 350 call void @bar() 351 ret i32 %op2 352} 353 354define i32 @test_binop_wrong_ops(i1 %c, i32 %a, i32 %b, i32 %d) { 355; CHECK-LABEL: @test_binop_wrong_ops( 356; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 357; CHECK: common.ret: 358; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ] 359; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] 360; CHECK: if: 361; CHECK-NEXT: [[OP1]] = add i32 [[A:%.*]], [[B:%.*]] 362; CHECK-NEXT: call void @foo() 363; CHECK-NEXT: br label [[COMMON_RET:%.*]] 364; CHECK: else: 365; CHECK-NEXT: [[OP2]] = add i32 [[B]], [[D:%.*]] 366; CHECK-NEXT: call void @bar() 367; CHECK-NEXT: br label [[COMMON_RET]] 368; 369 br i1 %c, label %if, label %else 370 371if: 372 %op1 = add i32 %a, %b 373 call void @foo() 374 ret i32 %op1 375 376else: 377 %op2 = add i32 %b, %d 378 call void @bar() 379 ret i32 %op2 380} 381 382define i32 @test_intrin(i1 %c, i32 %a, i32 %b) { 383; CHECK-LABEL: @test_intrin( 384; CHECK-NEXT: [[OP1:%.*]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 [[B:%.*]]) 385; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 386; CHECK: common.ret: 387; CHECK-NEXT: ret i32 [[OP1]] 388; CHECK: if: 389; CHECK-NEXT: call void @foo() 390; CHECK-NEXT: br label [[COMMON_RET:%.*]] 391; CHECK: else: 392; CHECK-NEXT: call void @bar() 393; CHECK-NEXT: br label [[COMMON_RET]] 394; 395 br i1 %c, label %if, label %else 396 397if: 398 %op1 = call i32 @llvm.umin(i32 %a, i32 %b) 399 call void @foo() 400 ret i32 %op1 401 402else: 403 %op2 = call i32 @llvm.umin(i32 %b, i32 %a) 404 call void @bar() 405 ret i32 %op2 406} 407 408define i32 @test_intrin_not_same(i1 %c, i32 %a, i32 %b) { 409; CHECK-LABEL: @test_intrin_not_same( 410; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 411; CHECK: common.ret: 412; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ] 413; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] 414; CHECK: if: 415; CHECK-NEXT: [[OP1]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 [[B:%.*]]) 416; CHECK-NEXT: call void @foo() 417; CHECK-NEXT: br label [[COMMON_RET:%.*]] 418; CHECK: else: 419; CHECK-NEXT: [[OP2]] = call i32 @llvm.umax.i32(i32 [[B]], i32 [[A]]) 420; CHECK-NEXT: call void @bar() 421; CHECK-NEXT: br label [[COMMON_RET]] 422; 423 br i1 %c, label %if, label %else 424 425if: 426 %op1 = call i32 @llvm.umin(i32 %a, i32 %b) 427 call void @foo() 428 ret i32 %op1 429 430else: 431 %op2 = call i32 @llvm.umax(i32 %b, i32 %a) 432 call void @bar() 433 ret i32 %op2 434} 435 436define float @test_intrin_3arg(i1 %c, float %a, float %b, float %d) { 437; CHECK-LABEL: @test_intrin_3arg( 438; CHECK-NEXT: [[OP1:%.*]] = call float @llvm.fma.f32(float [[A:%.*]], float [[B:%.*]], float [[D:%.*]]) 439; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 440; CHECK: common.ret: 441; CHECK-NEXT: ret float [[OP1]] 442; CHECK: if: 443; CHECK-NEXT: call void @foo() 444; CHECK-NEXT: br label [[COMMON_RET:%.*]] 445; CHECK: else: 446; CHECK-NEXT: call void @bar() 447; CHECK-NEXT: br label [[COMMON_RET]] 448; 449 br i1 %c, label %if, label %else 450 451if: 452 %op1 = call float @llvm.fma(float %a, float %b, float %d) 453 call void @foo() 454 ret float %op1 455 456else: 457 %op2 = call float @llvm.fma(float %b, float %a, float %d) 458 call void @bar() 459 ret float %op2 460} 461 462define float @test_intrin_3arg_wrong_args_commuted(i1 %c, float %a, float %b, float %d) { 463; CHECK-LABEL: @test_intrin_3arg_wrong_args_commuted( 464; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 465; CHECK: common.ret: 466; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi float [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ] 467; CHECK-NEXT: ret float [[COMMON_RET_OP]] 468; CHECK: if: 469; CHECK-NEXT: [[OP1]] = call float @llvm.fma.f32(float [[A:%.*]], float [[B:%.*]], float [[D:%.*]]) 470; CHECK-NEXT: call void @foo() 471; CHECK-NEXT: br label [[COMMON_RET:%.*]] 472; CHECK: else: 473; CHECK-NEXT: [[OP2]] = call float @llvm.fma.f32(float [[A]], float [[D]], float [[B]]) 474; CHECK-NEXT: call void @bar() 475; CHECK-NEXT: br label [[COMMON_RET]] 476; 477 br i1 %c, label %if, label %else 478 479if: 480 %op1 = call float @llvm.fma(float %a, float %b, float %d) 481 call void @foo() 482 ret float %op1 483 484else: 485 %op2 = call float @llvm.fma(float %a, float %d, float %b) 486 call void @bar() 487 ret float %op2 488} 489