Skip to content

[RISCV][GISEL] Introduce the RISCVPostLegalizerLowering pass #108991

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 17, 2024

Conversation

michaelmaitland
Copy link
Contributor

This is mostly a copy of the AArch64PostLegalizerLoweringPass, except it removes all of the AArch64 combines.

This pass allows us to lower instructions after the generic post-legalization combiner has had a chance to run.

We will be adding combines to this pass in future patches.

This is mostly a copy of the AArch64PostLegalizerLoweringPass, except it removes
all of the AArch64 combines.

This pass allows us to lower instructions after the generic post-legalization
combiner has had a chance to run.

We will be adding combines to this pass in future patches.
@llvmbot
Copy link
Member

llvmbot commented Sep 17, 2024

@llvm/pr-subscribers-llvm-globalisel

Author: Michael Maitland (michaelmaitland)

Changes

This is mostly a copy of the AArch64PostLegalizerLoweringPass, except it removes all of the AArch64 combines.

This pass allows us to lower instructions after the generic post-legalization combiner has had a chance to run.

We will be adding combines to this pass in future patches.


Full diff: https://github.com/llvm/llvm-project/pull/108991.diff

6 Files Affected:

  • (modified) llvm/lib/Target/RISCV/CMakeLists.txt (+3)
  • (added) llvm/lib/Target/RISCV/GISel/RISCVPostLegalizerLowering.cpp (+154)
  • (modified) llvm/lib/Target/RISCV/RISCV.h (+3)
  • (modified) llvm/lib/Target/RISCV/RISCVCombine.td (+7)
  • (modified) llvm/lib/Target/RISCV/RISCVTargetMachine.cpp (+2)
  • (modified) llvm/test/CodeGen/RISCV/GlobalISel/gisel-commandline-option.ll (+1)
diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index 124bc239451aed..7d02d630a28199 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -24,6 +24,8 @@ tablegen(LLVM RISCVGenPreLegalizeGICombiner.inc -gen-global-isel-combiner
               -combiners="RISCVPreLegalizerCombiner")
 tablegen(LLVM RISCVGenPostLegalizeGICombiner.inc -gen-global-isel-combiner
               -combiners="RISCVPostLegalizerCombiner")
+tablegen(LLVM RISCVGenPostLegalizeGILowering.inc -gen-global-isel-combiner
+              -combiners="RISCVPostLegalizerLowering")
 
 add_public_tablegen_target(RISCVCommonTableGen)
 
