Skip to content

Commit c1152ff

Browse files
committed
[InstCombine] Fold select pattern with sub and negation to abs intrinsic
This patch adds a new fold in InstCombine to recognize and optimize a common absolute value pattern. ```llvm %sub = sub nsw T %x, %y %cmp = icmp sgt T %x, %y ; or sge %neg = sub T 0, %sub %abs = select i1 %cmp, T %sub, T %neg ``` becomes:| ```llvm %sub = sub nsw T %x, %y %abs = call T @llvm.abs.T(T %sub, i1 false) ```
1 parent d29f36e commit c1152ff

File tree

2 files changed

+106
-6
lines changed

2 files changed

+106
-6
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,45 @@ static Value *foldAbsDiff(ICmpInst *Cmp, Value *TVal, Value *FVal,
11531153
return Builder.CreateBinaryIntrinsic(Intrinsic::abs, TI, Builder.getTrue());
11541154
}
11551155

1156+
// Match: (A > B) ? (A - B) : (0 - (A - B)) --> abs(A - B)
1157+
// Also handles commuted cases like (B < A), (A >= B), (B <= A) after
1158+
// normalization
1159+
if (Pred == CmpInst::ICMP_SGT &&
1160+
match(TI, m_NSWSub(m_Specific(A), m_Specific(B))) &&
1161+
match(FI, m_Neg(m_Specific(TI)))) {
1162+
return Builder.CreateBinaryIntrinsic(Intrinsic::abs, TI,
1163+
Builder.getFalse());
1164+
}
1165+
1166+
// Match: (A < B) ? (0 - (A - B)) : (A - B) --> abs(A - B)
1167+
// This handles cases like (A <= B) after normalization
1168+
if (Pred == CmpInst::ICMP_SLT &&
1169+
match(TI, m_Neg(m_NSWSub(m_Specific(A), m_Specific(B)))) &&
1170+
match(FI, m_NSWSub(m_Specific(A), m_Specific(B)))) {
1171+
return Builder.CreateBinaryIntrinsic(Intrinsic::abs, FI,
1172+
Builder.getFalse());
1173+
}
1174+
1175+
// Match: (A > B) ? (0 - (B - A)) : (B - A) --> abs(B - A)
1176+
// This handles cases like (B <= A) after normalization where the subtraction
1177+
// operands are swapped
1178+
if (Pred == CmpInst::ICMP_SGT &&
1179+
match(TI, m_Neg(m_NSWSub(m_Specific(B), m_Specific(A)))) &&
1180+
match(FI, m_NSWSub(m_Specific(B), m_Specific(A)))) {
1181+
return Builder.CreateBinaryIntrinsic(Intrinsic::abs, FI,
1182+
Builder.getFalse());
1183+
}
1184+
1185+
// Match: (A < B) ? (B - A) : (0 - (B - A)) --> abs(B - A)
1186+
// This handles cases where comparison operands are swapped relative to
1187+
// subtraction
1188+
if (Pred == CmpInst::ICMP_SLT &&
1189+
match(TI, m_NSWSub(m_Specific(B), m_Specific(A))) &&
1190+
match(FI, m_Neg(m_Specific(TI)))) {
1191+
return Builder.CreateBinaryIntrinsic(Intrinsic::abs, TI,
1192+
Builder.getFalse());
1193+
}
1194+
11561195
return nullptr;
11571196
}
11581197

