[PATCH] D106932: [AArch64][SVE][InstCombine] Move last{a,b} before binop if one operand is a splat value
Usman Nadeem via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 27 21:29:04 PDT 2021
mnadeem created this revision.
mnadeem added reviewers: efriedma, sdesmalen, paulwalker-arm.
Herald added subscribers: psnobl, hiraditya, kristof.beyls, tschuett.
mnadeem requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.
Move the last{a,b} operation to the vector operand of the binary instruction if
the binop's second operand is a splat value. This essentially converts the binop
to a scalar operation.
Example:
lastX (binop (x, splat(y))) --> binop(lastX(x), y)
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D106932
Files:
llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-lasta-lastb.ll
Index: llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-lasta-lastb.ll
===================================================================
--- llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-lasta-lastb.ll
+++ llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-lasta-lastb.ll
@@ -163,6 +163,49 @@
ret i8 %last
}
+; Check that we move the lastb before the binary operation so that the new binary op is scalar.
+define i8 @lastb_binop_RHS_splat(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
+; OPT-LABEL: @lastb_binop_RHS_splat(
+; OPT-NEXT: %1 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vector)
+; OPT-NEXT: %binop1 = udiv i8 %1, %scalar
+; OPT-NEXT: ret i8 %binop1
+ %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
+ %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
+ %binop = udiv <vscale x 16 x i8> %vector, %splat
+ %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
+ ret i8 %last
+}
+
+define i8 @lastb_binop_LHS_splat(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
+; OPT-LABEL: @lastb_binop_LHS_splat(
+; OPT-NEXT: %1 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vector)
+; OPT-NEXT: %binop1 = udiv i8 %scalar, %1
+; OPT-NEXT: ret i8 %binop1
+ %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
+ %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
+ %binop = udiv <vscale x 16 x i8> %splat, %vector
+ %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
+ ret i8 %last
+}
+
+; Check that we dont do anything as the binary op has multiple uses.
+define i8 @lastb_binop_nochange(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
+; OPT-LABEL: @lastb_binop_nochange(
+; OPT-NEXT: %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
+; OPT-NEXT: %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
+; OPT-NEXT: %binop = udiv <vscale x 16 x i8> %vector, %splat
+; OPT-NEXT: %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
+; OPT-NEXT: call void @use(<vscale x 16 x i8> %binop)
+; OPT-NEXT: ret i8 %last
+ %splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
+ %splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
+ %binop = udiv <vscale x 16 x i8> %vector, %splat
+ %last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
+ call void @use(<vscale x 16 x i8> %binop)
+ ret i8 %last
+}
+
+declare void @use(<vscale x 16 x i8>)
declare <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32)
declare i8 @llvm.aarch64.sve.lasta.nxv16i8(<vscale x 16 x i1>, <vscale x 16 x i8>)
declare i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1>, <vscale x 16 x i8>)
Index: llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
===================================================================
--- llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -555,6 +555,29 @@
if (auto *SplatVal = getSplatValue(Vec))
return IC.replaceInstUsesWith(II, SplatVal);
+ // lastX (binop (x, splat(y))) --> binop(lastX(x), y)
+ // lastX (binop (splat(x), y)) --> binop(x, lastX(y))
+ Value *LHS, *RHS;
+ if (match(Vec, m_OneUse(m_BinOp(m_Value(LHS), m_Value(RHS)))) &&
+ (isSplatValue(LHS) || isSplatValue(RHS))) {
+ BinaryOperator *NewBinOp = nullptr;
+ auto OpC = cast<BinaryOperator>(Vec)->getOpcode();
+ auto *NewII = cast<IntrinsicInst>(II.clone());
+ NewII->insertBefore(&II);
+
+ if (auto *SplatVal = getSplatValue(RHS)) {
+ NewII->setArgOperand(1, LHS);
+ NewBinOp =
+ BinaryOperator::Create(OpC, NewII, SplatVal, Vec->getName(), &II);
+ } else if (auto *SplatVal = getSplatValue(LHS)) {
+ NewII->setArgOperand(1, RHS);
+ NewBinOp =
+ BinaryOperator::Create(OpC, SplatVal, NewII, Vec->getName(), &II);
+ }
+
+ return IC.replaceInstUsesWith(II, NewBinOp);
+ }
+
auto *C = dyn_cast<Constant>(Pg);
if (IsAfter && C && C->isNullValue()) {
// The intrinsic is extracting lane 0 so use an extract instead.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D106932.362274.patch
Type: text/x-patch
Size: 4673 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210728/40b5ce7c/attachment.bin>
More information about the llvm-commits
mailing list