[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