llvm.org GIT mirror llvm / fc0780a
[InstSimplify] delete shift-of-zero guard ops around funnel shifts This is a problem seen in common rotate idioms as noted in: https://bugs.llvm.org/show_bug.cgi?id=34924 Note that we are not canonicalizing standard IR (shifts and logic) to the intrinsics yet. (Although I've written this before...) I think this is the last step before we enable that transform. Ie, we could regress code by doing that transform without this simplification in place. In PR34924, I questioned whether this is a valid transform for target-independent IR, but I convinced myself this is ok. If we're speculating a funnel shift by turning cmp+br into select, then SimplifyCFG has already determined that the transform is justified. It's possible that SimplifyCFG is not taking into account profile or other metadata, but if that's true, then it's a bug independent of funnel shifts. Also, we do have CGP code to restore a guard like this around an intrinsic if it can't be lowered cheaply. But that isn't necessary for funnel shift because the default expansion in SelectionDAGBuilder includes this same cmp+select. Differential Revision: https://reviews.llvm.org/D54552 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@346960 91177308-0d34-0410-b5e6-96231b3b80d8 Sanjay Patel 10 months ago
2 changed file(s) with 56 addition(s) and 36 deletion(s). Raw diff Collapse all Expand all
38363836 if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, X, Y,
38373837 Pred == ICmpInst::ICMP_EQ))
38383838 return V;
3839
3840 // Test for zero-shift-guard-ops around funnel shifts. These are used to
3841 // avoid UB from oversized shifts in raw IR rotate patterns, but the
3842 // intrinsics do not have that problem.
3843 Value *ShAmt;
3844 auto isFsh = m_CombineOr(m_Intrinsic(m_Value(X), m_Value(),
3845 m_Value(ShAmt)),
3846 m_Intrinsic(m_Value(), m_Value(X),
3847 m_Value(ShAmt)));
3848 // (ShAmt != 0) ? fshl(X, *, ShAmt) : X --> fshl(X, *, ShAmt)
3849 // (ShAmt != 0) ? fshr(*, X, ShAmt) : X --> fshr(*, X, ShAmt)
3850 // (ShAmt == 0) ? fshl(X, *, ShAmt) : X --> X
3851 // (ShAmt == 0) ? fshr(*, X, ShAmt) : X --> X
3852 if (match(TrueVal, isFsh) && FalseVal == X && CmpLHS == ShAmt)
3853 return Pred == ICmpInst::ICMP_NE ? TrueVal : X;
3854
3855 // (ShAmt == 0) ? X : fshl(X, *, ShAmt) --> fshl(X, *, ShAmt)
3856 // (ShAmt == 0) ? X : fshr(*, X, ShAmt) --> fshr(*, X, ShAmt)
3857 // (ShAmt != 0) ? X : fshl(X, *, ShAmt) --> X
3858 // (ShAmt != 0) ? X : fshr(*, X, ShAmt) --> X
3859 if (match(FalseVal, isFsh) && TrueVal == X && CmpLHS == ShAmt)
3860 return Pred == ICmpInst::ICMP_EQ ? FalseVal : X;
38393861 }
38403862
38413863 // Check for other compares that behave like bit test.
499499 ret <2 x i8> %z
500500 }
501501
502 ; When the shift amount is 0, fshl returns its 1st parameter (x), so the guard is not needed.
503
502504 define i8 @fshl_zero_shift_guard(i8 %x, i8 %y, i8 %sh) {
503505 ; CHECK-LABEL: @fshl_zero_shift_guard(
504 ; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[SH:%.*]], 0
505 ; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH]])
506 ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i8 [[X]], i8 [[F]]
507 ; CHECK-NEXT: ret i8 [[S]]
506 ; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH:%.*]])
507 ; CHECK-NEXT: ret i8 [[F]]
508508 ;
509509 %c = icmp eq i8 %sh, 0
510510 %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh)
512512 ret i8 %s
513513 }
514514
515 ; When the shift amount is 0, fshl returns its 1st parameter (x), so the guard is not needed.
516
515517 define i8 @fshl_zero_shift_guard_swapped(i8 %x, i8 %y, i8 %sh) {
516518 ; CHECK-LABEL: @fshl_zero_shift_guard_swapped(
517 ; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[SH:%.*]], 0
518 ; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH]])
519 ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i8 [[F]], i8 [[X]]
520 ; CHECK-NEXT: ret i8 [[S]]
519 ; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH:%.*]])
520 ; CHECK-NEXT: ret i8 [[F]]
521521 ;
522522 %c = icmp ne i8 %sh, 0
523523 %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh)
525525 ret i8 %s
526526 }
527527
528 ; When the shift amount is 0, fshl returns its 1st parameter (x), so everything is deleted.
529
528530 define i8 @fshl_zero_shift_guard_inverted(i8 %x, i8 %y, i8 %sh) {
529531 ; CHECK-LABEL: @fshl_zero_shift_guard_inverted(
530 ; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[SH:%.*]], 0
531 ; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH]])
532 ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i8 [[F]], i8 [[X]]
533 ; CHECK-NEXT: ret i8 [[S]]
532 ; CHECK-NEXT: ret i8 [[X:%.*]]
534533 ;
535534 %c = icmp eq i8 %sh, 0
536535 %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh)
538537 ret i8 %s
539538 }
540539
540 ; When the shift amount is 0, fshl returns its 1st parameter (x), so everything is deleted.
541
541542 define i8 @fshl_zero_shift_guard_inverted_swapped(i8 %x, i8 %y, i8 %sh) {
542543 ; CHECK-LABEL: @fshl_zero_shift_guard_inverted_swapped(
543 ; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[SH:%.*]], 0
544 ; CHECK-NEXT: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[SH]])
545 ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i8 [[X]], i8 [[F]]
546 ; CHECK-NEXT: ret i8 [[S]]
544 ; CHECK-NEXT: ret i8 [[X:%.*]]
547545 ;
548546 %c = icmp ne i8 %sh, 0
549547 %f = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 %sh)
551549 ret i8 %s
552550 }
553551
552 ; When the shift amount is 0, fshr returns its 2nd parameter (y), so the guard is not needed.
553
554554 define i9 @fshr_zero_shift_guard(i9 %x, i9 %y, i9 %sh) {
555555 ; CHECK-LABEL: @fshr_zero_shift_guard(
556 ; CHECK-NEXT: [[C:%.*]] = icmp eq i9 [[SH:%.*]], 0
557 ; CHECK-NEXT: [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[Y:%.*]], i9 [[SH]])
558 ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i9 [[Y]], i9 [[F]]
559 ; CHECK-NEXT: ret i9 [[S]]
556 ; CHECK-NEXT: [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[Y:%.*]], i9 [[SH:%.*]])
557 ; CHECK-NEXT: ret i9 [[F]]
560558 ;
561559 %c = icmp eq i9 %sh, 0
562560 %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh)
564562 ret i9 %s
565563 }
566564
565 ; When the shift amount is 0, fshr returns its 2nd parameter (y), so the guard is not needed.
566
567567 define i9 @fshr_zero_shift_guard_swapped(i9 %x, i9 %y, i9 %sh) {
568568 ; CHECK-LABEL: @fshr_zero_shift_guard_swapped(
569 ; CHECK-NEXT: [[C:%.*]] = icmp ne i9 [[SH:%.*]], 0
570 ; CHECK-NEXT: [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[Y:%.*]], i9 [[SH]])
571 ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i9 [[F]], i9 [[Y]]
572 ; CHECK-NEXT: ret i9 [[S]]
569 ; CHECK-NEXT: [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[Y:%.*]], i9 [[SH:%.*]])
570 ; CHECK-NEXT: ret i9 [[F]]
573571 ;
574572 %c = icmp ne i9 %sh, 0
575573 %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh)
577575 ret i9 %s
578576 }
579577
578 ; When the shift amount is 0, fshr returns its 2nd parameter (y), so everything is deleted.
579
580580 define i9 @fshr_zero_shift_guard_inverted(i9 %x, i9 %y, i9 %sh) {
581581 ; CHECK-LABEL: @fshr_zero_shift_guard_inverted(
582 ; CHECK-NEXT: [[C:%.*]] = icmp eq i9 [[SH:%.*]], 0
583 ; CHECK-NEXT: [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[Y:%.*]], i9 [[SH]])
584 ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i9 [[F]], i9 [[Y]]
585 ; CHECK-NEXT: ret i9 [[S]]
582 ; CHECK-NEXT: ret i9 [[Y:%.*]]
586583 ;
587584 %c = icmp eq i9 %sh, 0
588585 %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh)
590587 ret i9 %s
591588 }
592589
590 ; When the shift amount is 0, fshr returns its 2nd parameter (y), so everything is deleted.
591
593592 define i9 @fshr_zero_shift_guard_inverted_swapped(i9 %x, i9 %y, i9 %sh) {
594593 ; CHECK-LABEL: @fshr_zero_shift_guard_inverted_swapped(
595 ; CHECK-NEXT: [[C:%.*]] = icmp ne i9 [[SH:%.*]], 0
596 ; CHECK-NEXT: [[F:%.*]] = call i9 @llvm.fshr.i9(i9 [[X:%.*]], i9 [[Y:%.*]], i9 [[SH]])
597 ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i9 [[Y]], i9 [[F]]
598 ; CHECK-NEXT: ret i9 [[S]]
594 ; CHECK-NEXT: ret i9 [[Y:%.*]]
599595 ;
600596 %c = icmp ne i9 %sh, 0
601597 %f = call i9 @llvm.fshr.i9(i9 %x, i9 %y, i9 %sh)
602598 %s = select i1 %c, i9 %y, i9 %f
603599 ret i9 %s
604600 }
601
602 ; Negative test - make sure we're matching the correct parameter of fshl.
605603
606604 define i8 @fshl_zero_shift_guard_wrong_select_op(i8 %x, i8 %y, i8 %sh) {
607605 ; CHECK-LABEL: @fshl_zero_shift_guard_wrong_select_op(
616614 ret i8 %s
617615 }
618616
617 ; Vector types work too.
618
619619 define <2 x i8> @fshr_zero_shift_guard_splat(<2 x i8> %x, <2 x i8> %y, <2 x i8> %sh) {
620620 ; CHECK-LABEL: @fshr_zero_shift_guard_splat(
621 ; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[SH:%.*]], zeroinitializer
622 ; CHECK-NEXT: [[F:%.*]] = call <2 x i8> @llvm.fshr.v2i8(<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[SH]])
623 ; CHECK-NEXT: [[S:%.*]] = select <2 x i1> [[C]], <2 x i8> [[Y]], <2 x i8> [[F]]
624 ; CHECK-NEXT: ret <2 x i8> [[S]]
621 ; CHECK-NEXT: [[F:%.*]] = call <2 x i8> @llvm.fshr.v2i8(<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[SH:%.*]])
622 ; CHECK-NEXT: ret <2 x i8> [[F]]
625623 ;
626624 %c = icmp eq <2 x i8> %sh, zeroinitializer
627625 %f = call <2 x i8> @llvm.fshr.v2i8(<2 x i8> %x, <2 x i8> %y, <2 x i8> %sh)