Skip to content

Commit 05d4c4e

Browse files
committed
[InstCombine] Canonicalize SPF_ABS to abs intrinc
Enable canonicalization of SPF_ABS and SPF_NABS to the abs intrinsic. To be conservative, the one-use check on the comparison is retained, this may be relaxed if all goes well. It's pretty likely that this will uncover places that missing handling for the abs() intrinsic. Please report any seen performance regressions. Differential Revision: https://reviews.llvm.org/D87188
1 parent 1cee33e commit 05d4c4e

File tree

12 files changed

+324
-600
lines changed

12 files changed

+324
-600
lines changed

clang/test/CodeGen/builtins-wasm.c

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -328,26 +328,20 @@ u8x16 sub_saturate_u_i8x16(u8x16 x, u8x16 y) {
328328

329329
i8x16 abs_i8x16(i8x16 v) {
330330
return __builtin_wasm_abs_i8x16(v);
331-
// WEBASSEMBLY: %neg = sub <16 x i8> zeroinitializer, %v
332-
// WEBASSEMBLY: %abscond = icmp slt <16 x i8> %v, zeroinitializer
333-
// WEBASSEMBLY: %abs = select <16 x i1> %abscond, <16 x i8> %neg, <16 x i8> %v
334-
// WEBASSEMBLY: ret <16 x i8> %abs
331+
// WEBASSEMBLY: call <16 x i8> @llvm.abs.v16i8(<16 x i8> %v, i1 false)
332+
// WEBASSEMBLY-NEXT: ret
335333
}
336334

337335
i16x8 abs_i16x8(i16x8 v) {
338336
return __builtin_wasm_abs_i16x8(v);
339-
// WEBASSEMBLY: %neg = sub <8 x i16> zeroinitializer, %v
340-
// WEBASSEMBLY: %abscond = icmp slt <8 x i16> %v, zeroinitializer
341-
// WEBASSEMBLY: %abs = select <8 x i1> %abscond, <8 x i16> %neg, <8 x i16> %v
342-
// WEBASSEMBLY: ret <8 x i16> %abs
337+
// WEBASSEMBLY: call <8 x i16> @llvm.abs.v8i16(<8 x i16> %v, i1 false)
338+
// WEBASSEMBLY-NEXT: ret
343339
}
344340

345341
i32x4 abs_i32x4(i32x4 v) {
346342
return __builtin_wasm_abs_i32x4(v);
347-
// WEBASSEMBLY: %neg = sub <4 x i32> zeroinitializer, %v
348-
// WEBASSEMBLY: %abscond = icmp slt <4 x i32> %v, zeroinitializer
349-
// WEBASSEMBLY: %abs = select <4 x i1> %abscond, <4 x i32> %neg, <4 x i32> %v
350-
// WEBASSEMBLY: ret <4 x i32> %abs
343+
// WEBASSEMBLY: call <4 x i32> @llvm.abs.v4i32(<4 x i32> %v, i1 false)
344+
// WEBASSEMBLY-NEXT: ret
351345
}
352346

353347
i8x16 min_s_i8x16(i8x16 x, i8x16 y) {

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 10 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,89 +1064,29 @@ static Instruction *canonicalizeMinMaxWithConstant(SelectInst &Sel,
10641064
return &Sel;
10651065
}
10661066

1067-
/// There are many select variants for each of ABS/NABS.
1068-
/// In matchSelectPattern(), there are different compare constants, compare
1069-
/// predicates/operands and select operands.
1070-
/// In isKnownNegation(), there are different formats of negated operands.
1071-
/// Canonicalize all these variants to 1 pattern.
1072-
/// This makes CSE more likely.
1067+
/// Canonicalize select-based abs/nabs to llvm.abs() intrinsic.
10731068
static Instruction *canonicalizeAbsNabs(SelectInst &Sel, ICmpInst &Cmp,
10741069
InstCombinerImpl &IC) {
10751070
if (!Cmp.hasOneUse() || !isa<Constant>(Cmp.getOperand(1)))
10761071
return nullptr;
10771072

1078-
// Choose a sign-bit check for the compare (likely simpler for codegen).
1079-
// ABS: (X <s 0) ? -X : X
1080-
// NABS: (X <s 0) ? X : -X
10811073
Value *LHS, *RHS;
10821074
SelectPatternFlavor SPF = matchSelectPattern(&Sel, LHS, RHS).Flavor;
10831075
if (SPF != SelectPatternFlavor::SPF_ABS &&
10841076
SPF != SelectPatternFlavor::SPF_NABS)
10851077
return nullptr;
10861078

1087-
Value *TVal = Sel.getTrueValue();
1088-
Value *FVal = Sel.getFalseValue();
1089-
assert(isKnownNegation(TVal, FVal) &&
1090-
"Unexpected result from matchSelectPattern");
1091-
1092-
// The compare may use the negated abs()/nabs() operand, or it may use
1093-
// negation in non-canonical form such as: sub A, B.
1094-
bool CmpUsesNegatedOp = match(Cmp.getOperand(0), m_Neg(m_Specific(TVal))) ||
1095-
match(Cmp.getOperand(0), m_Neg(m_Specific(FVal)));
1096-
1097-
bool CmpCanonicalized = !CmpUsesNegatedOp &&
1098-
match(Cmp.getOperand(1), m_ZeroInt()) &&
1099-
Cmp.getPredicate() == ICmpInst::ICMP_SLT;
1100-
bool RHSCanonicalized = match(RHS, m_Neg(m_Specific(LHS)));
1101-
1102-
// Is this already canonical?
1103-
if (CmpCanonicalized && RHSCanonicalized)
1104-
return nullptr;
1105-
1106-
// If RHS is not canonical but is used by other instructions, don't
1107-
// canonicalize it and potentially increase the instruction count.
1108-
if (!RHSCanonicalized)
1109-
if (!(RHS->hasOneUse() || (RHS->hasNUses(2) && CmpUsesNegatedOp)))
1110-
return nullptr;
1079+
bool IntMinIsPoison = match(RHS, m_NSWNeg(m_Specific(LHS)));
1080+
Constant *IntMinIsPoisonC =
1081+
ConstantInt::get(Type::getInt1Ty(Sel.getContext()), IntMinIsPoison);
1082+
Instruction *Abs =
1083+
IC.Builder.CreateBinaryIntrinsic(Intrinsic::abs, LHS, IntMinIsPoisonC);
11111084

1112-
// Create the canonical compare: icmp slt LHS 0.
1113-
if (!CmpCanonicalized) {
1114-
Cmp.setPredicate(ICmpInst::ICMP_SLT);
1115-
Cmp.setOperand(1, ConstantInt::getNullValue(Cmp.getOperand(0)->getType()));
1116-
if (CmpUsesNegatedOp)
1117-
Cmp.setOperand(0, LHS);
1118-
}
1119-
1120-
// Create the canonical RHS: RHS = sub (0, LHS).
1121-
if (!RHSCanonicalized) {
1122-
assert(RHS->hasOneUse() && "RHS use number is not right");
1123-
RHS = IC.Builder.CreateNeg(LHS);
1124-
if (TVal == LHS) {
1125-
// Replace false value.
1126-
IC.replaceOperand(Sel, 2, RHS);
1127-
FVal = RHS;
1128-
} else {
1129-
// Replace true value.
1130-
IC.replaceOperand(Sel, 1, RHS);
1131-
TVal = RHS;
1132-
}
1133-
}
1085+
if (SPF == SelectPatternFlavor::SPF_NABS)
1086+
return IntMinIsPoison ? BinaryOperator::CreateNSWNeg(Abs)
1087+
: BinaryOperator::CreateNeg(Abs);
11341088

1135-
// If the select operands do not change, we're done.
1136-
if (SPF == SelectPatternFlavor::SPF_NABS) {
1137-
if (TVal == LHS)
1138-
return &Sel;
1139-
assert(FVal == LHS && "Unexpected results from matchSelectPattern");
1140-
} else {
1141-
if (FVal == LHS)
1142-
return &Sel;
1143-
assert(TVal == LHS && "Unexpected results from matchSelectPattern");
1144-
}
1145-
1146-
// We are swapping the select operands, so swap the metadata too.
1147-
Sel.swapValues();
1148-
Sel.swapProfMetadata();
1149-
return &Sel;
1089+
return IC.replaceInstUsesWith(Sel, Abs);
11501090
}
11511091

11521092
/// If we have a select with an equality comparison, then we know the value in

0 commit comments

Comments
 (0)