520 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=aggressive-instcombine -S | FileCheck %s3 4define i32 @fshl(i32 %a, i32 %b, i32 %c) {5; CHECK-LABEL: @fshl(6; CHECK-NEXT: entry:7; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 08; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]9; CHECK: fshbb:10; CHECK-NEXT: br label [[END]]11; CHECK: end:12; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[B:%.*]]13; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[TMP0]], i32 [[C]])14; CHECK-NEXT: ret i32 [[TMP1]]15;16entry:17 %cmp = icmp eq i32 %c, 018 br i1 %cmp, label %end, label %fshbb19 20fshbb:21 %sub = sub i32 32, %c22 %shr = lshr i32 %b, %sub23 %shl = shl i32 %a, %c24 %or = or i32 %shr, %shl25 br label %end26 27end:28 %cond = phi i32 [ %or, %fshbb ], [ %a, %entry ]29 ret i32 %cond30}31 32define i32 @fshl_commute_phi(i32 %a, i32 %b, i32 %c) {33; CHECK-LABEL: @fshl_commute_phi(34; CHECK-NEXT: entry:35; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 036; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]37; CHECK: fshbb:38; CHECK-NEXT: br label [[END]]39; CHECK: end:40; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[B:%.*]]41; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[TMP0]], i32 [[C]])42; CHECK-NEXT: ret i32 [[TMP1]]43;44entry:45 %cmp = icmp eq i32 %c, 046 br i1 %cmp, label %end, label %fshbb47 48fshbb:49 %sub = sub i32 32, %c50 %shr = lshr i32 %b, %sub51 %shl = shl i32 %a, %c52 %or = or i32 %shr, %shl53 br label %end54 55end:56 %cond = phi i32 [ %a, %entry ], [ %or, %fshbb ]57 ret i32 %cond58}59 60define i32 @fshl_commute_or(i32 %a, i32 %b, i32 %c) {61; CHECK-LABEL: @fshl_commute_or(62; CHECK-NEXT: entry:63; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 064; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]65; CHECK: fshbb:66; CHECK-NEXT: br label [[END]]67; CHECK: end:68; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[B:%.*]]69; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[TMP0]], i32 [[C]])70; CHECK-NEXT: ret i32 [[TMP1]]71;72entry:73 %cmp = icmp eq i32 %c, 074 br i1 %cmp, label %end, label %fshbb75 76fshbb:77 %sub = sub i32 32, %c78 %shr = lshr i32 %b, %sub79 %shl = shl i32 %a, %c80 %or = or i32 %shl, %shr81 br label %end82 83end:84 %cond = phi i32 [ %a, %entry ], [ %or, %fshbb ]85 ret i32 %cond86}87 88; Verify that the intrinsic is inserted into a valid position.89 90define i32 @fshl_insert_valid_location(i32 %a, i32 %b, i32 %c) {91; CHECK-LABEL: @fshl_insert_valid_location(92; CHECK-NEXT: entry:93; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 094; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]95; CHECK: fshbb:96; CHECK-NEXT: br label [[END]]97; CHECK: end:98; CHECK-NEXT: [[OTHER:%.*]] = phi i32 [ 1, [[FSHBB]] ], [ 2, [[ENTRY:%.*]] ]99; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[B:%.*]]100; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[TMP0]], i32 [[C]])101; CHECK-NEXT: [[RES:%.*]] = or i32 [[TMP1]], [[OTHER]]102; CHECK-NEXT: ret i32 [[RES]]103;104entry:105 %cmp = icmp eq i32 %c, 0106 br i1 %cmp, label %end, label %fshbb107 108fshbb:109 %sub = sub i32 32, %c110 %shr = lshr i32 %b, %sub111 %shl = shl i32 %a, %c112 %or = or i32 %shr, %shl113 br label %end114 115end:116 %cond = phi i32 [ %or, %fshbb ], [ %a, %entry ]117 %other = phi i32 [ 1, %fshbb ], [ 2, %entry ]118 %res = or i32 %cond, %other119 ret i32 %res120}121 122define i32 @fshr(i32 %a, i32 %b, i32 %c) {123; CHECK-LABEL: @fshr(124; CHECK-NEXT: entry:125; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0126; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]127; CHECK: fshbb:128; CHECK-NEXT: br label [[END]]129; CHECK: end:130; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[A:%.*]]131; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshr.i32(i32 [[TMP0]], i32 [[B:%.*]], i32 [[C]])132; CHECK-NEXT: ret i32 [[TMP1]]133;134entry:135 %cmp = icmp eq i32 %c, 0136 br i1 %cmp, label %end, label %fshbb137 138fshbb:139 %sub = sub i32 32, %c140 %shl = shl i32 %a, %sub141 %shr = lshr i32 %b, %c142 %or = or i32 %shr, %shl143 br label %end144 145end:146 %cond = phi i32 [ %or, %fshbb ], [ %b, %entry ]147 ret i32 %cond148}149 150define i32 @fshr_commute_phi(i32 %a, i32 %b, i32 %c) {151; CHECK-LABEL: @fshr_commute_phi(152; CHECK-NEXT: entry:153; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0154; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]155; CHECK: fshbb:156; CHECK-NEXT: br label [[END]]157; CHECK: end:158; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[A:%.*]]159; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshr.i32(i32 [[TMP0]], i32 [[B:%.*]], i32 [[C]])160; CHECK-NEXT: ret i32 [[TMP1]]161;162entry:163 %cmp = icmp eq i32 %c, 0164 br i1 %cmp, label %end, label %fshbb165 166fshbb:167 %sub = sub i32 32, %c168 %shl = shl i32 %a, %sub169 %shr = lshr i32 %b, %c170 %or = or i32 %shr, %shl171 br label %end172 173end:174 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]175 ret i32 %cond176}177 178define i32 @fshr_commute_or(i32 %a, i32 %b, i32 %c) {179; CHECK-LABEL: @fshr_commute_or(180; CHECK-NEXT: entry:181; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0182; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]183; CHECK: fshbb:184; CHECK-NEXT: br label [[END]]185; CHECK: end:186; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[A:%.*]]187; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshr.i32(i32 [[TMP0]], i32 [[B:%.*]], i32 [[C]])188; CHECK-NEXT: ret i32 [[TMP1]]189;190entry:191 %cmp = icmp eq i32 %c, 0192 br i1 %cmp, label %end, label %fshbb193 194fshbb:195 %sub = sub i32 32, %c196 %shl = shl i32 %a, %sub197 %shr = lshr i32 %b, %c198 %or = or i32 %shl, %shr199 br label %end200 201end:202 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]203 ret i32 %cond204}205 206; Negative test - non-power-of-2 might require urem expansion in the backend.207 208define i12 @could_be_fshr_weird_type(i12 %a, i12 %b, i12 %c) {209; CHECK-LABEL: @could_be_fshr_weird_type(210; CHECK-NEXT: entry:211; CHECK-NEXT: [[CMP:%.*]] = icmp eq i12 [[C:%.*]], 0212; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]213; CHECK: fshbb:214; CHECK-NEXT: [[SUB:%.*]] = sub i12 12, [[C]]215; CHECK-NEXT: [[SHL:%.*]] = shl i12 [[A:%.*]], [[SUB]]216; CHECK-NEXT: [[SHR:%.*]] = lshr i12 [[B:%.*]], [[C]]217; CHECK-NEXT: [[OR:%.*]] = or i12 [[SHL]], [[SHR]]218; CHECK-NEXT: br label [[END]]219; CHECK: end:220; CHECK-NEXT: [[COND:%.*]] = phi i12 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]221; CHECK-NEXT: ret i12 [[COND]]222;223entry:224 %cmp = icmp eq i12 %c, 0225 br i1 %cmp, label %end, label %fshbb226 227fshbb:228 %sub = sub i12 12, %c229 %shl = shl i12 %a, %sub230 %shr = lshr i12 %b, %c231 %or = or i12 %shl, %shr232 br label %end233 234end:235 %cond = phi i12 [ %b, %entry ], [ %or, %fshbb ]236 ret i12 %cond237}238 239; Negative test - wrong phi ops.240 241define i32 @not_fshr_1(i32 %a, i32 %b, i32 %c) {242; CHECK-LABEL: @not_fshr_1(243; CHECK-NEXT: entry:244; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0245; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]246; CHECK: fshbb:247; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[C]]248; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]249; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[B:%.*]], [[C]]250; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]251; CHECK-NEXT: br label [[END]]252; CHECK: end:253; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[C]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]254; CHECK-NEXT: ret i32 [[COND]]255;256entry:257 %cmp = icmp eq i32 %c, 0258 br i1 %cmp, label %end, label %fshbb259 260fshbb:261 %sub = sub i32 32, %c262 %shl = shl i32 %a, %sub263 %shr = lshr i32 %b, %c264 %or = or i32 %shl, %shr265 br label %end266 267end:268 %cond = phi i32 [ %c, %entry ], [ %or, %fshbb ]269 ret i32 %cond270}271 272; Negative test - too many phi ops.273 274define i32 @not_fshr_2(i32 %a, i32 %b, i32 %c, i32 %d) {275; CHECK-LABEL: @not_fshr_2(276; CHECK-NEXT: entry:277; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0278; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]279; CHECK: fshbb:280; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[C]]281; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]282; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[B:%.*]], [[C]]283; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]284; CHECK-NEXT: [[CMP42:%.*]] = icmp ugt i32 [[OR]], 42285; CHECK-NEXT: br i1 [[CMP42]], label [[END]], label [[BOGUS:%.*]]286; CHECK: bogus:287; CHECK-NEXT: br label [[END]]288; CHECK: end:289; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ], [ [[D:%.*]], [[BOGUS]] ]290; CHECK-NEXT: ret i32 [[COND]]291;292entry:293 %cmp = icmp eq i32 %c, 0294 br i1 %cmp, label %end, label %fshbb295 296fshbb:297 %sub = sub i32 32, %c298 %shl = shl i32 %a, %sub299 %shr = lshr i32 %b, %c300 %or = or i32 %shl, %shr301 %cmp42 = icmp ugt i32 %or, 42302 br i1 %cmp42, label %end, label %bogus303 304bogus:305 br label %end306 307end:308 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ], [ %d, %bogus ]309 ret i32 %cond310}311 312; Negative test - wrong cmp (but this should match?).313 314define i32 @not_fshr_3(i32 %a, i32 %b, i32 %c) {315; CHECK-LABEL: @not_fshr_3(316; CHECK-NEXT: entry:317; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[C:%.*]], 0318; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]319; CHECK: fshbb:320; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[C]]321; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]322; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[B:%.*]], [[C]]323; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]324; CHECK-NEXT: br label [[END]]325; CHECK: end:326; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]327; CHECK-NEXT: ret i32 [[COND]]328;329entry:330 %cmp = icmp sle i32 %c, 0331 br i1 %cmp, label %end, label %fshbb332 333fshbb:334 %sub = sub i32 32, %c335 %shl = shl i32 %a, %sub336 %shr = lshr i32 %b, %c337 %or = or i32 %shl, %shr338 br label %end339 340end:341 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]342 ret i32 %cond343}344 345; Negative test - wrong shift.346 347define i32 @not_fshr_4(i32 %a, i32 %b, i32 %c) {348; CHECK-LABEL: @not_fshr_4(349; CHECK-NEXT: entry:350; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0351; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]352; CHECK: fshbb:353; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[C]]354; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]355; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[B:%.*]], [[C]]356; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]357; CHECK-NEXT: br label [[END]]358; CHECK: end:359; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]360; CHECK-NEXT: ret i32 [[COND]]361;362entry:363 %cmp = icmp eq i32 %c, 0364 br i1 %cmp, label %end, label %fshbb365 366fshbb:367 %sub = sub i32 32, %c368 %shl = shl i32 %a, %sub369 %shr = ashr i32 %b, %c370 %or = or i32 %shl, %shr371 br label %end372 373end:374 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]375 ret i32 %cond376}377 378; Negative test - wrong shift for rotate (but can be folded to a generic funnel shift).379 380define i32 @not_fshr_5(i32 %a, i32 %b, i32 %c) {381; CHECK-LABEL: @not_fshr_5(382; CHECK-NEXT: entry:383; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0384; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]385; CHECK: fshbb:386; CHECK-NEXT: br label [[END]]387; CHECK: end:388; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.fshr.i32(i32 [[C]], i32 [[B:%.*]], i32 [[C]])389; CHECK-NEXT: ret i32 [[TMP0]]390;391entry:392 %cmp = icmp eq i32 %c, 0393 br i1 %cmp, label %end, label %fshbb394 395fshbb:396 %sub = sub i32 32, %c397 %shl = shl i32 %c, %sub398 %shr = lshr i32 %b, %c399 %or = or i32 %shl, %shr400 br label %end401 402end:403 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]404 ret i32 %cond405}406 407; Negative test - wrong sub.408 409define i32 @not_fshr_6(i32 %a, i32 %b, i32 %c) {410; CHECK-LABEL: @not_fshr_6(411; CHECK-NEXT: entry:412; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0413; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]414; CHECK: fshbb:415; CHECK-NEXT: [[SUB:%.*]] = sub i32 8, [[C]]416; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]417; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[B:%.*]], [[C]]418; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]419; CHECK-NEXT: br label [[END]]420; CHECK: end:421; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]422; CHECK-NEXT: ret i32 [[COND]]423;424entry:425 %cmp = icmp eq i32 %c, 0426 br i1 %cmp, label %end, label %fshbb427 428fshbb:429 %sub = sub i32 8, %c430 %shl = shl i32 %a, %sub431 %shr = lshr i32 %b, %c432 %or = or i32 %shl, %shr433 br label %end434 435end:436 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]437 ret i32 %cond438}439 440; Negative test - extra use. Technically, we could transform this441; because it doesn't increase the instruction count, but we're442; being cautious not to cause a potential perf pessimization for443; targets that do not have a fshate instruction.444 445define i32 @could_be_fshr(i32 %a, i32 %b, i32 %c, ptr %p) {446; CHECK-LABEL: @could_be_fshr(447; CHECK-NEXT: entry:448; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0449; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]450; CHECK: fshbb:451; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[C]]452; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]453; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[B:%.*]], [[C]]454; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]455; CHECK-NEXT: store i32 [[OR]], ptr [[P:%.*]], align 4456; CHECK-NEXT: br label [[END]]457; CHECK: end:458; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]459; CHECK-NEXT: ret i32 [[COND]]460;461entry:462 %cmp = icmp eq i32 %c, 0463 br i1 %cmp, label %end, label %fshbb464 465fshbb:466 %sub = sub i32 32, %c467 %shl = shl i32 %a, %sub468 %shr = lshr i32 %b, %c469 %or = or i32 %shl, %shr470 store i32 %or, ptr %p471 br label %end472 473end:474 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]475 ret i32 %cond476}477 478; PR48068 - Ensure we don't fold a funnel shift that depends on a shift value that479; can't be hoisted out of a basic block.480@a = global i32 0, align 4481declare i32 @i(...)482declare i32 @f(...)483 484define i32 @PR48068() {485; CHECK-LABEL: @PR48068(486; CHECK-NEXT: entry:487; CHECK-NEXT: [[CALL:%.*]] = call i32 @i()488; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @a, align 4489; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[TMP0]], 0490; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]491; CHECK: if.then:492; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CALL]], [[TMP0]]493; CHECK-NEXT: [[CALL_I:%.*]] = call i32 @f()494; CHECK-NEXT: [[SUB_I:%.*]] = sub nsw i32 32, [[TMP0]]495; CHECK-NEXT: [[SHR_I:%.*]] = lshr i32 [[CALL_I]], [[SUB_I]]496; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR_I]]497; CHECK-NEXT: br label [[IF_END]]498; CHECK: if.end:499; CHECK-NEXT: [[H_0:%.*]] = phi i32 [ [[OR]], [[IF_THEN]] ], [ [[CALL]], [[ENTRY:%.*]] ]500; CHECK-NEXT: ret i32 [[H_0]]501;502entry:503 %call = call i32 @i()504 %0 = load i32, ptr @a, align 4505 %tobool.not = icmp eq i32 %0, 0506 br i1 %tobool.not, label %if.end, label %if.then507 508if.then: ; preds = %entry509 %shl = shl i32 %call, %0510 %call.i = call i32 @f()511 %sub.i = sub nsw i32 32, %0512 %shr.i = lshr i32 %call.i, %sub.i513 %or = or i32 %shl, %shr.i514 br label %if.end515 516if.end: ; preds = %if.then, %entry517 %h.0 = phi i32 [ %or, %if.then ], [ %call, %entry ]518 ret i32 %h.0519}520