[llvm] 3bdd711 - [TableGen][GISel] Extract helper function for constraining operands (#115148)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 6 20:16:57 PST 2024
Author: Sergei Barannikov
Date: 2024-11-07T07:16:54+03:00
New Revision: 3bdd71137eb6a54a3f8a45bdb33bfe15edc05f28
URL: https://github.com/llvm/llvm-project/commit/3bdd71137eb6a54a3f8a45bdb33bfe15edc05f28
DIFF: https://github.com/llvm/llvm-project/commit/3bdd71137eb6a54a3f8a45bdb33bfe15edc05f28.diff
LOG: [TableGen][GISel] Extract helper function for constraining operands (#115148)
As a side effect, this fixes COPY_TO_REGCLASS not being constrained
if it is not top-level (the reason for changes in tests).
Added:
Modified:
llvm/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir
llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-sext.mir
llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-zext.mir
llvm/utils/TableGen/GlobalISelEmitter.cpp
Removed:
################################################################################
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir
index 03cc505b3e15b9..74436c21d79d81 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir
@@ -1,3 +1,4 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
# RUN: llc -O0 -mtriple=arm64eb-- -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
---
name: bitcast_v2f32_to_s64
@@ -9,9 +10,13 @@ body: |
liveins: $x0
; CHECK-LABEL: name: bitcast_v2f32_to_s64
- ; CHECK: [[COPY:%[0-9]+]]:fpr64 = COPY $x0
- ; CHECK: [[REV:%[0-9]+]]:fpr64 = REV64v2i32 [[COPY]]
- ; CHECK: $x0 = COPY [[REV]]
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $x0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY [[COPY]]
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:fpr64 = COPY [[COPY1]]
+ ; CHECK-NEXT: [[REV64v2i32_:%[0-9]+]]:fpr64 = REV64v2i32 [[COPY2]]
+ ; CHECK-NEXT: $x0 = COPY [[REV64v2i32_]]
%0:fpr(<2 x s32>) = COPY $x0
%1:fpr(s64) = G_BITCAST %0
$x0 = COPY %1(s64)
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-sext.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-sext.mir
index 150d9b72afcee5..1de18cf17eb99a 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-sext.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-sext.mir
@@ -107,7 +107,7 @@ body: |
; GCN-NEXT: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 31
; GCN-NEXT: [[S_SEXT_I32_I16_:%[0-9]+]]:sreg_32 = S_SEXT_I32_I16 [[COPY]]
; GCN-NEXT: [[S_ASHR_I32_:%[0-9]+]]:sreg_32 = S_ASHR_I32 [[S_SEXT_I32_I16_]], [[S_MOV_B32_]], implicit-def dead $scc
- ; GCN-NEXT: [[COPY1:%[0-9]+]]:sreg_32_xm0 = COPY [[S_ASHR_I32_]]
+ ; GCN-NEXT: [[COPY1:%[0-9]+]]:sgpr_32 = COPY [[S_ASHR_I32_]]
; GCN-NEXT: [[S_SEXT_I32_I16_1:%[0-9]+]]:sreg_32_xexec_hi_and_sreg_32_xm0 = S_SEXT_I32_I16 [[COPY]]
; GCN-NEXT: [[REG_SEQUENCE:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[S_SEXT_I32_I16_1]], %subreg.sub0, [[COPY1]], %subreg.sub1
; GCN-NEXT: $sgpr0_sgpr1 = COPY [[REG_SEQUENCE]]
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-zext.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-zext.mir
index 1589172a028265..b709ddf2e35879 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-zext.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-zext.mir
@@ -107,7 +107,7 @@ body: |
; GCN-NEXT: [[S_MOV_B32_:%[0-9]+]]:sreg_32_xm0 = S_MOV_B32 0
; GCN-NEXT: [[S_MOV_B32_1:%[0-9]+]]:sreg_32 = S_MOV_B32 65535
; GCN-NEXT: [[S_AND_B32_:%[0-9]+]]:sreg_32 = S_AND_B32 [[COPY]], [[S_MOV_B32_1]], implicit-def dead $scc
- ; GCN-NEXT: [[COPY1:%[0-9]+]]:sreg_32_xexec_hi_and_sreg_32_xm0 = COPY [[S_AND_B32_]]
+ ; GCN-NEXT: [[COPY1:%[0-9]+]]:sgpr_32 = COPY [[S_AND_B32_]]
; GCN-NEXT: [[REG_SEQUENCE:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[COPY1]], %subreg.sub0, [[S_MOV_B32_]], %subreg.sub1
; GCN-NEXT: $sgpr0_sgpr1 = COPY [[REG_SEQUENCE]]
%0:sgpr(s32) = COPY $sgpr0
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 859310906af468..1e5d28f8ce95b7 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -460,6 +460,9 @@ class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter {
std::optional<const CodeGenRegisterClass *>
inferRegClassFromPattern(const TreePatternNode &N);
+ Error constrainOperands(action_iterator InsertPt, RuleMatcher &M,
+ unsigned InsnID, const TreePatternNode &Dst);
+
/// Return the size of the MemoryVT in this predicate, if possible.
std::optional<unsigned>
getMemSizeBitsFromPredicate(const TreePredicateFn &Predicate);
@@ -1409,103 +1412,10 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
- // We need to make sure that when we import an INSERT_SUBREG as a
- // subinstruction that it ends up being constrained to the correct super
- // register and subregister classes.
- auto OpName = Target.getInstruction(Dst.getOperator()).TheDef->getName();
- if (OpName == "INSERT_SUBREG") {
- auto SubClass = inferRegClassFromPattern(Dst.getChild(1));
- if (!SubClass)
- return failedImport(
- "Cannot infer register class from INSERT_SUBREG operand #1");
- std::optional<const CodeGenRegisterClass *> SuperClass =
- inferSuperRegisterClassForNode(Dst.getExtType(0), Dst.getChild(0),
- Dst.getChild(2));
- if (!SuperClass)
- return failedImport(
- "Cannot infer register class for INSERT_SUBREG operand #0");
- // The destination and the super register source of an INSERT_SUBREG must
- // be the same register class.
- M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
- M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 1, **SuperClass);
- M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 2, **SubClass);
- return InsertPtOrError.get();
- }
-
- if (OpName == "EXTRACT_SUBREG") {
- // EXTRACT_SUBREG selects into a subregister COPY but unlike most
- // instructions, the result register class is controlled by the
- // subregisters of the operand. As a result, we must constrain the result
- // class rather than check that it's already the right one.
- 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");
-
- const auto SrcRCDstRCPair =
- (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
- assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
- M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 0, *SrcRCDstRCPair->second);
- M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 1, *SrcRCDstRCPair->first);
-
- // We're done with this pattern! It's eligible for GISel emission; return
- // it.
- return InsertPtOrError.get();
- }
-
- // Similar to INSERT_SUBREG, we also have to handle SUBREG_TO_REG as a
- // subinstruction.
- if (OpName == "SUBREG_TO_REG") {
- auto SubClass = inferRegClassFromPattern(Dst.getChild(1));
- if (!SubClass)
- return failedImport(
- "Cannot infer register class from SUBREG_TO_REG child #1");
- 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, DstMIBuilder.getInsnID(), 0, **SuperClass);
- M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 2, **SubClass);
- return InsertPtOrError.get();
- }
-
- if (OpName == "REG_SEQUENCE") {
- auto SuperClass = inferRegClassFromPattern(Dst.getChild(0));
- M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), 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);
- assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
- M.insertAction<ConstrainOperandToRegClassAction>(
- InsertPt, DstMIBuilder.getInsnID(), I, *SrcRCDstRCPair->second);
- }
-
- return InsertPtOrError.get();
- }
+ if (auto Error =
+ constrainOperands(InsertPt, M, DstMIBuilder.getInsnID(), Dst))
+ return std::move(Error);
- M.insertAction<ConstrainOperandsToDefinitionAction>(InsertPt,
- DstMIBuilder.getInsnID());
return InsertPtOrError.get();
}
@@ -1794,6 +1704,116 @@ Error GlobalISelEmitter::importImplicitDefRenderers(
return Error::success();
}
+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();
+}
+
std::optional<const CodeGenRegisterClass *>
GlobalISelEmitter::getRegClassFromLeaf(const TreePatternNode &Leaf) {
assert(Leaf.isLeaf() && "Expected leaf?");
@@ -2123,106 +2143,9 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// Constrain the registers to classes. This is normally derived from the
// emitted instruction but a few instructions require special handling.
- 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.addAction<ConstrainOperandToRegClassAction>(
- 0, 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.
- assert(Src.getExtTypes().size() == 1 &&
- "Expected Src of EXTRACT_SUBREG to have one result type");
-
- 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.addAction<ConstrainOperandToRegClassAction>(0, 0,
- *SrcRCDstRCPair->second);
- M.addAction<ConstrainOperandToRegClassAction>(0, 1, *SrcRCDstRCPair->first);
- } else if (DstIName == "INSERT_SUBREG") {
- assert(Src.getExtTypes().size() == 1 &&
- "Expected Src of INSERT_SUBREG to have one result type");
- // 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(
- Src.getExtType(0), Dst.getChild(0), Dst.getChild(2));
- if (!SuperClass)
- return failedImport(
- "Cannot infer register class for INSERT_SUBREG operand #0");
- M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass);
- M.addAction<ConstrainOperandToRegClassAction>(0, 1, **SuperClass);
- M.addAction<ConstrainOperandToRegClassAction>(0, 2, **SubClass);
- } else if (DstIName == "SUBREG_TO_REG") {
- // We need to constrain the destination and subregister source.
- assert(Src.getExtTypes().size() == 1 &&
- "Expected Src of SUBREG_TO_REG to have one result type");
-
- // 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(Src.getExtType(0), Dst.getChild(2));
- if (!SuperClass)
- return failedImport(
- "Cannot infer register class for SUBREG_TO_REG operand #0");
- M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass);
- M.addAction<ConstrainOperandToRegClassAction>(0, 2, **SubClass);
- } else if (DstIName == "REG_SEQUENCE") {
- auto SuperClass = inferRegClassFromPattern(Dst.getChild(0));
-
- M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass);
-
- unsigned Num = Dst.getNumChildren();
- for (unsigned I = 1; I != Num; I += 2) {
- 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.addAction<ConstrainOperandToRegClassAction>(0, I,
- *SrcRCDstRCPair->second);
- }
- } else {
- M.addAction<ConstrainOperandsToDefinitionAction>(0);
- }
+ if (auto Error =
+ constrainOperands(M.actions_end(), M, DstMIBuilder.getInsnID(), Dst))
+ return std::move(Error);
// Erase the root.
unsigned RootInsnID = M.getInsnVarID(InsnMatcher);
More information about the llvm-commits
mailing list