@@ -63,6 +65,7 @@ add_llvm_target(RISCVCodeGen
   GISel/RISCVInstructionSelector.cpp
   GISel/RISCVLegalizerInfo.cpp
   GISel/RISCVPostLegalizerCombiner.cpp
+  GISel/RISCVPostLegalizerLowering.cpp
   GISel/RISCVO0PreLegalizerCombiner.cpp
   GISel/RISCVPreLegalizerCombiner.cpp
   GISel/RISCVRegisterBankInfo.cpp
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVPostLegalizerLowering.cpp b/llvm/lib/Target/RISCV/GISel/RISCVPostLegalizerLowering.cpp
new file mode 100644
index 00000000000000..66db15e3a2e28c
--- /dev/null
+++ b/llvm/lib/Target/RISCV/GISel/RISCVPostLegalizerLowering.cpp
@@ -0,0 +1,154 @@
+//===--------------- RISCVPostLegalizerLowering.cpp -------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Post-legalization lowering for instructions.
+///
+/// This is used to offload pattern matching from the selector.
+///
+/// General optimization combines should be handled by either the
+/// RISCVPostLegalizerCombiner or the RISCVPreLegalizerCombiner.
+///
+//===----------------------------------------------------------------------===//
+
+#include "RISCVSubtarget.h"
+
+#include "llvm/CodeGen/GlobalISel/Combiner.h"
+#include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
+#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
+#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Support/Debug.h"
+
+#define GET_GICOMBINER_DEPS
+#include "RISCVGenPostLegalizeGILowering.inc"
+#undef GET_GICOMBINER_DEPS
+
+#define DEBUG_TYPE "riscv-postlegalizer-lowering"
+
+using namespace llvm;
+
+namespace {
+
+#define GET_GICOMBINER_TYPES
+#include "RISCVGenPostLegalizeGILowering.inc"
+#undef GET_GICOMBINER_TYPES
+
+class RISCVPostLegalizerLoweringImpl : public Combiner {
+protected:
+  // TODO: Make CombinerHelper methods const.
+  mutable CombinerHelper Helper;
+  const RISCVPostLegalizerLoweringImplRuleConfig &RuleConfig;
+  const RISCVSubtarget &STI;
+
+public:
+  RISCVPostLegalizerLoweringImpl(
+      MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
+      GISelCSEInfo *CSEInfo,
+      const RISCVPostLegalizerLoweringImplRuleConfig &RuleConfig,
+      const RISCVSubtarget &STI);
+
+  static const char *getName() { return "RISCVPreLegalizerCombiner"; }
+
+  bool tryCombineAll(MachineInstr &I) const override;
+
+private:
+#define GET_GICOMBINER_CLASS_MEMBERS
+#include "RISCVGenPostLegalizeGILowering.inc"
+#undef GET_GICOMBINER_CLASS_MEMBERS
+};
+
+#define GET_GICOMBINER_IMPL
+#include "RISCVGenPostLegalizeGILowering.inc"
+#undef GET_GICOMBINER_IMPL
+
+RISCVPostLegalizerLoweringImpl::RISCVPostLegalizerLoweringImpl(
+    MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
+    GISelCSEInfo *CSEInfo,
+    const RISCVPostLegalizerLoweringImplRuleConfig &RuleConfig,
+    const RISCVSubtarget &STI)
+    : Combiner(MF, CInfo, TPC, /*KB*/ nullptr, CSEInfo),
+      Helper(Observer, B, /*IsPreLegalize*/ true), RuleConfig(RuleConfig),
+      STI(STI),
+#define GET_GICOMBINER_CONSTRUCTOR_INITS
+#include "RISCVGenPostLegalizeGILowering.inc"
+#undef GET_GICOMBINER_CONSTRUCTOR_INITS
+{
+}
+
+class RISCVPostLegalizerLowering : public MachineFunctionPass {
+public:
+  static char ID;
+
+  RISCVPostLegalizerLowering();
+
+  StringRef getPassName() const override {
+    return "RISCVPostLegalizerLowering";
+  }
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  RISCVPostLegalizerLoweringImplRuleConfig RuleConfig;
+};
+} // end anonymous namespace
+
+void RISCVPostLegalizerLowering::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<TargetPassConfig>();
+  AU.setPreservesCFG();
+  getSelectionDAGFallbackAnalysisUsage(AU);
+  MachineFunctionPass::getAnalysisUsage(AU);
+}
+
+RISCVPostLegalizerLowering::RISCVPostLegalizerLowering()
+    : MachineFunctionPass(ID) {
+  if (!RuleConfig.parseCommandLineOption())
+    report_fatal_error("Invalid rule identifier");
+}
+
+bool RISCVPostLegalizerLowering::runOnMachineFunction(MachineFunction &MF) {
+  if (MF.getProperties().hasProperty(
+          MachineFunctionProperties::Property::FailedISel))
+    return false;
+  assert(MF.getProperties().hasProperty(
+             MachineFunctionProperties::Property::Legalized) &&
+         "Expected a legalized function?");
+  auto *TPC = &getAnalysis<TargetPassConfig>();
+  const Function &F = MF.getFunction();
+
+  const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
+  CombinerInfo CInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false,
+                     /*LegalizerInfo*/ nullptr, /*OptEnabled=*/true,
+                     F.hasOptSize(), F.hasMinSize());
+  // Disable fixed-point iteration to reduce compile-time
+  CInfo.MaxIterations = 1;
+  CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
+  // PostLegalizerCombiner performs DCE, so a full DCE pass is unnecessary.
+  CInfo.EnableFullDCE = false;
+  RISCVPostLegalizerLoweringImpl Impl(MF, CInfo, TPC, /*CSEInfo*/ nullptr,
+                                      RuleConfig, ST);
+  return Impl.combineMachineInstrs();
+}
+
+char RISCVPostLegalizerLowering::ID = 0;
+INITIALIZE_PASS_BEGIN(RISCVPostLegalizerLowering, DEBUG_TYPE,
+                      "Lower RISC-V MachineInstrs after legalization", false,
+                      false)
+INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
+INITIALIZE_PASS_END(RISCVPostLegalizerLowering, DEBUG_TYPE,
+                    "Lower RISC-V MachineInstrs after legalization", false,
+                    false)
+
+namespace llvm {
+FunctionPass *createRISCVPostLegalizerLowering() {
+  return new RISCVPostLegalizerLowering();
+}
+} // end namespace llvm
diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h
index 5a94ada8f8dd46..561e4895e19428 100644
--- a/llvm/lib/Target/RISCV/RISCV.h
+++ b/llvm/lib/Target/RISCV/RISCV.h
@@ -99,6 +99,9 @@ void initializeRISCVO0PreLegalizerCombinerPass(PassRegistry &);
 
 FunctionPass *createRISCVPreLegalizerCombiner();
 void initializeRISCVPreLegalizerCombinerPass(PassRegistry &);