llvm/test/Transforms/InstCombine/abs-intrinsic.ll

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -865,9 +865,7 @@ define i32 @abs_range_metadata(i32 %x) {
865865
define i32 @abs_diff(i32 %x, i32 %y) {
866866
; CHECK-LABEL: @abs_diff(
867867
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]]
868-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], [[Y]]
869-
; CHECK-NEXT: [[SUB1:%.*]] = sub i32 0, [[SUB]]
870-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[SUB1]]
868+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 false)
871869
; CHECK-NEXT: ret i32 [[COND]]
872870
;
873871
%sub = sub nsw i32 %x, %y
@@ -925,9 +923,33 @@ define i32 @abs_diff_neg_no_nsw(i32 %x, i32 %y) {
925923
define i32 @abs_diff_ge(i32 %x, i32 %y) {
926924
; CHECK-LABEL: @abs_diff_ge(
927925
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]]
928-
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp slt i32 [[X]], [[Y]]
929-
; CHECK-NEXT: [[SUB1:%.*]] = sub i32 0, [[SUB]]
930-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[SUB1]], i32 [[SUB]]
926+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 false)
927+
; CHECK-NEXT: ret i32 [[COND]]
928+
;
929+
%sub = sub nsw i32 %x, %y
930+
%cmp = icmp sge i32 %x, %y
931+
%sub1 = sub i32 0, %sub
932+
%cond = select i1 %cmp, i32 %sub, i32 %sub1
933+
ret i32 %cond
934+
}
935+
936+
define i32 @abs_diff_slt_commute(i32 %x, i32 %y) {
937+
; CHECK-LABEL: @abs_diff_slt_commute(
938+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]]
939+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 false)
940+
; CHECK-NEXT: ret i32 [[COND]]
941+
;
942+
%sub = sub nsw i32 %x, %y
943+
%cmp = icmp slt i32 %y, %x
944+
%sub1 = sub i32 0, %sub
945+
%cond = select i1 %cmp, i32 %sub, i32 %sub1
946+
ret i32 %cond
947+
}
948+
949+
define i32 @abs_diff_sge_same(i32 %x, i32 %y) {
950+
; CHECK-LABEL: @abs_diff_sge_same(
951+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]]
952+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 false)
931953
; CHECK-NEXT: ret i32 [[COND]]
932954
;
933955
%sub = sub nsw i32 %x, %y
@@ -936,3 +958,42 @@ define i32 @abs_diff_ge(i32 %x, i32 %y) {
936958
%cond = select i1 %cmp, i32 %sub, i32 %sub1
937959
ret i32 %cond
938960
}
961+
962+
define i32 @abs_diff_sle_inverted(i32 %x, i32 %y) {
963+
; CHECK-LABEL: @abs_diff_sle_inverted(
964+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]]
965+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 false)
966+
; CHECK-NEXT: ret i32 [[COND]]
967+
;
968+
%sub = sub nsw i32 %x, %y
969+
%cmp = icmp sle i32 %x, %y
970+
%sub1 = sub i32 0, %sub
971+
%cond = select i1 %cmp, i32 %sub1, i32 %sub
972+
ret i32 %cond
973+
}
974+
975+
define i32 @abs_diff_sle_commute(i32 %x, i32 %y) {
976+
; CHECK-LABEL: @abs_diff_sle_commute(
977+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]]
978+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 false)
979+
; CHECK-NEXT: ret i32 [[COND]]
980+
;
981+
%sub = sub nsw i32 %x, %y
982+
%cmp = icmp sle i32 %y, %x
983+
%sub1 = sub i32 0, %sub
984+
%cond = select i1 %cmp, i32 %sub, i32 %sub1
985+
ret i32 %cond
986+
}
987+
988+
define i8 @abs_diff_sle_y_x(i8 %x, i8 %y) {
989+
; CHECK-LABEL: @abs_diff_sle_y_x(
990+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]]
991+
; CHECK-NEXT: [[COND:%.*]] = call i8 @llvm.abs.i8(i8 [[SUB]], i1 false)
992+
; CHECK-NEXT: ret i8 [[COND]]
993+
;
994+
%sub = sub nsw i8 %x, %y
995+
%cmp = icmp sle i8 %y, %x
996+
%sub1 = sub i8 0, %sub
997+
%cond = select i1 %cmp, i8 %sub, i8 %sub1
998+
ret i8 %cond
999+
}

0 commit comments

Comments
 (0)