[llvm] [GlobalIsel] Combine G_EXTRACT_VECTOR_ELT (PR #85321)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 15 00:37:28 PDT 2024


Thorsten =?utf-8?q?Schütt?= <schuett at gmail.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/85321 at github.com>


================
@@ -0,0 +1,175 @@
+//===- CombinerHelperVectorOps.cpp-----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements CombinerHelper for G_EXTRACT_VECTOR_ELT.
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
+#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
+#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
+#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
+#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/GlobalISel/Utils.h"
+#include "llvm/CodeGen/LowLevelTypeUtils.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/CodeGen/TargetOpcodes.h"
+#include "llvm/Support/Casting.h"
+#include <optional>
+
+#define DEBUG_TYPE "gi-combiner"
+
+using namespace llvm;
+using namespace MIPatternMatch;
+
+bool CombinerHelper::matchExtractVectorElement(MachineInstr &MI,
+                                               BuildFnTy &MatchInfo) {
+  GExtractVectorElement *Extract = cast<GExtractVectorElement>(&MI);
+
+  Register Dst = Extract->getReg(0);
+  Register Vector = Extract->getVectorReg();
+  Register Index = Extract->getIndexReg();
+  LLT DstTy = MRI.getType(Dst);
+  LLT VectorTy = MRI.getType(Vector);
+
+  // The vector register can be def'd by various ops that have vector as its
+  // type. They can all be used for constant folding, scalarizing,
+  // canonicalization, or combining based on symmetry.
+  //
+  // vector like ops
+  // * build vector
+  // * build vector trunc
+  // * shuffle vector
+  // * splat vector
+  // * concat vectors
+  // * insert/extract vector element
+  // * insert/extract subvector
+  // * vector loads
+  // * scalable vector loads
+  //
+  // compute like ops
+  // * binary ops
+  // * unary ops
+  //  * exts and truncs
+  //  * casts
+  //  * fneg
+  // * select
+  // * phis
+  // * cmps
+  // * freeze
+  // * bitcast
+  // * undef
+
+  // The MIs def'd on the Index and Vector register;
+  MachineInstr *IndexMI = getDefIgnoringCopies(Index, MRI);
+  MachineInstr *VectorMI = getDefIgnoringCopies(Vector, MRI);
+
+  // Fold extractVectorElement(undef, undef) -> undef
+  if ((isa<GImplicitDef>(VectorMI) || isa<GImplicitDef>(IndexMI)) &&
+      isLegalOrBeforeLegalizer({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) {
+    // If the Vector register is undef, then we cannot extract an element from
+    // it. An undef extract Index can be arbitrarily chosen to be an
+    // out-of-range index value, which would result in the instruction being
+    // poison.
+    MatchInfo = [=](MachineIRBuilder &B) { B.buildUndef(Dst); };
+    return true;
+  }
+
+  // We try to get the value of the Index register.
+  std::optional<ValueAndVReg> MaybeIndex =
+      getIConstantVRegValWithLookThrough(Index, MRI);
+  std::optional<APInt> IndexC = std::nullopt;
+
+  if (MaybeIndex)
+    IndexC = MaybeIndex->Value;
+
+  // Fold extractVectorElement(Vector, TOOLARGE) -> undef
+  if (IndexC && VectorTy.isFixedVector() &&
+      IndexC->uge(VectorTy.getNumElements()) &&
+      isLegalOrBeforeLegalizer({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) {
+    // For fixed-length vectors, it's invalid to extract out-of-range elements.
+    MatchInfo = [=](MachineIRBuilder &B) { B.buildUndef(Dst); };
+    return true;
+  }
+
+  // Fold extractVectorElement(freeze(FV), Index) ->
+  //     freeze(extractVectorElement(FV, Index))
+  if (auto *Freeze = dyn_cast<GFreeze>(VectorMI)) {
+    if (MRI.hasOneNonDBGUse(Freeze->getReg(0)) &&
+        isLegalOrBeforeLegalizer({TargetOpcode::G_FREEZE, {DstTy}})) {
+      // For G_FREEZE, the input and the output types are identical.
+      // Moving the freeze from the Vector into the front of the extract
+      // preserves the freeze semantics. We check above that
+      // the Index register is not undef.
+      // Furthermore, the Vector register
+      // becomes easier to analyze. A build vector
+      // could have been hidden behind the freeze.
+      MatchInfo = [=](MachineIRBuilder &B) {
+        auto Extract =
+            B.buildExtractVectorElement(DstTy, Freeze->getSourceReg(), Index);
+        B.buildFreeze(Dst, Extract);
+      };
+      return true;
+    }
+  }
+
+  // Fold extractVectorElement(insertVectorElement(_, Value, Index), Index) ->
+  // Value
+  if (auto *Insert = dyn_cast<GInsertVectorElement>(VectorMI)) {
----------------
arsenm wrote:

All these different source cases should be separate top level combines. This one for example can be done entirely in tablegen 

https://github.com/llvm/llvm-project/pull/85321


More information about the llvm-commits mailing list