+
+FunctionPass *createRISCVPostLegalizerLowering();
+void initializeRISCVPostLegalizerLoweringPass(PassRegistry &);
 } // namespace llvm
 
 #endif
diff --git a/llvm/lib/Target/RISCV/RISCVCombine.td b/llvm/lib/Target/RISCV/RISCVCombine.td
index 3a5afb1b075c9e..d48698ae6f2bfb 100644
--- a/llvm/lib/Target/RISCV/RISCVCombine.td
+++ b/llvm/lib/Target/RISCV/RISCVCombine.td
@@ -19,6 +19,13 @@ def RISCVO0PreLegalizerCombiner: GICombiner<
   "RISCVO0PreLegalizerCombinerImpl", [optnone_combines]> {
 }
 
+// Post-legalization combines which should happen at all optimization levels.
+// (E.g. ones that facilitate matching for the selector) For example, matching
+// pseudos.
+def RISCVPostLegalizerLowering
+    : GICombiner<"RISCVPostLegalizerLoweringImpl", []> {
+}
+
 // Post-legalization combines which are primarily optimizations.
 // TODO: Add more combines.
 def RISCVPostLegalizerCombiner
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 794df2212dfa53..5cb9fbc8a9eb98 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -111,6 +111,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
   initializeRISCVO0PreLegalizerCombinerPass(*PR);
   initializeRISCVPreLegalizerCombinerPass(*PR);
   initializeRISCVPostLegalizerCombinerPass(*PR);
+  initializeRISCVPostLegalizerLoweringPass(*PR);
   initializeKCFIPass(*PR);
   initializeRISCVDeadRegisterDefinitionsPass(*PR);
   initializeRISCVMakeCompressibleOptPass(*PR);
