Skip to content

Commit 9303ecc

Browse files
committed
[TableGen][GISel] Extract helper function for constraining operands
As a side effect, this fixes COPY_TO_REGCLASS not being constrained if it is not the top-level instruction in the destination pattern.
1 parent f87484d commit 9303ecc

File tree

4 files changed

+129
-201
lines changed

4 files changed

+129
-201
lines changed

llvm/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
12
# RUN: llc -O0 -mtriple=arm64eb-- -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
23
---
34
name: bitcast_v2f32_to_s64
@@ -9,9 +10,13 @@ body: |
910
liveins: $x0
1011
1112
; CHECK-LABEL: name: bitcast_v2f32_to_s64
12-
; CHECK: [[COPY:%[0-9]+]]:fpr64 = COPY $x0
13-
; CHECK: [[REV:%[0-9]+]]:fpr64 = REV64v2i32 [[COPY]]
14-
; CHECK: $x0 = COPY [[REV]]
13+
; CHECK: liveins: $x0
14+
; CHECK-NEXT: {{ $}}
15+
; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $x0
16+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY [[COPY]]
17+
; CHECK-NEXT: [[COPY2:%[0-9]+]]:fpr64 = COPY [[COPY1]]
18+
; CHECK-NEXT: [[REV64v2i32_:%[0-9]+]]:fpr64 = REV64v2i32 [[COPY2]]
19+
; CHECK-NEXT: $x0 = COPY [[REV64v2i32_]]
1520
%0:fpr(<2 x s32>) = COPY $x0
1621
%1:fpr(s64) = G_BITCAST %0
1722
$x0 = COPY %1(s64)

llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-sext.mir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ body: |
107107
; GCN-NEXT: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 31
108108
; GCN-NEXT: [[S_SEXT_I32_I16_:%[0-9]+]]:sreg_32 = S_SEXT_I32_I16 [[COPY]]
109109
; GCN-NEXT: [[S_ASHR_I32_:%[0-9]+]]:sreg_32 = S_ASHR_I32 [[S_SEXT_I32_I16_]], [[S_MOV_B32_]], implicit-def dead $scc
110-
; GCN-NEXT: [[COPY1:%[0-9]+]]:sreg_32_xm0 = COPY [[S_ASHR_I32_]]
110+
; GCN-NEXT: [[COPY1:%[0-9]+]]:sgpr_32 = COPY [[S_ASHR_I32_]]
111111
; GCN-NEXT: [[S_SEXT_I32_I16_1:%[0-9]+]]:sreg_32_xexec_hi_and_sreg_32_xm0 = S_SEXT_I32_I16 [[COPY]]
112112
; GCN-NEXT: [[REG_SEQUENCE:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[S_SEXT_I32_I16_1]], %subreg.sub0, [[COPY1]], %subreg.sub1
113113
; GCN-NEXT: $sgpr0_sgpr1 = COPY [[REG_SEQUENCE]]

llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-zext.mir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ body: |
107107
; GCN-NEXT: [[S_MOV_B32_:%[0-9]+]]:sreg_32_xm0 = S_MOV_B32 0
108108
; GCN-NEXT: [[S_MOV_B32_1:%[0-9]+]]:sreg_32 = S_MOV_B32 65535
109109
; GCN-NEXT: [[S_AND_B32_:%[0-9]+]]:sreg_32 = S_AND_B32 [[COPY]], [[S_MOV_B32_1]], implicit-def dead $scc
110-
; GCN-NEXT: [[COPY1:%[0-9]+]]:sreg_32_xexec_hi_and_sreg_32_xm0 = COPY [[S_AND_B32_]]
110+
; GCN-NEXT: [[COPY1:%[0-9]+]]:sgpr_32 = COPY [[S_AND_B32_]]
111111
; GCN-NEXT: [[REG_SEQUENCE:%[0-9]+]]:sreg_64 = REG_SEQUENCE [[COPY1]], %subreg.sub0, [[S_MOV_B32_]], %subreg.sub1
112112
; GCN-NEXT: $sgpr0_sgpr1 = COPY [[REG_SEQUENCE]]
113113
%0:sgpr(s32) = COPY $sgpr0

llvm/utils/TableGen/GlobalISelEmitter.cpp

Lines changed: 119 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,9 @@ class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter {
460460
std::optional<const CodeGenRegisterClass *>
461461
inferRegClassFromPattern(const TreePatternNode &N);
462462

463+
Error constrainOperands(action_iterator InsertPt, RuleMatcher &M,
464+
unsigned InsnID, const TreePatternNode &Dst);
465+
463466
/// Return the size of the MemoryVT in this predicate, if possible.
464467
std::optional<unsigned>
465468
getMemSizeBitsFromPredicate(const TreePredicateFn &Predicate);
@@ -1409,103 +1412,10 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
14091412
if (auto Error = InsertPtOrError.takeError())
14101413
return std::move(Error);
14111414

1412-
// We need to make sure that when we import an INSERT_SUBREG as a
1413-
// subinstruction that it ends up being constrained to the correct super
1414-
// register and subregister classes.
1415-
auto OpName = Target.getInstruction(Dst.getOperator()).TheDef->getName();
1416-
if (OpName == "INSERT_SUBREG") {
1417-
auto SubClass = inferRegClassFromPattern(Dst.getChild(1));
1418-
if (!SubClass)
1419-
return failedImport(
1420-
"Cannot infer register class from INSERT_SUBREG operand #1");
1421-
std::optional<const CodeGenRegisterClass *> SuperClass =
1422-
inferSuperRegisterClassForNode(Dst.getExtType(0), Dst.getChild(0),
1423-
Dst.getChild(2));
1424-
if (!SuperClass)
1425-
return failedImport(
1426-
"Cannot infer register class for INSERT_SUBREG operand #0");
1427-
// The destination and the super register source of an INSERT_SUBREG must
1428-
// be the same register class.
1429-
M.insertAction<ConstrainOperandToRegClassAction>(
1430-
InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
1431-
M.insertAction<ConstrainOperandToRegClassAction>(
1432-
InsertPt, DstMIBuilder.getInsnID(), 1, **SuperClass);
1433-
M.insertAction<ConstrainOperandToRegClassAction>(
1434-
InsertPt, DstMIBuilder.getInsnID(), 2, **SubClass);
1435-
return InsertPtOrError.get();
1436-
}
1437-
1438-
if (OpName == "EXTRACT_SUBREG") {
1439-
// EXTRACT_SUBREG selects into a subregister COPY but unlike most
1440-
// instructions, the result register class is controlled by the
1441-
// subregisters of the operand. As a result, we must constrain the result
1442-
// class rather than check that it's already the right one.
1443-
auto SuperClass = inferRegClassFromPattern(Dst.getChild(0));
1444-
if (!SuperClass)
1445-
return failedImport(
1446-
"Cannot infer register class from EXTRACT_SUBREG operand #0");
1447-
1448-
auto SubIdx = inferSubRegIndexForNode(Dst.getChild(1));
1449-
if (!SubIdx)
1450-
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
1451-
1452-
const auto SrcRCDstRCPair =
1453-
(*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
1454-
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
1455-
M.insertAction<ConstrainOperandToRegClassAction>(
1456-
InsertPt, DstMIBuilder.getInsnID(), 0, *SrcRCDstRCPair->second);
1457-
M.insertAction<ConstrainOperandToRegClassAction>(
1458-
InsertPt, DstMIBuilder.getInsnID(), 1, *SrcRCDstRCPair->first);
1459-
1460-
// We're done with this pattern! It's eligible for GISel emission; return
1461-
// it.
1462-
return InsertPtOrError.get();
1463-
}
1464-
1465-
// Similar to INSERT_SUBREG, we also have to handle SUBREG_TO_REG as a
1466-
// subinstruction.
1467-
if (OpName == "SUBREG_TO_REG") {
1468-
auto SubClass = inferRegClassFromPattern(Dst.getChild(1));
1469-
if (!SubClass)
1470-
return failedImport(
1471-
"Cannot infer register class from SUBREG_TO_REG child #1");
1472-
auto SuperClass =
1473-
inferSuperRegisterClass(Dst.getExtType(0), Dst.getChild(2));
1474-
if (!SuperClass)
1475-
return failedImport(
1476-
"Cannot infer register class for SUBREG_TO_REG operand #0");
1477-
M.insertAction<ConstrainOperandToRegClassAction>(
1478-
InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
1479-
M.insertAction<ConstrainOperandToRegClassAction>(
1480-
InsertPt, DstMIBuilder.getInsnID(), 2, **SubClass);
1481-
return InsertPtOrError.get();
1482-
}
1483-
1484-
if (OpName == "REG_SEQUENCE") {
1485-
auto SuperClass = inferRegClassFromPattern(Dst.getChild(0));
1486-
M.insertAction<ConstrainOperandToRegClassAction>(
1487-
InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
1488-
1489-
unsigned Num = Dst.getNumChildren();
1490-
for (unsigned I = 1; I != Num; I += 2) {
1491-
const TreePatternNode &SubRegChild = Dst.getChild(I + 1);
1492-
1493-
auto SubIdx = inferSubRegIndexForNode(SubRegChild);
1494-
if (!SubIdx)
1495-
return failedImport("REG_SEQUENCE child is not a subreg index");
1496-
1497-
const auto SrcRCDstRCPair =
1498-
(*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
1499-
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
1500-
M.insertAction<ConstrainOperandToRegClassAction>(
1501-
InsertPt, DstMIBuilder.getInsnID(), I, *SrcRCDstRCPair->second);
1502-
}
1503-
1504-
return InsertPtOrError.get();
1505-
}
1415+
if (auto Error =
1416+
constrainOperands(InsertPt, M, DstMIBuilder.getInsnID(), Dst))
1417+
return std::move(Error);
15061418

1507-
M.insertAction<ConstrainOperandsToDefinitionAction>(InsertPt,
1508-
DstMIBuilder.getInsnID());
15091419
return InsertPtOrError.get();
15101420
}
15111421

@@ -1794,6 +1704,116 @@ Error GlobalISelEmitter::importImplicitDefRenderers(
17941704
return Error::success();
17951705
}
17961706

1707+
Error GlobalISelEmitter::constrainOperands(action_iterator InsertPt,
1708+
RuleMatcher &M, unsigned InsnID,
1709+
const TreePatternNode &Dst) {
1710+
const Record *DstOp = Dst.getOperator();
1711+
const CodeGenInstruction &DstI = Target.getInstruction(DstOp);
1712+
StringRef DstIName = DstI.TheDef->getName();
1713+
1714+
if (DstIName == "COPY_TO_REGCLASS") {
1715+
// COPY_TO_REGCLASS does not provide operand constraints itself but the
1716+
// result is constrained to the class given by the second child.
1717+
const Record *DstIOpRec =
1718+
getInitValueAsRegClass(Dst.getChild(1).getLeafValue());
1719+
1720+
if (DstIOpRec == nullptr)
1721+
return failedImport("COPY_TO_REGCLASS operand #1 isn't a register class");
1722+
1723+
M.insertAction<ConstrainOperandToRegClassAction>(
1724+
InsertPt, InsnID, 0, Target.getRegisterClass(DstIOpRec));
1725+
} else if (DstIName == "EXTRACT_SUBREG") {
1726+
auto SuperClass = inferRegClassFromPattern(Dst.getChild(0));
1727+
if (!SuperClass)
1728+
return failedImport(
1729+
"Cannot infer register class from EXTRACT_SUBREG operand #0");
1730+
1731+
auto SubIdx = inferSubRegIndexForNode(Dst.getChild(1));
1732+
if (!SubIdx)
1733+
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
1734+
1735+
// It would be nice to leave this constraint implicit but we're required
1736+
// to pick a register class so constrain the result to a register class
1737+
// that can hold the correct MVT.
1738+
//
1739+
// FIXME: This may introduce an extra copy if the chosen class doesn't
1740+
// actually contain the subregisters.
1741+
const auto SrcRCDstRCPair =
1742+
(*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
1743+
if (!SrcRCDstRCPair) {
1744+
return failedImport("subreg index is incompatible "
1745+
"with inferred reg class");
1746+
}
1747+
1748+
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
1749+
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 0,
1750+
*SrcRCDstRCPair->second);
1751+
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 1,
1752+
*SrcRCDstRCPair->first);
1753+
} else if (DstIName == "INSERT_SUBREG") {
1754+
// We need to constrain the destination, a super regsister source, and a
1755+
// subregister source.
1756+
auto SubClass = inferRegClassFromPattern(Dst.getChild(1));
1757+
if (!SubClass)
1758+
return failedImport(
1759+
"Cannot infer register class from INSERT_SUBREG operand #1");
1760+
auto SuperClass = inferSuperRegisterClassForNode(
1761+
Dst.getExtType(0), Dst.getChild(0), Dst.getChild(2));
1762+
if (!SuperClass)
1763+
return failedImport(
1764+
"Cannot infer register class for INSERT_SUBREG operand #0");
1765+
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 0,
1766+
**SuperClass);
1767+
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 1,
1768+
**SuperClass);
1769+
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 2,
1770+
**SubClass);
1771+
} else if (DstIName == "SUBREG_TO_REG") {
1772+
// We need to constrain the destination and subregister source.
1773+
// Attempt to infer the subregister source from the first child. If it has
1774+
// an explicitly given register class, we'll use that. Otherwise, we will
1775+
// fail.
1776+
auto SubClass = inferRegClassFromPattern(Dst.getChild(1));
1777+
if (!SubClass)
1778+
return failedImport(
1779+
"Cannot infer register class from SUBREG_TO_REG child #1");
1780+
// We don't have a child to look at that might have a super register node.
1781+
auto SuperClass =
1782+
inferSuperRegisterClass(Dst.getExtType(0), Dst.getChild(2));
1783+
if (!SuperClass)
1784+
return failedImport(
1785+
"Cannot infer register class for SUBREG_TO_REG operand #0");
1786+
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 0,
1787+
**SuperClass);
1788+
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 2,
1789+
**SubClass);
1790+
} else if (DstIName == "REG_SEQUENCE") {
1791+
auto SuperClass = inferRegClassFromPattern(Dst.getChild(0));
1792+
1793+
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, 0,
1794+
**SuperClass);
1795+
1796+
unsigned Num = Dst.getNumChildren();
1797+
for (unsigned I = 1; I != Num; I += 2) {
1798+
const TreePatternNode &SubRegChild = Dst.getChild(I + 1);
1799+
1800+
auto SubIdx = inferSubRegIndexForNode(SubRegChild);
1801+
if (!SubIdx)
1802+
return failedImport("REG_SEQUENCE child is not a subreg index");
1803+
1804+
const auto SrcRCDstRCPair =
1805+
(*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
1806+
1807+
M.insertAction<ConstrainOperandToRegClassAction>(InsertPt, InsnID, I,
1808+
*SrcRCDstRCPair->second);
1809+
}
1810+
} else {
1811+
M.insertAction<ConstrainOperandsToDefinitionAction>(InsertPt, InsnID);
1812+
}
1813+
1814+
return Error::success();
1815+
}
1816+
17971817
std::optional<const CodeGenRegisterClass *>
17981818
GlobalISelEmitter::getRegClassFromLeaf(const TreePatternNode &Leaf) {
17991819
assert(Leaf.isLeaf() && "Expected leaf?");
@@ -2123,106 +2143,9 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
21232143

21242144
// Constrain the registers to classes. This is normally derived from the
21252145
// emitted instruction but a few instructions require special handling.
2126-
if (DstIName == "COPY_TO_REGCLASS") {
2127-
// COPY_TO_REGCLASS does not provide operand constraints itself but the
2128-
// result is constrained to the class given by the second child.
2129-
const Record *DstIOpRec =
2130-
getInitValueAsRegClass(Dst.getChild(1).getLeafValue());
2131-
2132-
if (DstIOpRec == nullptr)
2133-
return failedImport("COPY_TO_REGCLASS operand #1 isn't a register class");
2134-
2135-
M.addAction<ConstrainOperandToRegClassAction>(
2136-
0, 0, Target.getRegisterClass(DstIOpRec));
2137-
} else if (DstIName == "EXTRACT_SUBREG") {
2138-
auto SuperClass = inferRegClassFromPattern(Dst.getChild(0));
2139-
if (!SuperClass)
2140-
return failedImport(
2141-
"Cannot infer register class from EXTRACT_SUBREG operand #0");
2142-
2143-
auto SubIdx = inferSubRegIndexForNode(Dst.getChild(1));
2144-
if (!SubIdx)
2145-
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
2146-
2147-
// It would be nice to leave this constraint implicit but we're required
2148-
// to pick a register class so constrain the result to a register class
2149-
// that can hold the correct MVT.
2150-
//
2151-
// FIXME: This may introduce an extra copy if the chosen class doesn't
2152-
// actually contain the subregisters.
2153-
assert(Src.getExtTypes().size() == 1 &&
2154-
"Expected Src of EXTRACT_SUBREG to have one result type");
2155-
2156-
const auto SrcRCDstRCPair =
2157-
(*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
2158-
if (!SrcRCDstRCPair) {
2159-
return failedImport("subreg index is incompatible "
2160-
"with inferred reg class");
2161-
}
2162-
2163-
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
2164-
M.addAction<ConstrainOperandToRegClassAction>(0, 0,
2165-
*SrcRCDstRCPair->second);
2166-
M.addAction<ConstrainOperandToRegClassAction>(0, 1, *SrcRCDstRCPair->first);
2167-
} else if (DstIName == "INSERT_SUBREG") {
2168-
assert(Src.getExtTypes().size() == 1 &&
2169-
"Expected Src of INSERT_SUBREG to have one result type");
2170-
// We need to constrain the destination, a super regsister source, and a
2171-
// subregister source.
2172-
auto SubClass = inferRegClassFromPattern(Dst.getChild(1));
2173-
if (!SubClass)
2174-
return failedImport(
2175-
"Cannot infer register class from INSERT_SUBREG operand #1");
2176-
auto SuperClass = inferSuperRegisterClassForNode(
2177-
Src.getExtType(0), Dst.getChild(0), Dst.getChild(2));
2178-
if (!SuperClass)
2179-
return failedImport(
2180-
"Cannot infer register class for INSERT_SUBREG operand #0");
2181-
M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass);
2182-
M.addAction<ConstrainOperandToRegClassAction>(0, 1, **SuperClass);
2183-
M.addAction<ConstrainOperandToRegClassAction>(0, 2, **SubClass);
2184-
} else if (DstIName == "SUBREG_TO_REG") {
2185-
// We need to constrain the destination and subregister source.
2186-
assert(Src.getExtTypes().size() == 1 &&
2187-
"Expected Src of SUBREG_TO_REG to have one result type");
2188-
2189-
// Attempt to infer the subregister source from the first child. If it has
2190-
// an explicitly given register class, we'll use that. Otherwise, we will
2191-
// fail.
2192-
auto SubClass = inferRegClassFromPattern(Dst.getChild(1));
2193-
if (!SubClass)
2194-
return failedImport(
2195-
"Cannot infer register class from SUBREG_TO_REG child #1");
2196-
// We don't have a child to look at that might have a super register node.
2197-
auto SuperClass =
2198-
inferSuperRegisterClass(Src.getExtType(0), Dst.getChild(2));
2199-
if (!SuperClass)
2200-
return failedImport(
2201-
"Cannot infer register class for SUBREG_TO_REG operand #0");
2202-
M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass);
2203-
M.addAction<ConstrainOperandToRegClassAction>(0, 2, **SubClass);
2204-
} else if (DstIName == "REG_SEQUENCE") {
2205-
auto SuperClass = inferRegClassFromPattern(Dst.getChild(0));
2206-
2207-
M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass);
2208-
2209-
unsigned Num = Dst.getNumChildren();
2210-
for (unsigned I = 1; I != Num; I += 2) {
2211-
TreePatternNode &SubRegChild = Dst.getChild(I + 1);
2212-
2213-
auto SubIdx = inferSubRegIndexForNode(SubRegChild);
2214-
if (!SubIdx)
2215-
return failedImport("REG_SEQUENCE child is not a subreg index");
2216-
2217-
const auto SrcRCDstRCPair =
2218-
(*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
2219-
2220-
M.addAction<ConstrainOperandToRegClassAction>(0, I,
2221-
*SrcRCDstRCPair->second);
2222-
}
2223-
} else {
2224-
M.addAction<ConstrainOperandsToDefinitionAction>(0);
2225-
}
2146+
if (auto Error =
2147+
constrainOperands(M.actions_end(), M, DstMIBuilder.getInsnID(), Dst))
2148+
return std::move(Error);
22262149

22272150
// Erase the root.
22282151
unsigned RootInsnID = M.getInsnVarID(InsnMatcher);

0 commit comments

Comments
 (0)