2023-11-03 12:44:38 +01:00
|
|
|
|
2016-12-21 23:26:20 +00:00
|
|
|
//===- GlobalISelEmitter.cpp - Generate an instruction selector -----------===//
|
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// 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
|
2016-12-21 23:26:20 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
/// \file
|
|
|
|
/// This tablegen backend emits code for use by the GlobalISel instruction
|
2023-02-20 10:05:37 +08:00
|
|
|
/// selector. See include/llvm/Target/GlobalISel/Target.td.
|
2016-12-21 23:26:20 +00:00
|
|
|
///
|
|
|
|
/// This file analyzes the patterns recognized by the SelectionDAGISel tablegen
|
|
|
|
/// backend, filters out the ones that are unsupported, maps
|
|
|
|
/// SelectionDAG-specific constructs to their GlobalISel counterpart
|
|
|
|
/// (when applicable: MVT to LLT; SDNode to generic Instruction).
|
|
|
|
///
|
|
|
|
/// Not all patterns are supported: pass the tablegen invocation
|
|
|
|
/// "-warn-on-skipped-patterns" to emit a warning when a pattern is skipped,
|
|
|
|
/// as well as why.
|
|
|
|
///
|
|
|
|
/// The generated file defines a single method:
|
|
|
|
/// bool <Target>InstructionSelector::selectImpl(MachineInstr &I) const;
|
|
|
|
/// intended to be used in InstructionSelector::select as the first-step
|
|
|
|
/// selector for the patterns that don't require complex C++.
|
|
|
|
///
|
|
|
|
/// FIXME: We'll probably want to eventually define a base
|
|
|
|
/// "TargetGenInstructionSelector" class.
|
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2024-03-25 09:40:35 +01:00
|
|
|
#include "Basic/CodeGenIntrinsics.h"
|
|
|
|
#include "Common/CodeGenDAGPatterns.h"
|
|
|
|
#include "Common/CodeGenInstruction.h"
|
|
|
|
#include "Common/CodeGenRegisters.h"
|
|
|
|
#include "Common/CodeGenTarget.h"
|
|
|
|
#include "Common/GlobalISel/GlobalISelMatchTable.h"
|
|
|
|
#include "Common/GlobalISel/GlobalISelMatchTableExecutorEmitter.h"
|
|
|
|
#include "Common/InfoByHwMode.h"
|
2016-12-21 23:26:20 +00:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2024-01-25 12:01:31 -05:00
|
|
|
#include "llvm/CodeGenTypes/LowLevelType.h"
|
|
|
|
#include "llvm/CodeGenTypes/MachineValueType.h"
|
[globalisel][tablegen] Generate rule coverage and use it to identify untested rules
Summary:
This patch adds a LLVM_ENABLE_GISEL_COV which, like LLVM_ENABLE_DAGISEL_COV,
causes TableGen to instrument the generated table to collect rule coverage
information. However, LLVM_ENABLE_GISEL_COV goes a bit further than
LLVM_ENABLE_DAGISEL_COV. The information is written to files
(${CMAKE_BINARY_DIR}/gisel-coverage-* by default). These files can then be
concatenated into ${LLVM_GISEL_COV_PREFIX}-all after which TableGen will
read this information and use it to emit warnings about untested rules.
This technique could also be used by SelectionDAG and can be further
extended to detect hot rules and give them priority over colder rules.
Usage:
* Enable LLVM_ENABLE_GISEL_COV in CMake
* Build the compiler and run some tests
* cat gisel-coverage-[0-9]* > gisel-coverage-all
* Delete lib/Target/*/*GenGlobalISel.inc*
* Build the compiler
Known issues:
* ${LLVM_GISEL_COV_PREFIX}-all must be generated as a manual
step due to a lack of a portable 'cat' command. It should be the
concatenation of all ${LLVM_GISEL_COV_PREFIX}-[0-9]* files.
* There's no mechanism to discard coverage information when the ruleset
changes
Depends on D39742
Reviewers: ab, qcolombet, t.p.northover, aditya_nandakumar, rovka
Reviewed By: rovka
Subscribers: vsk, arsenm, nhaehnle, mgorny, kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D39747
llvm-svn: 318356
2017-11-16 00:46:35 +00:00
|
|
|
#include "llvm/Support/CodeGenCoverage.h"
|
2016-12-21 23:26:20 +00:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2017-02-10 04:00:17 +00:00
|
|
|
#include "llvm/Support/Error.h"
|
2017-02-21 09:19:41 +00:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
2016-12-21 23:26:20 +00:00
|
|
|
#include "llvm/TableGen/Error.h"
|
|
|
|
#include "llvm/TableGen/Record.h"
|
|
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
[globalisel][tablegen] Generate rule coverage and use it to identify untested rules
Summary:
This patch adds a LLVM_ENABLE_GISEL_COV which, like LLVM_ENABLE_DAGISEL_COV,
causes TableGen to instrument the generated table to collect rule coverage
information. However, LLVM_ENABLE_GISEL_COV goes a bit further than
LLVM_ENABLE_DAGISEL_COV. The information is written to files
(${CMAKE_BINARY_DIR}/gisel-coverage-* by default). These files can then be
concatenated into ${LLVM_GISEL_COV_PREFIX}-all after which TableGen will
read this information and use it to emit warnings about untested rules.
This technique could also be used by SelectionDAG and can be further
extended to detect hot rules and give them priority over colder rules.
Usage:
* Enable LLVM_ENABLE_GISEL_COV in CMake
* Build the compiler and run some tests
* cat gisel-coverage-[0-9]* > gisel-coverage-all
* Delete lib/Target/*/*GenGlobalISel.inc*
* Build the compiler
Known issues:
* ${LLVM_GISEL_COV_PREFIX}-all must be generated as a manual
step due to a lack of a portable 'cat' command. It should be the
concatenation of all ${LLVM_GISEL_COV_PREFIX}-[0-9]* files.
* There's no mechanism to discard coverage information when the ruleset
changes
Depends on D39742
Reviewers: ab, qcolombet, t.p.northover, aditya_nandakumar, rovka
Reviewed By: rovka
Subscribers: vsk, arsenm, nhaehnle, mgorny, kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D39747
llvm-svn: 318356
2017-11-16 00:46:35 +00:00
|
|
|
#include <string>
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
|
2016-12-21 23:26:20 +00:00
|
|
|
using namespace llvm;
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
using namespace llvm::gi;
|
|
|
|
|
|
|
|
using action_iterator = RuleMatcher::action_iterator;
|
2016-12-21 23:26:20 +00:00
|
|
|
|
|
|
|
#define DEBUG_TYPE "gisel-emitter"
|
|
|
|
|
|
|
|
STATISTIC(NumPatternTotal, "Total number of patterns");
|
2017-02-20 14:31:27 +00:00
|
|
|
STATISTIC(NumPatternImported, "Number of patterns imported from SelectionDAG");
|
|
|
|
STATISTIC(NumPatternImportsSkipped, "Number of SelectionDAG imports skipped");
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
STATISTIC(NumPatternsTested,
|
|
|
|
"Number of patterns executed according to coverage information");
|
2016-12-21 23:26:20 +00:00
|
|
|
|
2017-03-27 13:15:13 +00:00
|
|
|
cl::OptionCategory GlobalISelEmitterCat("Options for -gen-global-isel");
|
|
|
|
|
2016-12-21 23:26:20 +00:00
|
|
|
static cl::opt<bool> WarnOnSkippedPatterns(
|
|
|
|
"warn-on-skipped-patterns",
|
|
|
|
cl::desc("Explain why a pattern was skipped for inclusion "
|
|
|
|
"in the GlobalISel selector"),
|
2017-03-27 13:15:13 +00:00
|
|
|
cl::init(false), cl::cat(GlobalISelEmitterCat));
|
2016-12-21 23:26:20 +00:00
|
|
|
|
[globalisel][tablegen] Generate rule coverage and use it to identify untested rules
Summary:
This patch adds a LLVM_ENABLE_GISEL_COV which, like LLVM_ENABLE_DAGISEL_COV,
causes TableGen to instrument the generated table to collect rule coverage
information. However, LLVM_ENABLE_GISEL_COV goes a bit further than
LLVM_ENABLE_DAGISEL_COV. The information is written to files
(${CMAKE_BINARY_DIR}/gisel-coverage-* by default). These files can then be
concatenated into ${LLVM_GISEL_COV_PREFIX}-all after which TableGen will
read this information and use it to emit warnings about untested rules.
This technique could also be used by SelectionDAG and can be further
extended to detect hot rules and give them priority over colder rules.
Usage:
* Enable LLVM_ENABLE_GISEL_COV in CMake
* Build the compiler and run some tests
* cat gisel-coverage-[0-9]* > gisel-coverage-all
* Delete lib/Target/*/*GenGlobalISel.inc*
* Build the compiler
Known issues:
* ${LLVM_GISEL_COV_PREFIX}-all must be generated as a manual
step due to a lack of a portable 'cat' command. It should be the
concatenation of all ${LLVM_GISEL_COV_PREFIX}-[0-9]* files.
* There's no mechanism to discard coverage information when the ruleset
changes
Depends on D39742
Reviewers: ab, qcolombet, t.p.northover, aditya_nandakumar, rovka
Reviewed By: rovka
Subscribers: vsk, arsenm, nhaehnle, mgorny, kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D39747
llvm-svn: 318356
2017-11-16 00:46:35 +00:00
|
|
|
static cl::opt<bool> GenerateCoverage(
|
|
|
|
"instrument-gisel-coverage",
|
|
|
|
cl::desc("Generate coverage instrumentation for GlobalISel"),
|
|
|
|
cl::init(false), cl::cat(GlobalISelEmitterCat));
|
|
|
|
|
|
|
|
static cl::opt<std::string> UseCoverageFile(
|
|
|
|
"gisel-coverage-file", cl::init(""),
|
|
|
|
cl::desc("Specify file to retrieve coverage information from"),
|
|
|
|
cl::cat(GlobalISelEmitterCat));
|
|
|
|
|
[TableGen][GlobalISel] Optimize MatchTable for faster instruction selection
*** Context ***
Prior to this patchw, the table generated for matching instruction was
straight forward but highly inefficient.
Basically, each pattern generates its own set of self contained checks
and actions.
E.g., TableGen generated:
// First pattern
CheckNumOperand 3
CheckOpcode G_ADD
...
Build ADDrr
// Second pattern
CheckNumOperand 3
CheckOpcode G_ADD
...
Build ADDri
// Third pattern
CheckNumOperand 3
CheckOpcode G_SUB
...
Build SUBrr
*** Problem ***
Because of that generation, a *lot* of check were redundant between each
pattern and were checked every single time until we reach the pattern
that matches.
E.g., Taking the previous table, let say we are matching a G_SUB, that
means we were going to check all the rules for G_ADD before looking at
the G_SUB rule. In particular we are going to do:
check 3 operands; PASS
check G_ADD; FAIL
; Next rule
check 3 operands; PASS (but we already knew that!)
check G_ADD; FAIL (well it is still not true)
; Next rule
check 3 operands; PASS (really!!)
check G_SUB; PASS (at last :P)
*** Proposed Solution ***
This patch introduces a concept of group of rules (GroupMatcher) that
share some predicates and only get checked once for the whole group.
This patch only creates groups with one nesting level. Conceptually
there is nothing preventing us for having deeper nest level. However,
the current implementation is not smart enough to share the recording
(aka capturing) of values. That limits its ability to do more sharing.
For the given example the current patch will generate:
// First group
CheckOpcode G_ADD
// First pattern
CheckNumOperand 3
...
Build ADDrr
// Second pattern
CheckNumOperand 3
...
Build ADDri
// Second group
CheckOpcode G_SUB
// Third pattern
CheckNumOperand 3
...
Build SUBrr
But if we allowed several nesting level, it could create a sub group
for the checknumoperand 3.
(We would need to call optimizeRules on the rules within a group.)
*** Result ***
With only one level of nesting, the instruction selection pass is up
to 4x faster. For instance, one instruction now takes 500 checks,
instead of 24k! With more nesting we could get in the tens I believe.
Differential Revision: https://reviews.llvm.org/D39034
rdar://problem/34670699
llvm-svn: 321017
2017-12-18 19:47:41 +00:00
|
|
|
static cl::opt<bool> OptimizeMatchTable(
|
|
|
|
"optimize-match-table",
|
|
|
|
cl::desc("Generate an optimized version of the match table"),
|
|
|
|
cl::init(true), cl::cat(GlobalISelEmitterCat));
|
|
|
|
|
2017-03-15 20:18:38 +00:00
|
|
|
namespace {
|
2016-12-21 23:26:20 +00:00
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
static std::string explainPredicates(const TreePatternNode &N) {
|
2021-01-12 21:43:46 -08:00
|
|
|
std::string Explanation;
|
2017-04-13 09:45:37 +00:00
|
|
|
StringRef Separator = "";
|
2024-02-09 13:35:42 +00:00
|
|
|
for (const TreePredicateCall &Call : N.getPredicateCalls()) {
|
TableGen/ISel: Allow PatFrag predicate code to access captured operands
Summary:
This simplifies writing predicates for pattern fragments that are
automatically re-associated or commuted.
For example, a followup patch adds patterns for fragments of the form
(add (shl $x, $y), $z) to the AMDGPU backend. Such patterns are
automatically commuted to (add $z, (shl $x, $y)), which makes it basically
impossible to refer to $x, $y, and $z generically in the PredicateCode.
With this change, the PredicateCode can refer to $x, $y, and $z simply
as `Operands[i]`.
Test confirmed that there are no changes to any of the generated files
when building all (non-experimental) targets.
Change-Id: I61c00ace7eed42c1d4edc4c5351174b56b77a79c
Reviewers: arsenm, rampitec, RKSimon, craig.topper, hfinkel, uweigand
Subscribers: wdng, tpr, llvm-commits
Differential Revision: https://reviews.llvm.org/D51994
llvm-svn: 347992
2018-11-30 14:15:13 +00:00
|
|
|
const TreePredicateFn &P = Call.Fn;
|
2017-04-13 09:45:37 +00:00
|
|
|
Explanation +=
|
|
|
|
(Separator + P.getOrigPatFragRecord()->getRecord()->getName()).str();
|
2017-11-28 22:07:05 +00:00
|
|
|
Separator = ", ";
|
|
|
|
|
2017-04-13 09:45:37 +00:00
|
|
|
if (P.isAlwaysTrue())
|
|
|
|
Explanation += " always-true";
|
|
|
|
if (P.isImmediatePattern())
|
|
|
|
Explanation += " immediate";
|
2017-10-15 02:06:44 +00:00
|
|
|
|
|
|
|
if (P.isUnindexed())
|
|
|
|
Explanation += " unindexed";
|
|
|
|
|
|
|
|
if (P.isNonExtLoad())
|
|
|
|
Explanation += " non-extload";
|
|
|
|
if (P.isAnyExtLoad())
|
|
|
|
Explanation += " extload";
|
|
|
|
if (P.isSignExtLoad())
|
|
|
|
Explanation += " sextload";
|
|
|
|
if (P.isZeroExtLoad())
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
Explanation += " zextload";
|
2023-06-05 09:37:51 +02:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (P.isNonTruncStore())
|
|
|
|
Explanation += " non-truncstore";
|
|
|
|
if (P.isTruncStore())
|
|
|
|
Explanation += " truncstore";
|
2017-06-20 12:36:34 +00:00
|
|
|
|
2024-09-11 08:52:26 -07:00
|
|
|
if (const Record *VT = P.getMemoryVT())
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
Explanation += (" MemVT=" + VT->getName()).str();
|
2024-09-23 13:07:31 -07:00
|
|
|
if (const Record *VT = P.getScalarMemoryVT())
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
Explanation += (" ScalarVT(MemVT)=" + VT->getName()).str();
|
2017-06-20 12:36:34 +00:00
|
|
|
|
2024-09-23 13:07:31 -07:00
|
|
|
if (const ListInit *AddrSpaces = P.getAddressSpaces()) {
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
raw_string_ostream OS(Explanation);
|
|
|
|
OS << " AddressSpaces=[";
|
2017-06-20 12:36:34 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
StringRef AddrSpaceSeparator;
|
2024-09-23 13:07:31 -07:00
|
|
|
for (const Init *Val : AddrSpaces->getValues()) {
|
|
|
|
const IntInit *IntVal = dyn_cast<IntInit>(Val);
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (!IntVal)
|
|
|
|
continue;
|
2017-06-20 12:36:34 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
OS << AddrSpaceSeparator << IntVal->getValue();
|
|
|
|
AddrSpaceSeparator = ", ";
|
|
|
|
}
|
2016-12-21 23:26:20 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
OS << ']';
|
|
|
|
}
|
2017-11-01 19:57:57 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
int64_t MinAlign = P.getMinAlignment();
|
|
|
|
if (MinAlign > 0)
|
|
|
|
Explanation += " MinAlign=" + utostr(MinAlign);
|
2017-11-01 19:57:57 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (P.isAtomicOrderingMonotonic())
|
|
|
|
Explanation += " monotonic";
|
|
|
|
if (P.isAtomicOrderingAcquire())
|
|
|
|
Explanation += " acquire";
|
|
|
|
if (P.isAtomicOrderingRelease())
|
|
|
|
Explanation += " release";
|
|
|
|
if (P.isAtomicOrderingAcquireRelease())
|
|
|
|
Explanation += " acq_rel";
|
|
|
|
if (P.isAtomicOrderingSequentiallyConsistent())
|
|
|
|
Explanation += " seq_cst";
|
|
|
|
if (P.isAtomicOrderingAcquireOrStronger())
|
|
|
|
Explanation += " >=acquire";
|
|
|
|
if (P.isAtomicOrderingWeakerThanAcquire())
|
|
|
|
Explanation += " <acquire";
|
|
|
|
if (P.isAtomicOrderingReleaseOrStronger())
|
|
|
|
Explanation += " >=release";
|
|
|
|
if (P.isAtomicOrderingWeakerThanRelease())
|
|
|
|
Explanation += " <release";
|
2017-11-01 19:57:57 +00:00
|
|
|
}
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
return Explanation;
|
2023-06-05 09:37:51 +02:00
|
|
|
}
|
2017-10-14 00:31:58 +00:00
|
|
|
|
2024-09-11 08:52:26 -07:00
|
|
|
std::string explainOperator(const Record *Operator) {
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Operator->isSubClassOf("SDNode"))
|
|
|
|
return (" (" + Operator->getValueAsString("Opcode") + ")").str();
|
2019-09-06 20:32:37 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Operator->isSubClassOf("Intrinsic"))
|
|
|
|
return (" (Operator is an Intrinsic, " + Operator->getName() + ")").str();
|
2017-08-08 10:44:31 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Operator->isSubClassOf("ComplexPattern"))
|
|
|
|
return (" (Operator is an unmapped ComplexPattern, " + Operator->getName() +
|
|
|
|
")")
|
|
|
|
.str();
|
2019-09-06 20:32:37 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Operator->isSubClassOf("SDNodeXForm"))
|
|
|
|
return (" (Operator is an unmapped SDNodeXForm, " + Operator->getName() +
|
|
|
|
")")
|
|
|
|
.str();
|
2019-09-06 20:32:37 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
return (" (Operator " + Operator->getName() + " not understood)").str();
|
2023-06-05 09:37:51 +02:00
|
|
|
}
|
2019-09-06 20:32:37 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
/// Helper function to let the emitter report skip reason error messages.
|
|
|
|
static Error failedImport(const Twine &Reason) {
|
|
|
|
return make_error<StringError>(Reason, inconvertibleErrorCode());
|
2023-06-05 09:37:51 +02:00
|
|
|
}
|
2017-10-14 00:31:58 +00:00
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
static Error isTrivialOperatorNode(const TreePatternNode &N) {
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
std::string Explanation;
|
|
|
|
std::string Separator;
|
2017-10-14 00:31:58 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
bool HasUnsupportedPredicate = false;
|
2024-02-09 13:35:42 +00:00
|
|
|
for (const TreePredicateCall &Call : N.getPredicateCalls()) {
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
const TreePredicateFn &Predicate = Call.Fn;
|
2017-10-14 00:31:58 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.isAlwaysTrue())
|
|
|
|
continue;
|
[tablegen][globalisel] Capture instructions into locals and related infrastructure for multiple instructions matches.
Summary:
Prepare the way for nested instruction matching support by having actions
like CopyRenderer look up operands in the RuleMatcher rather than a
specific InstructionMatcher. This allows actions to reference any operand
from any matched instruction.
It works by checking the 'shape' of the match and capturing
each matched instruction to a local variable. If the shape is wrong
(not enough operands, leaf nodes where non-leafs are expected, etc.), then
the rule exits early without checking the predicates. Once we've captured
the instructions, we then test the predicates as before (except using the
local variables). If the match is successful, then we render the new
instruction as before using the local variables.
It's not noticable in this patch but by the time we support multiple
instruction matching, this patch will also cause a significant improvement
to readability of the emitted code since
MRI.getVRegDef(I->getOperand(0).getReg()) will simply be MI1 after
emitCxxCaptureStmts().
This isn't quite NFC because I've also fixed a bug that I'm surprised we
haven't encountered yet. It now checks there are at least the expected
number of operands before accessing them with getOperand().
Depends on D30531
Reviewers: t.p.northover, qcolombet, aditya_nandakumar, ab, rovka
Reviewed By: rovka
Subscribers: dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D30535
llvm-svn: 298257
2017-03-20 15:20:42 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.isImmediatePattern())
|
|
|
|
continue;
|
[globalisel][tablegen] Partially fix compile-time regressions by converting matcher to state-machine(s)
Summary:
Replace the matcher if-statements for each rule with a state-machine. This
significantly reduces compile time, memory allocations, and cumulative memory
allocation when compiling AArch64InstructionSelector.cpp.o after r303259 is
recommitted.
The following patches will expand on this further to fully fix the regressions.
Reviewers: rovka, ab, t.p.northover, qcolombet, aditya_nandakumar
Reviewed By: ab
Subscribers: vitalybuka, aemerson, javed.absar, igorb, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D33758
llvm-svn: 307079
2017-07-04 14:35:06 +00:00
|
|
|
|
2024-05-20 06:18:49 -08:00
|
|
|
if (Predicate.hasNoUse() || Predicate.hasOneUse())
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
continue;
|
2023-06-05 09:37:51 +02:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.isNonExtLoad() || Predicate.isAnyExtLoad() ||
|
|
|
|
Predicate.isSignExtLoad() || Predicate.isZeroExtLoad())
|
|
|
|
continue;
|
2023-06-05 09:37:51 +02:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.isNonTruncStore() || Predicate.isTruncStore())
|
|
|
|
continue;
|
2023-06-05 09:37:51 +02:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.isLoad() && Predicate.getMemoryVT())
|
|
|
|
continue;
|
2023-06-05 09:37:51 +02:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.isLoad() || Predicate.isStore()) {
|
|
|
|
if (Predicate.isUnindexed())
|
[tablegen][globalisel] Add support for nested instruction matching.
Summary:
Lift the restrictions that prevented the tree walking introduced in the
previous change and add support for patterns like:
(G_ADD (G_MUL (G_SEXT $src1), (G_SEXT $src2)), $src3) -> SMADDWrrr $dst, $src1, $src2, $src3
Also adds support for G_SEXT and G_ZEXT to support these cases.
One particular aspect of this that I should draw attention to is that I've
tried to be overly conservative in determining the safety of matches that
involve non-adjacent instructions and multiple basic blocks. This is intended
to be used as a cheap initial check and we may add a more expensive check in
the future. The current rules are:
* Reject if any instruction may load/store (we'd need to check for intervening
memory operations.
* Reject if any instruction has implicit operands.
* Reject if any instruction has unmodelled side-effects.
See isObviouslySafeToFold().
Reviewers: t.p.northover, javed.absar, qcolombet, aditya_nandakumar, ab, rovka
Reviewed By: ab
Subscribers: igorb, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30539
llvm-svn: 299430
2017-04-04 13:25:23 +00:00
|
|
|
continue;
|
2017-05-25 01:51:53 +00:00
|
|
|
}
|
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) {
|
|
|
|
const ListInit *AddrSpaces = Predicate.getAddressSpaces();
|
|
|
|
if (AddrSpaces && !AddrSpaces->empty())
|
|
|
|
continue;
|
[tablegen][globalisel] Add support for nested instruction matching.
Summary:
Lift the restrictions that prevented the tree walking introduced in the
previous change and add support for patterns like:
(G_ADD (G_MUL (G_SEXT $src1), (G_SEXT $src2)), $src3) -> SMADDWrrr $dst, $src1, $src2, $src3
Also adds support for G_SEXT and G_ZEXT to support these cases.
One particular aspect of this that I should draw attention to is that I've
tried to be overly conservative in determining the safety of matches that
involve non-adjacent instructions and multiple basic blocks. This is intended
to be used as a cheap initial check and we may add a more expensive check in
the future. The current rules are:
* Reject if any instruction may load/store (we'd need to check for intervening
memory operations.
* Reject if any instruction has implicit operands.
* Reject if any instruction has unmodelled side-effects.
See isObviouslySafeToFold().
Reviewers: t.p.northover, javed.absar, qcolombet, aditya_nandakumar, ab, rovka
Reviewed By: ab
Subscribers: igorb, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30539
llvm-svn: 299430
2017-04-04 13:25:23 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.getMinAlignment() > 0)
|
|
|
|
continue;
|
[tablegen][globalisel] Add support for nested instruction matching.
Summary:
Lift the restrictions that prevented the tree walking introduced in the
previous change and add support for patterns like:
(G_ADD (G_MUL (G_SEXT $src1), (G_SEXT $src2)), $src3) -> SMADDWrrr $dst, $src1, $src2, $src3
Also adds support for G_SEXT and G_ZEXT to support these cases.
One particular aspect of this that I should draw attention to is that I've
tried to be overly conservative in determining the safety of matches that
involve non-adjacent instructions and multiple basic blocks. This is intended
to be used as a cheap initial check and we may add a more expensive check in
the future. The current rules are:
* Reject if any instruction may load/store (we'd need to check for intervening
memory operations.
* Reject if any instruction has implicit operands.
* Reject if any instruction has unmodelled side-effects.
See isObviouslySafeToFold().
Reviewers: t.p.northover, javed.absar, qcolombet, aditya_nandakumar, ab, rovka
Reviewed By: ab
Subscribers: igorb, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30539
llvm-svn: 299430
2017-04-04 13:25:23 +00:00
|
|
|
}
|
2016-12-21 23:26:20 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.isAtomic() && Predicate.getMemoryVT())
|
|
|
|
continue;
|
[globalisel] Sort RuleMatchers by priority.
Summary:
This makes more important rules have priority over less important rules.
For example, '%a = G_ADD $b:s64, $c:s64' has priority over
'%a = G_ADD $b:s32, $c:s32'. Previously these rules were emitted in the
correct order by chance.
NFC in this patch but it is required to make the next patch work correctly.
Depends on D29710
Reviewers: t.p.northover, ab, qcolombet, aditya_nandakumar, rovka
Reviewed By: ab, rovka
Subscribers: javed.absar, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D29711
llvm-svn: 296121
2017-02-24 13:58:11 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.isAtomic() &&
|
|
|
|
(Predicate.isAtomicOrderingMonotonic() ||
|
|
|
|
Predicate.isAtomicOrderingAcquire() ||
|
|
|
|
Predicate.isAtomicOrderingRelease() ||
|
|
|
|
Predicate.isAtomicOrderingAcquireRelease() ||
|
|
|
|
Predicate.isAtomicOrderingSequentiallyConsistent() ||
|
|
|
|
Predicate.isAtomicOrderingAcquireOrStronger() ||
|
|
|
|
Predicate.isAtomicOrderingWeakerThanAcquire() ||
|
|
|
|
Predicate.isAtomicOrderingReleaseOrStronger() ||
|
|
|
|
Predicate.isAtomicOrderingWeakerThanRelease()))
|
|
|
|
continue;
|
2023-06-05 09:37:51 +02:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (Predicate.hasGISelPredicateCode())
|
|
|
|
continue;
|
2023-06-05 09:37:51 +02:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
HasUnsupportedPredicate = true;
|
|
|
|
Explanation = Separator + "Has a predicate (" + explainPredicates(N) + ")";
|
|
|
|
Separator = ", ";
|
|
|
|
Explanation += (Separator + "first-failing:" +
|
|
|
|
Predicate.getOrigPatFragRecord()->getRecord()->getName())
|
|
|
|
.str();
|
|
|
|
break;
|
2017-03-14 21:32:08 +00:00
|
|
|
}
|
2017-03-15 20:18:38 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (!HasUnsupportedPredicate)
|
|
|
|
return Error::success();
|
2016-12-21 23:26:20 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
return failedImport(Explanation);
|
2017-03-15 20:18:38 +00:00
|
|
|
}
|
|
|
|
|
2024-09-23 13:07:31 -07:00
|
|
|
static const Record *getInitValueAsRegClass(const Init *V) {
|
|
|
|
if (const DefInit *VDefInit = dyn_cast<DefInit>(V)) {
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
if (VDefInit->getDef()->isSubClassOf("RegisterOperand"))
|
|
|
|
return VDefInit->getDef()->getValueAsDef("RegClass");
|
|
|
|
if (VDefInit->getDef()->isSubClassOf("RegisterClass"))
|
|
|
|
return VDefInit->getDef();
|
2017-08-08 10:44:31 +00:00
|
|
|
}
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
return nullptr;
|
2017-08-08 13:21:26 +00:00
|
|
|
}
|
2017-08-08 10:44:31 +00:00
|
|
|
|
[NFC][RFC][TableGen] Split GlobalISelEmitter.cpp
This patch splits the GlobalISelEmitter.cpp file, which imports DAG ISel patterns for GISel, into separate "GISelMatchTable.h/cpp" files.
The main motive is readability & maintainability. GlobalISelEmitter.cpp was about 6400 lines of mixed code, some bits implementing the match table codegen, some others dedicated to importing DAG patterns.
Now it's down to 2700 + a 2150 header + 2000 impl.
It's a tiny bit more lines overall but that's to be expected - moving
inline definitions to out-of-line, adding comments in the .cpp, etc. all of that takes additional space, but I think the tradeoff is worth it.
I did as little unrelated code changes as possible, I would say the biggest change is the introduction of the `gi` namespace used to prevent name conflicts/ODR violations with type common names such as `Matcher`.
It was previously not an issue because all of the code was in an anonymous namespace.
This moves all of the "match table" code out of the file, so predicates,
rules, and actions are all separated now. I believe this helps separating concerns, now `GlobalISelEmitter.cpp` is more focused on importing DAG patterns into GI, instead of also containing the whole match table internals as well.
Note: the new files have a "GISel" prefix to make them distinct from the other "GI" files in the same folder, which are for the combiner.
Reviewed By: aemerson
Differential Revision: https://reviews.llvm.org/D151432
2023-05-25 14:19:08 +02:00
|
|
|
static std::string getScopedName(unsigned Scope, const std::string &Name) {
|
|
|
|
return ("pred:" + Twine(Scope) + ":" + Name).str();
|
2017-10-14 00:31:58 +00:00
|
|
|
}
|
|
|
|
|
2023-12-10 13:25:11 +03:00
|
|
|
static std::string getMangledRootDefName(StringRef DefOperandName) {
|
|
|
|
return ("DstI[" + DefOperandName + "]").str();
|
|
|
|
}
|
|
|
|
|
2016-12-21 23:26:20 +00:00
|
|
|
//===- GlobalISelEmitter class --------------------------------------------===//
|
|
|
|
|
2023-11-03 12:44:38 +01:00
|
|
|
static Expected<LLTCodeGen> getInstResultType(const TreePatternNode &Dst,
|
|
|
|
const CodeGenTarget &Target) {
|
|
|
|
// While we allow more than one output (both implicit and explicit defs)
|
|
|
|
// below, we only expect one explicit def here.
|
|
|
|
assert(Dst.getOperator()->isSubClassOf("Instruction"));
|
|
|
|
CodeGenInstruction &InstInfo = Target.getInstruction(Dst.getOperator());
|
2024-03-08 09:39:10 +01:00
|
|
|
if (!InstInfo.Operands.NumDefs)
|
|
|
|
return failedImport("Dst pattern child needs a def");
|
2023-11-03 12:44:38 +01:00
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
ArrayRef<TypeSetByHwMode> ChildTypes = Dst.getExtTypes();
|
2023-11-03 12:44:38 +01:00
|
|
|
if (ChildTypes.size() < 1)
|
|
|
|
return failedImport("Dst pattern child has no result");
|
2020-01-14 16:02:02 -05:00
|
|
|
|
2023-11-03 12:44:38 +01:00
|
|
|
// If there are multiple results, just take the first one (this is how
|
|
|
|
// SelectionDAG does it).
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<LLTCodeGen> MaybeOpTy;
|
2020-01-14 16:02:02 -05:00
|
|
|
if (ChildTypes.front().isMachineValueType()) {
|
2023-06-23 11:42:51 +02:00
|
|
|
MaybeOpTy = MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
|
2020-01-14 16:02:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!MaybeOpTy)
|
|
|
|
return failedImport("Dst operand has an unsupported type");
|
|
|
|
return *MaybeOpTy;
|
|
|
|
}
|
|
|
|
|
2023-06-26 11:44:18 +02:00
|
|
|
class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter {
|
2017-02-10 04:00:17 +00:00
|
|
|
public:
|
2024-09-30 06:37:36 -07:00
|
|
|
explicit GlobalISelEmitter(const RecordKeeper &RK);
|
2023-06-26 11:44:18 +02:00
|
|
|
|
|
|
|
void emitAdditionalImpl(raw_ostream &OS) override;
|
|
|
|
|
|
|
|
void emitMIPredicateFns(raw_ostream &OS) override;
|
|
|
|
void emitI64ImmPredicateFns(raw_ostream &OS) override;
|
|
|
|
void emitAPFloatImmPredicateFns(raw_ostream &OS) override;
|
|
|
|
void emitAPIntImmPredicateFns(raw_ostream &OS) override;
|
2023-06-26 13:23:18 +02:00
|
|
|
void emitTestSimplePredicate(raw_ostream &OS) override;
|
|
|
|
void emitRunCustomAction(raw_ostream &OS) override;
|
2023-06-26 11:44:18 +02:00
|
|
|
|
2023-08-07 12:59:24 +02:00
|
|
|
void postProcessRule(RuleMatcher &M);
|
|
|
|
|
2023-06-26 11:44:18 +02:00
|
|
|
const CodeGenTarget &getTarget() const override { return Target; }
|
|
|
|
StringRef getClassName() const override { return ClassName; }
|
|
|
|
|
2017-02-10 04:00:17 +00:00
|
|
|
void run(raw_ostream &OS);
|
|
|
|
|
|
|
|
private:
|
2023-06-26 11:44:18 +02:00
|
|
|
std::string ClassName;
|
|
|
|
|
2024-09-30 06:37:36 -07:00
|
|
|
const RecordKeeper &RK;
|
2017-02-10 04:00:17 +00:00
|
|
|
const CodeGenDAGPatterns CGP;
|
|
|
|
const CodeGenTarget &Target;
|
2020-01-14 13:48:34 -05:00
|
|
|
CodeGenRegBank &CGRegs;
|
2017-02-10 04:00:17 +00:00
|
|
|
|
2024-09-30 06:37:36 -07:00
|
|
|
ArrayRef<const Record *> AllPatFrags;
|
2023-06-26 11:44:18 +02:00
|
|
|
|
[globalisel][tablegen] Map ld and st to G_LOAD and G_STORE. NFC
Summary:
There is an important mismatch between ISD::LOAD and G_LOAD (and likewise for
ISD::STORE and G_STORE). In SelectionDAG, ISD::LOAD is a non-atomic load
and atomic loads are handled by a separate node. However, this is not true of
GlobalISel's G_LOAD. For G_LOAD, the MachineMemOperand indicates the atomicity
of the operation. As a result, this mapping must also add a predicate that
checks for non-atomic MachineMemOperands.
This is NFC since these nodes always have predicates in practice and are
therefore always rejected at the moment.
Depends on D37443
Reviewers: ab, qcolombet, t.p.northover, rovka, aditya_nandakumar
Reviewed By: qcolombet
Subscribers: kristof.beyls, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D37445
llvm-svn: 315843
2017-10-15 02:41:12 +00:00
|
|
|
/// Keep track of the equivalence between SDNodes and Instruction by mapping
|
2017-12-05 05:52:07 +00:00
|
|
|
/// SDNodes to the GINodeEquiv mapping. We need to map to the GINodeEquiv to
|
|
|
|
/// check for attributes on the relation such as CheckMMOIsNonAtomic.
|
2017-02-10 04:00:17 +00:00
|
|
|
/// This is defined using 'GINodeEquiv' in the target description.
|
2024-09-30 06:37:36 -07:00
|
|
|
DenseMap<const Record *, const Record *> NodeEquivs;
|
2017-02-10 04:00:17 +00:00
|
|
|
|
2017-03-14 21:32:08 +00:00
|
|
|
/// Keep track of the equivalence between ComplexPattern's and
|
|
|
|
/// GIComplexOperandMatcher. Map entries are specified by subclassing
|
|
|
|
/// GIComplexPatternEquiv.
|
|
|
|
DenseMap<const Record *, const Record *> ComplexPatternEquivs;
|
|
|
|
|
2018-01-16 18:44:05 +00:00
|
|
|
/// Keep track of the equivalence between SDNodeXForm's and
|
|
|
|
/// GICustomOperandRenderer. Map entries are specified by subclassing
|
|
|
|
/// GISDNodeXFormEquiv.
|
|
|
|
DenseMap<const Record *, const Record *> SDNodeXFormEquivs;
|
|
|
|
|
2018-02-16 22:37:15 +00:00
|
|
|
/// Keep track of Scores of PatternsToMatch similar to how the DAG does.
|
|
|
|
/// This adds compatibility for RuleMatchers to use this for ordering rules.
|
|
|
|
DenseMap<uint64_t, int> RuleMatcherScores;
|
|
|
|
|
[globalisel][tablegen] Generate rule coverage and use it to identify untested rules
Summary:
This patch adds a LLVM_ENABLE_GISEL_COV which, like LLVM_ENABLE_DAGISEL_COV,
causes TableGen to instrument the generated table to collect rule coverage
information. However, LLVM_ENABLE_GISEL_COV goes a bit further than
LLVM_ENABLE_DAGISEL_COV. The information is written to files
(${CMAKE_BINARY_DIR}/gisel-coverage-* by default). These files can then be
concatenated into ${LLVM_GISEL_COV_PREFIX}-all after which TableGen will
read this information and use it to emit warnings about untested rules.
This technique could also be used by SelectionDAG and can be further
extended to detect hot rules and give them priority over colder rules.
Usage:
* Enable LLVM_ENABLE_GISEL_COV in CMake
* Build the compiler and run some tests
* cat gisel-coverage-[0-9]* > gisel-coverage-all
* Delete lib/Target/*/*GenGlobalISel.inc*
* Build the compiler
Known issues:
* ${LLVM_GISEL_COV_PREFIX}-all must be generated as a manual
step due to a lack of a portable 'cat' command. It should be the
concatenation of all ${LLVM_GISEL_COV_PREFIX}-[0-9]* files.
* There's no mechanism to discard coverage information when the ruleset
changes
Depends on D39742
Reviewers: ab, qcolombet, t.p.northover, aditya_nandakumar, rovka
Reviewed By: rovka
Subscribers: vsk, arsenm, nhaehnle, mgorny, kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D39747
llvm-svn: 318356
2017-11-16 00:46:35 +00:00
|
|
|
// Rule coverage information.
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<CodeGenCoverage> RuleCoverage;
|
[globalisel][tablegen] Generate rule coverage and use it to identify untested rules
Summary:
This patch adds a LLVM_ENABLE_GISEL_COV which, like LLVM_ENABLE_DAGISEL_COV,
causes TableGen to instrument the generated table to collect rule coverage
information. However, LLVM_ENABLE_GISEL_COV goes a bit further than
LLVM_ENABLE_DAGISEL_COV. The information is written to files
(${CMAKE_BINARY_DIR}/gisel-coverage-* by default). These files can then be
concatenated into ${LLVM_GISEL_COV_PREFIX}-all after which TableGen will
read this information and use it to emit warnings about untested rules.
This technique could also be used by SelectionDAG and can be further
extended to detect hot rules and give them priority over colder rules.
Usage:
* Enable LLVM_ENABLE_GISEL_COV in CMake
* Build the compiler and run some tests
* cat gisel-coverage-[0-9]* > gisel-coverage-all
* Delete lib/Target/*/*GenGlobalISel.inc*
* Build the compiler
Known issues:
* ${LLVM_GISEL_COV_PREFIX}-all must be generated as a manual
step due to a lack of a portable 'cat' command. It should be the
concatenation of all ${LLVM_GISEL_COV_PREFIX}-[0-9]* files.
* There's no mechanism to discard coverage information when the ruleset
changes
Depends on D39742
Reviewers: ab, qcolombet, t.p.northover, aditya_nandakumar, rovka
Reviewed By: rovka
Subscribers: vsk, arsenm, nhaehnle, mgorny, kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D39747
llvm-svn: 318356
2017-11-16 00:46:35 +00:00
|
|
|
|
2020-09-14 10:39:25 +02:00
|
|
|
/// Variables used to help with collecting of named operands for predicates
|
|
|
|
/// with 'let PredicateCodeUsesOperands = 1'. WaitingForNamedOperands is set
|
|
|
|
/// to the number of named operands that predicate expects. Store locations in
|
|
|
|
/// StoreIdxForName correspond to the order in which operand names appear in
|
|
|
|
/// predicate's argument list.
|
2023-10-05 08:57:15 -07:00
|
|
|
/// When we visit named operand and WaitingForNamedOperands is not zero, add
|
|
|
|
/// matcher that will record operand and decrease counter.
|
2020-09-14 10:39:25 +02:00
|
|
|
unsigned WaitingForNamedOperands = 0;
|
|
|
|
StringMap<unsigned> StoreIdxForName;
|
|
|
|
|
2018-05-21 23:28:51 +00:00
|
|
|
void gatherOpcodeValues();
|
|
|
|
void gatherTypeIDValues();
|
2017-02-10 04:00:17 +00:00
|
|
|
void gatherNodeEquivs();
|
2018-06-15 23:13:43 +00:00
|
|
|
|
2024-09-30 06:37:36 -07:00
|
|
|
const Record *findNodeEquiv(const Record *N) const;
|
|
|
|
const CodeGenInstruction *getEquivNode(const Record &Equiv,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &N) const;
|
2017-02-10 04:00:17 +00:00
|
|
|
|
2024-09-23 13:07:31 -07:00
|
|
|
Error importRulePredicates(RuleMatcher &M,
|
|
|
|
ArrayRef<const Record *> Predicates);
|
2018-06-15 23:13:43 +00:00
|
|
|
Expected<InstructionMatcher &>
|
|
|
|
createAndImportSelDAGMatcher(RuleMatcher &Rule,
|
|
|
|
InstructionMatcher &InsnMatcher,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &Src, unsigned &TempOpIdx);
|
2024-09-11 08:52:26 -07:00
|
|
|
Error importComplexPatternOperandMatcher(OperandMatcher &OM, const Record *R,
|
2017-10-15 18:22:54 +00:00
|
|
|
unsigned &TempOpIdx) const;
|
|
|
|
Error importChildMatcher(RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &SrcChild,
|
2020-01-08 15:40:37 -05:00
|
|
|
bool OperandIsAPointer, bool OperandIsImmArg,
|
|
|
|
unsigned OpIdx, unsigned &TempOpIdx);
|
2017-10-31 19:09:29 +00:00
|
|
|
|
2019-09-06 20:32:37 +00:00
|
|
|
Expected<BuildMIAction &> createAndImportInstructionRenderer(
|
|
|
|
RuleMatcher &M, InstructionMatcher &InsnMatcher,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &Src, const TreePatternNode &Dst);
|
2017-11-01 19:57:57 +00:00
|
|
|
Expected<action_iterator> createAndImportSubInstructionRenderer(
|
2024-02-09 13:35:42 +00:00
|
|
|
action_iterator InsertPt, RuleMatcher &M, const TreePatternNode &Dst,
|
|
|
|
const TreePatternNode &Src, unsigned TempReg);
|
2017-10-31 23:03:18 +00:00
|
|
|
Expected<action_iterator>
|
|
|
|
createInstructionRenderer(action_iterator InsertPt, RuleMatcher &M,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &Dst);
|
2020-07-13 08:59:38 -04:00
|
|
|
|
2024-03-08 09:39:10 +01:00
|
|
|
Expected<action_iterator>
|
|
|
|
importExplicitDefRenderers(action_iterator InsertPt, RuleMatcher &M,
|
|
|
|
BuildMIAction &DstMIBuilder,
|
|
|
|
const TreePatternNode &Src,
|
|
|
|
const TreePatternNode &Dst, unsigned Start = 0);
|
2019-09-06 20:32:37 +00:00
|
|
|
|
2023-01-09 04:07:52 +00:00
|
|
|
Expected<action_iterator> importExplicitUseRenderers(
|
|
|
|
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
|
2024-02-09 13:35:42 +00:00
|
|
|
const llvm::TreePatternNode &Dst, const TreePatternNode &Src);
|
2023-01-09 04:07:52 +00:00
|
|
|
Expected<action_iterator> importExplicitUseRenderer(
|
|
|
|
action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &DstChild, const TreePatternNode &Src);
|
2019-05-30 07:30:37 +00:00
|
|
|
Error importDefaultOperandRenderers(action_iterator InsertPt, RuleMatcher &M,
|
|
|
|
BuildMIAction &DstMIBuilder,
|
2023-12-17 15:02:10 -05:00
|
|
|
const DAGDefaultOperand &DefaultOp) const;
|
2024-09-23 13:07:31 -07:00
|
|
|
Error importImplicitDefRenderers(BuildMIAction &DstMIBuilder,
|
|
|
|
ArrayRef<const Record *> ImplicitDefs) const;
|
2017-03-29 15:37:18 +00:00
|
|
|
|
2017-02-10 04:00:17 +00:00
|
|
|
/// Analyze pattern \p P, returning a matcher for it if possible.
|
|
|
|
/// Otherwise, return an Error explaining why we don't support it.
|
|
|
|
Expected<RuleMatcher> runOnPattern(const PatternToMatch &P);
|
[globalisel][tablegen] Import SelectionDAG's rule predicates and support the equivalent in GIRule.
Summary:
The SelectionDAG importer now imports rules with Predicate's attached via
Requires, PredicateControl, etc. These predicates are implemented as
bitset's to allow multiple predicates to be tested together. However,
unlike the MC layer subtarget features, each target only pays for it's own
predicates (e.g. AArch64 doesn't have 192 feature bits just because X86
needs a lot).
Both AArch64 and X86 derive at least one predicate from the MachineFunction
or Function so they must re-initialize AvailableFeatures before each
function. They also declare locals in <Target>InstructionSelector so that
computeAvailableFeatures() can use the code from SelectionDAG without
modification.
Reviewers: rovka, qcolombet, aditya_nandakumar, t.p.northover, ab
Reviewed By: rovka
Subscribers: aemerson, rengolin, dberris, kristof.beyls, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D31418
llvm-svn: 300993
2017-04-21 15:59:56 +00:00
|
|
|
|
2024-09-23 13:07:31 -07:00
|
|
|
void declareSubtargetFeature(const Record *Predicate);
|
2017-11-11 03:23:44 +00:00
|
|
|
|
2023-08-23 21:04:28 -07:00
|
|
|
unsigned declareHwModeCheck(StringRef HwModeFeatures);
|
|
|
|
|
2018-05-21 23:28:51 +00:00
|
|
|
MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules, bool Optimize,
|
|
|
|
bool WithCoverage);
|
|
|
|
|
2019-08-27 17:47:06 +00:00
|
|
|
/// Infer a CodeGenRegisterClass for the type of \p SuperRegNode. The returned
|
|
|
|
/// CodeGenRegisterClass will support the CodeGenRegisterClass of
|
|
|
|
/// \p SubRegNode, and the subregister index defined by \p SubRegIdxNode.
|
2022-12-04 17:12:44 -08:00
|
|
|
/// If no register class is found, return std::nullopt.
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<const CodeGenRegisterClass *>
|
2019-08-28 20:12:31 +00:00
|
|
|
inferSuperRegisterClassForNode(const TypeSetByHwMode &Ty,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &SuperRegNode,
|
|
|
|
const TreePatternNode &SubRegIdxNode);
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<CodeGenSubRegIndex *>
|
2024-02-09 13:35:42 +00:00
|
|
|
inferSubRegIndexForNode(const TreePatternNode &SubRegIdxNode);
|
2019-08-28 20:12:31 +00:00
|
|
|
|
|
|
|
/// Infer a CodeGenRegisterClass which suppoorts \p Ty and \p SubRegIdxNode.
|
2022-12-04 17:31:16 -08:00
|
|
|
/// Return std::nullopt if no such class exists.
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<const CodeGenRegisterClass *>
|
2019-08-27 17:47:06 +00:00
|
|
|
inferSuperRegisterClass(const TypeSetByHwMode &Ty,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &SubRegIdxNode);
|
2019-08-27 17:47:06 +00:00
|
|
|
|
|
|
|
/// Return the CodeGenRegisterClass associated with \p Leaf if it has one.
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<const CodeGenRegisterClass *>
|
2024-02-09 13:35:42 +00:00
|
|
|
getRegClassFromLeaf(const TreePatternNode &Leaf);
|
2019-08-27 17:47:06 +00:00
|
|
|
|
2022-12-04 17:31:16 -08:00
|
|
|
/// Return a CodeGenRegisterClass for \p N if one can be found. Return
|
|
|
|
/// std::nullopt otherwise.
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<const CodeGenRegisterClass *>
|
2024-02-09 13:35:42 +00:00
|
|
|
inferRegClassFromPattern(const TreePatternNode &N);
|
2019-08-27 17:47:06 +00:00
|
|
|
|
2024-11-07 07:16:54 +03:00
|
|
|
Error constrainOperands(action_iterator InsertPt, RuleMatcher &M,
|
|
|
|
unsigned InsnID, const TreePatternNode &Dst);
|
|
|
|
|
2021-01-24 00:35:15 -08:00
|
|
|
/// Return the size of the MemoryVT in this predicate, if possible.
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<unsigned>
|
2021-01-24 00:35:15 -08:00
|
|
|
getMemSizeBitsFromPredicate(const TreePredicateFn &Predicate);
|
|
|
|
|
2020-07-02 09:08:06 +00:00
|
|
|
// Add builtin predicates.
|
|
|
|
Expected<InstructionMatcher &>
|
|
|
|
addBuiltinPredicates(const Record *SrcGIEquivOrNull,
|
|
|
|
const TreePredicateFn &Predicate,
|
|
|
|
InstructionMatcher &InsnMatcher, bool &HasAddedMatcher);
|
2018-05-21 22:21:24 +00:00
|
|
|
};
|
[GlobalISel] Improving InstructionSelect's performance by reducing MatchTable, mostly NFC, perf patch 1
This patch starts a series of patches that decrease time spent by
GlobalISel in its InstructionSelect pass by roughly 60% for -O0 builds
for large inputs as measured on sqlite3-amalgamation
(http://sqlite.org/download.html) targeting AArch64.
The performance improvements are achieved solely by reducing the
number of matching GIM_* opcodes executed by the MatchTable's
interpreter during the selection by approx. a factor of 30, which also
brings contribution of this particular part of the selection process
to the overall runtime of InstructionSelect pass down from approx.
60-70% to 5-7%, thus making further improvements in this particular
direction not very profitable.
The improvements described above are expected for any target that
doesn't have many complex patterns. The targets that do should
strictly benefit from the changes, but by how much exactly is hard to
estimate beforehand. It's also likely that such target WILL benefit
from further improvements to MatchTable, most likely the ones that
bring it closer to a perfect decision tree.
This commit specifically is rather large mostly NFC commit that does
necessary preparation work and refactoring, there will be a following
series of small patches introducing a specific optimization each
shortly after.
This commit specifically is expected to cause a small compile time
regression (around 2.5% of InstructionSelect pass time), which should
be fixed by the next commit of the series.
Every commit planned shares the same Phabricator Review.
Reviewers: qcolombet, dsanders, bogner, aemerson, javed.absar
Reviewed By: qcolombet
Subscribers: rovka, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D44700
llvm-svn: 332907
2018-05-21 22:04:39 +00:00
|
|
|
|
2024-09-30 06:37:36 -07:00
|
|
|
StringRef getPatFragPredicateEnumName(const Record *R) { return R->getName(); }
|
2023-06-26 11:44:18 +02:00
|
|
|
|
2018-05-21 23:28:51 +00:00
|
|
|
void GlobalISelEmitter::gatherOpcodeValues() {
|
|
|
|
InstructionOpcodeMatcher::initOpcodeValuesMap(Target);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalISelEmitter::gatherTypeIDValues() {
|
|
|
|
LLTOperandMatcher::initTypeIDValuesMap();
|
|
|
|
}
|
|
|
|
|
2016-12-21 23:26:20 +00:00
|
|
|
void GlobalISelEmitter::gatherNodeEquivs() {
|
|
|
|
assert(NodeEquivs.empty());
|
2024-09-30 06:37:36 -07:00
|
|
|
for (const Record *Equiv : RK.getAllDerivedDefinitions("GINodeEquiv"))
|
[globalisel][tablegen] Map ld and st to G_LOAD and G_STORE. NFC
Summary:
There is an important mismatch between ISD::LOAD and G_LOAD (and likewise for
ISD::STORE and G_STORE). In SelectionDAG, ISD::LOAD is a non-atomic load
and atomic loads are handled by a separate node. However, this is not true of
GlobalISel's G_LOAD. For G_LOAD, the MachineMemOperand indicates the atomicity
of the operation. As a result, this mapping must also add a predicate that
checks for non-atomic MachineMemOperands.
This is NFC since these nodes always have predicates in practice and are
therefore always rejected at the moment.
Depends on D37443
Reviewers: ab, qcolombet, t.p.northover, rovka, aditya_nandakumar
Reviewed By: qcolombet
Subscribers: kristof.beyls, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D37445
llvm-svn: 315843
2017-10-15 02:41:12 +00:00
|
|
|
NodeEquivs[Equiv->getValueAsDef("Node")] = Equiv;
|
2017-03-14 21:32:08 +00:00
|
|
|
|
|
|
|
assert(ComplexPatternEquivs.empty());
|
2024-09-30 06:37:36 -07:00
|
|
|
for (const Record *Equiv :
|
|
|
|
RK.getAllDerivedDefinitions("GIComplexPatternEquiv")) {
|
|
|
|
const Record *SelDAGEquiv = Equiv->getValueAsDef("SelDAGEquivalent");
|
2017-03-14 21:32:08 +00:00
|
|
|
if (!SelDAGEquiv)
|
|
|
|
continue;
|
|
|
|
ComplexPatternEquivs[SelDAGEquiv] = Equiv;
|
2023-06-23 11:42:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
assert(SDNodeXFormEquivs.empty());
|
2024-09-30 06:37:36 -07:00
|
|
|
for (const Record *Equiv :
|
|
|
|
RK.getAllDerivedDefinitions("GISDNodeXFormEquiv")) {
|
|
|
|
const Record *SelDAGEquiv = Equiv->getValueAsDef("SelDAGEquivalent");
|
2023-06-23 11:42:51 +02:00
|
|
|
if (!SelDAGEquiv)
|
|
|
|
continue;
|
|
|
|
SDNodeXFormEquivs[SelDAGEquiv] = Equiv;
|
|
|
|
}
|
2016-12-21 23:26:20 +00:00
|
|
|
}
|
|
|
|
|
2024-09-30 06:37:36 -07:00
|
|
|
const Record *GlobalISelEmitter::findNodeEquiv(const Record *N) const {
|
2016-12-21 23:26:20 +00:00
|
|
|
return NodeEquivs.lookup(N);
|
|
|
|
}
|
|
|
|
|
[globalisel] Update GlobalISel emitter to match new representation of extending loads
Summary:
Previously, a extending load was represented at (G_*EXT (G_LOAD x)).
This had a few drawbacks:
* G_LOAD had to be legal for all sizes you could extend from, even if
registers didn't naturally hold those sizes.
* All sizes you could extend from had to be allocatable just in case the
extend went missing (e.g. by optimization).
* At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we
improve optimization of extends and truncates, this legality requirement
would spread without considerable care w.r.t when certain combines were
permitted.
* The SelectionDAG importer required some ugly and fragile pattern
rewriting to translate patterns into this style.
This patch changes the representation to:
* (G_[SZ]EXTLOAD x)
* (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits()
which resolves these issues by allowing targets to work entirely in their
native register sizes, and by having a more direct translation from
SelectionDAG patterns.
Each extending load can be lowered by the legalizer into separate extends
and loads, however a target that supports s1 will need the any-extending
load to extend to at least s8 since LLVM does not represent memory accesses
smaller than 8 bit. The legalizer can widenScalar G_LOAD into an
any-extending load but sign/zero-extending loads need help from something
else like a combiner pass. A follow-up patch that adds combiner helpers for
for this will follow.
The new representation requires that the MMO correctly reflect the memory
access so this has been corrected in a couple tests. I've also moved the
extending loads to their own tests since they are (mostly) separate opcodes
now. Additionally, the re-write appears to have invalidated two tests from
select-with-no-legality-check.mir since the matcher table no longer contains
loads that result in s1's and they aren't legal in AArch64 anymore.
Depends on D45540
Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, javed.absar
Reviewed By: rtereshin
Subscribers: javed.absar, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D45541
llvm-svn: 331601
2018-05-05 20:53:24 +00:00
|
|
|
const CodeGenInstruction *
|
2024-09-30 06:37:36 -07:00
|
|
|
GlobalISelEmitter::getEquivNode(const Record &Equiv,
|
|
|
|
const TreePatternNode &N) const {
|
2024-02-09 13:35:42 +00:00
|
|
|
if (N.getNumChildren() >= 1) {
|
2019-08-29 01:13:41 +00:00
|
|
|
// setcc operation maps to two different G_* instructions based on the type.
|
|
|
|
if (!Equiv.isValueUnset("IfFloatingPoint") &&
|
2024-02-09 13:35:42 +00:00
|
|
|
MVT(N.getChild(0).getSimpleType(0)).isFloatingPoint())
|
2019-08-29 01:13:41 +00:00
|
|
|
return &Target.getInstruction(Equiv.getValueAsDef("IfFloatingPoint"));
|
|
|
|
}
|
|
|
|
|
2023-07-31 12:14:34 +05:30
|
|
|
if (!Equiv.isValueUnset("IfConvergent") &&
|
2024-02-09 13:35:42 +00:00
|
|
|
N.getIntrinsicInfo(CGP)->isConvergent)
|
2023-07-31 12:14:34 +05:30
|
|
|
return &Target.getInstruction(Equiv.getValueAsDef("IfConvergent"));
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
for (const TreePredicateCall &Call : N.getPredicateCalls()) {
|
TableGen/ISel: Allow PatFrag predicate code to access captured operands
Summary:
This simplifies writing predicates for pattern fragments that are
automatically re-associated or commuted.
For example, a followup patch adds patterns for fragments of the form
(add (shl $x, $y), $z) to the AMDGPU backend. Such patterns are
automatically commuted to (add $z, (shl $x, $y)), which makes it basically
impossible to refer to $x, $y, and $z generically in the PredicateCode.
With this change, the PredicateCode can refer to $x, $y, and $z simply
as `Operands[i]`.
Test confirmed that there are no changes to any of the generated files
when building all (non-experimental) targets.
Change-Id: I61c00ace7eed42c1d4edc4c5351174b56b77a79c
Reviewers: arsenm, rampitec, RKSimon, craig.topper, hfinkel, uweigand
Subscribers: wdng, tpr, llvm-commits
Differential Revision: https://reviews.llvm.org/D51994
llvm-svn: 347992
2018-11-30 14:15:13 +00:00
|
|
|
const TreePredicateFn &Predicate = Call.Fn;
|
2022-04-09 14:06:04 -04:00
|
|
|
if (!Equiv.isValueUnset("IfSignExtend") &&
|
|
|
|
(Predicate.isLoad() || Predicate.isAtomic()) &&
|
[globalisel] Update GlobalISel emitter to match new representation of extending loads
Summary:
Previously, a extending load was represented at (G_*EXT (G_LOAD x)).
This had a few drawbacks:
* G_LOAD had to be legal for all sizes you could extend from, even if
registers didn't naturally hold those sizes.
* All sizes you could extend from had to be allocatable just in case the
extend went missing (e.g. by optimization).
* At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we
improve optimization of extends and truncates, this legality requirement
would spread without considerable care w.r.t when certain combines were
permitted.
* The SelectionDAG importer required some ugly and fragile pattern
rewriting to translate patterns into this style.
This patch changes the representation to:
* (G_[SZ]EXTLOAD x)
* (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits()
which resolves these issues by allowing targets to work entirely in their
native register sizes, and by having a more direct translation from
SelectionDAG patterns.
Each extending load can be lowered by the legalizer into separate extends
and loads, however a target that supports s1 will need the any-extending
load to extend to at least s8 since LLVM does not represent memory accesses
smaller than 8 bit. The legalizer can widenScalar G_LOAD into an
any-extending load but sign/zero-extending loads need help from something
else like a combiner pass. A follow-up patch that adds combiner helpers for
for this will follow.
The new representation requires that the MMO correctly reflect the memory
access so this has been corrected in a couple tests. I've also moved the
extending loads to their own tests since they are (mostly) separate opcodes
now. Additionally, the re-write appears to have invalidated two tests from
select-with-no-legality-check.mir since the matcher table no longer contains
loads that result in s1's and they aren't legal in AArch64 anymore.
Depends on D45540
Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, javed.absar
Reviewed By: rtereshin
Subscribers: javed.absar, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D45541
llvm-svn: 331601
2018-05-05 20:53:24 +00:00
|
|
|
Predicate.isSignExtLoad())
|
|
|
|
return &Target.getInstruction(Equiv.getValueAsDef("IfSignExtend"));
|
2022-04-09 14:06:04 -04:00
|
|
|
if (!Equiv.isValueUnset("IfZeroExtend") &&
|
|
|
|
(Predicate.isLoad() || Predicate.isAtomic()) &&
|
[globalisel] Update GlobalISel emitter to match new representation of extending loads
Summary:
Previously, a extending load was represented at (G_*EXT (G_LOAD x)).
This had a few drawbacks:
* G_LOAD had to be legal for all sizes you could extend from, even if
registers didn't naturally hold those sizes.
* All sizes you could extend from had to be allocatable just in case the
extend went missing (e.g. by optimization).
* At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we
improve optimization of extends and truncates, this legality requirement
would spread without considerable care w.r.t when certain combines were
permitted.
* The SelectionDAG importer required some ugly and fragile pattern
rewriting to translate patterns into this style.
This patch changes the representation to:
* (G_[SZ]EXTLOAD x)
* (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits()
which resolves these issues by allowing targets to work entirely in their
native register sizes, and by having a more direct translation from
SelectionDAG patterns.
Each extending load can be lowered by the legalizer into separate extends
and loads, however a target that supports s1 will need the any-extending
load to extend to at least s8 since LLVM does not represent memory accesses
smaller than 8 bit. The legalizer can widenScalar G_LOAD into an
any-extending load but sign/zero-extending loads need help from something
else like a combiner pass. A follow-up patch that adds combiner helpers for
for this will follow.
The new representation requires that the MMO correctly reflect the memory
access so this has been corrected in a couple tests. I've also moved the
extending loads to their own tests since they are (mostly) separate opcodes
now. Additionally, the re-write appears to have invalidated two tests from
select-with-no-legality-check.mir since the matcher table no longer contains
loads that result in s1's and they aren't legal in AArch64 anymore.
Depends on D45540
Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, javed.absar
Reviewed By: rtereshin
Subscribers: javed.absar, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D45541
llvm-svn: 331601
2018-05-05 20:53:24 +00:00
|
|
|
Predicate.isZeroExtLoad())
|
|
|
|
return &Target.getInstruction(Equiv.getValueAsDef("IfZeroExtend"));
|
|
|
|
}
|
2019-08-29 01:13:41 +00:00
|
|
|
|
[globalisel] Update GlobalISel emitter to match new representation of extending loads
Summary:
Previously, a extending load was represented at (G_*EXT (G_LOAD x)).
This had a few drawbacks:
* G_LOAD had to be legal for all sizes you could extend from, even if
registers didn't naturally hold those sizes.
* All sizes you could extend from had to be allocatable just in case the
extend went missing (e.g. by optimization).
* At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we
improve optimization of extends and truncates, this legality requirement
would spread without considerable care w.r.t when certain combines were
permitted.
* The SelectionDAG importer required some ugly and fragile pattern
rewriting to translate patterns into this style.
This patch changes the representation to:
* (G_[SZ]EXTLOAD x)
* (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits()
which resolves these issues by allowing targets to work entirely in their
native register sizes, and by having a more direct translation from
SelectionDAG patterns.
Each extending load can be lowered by the legalizer into separate extends
and loads, however a target that supports s1 will need the any-extending
load to extend to at least s8 since LLVM does not represent memory accesses
smaller than 8 bit. The legalizer can widenScalar G_LOAD into an
any-extending load but sign/zero-extending loads need help from something
else like a combiner pass. A follow-up patch that adds combiner helpers for
for this will follow.
The new representation requires that the MMO correctly reflect the memory
access so this has been corrected in a couple tests. I've also moved the
extending loads to their own tests since they are (mostly) separate opcodes
now. Additionally, the re-write appears to have invalidated two tests from
select-with-no-legality-check.mir since the matcher table no longer contains
loads that result in s1's and they aren't legal in AArch64 anymore.
Depends on D45540
Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, javed.absar
Reviewed By: rtereshin
Subscribers: javed.absar, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D45541
llvm-svn: 331601
2018-05-05 20:53:24 +00:00
|
|
|
return &Target.getInstruction(Equiv.getValueAsDef("I"));
|
|
|
|
}
|
|
|
|
|
2024-09-30 06:37:36 -07:00
|
|
|
GlobalISelEmitter::GlobalISelEmitter(const RecordKeeper &RK)
|
2023-06-26 11:44:18 +02:00
|
|
|
: GlobalISelMatchTableExecutorEmitter(), RK(RK), CGP(RK),
|
|
|
|
Target(CGP.getTargetInfo()), CGRegs(Target.getRegBank()) {
|
|
|
|
ClassName = Target.getName().str() + "InstructionSelector";
|
|
|
|
}
|
2016-12-21 23:26:20 +00:00
|
|
|
|
|
|
|
//===- Emitter ------------------------------------------------------------===//
|
|
|
|
|
2024-09-23 13:07:31 -07:00
|
|
|
Error GlobalISelEmitter::importRulePredicates(
|
|
|
|
RuleMatcher &M, ArrayRef<const Record *> Predicates) {
|
|
|
|
for (const Record *Pred : Predicates) {
|
2021-04-28 11:13:10 -07:00
|
|
|
if (Pred->getValueAsString("CondString").empty())
|
2017-09-14 16:56:21 +00:00
|
|
|
continue;
|
2021-04-28 11:13:10 -07:00
|
|
|
declareSubtargetFeature(Pred);
|
|
|
|
M.addRequiredFeature(Pred);
|
[globalisel][tablegen] Import SelectionDAG's rule predicates and support the equivalent in GIRule.
Summary:
The SelectionDAG importer now imports rules with Predicate's attached via
Requires, PredicateControl, etc. These predicates are implemented as
bitset's to allow multiple predicates to be tested together. However,
unlike the MC layer subtarget features, each target only pays for it's own
predicates (e.g. AArch64 doesn't have 192 feature bits just because X86
needs a lot).
Both AArch64 and X86 derive at least one predicate from the MachineFunction
or Function so they must re-initialize AvailableFeatures before each
function. They also declare locals in <Target>InstructionSelector so that
computeAvailableFeatures() can use the code from SelectionDAG without
modification.
Reviewers: rovka, qcolombet, aditya_nandakumar, t.p.northover, ab
Reviewed By: rovka
Subscribers: aemerson, rengolin, dberris, kristof.beyls, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D31418
llvm-svn: 300993
2017-04-21 15:59:56 +00:00
|
|
|
}
|
|
|
|
|
2017-03-30 09:36:33 +00:00
|
|
|
return Error::success();
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
2016-12-21 23:26:20 +00:00
|
|
|
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<unsigned> GlobalISelEmitter::getMemSizeBitsFromPredicate(
|
|
|
|
const TreePredicateFn &Predicate) {
|
|
|
|
std::optional<LLTCodeGen> MemTyOrNone =
|
2021-01-24 00:35:15 -08:00
|
|
|
MVTToLLT(getValueType(Predicate.getMemoryVT()));
|
|
|
|
|
|
|
|
if (!MemTyOrNone)
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2021-01-24 00:35:15 -08:00
|
|
|
|
|
|
|
// Align so unusual types like i1 don't get rounded down.
|
2021-06-27 16:07:19 +01:00
|
|
|
return llvm::alignTo(
|
|
|
|
static_cast<unsigned>(MemTyOrNone->get().getSizeInBits()), 8);
|
2021-01-24 00:35:15 -08:00
|
|
|
}
|
|
|
|
|
2020-07-02 09:08:06 +00:00
|
|
|
Expected<InstructionMatcher &> GlobalISelEmitter::addBuiltinPredicates(
|
|
|
|
const Record *SrcGIEquivOrNull, const TreePredicateFn &Predicate,
|
|
|
|
InstructionMatcher &InsnMatcher, bool &HasAddedMatcher) {
|
|
|
|
if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) {
|
|
|
|
if (const ListInit *AddrSpaces = Predicate.getAddressSpaces()) {
|
|
|
|
SmallVector<unsigned, 4> ParsedAddrSpaces;
|
|
|
|
|
2024-10-18 07:50:22 -07:00
|
|
|
for (const Init *Val : AddrSpaces->getValues()) {
|
|
|
|
const IntInit *IntVal = dyn_cast<IntInit>(Val);
|
2020-07-02 09:08:06 +00:00
|
|
|
if (!IntVal)
|
|
|
|
return failedImport("Address space is not an integer");
|
|
|
|
ParsedAddrSpaces.push_back(IntVal->getValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ParsedAddrSpaces.empty()) {
|
|
|
|
InsnMatcher.addPredicate<MemoryAddressSpacePredicateMatcher>(
|
|
|
|
0, ParsedAddrSpaces);
|
2022-04-05 10:36:57 -04:00
|
|
|
return InsnMatcher;
|
2020-07-02 09:08:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t MinAlign = Predicate.getMinAlignment();
|
2022-04-05 10:36:57 -04:00
|
|
|
if (MinAlign > 0) {
|
2020-07-02 09:08:06 +00:00
|
|
|
InsnMatcher.addPredicate<MemoryAlignmentPredicateMatcher>(0, MinAlign);
|
2022-04-05 10:36:57 -04:00
|
|
|
return InsnMatcher;
|
|
|
|
}
|
2020-07-02 09:08:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// G_LOAD is used for both non-extending and any-extending loads.
|
|
|
|
if (Predicate.isLoad() && Predicate.isNonExtLoad()) {
|
|
|
|
InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
|
|
|
|
0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0);
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
if (Predicate.isLoad() && Predicate.isAnyExtLoad()) {
|
|
|
|
InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
|
|
|
|
0, MemoryVsLLTSizePredicateMatcher::LessThan, 0);
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Predicate.isStore()) {
|
|
|
|
if (Predicate.isTruncStore()) {
|
2021-01-24 00:35:15 -08:00
|
|
|
if (Predicate.getMemoryVT() != nullptr) {
|
|
|
|
// FIXME: If MemoryVT is set, we end up with 2 checks for the MMO size.
|
|
|
|
auto MemSizeInBits = getMemSizeBitsFromPredicate(Predicate);
|
|
|
|
if (!MemSizeInBits)
|
|
|
|
return failedImport("MemVT could not be converted to LLT");
|
|
|
|
|
|
|
|
InsnMatcher.addPredicate<MemorySizePredicateMatcher>(0, *MemSizeInBits /
|
|
|
|
8);
|
|
|
|
} else {
|
|
|
|
InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
|
|
|
|
0, MemoryVsLLTSizePredicateMatcher::LessThan, 0);
|
|
|
|
}
|
2020-07-02 09:08:06 +00:00
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
if (Predicate.isNonTruncStore()) {
|
|
|
|
// We need to check the sizes match here otherwise we could incorrectly
|
|
|
|
// match truncating stores with non-truncating ones.
|
|
|
|
InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
|
|
|
|
0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 21:17:51 +08:00
|
|
|
assert(SrcGIEquivOrNull != nullptr && "Invalid SrcGIEquivOrNull value");
|
2020-07-02 09:08:06 +00:00
|
|
|
// No check required. We already did it by swapping the opcode.
|
|
|
|
if (!SrcGIEquivOrNull->isValueUnset("IfSignExtend") &&
|
|
|
|
Predicate.isSignExtLoad())
|
|
|
|
return InsnMatcher;
|
|
|
|
|
|
|
|
// No check required. We already did it by swapping the opcode.
|
|
|
|
if (!SrcGIEquivOrNull->isValueUnset("IfZeroExtend") &&
|
|
|
|
Predicate.isZeroExtLoad())
|
|
|
|
return InsnMatcher;
|
|
|
|
|
|
|
|
// No check required. G_STORE by itself is a non-extending store.
|
|
|
|
if (Predicate.isNonTruncStore())
|
|
|
|
return InsnMatcher;
|
|
|
|
|
|
|
|
if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) {
|
|
|
|
if (Predicate.getMemoryVT() != nullptr) {
|
2021-01-24 00:35:15 -08:00
|
|
|
auto MemSizeInBits = getMemSizeBitsFromPredicate(Predicate);
|
|
|
|
if (!MemSizeInBits)
|
2020-07-02 09:08:06 +00:00
|
|
|
return failedImport("MemVT could not be converted to LLT");
|
|
|
|
|
|
|
|
InsnMatcher.addPredicate<MemorySizePredicateMatcher>(0,
|
2021-01-24 00:35:15 -08:00
|
|
|
*MemSizeInBits / 8);
|
2020-07-02 09:08:06 +00:00
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Predicate.isLoad() || Predicate.isStore()) {
|
|
|
|
// No check required. A G_LOAD/G_STORE is an unindexed load.
|
|
|
|
if (Predicate.isUnindexed())
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Predicate.isAtomic()) {
|
|
|
|
if (Predicate.isAtomicOrderingMonotonic()) {
|
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Monotonic");
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
if (Predicate.isAtomicOrderingAcquire()) {
|
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Acquire");
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
if (Predicate.isAtomicOrderingRelease()) {
|
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Release");
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
if (Predicate.isAtomicOrderingAcquireRelease()) {
|
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
|
|
|
|
"AcquireRelease");
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
if (Predicate.isAtomicOrderingSequentiallyConsistent()) {
|
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
|
|
|
|
"SequentiallyConsistent");
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Predicate.isAtomicOrderingAcquireOrStronger()) {
|
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
|
|
|
|
"Acquire", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
if (Predicate.isAtomicOrderingWeakerThanAcquire()) {
|
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
|
|
|
|
"Acquire", AtomicOrderingMMOPredicateMatcher::AO_WeakerThan);
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Predicate.isAtomicOrderingReleaseOrStronger()) {
|
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
|
|
|
|
"Release", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
if (Predicate.isAtomicOrderingWeakerThanRelease()) {
|
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
|
|
|
|
"Release", AtomicOrderingMMOPredicateMatcher::AO_WeakerThan);
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
HasAddedMatcher = false;
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
|
2017-12-05 05:52:07 +00:00
|
|
|
Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
|
|
|
|
RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &Src, unsigned &TempOpIdx) {
|
|
|
|
const auto SavedFlags = Rule.setGISelFlags(Src.getGISelFlagsRecord());
|
2023-01-25 14:06:09 +01:00
|
|
|
|
2024-09-30 06:37:36 -07:00
|
|
|
const Record *SrcGIEquivOrNull = nullptr;
|
2017-12-05 05:52:07 +00:00
|
|
|
const CodeGenInstruction *SrcGIOrNull = nullptr;
|
|
|
|
|
|
|
|
// Start with the defined operands (i.e., the results of the root operator).
|
2024-02-09 13:35:42 +00:00
|
|
|
if (Src.isLeaf()) {
|
2024-09-23 13:07:31 -07:00
|
|
|
const Init *SrcInit = Src.getLeafValue();
|
2017-12-05 05:52:07 +00:00
|
|
|
if (isa<IntInit>(SrcInit)) {
|
|
|
|
InsnMatcher.addPredicate<InstructionOpcodeMatcher>(
|
|
|
|
&Target.getInstruction(RK.getDef("G_CONSTANT")));
|
|
|
|
} else
|
|
|
|
return failedImport(
|
|
|
|
"Unable to deduce gMIR opcode to handle Src (which is a leaf)");
|
|
|
|
} else {
|
2024-02-09 13:35:42 +00:00
|
|
|
SrcGIEquivOrNull = findNodeEquiv(Src.getOperator());
|
2017-12-05 05:52:07 +00:00
|
|
|
if (!SrcGIEquivOrNull)
|
|
|
|
return failedImport("Pattern operator lacks an equivalent Instruction" +
|
2024-02-09 13:35:42 +00:00
|
|
|
explainOperator(Src.getOperator()));
|
[globalisel] Update GlobalISel emitter to match new representation of extending loads
Summary:
Previously, a extending load was represented at (G_*EXT (G_LOAD x)).
This had a few drawbacks:
* G_LOAD had to be legal for all sizes you could extend from, even if
registers didn't naturally hold those sizes.
* All sizes you could extend from had to be allocatable just in case the
extend went missing (e.g. by optimization).
* At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we
improve optimization of extends and truncates, this legality requirement
would spread without considerable care w.r.t when certain combines were
permitted.
* The SelectionDAG importer required some ugly and fragile pattern
rewriting to translate patterns into this style.
This patch changes the representation to:
* (G_[SZ]EXTLOAD x)
* (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits()
which resolves these issues by allowing targets to work entirely in their
native register sizes, and by having a more direct translation from
SelectionDAG patterns.
Each extending load can be lowered by the legalizer into separate extends
and loads, however a target that supports s1 will need the any-extending
load to extend to at least s8 since LLVM does not represent memory accesses
smaller than 8 bit. The legalizer can widenScalar G_LOAD into an
any-extending load but sign/zero-extending loads need help from something
else like a combiner pass. A follow-up patch that adds combiner helpers for
for this will follow.
The new representation requires that the MMO correctly reflect the memory
access so this has been corrected in a couple tests. I've also moved the
extending loads to their own tests since they are (mostly) separate opcodes
now. Additionally, the re-write appears to have invalidated two tests from
select-with-no-legality-check.mir since the matcher table no longer contains
loads that result in s1's and they aren't legal in AArch64 anymore.
Depends on D45540
Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, javed.absar
Reviewed By: rtereshin
Subscribers: javed.absar, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D45541
llvm-svn: 331601
2018-05-05 20:53:24 +00:00
|
|
|
SrcGIOrNull = getEquivNode(*SrcGIEquivOrNull, Src);
|
2017-12-05 05:52:07 +00:00
|
|
|
|
|
|
|
// The operators look good: match the opcode
|
|
|
|
InsnMatcher.addPredicate<InstructionOpcodeMatcher>(SrcGIOrNull);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned OpIdx = 0;
|
2024-02-09 13:35:42 +00:00
|
|
|
for (const TypeSetByHwMode &VTy : Src.getExtTypes()) {
|
2017-12-05 05:52:07 +00:00
|
|
|
// Results don't have a name unless they are the root node. The caller will
|
|
|
|
// set the name if appropriate.
|
2022-08-24 12:13:04 +00:00
|
|
|
const bool OperandIsAPointer =
|
|
|
|
SrcGIOrNull && SrcGIOrNull->isOutOperandAPointer(OpIdx);
|
2017-12-05 05:52:07 +00:00
|
|
|
OperandMatcher &OM = InsnMatcher.addOperand(OpIdx++, "", TempOpIdx);
|
2022-08-24 12:13:04 +00:00
|
|
|
if (auto Error = OM.addTypeCheckPredicate(VTy, OperandIsAPointer))
|
2017-12-05 05:52:07 +00:00
|
|
|
return failedImport(toString(std::move(Error)) +
|
|
|
|
" for result of Src pattern operator");
|
|
|
|
}
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
for (const TreePredicateCall &Call : Src.getPredicateCalls()) {
|
TableGen/ISel: Allow PatFrag predicate code to access captured operands
Summary:
This simplifies writing predicates for pattern fragments that are
automatically re-associated or commuted.
For example, a followup patch adds patterns for fragments of the form
(add (shl $x, $y), $z) to the AMDGPU backend. Such patterns are
automatically commuted to (add $z, (shl $x, $y)), which makes it basically
impossible to refer to $x, $y, and $z generically in the PredicateCode.
With this change, the PredicateCode can refer to $x, $y, and $z simply
as `Operands[i]`.
Test confirmed that there are no changes to any of the generated files
when building all (non-experimental) targets.
Change-Id: I61c00ace7eed42c1d4edc4c5351174b56b77a79c
Reviewers: arsenm, rampitec, RKSimon, craig.topper, hfinkel, uweigand
Subscribers: wdng, tpr, llvm-commits
Differential Revision: https://reviews.llvm.org/D51994
llvm-svn: 347992
2018-11-30 14:15:13 +00:00
|
|
|
const TreePredicateFn &Predicate = Call.Fn;
|
2020-07-02 09:08:06 +00:00
|
|
|
bool HasAddedBuiltinMatcher = true;
|
2017-08-24 09:11:20 +00:00
|
|
|
if (Predicate.isAlwaysTrue())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (Predicate.isImmediatePattern()) {
|
|
|
|
InsnMatcher.addPredicate<InstructionImmPredicateMatcher>(Predicate);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-07-02 09:08:06 +00:00
|
|
|
auto InsnMatcherOrError = addBuiltinPredicates(
|
|
|
|
SrcGIEquivOrNull, Predicate, InsnMatcher, HasAddedBuiltinMatcher);
|
|
|
|
if (auto Error = InsnMatcherOrError.takeError())
|
|
|
|
return std::move(Error);
|
2017-10-23 18:19:24 +00:00
|
|
|
|
2022-05-08 21:24:52 +05:30
|
|
|
// FIXME: This should be part of addBuiltinPredicates(). If we add this at
|
|
|
|
// the start of addBuiltinPredicates() without returning, then there might
|
|
|
|
// be cases where we hit the last return before which the
|
|
|
|
// HasAddedBuiltinMatcher will be set to false. The predicate could be
|
|
|
|
// missed if we add it in the middle or at the end due to return statements
|
|
|
|
// after the addPredicate<>() calls.
|
|
|
|
if (Predicate.hasNoUse()) {
|
|
|
|
InsnMatcher.addPredicate<NoUsePredicateMatcher>();
|
|
|
|
HasAddedBuiltinMatcher = true;
|
|
|
|
}
|
2024-05-20 06:18:49 -08:00
|
|
|
if (Predicate.hasOneUse()) {
|
|
|
|
InsnMatcher.addPredicate<OneUsePredicateMatcher>();
|
|
|
|
HasAddedBuiltinMatcher = true;
|
|
|
|
}
|
2022-05-08 21:24:52 +05:30
|
|
|
|
2018-06-15 23:13:43 +00:00
|
|
|
if (Predicate.hasGISelPredicateCode()) {
|
2020-09-14 10:39:25 +02:00
|
|
|
if (Predicate.usesOperands()) {
|
|
|
|
assert(WaitingForNamedOperands == 0 &&
|
|
|
|
"previous predicate didn't find all operands or "
|
|
|
|
"nested predicate that uses operands");
|
|
|
|
TreePattern *TP = Predicate.getOrigPatFragRecord();
|
|
|
|
WaitingForNamedOperands = TP->getNumArgs();
|
2024-04-29 14:47:46 -04:00
|
|
|
for (unsigned I = 0; I < WaitingForNamedOperands; ++I)
|
|
|
|
StoreIdxForName[getScopedName(Call.Scope, TP->getArgName(I))] = I;
|
2020-09-14 10:39:25 +02:00
|
|
|
}
|
2018-06-15 23:13:43 +00:00
|
|
|
InsnMatcher.addPredicate<GenericInstructionPredicateMatcher>(Predicate);
|
|
|
|
continue;
|
|
|
|
}
|
2020-07-02 09:08:06 +00:00
|
|
|
if (!HasAddedBuiltinMatcher) {
|
|
|
|
return failedImport("Src pattern child has predicate (" +
|
|
|
|
explainPredicates(Src) + ")");
|
|
|
|
}
|
2017-08-24 09:11:20 +00:00
|
|
|
}
|
2020-08-02 17:23:52 -04:00
|
|
|
|
2023-06-23 11:42:51 +02:00
|
|
|
if (SrcGIEquivOrNull &&
|
|
|
|
SrcGIEquivOrNull->getValueAsBit("CheckMMOIsNonAtomic"))
|
2017-12-05 05:52:07 +00:00
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("NotAtomic");
|
2023-06-23 11:42:51 +02:00
|
|
|
else if (SrcGIEquivOrNull &&
|
|
|
|
SrcGIEquivOrNull->getValueAsBit("CheckMMOIsAtomic")) {
|
2019-09-09 16:18:07 +00:00
|
|
|
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
|
2023-06-23 11:42:51 +02:00
|
|
|
"Unordered", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
|
2019-09-09 16:18:07 +00:00
|
|
|
}
|
2017-08-24 09:11:20 +00:00
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
if (Src.isLeaf()) {
|
2024-09-23 13:07:31 -07:00
|
|
|
const Init *SrcInit = Src.getLeafValue();
|
|
|
|
if (const IntInit *SrcIntInit = dyn_cast<IntInit>(SrcInit)) {
|
2017-10-14 00:31:58 +00:00
|
|
|
OperandMatcher &OM =
|
2024-02-09 13:35:42 +00:00
|
|
|
InsnMatcher.addOperand(OpIdx++, Src.getName(), TempOpIdx);
|
2017-05-23 19:33:16 +00:00
|
|
|
OM.addPredicate<LiteralIntOperandMatcher>(SrcIntInit->getValue());
|
|
|
|
} else
|
2017-06-28 13:50:04 +00:00
|
|
|
return failedImport(
|
|
|
|
"Unable to deduce gMIR opcode to handle Src (which is a leaf)");
|
2017-05-23 19:33:16 +00:00
|
|
|
} else {
|
2017-07-06 08:12:20 +00:00
|
|
|
assert(SrcGIOrNull &&
|
|
|
|
"Expected to have already found an equivalent Instruction");
|
[globalisel][tablegen] Add support for fpimm and import of APInt/APFloat based ImmLeaf.
Summary:
There's only a tablegen testcase for IntImmLeaf and not a CodeGen one
because the relevant rules are rejected for other reasons at the moment.
On AArch64, it's because there's an SDNodeXForm attached to the operand.
On X86, it's because the rule either emits multiple instructions or has
another predicate using PatFrag which cannot easily be supported at the
same time.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Reviewed By: qcolombet
Subscribers: aemerson, javed.absar, igorb, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D36569
llvm-svn: 315761
2017-10-13 21:28:03 +00:00
|
|
|
if (SrcGIOrNull->TheDef->getName() == "G_CONSTANT" ||
|
|
|
|
SrcGIOrNull->TheDef->getName() == "G_FCONSTANT") {
|
|
|
|
// imm/fpimm still have operands but we don't need to do anything with it
|
2017-08-08 10:44:31 +00:00
|
|
|
// here since we don't support ImmLeaf predicates yet. However, we still
|
|
|
|
// need to note the hidden operand to get GIM_CheckNumOperands correct.
|
|
|
|
InsnMatcher.addOperand(OpIdx++, "", TempOpIdx);
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
|
2024-04-29 12:06:26 -04:00
|
|
|
if (SrcGIOrNull->TheDef->getName() == "G_FRAME_INDEX") {
|
|
|
|
InsnMatcher.addOperand(OpIdx++, Src.getName(), TempOpIdx);
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
|
2019-08-29 01:13:41 +00:00
|
|
|
// Special case because the operand order is changed from setcc. The
|
|
|
|
// predicate operand needs to be swapped from the last operand to the first
|
|
|
|
// source.
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
unsigned NumChildren = Src.getNumChildren();
|
2019-08-29 01:13:41 +00:00
|
|
|
bool IsFCmp = SrcGIOrNull->TheDef->getName() == "G_FCMP";
|
|
|
|
|
|
|
|
if (IsFCmp || SrcGIOrNull->TheDef->getName() == "G_ICMP") {
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &SrcChild = Src.getChild(NumChildren - 1);
|
|
|
|
if (SrcChild.isLeaf()) {
|
2024-09-23 13:07:31 -07:00
|
|
|
const DefInit *DI = dyn_cast<DefInit>(SrcChild.getLeafValue());
|
|
|
|
const Record *CCDef = DI ? DI->getDef() : nullptr;
|
2019-08-29 01:13:41 +00:00
|
|
|
if (!CCDef || !CCDef->isSubClassOf("CondCode"))
|
|
|
|
return failedImport("Unable to handle CondCode");
|
|
|
|
|
|
|
|
OperandMatcher &OM =
|
2024-02-09 13:35:42 +00:00
|
|
|
InsnMatcher.addOperand(OpIdx++, SrcChild.getName(), TempOpIdx);
|
2023-06-23 11:42:51 +02:00
|
|
|
StringRef PredType = IsFCmp ? CCDef->getValueAsString("FCmpPredicate")
|
|
|
|
: CCDef->getValueAsString("ICmpPredicate");
|
2019-08-29 01:13:41 +00:00
|
|
|
|
|
|
|
if (!PredType.empty()) {
|
2020-01-28 20:23:46 +01:00
|
|
|
OM.addPredicate<CmpPredicateOperandMatcher>(std::string(PredType));
|
2019-08-29 01:13:41 +00:00
|
|
|
// Process the other 2 operands normally.
|
|
|
|
--NumChildren;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-23 19:33:16 +00:00
|
|
|
// Match the used operands (i.e. the children of the operator).
|
2019-08-20 22:04:10 +00:00
|
|
|
bool IsIntrinsic =
|
|
|
|
SrcGIOrNull->TheDef->getName() == "G_INTRINSIC" ||
|
2023-07-31 12:14:34 +05:30
|
|
|
SrcGIOrNull->TheDef->getName() == "G_INTRINSIC_W_SIDE_EFFECTS" ||
|
|
|
|
SrcGIOrNull->TheDef->getName() == "G_INTRINSIC_CONVERGENT" ||
|
|
|
|
SrcGIOrNull->TheDef->getName() ==
|
|
|
|
"G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS";
|
2024-02-09 13:35:42 +00:00
|
|
|
const CodeGenIntrinsic *II = Src.getIntrinsicInfo(CGP);
|
2019-08-20 22:04:10 +00:00
|
|
|
if (IsIntrinsic && !II)
|
|
|
|
return failedImport("Expected IntInit containing intrinsic ID)");
|
|
|
|
|
2024-04-29 14:47:46 -04:00
|
|
|
for (unsigned I = 0; I != NumChildren; ++I) {
|
|
|
|
const TreePatternNode &SrcChild = Src.getChild(I);
|
2017-07-06 08:12:20 +00:00
|
|
|
|
2020-01-08 15:40:37 -05:00
|
|
|
// We need to determine the meaning of a literal integer based on the
|
|
|
|
// context. If this is a field required to be an immediate (such as an
|
|
|
|
// immarg intrinsic argument), the required predicates are different than
|
|
|
|
// a constant which may be materialized in a register. If we have an
|
|
|
|
// argument that is required to be an immediate, we should not emit an LLT
|
|
|
|
// type check, and should not be looking for a G_CONSTANT defined
|
|
|
|
// register.
|
2024-04-29 14:47:46 -04:00
|
|
|
bool OperandIsImmArg = SrcGIOrNull->isInOperandImmArg(I);
|
2020-01-08 15:40:37 -05:00
|
|
|
|
[globalisel][tablegen] Implement unindexed load, non-extending load, and MemVT checks
Summary:
This includes some context-sensitivity in the MVT to LLT conversion so that
pointer types are tested correctly.
FIXME: I'm not happy with the way this is done since everything is a
special-case. I've yet to find a reasonable way to implement it.
select-load.mir fails because <1 x s64> loads in tablegen get priority over s64
loads. This is fixed in the next patch and as such they should be committed
together, I've posted them separately to help with the review.
Depends on D37456
Reviewers: ab, qcolombet, t.p.northover, rovka, aditya_nandakumar
Subscribers: kristof.beyls, javed.absar, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D37457
llvm-svn: 315884
2017-10-16 00:56:30 +00:00
|
|
|
// SelectionDAG allows pointers to be represented with iN since it doesn't
|
2023-06-23 11:42:51 +02:00
|
|
|
// distinguish between pointers and integers but they are different types
|
|
|
|
// in GlobalISel. Coerce integers to pointers to address space 0 if the
|
|
|
|
// context indicates a pointer.
|
2020-01-08 15:40:37 -05:00
|
|
|
//
|
2024-04-29 14:47:46 -04:00
|
|
|
bool OperandIsAPointer = SrcGIOrNull->isInOperandAPointer(I);
|
[globalisel][tablegen] Implement unindexed load, non-extending load, and MemVT checks
Summary:
This includes some context-sensitivity in the MVT to LLT conversion so that
pointer types are tested correctly.
FIXME: I'm not happy with the way this is done since everything is a
special-case. I've yet to find a reasonable way to implement it.
select-load.mir fails because <1 x s64> loads in tablegen get priority over s64
loads. This is fixed in the next patch and as such they should be committed
together, I've posted them separately to help with the review.
Depends on D37456
Reviewers: ab, qcolombet, t.p.northover, rovka, aditya_nandakumar
Subscribers: kristof.beyls, javed.absar, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D37457
llvm-svn: 315884
2017-10-16 00:56:30 +00:00
|
|
|
|
2019-08-20 22:04:10 +00:00
|
|
|
if (IsIntrinsic) {
|
|
|
|
// For G_INTRINSIC/G_INTRINSIC_W_SIDE_EFFECTS, the operand immediately
|
|
|
|
// following the defs is an intrinsic ID.
|
2024-04-29 14:47:46 -04:00
|
|
|
if (I == 0) {
|
2017-07-06 08:12:20 +00:00
|
|
|
OperandMatcher &OM =
|
2024-02-09 13:35:42 +00:00
|
|
|
InsnMatcher.addOperand(OpIdx++, SrcChild.getName(), TempOpIdx);
|
2017-07-11 08:57:29 +00:00
|
|
|
OM.addPredicate<IntrinsicIDOperandMatcher>(II);
|
2017-07-06 08:12:20 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-01-08 15:40:37 -05:00
|
|
|
// We have to check intrinsics for llvm_anyptr_ty and immarg parameters.
|
2019-08-20 22:04:10 +00:00
|
|
|
//
|
|
|
|
// Note that we have to look at the i-1th parameter, because we don't
|
|
|
|
// have the intrinsic ID in the intrinsic's parameter list.
|
2024-04-29 14:47:46 -04:00
|
|
|
OperandIsAPointer |= II->isParamAPointer(I - 1);
|
|
|
|
OperandIsImmArg |= II->isParamImmArg(I - 1);
|
2017-07-06 08:12:20 +00:00
|
|
|
}
|
|
|
|
|
[globalisel][tablegen] Implement unindexed load, non-extending load, and MemVT checks
Summary:
This includes some context-sensitivity in the MVT to LLT conversion so that
pointer types are tested correctly.
FIXME: I'm not happy with the way this is done since everything is a
special-case. I've yet to find a reasonable way to implement it.
select-load.mir fails because <1 x s64> loads in tablegen get priority over s64
loads. This is fixed in the next patch and as such they should be committed
together, I've posted them separately to help with the review.
Depends on D37456
Reviewers: ab, qcolombet, t.p.northover, rovka, aditya_nandakumar
Subscribers: kristof.beyls, javed.absar, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D37457
llvm-svn: 315884
2017-10-16 00:56:30 +00:00
|
|
|
if (auto Error =
|
|
|
|
importChildMatcher(Rule, InsnMatcher, SrcChild, OperandIsAPointer,
|
2020-01-08 15:40:37 -05:00
|
|
|
OperandIsImmArg, OpIdx++, TempOpIdx))
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2017-05-23 19:33:16 +00:00
|
|
|
}
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return InsnMatcher;
|
|
|
|
}
|
|
|
|
|
2017-10-15 18:22:54 +00:00
|
|
|
Error GlobalISelEmitter::importComplexPatternOperandMatcher(
|
2024-09-11 08:52:26 -07:00
|
|
|
OperandMatcher &OM, const Record *R, unsigned &TempOpIdx) const {
|
2017-10-15 18:22:54 +00:00
|
|
|
const auto &ComplexPattern = ComplexPatternEquivs.find(R);
|
|
|
|
if (ComplexPattern == ComplexPatternEquivs.end())
|
|
|
|
return failedImport("SelectionDAG ComplexPattern (" + R->getName() +
|
|
|
|
") not mapped to GlobalISel");
|
|
|
|
|
|
|
|
OM.addPredicate<ComplexPatternOperandMatcher>(OM, *ComplexPattern->second);
|
|
|
|
TempOpIdx++;
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2019-09-06 20:32:37 +00:00
|
|
|
// Get the name to use for a pattern operand. For an anonymous physical register
|
|
|
|
// input, this should use the register name.
|
2024-02-09 13:35:42 +00:00
|
|
|
static StringRef getSrcChildName(const TreePatternNode &SrcChild,
|
2024-09-30 06:37:36 -07:00
|
|
|
const Record *&PhysReg) {
|
2024-02-09 13:35:42 +00:00
|
|
|
StringRef SrcChildName = SrcChild.getName();
|
|
|
|
if (SrcChildName.empty() && SrcChild.isLeaf()) {
|
|
|
|
if (auto *ChildDefInit = dyn_cast<DefInit>(SrcChild.getLeafValue())) {
|
2019-09-06 20:32:37 +00:00
|
|
|
auto *ChildRec = ChildDefInit->getDef();
|
|
|
|
if (ChildRec->isSubClassOf("Register")) {
|
|
|
|
SrcChildName = ChildRec->getName();
|
|
|
|
PhysReg = ChildRec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SrcChildName;
|
|
|
|
}
|
|
|
|
|
2020-01-08 15:40:37 -05:00
|
|
|
Error GlobalISelEmitter::importChildMatcher(
|
|
|
|
RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &SrcChild, bool OperandIsAPointer,
|
2020-01-08 15:40:37 -05:00
|
|
|
bool OperandIsImmArg, unsigned OpIdx, unsigned &TempOpIdx) {
|
2019-09-06 20:32:37 +00:00
|
|
|
|
2024-09-30 06:37:36 -07:00
|
|
|
const Record *PhysReg = nullptr;
|
2020-09-14 11:37:14 +02:00
|
|
|
std::string SrcChildName = std::string(getSrcChildName(SrcChild, PhysReg));
|
2024-02-09 13:35:42 +00:00
|
|
|
if (!SrcChild.isLeaf() &&
|
|
|
|
SrcChild.getOperator()->isSubClassOf("ComplexPattern")) {
|
2020-09-14 11:37:14 +02:00
|
|
|
// The "name" of a non-leaf complex pattern (MY_PAT $op1, $op2) is
|
|
|
|
// "MY_PAT:op1:op2" and the ones with same "name" represent same operand.
|
2024-02-09 13:35:42 +00:00
|
|
|
std::string PatternName = std::string(SrcChild.getOperator()->getName());
|
2024-04-29 14:47:46 -04:00
|
|
|
for (unsigned I = 0; I < SrcChild.getNumChildren(); ++I) {
|
2020-09-14 11:37:14 +02:00
|
|
|
PatternName += ":";
|
2024-04-29 14:47:46 -04:00
|
|
|
PatternName += SrcChild.getChild(I).getName();
|
2020-09-14 11:37:14 +02:00
|
|
|
}
|
|
|
|
SrcChildName = PatternName;
|
|
|
|
}
|
2019-09-06 20:32:37 +00:00
|
|
|
|
2020-01-28 20:23:46 +01:00
|
|
|
OperandMatcher &OM =
|
2020-09-14 11:37:14 +02:00
|
|
|
PhysReg ? InsnMatcher.addPhysRegInput(PhysReg, OpIdx, TempOpIdx)
|
|
|
|
: InsnMatcher.addOperand(OpIdx, SrcChildName, TempOpIdx);
|
2017-10-14 00:31:58 +00:00
|
|
|
if (OM.isSameAsAnotherOperand())
|
|
|
|
return Error::success();
|
2017-03-29 15:37:18 +00:00
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
ArrayRef<TypeSetByHwMode> ChildTypes = SrcChild.getExtTypes();
|
2017-03-29 15:37:18 +00:00
|
|
|
if (ChildTypes.size() != 1)
|
|
|
|
return failedImport("Src pattern child has multiple results");
|
|
|
|
|
|
|
|
// Check MBB's before the type check since they are not a known type.
|
2024-02-09 13:35:42 +00:00
|
|
|
if (!SrcChild.isLeaf()) {
|
|
|
|
if (SrcChild.getOperator()->isSubClassOf("SDNode")) {
|
|
|
|
auto &ChildSDNI = CGP.getSDNodeInfo(SrcChild.getOperator());
|
2017-03-29 15:37:18 +00:00
|
|
|
if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") {
|
|
|
|
OM.addPredicate<MBBOperandMatcher>();
|
2017-03-30 09:36:33 +00:00
|
|
|
return Error::success();
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
2024-02-09 13:35:42 +00:00
|
|
|
if (SrcChild.getOperator()->getName() == "timm") {
|
2019-09-19 16:26:14 +00:00
|
|
|
OM.addPredicate<ImmOperandMatcher>();
|
2021-03-29 15:21:46 +02:00
|
|
|
|
|
|
|
// Add predicates, if any
|
2024-02-09 13:35:42 +00:00
|
|
|
for (const TreePredicateCall &Call : SrcChild.getPredicateCalls()) {
|
2021-03-29 15:21:46 +02:00
|
|
|
const TreePredicateFn &Predicate = Call.Fn;
|
|
|
|
|
|
|
|
// Only handle immediate patterns for now
|
|
|
|
if (Predicate.isImmediatePattern()) {
|
|
|
|
OM.addPredicate<OperandImmPredicateMatcher>(Predicate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-19 16:26:14 +00:00
|
|
|
return Error::success();
|
|
|
|
}
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
2024-11-08 22:26:56 -08:00
|
|
|
} else if (auto *ChildDefInit = dyn_cast<DefInit>(SrcChild.getLeafValue())) {
|
|
|
|
auto *ChildRec = ChildDefInit->getDef();
|
|
|
|
if (ChildRec->isSubClassOf("ValueType") && !SrcChild.hasName()) {
|
|
|
|
// An unnamed ValueType as in (sext_inreg GPR:$foo, i8). GISel represents
|
|
|
|
// this as a literal constant with the scalar size.
|
|
|
|
MVT::SimpleValueType VT = llvm::getValueType(ChildRec);
|
|
|
|
OM.addPredicate<LiteralIntOperandMatcher>(MVT(VT).getScalarSizeInBits());
|
|
|
|
return Error::success();
|
|
|
|
}
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2020-01-08 15:40:37 -05:00
|
|
|
// Immediate arguments have no meaningful type to check as they don't have
|
|
|
|
// registers.
|
|
|
|
if (!OperandIsImmArg) {
|
|
|
|
if (auto Error =
|
|
|
|
OM.addTypeCheckPredicate(ChildTypes.front(), OperandIsAPointer))
|
|
|
|
return failedImport(toString(std::move(Error)) + " for Src operand (" +
|
2024-02-09 13:35:42 +00:00
|
|
|
to_string(SrcChild) + ")");
|
2020-01-08 15:40:37 -05:00
|
|
|
}
|
2017-03-29 15:37:18 +00:00
|
|
|
|
2023-10-05 08:57:15 -07:00
|
|
|
// Try look up SrcChild for a (named) predicate operand if there is any.
|
|
|
|
if (WaitingForNamedOperands) {
|
2024-02-09 13:35:42 +00:00
|
|
|
auto &ScopedNames = SrcChild.getNamesAsPredicateArg();
|
2023-10-05 08:57:15 -07:00
|
|
|
if (!ScopedNames.empty()) {
|
|
|
|
auto PA = ScopedNames.begin();
|
|
|
|
std::string Name = getScopedName(PA->getScope(), PA->getIdentifier());
|
|
|
|
OM.addPredicate<RecordNamedOperandMatcher>(StoreIdxForName[Name], Name);
|
|
|
|
--WaitingForNamedOperands;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[tablegen][globalisel] Add support for nested instruction matching.
Summary:
Lift the restrictions that prevented the tree walking introduced in the
previous change and add support for patterns like:
(G_ADD (G_MUL (G_SEXT $src1), (G_SEXT $src2)), $src3) -> SMADDWrrr $dst, $src1, $src2, $src3
Also adds support for G_SEXT and G_ZEXT to support these cases.
One particular aspect of this that I should draw attention to is that I've
tried to be overly conservative in determining the safety of matches that
involve non-adjacent instructions and multiple basic blocks. This is intended
to be used as a cheap initial check and we may add a more expensive check in
the future. The current rules are:
* Reject if any instruction may load/store (we'd need to check for intervening
memory operations.
* Reject if any instruction has implicit operands.
* Reject if any instruction has unmodelled side-effects.
See isObviouslySafeToFold().
Reviewers: t.p.northover, javed.absar, qcolombet, aditya_nandakumar, ab, rovka
Reviewed By: ab
Subscribers: igorb, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30539
llvm-svn: 299430
2017-04-04 13:25:23 +00:00
|
|
|
// Check for nested instructions.
|
2024-02-09 13:35:42 +00:00
|
|
|
if (!SrcChild.isLeaf()) {
|
|
|
|
if (SrcChild.getOperator()->isSubClassOf("ComplexPattern")) {
|
2017-10-15 18:22:54 +00:00
|
|
|
// When a ComplexPattern is used as an operator, it should do the same
|
|
|
|
// thing as when used as a leaf. However, the children of the operator
|
|
|
|
// name the sub-operands that make up the complex operand and we must
|
|
|
|
// prepare to reference them in the renderer too.
|
|
|
|
unsigned RendererID = TempOpIdx;
|
|
|
|
if (auto Error = importComplexPatternOperandMatcher(
|
2024-02-09 13:35:42 +00:00
|
|
|
OM, SrcChild.getOperator(), TempOpIdx))
|
2017-10-15 18:22:54 +00:00
|
|
|
return Error;
|
|
|
|
|
2024-04-29 14:47:46 -04:00
|
|
|
for (unsigned I = 0, E = SrcChild.getNumChildren(); I != E; ++I) {
|
|
|
|
auto &SubOperand = SrcChild.getChild(I);
|
2024-02-09 13:35:42 +00:00
|
|
|
if (!SubOperand.getName().empty()) {
|
2020-09-14 11:37:14 +02:00
|
|
|
if (auto Error = Rule.defineComplexSubOperand(
|
2024-04-29 14:47:46 -04:00
|
|
|
SubOperand.getName(), SrcChild.getOperator(), RendererID, I,
|
2020-09-14 11:37:14 +02:00
|
|
|
SrcChildName))
|
2019-02-09 00:29:13 +00:00
|
|
|
return Error;
|
|
|
|
}
|
2017-10-15 18:22:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2017-10-14 00:31:58 +00:00
|
|
|
auto MaybeInsnOperand = OM.addPredicate<InstructionOperandMatcher>(
|
2024-02-09 13:35:42 +00:00
|
|
|
InsnMatcher.getRuleMatcher(), SrcChild.getName());
|
2022-06-20 10:38:12 -07:00
|
|
|
if (!MaybeInsnOperand) {
|
2017-10-14 00:31:58 +00:00
|
|
|
// This isn't strictly true. If the user were to provide exactly the same
|
|
|
|
// matchers as the original operand then we could allow it. However, it's
|
|
|
|
// simpler to not permit the redundant specification.
|
2023-06-23 11:42:51 +02:00
|
|
|
return failedImport(
|
|
|
|
"Nested instruction cannot be the same as another operand");
|
2017-10-14 00:31:58 +00:00
|
|
|
}
|
|
|
|
|
[tablegen][globalisel] Add support for nested instruction matching.
Summary:
Lift the restrictions that prevented the tree walking introduced in the
previous change and add support for patterns like:
(G_ADD (G_MUL (G_SEXT $src1), (G_SEXT $src2)), $src3) -> SMADDWrrr $dst, $src1, $src2, $src3
Also adds support for G_SEXT and G_ZEXT to support these cases.
One particular aspect of this that I should draw attention to is that I've
tried to be overly conservative in determining the safety of matches that
involve non-adjacent instructions and multiple basic blocks. This is intended
to be used as a cheap initial check and we may add a more expensive check in
the future. The current rules are:
* Reject if any instruction may load/store (we'd need to check for intervening
memory operations.
* Reject if any instruction has implicit operands.
* Reject if any instruction has unmodelled side-effects.
See isObviouslySafeToFold().
Reviewers: t.p.northover, javed.absar, qcolombet, aditya_nandakumar, ab, rovka
Reviewed By: ab
Subscribers: igorb, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30539
llvm-svn: 299430
2017-04-04 13:25:23 +00:00
|
|
|
// Map the node to a gMIR instruction.
|
2017-10-14 00:31:58 +00:00
|
|
|
InstructionOperandMatcher &InsnOperand = **MaybeInsnOperand;
|
2017-07-11 10:40:18 +00:00
|
|
|
auto InsnMatcherOrError = createAndImportSelDAGMatcher(
|
2017-10-15 18:22:54 +00:00
|
|
|
Rule, InsnOperand.getInsnMatcher(), SrcChild, TempOpIdx);
|
[tablegen][globalisel] Add support for nested instruction matching.
Summary:
Lift the restrictions that prevented the tree walking introduced in the
previous change and add support for patterns like:
(G_ADD (G_MUL (G_SEXT $src1), (G_SEXT $src2)), $src3) -> SMADDWrrr $dst, $src1, $src2, $src3
Also adds support for G_SEXT and G_ZEXT to support these cases.
One particular aspect of this that I should draw attention to is that I've
tried to be overly conservative in determining the safety of matches that
involve non-adjacent instructions and multiple basic blocks. This is intended
to be used as a cheap initial check and we may add a more expensive check in
the future. The current rules are:
* Reject if any instruction may load/store (we'd need to check for intervening
memory operations.
* Reject if any instruction has implicit operands.
* Reject if any instruction has unmodelled side-effects.
See isObviouslySafeToFold().
Reviewers: t.p.northover, javed.absar, qcolombet, aditya_nandakumar, ab, rovka
Reviewed By: ab
Subscribers: igorb, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30539
llvm-svn: 299430
2017-04-04 13:25:23 +00:00
|
|
|
if (auto Error = InsnMatcherOrError.takeError())
|
|
|
|
return Error;
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
if (SrcChild.hasAnyPredicate())
|
2017-11-03 10:30:19 +00:00
|
|
|
return failedImport("Src pattern child has unsupported predicate");
|
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
// Check for constant immediates.
|
2024-02-09 13:35:42 +00:00
|
|
|
if (auto *ChildInt = dyn_cast<IntInit>(SrcChild.getLeafValue())) {
|
2020-01-08 15:40:37 -05:00
|
|
|
if (OperandIsImmArg) {
|
|
|
|
// Checks for argument directly in operand list
|
|
|
|
OM.addPredicate<LiteralIntOperandMatcher>(ChildInt->getValue());
|
|
|
|
} else {
|
|
|
|
// Checks for materialized constant
|
|
|
|
OM.addPredicate<ConstantIntOperandMatcher>(ChildInt->getValue());
|
|
|
|
}
|
2017-03-30 09:36:33 +00:00
|
|
|
return Error::success();
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check for def's like register classes or ComplexPattern's.
|
2024-02-09 13:35:42 +00:00
|
|
|
if (auto *ChildDefInit = dyn_cast<DefInit>(SrcChild.getLeafValue())) {
|
2017-03-29 15:37:18 +00:00
|
|
|
auto *ChildRec = ChildDefInit->getDef();
|
|
|
|
|
|
|
|
// Check for register classes.
|
2017-06-20 12:36:34 +00:00
|
|
|
if (ChildRec->isSubClassOf("RegisterClass") ||
|
|
|
|
ChildRec->isSubClassOf("RegisterOperand")) {
|
2017-04-22 15:53:21 +00:00
|
|
|
OM.addPredicate<RegisterBankOperandMatcher>(
|
2017-06-20 12:36:34 +00:00
|
|
|
Target.getRegisterClass(getInitValueAsRegClass(ChildDefInit)));
|
2017-04-22 15:53:21 +00:00
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2019-09-06 20:32:37 +00:00
|
|
|
if (ChildRec->isSubClassOf("Register")) {
|
|
|
|
// This just be emitted as a copy to the specific register.
|
|
|
|
ValueTypeByHwMode VT = ChildTypes.front().getValueTypeByHwMode();
|
2023-06-23 11:42:51 +02:00
|
|
|
const CodeGenRegisterClass *RC =
|
|
|
|
CGRegs.getMinimalPhysRegClass(ChildRec, &VT);
|
2019-09-06 20:32:37 +00:00
|
|
|
if (!RC) {
|
|
|
|
return failedImport(
|
2023-06-23 11:42:51 +02:00
|
|
|
"Could not determine physical register class of pattern source");
|
2019-09-06 20:32:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
OM.addPredicate<RegisterBankOperandMatcher>(*RC);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2017-10-09 18:14:53 +00:00
|
|
|
// Check for ValueType.
|
|
|
|
if (ChildRec->isSubClassOf("ValueType")) {
|
|
|
|
// We already added a type check as standard practice so this doesn't need
|
|
|
|
// to do anything.
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
// Check for ComplexPattern's.
|
2017-10-15 18:22:54 +00:00
|
|
|
if (ChildRec->isSubClassOf("ComplexPattern"))
|
|
|
|
return importComplexPatternOperandMatcher(OM, ChildRec, TempOpIdx);
|
2017-03-29 15:37:18 +00:00
|
|
|
|
2017-04-13 09:45:37 +00:00
|
|
|
if (ChildRec->isSubClassOf("ImmLeaf")) {
|
|
|
|
return failedImport(
|
|
|
|
"Src pattern child def is an unsupported tablegen class (ImmLeaf)");
|
|
|
|
}
|
|
|
|
|
2020-01-16 10:47:13 -05:00
|
|
|
// Place holder for SRCVALUE nodes. Nothing to do here.
|
|
|
|
if (ChildRec->getName() == "srcvalue")
|
|
|
|
return Error::success();
|
|
|
|
|
2020-08-01 10:39:21 -04:00
|
|
|
const bool ImmAllOnesV = ChildRec->getName() == "immAllOnesV";
|
|
|
|
if (ImmAllOnesV || ChildRec->getName() == "immAllZerosV") {
|
|
|
|
auto MaybeInsnOperand = OM.addPredicate<InstructionOperandMatcher>(
|
2024-02-09 13:35:42 +00:00
|
|
|
InsnMatcher.getRuleMatcher(), SrcChild.getName(), false);
|
2020-08-01 10:39:21 -04:00
|
|
|
InstructionOperandMatcher &InsnOperand = **MaybeInsnOperand;
|
|
|
|
|
|
|
|
ValueTypeByHwMode VTy = ChildTypes.front().getValueTypeByHwMode();
|
2020-08-02 14:52:20 -04:00
|
|
|
|
2023-06-23 11:42:51 +02:00
|
|
|
const CodeGenInstruction &BuildVector =
|
|
|
|
Target.getInstruction(RK.getDef("G_BUILD_VECTOR"));
|
|
|
|
const CodeGenInstruction &BuildVectorTrunc =
|
|
|
|
Target.getInstruction(RK.getDef("G_BUILD_VECTOR_TRUNC"));
|
2020-08-02 14:52:20 -04:00
|
|
|
|
|
|
|
// Treat G_BUILD_VECTOR as the canonical opcode, and G_BUILD_VECTOR_TRUNC
|
|
|
|
// as an alternative.
|
2020-08-01 10:39:21 -04:00
|
|
|
InsnOperand.getInsnMatcher().addPredicate<InstructionOpcodeMatcher>(
|
2023-01-04 08:28:45 +01:00
|
|
|
ArrayRef({&BuildVector, &BuildVectorTrunc}));
|
2020-08-01 10:39:21 -04:00
|
|
|
|
|
|
|
// TODO: Handle both G_BUILD_VECTOR and G_BUILD_VECTOR_TRUNC We could
|
|
|
|
// theoretically not emit any opcode check, but getOpcodeMatcher currently
|
|
|
|
// has to succeed.
|
|
|
|
OperandMatcher &OM =
|
|
|
|
InsnOperand.getInsnMatcher().addOperand(0, "", TempOpIdx);
|
|
|
|
if (auto Error =
|
2024-07-31 14:50:25 -07:00
|
|
|
OM.addTypeCheckPredicate(TypeSetByHwMode(VTy), false /* OperandIsAPointer */))
|
2020-08-01 10:39:21 -04:00
|
|
|
return failedImport(toString(std::move(Error)) +
|
|
|
|
" for result of Src pattern operator");
|
|
|
|
|
|
|
|
InsnOperand.getInsnMatcher().addPredicate<VectorSplatImmPredicateMatcher>(
|
|
|
|
ImmAllOnesV ? VectorSplatImmPredicateMatcher::AllOnes
|
|
|
|
: VectorSplatImmPredicateMatcher::AllZeros);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
return failedImport(
|
|
|
|
"Src pattern child def is an unsupported tablegen class");
|
|
|
|
}
|
|
|
|
|
|
|
|
return failedImport("Src pattern child is an unsupported kind");
|
|
|
|
}
|
|
|
|
|
2017-10-31 23:03:18 +00:00
|
|
|
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
|
|
|
|
action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &DstChild, const TreePatternNode &Src) {
|
2017-08-24 09:11:20 +00:00
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
const auto &SubOperand = Rule.getComplexSubOperand(DstChild.getName());
|
2022-06-20 10:38:12 -07:00
|
|
|
if (SubOperand) {
|
2017-10-15 18:22:54 +00:00
|
|
|
DstMIBuilder.addRenderer<RenderComplexPatternOperand>(
|
2024-02-09 13:35:42 +00:00
|
|
|
*std::get<0>(*SubOperand), DstChild.getName(), std::get<1>(*SubOperand),
|
|
|
|
std::get<2>(*SubOperand));
|
2017-10-31 23:03:18 +00:00
|
|
|
return InsertPt;
|
2017-10-15 18:22:54 +00:00
|
|
|
}
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
if (!DstChild.isLeaf()) {
|
|
|
|
if (DstChild.getOperator()->isSubClassOf("SDNodeXForm")) {
|
|
|
|
auto &Child = DstChild.getChild(0);
|
|
|
|
auto I = SDNodeXFormEquivs.find(DstChild.getOperator());
|
2018-01-16 18:44:05 +00:00
|
|
|
if (I != SDNodeXFormEquivs.end()) {
|
2024-09-30 06:37:36 -07:00
|
|
|
const Record *XFormOpc =
|
|
|
|
DstChild.getOperator()->getValueAsDef("Opcode");
|
TableGen/GlobalISel: Add way for SDNodeXForm to work on timm
The current implementation assumes there is an instruction associated
with the transform, but this is not the case for
timm/TargetConstant/immarg values. These transforms should directly
operate on a specific MachineOperand in the source
instruction. TableGen would assert if you attempted to define an
equivalent GISDNodeXFormEquiv using timm when it failed to find the
instruction matcher.
Specially recognize SDNodeXForms on timm, and pass the operand index
to the render function.
Ideally this would be a separate render function type that looks like
void renderFoo(MachineInstrBuilder, const MachineOperand&), but this
proved to be somewhat mechanically painful. Add an optional operand
index which will only be passed if the transform should only look at
the one source operand.
Theoretically it would also be possible to only ever pass the
MachineOperand, and the existing renderers would check the parent. I
think that would be somewhat ugly for the standard usage which may
want to inspect other operands, and I also think MachineOperand should
eventually not carry a pointer to the parent instruction.
Use it in one sample pattern. This isn't a great example, since the
transform exists to satisfy DAG type constraints. This could also be
avoided by just changing the MachineInstr's arbitrary choice of
operand type from i16 to i32. Other patterns have nontrivial uses, but
this serves as the simplest example.
One flaw this still has is if you try to use an SDNodeXForm defined
for imm, but the source pattern uses timm, you still see the "Failed
to lookup instruction" assert. However, there is now a way to avoid
it.
2020-01-08 12:53:15 -05:00
|
|
|
if (XFormOpc->getName() == "timm") {
|
|
|
|
// If this is a TargetConstant, there won't be a corresponding
|
|
|
|
// instruction to transform. Instead, this will refer directly to an
|
|
|
|
// operand in an instruction's operand list.
|
|
|
|
DstMIBuilder.addRenderer<CustomOperandRenderer>(*I->second,
|
2024-02-09 13:35:42 +00:00
|
|
|
Child.getName());
|
TableGen/GlobalISel: Add way for SDNodeXForm to work on timm
The current implementation assumes there is an instruction associated
with the transform, but this is not the case for
timm/TargetConstant/immarg values. These transforms should directly
operate on a specific MachineOperand in the source
instruction. TableGen would assert if you attempted to define an
equivalent GISDNodeXFormEquiv using timm when it failed to find the
instruction matcher.
Specially recognize SDNodeXForms on timm, and pass the operand index
to the render function.
Ideally this would be a separate render function type that looks like
void renderFoo(MachineInstrBuilder, const MachineOperand&), but this
proved to be somewhat mechanically painful. Add an optional operand
index which will only be passed if the transform should only look at
the one source operand.
Theoretically it would also be possible to only ever pass the
MachineOperand, and the existing renderers would check the parent. I
think that would be somewhat ugly for the standard usage which may
want to inspect other operands, and I also think MachineOperand should
eventually not carry a pointer to the parent instruction.
Use it in one sample pattern. This isn't a great example, since the
transform exists to satisfy DAG type constraints. This could also be
avoided by just changing the MachineInstr's arbitrary choice of
operand type from i16 to i32. Other patterns have nontrivial uses, but
this serves as the simplest example.
One flaw this still has is if you try to use an SDNodeXForm defined
for imm, but the source pattern uses timm, you still see the "Failed
to lookup instruction" assert. However, there is now a way to avoid
it.
2020-01-08 12:53:15 -05:00
|
|
|
} else {
|
2024-02-09 13:35:42 +00:00
|
|
|
DstMIBuilder.addRenderer<CustomRenderer>(*I->second, Child.getName());
|
TableGen/GlobalISel: Add way for SDNodeXForm to work on timm
The current implementation assumes there is an instruction associated
with the transform, but this is not the case for
timm/TargetConstant/immarg values. These transforms should directly
operate on a specific MachineOperand in the source
instruction. TableGen would assert if you attempted to define an
equivalent GISDNodeXFormEquiv using timm when it failed to find the
instruction matcher.
Specially recognize SDNodeXForms on timm, and pass the operand index
to the render function.
Ideally this would be a separate render function type that looks like
void renderFoo(MachineInstrBuilder, const MachineOperand&), but this
proved to be somewhat mechanically painful. Add an optional operand
index which will only be passed if the transform should only look at
the one source operand.
Theoretically it would also be possible to only ever pass the
MachineOperand, and the existing renderers would check the parent. I
think that would be somewhat ugly for the standard usage which may
want to inspect other operands, and I also think MachineOperand should
eventually not carry a pointer to the parent instruction.
Use it in one sample pattern. This isn't a great example, since the
transform exists to satisfy DAG type constraints. This could also be
avoided by just changing the MachineInstr's arbitrary choice of
operand type from i16 to i32. Other patterns have nontrivial uses, but
this serves as the simplest example.
One flaw this still has is if you try to use an SDNodeXForm defined
for imm, but the source pattern uses timm, you still see the "Failed
to lookup instruction" assert. However, there is now a way to avoid
it.
2020-01-08 12:53:15 -05:00
|
|
|
}
|
|
|
|
|
2018-01-16 18:44:05 +00:00
|
|
|
return InsertPt;
|
|
|
|
}
|
2024-02-09 13:35:42 +00:00
|
|
|
return failedImport("SDNodeXForm " + Child.getName() +
|
2018-01-16 18:44:05 +00:00
|
|
|
" has no custom renderer");
|
|
|
|
}
|
|
|
|
|
2017-08-08 10:44:31 +00:00
|
|
|
// We accept 'bb' here. It's an operator because BasicBlockSDNode isn't
|
|
|
|
// inline, but in MI it's just another operand.
|
2024-02-09 13:35:42 +00:00
|
|
|
if (DstChild.getOperator()->isSubClassOf("SDNode")) {
|
|
|
|
auto &ChildSDNI = CGP.getSDNodeInfo(DstChild.getOperator());
|
2017-03-29 15:37:18 +00:00
|
|
|
if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") {
|
2024-02-09 13:35:42 +00:00
|
|
|
DstMIBuilder.addRenderer<CopyRenderer>(DstChild.getName());
|
2017-10-31 23:03:18 +00:00
|
|
|
return InsertPt;
|
2016-12-21 23:26:20 +00:00
|
|
|
}
|
|
|
|
}
|
2017-08-08 10:44:31 +00:00
|
|
|
|
|
|
|
// Similarly, imm is an operator in TreePatternNode's view but must be
|
|
|
|
// rendered as operands.
|
|
|
|
// FIXME: The target should be able to choose sign-extended when appropriate
|
|
|
|
// (e.g. on Mips).
|
2024-02-09 13:35:42 +00:00
|
|
|
if (DstChild.getOperator()->getName() == "timm") {
|
|
|
|
DstMIBuilder.addRenderer<CopyRenderer>(DstChild.getName());
|
2019-09-19 16:26:14 +00:00
|
|
|
return InsertPt;
|
2024-04-29 12:06:26 -04:00
|
|
|
}
|
|
|
|
if (DstChild.getOperator()->getName() == "tframeindex") {
|
|
|
|
DstMIBuilder.addRenderer<CopyRenderer>(DstChild.getName());
|
|
|
|
return InsertPt;
|
2024-04-29 14:47:46 -04:00
|
|
|
}
|
|
|
|
if (DstChild.getOperator()->getName() == "imm") {
|
2024-02-09 13:35:42 +00:00
|
|
|
DstMIBuilder.addRenderer<CopyConstantAsImmRenderer>(DstChild.getName());
|
2017-10-31 23:03:18 +00:00
|
|
|
return InsertPt;
|
2024-04-29 14:47:46 -04:00
|
|
|
}
|
|
|
|
if (DstChild.getOperator()->getName() == "fpimm") {
|
[globalisel][tablegen] Add support for fpimm and import of APInt/APFloat based ImmLeaf.
Summary:
There's only a tablegen testcase for IntImmLeaf and not a CodeGen one
because the relevant rules are rejected for other reasons at the moment.
On AArch64, it's because there's an SDNodeXForm attached to the operand.
On X86, it's because the rule either emits multiple instructions or has
another predicate using PatFrag which cannot easily be supported at the
same time.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Reviewed By: qcolombet
Subscribers: aemerson, javed.absar, igorb, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D36569
llvm-svn: 315761
2017-10-13 21:28:03 +00:00
|
|
|
DstMIBuilder.addRenderer<CopyFConstantAsFPImmRenderer>(
|
2024-02-09 13:35:42 +00:00
|
|
|
DstChild.getName());
|
2017-10-31 23:03:18 +00:00
|
|
|
return InsertPt;
|
2017-08-08 10:44:31 +00:00
|
|
|
}
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
if (DstChild.getOperator()->isSubClassOf("Instruction")) {
|
2023-11-03 12:44:38 +01:00
|
|
|
auto OpTy = getInstResultType(DstChild, Target);
|
2020-01-14 16:02:02 -05:00
|
|
|
if (!OpTy)
|
|
|
|
return OpTy.takeError();
|
2017-11-01 19:57:57 +00:00
|
|
|
|
|
|
|
unsigned TempRegID = Rule.allocateTempRegID();
|
2023-06-23 11:42:51 +02:00
|
|
|
InsertPt =
|
|
|
|
Rule.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
|
2017-11-01 19:57:57 +00:00
|
|
|
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
|
|
|
|
|
|
|
|
auto InsertPtOrError = createAndImportSubInstructionRenderer(
|
2023-01-09 04:07:52 +00:00
|
|
|
++InsertPt, Rule, DstChild, Src, TempRegID);
|
2017-11-01 19:57:57 +00:00
|
|
|
if (auto Error = InsertPtOrError.takeError())
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2017-11-01 19:57:57 +00:00
|
|
|
return InsertPtOrError.get();
|
|
|
|
}
|
|
|
|
|
2023-06-23 11:42:51 +02:00
|
|
|
return failedImport("Dst pattern child isn't a leaf node or an MBB" +
|
2024-02-09 13:35:42 +00:00
|
|
|
llvm::to_string(DstChild));
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
2016-12-21 23:26:20 +00:00
|
|
|
|
2017-11-30 18:48:35 +00:00
|
|
|
// It could be a specific immediate in which case we should just check for
|
|
|
|
// that immediate.
|
|
|
|
if (const IntInit *ChildIntInit =
|
2024-02-09 13:35:42 +00:00
|
|
|
dyn_cast<IntInit>(DstChild.getLeafValue())) {
|
2017-11-30 18:48:35 +00:00
|
|
|
DstMIBuilder.addRenderer<ImmRenderer>(ChildIntInit->getValue());
|
|
|
|
return InsertPt;
|
|
|
|
}
|
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
// Otherwise, we're looking for a bog-standard RegisterClass operand.
|
2024-02-09 13:35:42 +00:00
|
|
|
if (auto *ChildDefInit = dyn_cast<DefInit>(DstChild.getLeafValue())) {
|
2017-03-29 15:37:18 +00:00
|
|
|
auto *ChildRec = ChildDefInit->getDef();
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
ArrayRef<TypeSetByHwMode> ChildTypes = DstChild.getExtTypes();
|
2016-12-21 23:26:20 +00:00
|
|
|
if (ChildTypes.size() != 1)
|
2017-03-29 15:37:18 +00:00
|
|
|
return failedImport("Dst pattern child has multiple results");
|
2016-12-21 23:26:20 +00:00
|
|
|
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<LLTCodeGen> OpTyOrNone;
|
2017-09-14 16:56:21 +00:00
|
|
|
if (ChildTypes.front().isMachineValueType())
|
|
|
|
OpTyOrNone = MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
|
2016-12-21 23:26:20 +00:00
|
|
|
if (!OpTyOrNone)
|
2017-03-29 15:37:18 +00:00
|
|
|
return failedImport("Dst operand has an unsupported type");
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
if (ChildRec->isSubClassOf("Register")) {
|
2020-09-18 10:08:32 +02:00
|
|
|
DstMIBuilder.addRenderer<AddRegisterRenderer>(Target, ChildRec);
|
2017-10-31 23:03:18 +00:00
|
|
|
return InsertPt;
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
}
|
|
|
|
|
2017-04-22 15:53:21 +00:00
|
|
|
if (ChildRec->isSubClassOf("RegisterClass") ||
|
2017-10-09 18:14:53 +00:00
|
|
|
ChildRec->isSubClassOf("RegisterOperand") ||
|
|
|
|
ChildRec->isSubClassOf("ValueType")) {
|
2017-10-23 18:19:24 +00:00
|
|
|
if (ChildRec->isSubClassOf("RegisterOperand") &&
|
|
|
|
!ChildRec->isValueUnset("GIZeroRegister")) {
|
|
|
|
DstMIBuilder.addRenderer<CopyOrAddZeroRegRenderer>(
|
2024-02-09 13:35:42 +00:00
|
|
|
DstChild.getName(), ChildRec->getValueAsDef("GIZeroRegister"));
|
2017-10-31 23:03:18 +00:00
|
|
|
return InsertPt;
|
2017-10-23 18:19:24 +00:00
|
|
|
}
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
DstMIBuilder.addRenderer<CopyRenderer>(DstChild.getName());
|
2017-10-31 23:03:18 +00:00
|
|
|
return InsertPt;
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2019-08-27 17:47:06 +00:00
|
|
|
if (ChildRec->isSubClassOf("SubRegIndex")) {
|
|
|
|
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(ChildRec);
|
|
|
|
DstMIBuilder.addRenderer<ImmRenderer>(SubIdx->EnumValue);
|
|
|
|
return InsertPt;
|
|
|
|
}
|
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
if (ChildRec->isSubClassOf("ComplexPattern")) {
|
|
|
|
const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec);
|
|
|
|
if (ComplexPattern == ComplexPatternEquivs.end())
|
|
|
|
return failedImport(
|
|
|
|
"SelectionDAG ComplexPattern not mapped to GlobalISel");
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
const OperandMatcher &OM = Rule.getOperandMatcher(DstChild.getName());
|
2017-03-29 15:37:18 +00:00
|
|
|
DstMIBuilder.addRenderer<RenderComplexPatternOperand>(
|
2024-02-09 13:35:42 +00:00
|
|
|
*ComplexPattern->second, DstChild.getName(),
|
[globalisel][tablegen] Revise API for ComplexPattern operands to improve flexibility.
Summary:
Some targets need to be able to do more complex rendering than just adding an
operand or two to an instruction. For example, it may need to insert an
instruction to extract a subreg first, or it may need to perform an operation
on the operand.
In SelectionDAG, targets would create SDNode's to achieve the desired effect
during the complex pattern predicate. This worked because SelectionDAG had a
form of garbage collection that would take care of SDNode's that were created
but not used due to a later predicate rejecting a match. This doesn't translate
well to GlobalISel and the churn was wasteful.
The API changes in this patch enable GlobalISel to accomplish the same thing
without the waste. The API is now:
InstructionSelector::OptionalComplexRendererFn selectArithImmed(MachineOperand &Root) const;
where Root is the root of the match. The return value can be omitted to
indicate that the predicate failed to match, or a function with the signature
ComplexRendererFn can be returned. For example:
return OptionalComplexRendererFn(
[=](MachineInstrBuilder &MIB) { MIB.addImm(Immed).addImm(ShVal); });
adds two immediate operands to the rendered instruction. Immed and ShVal are
captured from the predicate function.
As an added bonus, this also reduces the amount of information we need to
provide to GIComplexOperandMatcher.
Depends on D31418
Reviewers: aditya_nandakumar, t.p.northover, qcolombet, rovka, ab, javed.absar
Reviewed By: ab
Subscribers: dberris, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D31761
llvm-svn: 301079
2017-04-22 15:11:04 +00:00
|
|
|
OM.getAllocatedTemporariesBaseID());
|
2017-10-31 23:03:18 +00:00
|
|
|
return InsertPt;
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
return failedImport(
|
|
|
|
"Dst pattern child def is an unsupported tablegen class");
|
|
|
|
}
|
2023-01-09 04:07:52 +00:00
|
|
|
|
|
|
|
// Handle the case where the MVT/register class is omitted in the dest pattern
|
|
|
|
// but MVT exists in the source pattern.
|
2024-02-09 13:35:42 +00:00
|
|
|
if (isa<UnsetInit>(DstChild.getLeafValue())) {
|
|
|
|
for (unsigned NumOp = 0; NumOp < Src.getNumChildren(); NumOp++)
|
|
|
|
if (Src.getChild(NumOp).getName() == DstChild.getName()) {
|
|
|
|
DstMIBuilder.addRenderer<CopyRenderer>(Src.getChild(NumOp).getName());
|
2023-01-09 04:07:52 +00:00
|
|
|
return InsertPt;
|
|
|
|
}
|
|
|
|
}
|
2017-03-29 15:37:18 +00:00
|
|
|
return failedImport("Dst pattern child is an unsupported kind");
|
|
|
|
}
|
2017-03-14 21:32:08 +00:00
|
|
|
|
2017-03-30 09:36:33 +00:00
|
|
|
Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
|
2024-02-09 13:35:42 +00:00
|
|
|
RuleMatcher &M, InstructionMatcher &InsnMatcher, const TreePatternNode &Src,
|
|
|
|
const TreePatternNode &Dst) {
|
2017-10-31 23:03:18 +00:00
|
|
|
auto InsertPtOrError = createInstructionRenderer(M.actions_end(), M, Dst);
|
|
|
|
if (auto Error = InsertPtOrError.takeError())
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2017-10-31 19:09:29 +00:00
|
|
|
|
2017-10-31 23:03:18 +00:00
|
|
|
action_iterator InsertPt = InsertPtOrError.get();
|
|
|
|
BuildMIAction &DstMIBuilder = *static_cast<BuildMIAction *>(InsertPt->get());
|
2017-10-31 19:09:29 +00:00
|
|
|
|
2019-09-06 20:32:37 +00:00
|
|
|
for (auto PhysInput : InsnMatcher.getPhysRegInputs()) {
|
|
|
|
InsertPt = M.insertAction<BuildMIAction>(
|
|
|
|
InsertPt, M.allocateOutputInsnID(),
|
|
|
|
&Target.getInstruction(RK.getDef("COPY")));
|
|
|
|
BuildMIAction &CopyToPhysRegMIBuilder =
|
|
|
|
*static_cast<BuildMIAction *>(InsertPt->get());
|
2023-06-23 11:42:51 +02:00
|
|
|
CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(
|
|
|
|
Target, PhysInput.first, true);
|
2019-09-06 20:32:37 +00:00
|
|
|
CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first);
|
|
|
|
}
|
|
|
|
|
2023-02-04 08:23:46 -04:00
|
|
|
if (auto Error =
|
|
|
|
importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Src, Dst)
|
|
|
|
.takeError())
|
2020-07-13 08:59:38 -04:00
|
|
|
return std::move(Error);
|
2017-10-31 19:09:29 +00:00
|
|
|
|
2023-01-09 04:07:52 +00:00
|
|
|
if (auto Error =
|
|
|
|
importExplicitUseRenderers(InsertPt, M, DstMIBuilder, Dst, Src)
|
|
|
|
.takeError())
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2017-10-31 19:09:29 +00:00
|
|
|
|
|
|
|
return DstMIBuilder;
|
|
|
|
}
|
|
|
|
|
2017-11-01 19:57:57 +00:00
|
|
|
Expected<action_iterator>
|
|
|
|
GlobalISelEmitter::createAndImportSubInstructionRenderer(
|
2024-02-09 13:35:42 +00:00
|
|
|
const action_iterator InsertPt, RuleMatcher &M, const TreePatternNode &Dst,
|
|
|
|
const TreePatternNode &Src, unsigned TempRegID) {
|
2017-11-01 19:57:57 +00:00
|
|
|
auto InsertPtOrError = createInstructionRenderer(InsertPt, M, Dst);
|
|
|
|
|
|
|
|
// TODO: Assert there's exactly one result.
|
|
|
|
|
|
|
|
if (auto Error = InsertPtOrError.takeError())
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2017-11-01 19:57:57 +00:00
|
|
|
|
|
|
|
BuildMIAction &DstMIBuilder =
|
|
|
|
*static_cast<BuildMIAction *>(InsertPtOrError.get()->get());
|
|
|
|
|
|
|
|
// Assign the result to TempReg.
|
|
|
|
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true);
|
|
|
|
|
2024-03-08 09:39:10 +01:00
|
|
|
// Handle additional (ignored) results.
|
|
|
|
if (DstMIBuilder.getCGI()->Operands.NumDefs > 1) {
|
|
|
|
InsertPtOrError = importExplicitDefRenderers(
|
|
|
|
std::prev(*InsertPtOrError), M, DstMIBuilder, Src, Dst, /*Start=*/1);
|
|
|
|
if (auto Error = InsertPtOrError.takeError())
|
|
|
|
return std::move(Error);
|
|
|
|
}
|
|
|
|
|
2023-01-09 04:07:52 +00:00
|
|
|
InsertPtOrError = importExplicitUseRenderers(InsertPtOrError.get(), M,
|
|
|
|
DstMIBuilder, Dst, Src);
|
2017-11-01 19:57:57 +00:00
|
|
|
if (auto Error = InsertPtOrError.takeError())
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2017-11-01 19:57:57 +00:00
|
|
|
|
2024-11-07 07:16:54 +03:00
|
|
|
if (auto Error =
|
|
|
|
constrainOperands(InsertPt, M, DstMIBuilder.getInsnID(), Dst))
|
|
|
|
return std::move(Error);
|
2020-04-07 09:32:51 -04:00
|
|
|
|
2017-11-01 19:57:57 +00:00
|
|
|
return InsertPtOrError.get();
|
|
|
|
}
|
|
|
|
|
2017-10-31 23:03:18 +00:00
|
|
|
Expected<action_iterator> GlobalISelEmitter::createInstructionRenderer(
|
2024-02-09 13:35:42 +00:00
|
|
|
action_iterator InsertPt, RuleMatcher &M, const TreePatternNode &Dst) {
|
2024-09-11 08:52:26 -07:00
|
|
|
const Record *DstOp = Dst.getOperator();
|
2017-04-13 09:45:37 +00:00
|
|
|
if (!DstOp->isSubClassOf("Instruction")) {
|
|
|
|
if (DstOp->isSubClassOf("ValueType"))
|
|
|
|
return failedImport(
|
|
|
|
"Pattern operator isn't an instruction (it's a ValueType)");
|
2017-03-29 15:37:18 +00:00
|
|
|
return failedImport("Pattern operator isn't an instruction");
|
2017-04-13 09:45:37 +00:00
|
|
|
}
|
2017-06-20 12:36:34 +00:00
|
|
|
CodeGenInstruction *DstI = &Target.getInstruction(DstOp);
|
|
|
|
|
|
|
|
// COPY_TO_REGCLASS is just a copy with a ConstrainOperandToRegClassAction
|
2017-06-27 10:11:39 +00:00
|
|
|
// attached. Similarly for EXTRACT_SUBREG except that's a subregister copy.
|
2019-09-10 17:57:33 +00:00
|
|
|
StringRef Name = DstI->TheDef->getName();
|
|
|
|
if (Name == "COPY_TO_REGCLASS" || Name == "EXTRACT_SUBREG")
|
2017-06-20 12:36:34 +00:00
|
|
|
DstI = &Target.getInstruction(RK.getDef("COPY"));
|
2017-03-29 15:37:18 +00:00
|
|
|
|
2017-11-01 00:29:47 +00:00
|
|
|
return M.insertAction<BuildMIAction>(InsertPt, M.allocateOutputInsnID(),
|
|
|
|
DstI);
|
2017-10-31 19:09:29 +00:00
|
|
|
}
|
|
|
|
|
2020-07-13 08:59:38 -04:00
|
|
|
Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
|
|
|
|
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
|
2024-03-08 09:39:10 +01:00
|
|
|
const TreePatternNode &Src, const TreePatternNode &Dst, unsigned Start) {
|
2017-10-31 19:09:29 +00:00
|
|
|
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
|
2024-02-09 13:35:42 +00:00
|
|
|
const unsigned SrcNumDefs = Src.getExtTypes().size();
|
2023-02-04 08:23:46 -04:00
|
|
|
const unsigned DstNumDefs = DstI->Operands.NumDefs;
|
|
|
|
if (DstNumDefs == 0)
|
2020-07-13 08:59:38 -04:00
|
|
|
return InsertPt;
|
|
|
|
|
2024-03-08 09:39:10 +01:00
|
|
|
for (unsigned I = Start; I < SrcNumDefs; ++I) {
|
2023-12-10 13:25:11 +03:00
|
|
|
std::string OpName = getMangledRootDefName(DstI->Operands[I].Name);
|
|
|
|
// CopyRenderer saves a StringRef, so cannot pass OpName itself -
|
|
|
|
// let's use a string with an appropriate lifetime.
|
|
|
|
StringRef PermanentRef = M.getOperandMatcher(OpName).getSymbolicName();
|
|
|
|
DstMIBuilder.addRenderer<CopyRenderer>(PermanentRef);
|
|
|
|
}
|
2020-07-13 08:59:38 -04:00
|
|
|
|
2020-07-27 20:29:53 -04:00
|
|
|
// Some instructions have multiple defs, but are missing a type entry
|
|
|
|
// (e.g. s_cc_out operands).
|
2024-02-09 13:35:42 +00:00
|
|
|
if (Dst.getExtTypes().size() < DstNumDefs)
|
2020-07-27 20:29:53 -04:00
|
|
|
return failedImport("unhandled discarded def");
|
|
|
|
|
2023-02-04 08:23:46 -04:00
|
|
|
for (unsigned I = SrcNumDefs; I < DstNumDefs; ++I) {
|
2024-02-09 13:35:42 +00:00
|
|
|
const TypeSetByHwMode &ExtTy = Dst.getExtType(I);
|
2020-07-13 08:59:38 -04:00
|
|
|
if (!ExtTy.isMachineValueType())
|
|
|
|
return failedImport("unsupported typeset");
|
|
|
|
|
|
|
|
auto OpTy = MVTToLLT(ExtTy.getMachineValueType().SimpleTy);
|
|
|
|
if (!OpTy)
|
|
|
|
return failedImport("unsupported type");
|
|
|
|
|
|
|
|
unsigned TempRegID = M.allocateTempRegID();
|
|
|
|
InsertPt =
|
2023-06-23 11:42:51 +02:00
|
|
|
M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
|
2020-07-13 08:59:38 -04:00
|
|
|
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true, nullptr, true);
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
}
|
2020-07-13 08:59:38 -04:00
|
|
|
|
|
|
|
return InsertPt;
|
2017-10-31 19:09:29 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 23:03:18 +00:00
|
|
|
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
|
|
|
|
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
|
2024-02-09 13:35:42 +00:00
|
|
|
const llvm::TreePatternNode &Dst, const llvm::TreePatternNode &Src) {
|
2017-10-31 19:09:29 +00:00
|
|
|
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
|
2024-02-09 13:35:42 +00:00
|
|
|
CodeGenInstruction *OrigDstI = &Target.getInstruction(Dst.getOperator());
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2019-09-10 17:57:33 +00:00
|
|
|
StringRef Name = OrigDstI->TheDef->getName();
|
2024-02-09 13:35:42 +00:00
|
|
|
unsigned ExpectedDstINumUses = Dst.getNumChildren();
|
2019-09-10 17:57:33 +00:00
|
|
|
|
2017-06-27 10:11:39 +00:00
|
|
|
// EXTRACT_SUBREG needs to use a subregister COPY.
|
2019-09-10 17:57:33 +00:00
|
|
|
if (Name == "EXTRACT_SUBREG") {
|
2024-02-09 13:35:42 +00:00
|
|
|
if (!Dst.getChild(1).isLeaf())
|
2021-01-11 16:19:01 +01:00
|
|
|
return failedImport("EXTRACT_SUBREG child #1 is not a leaf");
|
2024-09-23 13:07:31 -07:00
|
|
|
const DefInit *SubRegInit =
|
|
|
|
dyn_cast<DefInit>(Dst.getChild(1).getLeafValue());
|
2020-01-14 16:02:02 -05:00
|
|
|
if (!SubRegInit)
|
|
|
|
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
|
|
|
|
|
|
|
|
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &ValChild = Dst.getChild(0);
|
|
|
|
if (!ValChild.isLeaf()) {
|
2020-01-14 16:02:02 -05:00
|
|
|
// We really have to handle the source instruction, and then insert a
|
|
|
|
// copy from the subregister.
|
2023-11-03 12:44:38 +01:00
|
|
|
auto ExtractSrcTy = getInstResultType(ValChild, Target);
|
2020-01-14 16:02:02 -05:00
|
|
|
if (!ExtractSrcTy)
|
|
|
|
return ExtractSrcTy.takeError();
|
2017-06-27 10:11:39 +00:00
|
|
|
|
2020-01-14 16:02:02 -05:00
|
|
|
unsigned TempRegID = M.allocateTempRegID();
|
2023-06-23 11:42:51 +02:00
|
|
|
InsertPt = M.insertAction<MakeTempRegisterAction>(InsertPt, *ExtractSrcTy,
|
|
|
|
TempRegID);
|
2020-01-14 16:02:02 -05:00
|
|
|
|
|
|
|
auto InsertPtOrError = createAndImportSubInstructionRenderer(
|
2023-06-23 11:42:51 +02:00
|
|
|
++InsertPt, M, ValChild, Src, TempRegID);
|
2020-01-14 16:02:02 -05:00
|
|
|
if (auto Error = InsertPtOrError.takeError())
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2020-01-14 16:02:02 -05:00
|
|
|
|
|
|
|
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, false, SubIdx);
|
2017-10-31 23:03:18 +00:00
|
|
|
return InsertPt;
|
2017-06-27 10:11:39 +00:00
|
|
|
}
|
|
|
|
|
2020-01-14 16:02:02 -05:00
|
|
|
// If this is a source operand, this is just a subregister copy.
|
2024-09-23 13:07:31 -07:00
|
|
|
const Record *RCDef = getInitValueAsRegClass(ValChild.getLeafValue());
|
2020-01-14 16:02:02 -05:00
|
|
|
if (!RCDef)
|
|
|
|
return failedImport("EXTRACT_SUBREG child #0 could not "
|
|
|
|
"be coerced to a register class");
|
|
|
|
|
|
|
|
CodeGenRegisterClass *RC = CGRegs.getRegClass(RCDef);
|
|
|
|
|
|
|
|
const auto SrcRCDstRCPair =
|
2023-06-23 11:42:51 +02:00
|
|
|
RC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx);
|
2022-06-20 10:38:12 -07:00
|
|
|
if (SrcRCDstRCPair) {
|
2020-01-14 16:02:02 -05:00
|
|
|
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
|
|
|
|
if (SrcRCDstRCPair->first != RC)
|
|
|
|
return failedImport("EXTRACT_SUBREG requires an additional COPY");
|
|
|
|
}
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
StringRef RegOperandName = Dst.getChild(0).getName();
|
2023-03-27 11:37:16 +01:00
|
|
|
if (const auto &SubOperand = M.getComplexSubOperand(RegOperandName)) {
|
|
|
|
DstMIBuilder.addRenderer<RenderComplexPatternOperand>(
|
|
|
|
*std::get<0>(*SubOperand), RegOperandName, std::get<1>(*SubOperand),
|
|
|
|
std::get<2>(*SubOperand), SubIdx);
|
|
|
|
return InsertPt;
|
|
|
|
}
|
|
|
|
|
|
|
|
DstMIBuilder.addRenderer<CopySubRegRenderer>(RegOperandName, SubIdx);
|
2020-01-14 16:02:02 -05:00
|
|
|
return InsertPt;
|
2017-06-27 10:11:39 +00:00
|
|
|
}
|
|
|
|
|
2019-09-10 17:57:33 +00:00
|
|
|
if (Name == "REG_SEQUENCE") {
|
2024-02-09 13:35:42 +00:00
|
|
|
if (!Dst.getChild(0).isLeaf())
|
2019-09-10 17:57:33 +00:00
|
|
|
return failedImport("REG_SEQUENCE child #0 is not a leaf");
|
|
|
|
|
2024-09-23 13:07:31 -07:00
|
|
|
const Record *RCDef =
|
|
|
|
getInitValueAsRegClass(Dst.getChild(0).getLeafValue());
|
2019-09-10 17:57:33 +00:00
|
|
|
if (!RCDef)
|
|
|
|
return failedImport("REG_SEQUENCE child #0 could not "
|
|
|
|
"be coerced to a register class");
|
|
|
|
|
|
|
|
if ((ExpectedDstINumUses - 1) % 2 != 0)
|
|
|
|
return failedImport("Malformed REG_SEQUENCE");
|
|
|
|
|
|
|
|
for (unsigned I = 1; I != ExpectedDstINumUses; I += 2) {
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &ValChild = Dst.getChild(I);
|
|
|
|
const TreePatternNode &SubRegChild = Dst.getChild(I + 1);
|
2019-09-10 17:57:33 +00:00
|
|
|
|
2024-09-23 13:07:31 -07:00
|
|
|
if (const DefInit *SubRegInit =
|
|
|
|
dyn_cast<DefInit>(SubRegChild.getLeafValue())) {
|
2019-09-10 17:57:33 +00:00
|
|
|
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
|
|
|
|
|
|
|
|
auto InsertPtOrError =
|
2023-01-09 04:07:52 +00:00
|
|
|
importExplicitUseRenderer(InsertPt, M, DstMIBuilder, ValChild, Src);
|
2019-09-10 17:57:33 +00:00
|
|
|
if (auto Error = InsertPtOrError.takeError())
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2019-09-10 17:57:33 +00:00
|
|
|
InsertPt = InsertPtOrError.get();
|
|
|
|
DstMIBuilder.addRenderer<SubRegIndexRenderer>(SubIdx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return InsertPt;
|
|
|
|
}
|
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
// Render the explicit uses.
|
2017-10-31 19:09:29 +00:00
|
|
|
unsigned DstINumUses = OrigDstI->Operands.size() - OrigDstI->Operands.NumDefs;
|
2019-09-10 17:57:33 +00:00
|
|
|
if (Name == "COPY_TO_REGCLASS") {
|
2017-10-31 19:09:29 +00:00
|
|
|
DstINumUses--; // Ignore the class constraint.
|
|
|
|
ExpectedDstINumUses--;
|
|
|
|
}
|
|
|
|
|
2019-10-21 21:39:42 -07:00
|
|
|
// NumResults - This is the number of results produced by the instruction in
|
|
|
|
// the "outs" list.
|
|
|
|
unsigned NumResults = OrigDstI->Operands.NumDefs;
|
|
|
|
|
|
|
|
// Number of operands we know the output instruction must have. If it is
|
|
|
|
// variadic, we could have more operands.
|
|
|
|
unsigned NumFixedOperands = DstI->Operands.size();
|
|
|
|
|
|
|
|
// Loop over all of the fixed operands of the instruction pattern, emitting
|
|
|
|
// code to fill them all in. The node 'N' usually has number children equal to
|
|
|
|
// the number of input operands of the instruction. However, in cases where
|
|
|
|
// there are predicate operands for an instruction, we need to fill in the
|
|
|
|
// 'execute always' values. Match up the node operands to the instruction
|
|
|
|
// operands to do this.
|
[globalisel][tablegen] Add experimental support for OperandWithDefaultOps, PredicateOperand, and OptionalDefOperand
Summary:
As far as instruction selection is concerned, all three appear to be same thing.
Support for these operands is experimental since AArch64 doesn't make use
of them and the in-tree targets that do use them (AMDGPU for
OperandWithDefaultOps, AMDGPU/ARM/Hexagon/Lanai for PredicateOperand, and ARM
for OperandWithDefaultOps) are not using tablegen-erated GlobalISel yet.
Reviewers: rovka, aditya_nandakumar, t.p.northover, qcolombet, ab
Reviewed By: rovka
Subscribers: inglorion, aemerson, rengolin, mehdi_amini, dberris, kristof.beyls, igorb, tpr, llvm-commits
Differential Revision: https://reviews.llvm.org/D31135
llvm-svn: 300037
2017-04-12 08:23:08 +00:00
|
|
|
unsigned Child = 0;
|
2019-10-21 21:39:42 -07:00
|
|
|
|
|
|
|
// Similarly to the code in TreePatternNode::ApplyTypeConstraints, count the
|
|
|
|
// number of operands at the end of the list which have default values.
|
|
|
|
// Those can come from the pattern if it provides enough arguments, or be
|
|
|
|
// filled in with the default if the pattern hasn't provided them. But any
|
|
|
|
// operand with a default value _before_ the last mandatory one will be
|
|
|
|
// filled in with their defaults unconditionally.
|
|
|
|
unsigned NonOverridableOperands = NumFixedOperands;
|
|
|
|
while (NonOverridableOperands > NumResults &&
|
|
|
|
CGP.operandHasDefault(DstI->Operands[NonOverridableOperands - 1].Rec))
|
|
|
|
--NonOverridableOperands;
|
|
|
|
|
2017-05-17 08:57:28 +00:00
|
|
|
unsigned NumDefaultOps = 0;
|
[globalisel][tablegen] Add experimental support for OperandWithDefaultOps, PredicateOperand, and OptionalDefOperand
Summary:
As far as instruction selection is concerned, all three appear to be same thing.
Support for these operands is experimental since AArch64 doesn't make use
of them and the in-tree targets that do use them (AMDGPU for
OperandWithDefaultOps, AMDGPU/ARM/Hexagon/Lanai for PredicateOperand, and ARM
for OperandWithDefaultOps) are not using tablegen-erated GlobalISel yet.
Reviewers: rovka, aditya_nandakumar, t.p.northover, qcolombet, ab
Reviewed By: rovka
Subscribers: inglorion, aemerson, rengolin, mehdi_amini, dberris, kristof.beyls, igorb, tpr, llvm-commits
Differential Revision: https://reviews.llvm.org/D31135
llvm-svn: 300037
2017-04-12 08:23:08 +00:00
|
|
|
for (unsigned I = 0; I != DstINumUses; ++I) {
|
2019-10-21 21:39:42 -07:00
|
|
|
unsigned InstOpNo = DstI->Operands.NumDefs + I;
|
|
|
|
|
|
|
|
// Determine what to emit for this operand.
|
2024-09-09 14:33:21 -07:00
|
|
|
const Record *OperandNode = DstI->Operands[InstOpNo].Rec;
|
[globalisel][tablegen] Add experimental support for OperandWithDefaultOps, PredicateOperand, and OptionalDefOperand
Summary:
As far as instruction selection is concerned, all three appear to be same thing.
Support for these operands is experimental since AArch64 doesn't make use
of them and the in-tree targets that do use them (AMDGPU for
OperandWithDefaultOps, AMDGPU/ARM/Hexagon/Lanai for PredicateOperand, and ARM
for OperandWithDefaultOps) are not using tablegen-erated GlobalISel yet.
Reviewers: rovka, aditya_nandakumar, t.p.northover, qcolombet, ab
Reviewed By: rovka
Subscribers: inglorion, aemerson, rengolin, mehdi_amini, dberris, kristof.beyls, igorb, tpr, llvm-commits
Differential Revision: https://reviews.llvm.org/D31135
llvm-svn: 300037
2017-04-12 08:23:08 +00:00
|
|
|
|
2017-05-17 08:57:28 +00:00
|
|
|
// If the operand has default values, introduce them now.
|
2019-10-21 21:39:42 -07:00
|
|
|
if (CGP.operandHasDefault(OperandNode) &&
|
2024-02-09 13:35:42 +00:00
|
|
|
(InstOpNo < NonOverridableOperands || Child >= Dst.getNumChildren())) {
|
2019-10-21 21:39:42 -07:00
|
|
|
// This is a predicate or optional def operand which the pattern has not
|
|
|
|
// overridden, or which we aren't letting it override; emit the 'default
|
|
|
|
// ops' operands.
|
|
|
|
|
2024-09-09 14:33:21 -07:00
|
|
|
const Record *OperandNode = DstI->Operands[InstOpNo].Rec;
|
2023-12-17 15:02:10 -05:00
|
|
|
if (auto Error = importDefaultOperandRenderers(
|
|
|
|
InsertPt, M, DstMIBuilder, CGP.getDefaultOperand(OperandNode)))
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2023-12-17 15:02:10 -05:00
|
|
|
|
2017-05-17 08:57:28 +00:00
|
|
|
++NumDefaultOps;
|
[globalisel][tablegen] Add experimental support for OperandWithDefaultOps, PredicateOperand, and OptionalDefOperand
Summary:
As far as instruction selection is concerned, all three appear to be same thing.
Support for these operands is experimental since AArch64 doesn't make use
of them and the in-tree targets that do use them (AMDGPU for
OperandWithDefaultOps, AMDGPU/ARM/Hexagon/Lanai for PredicateOperand, and ARM
for OperandWithDefaultOps) are not using tablegen-erated GlobalISel yet.
Reviewers: rovka, aditya_nandakumar, t.p.northover, qcolombet, ab
Reviewed By: rovka
Subscribers: inglorion, aemerson, rengolin, mehdi_amini, dberris, kristof.beyls, igorb, tpr, llvm-commits
Differential Revision: https://reviews.llvm.org/D31135
llvm-svn: 300037
2017-04-12 08:23:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-10-31 23:03:18 +00:00
|
|
|
auto InsertPtOrError = importExplicitUseRenderer(InsertPt, M, DstMIBuilder,
|
2024-02-09 13:35:42 +00:00
|
|
|
Dst.getChild(Child), Src);
|
2017-10-31 23:03:18 +00:00
|
|
|
if (auto Error = InsertPtOrError.takeError())
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2017-10-31 23:03:18 +00:00
|
|
|
InsertPt = InsertPtOrError.get();
|
[globalisel][tablegen] Add experimental support for OperandWithDefaultOps, PredicateOperand, and OptionalDefOperand
Summary:
As far as instruction selection is concerned, all three appear to be same thing.
Support for these operands is experimental since AArch64 doesn't make use
of them and the in-tree targets that do use them (AMDGPU for
OperandWithDefaultOps, AMDGPU/ARM/Hexagon/Lanai for PredicateOperand, and ARM
for OperandWithDefaultOps) are not using tablegen-erated GlobalISel yet.
Reviewers: rovka, aditya_nandakumar, t.p.northover, qcolombet, ab
Reviewed By: rovka
Subscribers: inglorion, aemerson, rengolin, mehdi_amini, dberris, kristof.beyls, igorb, tpr, llvm-commits
Differential Revision: https://reviews.llvm.org/D31135
llvm-svn: 300037
2017-04-12 08:23:08 +00:00
|
|
|
++Child;
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2017-06-20 12:36:34 +00:00
|
|
|
if (NumDefaultOps + ExpectedDstINumUses != DstINumUses)
|
2017-05-17 09:25:08 +00:00
|
|
|
return failedImport("Expected " + llvm::to_string(DstINumUses) +
|
2017-05-17 08:57:28 +00:00
|
|
|
" used operands but found " +
|
2017-06-20 12:36:34 +00:00
|
|
|
llvm::to_string(ExpectedDstINumUses) +
|
2017-05-17 09:25:08 +00:00
|
|
|
" explicit ones and " + llvm::to_string(NumDefaultOps) +
|
2017-05-17 08:57:28 +00:00
|
|
|
" default ones");
|
|
|
|
|
2017-10-31 23:03:18 +00:00
|
|
|
return InsertPt;
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2017-05-17 08:57:28 +00:00
|
|
|
Error GlobalISelEmitter::importDefaultOperandRenderers(
|
2019-05-30 07:30:37 +00:00
|
|
|
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
|
2023-12-17 15:02:10 -05:00
|
|
|
const DAGDefaultOperand &DefaultOp) const {
|
|
|
|
for (const auto &Op : DefaultOp.DefaultOps) {
|
2024-02-09 13:35:42 +00:00
|
|
|
const auto &N = *Op;
|
|
|
|
if (!N.isLeaf())
|
2023-12-17 15:02:10 -05:00
|
|
|
return failedImport("Could not add default op");
|
2019-05-30 07:30:37 +00:00
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
const auto *DefaultOp = N.getLeafValue();
|
2017-05-17 08:57:28 +00:00
|
|
|
|
|
|
|
if (const DefInit *DefaultDefOp = dyn_cast<DefInit>(DefaultOp)) {
|
2024-02-09 13:35:42 +00:00
|
|
|
std::optional<LLTCodeGen> OpTyOrNone = MVTToLLT(N.getSimpleType(0));
|
2024-04-29 14:47:46 -04:00
|
|
|
auto *Def = DefaultDefOp->getDef();
|
2019-05-30 07:30:37 +00:00
|
|
|
if (Def->getName() == "undef_tied_input") {
|
|
|
|
unsigned TempRegID = M.allocateTempRegID();
|
2022-12-16 22:44:08 +00:00
|
|
|
M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTyOrNone,
|
2022-07-13 23:11:56 -07:00
|
|
|
TempRegID);
|
2019-05-30 07:30:37 +00:00
|
|
|
InsertPt = M.insertAction<BuildMIAction>(
|
2023-06-23 11:42:51 +02:00
|
|
|
InsertPt, M.allocateOutputInsnID(),
|
|
|
|
&Target.getInstruction(RK.getDef("IMPLICIT_DEF")));
|
|
|
|
BuildMIAction &IDMIBuilder =
|
|
|
|
*static_cast<BuildMIAction *>(InsertPt->get());
|
2019-05-30 07:30:37 +00:00
|
|
|
IDMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
|
|
|
|
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
|
|
|
|
} else {
|
2020-09-18 10:08:32 +02:00
|
|
|
DstMIBuilder.addRenderer<AddRegisterRenderer>(Target, Def);
|
2019-05-30 07:30:37 +00:00
|
|
|
}
|
2017-05-17 08:57:28 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const IntInit *DefaultIntOp = dyn_cast<IntInit>(DefaultOp)) {
|
2017-11-01 00:29:47 +00:00
|
|
|
DstMIBuilder.addRenderer<ImmRenderer>(DefaultIntOp->getValue());
|
2017-05-17 08:57:28 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return failedImport("Could not add default op");
|
|
|
|
}
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2017-03-30 09:36:33 +00:00
|
|
|
Error GlobalISelEmitter::importImplicitDefRenderers(
|
2024-09-23 13:07:31 -07:00
|
|
|
BuildMIAction &DstMIBuilder, ArrayRef<const Record *> ImplicitDefs) const {
|
2017-03-29 15:37:18 +00:00
|
|
|
if (!ImplicitDefs.empty())
|
|
|
|
return failedImport("Pattern defines a physical register");
|
2017-03-30 09:36:33 +00:00
|
|
|
return Error::success();
|
2017-03-29 15:37:18 +00:00
|
|
|
}
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2024-11-07 07:16:54 +03:00
|
|
|
Error GlobalISelEmitter::constrainOperands(action_iterator InsertPt,
|
|
|
|
RuleMatcher &M, unsigned InsnID,
|
|
|
|
const TreePatternNode &Dst) {
|
|
|
|
const Record *DstOp = Dst.getOperator();
|
|
|
|
const CodeGenInstruction &DstI = Target.getInstruction(DstOp);
|
|
|
|
StringRef DstIName = DstI.TheDef->getName();
|
|
|
|
|
|
|
|
if (DstIName == "COPY_TO_REGCLASS") {
|
|
|
|
// COPY_TO_REGCLASS does not provide operand constraints itself but the
|
|
|
|
// result is constrained to the class given by the second child.
|
|
|
|
const Record *DstIOpRec =
|
|
|
|
getInitValueAsRegClass(Dst.getChild(1).getLeafValue());
|
|
|
|
|
|
|
|
if (DstIOpRec == nullptr)
|
|
|
|
return failedImport("COPY_TO_REGCLASS operand #1 isn't a register class");
|
|
|
|
|
|
|
|
M.insertAction<ConstrainOperandToRegClassAction>(
|
|
|
|
InsertPt, InsnID, 0, Target.getRegisterClass(DstIOpRec));
|
|
|
|
} else if (DstIName == "EXTRACT_SUBREG") {
|
|
|
|
auto SuperClass = inferRegClassFromPattern(Dst.getChild(0));
|
|
|
|
if (!SuperClass)
|
|
|
|
return failedImport(
|
|
|
|
"Cannot infer register class from EXTRACT_SUBREG operand #0");
|
|
|
|
|
|
|
|
auto SubIdx = inferSubRegIndexForNode(Dst.getChild(1));
|
|
|
|
if (!SubIdx)
|
|
|
|
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
|
|
|
|
|
|
|
|
// It would be nice to leave this constraint implicit but we're required
|
|
|
|
// to pick a register class so constrain the result to a register class
|
|
|
|
// that can hold the correct MVT.
|
|
|
|
//
|
|
|
|
// FIXME: This may introduce an extra copy if the chosen class doesn't
|
|
|
|
// actually contain the subregisters.
|
|
|
|
const auto SrcRCDstRCPair =
|
|
|
|
(*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
|
|
|
|
if (!SrcRCDstRCPair) {
|
|
|
|
return failedImport("subreg index is incompatible "
|
|
|
|
"with inferred reg class");
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
|
|
|
|
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 0,
|
|
|
|
*SrcRCDstRCPair->second);
|
|
|
|
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 1,
|
|
|
|
*SrcRCDstRCPair->first);
|
|
|
|
} else if (DstIName == "INSERT_SUBREG") {
|
|
|
|
// We need to constrain the destination, a super regsister source, and a
|
|
|
|
// subregister source.
|
|
|
|
auto SubClass = inferRegClassFromPattern(Dst.getChild(1));
|
|
|
|
if (!SubClass)
|
|
|
|
return failedImport(
|
|
|
|
"Cannot infer register class from INSERT_SUBREG operand #1");
|
|
|
|
auto SuperClass = inferSuperRegisterClassForNode(
|
|
|
|
Dst.getExtType(0), Dst.getChild(0), Dst.getChild(2));
|
|
|
|
if (!SuperClass)
|
|
|
|
return failedImport(
|
|
|
|
"Cannot infer register class for INSERT_SUBREG operand #0");
|
|
|
|
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 0,
|
|
|
|
**SuperClass);
|
|
|
|
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 1,
|
|
|
|
**SuperClass);
|
|
|
|
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 2,
|
|
|
|
**SubClass);
|
|
|
|
} else if (DstIName == "SUBREG_TO_REG") {
|
|
|
|
// We need to constrain the destination and subregister source.
|
|
|
|
// Attempt to infer the subregister source from the first child. If it has
|
|
|
|
// an explicitly given register class, we'll use that. Otherwise, we will
|
|
|
|
// fail.
|
|
|
|
auto SubClass = inferRegClassFromPattern(Dst.getChild(1));
|
|
|
|
if (!SubClass)
|
|
|
|
return failedImport(
|
|
|
|
"Cannot infer register class from SUBREG_TO_REG child #1");
|
|
|
|
// We don't have a child to look at that might have a super register node.
|
|
|
|
auto SuperClass =
|
|
|
|
inferSuperRegisterClass(Dst.getExtType(0), Dst.getChild(2));
|
|
|
|
if (!SuperClass)
|
|
|
|
return failedImport(
|
|
|
|
"Cannot infer register class for SUBREG_TO_REG operand #0");
|
|
|
|
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 0,
|
|
|
|
**SuperClass);
|
|
|
|
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 2,
|
|
|
|
**SubClass);
|
|
|
|
} else if (DstIName == "REG_SEQUENCE") {
|
|
|
|
auto SuperClass = inferRegClassFromPattern(Dst.getChild(0));
|
|
|
|
|
|
|
|
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 0,
|
|
|
|
**SuperClass);
|
|
|
|
|
|
|
|
unsigned Num = Dst.getNumChildren();
|
|
|
|
for (unsigned I = 1; I != Num; I += 2) {
|
|
|
|
const TreePatternNode &SubRegChild = Dst.getChild(I + 1);
|
|
|
|
|
|
|
|
auto SubIdx = inferSubRegIndexForNode(SubRegChild);
|
|
|
|
if (!SubIdx)
|
|
|
|
return failedImport("REG_SEQUENCE child is not a subreg index");
|
|
|
|
|
|
|
|
const auto SrcRCDstRCPair =
|
|
|
|
(*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
|
|
|
|
|
|
|
|
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, I,
|
|
|
|
*SrcRCDstRCPair->second);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
M.insertAction<ConstrainOperandsToDefinitionAction>(InsertPt, InsnID);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<const CodeGenRegisterClass *>
|
2024-02-09 13:35:42 +00:00
|
|
|
GlobalISelEmitter::getRegClassFromLeaf(const TreePatternNode &Leaf) {
|
|
|
|
assert(Leaf.isLeaf() && "Expected leaf?");
|
2024-09-23 13:07:31 -07:00
|
|
|
const Record *RCRec = getInitValueAsRegClass(Leaf.getLeafValue());
|
2019-08-27 17:47:06 +00:00
|
|
|
if (!RCRec)
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2024-09-23 13:07:31 -07:00
|
|
|
const CodeGenRegisterClass *RC = CGRegs.getRegClass(RCRec);
|
2019-08-27 17:47:06 +00:00
|
|
|
if (!RC)
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2019-08-27 17:47:06 +00:00
|
|
|
return RC;
|
|
|
|
}
|
|
|
|
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<const CodeGenRegisterClass *>
|
2024-02-09 13:35:42 +00:00
|
|
|
GlobalISelEmitter::inferRegClassFromPattern(const TreePatternNode &N) {
|
|
|
|
if (N.isLeaf())
|
2019-08-27 17:47:06 +00:00
|
|
|
return getRegClassFromLeaf(N);
|
|
|
|
|
|
|
|
// We don't have a leaf node, so we have to try and infer something. Check
|
2023-11-03 12:44:38 +01:00
|
|
|
// that we have an instruction that we can infer something from.
|
2019-08-27 17:47:06 +00:00
|
|
|
|
2023-11-03 12:44:38 +01:00
|
|
|
// Only handle things that produce at least one value (if multiple values,
|
|
|
|
// just take the first one).
|
|
|
|
if (N.getNumTypes() < 1)
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2024-09-11 08:52:26 -07:00
|
|
|
const Record *OpRec = N.getOperator();
|
2019-08-27 17:47:06 +00:00
|
|
|
|
|
|
|
// We only want instructions.
|
|
|
|
if (!OpRec->isSubClassOf("Instruction"))
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2019-08-27 17:47:06 +00:00
|
|
|
|
|
|
|
// Don't want to try and infer things when there could potentially be more
|
|
|
|
// than one candidate register class.
|
|
|
|
auto &Inst = Target.getInstruction(OpRec);
|
|
|
|
|
|
|
|
// Handle any special-case instructions which we can safely infer register
|
|
|
|
// classes from.
|
|
|
|
StringRef InstName = Inst.TheDef->getName();
|
2019-09-04 16:19:34 +00:00
|
|
|
bool IsRegSequence = InstName == "REG_SEQUENCE";
|
|
|
|
if (IsRegSequence || InstName == "COPY_TO_REGCLASS") {
|
2019-08-27 17:47:06 +00:00
|
|
|
// If we have a COPY_TO_REGCLASS, then we need to handle it specially. It
|
|
|
|
// has the desired register class as the first child.
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &RCChild = N.getChild(IsRegSequence ? 0 : 1);
|
|
|
|
if (!RCChild.isLeaf())
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2019-08-27 17:47:06 +00:00
|
|
|
return getRegClassFromLeaf(RCChild);
|
|
|
|
}
|
2020-10-05 10:28:50 +02:00
|
|
|
if (InstName == "INSERT_SUBREG") {
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &Child0 = N.getChild(0);
|
|
|
|
assert(Child0.getNumTypes() == 1 && "Unexpected number of types!");
|
|
|
|
const TypeSetByHwMode &VTy = Child0.getExtType(0);
|
|
|
|
return inferSuperRegisterClassForNode(VTy, Child0, N.getChild(2));
|
2020-10-05 10:28:50 +02:00
|
|
|
}
|
|
|
|
if (InstName == "EXTRACT_SUBREG") {
|
2024-02-09 13:35:42 +00:00
|
|
|
assert(N.getNumTypes() == 1 && "Unexpected number of types!");
|
|
|
|
const TypeSetByHwMode &VTy = N.getExtType(0);
|
|
|
|
return inferSuperRegisterClass(VTy, N.getChild(1));
|
2020-10-05 10:28:50 +02:00
|
|
|
}
|
2019-08-27 17:47:06 +00:00
|
|
|
|
|
|
|
// Handle destination record types that we can safely infer a register class
|
|
|
|
// from.
|
|
|
|
const auto &DstIOperand = Inst.Operands[0];
|
2024-09-09 14:33:21 -07:00
|
|
|
const Record *DstIOpRec = DstIOperand.Rec;
|
2019-08-27 17:47:06 +00:00
|
|
|
if (DstIOpRec->isSubClassOf("RegisterOperand")) {
|
|
|
|
DstIOpRec = DstIOpRec->getValueAsDef("RegClass");
|
|
|
|
const CodeGenRegisterClass &RC = Target.getRegisterClass(DstIOpRec);
|
|
|
|
return &RC;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DstIOpRec->isSubClassOf("RegisterClass")) {
|
|
|
|
const CodeGenRegisterClass &RC = Target.getRegisterClass(DstIOpRec);
|
|
|
|
return &RC;
|
|
|
|
}
|
|
|
|
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2019-08-27 17:47:06 +00:00
|
|
|
}
|
|
|
|
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<const CodeGenRegisterClass *>
|
2023-04-18 01:19:29 -07:00
|
|
|
GlobalISelEmitter::inferSuperRegisterClass(
|
2024-02-09 13:35:42 +00:00
|
|
|
const TypeSetByHwMode &Ty, const TreePatternNode &SubRegIdxNode) {
|
2019-08-27 17:47:06 +00:00
|
|
|
// We need a ValueTypeByHwMode for getSuperRegForSubReg.
|
|
|
|
if (!Ty.isValueTypeByHwMode(false))
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2024-02-09 13:35:42 +00:00
|
|
|
if (!SubRegIdxNode.isLeaf())
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2024-09-23 13:07:31 -07:00
|
|
|
const DefInit *SubRegInit = dyn_cast<DefInit>(SubRegIdxNode.getLeafValue());
|
2019-08-27 17:47:06 +00:00
|
|
|
if (!SubRegInit)
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2024-09-23 13:07:31 -07:00
|
|
|
const CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
|
2019-08-27 17:47:06 +00:00
|
|
|
|
|
|
|
// Use the information we found above to find a minimal register class which
|
|
|
|
// supports the subregister and type we want.
|
|
|
|
auto RC =
|
2021-01-05 09:12:58 +01:00
|
|
|
Target.getSuperRegForSubReg(Ty.getValueTypeByHwMode(), CGRegs, SubIdx,
|
|
|
|
/* MustBeAllocatable */ true);
|
2019-08-27 17:47:06 +00:00
|
|
|
if (!RC)
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2019-08-27 17:47:06 +00:00
|
|
|
return *RC;
|
|
|
|
}
|
|
|
|
|
2022-12-06 07:21:02 +00:00
|
|
|
std::optional<const CodeGenRegisterClass *>
|
2019-08-28 20:12:31 +00:00
|
|
|
GlobalISelEmitter::inferSuperRegisterClassForNode(
|
2024-02-09 13:35:42 +00:00
|
|
|
const TypeSetByHwMode &Ty, const TreePatternNode &SuperRegNode,
|
|
|
|
const TreePatternNode &SubRegIdxNode) {
|
2019-08-28 20:12:31 +00:00
|
|
|
// Check if we already have a defined register class for the super register
|
|
|
|
// node. If we do, then we should preserve that rather than inferring anything
|
|
|
|
// from the subregister index node. We can assume that whoever wrote the
|
|
|
|
// pattern in the first place made sure that the super register and
|
|
|
|
// subregister are compatible.
|
2022-12-06 07:21:02 +00:00
|
|
|
if (std::optional<const CodeGenRegisterClass *> SuperRegisterClass =
|
2019-08-28 20:12:31 +00:00
|
|
|
inferRegClassFromPattern(SuperRegNode))
|
|
|
|
return *SuperRegisterClass;
|
|
|
|
return inferSuperRegisterClass(Ty, SubRegIdxNode);
|
|
|
|
}
|
|
|
|
|
2023-04-18 01:19:29 -07:00
|
|
|
std::optional<CodeGenSubRegIndex *> GlobalISelEmitter::inferSubRegIndexForNode(
|
2024-02-09 13:35:42 +00:00
|
|
|
const TreePatternNode &SubRegIdxNode) {
|
|
|
|
if (!SubRegIdxNode.isLeaf())
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2019-09-06 00:05:58 +00:00
|
|
|
|
2024-09-23 13:07:31 -07:00
|
|
|
const DefInit *SubRegInit = dyn_cast<DefInit>(SubRegIdxNode.getLeafValue());
|
2019-09-06 00:05:58 +00:00
|
|
|
if (!SubRegInit)
|
2022-12-02 21:11:42 -08:00
|
|
|
return std::nullopt;
|
2019-09-06 00:05:58 +00:00
|
|
|
return CGRegs.getSubRegIdx(SubRegInit->getDef());
|
|
|
|
}
|
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
|
|
|
|
// Keep track of the matchers and actions to emit.
|
2018-02-16 22:37:15 +00:00
|
|
|
int Score = P.getPatternComplexity(CGP);
|
2017-10-14 00:31:58 +00:00
|
|
|
RuleMatcher M(P.getSrcRecord()->getLoc());
|
2018-02-16 22:37:15 +00:00
|
|
|
RuleMatcherScores[M.getRuleID()] = Score;
|
2024-02-09 13:35:42 +00:00
|
|
|
M.addAction<DebugCommentAction>(llvm::to_string(P.getSrcPattern()) +
|
2017-10-31 18:07:03 +00:00
|
|
|
" => " +
|
2024-02-09 13:35:42 +00:00
|
|
|
llvm::to_string(P.getDstPattern()));
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2024-09-23 13:07:31 -07:00
|
|
|
SmallVector<const Record *, 4> Predicates;
|
2021-04-28 11:13:10 -07:00
|
|
|
P.getPredicateRecords(Predicates);
|
|
|
|
if (auto Error = importRulePredicates(M, Predicates))
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2023-08-23 21:04:28 -07:00
|
|
|
if (!P.getHwModeFeatures().empty())
|
|
|
|
M.addHwModeIdx(declareHwModeCheck(P.getHwModeFeatures()));
|
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
// Next, analyze the pattern operators.
|
2024-02-09 13:35:42 +00:00
|
|
|
TreePatternNode &Src = P.getSrcPattern();
|
|
|
|
TreePatternNode &Dst = P.getDstPattern();
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
// If the root of either pattern isn't a simple operator, ignore it.
|
2017-04-13 09:45:37 +00:00
|
|
|
if (auto Err = isTrivialOperatorNode(Dst))
|
|
|
|
return failedImport("Dst pattern root isn't a trivial operator (" +
|
|
|
|
toString(std::move(Err)) + ")");
|
|
|
|
if (auto Err = isTrivialOperatorNode(Src))
|
|
|
|
return failedImport("Src pattern root isn't a trivial operator (" +
|
|
|
|
toString(std::move(Err)) + ")");
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2017-12-15 23:07:42 +00:00
|
|
|
// The different predicates and matchers created during
|
|
|
|
// addInstructionMatcher use the RuleMatcher M to set up their
|
|
|
|
// instruction ID (InsnVarID) that are going to be used when
|
|
|
|
// M is going to be emitted.
|
|
|
|
// However, the code doing the emission still relies on the IDs
|
|
|
|
// returned during that process by the RuleMatcher when issuing
|
|
|
|
// the recordInsn opcodes.
|
|
|
|
// Because of that:
|
|
|
|
// 1. The order in which we created the predicates
|
|
|
|
// and such must be the same as the order in which we emit them,
|
|
|
|
// and
|
|
|
|
// 2. We need to reset the generation of the IDs in M somewhere between
|
|
|
|
// addInstructionMatcher and emit
|
|
|
|
//
|
|
|
|
// FIXME: Long term, we don't want to have to rely on this implicit
|
|
|
|
// naming being the same. One possible solution would be to have
|
|
|
|
// explicit operator for operation capture and reference those.
|
|
|
|
// The plus side is that it would expose opportunities to share
|
|
|
|
// the capture accross rules. The downside is that it would
|
|
|
|
// introduce a dependency between predicates (captures must happen
|
|
|
|
// before their first use.)
|
2024-02-09 13:35:42 +00:00
|
|
|
InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(Src.getName());
|
Re-commit: [globalisel][tablegen] Support zero-instruction emission.
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.
The previous commit failed on Windows machines due to a flaw in the sort
predicate which allowed both A < B < C and B == C to be satisfied
simultaneously. The cause of this was some sloppiness in the priority order of
G_CONSTANT instructions compared to other instructions. These had equal priority
because it makes no difference, however there were operands had higher priority
than G_CONSTANT but lower priority than any other instruction. As a result, a
priority order between G_CONSTANT and other instructions must be enforced to
ensure the predicate defines a strict weak order.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36084
llvm-svn: 311076
2017-08-17 09:26:14 +00:00
|
|
|
unsigned TempOpIdx = 0;
|
2023-01-25 14:06:09 +01:00
|
|
|
|
|
|
|
const auto SavedFlags = M.setGISelFlags(P.getSrcRecord());
|
|
|
|
|
Re-commit: [globalisel][tablegen] Support zero-instruction emission.
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.
The previous commit failed on Windows machines due to a flaw in the sort
predicate which allowed both A < B < C and B == C to be satisfied
simultaneously. The cause of this was some sloppiness in the priority order of
G_CONSTANT instructions compared to other instructions. These had equal priority
because it makes no difference, however there were operands had higher priority
than G_CONSTANT but lower priority than any other instruction. As a result, a
priority order between G_CONSTANT and other instructions must be enforced to
ensure the predicate defines a strict weak order.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36084
llvm-svn: 311076
2017-08-17 09:26:14 +00:00
|
|
|
auto InsnMatcherOrError =
|
2017-10-15 18:22:54 +00:00
|
|
|
createAndImportSelDAGMatcher(M, InsnMatcherTemp, Src, TempOpIdx);
|
Re-commit: [globalisel][tablegen] Support zero-instruction emission.
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.
The previous commit failed on Windows machines due to a flaw in the sort
predicate which allowed both A < B < C and B == C to be satisfied
simultaneously. The cause of this was some sloppiness in the priority order of
G_CONSTANT instructions compared to other instructions. These had equal priority
because it makes no difference, however there were operands had higher priority
than G_CONSTANT but lower priority than any other instruction. As a result, a
priority order between G_CONSTANT and other instructions must be enforced to
ensure the predicate defines a strict weak order.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36084
llvm-svn: 311076
2017-08-17 09:26:14 +00:00
|
|
|
if (auto Error = InsnMatcherOrError.takeError())
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
Re-commit: [globalisel][tablegen] Support zero-instruction emission.
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.
The previous commit failed on Windows machines due to a flaw in the sort
predicate which allowed both A < B < C and B == C to be satisfied
simultaneously. The cause of this was some sloppiness in the priority order of
G_CONSTANT instructions compared to other instructions. These had equal priority
because it makes no difference, however there were operands had higher priority
than G_CONSTANT but lower priority than any other instruction. As a result, a
priority order between G_CONSTANT and other instructions must be enforced to
ensure the predicate defines a strict weak order.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36084
llvm-svn: 311076
2017-08-17 09:26:14 +00:00
|
|
|
InstructionMatcher &InsnMatcher = InsnMatcherOrError.get();
|
|
|
|
|
2024-02-09 13:35:42 +00:00
|
|
|
if (Dst.isLeaf()) {
|
2024-09-23 13:07:31 -07:00
|
|
|
if (const Record *RCDef = getInitValueAsRegClass(Dst.getLeafValue())) {
|
2020-11-24 07:12:54 +01:00
|
|
|
const CodeGenRegisterClass &RC = Target.getRegisterClass(RCDef);
|
|
|
|
|
Re-commit: [globalisel][tablegen] Support zero-instruction emission.
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.
The previous commit failed on Windows machines due to a flaw in the sort
predicate which allowed both A < B < C and B == C to be satisfied
simultaneously. The cause of this was some sloppiness in the priority order of
G_CONSTANT instructions compared to other instructions. These had equal priority
because it makes no difference, however there were operands had higher priority
than G_CONSTANT but lower priority than any other instruction. As a result, a
priority order between G_CONSTANT and other instructions must be enforced to
ensure the predicate defines a strict weak order.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36084
llvm-svn: 311076
2017-08-17 09:26:14 +00:00
|
|
|
// We need to replace the def and all its uses with the specified
|
|
|
|
// operand. However, we must also insert COPY's wherever needed.
|
|
|
|
// For now, emit a copy and let the register allocator clean up.
|
|
|
|
auto &DstI = Target.getInstruction(RK.getDef("COPY"));
|
|
|
|
const auto &DstIOperand = DstI.Operands[0];
|
|
|
|
|
|
|
|
OperandMatcher &OM0 = InsnMatcher.getOperand(0);
|
|
|
|
OM0.setSymbolicName(DstIOperand.Name);
|
2017-10-14 00:31:58 +00:00
|
|
|
M.defineOperand(OM0.getSymbolicName(), OM0);
|
Re-commit: [globalisel][tablegen] Support zero-instruction emission.
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.
The previous commit failed on Windows machines due to a flaw in the sort
predicate which allowed both A < B < C and B == C to be satisfied
simultaneously. The cause of this was some sloppiness in the priority order of
G_CONSTANT instructions compared to other instructions. These had equal priority
because it makes no difference, however there were operands had higher priority
than G_CONSTANT but lower priority than any other instruction. As a result, a
priority order between G_CONSTANT and other instructions must be enforced to
ensure the predicate defines a strict weak order.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36084
llvm-svn: 311076
2017-08-17 09:26:14 +00:00
|
|
|
OM0.addPredicate<RegisterBankOperandMatcher>(RC);
|
|
|
|
|
2017-11-01 00:29:47 +00:00
|
|
|
auto &DstMIBuilder =
|
|
|
|
M.addAction<BuildMIAction>(M.allocateOutputInsnID(), &DstI);
|
|
|
|
DstMIBuilder.addRenderer<CopyRenderer>(DstIOperand.Name);
|
2024-02-09 13:35:42 +00:00
|
|
|
DstMIBuilder.addRenderer<CopyRenderer>(Dst.getName());
|
Re-commit: [globalisel][tablegen] Support zero-instruction emission.
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.
The previous commit failed on Windows machines due to a flaw in the sort
predicate which allowed both A < B < C and B == C to be satisfied
simultaneously. The cause of this was some sloppiness in the priority order of
G_CONSTANT instructions compared to other instructions. These had equal priority
because it makes no difference, however there were operands had higher priority
than G_CONSTANT but lower priority than any other instruction. As a result, a
priority order between G_CONSTANT and other instructions must be enforced to
ensure the predicate defines a strict weak order.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36084
llvm-svn: 311076
2017-08-17 09:26:14 +00:00
|
|
|
M.addAction<ConstrainOperandToRegClassAction>(0, 0, RC);
|
|
|
|
|
[GISel] Erase the root instruction after emitting all its potential uses (#77494)
This tries to fix a bug by resolving a few FIXMEs. The bug is that
`EraseInstAction` is emitted after emitting the _first_ `BuildMIAction`,
which is too early because the erased instruction may still be used by
subsequent `BuildMIAction`s (in particular, by `CopyRenderer`).
An example of the bug (from `match-table-operand-types.td`):
```
def InstTest0 : GICombineRule<
(defs root:$a),
(match (G_MUL i32:$x, i32:$b, i32:$c),
(G_MUL $a, i32:$b, i32:$x)),
(apply (G_ADD i64:$tmp, $b, i32:$c),
(G_ADD i8:$a, $b, i64:$tmp))>;
GIR_EraseFromParent, /*InsnID*/0,
GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::G_ADD),
GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/0, // a
GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // b
GIR_AddSimpleTempRegister, /*InsnID*/1, /*TempRegID*/0,
```
Here, the root instruction is destroyed before copying its operands ('a'
and 'b') to the new instruction.
The solution is to emit `EraseInstAction` for the root instruction as
the last action in the emission pipeline.
2024-01-13 11:17:41 +03:00
|
|
|
// Erase the root.
|
|
|
|
unsigned RootInsnID = M.getInsnVarID(InsnMatcher);
|
|
|
|
M.addAction<EraseInstAction>(RootInsnID);
|
|
|
|
|
Re-commit: [globalisel][tablegen] Support zero-instruction emission.
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.
The previous commit failed on Windows machines due to a flaw in the sort
predicate which allowed both A < B < C and B == C to be satisfied
simultaneously. The cause of this was some sloppiness in the priority order of
G_CONSTANT instructions compared to other instructions. These had equal priority
because it makes no difference, however there were operands had higher priority
than G_CONSTANT but lower priority than any other instruction. As a result, a
priority order between G_CONSTANT and other instructions must be enforced to
ensure the predicate defines a strict weak order.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36084
llvm-svn: 311076
2017-08-17 09:26:14 +00:00
|
|
|
// We're done with this pattern! It's eligible for GISel emission; return
|
|
|
|
// it.
|
|
|
|
++NumPatternImported;
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(M);
|
Re-commit: [globalisel][tablegen] Support zero-instruction emission.
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.
The previous commit failed on Windows machines due to a flaw in the sort
predicate which allowed both A < B < C and B == C to be satisfied
simultaneously. The cause of this was some sloppiness in the priority order of
G_CONSTANT instructions compared to other instructions. These had equal priority
because it makes no difference, however there were operands had higher priority
than G_CONSTANT but lower priority than any other instruction. As a result, a
priority order between G_CONSTANT and other instructions must be enforced to
ensure the predicate defines a strict weak order.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36084
llvm-svn: 311076
2017-08-17 09:26:14 +00:00
|
|
|
}
|
|
|
|
|
2017-05-23 19:33:16 +00:00
|
|
|
return failedImport("Dst pattern root isn't a known leaf");
|
Re-commit: [globalisel][tablegen] Support zero-instruction emission.
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.
The previous commit failed on Windows machines due to a flaw in the sort
predicate which allowed both A < B < C and B == C to be satisfied
simultaneously. The cause of this was some sloppiness in the priority order of
G_CONSTANT instructions compared to other instructions. These had equal priority
because it makes no difference, however there were operands had higher priority
than G_CONSTANT but lower priority than any other instruction. As a result, a
priority order between G_CONSTANT and other instructions must be enforced to
ensure the predicate defines a strict weak order.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar
Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D36084
llvm-svn: 311076
2017-08-17 09:26:14 +00:00
|
|
|
}
|
2017-05-23 19:33:16 +00:00
|
|
|
|
[tablegen][globalisel] Add support for nested instruction matching.
Summary:
Lift the restrictions that prevented the tree walking introduced in the
previous change and add support for patterns like:
(G_ADD (G_MUL (G_SEXT $src1), (G_SEXT $src2)), $src3) -> SMADDWrrr $dst, $src1, $src2, $src3
Also adds support for G_SEXT and G_ZEXT to support these cases.
One particular aspect of this that I should draw attention to is that I've
tried to be overly conservative in determining the safety of matches that
involve non-adjacent instructions and multiple basic blocks. This is intended
to be used as a cheap initial check and we may add a more expensive check in
the future. The current rules are:
* Reject if any instruction may load/store (we'd need to check for intervening
memory operations.
* Reject if any instruction has implicit operands.
* Reject if any instruction has unmodelled side-effects.
See isObviouslySafeToFold().
Reviewers: t.p.northover, javed.absar, qcolombet, aditya_nandakumar, ab, rovka
Reviewed By: ab
Subscribers: igorb, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30539
llvm-svn: 299430
2017-04-04 13:25:23 +00:00
|
|
|
// Start with the defined operands (i.e., the results of the root operator).
|
2024-09-11 08:52:26 -07:00
|
|
|
const Record *DstOp = Dst.getOperator();
|
2017-03-29 15:37:18 +00:00
|
|
|
if (!DstOp->isSubClassOf("Instruction"))
|
|
|
|
return failedImport("Pattern operator isn't an instruction");
|
2017-03-14 21:32:08 +00:00
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
auto &DstI = Target.getInstruction(DstOp);
|
2019-09-04 16:19:34 +00:00
|
|
|
StringRef DstIName = DstI.TheDef->getName();
|
|
|
|
|
2024-10-18 05:50:44 -04:00
|
|
|
// Count both implicit and explicit defs in the dst instruction.
|
|
|
|
// This avoids errors importing patterns that have inherent implicit defs.
|
|
|
|
unsigned DstExpDefs = DstI.Operands.NumDefs,
|
|
|
|
DstNumDefs = DstI.ImplicitDefs.size() + DstExpDefs,
|
2024-02-09 13:35:42 +00:00
|
|
|
SrcNumDefs = Src.getExtTypes().size();
|
2022-05-08 21:24:52 +05:30
|
|
|
if (DstNumDefs < SrcNumDefs) {
|
|
|
|
if (DstNumDefs != 0)
|
|
|
|
return failedImport("Src pattern result has more defs than dst MI (" +
|
|
|
|
to_string(SrcNumDefs) + " def(s) vs " +
|
|
|
|
to_string(DstNumDefs) + " def(s))");
|
|
|
|
|
|
|
|
bool FoundNoUsePred = false;
|
|
|
|
for (const auto &Pred : InsnMatcher.predicates()) {
|
|
|
|
if ((FoundNoUsePred = isa<NoUsePredicateMatcher>(Pred.get())))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!FoundNoUsePred)
|
|
|
|
return failedImport("Src pattern result has " + to_string(SrcNumDefs) +
|
|
|
|
" def(s) without the HasNoUse predicate set to true "
|
|
|
|
"but Dst MI has no def");
|
|
|
|
}
|
[globalisel] Decouple src pattern operands from dst pattern operands.
Summary:
This isn't testable for AArch64 by itself so this patch also adds
support for constant immediates in the pattern and physical
register uses in the result.
The new IntOperandMatcher matches the constant in patterns such as
'(set $rd:GPR32, (G_XOR $rs:GPR32, -1))'. It's always safe to fold
immediates into an instruction so this is the first rule that will match
across multiple BB's.
The Renderer hierarchy is responsible for adding operands to the result
instruction. Renderers can copy operands (CopyRenderer) or add physical
registers (in particular %wzr and %xzr) to the result instruction
in any order (OperandMatchers now import the operand names from
SelectionDAG to allow renderers to access any operand). This allows us to
emit the result instruction for:
%1 = G_XOR %0, -1 --> %1 = ORNWrr %wzr, %0
%1 = G_XOR -1, %0 --> %1 = ORNWrr %wzr, %0
although the latter is untested since the matcher/importer has not been
taught about commutativity yet.
Added BuildMIAction which can build new instructions and mutate them where
possible. W.r.t the mutation aspect, MatchActions are now told the name of
an instruction they can recycle and BuildMIAction will emit mutation code
when the renderers are appropriate. They are appropriate when all operands
are rendered using CopyRenderer and the indices are the same as the matcher.
This currently assumes that all operands have at least one matcher.
Finally, this change also fixes a crash in
AArch64InstructionSelector::select() caused by an immediate operand
passing isImm() rather than isCImm(). This was uncovered by the other
changes and was detected by existing tests.
Depends on D29711
Reviewers: t.p.northover, ab, qcolombet, rovka, aditya_nandakumar, javed.absar
Reviewed By: rovka
Subscribers: aemerson, dberris, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D29712
llvm-svn: 296131
2017-02-24 15:43:30 +00:00
|
|
|
|
2017-03-29 15:37:18 +00:00
|
|
|
// The root of the match also has constraints on the register bank so that it
|
|
|
|
// matches the result instruction.
|
|
|
|
unsigned OpIdx = 0;
|
2024-10-18 05:50:44 -04:00
|
|
|
unsigned N = std::min(DstExpDefs, SrcNumDefs);
|
2022-05-08 21:24:52 +05:30
|
|
|
for (unsigned I = 0; I < N; ++I) {
|
2024-02-09 13:35:42 +00:00
|
|
|
const TypeSetByHwMode &VTy = Src.getExtType(I);
|
2017-03-29 15:37:18 +00:00
|
|
|
|
|
|
|
const auto &DstIOperand = DstI.Operands[OpIdx];
|
2024-09-09 14:33:21 -07:00
|
|
|
PointerUnion<const Record *, const CodeGenRegisterClass *> MatchedRC =
|
2023-12-10 13:25:11 +03:00
|
|
|
DstIOperand.Rec;
|
2019-09-04 16:19:34 +00:00
|
|
|
if (DstIName == "COPY_TO_REGCLASS") {
|
2024-02-09 13:35:42 +00:00
|
|
|
MatchedRC = getInitValueAsRegClass(Dst.getChild(1).getLeafValue());
|
2017-06-20 12:36:34 +00:00
|
|
|
|
2023-12-10 13:25:11 +03:00
|
|
|
if (MatchedRC.isNull())
|
2017-06-20 12:36:34 +00:00
|
|
|
return failedImport(
|
|
|
|
"COPY_TO_REGCLASS operand #1 isn't a register class");
|
2019-09-04 16:19:34 +00:00
|
|
|
} else if (DstIName == "REG_SEQUENCE") {
|
2024-02-09 13:35:42 +00:00
|
|
|
MatchedRC = getInitValueAsRegClass(Dst.getChild(0).getLeafValue());
|
2023-12-10 13:25:11 +03:00
|
|
|
if (MatchedRC.isNull())
|
2019-09-04 16:19:34 +00:00
|
|
|
return failedImport("REG_SEQUENCE operand #0 isn't a register class");
|
|
|
|
} else if (DstIName == "EXTRACT_SUBREG") {
|
2024-02-09 13:35:42 +00:00
|
|
|
auto InferredClass = inferRegClassFromPattern(Dst.getChild(0));
|
2020-01-14 16:02:02 -05:00
|
|
|
if (!InferredClass)
|
2023-06-23 11:42:51 +02:00
|
|
|
return failedImport(
|
|
|
|
"Could not infer class for EXTRACT_SUBREG operand #0");
|
2017-06-27 10:11:39 +00:00
|
|
|
|
2017-06-28 13:50:04 +00:00
|
|
|
// We can assume that a subregister is in the same bank as it's super
|
|
|
|
// register.
|
2023-12-10 13:25:11 +03:00
|
|
|
MatchedRC = (*InferredClass)->getDef();
|
2019-09-04 16:19:34 +00:00
|
|
|
} else if (DstIName == "INSERT_SUBREG") {
|
2024-02-09 13:35:42 +00:00
|
|
|
auto MaybeSuperClass =
|
|
|
|
inferSuperRegisterClassForNode(VTy, Dst.getChild(0), Dst.getChild(2));
|
2019-08-27 17:47:06 +00:00
|
|
|
if (!MaybeSuperClass)
|
2017-06-27 10:11:39 +00:00
|
|
|
return failedImport(
|
2019-08-27 17:47:06 +00:00
|
|
|
"Cannot infer register class for INSERT_SUBREG operand #0");
|
|
|
|
// Move to the next pattern here, because the register class we found
|
|
|
|
// doesn't necessarily have a record associated with it. So, we can't
|
|
|
|
// set DstIOpRec using this.
|
2023-12-10 13:25:11 +03:00
|
|
|
MatchedRC = *MaybeSuperClass;
|
2019-09-04 16:19:34 +00:00
|
|
|
} else if (DstIName == "SUBREG_TO_REG") {
|
2024-02-09 13:35:42 +00:00
|
|
|
auto MaybeRegClass = inferSuperRegisterClass(VTy, Dst.getChild(2));
|
2019-08-28 20:12:31 +00:00
|
|
|
if (!MaybeRegClass)
|
|
|
|
return failedImport(
|
|
|
|
"Cannot infer register class for SUBREG_TO_REG operand #0");
|
2023-12-10 13:25:11 +03:00
|
|
|
MatchedRC = *MaybeRegClass;
|
2024-09-09 14:33:21 -07:00
|
|
|
} else if (MatchedRC.get<const Record *>()->isSubClassOf("RegisterOperand"))
|
|
|
|
MatchedRC = MatchedRC.get<const Record *>()->getValueAsDef("RegClass");
|
|
|
|
else if (!MatchedRC.get<const Record *>()->isSubClassOf("RegisterClass"))
|
2024-02-09 13:35:42 +00:00
|
|
|
return failedImport("Dst MI def isn't a register class" + to_string(Dst));
|
2017-03-29 15:37:18 +00:00
|
|
|
|
|
|
|
OperandMatcher &OM = InsnMatcher.getOperand(OpIdx);
|
2023-12-10 13:25:11 +03:00
|
|
|
// The operand names declared in the DstI instruction are unrelated to
|
|
|
|
// those used in pattern's source and destination DAGs, so mangle the
|
|
|
|
// former to prevent implicitly adding unexpected
|
|
|
|
// GIM_CheckIsSameOperand predicates by the defineOperand method.
|
|
|
|
OM.setSymbolicName(getMangledRootDefName(DstIOperand.Name));
|
2017-10-14 00:31:58 +00:00
|
|
|
M.defineOperand(OM.getSymbolicName(), OM);
|
2024-09-09 14:33:21 -07:00
|
|
|
if (MatchedRC.is<const Record *>())
|
|
|
|
MatchedRC = &Target.getRegisterClass(MatchedRC.get<const Record *>());
|
2017-03-29 15:37:18 +00:00
|
|
|
OM.addPredicate<RegisterBankOperandMatcher>(
|
2023-12-10 13:25:11 +03:00
|
|
|
*MatchedRC.get<const CodeGenRegisterClass *>());
|
2017-03-29 15:37:18 +00:00
|
|
|
++OpIdx;
|
2016-12-21 23:26:20 +00:00
|
|
|
}
|
|
|
|
|
2019-09-06 20:32:37 +00:00
|
|
|
auto DstMIBuilderOrError =
|
|
|
|
createAndImportInstructionRenderer(M, InsnMatcher, Src, Dst);
|
2017-03-29 15:37:18 +00:00
|
|
|
if (auto Error = DstMIBuilderOrError.takeError())
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2017-03-29 15:37:18 +00:00
|
|
|
BuildMIAction &DstMIBuilder = DstMIBuilderOrError.get();
|
|
|
|
|
|
|
|
// Render the implicit defs.
|
|
|
|
// These are only added to the root of the result.
|
2017-03-30 09:36:33 +00:00
|
|
|
if (auto Error = importImplicitDefRenderers(DstMIBuilder, P.getDstRegs()))
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(Error);
|
2017-03-29 15:37:18 +00:00
|
|
|
|
2017-10-31 18:50:24 +00:00
|
|
|
DstMIBuilder.chooseInsnToMutate(M);
|
|
|
|
|
2017-06-20 12:36:34 +00:00
|
|
|
// Constrain the registers to classes. This is normally derived from the
|
|
|
|
// emitted instruction but a few instructions require special handling.
|
2024-11-07 07:16:54 +03:00
|
|
|
if (auto Error =
|
|
|
|
constrainOperands(M.actions_end(), M, DstMIBuilder.getInsnID(), Dst))
|
|
|
|
return std::move(Error);
|
2020-04-07 09:32:51 -04:00
|
|
|
|
[GISel] Erase the root instruction after emitting all its potential uses (#77494)
This tries to fix a bug by resolving a few FIXMEs. The bug is that
`EraseInstAction` is emitted after emitting the _first_ `BuildMIAction`,
which is too early because the erased instruction may still be used by
subsequent `BuildMIAction`s (in particular, by `CopyRenderer`).
An example of the bug (from `match-table-operand-types.td`):
```
def InstTest0 : GICombineRule<
(defs root:$a),
(match (G_MUL i32:$x, i32:$b, i32:$c),
(G_MUL $a, i32:$b, i32:$x)),
(apply (G_ADD i64:$tmp, $b, i32:$c),
(G_ADD i8:$a, $b, i64:$tmp))>;
GIR_EraseFromParent, /*InsnID*/0,
GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::G_ADD),
GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/0, // a
GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // b
GIR_AddSimpleTempRegister, /*InsnID*/1, /*TempRegID*/0,
```
Here, the root instruction is destroyed before copying its operands ('a'
and 'b') to the new instruction.
The solution is to emit `EraseInstAction` for the root instruction as
the last action in the emission pipeline.
2024-01-13 11:17:41 +03:00
|
|
|
// Erase the root.
|
|
|
|
unsigned RootInsnID = M.getInsnVarID(InsnMatcher);
|
|
|
|
M.addAction<EraseInstAction>(RootInsnID);
|
2017-06-20 12:36:34 +00:00
|
|
|
|
2017-02-10 04:00:17 +00:00
|
|
|
// We're done with this pattern! It's eligible for GISel emission; return it.
|
2017-02-20 14:31:27 +00:00
|
|
|
++NumPatternImported;
|
2020-02-10 07:06:45 -08:00
|
|
|
return std::move(M);
|
2016-12-21 23:26:20 +00:00
|
|
|
}
|
|
|
|
|
2018-05-02 20:08:14 +00:00
|
|
|
MatchTable
|
|
|
|
GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules,
|
2018-05-02 20:15:11 +00:00
|
|
|
bool Optimize, bool WithCoverage) {
|
2018-05-02 20:08:14 +00:00
|
|
|
std::vector<Matcher *> InputRules;
|
|
|
|
for (Matcher &Rule : Rules)
|
|
|
|
InputRules.push_back(&Rule);
|
|
|
|
|
|
|
|
if (!Optimize)
|
2018-05-02 20:15:11 +00:00
|
|
|
return MatchTable::buildTable(InputRules, WithCoverage);
|
2018-05-02 20:08:14 +00:00
|
|
|
|
2018-05-22 16:54:27 +00:00
|
|
|
unsigned CurrentOrdering = 0;
|
|
|
|
StringMap<unsigned> OpcodeOrder;
|
|
|
|
for (RuleMatcher &Rule : Rules) {
|
|
|
|
const StringRef Opcode = Rule.getOpcode();
|
|
|
|
assert(!Opcode.empty() && "Didn't expect an undefined opcode");
|
|
|
|
if (OpcodeOrder.count(Opcode) == 0)
|
|
|
|
OpcodeOrder[Opcode] = CurrentOrdering++;
|
|
|
|
}
|
|
|
|
|
2021-01-13 19:14:42 -08:00
|
|
|
llvm::stable_sort(InputRules, [&OpcodeOrder](const Matcher *A,
|
|
|
|
const Matcher *B) {
|
|
|
|
auto *L = static_cast<const RuleMatcher *>(A);
|
|
|
|
auto *R = static_cast<const RuleMatcher *>(B);
|
2024-08-01 08:30:20 +02:00
|
|
|
return std::tuple(OpcodeOrder[L->getOpcode()],
|
|
|
|
L->insnmatchers_front().getNumOperandMatchers()) <
|
|
|
|
std::tuple(OpcodeOrder[R->getOpcode()],
|
|
|
|
R->insnmatchers_front().getNumOperandMatchers());
|
2021-01-13 19:14:42 -08:00
|
|
|
});
|
2018-05-22 16:54:27 +00:00
|
|
|
|
2018-05-21 23:28:51 +00:00
|
|
|
for (Matcher *Rule : InputRules)
|
|
|
|
Rule->optimize();
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<Matcher>> MatcherStorage;
|
2018-05-02 20:08:14 +00:00
|
|
|
std::vector<Matcher *> OptRules =
|
2018-05-21 23:28:51 +00:00
|
|
|
optimizeRules<GroupMatcher>(InputRules, MatcherStorage);
|
|
|
|
|
|
|
|
for (Matcher *Rule : OptRules)
|
|
|
|
Rule->optimize();
|
2018-05-02 20:08:14 +00:00
|
|
|
|
[GlobalISel][InstructionSelect] Switching MatchTable over opcodes, perf patch 4
This patch continues a series of patches started by r332907 (reapplied
as r332917)
In this commit we introduce a new matching opcode GIM_SwitchOpcode
that implements a jump table over opcodes and start emitting them for
root instructions.
This is expected to decrease time GlobalISel spends in its
InstructionSelect pass by roughly 20% for an -O0 build as measured on
sqlite3-amalgamation (http://sqlite.org/download.html) targeting
AArch64.
To some degree, we assume here that the opcodes form a dense set,
which is true at the moment for all upstream targets given the
limitations of our rule importing mechanism.
It might not be true for out of tree targets, specifically due to
pseudo's. If so, we might noticeably increase the size of the
MatchTable with this patch due to padding zeros. This will be
addressed later.
Reviewers: qcolombet, dsanders, bogner, aemerson, javed.absar
Reviewed By: qcolombet
Subscribers: rovka, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D44700
llvm-svn: 333017
2018-05-22 19:37:59 +00:00
|
|
|
OptRules = optimizeRules<SwitchMatcher>(OptRules, MatcherStorage);
|
|
|
|
|
2018-05-02 20:15:11 +00:00
|
|
|
return MatchTable::buildTable(OptRules, WithCoverage);
|
2018-05-02 20:08:14 +00:00
|
|
|
}
|
|
|
|
|
2023-06-26 11:44:18 +02:00
|
|
|
void GlobalISelEmitter::emitAdditionalImpl(raw_ostream &OS) {
|
|
|
|
OS << "bool " << getClassName()
|
|
|
|
<< "::selectImpl(MachineInstr &I, CodeGenCoverage "
|
|
|
|
"&CoverageInfo) const {\n"
|
|
|
|
<< " const PredicateBitset AvailableFeatures = "
|
|
|
|
"getAvailableFeatures();\n"
|
2023-10-16 07:41:18 +02:00
|
|
|
<< " MachineIRBuilder B(I);\n"
|
2023-06-26 11:44:18 +02:00
|
|
|
<< " State.MIs.clear();\n"
|
|
|
|
<< " State.MIs.push_back(&I);\n\n"
|
2023-10-16 07:41:18 +02:00
|
|
|
<< " if (executeMatchTable(*this, State, ExecInfo, B"
|
2023-06-26 13:23:18 +02:00
|
|
|
<< ", getMatchTable(), TII, MF->getRegInfo(), TRI, RBI, AvailableFeatures"
|
2023-06-26 11:44:18 +02:00
|
|
|
<< ", &CoverageInfo)) {\n"
|
|
|
|
<< " return true;\n"
|
|
|
|
<< " }\n\n"
|
|
|
|
<< " return false;\n"
|
|
|
|
<< "}\n\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalISelEmitter::emitMIPredicateFns(raw_ostream &OS) {
|
2024-09-30 06:37:36 -07:00
|
|
|
std::vector<const Record *> MatchedRecords;
|
2023-06-26 11:44:18 +02:00
|
|
|
std::copy_if(AllPatFrags.begin(), AllPatFrags.end(),
|
2024-09-30 06:37:36 -07:00
|
|
|
std::back_inserter(MatchedRecords), [](const Record *R) {
|
2023-06-26 11:44:18 +02:00
|
|
|
return !R->getValueAsString("GISelPredicateCode").empty();
|
|
|
|
});
|
2024-09-30 06:37:36 -07:00
|
|
|
emitMIPredicateFnsImpl<const Record *>(
|
2023-06-26 11:44:18 +02:00
|
|
|
OS,
|
|
|
|
" const MachineFunction &MF = *MI.getParent()->getParent();\n"
|
|
|
|
" const MachineRegisterInfo &MRI = MF.getRegInfo();\n"
|
|
|
|
" const auto &Operands = State.RecordedOperands;\n"
|
|
|
|
" (void)Operands;\n"
|
|
|
|
" (void)MRI;",
|
2024-09-30 06:37:36 -07:00
|
|
|
ArrayRef<const Record *>(MatchedRecords), &getPatFragPredicateEnumName,
|
|
|
|
[](const Record *R) { return R->getValueAsString("GISelPredicateCode"); },
|
2023-06-26 11:44:18 +02:00
|
|
|
"PatFrag predicates.");
|
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalISelEmitter::emitI64ImmPredicateFns(raw_ostream &OS) {
|
2024-09-30 06:37:36 -07:00
|
|
|
std::vector<const Record *> MatchedRecords;
|
2023-06-26 11:44:18 +02:00
|
|
|
std::copy_if(AllPatFrags.begin(), AllPatFrags.end(),
|
2024-09-30 06:37:36 -07:00
|
|
|
std::back_inserter(MatchedRecords), [](const Record *R) {
|
2023-06-26 11:44:18 +02:00
|
|
|
bool Unset;
|
|
|
|
return !R->getValueAsString("ImmediateCode").empty() &&
|
|
|
|
!R->getValueAsBitOrUnset("IsAPFloat", Unset) &&
|
|
|
|
!R->getValueAsBit("IsAPInt");
|
|
|
|
});
|
2024-09-30 06:37:36 -07:00
|
|
|
emitImmPredicateFnsImpl<const Record *>(
|
|
|
|
OS, "I64", "int64_t", ArrayRef<const Record *>(MatchedRecords),
|
2023-06-26 11:44:18 +02:00
|
|
|
&getPatFragPredicateEnumName,
|
2024-09-30 06:37:36 -07:00
|
|
|
[](const Record *R) { return R->getValueAsString("ImmediateCode"); },
|
2023-06-26 11:44:18 +02:00
|
|
|
"PatFrag predicates.");
|
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalISelEmitter::emitAPFloatImmPredicateFns(raw_ostream &OS) {
|
2024-09-30 06:37:36 -07:00
|
|
|
std::vector<const Record *> MatchedRecords;
|
2023-06-26 11:44:18 +02:00
|
|
|
std::copy_if(AllPatFrags.begin(), AllPatFrags.end(),
|
2024-09-30 06:37:36 -07:00
|
|
|
std::back_inserter(MatchedRecords), [](const Record *R) {
|
2023-06-26 11:44:18 +02:00
|
|
|
bool Unset;
|
|
|
|
return !R->getValueAsString("ImmediateCode").empty() &&
|
|
|
|
R->getValueAsBitOrUnset("IsAPFloat", Unset);
|
|
|
|
});
|
2024-09-30 06:37:36 -07:00
|
|
|
emitImmPredicateFnsImpl<const Record *>(
|
|
|
|
OS, "APFloat", "const APFloat &",
|
|
|
|
ArrayRef<const Record *>(MatchedRecords), &getPatFragPredicateEnumName,
|
|
|
|
[](const Record *R) { return R->getValueAsString("ImmediateCode"); },
|
2023-06-26 11:44:18 +02:00
|
|
|
"PatFrag predicates.");
|
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalISelEmitter::emitAPIntImmPredicateFns(raw_ostream &OS) {
|
2024-09-30 06:37:36 -07:00
|
|
|
std::vector<const Record *> MatchedRecords;
|
2023-06-26 11:44:18 +02:00
|
|
|
std::copy_if(AllPatFrags.begin(), AllPatFrags.end(),
|
2024-09-30 06:37:36 -07:00
|
|
|
std::back_inserter(MatchedRecords), [](const Record *R) {
|
2023-06-26 11:44:18 +02:00
|
|
|
return !R->getValueAsString("ImmediateCode").empty() &&
|
|
|
|
R->getValueAsBit("IsAPInt");
|
|
|
|
});
|
2024-09-30 06:37:36 -07:00
|
|
|
emitImmPredicateFnsImpl<const Record *>(
|
|
|
|
OS, "APInt", "const APInt &", ArrayRef<const Record *>(MatchedRecords),
|
2023-06-26 11:44:18 +02:00
|
|
|
&getPatFragPredicateEnumName,
|
2024-09-30 06:37:36 -07:00
|
|
|
[](const Record *R) { return R->getValueAsString("ImmediateCode"); },
|
2023-06-26 11:44:18 +02:00
|
|
|
"PatFrag predicates.");
|
|
|
|
}
|
|
|
|
|
2023-06-26 13:23:18 +02:00
|
|
|
void GlobalISelEmitter::emitTestSimplePredicate(raw_ostream &OS) {
|
|
|
|
OS << "bool " << getClassName() << "::testSimplePredicate(unsigned) const {\n"
|
|
|
|
<< " llvm_unreachable(\"" + getClassName() +
|
|
|
|
" does not support simple predicates!\");\n"
|
|
|
|
<< " return false;\n"
|
|
|
|
<< "}\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalISelEmitter::emitRunCustomAction(raw_ostream &OS) {
|
2024-05-16 13:39:00 +02:00
|
|
|
OS << "bool " << getClassName()
|
2023-07-25 13:45:18 +02:00
|
|
|
<< "::runCustomAction(unsigned, const MatcherState&, NewMIVector &) const "
|
|
|
|
"{\n"
|
2023-06-26 13:23:18 +02:00
|
|
|
<< " llvm_unreachable(\"" + getClassName() +
|
|
|
|
" does not support custom C++ actions!\");\n"
|
|
|
|
<< "}\n";
|
|
|
|
}
|
|
|
|
|
2023-08-07 12:59:24 +02:00
|
|
|
void GlobalISelEmitter::postProcessRule(RuleMatcher &M) {
|
2024-09-18 22:27:26 -07:00
|
|
|
SmallPtrSet<const Record *, 16> UsedRegs;
|
2023-08-07 12:59:24 +02:00
|
|
|
|
|
|
|
// TODO: deal with subregs?
|
|
|
|
for (auto &A : M.actions()) {
|
|
|
|
auto *MI = dyn_cast<BuildMIAction>(A.get());
|
|
|
|
if (!MI)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (auto *Use : MI->getCGI()->ImplicitUses)
|
|
|
|
UsedRegs.insert(Use);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &A : M.actions()) {
|
|
|
|
auto *MI = dyn_cast<BuildMIAction>(A.get());
|
|
|
|
if (!MI)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (auto *Def : MI->getCGI()->ImplicitDefs) {
|
|
|
|
if (!UsedRegs.contains(Def))
|
|
|
|
MI->setDeadImplicitDef(Def);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-21 23:26:20 +00:00
|
|
|
void GlobalISelEmitter::run(raw_ostream &OS) {
|
[globalisel][tablegen] Generate rule coverage and use it to identify untested rules
Summary:
This patch adds a LLVM_ENABLE_GISEL_COV which, like LLVM_ENABLE_DAGISEL_COV,
causes TableGen to instrument the generated table to collect rule coverage
information. However, LLVM_ENABLE_GISEL_COV goes a bit further than
LLVM_ENABLE_DAGISEL_COV. The information is written to files
(${CMAKE_BINARY_DIR}/gisel-coverage-* by default). These files can then be
concatenated into ${LLVM_GISEL_COV_PREFIX}-all after which TableGen will
read this information and use it to emit warnings about untested rules.
This technique could also be used by SelectionDAG and can be further
extended to detect hot rules and give them priority over colder rules.
Usage:
* Enable LLVM_ENABLE_GISEL_COV in CMake
* Build the compiler and run some tests
* cat gisel-coverage-[0-9]* > gisel-coverage-all
* Delete lib/Target/*/*GenGlobalISel.inc*
* Build the compiler
Known issues:
* ${LLVM_GISEL_COV_PREFIX}-all must be generated as a manual
step due to a lack of a portable 'cat' command. It should be the
concatenation of all ${LLVM_GISEL_COV_PREFIX}-[0-9]* files.
* There's no mechanism to discard coverage information when the ruleset
changes
Depends on D39742
Reviewers: ab, qcolombet, t.p.northover, aditya_nandakumar, rovka
Reviewed By: rovka
Subscribers: vsk, arsenm, nhaehnle, mgorny, kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D39747
llvm-svn: 318356
2017-11-16 00:46:35 +00:00
|
|
|
if (!UseCoverageFile.empty()) {
|
|
|
|
RuleCoverage = CodeGenCoverage();
|
|
|
|
auto RuleCoverageBufOrErr = MemoryBuffer::getFile(UseCoverageFile);
|
|
|
|
if (!RuleCoverageBufOrErr) {
|
|
|
|
PrintWarning(SMLoc(), "Missing rule coverage data");
|
2022-12-02 21:11:42 -08:00
|
|
|
RuleCoverage = std::nullopt;
|
[globalisel][tablegen] Generate rule coverage and use it to identify untested rules
Summary:
This patch adds a LLVM_ENABLE_GISEL_COV which, like LLVM_ENABLE_DAGISEL_COV,
causes TableGen to instrument the generated table to collect rule coverage
information. However, LLVM_ENABLE_GISEL_COV goes a bit further than
LLVM_ENABLE_DAGISEL_COV. The information is written to files
(${CMAKE_BINARY_DIR}/gisel-coverage-* by default). These files can then be
concatenated into ${LLVM_GISEL_COV_PREFIX}-all after which TableGen will
read this information and use it to emit warnings about untested rules.
This technique could also be used by SelectionDAG and can be further
extended to detect hot rules and give them priority over colder rules.
Usage:
* Enable LLVM_ENABLE_GISEL_COV in CMake
* Build the compiler and run some tests
* cat gisel-coverage-[0-9]* > gisel-coverage-all
* Delete lib/Target/*/*GenGlobalISel.inc*
* Build the compiler
Known issues:
* ${LLVM_GISEL_COV_PREFIX}-all must be generated as a manual
step due to a lack of a portable 'cat' command. It should be the
concatenation of all ${LLVM_GISEL_COV_PREFIX}-[0-9]* files.
* There's no mechanism to discard coverage information when the ruleset
changes
Depends on D39742
Reviewers: ab, qcolombet, t.p.northover, aditya_nandakumar, rovka
Reviewed By: rovka
Subscribers: vsk, arsenm, nhaehnle, mgorny, kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D39747
llvm-svn: 318356
2017-11-16 00:46:35 +00:00
|
|
|
} else {
|
|
|
|
if (!RuleCoverage->parse(*RuleCoverageBufOrErr.get(), Target.getName())) {
|
|
|
|
PrintWarning(SMLoc(), "Ignoring invalid or missing rule coverage data");
|
2022-12-02 21:11:42 -08:00
|
|
|
RuleCoverage = std::nullopt;
|
[globalisel][tablegen] Generate rule coverage and use it to identify untested rules
Summary:
This patch adds a LLVM_ENABLE_GISEL_COV which, like LLVM_ENABLE_DAGISEL_COV,
causes TableGen to instrument the generated table to collect rule coverage
information. However, LLVM_ENABLE_GISEL_COV goes a bit further than
LLVM_ENABLE_DAGISEL_COV. The information is written to files
(${CMAKE_BINARY_DIR}/gisel-coverage-* by default). These files can then be
concatenated into ${LLVM_GISEL_COV_PREFIX}-all after which TableGen will
read this information and use it to emit warnings about untested rules.
This technique could also be used by SelectionDAG and can be further
extended to detect hot rules and give them priority over colder rules.
Usage:
* Enable LLVM_ENABLE_GISEL_COV in CMake
* Build the compiler and run some tests
* cat gisel-coverage-[0-9]* > gisel-coverage-all
* Delete lib/Target/*/*GenGlobalISel.inc*
* Build the compiler
Known issues:
* ${LLVM_GISEL_COV_PREFIX}-all must be generated as a manual
step due to a lack of a portable 'cat' command. It should be the
concatenation of all ${LLVM_GISEL_COV_PREFIX}-[0-9]* files.
* There's no mechanism to discard coverage information when the ruleset
changes
Depends on D39742
Reviewers: ab, qcolombet, t.p.northover, aditya_nandakumar, rovka
Reviewed By: rovka
Subscribers: vsk, arsenm, nhaehnle, mgorny, kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D39747
llvm-svn: 318356
2017-11-16 00:46:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-21 23:28:51 +00:00
|
|
|
// Track the run-time opcode values
|
|
|
|
gatherOpcodeValues();
|
|
|
|
// Track the run-time LLT ID values
|
|
|
|
gatherTypeIDValues();
|
|
|
|
|
2016-12-21 23:26:20 +00:00
|
|
|
// Track the GINodeEquiv definitions.
|
|
|
|
gatherNodeEquivs();
|
|
|
|
|
2023-06-26 11:44:18 +02:00
|
|
|
AllPatFrags = RK.getAllDerivedDefinitions("PatFrags");
|
|
|
|
|
2023-06-23 11:42:51 +02:00
|
|
|
emitSourceFileHeader(
|
|
|
|
("Global Instruction Selector for the " + Target.getName() + " target")
|
|
|
|
.str(),
|
|
|
|
OS);
|
2017-02-20 14:31:27 +00:00
|
|
|
std::vector<RuleMatcher> Rules;
|
2016-12-21 23:26:20 +00:00
|
|
|
// Look through the SelectionDAG patterns we found, possibly emitting some.
|
|
|
|
for (const PatternToMatch &Pat : CGP.ptms()) {
|
|
|
|
++NumPatternTotal;
|
2017-11-11 03:23:44 +00:00
|
|
|
|
2024-04-25 13:42:48 -07:00
|
|
|
if (Pat.getGISelShouldIgnore())
|
|
|
|
continue; // skip without warning
|
2017-02-10 04:00:17 +00:00
|
|
|
auto MatcherOrErr = runOnPattern(Pat);
|
|
|
|
|
|
|
|
// The pattern analysis can fail, indicating an unsupported pattern.
|
|
|
|
// Report that if we've been asked to do so.
|
|
|
|
if (auto Err = MatcherOrErr.takeError()) {
|
2016-12-21 23:26:20 +00:00
|
|
|
if (WarnOnSkippedPatterns) {
|
|
|
|
PrintWarning(Pat.getSrcRecord()->getLoc(),
|
2017-02-10 04:00:17 +00:00
|
|
|
"Skipped pattern: " + toString(std::move(Err)));
|
|
|
|
} else {
|
|
|
|
consumeError(std::move(Err));
|
2016-12-21 23:26:20 +00:00
|
|
|
}
|
2017-02-20 14:31:27 +00:00
|
|
|
++NumPatternImportsSkipped;
|
2017-02-10 04:00:17 +00:00
|
|
|
continue;
|
2016-12-21 23:26:20 +00:00
|
|
|
}
|
2017-02-10 04:00:17 +00:00
|
|
|
|
[globalisel][tablegen] Generate rule coverage and use it to identify untested rules
Summary:
This patch adds a LLVM_ENABLE_GISEL_COV which, like LLVM_ENABLE_DAGISEL_COV,
causes TableGen to instrument the generated table to collect rule coverage
information. However, LLVM_ENABLE_GISEL_COV goes a bit further than
LLVM_ENABLE_DAGISEL_COV. The information is written to files
(${CMAKE_BINARY_DIR}/gisel-coverage-* by default). These files can then be
concatenated into ${LLVM_GISEL_COV_PREFIX}-all after which TableGen will
read this information and use it to emit warnings about untested rules.
This technique could also be used by SelectionDAG and can be further
extended to detect hot rules and give them priority over colder rules.
Usage:
* Enable LLVM_ENABLE_GISEL_COV in CMake
* Build the compiler and run some tests
* cat gisel-coverage-[0-9]* > gisel-coverage-all
* Delete lib/Target/*/*GenGlobalISel.inc*
* Build the compiler
Known issues:
* ${LLVM_GISEL_COV_PREFIX}-all must be generated as a manual
step due to a lack of a portable 'cat' command. It should be the
concatenation of all ${LLVM_GISEL_COV_PREFIX}-[0-9]* files.
* There's no mechanism to discard coverage information when the ruleset
changes
Depends on D39742
Reviewers: ab, qcolombet, t.p.northover, aditya_nandakumar, rovka
Reviewed By: rovka
Subscribers: vsk, arsenm, nhaehnle, mgorny, kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D39747
llvm-svn: 318356
2017-11-16 00:46:35 +00:00
|
|
|
if (RuleCoverage) {
|
|
|
|
if (RuleCoverage->isCovered(MatcherOrErr->getRuleID()))
|
|
|
|
++NumPatternsTested;
|
|
|
|
else
|
|
|
|
PrintWarning(Pat.getSrcRecord()->getLoc(),
|
|
|
|
"Pattern is not covered by a test");
|
|
|
|
}
|
2017-02-20 14:31:27 +00:00
|
|
|
Rules.push_back(std::move(MatcherOrErr.get()));
|
2023-08-07 12:59:24 +02:00
|
|
|
postProcessRule(Rules.back());
|
2017-02-20 14:31:27 +00:00
|
|
|
}
|
|
|
|
|
2018-01-16 18:44:05 +00:00
|
|
|
// Comparison function to order records by name.
|
2024-04-29 14:47:46 -04:00
|
|
|
auto OrderByName = [](const Record *A, const Record *B) {
|
2018-01-16 18:44:05 +00:00
|
|
|
return A->getName() < B->getName();
|
|
|
|
};
|
|
|
|
|
2024-09-30 06:37:36 -07:00
|
|
|
std::vector<const Record *> ComplexPredicates =
|
[globalisel][tablegen] Partially fix compile-time regressions by converting matcher to state-machine(s)
Summary:
Replace the matcher if-statements for each rule with a state-machine. This
significantly reduces compile time, memory allocations, and cumulative memory
allocation when compiling AArch64InstructionSelector.cpp.o after r303259 is
recommitted.
The following patches will expand on this further to fully fix the regressions.
Reviewers: rovka, ab, t.p.northover, qcolombet, aditya_nandakumar
Reviewed By: ab
Subscribers: vitalybuka, aemerson, javed.absar, igorb, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D33758
llvm-svn: 307079
2017-07-04 14:35:06 +00:00
|
|
|
RK.getAllDerivedDefinitions("GIComplexOperandMatcher");
|
2024-04-29 14:47:46 -04:00
|
|
|
llvm::sort(ComplexPredicates, OrderByName);
|
2018-01-16 18:44:05 +00:00
|
|
|
|
2020-08-27 16:15:33 +01:00
|
|
|
std::vector<StringRef> CustomRendererFns;
|
|
|
|
transform(RK.getAllDerivedDefinitions("GICustomOperandRenderer"),
|
|
|
|
std::back_inserter(CustomRendererFns), [](const auto &Record) {
|
|
|
|
return Record->getValueAsString("RendererFn");
|
|
|
|
});
|
|
|
|
// Sort and remove duplicates to get a list of unique renderer functions, in
|
|
|
|
// case some were mentioned more than once.
|
|
|
|
llvm::sort(CustomRendererFns);
|
2024-06-02 11:52:12 -07:00
|
|
|
CustomRendererFns.erase(llvm::unique(CustomRendererFns),
|
|
|
|
CustomRendererFns.end());
|
2018-01-16 18:44:05 +00:00
|
|
|
|
2023-06-26 11:44:18 +02:00
|
|
|
// Create a table containing the LLT objects needed by the matcher and an enum
|
[globalisel][tablegen] Partially fix compile-time regressions by converting matcher to state-machine(s)
Summary:
Replace the matcher if-statements for each rule with a state-machine. This
significantly reduces compile time, memory allocations, and cumulative memory
allocation when compiling AArch64InstructionSelector.cpp.o after r303259 is
recommitted.
The following patches will expand on this further to fully fix the regressions.
Reviewers: rovka, ab, t.p.northover, qcolombet, aditya_nandakumar
Reviewed By: ab
Subscribers: vitalybuka, aemerson, javed.absar, igorb, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D33758
llvm-svn: 307079
2017-07-04 14:35:06 +00:00
|
|
|
// for the matcher to reference them with.
|
2017-08-17 13:18:35 +00:00
|
|
|
std::vector<LLTCodeGen> TypeObjects;
|
2021-01-25 19:23:57 -08:00
|
|
|
append_range(TypeObjects, KnownTypes);
|
llvm::sort(C.begin(), C.end(), ...) -> llvm::sort(C, ...)
Summary: The convenience wrapper in STLExtras is available since rL342102.
Reviewers: dblaikie, javed.absar, JDevlieghere, andreadb
Subscribers: MatzeB, sanjoy, arsenm, dschuff, mehdi_amini, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, eraman, aheejin, kbarton, JDevlieghere, javed.absar, gbedwell, jrtc27, mgrang, atanasyan, steven_wu, george.burgess.iv, dexonsmith, kristina, jsji, llvm-commits
Differential Revision: https://reviews.llvm.org/D52573
llvm-svn: 343163
2018-09-27 02:13:45 +00:00
|
|
|
llvm::sort(TypeObjects);
|
2018-01-16 18:44:05 +00:00
|
|
|
|
2023-06-26 11:44:18 +02:00
|
|
|
// Sort rules.
|
2019-04-23 14:51:27 +00:00
|
|
|
llvm::stable_sort(Rules, [&](const RuleMatcher &A, const RuleMatcher &B) {
|
2018-02-16 22:37:15 +00:00
|
|
|
int ScoreA = RuleMatcherScores[A.getRuleID()];
|
|
|
|
int ScoreB = RuleMatcherScores[B.getRuleID()];
|
|
|
|
if (ScoreA > ScoreB)
|
|
|
|
return true;
|
|
|
|
if (ScoreB > ScoreA)
|
|
|
|
return false;
|
[TableGen][GlobalISel] Optimize MatchTable for faster instruction selection
*** Context ***
Prior to this patchw, the table generated for matching instruction was
straight forward but highly inefficient.
Basically, each pattern generates its own set of self contained checks
and actions.
E.g., TableGen generated:
// First pattern
CheckNumOperand 3
CheckOpcode G_ADD
...
Build ADDrr
// Second pattern
CheckNumOperand 3
CheckOpcode G_ADD
...
Build ADDri
// Third pattern
CheckNumOperand 3
CheckOpcode G_SUB
...
Build SUBrr
*** Problem ***
Because of that generation, a *lot* of check were redundant between each
pattern and were checked every single time until we reach the pattern
that matches.
E.g., Taking the previous table, let say we are matching a G_SUB, that
means we were going to check all the rules for G_ADD before looking at
the G_SUB rule. In particular we are going to do:
check 3 operands; PASS
check G_ADD; FAIL
; Next rule
check 3 operands; PASS (but we already knew that!)
check G_ADD; FAIL (well it is still not true)
; Next rule
check 3 operands; PASS (really!!)
check G_SUB; PASS (at last :P)
*** Proposed Solution ***
This patch introduces a concept of group of rules (GroupMatcher) that
share some predicates and only get checked once for the whole group.
This patch only creates groups with one nesting level. Conceptually
there is nothing preventing us for having deeper nest level. However,
the current implementation is not smart enough to share the recording
(aka capturing) of values. That limits its ability to do more sharing.
For the given example the current patch will generate:
// First group
CheckOpcode G_ADD
// First pattern
CheckNumOperand 3
...
Build ADDrr
// Second pattern
CheckNumOperand 3
...
Build ADDri
// Second group
CheckOpcode G_SUB
// Third pattern
CheckNumOperand 3
...
Build SUBrr
But if we allowed several nesting level, it could create a sub group
for the checknumoperand 3.
(We would need to call optimizeRules on the rules within a group.)
*** Result ***
With only one level of nesting, the instruction selection pass is up
to 4x faster. For instance, one instruction now takes 500 checks,
instead of 24k! With more nesting we could get in the tens I believe.
Differential Revision: https://reviews.llvm.org/D39034
rdar://problem/34670699
llvm-svn: 321017
2017-12-18 19:47:41 +00:00
|
|
|
if (A.isHigherPriorityThan(B)) {
|
|
|
|
assert(!B.isHigherPriorityThan(A) && "Cannot be more important "
|
|
|
|
"and less important at "
|
|
|
|
"the same time");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
2018-05-02 20:07:15 +00:00
|
|
|
|
2023-06-26 11:44:18 +02:00
|
|
|
unsigned MaxTemporaries = 0;
|
|
|
|
for (const auto &Rule : Rules)
|
|
|
|
MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
|
2016-12-21 23:26:20 +00:00
|
|
|
|
2023-06-26 11:44:18 +02:00
|
|
|
// Build match table
|
2018-05-02 20:15:11 +00:00
|
|
|
const MatchTable Table =
|
|
|
|
buildMatchTable(Rules, OptimizeMatchTable, GenerateCoverage);
|
2023-06-26 11:44:18 +02:00
|
|
|
|
|
|
|
emitPredicateBitset(OS, "GET_GLOBALISEL_PREDICATE_BITSET");
|
|
|
|
emitTemporariesDecl(OS, "GET_GLOBALISEL_TEMPORARIES_DECL");
|
|
|
|
emitTemporariesInit(OS, MaxTemporaries, "GET_GLOBALISEL_TEMPORARIES_INIT");
|
|
|
|
emitExecutorImpl(OS, Table, TypeObjects, Rules, ComplexPredicates,
|
|
|
|
CustomRendererFns, "GET_GLOBALISEL_IMPL");
|
|
|
|
emitPredicatesDecl(OS, "GET_GLOBALISEL_PREDICATES_DECL");
|
|
|
|
emitPredicatesInit(OS, "GET_GLOBALISEL_PREDICATES_INIT");
|
2016-12-21 23:26:20 +00:00
|
|
|
}
|
|
|
|
|
2024-09-23 13:07:31 -07:00
|
|
|
void GlobalISelEmitter::declareSubtargetFeature(const Record *Predicate) {
|
2023-08-22 10:09:48 -07:00
|
|
|
SubtargetFeatures.try_emplace(Predicate, Predicate, SubtargetFeatures.size());
|
[globalisel][tablegen] Import SelectionDAG's rule predicates and support the equivalent in GIRule.
Summary:
The SelectionDAG importer now imports rules with Predicate's attached via
Requires, PredicateControl, etc. These predicates are implemented as
bitset's to allow multiple predicates to be tested together. However,
unlike the MC layer subtarget features, each target only pays for it's own
predicates (e.g. AArch64 doesn't have 192 feature bits just because X86
needs a lot).
Both AArch64 and X86 derive at least one predicate from the MachineFunction
or Function so they must re-initialize AvailableFeatures before each
function. They also declare locals in <Target>InstructionSelector so that
computeAvailableFeatures() can use the code from SelectionDAG without
modification.
Reviewers: rovka, qcolombet, aditya_nandakumar, t.p.northover, ab
Reviewed By: rovka
Subscribers: aemerson, rengolin, dberris, kristof.beyls, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D31418
llvm-svn: 300993
2017-04-21 15:59:56 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 21:04:28 -07:00
|
|
|
unsigned GlobalISelEmitter::declareHwModeCheck(StringRef HwModeFeatures) {
|
|
|
|
return HwModes.emplace(HwModeFeatures.str(), HwModes.size()).first->second;
|
|
|
|
}
|
|
|
|
|
2017-02-10 04:00:17 +00:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2016-12-21 23:26:20 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2023-02-19 14:30:14 +09:00
|
|
|
static TableGen::Emitter::OptClass<GlobalISelEmitter>
|
|
|
|
X("gen-global-isel", "Generate GlobalISel selector");
|