@@ -482,6 +483,7 @@ bool RISCVPassConfig::addLegalizeMachineIR() {
 void RISCVPassConfig::addPreRegBankSelect() {
   if (getOptLevel() != CodeGenOptLevel::None)
     addPass(createRISCVPostLegalizerCombiner());
+  addPass(createRISCVPostLegalizerLowering());
 }
 
 bool RISCVPassConfig::addRegBankSelect() {
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/gisel-commandline-option.ll b/llvm/test/CodeGen/RISCV/GlobalISel/gisel-commandline-option.ll
index 82c66c23b26ba9..75607bb81ff513 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/gisel-commandline-option.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/gisel-commandline-option.ll
@@ -23,6 +23,7 @@
 ; ENABLED-NEXT:  Legalizer
 ; ENABLED-O1-NEXT:  MachineDominator Tree Construction
 ; ENABLED-O1-NEXT:  RISCVPostLegalizerCombiner
+; ENABLED-NEXT:  RISCVPostLegalizerLowering
 ; ENABLED-NEXT:  RegBankSelect
 ; ENABLED-NEXT:  Analysis for ComputingKnownBits
 ; ENABLED-O1-NEXT:  Lazy Branch Probability Analysis

@llvmbot
Copy link
Member

llvmbot commented Sep 17, 2024

@llvm/pr-subscribers-backend-risc-v

Author: Michael Maitland (michaelmaitland)

Changes

This is mostly a copy of the AArch64PostLegalizerLoweringPass, except it removes all of the AArch64 combines.

This pass allows us to lower instructions after the generic post-legalization combiner has had a chance to run.

We will be adding combines to this pass in future patches.


Full diff: https://github.com/llvm/llvm-project/pull/108991.diff

6 Files Affected:

  • (modified) llvm/lib/Target/RISCV/CMakeLists.txt (+3)
  • (added) llvm/lib/Target/RISCV/GISel/RISCVPostLegalizerLowering.cpp (+154)
  • (modified) llvm/lib/Target/RISCV/RISCV.h (+3)
  • (modified) llvm/lib/Target/RISCV/RISCVCombine.td (+7)
  • (modified) llvm/lib/Target/RISCV/RISCVTargetMachine.cpp (+2)
  • (modified) llvm/test/CodeGen/RISCV/GlobalISel/gisel-commandline-option.ll (+1)
diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index 124bc239451aed..7d02d630a28199 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -24,6 +24,8 @@ tablegen(LLVM RISCVGenPreLegalizeGICombiner.inc -gen-global-isel-combiner
               -combiners="RISCVPreLegalizerCombiner")
 tablegen(LLVM RISCVGenPostLegalizeGICombiner.inc -gen-global-isel-combiner
               -combiners="RISCVPostLegalizerCombiner")
+tablegen(LLVM RISCVGenPostLegalizeGILowering.inc -gen-global-isel-combiner
+              -combiners="RISCVPostLegalizerLowering")
 
 add_public_tablegen_target(RISCVCommonTableGen)
 
@@ -63,6 +65,7 @@ add_llvm_target(RISCVCodeGen
   GISel/RISCVInstructionSelector.cpp
   GISel/RISCVLegalizerInfo.cpp
   GISel/RISCVPostLegalizerCombiner.cpp
+  GISel/RISCVPostLegalizerLowering.cpp
   GISel/RISCVO0PreLegalizerCombiner.cpp
   GISel/RISCVPreLegalizerCombiner.cpp
   GISel/RISCVRegisterBankInfo.cpp
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVPostLegalizerLowering.cpp b/llvm/lib/Target/RISCV/GISel/RISCVPostLegalizerLowering.cpp
new file mode 100644
index 00000000000000..66db15e3a2e28c
--- /dev/null
+++ b/llvm/lib/Target/RISCV/GISel/RISCVPostLegalizerLowering.cpp
@@ -0,0 +1,154 @@
+//===--------------- RISCVPostLegalizerLowering.cpp -------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Post-legalization lowering for instructions.
+///
+/// This is used to offload pattern matching from the selector.
+///
+/// General optimization combines should be handled by either the
+/// RISCVPostLegalizerCombiner or the RISCVPreLegalizerCombiner.
+///
+//===----------------------------------------------------------------------===//
+
+#include "RISCVSubtarget.h"
+
+#include "llvm/CodeGen/GlobalISel/Combiner.h"
+#include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
+#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
+#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Support/Debug.h"
+
+#define GET_GICOMBINER_DEPS
+#include "RISCVGenPostLegalizeGILowering.inc"
+#undef GET_GICOMBINER_DEPS
+
+#define DEBUG_TYPE "riscv-postlegalizer-lowering"
+
+using namespace llvm;
+
+namespace {
+
+#define GET_GICOMBINER_TYPES
+#include "RISCVGenPostLegalizeGILowering.inc"
+#undef GET_GICOMBINER_TYPES
+
+class RISCVPostLegalizerLoweringImpl : public Combiner {
+protected:
+  // TODO: Make CombinerHelper methods const.
+  mutable CombinerHelper Helper;
+  const RISCVPostLegalizerLoweringImplRuleConfig &RuleConfig;
+  const RISCVSubtarget &STI;
+
+public:
+  RISCVPostLegalizerLoweringImpl(
+      MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
+      GISelCSEInfo *CSEInfo,
+      const RISCVPostLegalizerLoweringImplRuleConfig &RuleConfig,
+      const RISCVSubtarget &STI);
+
+  static const char *getName() { return "RISCVPreLegalizerCombiner"; }
+
+  bool tryCombineAll(MachineInstr &I) const override;
+
+private:
+#define GET_GICOMBINER_CLASS_MEMBERS
+#include "RISCVGenPostLegalizeGILowering.inc"
+#undef GET_GICOMBINER_CLASS_MEMBERS
+};
+
+#define GET_GICOMBINER_IMPL
+#include "RISCVGenPostLegalizeGILowering.inc"
+#undef GET_GICOMBINER_IMPL
+
+RISCVPostLegalizerLoweringImpl::RISCVPostLegalizerLoweringImpl(
+    MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
+    GISelCSEInfo *CSEInfo,
+    const RISCVPostLegalizerLoweringImplRuleConfig &RuleConfig,
+    const RISCVSubtarget &STI)
+    : Combiner(MF, CInfo, TPC, /*KB*/ nullptr, CSEInfo),
+      Helper(Observer, B, /*IsPreLegalize*/ true), RuleConfig(RuleConfig),
+      STI(STI),
+#define GET_GICOMBINER_CONSTRUCTOR_INITS
+#include "RISCVGenPostLegalizeGILowering.inc"
+#undef GET_GICOMBINER_CONSTRUCTOR_INITS
+{
+}
+
+class RISCVPostLegalizerLowering : public MachineFunctionPass {
+public:
+  static char ID;
+
+  RISCVPostLegalizerLowering();
+
+  StringRef getPassName() const override {
+    return "RISCVPostLegalizerLowering";
+  }
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  RISCVPostLegalizerLoweringImplRuleConfig RuleConfig;
+};
+} // end anonymous namespace
+
+void RISCVPostLegalizerLowering::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<TargetPassConfig>();
+  AU.setPreservesCFG();
+  getSelectionDAGFallbackAnalysisUsage(AU);
+  MachineFunctionPass::getAnalysisUsage(AU);
+}
+
+RISCVPostLegalizerLowering::RISCVPostLegalizerLowering()
+    : MachineFunctionPass(ID) {
+  if (!RuleConfig.parseCommandLineOption())
+    report_fatal_error("Invalid rule identifier");
+}
+
+bool RISCVPostLegalizerLowering::runOnMachineFunction(MachineFunction &MF) {
+  if (MF.getProperties().hasProperty(
+          MachineFunctionProperties::Property::FailedISel))
+    return false;
+  assert(MF.getProperties().hasProperty(
+             MachineFunctionProperties::Property::Legalized) &&
+         "Expected a legalized function?");
+  auto *TPC = &getAnalysis<TargetPassConfig>();
+  const Function &F = MF.getFunction();
+
+  const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
+  CombinerInfo CInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false,
+                     /*LegalizerInfo*/ nullptr, /*OptEnabled=*/true,
+                     F.hasOptSize(), F.hasMinSize());
+  // Disable fixed-point iteration to reduce compile-time
+  CInfo.MaxIterations = 1;
+  CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
+  // PostLegalizerCombiner performs DCE, so a full DCE pass is unnecessary.
+  CInfo.EnableFullDCE = false;
+  RISCVPostLegalizerLoweringImpl Impl(MF, CInfo, TPC, /*CSEInfo*/ nullptr,
+                                      RuleConfig, ST);
+  return Impl.combineMachineInstrs();
+}
+
+char RISCVPostLegalizerLowering::ID = 0;
+INITIALIZE_PASS_BEGIN(RISCVPostLegalizerLowering, DEBUG_TYPE,
+                      "Lower RISC-V MachineInstrs after legalization", false,
+                      false)
+INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
+INITIALIZE_PASS_END(RISCVPostLegalizerLowering, DEBUG_TYPE,
+                    "Lower RISC-V MachineInstrs after legalization", false,
+                    false)
+
+namespace llvm {
+FunctionPass *createRISCVPostLegalizerLowering() {
+  return new RISCVPostLegalizerLowering();
+}
+} // end namespace llvm
diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h
index 5a94ada8f8dd46..561e4895e19428 100644
--- a/llvm/lib/Target/RISCV/RISCV.h
+++ b/llvm/lib/Target/RISCV/RISCV.h
@@ -99,6 +99,9 @@ void initializeRISCVO0PreLegalizerCombinerPass(PassRegistry &);
 
 FunctionPass *createRISCVPreLegalizerCombiner();
 void initializeRISCVPreLegalizerCombinerPass(PassRegistry &);
+
+FunctionPass *createRISCVPostLegalizerLowering();
+void initializeRISCVPostLegalizerLoweringPass(PassRegistry &);
 } // namespace llvm
 
 #endif
