Skip to content

Commit 5094e12

Browse files
committed
[InstCombine] fold min/max intrinsic with negated operand to abs
The smax case shows up in https://llvm.org/PR49885 . The others seem unlikely, but we might as well try for uniformity (although that could mean an extra instruction to create "nabs"). smax -- https://alive2.llvm.org/ce/z/8yYaGy smin -- https://alive2.llvm.org/ce/z/0_7zc_ umax -- https://alive2.llvm.org/ce/z/EcsZWs umin -- https://alive2.llvm.org/ce/z/Xw6WvB
1 parent c52dbdb commit 5094e12

File tree

2 files changed

+32
-21
lines changed

2 files changed

+32
-21
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,22 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
911911
}
912912
}
913913

914+
// smax(X, -X) --> abs(X)
915+
// smin(X, -X) --> -abs(X)
916+
// umax(X, -X) --> -abs(X)
917+
// umin(X, -X) --> abs(X)
918+
if (isKnownNegation(I0, I1)) {
919+
// This is some variant of abs(). See if we can propagate 'nsw' to the abs
920+
// operation and potentially its negation.
921+
bool IntMinIsPoison = isKnownNegation(I0, I1, /* NeedNSW */ true);
922+
Value *Abs = Builder.CreateBinaryIntrinsic(
923+
Intrinsic::abs, I0,
924+
ConstantInt::getBool(II->getContext(), IntMinIsPoison));
925+
if (IID == Intrinsic::smin || IID == Intrinsic::umax)
926+
Abs = Builder.CreateNeg(Abs, "nabs", /* NUW */ false, IntMinIsPoison);
927+
return replaceInstUsesWith(CI, Abs);
928+
}
929+
914930
break;
915931
}
916932
case Intrinsic::bswap: {

llvm/test/Transforms/InstCombine/minmax-intrinsics.ll

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -611,9 +611,8 @@ define i8 @not_umin_of_not_constant_op(i8 %x) {
611611
define i8 @smax_negation(i8 %x, i8 %y) {
612612
; CHECK-LABEL: @smax_negation(
613613
; CHECK-NEXT: [[S1:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
614-
; CHECK-NEXT: [[S2:%.*]] = sub i8 [[Y]], [[X]]
615-
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[S1]], i8 [[S2]])
616-
; CHECK-NEXT: ret i8 [[R]]
614+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S1]], i1 false)
615+
; CHECK-NEXT: ret i8 [[TMP1]]
617616
;
618617
%s1 = sub i8 %x, %y
619618
%s2 = sub i8 %y, %x
@@ -624,9 +623,8 @@ define i8 @smax_negation(i8 %x, i8 %y) {
624623
define i8 @smax_negation_nsw(i8 %x, i8 %y) {
625624
; CHECK-LABEL: @smax_negation_nsw(
626625
; CHECK-NEXT: [[S1:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]]
627-
; CHECK-NEXT: [[S2:%.*]] = sub nsw i8 [[Y]], [[X]]
628-
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[S1]], i8 [[S2]])
629-
; CHECK-NEXT: ret i8 [[R]]
626+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S1]], i1 true)
627+
; CHECK-NEXT: ret i8 [[TMP1]]
630628
;
631629
%s1 = sub nsw i8 %x, %y
632630
%s2 = sub nsw i8 %y, %x
@@ -637,9 +635,8 @@ define i8 @smax_negation_nsw(i8 %x, i8 %y) {
637635
define i8 @smax_negation_not_nsw(i8 %x, i8 %y) {
638636
; CHECK-LABEL: @smax_negation_not_nsw(
639637
; CHECK-NEXT: [[S1:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]]
640-
; CHECK-NEXT: [[S2:%.*]] = sub nuw i8 [[Y]], [[X]]
641-
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[S1]], i8 [[S2]])
642-
; CHECK-NEXT: ret i8 [[R]]
638+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S1]], i1 false)
639+
; CHECK-NEXT: ret i8 [[TMP1]]
643640
;
644641
%s1 = sub nsw i8 %x, %y
645642
%s2 = sub nuw i8 %y, %x
@@ -649,9 +646,8 @@ define i8 @smax_negation_not_nsw(i8 %x, i8 %y) {
649646

650647
define <3 x i8> @smax_negation_vec(<3 x i8> %x) {
651648
; CHECK-LABEL: @smax_negation_vec(
652-
; CHECK-NEXT: [[S:%.*]] = sub <3 x i8> <i8 0, i8 undef, i8 0>, [[X:%.*]]
653-
; CHECK-NEXT: [[R:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X]], <3 x i8> [[S]])
654-
; CHECK-NEXT: ret <3 x i8> [[R]]
649+
; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.abs.v3i8(<3 x i8> [[X:%.*]], i1 false)
650+
; CHECK-NEXT: ret <3 x i8> [[TMP1]]
655651
;
656652
%s = sub <3 x i8> <i8 0, i8 undef, i8 0>, %x
657653
%r = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %x, <3 x i8> %s)
@@ -661,9 +657,9 @@ define <3 x i8> @smax_negation_vec(<3 x i8> %x) {
661657
define i8 @smin_negation(i8 %x, i8 %y) {
662658
; CHECK-LABEL: @smin_negation(
663659
; CHECK-NEXT: [[S1:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
664-
; CHECK-NEXT: [[S2:%.*]] = sub i8 [[Y]], [[X]]
665-
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[S1]], i8 [[S2]])
666-
; CHECK-NEXT: ret i8 [[R]]
660+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S1]], i1 false)
661+
; CHECK-NEXT: [[NABS:%.*]] = sub i8 0, [[TMP1]]
662+
; CHECK-NEXT: ret i8 [[NABS]]
667663
;
668664
%s1 = sub i8 %x, %y
669665
%s2 = sub i8 %y, %x
@@ -674,9 +670,9 @@ define i8 @smin_negation(i8 %x, i8 %y) {
674670
define i8 @umax_negation(i8 %x, i8 %y) {
675671
; CHECK-LABEL: @umax_negation(
676672
; CHECK-NEXT: [[S1:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]]
677-
; CHECK-NEXT: [[S2:%.*]] = sub nsw i8 [[Y]], [[X]]
678-
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.umax.i8(i8 [[S1]], i8 [[S2]])
679-
; CHECK-NEXT: ret i8 [[R]]
673+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[S1]], i1 true)
674+
; CHECK-NEXT: [[NABS:%.*]] = sub nsw i8 0, [[TMP1]]
675+
; CHECK-NEXT: ret i8 [[NABS]]
680676
;
681677
%s1 = sub nsw i8 %x, %y
682678
%s2 = sub nsw i8 %y, %x
@@ -686,9 +682,8 @@ define i8 @umax_negation(i8 %x, i8 %y) {
686682

687683
define i8 @umin_negation(i8 %x) {
688684
; CHECK-LABEL: @umin_negation(
689-
; CHECK-NEXT: [[S:%.*]] = sub nsw i8 0, [[X:%.*]]
690-
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.umin.i8(i8 [[S]], i8 [[X]])
691-
; CHECK-NEXT: ret i8 [[R]]
685+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.abs.i8(i8 [[X:%.*]], i1 true)
686+
; CHECK-NEXT: ret i8 [[TMP1]]
692687
;
693688
%s = sub nsw i8 0, %x
694689
%r = call i8 @llvm.umin.i8(i8 %s, i8 %x)

0 commit comments

Comments
 (0)