diff --git a/llvm/lib/Target/RISCV/RISCVCombine.td b/llvm/lib/Target/RISCV/RISCVCombine.td
index 3a5afb1b075c9e..d48698ae6f2bfb 100644
--- a/llvm/lib/Target/RISCV/RISCVCombine.td
+++ b/llvm/lib/Target/RISCV/RISCVCombine.td
@@ -19,6 +19,13 @@ def RISCVO0PreLegalizerCombiner: GICombiner<
   "RISCVO0PreLegalizerCombinerImpl", [optnone_combines]> {
 }
 
+// Post-legalization combines which should happen at all optimization levels.
+// (E.g. ones that facilitate matching for the selector) For example, matching
+// pseudos.
+def RISCVPostLegalizerLowering
+    : GICombiner<"RISCVPostLegalizerLoweringImpl", []> {
+}
+
 // Post-legalization combines which are primarily optimizations.
 // TODO: Add more combines.
 def RISCVPostLegalizerCombiner
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 794df2212dfa53..5cb9fbc8a9eb98 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -111,6 +111,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
   initializeRISCVO0PreLegalizerCombinerPass(*PR);
   initializeRISCVPreLegalizerCombinerPass(*PR);
   initializeRISCVPostLegalizerCombinerPass(*PR);
+  initializeRISCVPostLegalizerLoweringPass(*PR);
   initializeKCFIPass(*PR);
   initializeRISCVDeadRegisterDefinitionsPass(*PR);
   initializeRISCVMakeCompressibleOptPass(*PR);
@@ -482,6 +483,7 @@ bool RISCVPassConfig::addLegalizeMachineIR() {
 void RISCVPassConfig::addPreRegBankSelect() {
   if (getOptLevel() != CodeGenOptLevel::None)
     addPass(createRISCVPostLegalizerCombiner());
+  addPass(createRISCVPostLegalizerLowering());
 }
 
 bool RISCVPassConfig::addRegBankSelect() {
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/gisel-commandline-option.ll b/llvm/test/CodeGen/RISCV/GlobalISel/gisel-commandline-option.ll
index 82c66c23b26ba9..75607bb81ff513 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/gisel-commandline-option.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/gisel-commandline-option.ll
@@ -23,6 +23,7 @@
 ; ENABLED-NEXT:  Legalizer
 ; ENABLED-O1-NEXT:  MachineDominator Tree Construction
 ; ENABLED-O1-NEXT:  RISCVPostLegalizerCombiner
+; ENABLED-NEXT:  RISCVPostLegalizerLowering
 ; ENABLED-NEXT:  RegBankSelect
 ; ENABLED-NEXT:  Analysis for ComputingKnownBits
 ; ENABLED-O1-NEXT:  Lazy Branch Probability Analysis

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@michaelmaitland michaelmaitland merged commit 6497283 into llvm:main Sep 17, 2024
11 checks passed
@aemerson
Copy link
Contributor

Are you sure you need this? @tobias-stadler in #97670 allowed us to re-select generic instructions in the selector, which I think should allow us to avoid having a lower phase.

@michaelmaitland
Copy link
Contributor Author

Are you sure you need this?

We took this because we wanted to avoid introducing target specific generic opcodes in the legalizer so that the post legalization combiner would only have to consider non-target specific generic opcodes. We still need to lower before instruction selection to target specific generic opcodes. We thought that this was the place to do it. It looks like thats what AArch64 does.

In order to understand whether we need this, I'd first like to ask two questions:

  1. Why does AArch64 take the post legalizer lowering approach instead of lowering to generic instructions in the selector
  2. Why isn't this pass marked deprecated if it is not needed? (Or is it marked deprecated and did I miss that?)

hamphet pushed a commit to hamphet/llvm-project that referenced this pull request Sep 18, 2024
…8991)

This is mostly a copy of the AArch64PostLegalizerLoweringPass, except it
removes all of the AArch64 combines.

This pass allows us to lower instructions after the generic
post-legalization combiner has had a chance to run.

We will be adding combines to this pass in future patches.
@tobias-stadler
Copy link
Contributor

tobias-stadler commented Sep 18, 2024

Currently, AArch64PostLegalizerLowering is needed and not deprecated, but I have started to reevaluate its necessity. Overall, I think it would be best to refrain from using Combiners for lowering. We probably need some more infrastructure work, before we can decide what's the best approach for these kinds of transformations though. I wanted to start a discussion on this when I have more time, but I can preliminarily dump some of my thoughts here.

As I see it, AArch64PostLegalizerLowering currently contains 2 classes of combines:

  1. Lowering: e.g. transforming shuffle vectors to other generic opcodes
  2. Canonicalization to offload pattern matching from the InstructionSelector: e.g. swapping operands such that they can be folded into addressing modes without always having to check if either LHS or RHS matches.

In my opinion, class 1 combines can and should be treated by reselecting generic instructions in the InstructionSelector, because they are only one-shot transformations, so they don't need to and therefore shouldn't happen inside a combiner. Instead these transformations can e.g. be done by creating generic instructions and recursively calling select() on them (which is only legal in all cases since #97670). I am thinking about adding a local worklist to InstructionSelect, so that instead of recursively calling select(), we can just mark instructions for reselection and InstructionSelect takes care of the rest. I have draft patches for this, but I am not sure this is the way to go, because it is only marginally more convenient than recursively calling select().

The problem is that this doesn't work for class 2 of combines, because they need to be fully applied to the entire MIR before ISel runs otherwise this can cause missed folding opportunities. They therefore need to happen inside a combiner. A solution for this would be to just throw these inside PostLegalizerCombiner and live with some O0 code-size regressions (haven't measured impact yet). Alternatively, once we have gMIR TableGen pattern support and ported enough ad-hoc matching code to TableGen, we can let TableGen deal with commutative instructions automagically and remove those combines entirely.

With my recent improvements to the core Combiner algorithm, AArch64PostLegalizerLowering went from ~4.5% to ~2.4% O0 and from ~1.1% to ~0.6% O2 back-end time, so this pass isn't as eye-wateringly expensive as it used to be, but still pretty expensive. (Other O2 times for reference: AArch64PreLegalizerCombiner 4.1%, AArch64PostLegalizerCombiner 1.9%, InstructionSelect: 3.4%). Once we have gMIR TableGen ISel patterns, porting combines to and from ISel should become very easy, so adding PostLegalizerLowering right now might not be difficult to reverse mistake.

@michaelmaitland
Copy link
Contributor Author

michaelmaitland commented Sep 18, 2024

@tobias-stadler Thank you for the insights. I took the advice and began to port #108859 to the instruction selector. I quickly ran into the problem that G_* instructions created in the instruction selector are not regbankselected. If you check out #108859, you can see that lowerInsertSubvector and its children have many calls to MIB.buildXXX (around 10 static calls to MIB.buildXXX). It seems quite yucky to have to manually regbankselect/constrain all all over the lowering/selection code.

I started to constrain them, but apparently only !preISelGenericOpcode instructions are allowed to be constrained. So I am not sure how to constrain them, even if I add in all the extra code to do it.

Also, it seems like I cannot test the intermediate lowering since whatever we lower to gets selected and that is what gets tested. This seems against the core value of GISEL easy ability to test specific things.

I am wondering if you have run into this problem and what your thoughts are on it.

@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 18, 2024

LLVM Buildbot has detected a new failure on builder llvm-clang-x86_64-expensive-checks-win running on as-worker-93 while building llvm at step 7 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/14/builds/1433

Here is the relevant piece of the build log for the reference
Step 7 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'LLVM-Unit :: Support/./SupportTests.exe/38/87' FAILED ********************
Script(shard):
--
GTEST_OUTPUT=json:C:\a\llvm-clang-x86_64-expensive-checks-win\build\unittests\Support\.\SupportTests.exe-LLVM-Unit-14636-38-87.json GTEST_SHUFFLE=0 GTEST_TOTAL_SHARDS=87 GTEST_SHARD_INDEX=38 C:\a\llvm-clang-x86_64-expensive-checks-win\build\unittests\Support\.\SupportTests.exe
--

Script:
--
C:\a\llvm-clang-x86_64-expensive-checks-win\build\unittests\Support\.\SupportTests.exe --gtest_filter=ProgramEnvTest.CreateProcessLongPath
--
C:\a\llvm-clang-x86_64-expensive-checks-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp(160): error: Expected equality of these values:
  0
  RC
    Which is: -2

C:\a\llvm-clang-x86_64-expensive-checks-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp(163): error: fs::remove(Twine(LongPath)): did not return errc::success.
error number: 13
error message: permission denied



C:\a\llvm-clang-x86_64-expensive-checks-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp:160
Expected equality of these values:
  0
  RC
    Which is: -2

C:\a\llvm-clang-x86_64-expensive-checks-win\llvm-project\llvm\unittests\Support\ProgramTest.cpp:163
fs::remove(Twine(LongPath)): did not return errc::success.
error number: 13
error message: permission denied




********************


@tobias-stadler
Copy link
Contributor

tobias-stadler commented Sep 18, 2024

If you check out #108859, you can see that lowerInsertSubvector and its children have many calls to MIB.buildXXX (around 10 static calls to MIB.buildXXX). It seems quite yucky to have to manually regbankselect/constrain all all over the lowering/selection code.

Also, it seems like I cannot test the intermediate lowering since whatever we lower to gets selected and that is what gets tested. This seems against the core value of GISEL easy ability to test specific things.

Last time I looked at AArch64PostLegalizerLowering almost all lowering combines were fairly trivial (mostly single instruction rewrites), so I didn't think these technicalities would be an issue. Your lowering appears to be more complex, so I completely agree.

I started to constrain them, but apparently only !preISelGenericOpcode instructions are allowed to be constrained. So I am not sure how to constrain them, even if I add in all the extra code to do it.

I don't think I quite understand this issue. It sounds like you were trying to constrain a RegClass? You should be able to at least use MRI.setRegBank. Maybe peek at AMDGPURegBankCombiner to see how they deal with RegBanks.

These technicalities seem solvable though, some ideas off the top of my head:

  1. We could set an Observer for the MIB, which assign regbanks on-demand (doesn't exist yet, but seems possible).
  2. Test the InstructionSelect debug output, which prints all instruction insertions/deletions (hacky?).

I wanted to experiment with these things before I ramble about this without proposing a proper solution. It probably makes the most sense to just run with RISCVPostLegalizerLowering for now unless you feel like experimenting or can live with these limitations.

I am not really attached to the idea of reselecting generic instructions (I hope it will work for AArch64 though). I just think that Combiners are the wrong place for one-shot expansions due to high overhead. In these cases SelectionDAG's split Type and Operation legalization phases kinda make sense. It could make sense to create stripped down single-pass low-overhead versions of either the Legalizer or the Combiner (e.g. without DCE, WorkList, ...) for these cases, but the problem is that just walking over the instructions and searching for certain opcodes is a significant compile-time contributor for O0, so we should aim to reduce the number of necessary O0 passes.

@tschuett
Copy link

One observation: If you create G_X in the lowering pass, you have to regbank-select them, but we have a pass which is an expert for it. In this case, it is probably better to do the lowering in the legalizer. As a by-product, we get legal G_X.

@topperc
Copy link
Collaborator

topperc commented Sep 18, 2024

One observation: If you create G_X in the lowering pass, you have to regbank-select them, but we have a pass which is an expert for it. In this case, it is probably better to do the lowering in the legalizer. As a by-product, we get legal G_X.

regbank select runs after the lowering pass...

@tschuett
Copy link

It leaves the question of legal G_X.

@topperc
Copy link
Collaborator

topperc commented Sep 18, 2024

Ok I concede we'll do it in the legalizer.

@tobias-stadler
Copy link
Contributor

Could you tag me when you encounter other cases that are annoying to solve using Legalizer? I'd like to compile these examples, so we can eventually find a better solution.

@aemerson
Copy link
Contributor

My mistake, I thought all the pieces to deprecate this for AArch64 was there. In any case, I want to give some more historical context for why we had this at all. Basically we wanted to do rewrites late once all optimizations were done (including all the post-legalizer combines). We would have done it in the selector if we could at the time. As Tobias said these are simple since they're basically selection split into two parts.

I would recommend the following for RISCV:

  • If you need to do late matching, after post-legalizer combines, either do this or have a custom MIR pass dedicated to one-shot lowering which may be a bit cheaper than using the combiner infrastructure.
  • If your rewrite can be expressed simply as a custom legalization rule then you can do it in the legalizer. One thing to keep in mind is that the earlier you start emitting target-specific-G_X operations the more you may lose in optimization potential by losing generality sooner.

tmsri pushed a commit to tmsri/llvm-project that referenced this pull request Sep 19, 2024
…8991)

This is mostly a copy of the AArch64PostLegalizerLoweringPass, except it
removes all of the AArch64 combines.

This pass allows us to lower instructions after the generic
post-legalization combiner has had a chance to run.

We will be adding combines to this pass in future patches.
michaelmaitland added a commit that referenced this pull request Sep 20, 2024
…108991)"

This reverts commit 6497283.

Based on the discussions in #108991 that happened post merge, we have decided
to remove this pass in favor of generating `RISCV::G_*` opcodes in the legalizer.

We may reconsider moving that code elsewhere in the future so that we can do
a better job during generic combines. We don't feel that doing it in instruciton
selection is the right decision today. Firstly, it requires us to manually
do regbankselect on the newly introduced instructions. Secondly, it is more
difficult to test since the test output will contain whatever `RISCV::G_*`
instructions select to (instead of `RISCV::G_*`).

My personal opinion is that the legalizer pass can be split into an early
legalizer and a late legalizer, both before regbankselect. The first legalizer
would not introduce target specific generic opcodes and the generic combiner
would run after it. The second legalizer would introduce the target specific
generic opcodes. I think this approach is better than the lowerer because the
legalizer guarantees that whatever we lower to is legal, and apparently because
it is more performant at compared to the lowerer (although, I'm not sure how
true this is).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants