Skip to content

Commit 44713f1

Browse files
authored
[AMDGPU][MC] Separate VOPC MnemonicAlias from Instruction (#89105)
Tablegen classes MnemonicAlias, Requires, and VOPC_Real, all define a field 'Predicates'. The prior formulation resulted in the instantiated record inheriting from all three to only have the Predicate set in Requires, i.e. Gen.AssemblerPredicate. This breaks the design of GCNPredicateControl (which is a parent class of VOPC_Real) that allows multiple predicates such as SubtargetPredicate and OtherPredicates to be set on an Instruction. MnemonicAlias does not need to be defined in the same record as VOPC_Real, so we can separate the definitions and remove Requires to avoid the issue. NFCI, but it enables future changes, such as setting multiple predicates on a VOPC_Real.
1 parent 68e814d commit 44713f1

File tree

1 file changed

+117
-105
lines changed

1 file changed

+117
-105
lines changed

llvm/lib/Target/AMDGPU/VOPCInstructions.td

Lines changed: 117 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,75 +1386,81 @@ multiclass VOPC_Real_Base<GFXGen Gen, bits<9> op> {
13861386

13871387
multiclass VOPC_Real_with_name<GFXGen Gen, bits<9> op, string OpName,
13881388
string asm_name, string pseudo_mnemonic = ""> {
1389-
let AssemblerPredicate = Gen.AssemblerPredicate, DecoderNamespace = Gen.DecoderNamespace in {
1390-
defvar ps32 = !cast<VOPC_Pseudo>(OpName#"_e32");
1391-
defvar ps64 = !cast<VOP3_Pseudo>(OpName#"_e64");
1392-
def _e32#Gen.Suffix :
1393-
// 32 and 64 bit forms of the instruction have _e32 and _e64
1394-
// respectively appended to their assembly mnemonic.
1395-
// _e64 is printed as part of the VOPDstS64orS32 operand, whereas
1396-
// the destination-less 32bit forms add it to the asmString here.
1397-
VOPC_Real<ps32, Gen.Subtarget, asm_name#"_e32">,
1398-
VOPCe<op{7-0}>,
1399-
MnemonicAlias<!if(!empty(pseudo_mnemonic), ps32.Mnemonic,
1400-
pseudo_mnemonic),
1401-
asm_name, ps32.AsmVariantName>,
1402-
Requires<[Gen.AssemblerPredicate]>;
1403-
def _e64#Gen.Suffix :
1404-
VOP3_Real<ps64, Gen.Subtarget, asm_name>,
1405-
VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl>,
1406-
MnemonicAlias<!if(!empty(pseudo_mnemonic), ps64.Mnemonic,
1407-
pseudo_mnemonic),
1389+
defvar ps32 = !cast<VOPC_Pseudo>(OpName#"_e32");
1390+
defvar ps64 = !cast<VOP3_Pseudo>(OpName#"_e64");
1391+
let AssemblerPredicate = Gen.AssemblerPredicate in {
1392+
// MnemonicAlias and GCNPredicateControl both define the field Predicates,
1393+
// so GCNPredicateControl must come after MnemonicAlias because it contains
1394+
// the predicates we actually want.
1395+
def : MnemonicAlias<!if(!empty(pseudo_mnemonic), ps32.Mnemonic,
1396+
pseudo_mnemonic),
1397+
asm_name, ps32.AsmVariantName>,
1398+
GCNPredicateControl;
1399+
def : MnemonicAlias<!if(!empty(pseudo_mnemonic), ps64.Mnemonic,
1400+
pseudo_mnemonic),
14081401
asm_name, ps64.AsmVariantName>,
1409-
Requires<[Gen.AssemblerPredicate]> {
1410-
// Encoding used for VOPC instructions encoded as VOP3 differs from
1411-
// VOP3e by destination name (sdst) as VOPC doesn't have vector dst.
1412-
bits<8> sdst;
1413-
let Inst{7-0} = sdst;
1414-
}
1415-
1416-
defm : VOPCInstAliases<OpName, !substr(Gen.Suffix, 1), NAME, asm_name>;
1417-
1418-
if ps32.Pfl.HasExtDPP then {
1419-
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName #"_e32" #"_dpp");
1420-
defvar AsmDPP = ps32.Pfl.AsmDPP16;
1421-
def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP,
1422-
Gen.Subtarget, asm_name>;
1423-
def _e32_dpp_w32#Gen.Suffix
1424-
: VOPC_DPP16<op{7-0}, psDPP, asm_name> {
1425-
let AsmString = asm_name # " vcc_lo, " # AsmDPP;
1426-
let isAsmParserOnly = 1;
1427-
let WaveSizePredicate = isWave32;
1428-
}
1429-
def _e32_dpp_w64#Gen.Suffix
1430-
: VOPC_DPP16<op{7-0}, psDPP, asm_name> {
1431-
let AsmString = asm_name # " vcc, " # AsmDPP;
1432-
let isAsmParserOnly = 1;
1433-
let WaveSizePredicate = isWave64;
1402+
GCNPredicateControl;
1403+
1404+
let DecoderNamespace = Gen.DecoderNamespace in {
1405+
def _e32#Gen.Suffix :
1406+
// 32 and 64 bit forms of the instruction have _e32 and _e64
1407+
// respectively appended to their assembly mnemonic.
1408+
// _e64 is printed as part of the VOPDstS64orS32 operand, whereas
1409+
// the destination-less 32bit forms add it to the asmString here.
1410+
VOPC_Real<ps32, Gen.Subtarget, asm_name#"_e32">,
1411+
VOPCe<op{7-0}>;
1412+
def _e64#Gen.Suffix :
1413+
VOP3_Real_Gen<ps64, Gen, asm_name>,
1414+
VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl> {
1415+
// Encoding used for VOPC instructions encoded as VOP3 differs from
1416+
// VOP3e by destination name (sdst) as VOPC doesn't have vector dst.
1417+
bits<8> sdst;
1418+
let Inst{7-0} = sdst;
14341419
}
1435-
defvar AsmDPP8 = ps32.Pfl.AsmDPP8;
1436-
def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32, asm_name>;
1437-
def _e32_dpp8_w32#Gen.Suffix
1438-
: VOPC_DPP8<op{7-0}, ps32, asm_name> {
1439-
let AsmString = asm_name # " vcc_lo, " # AsmDPP8;
1440-
let isAsmParserOnly = 1;
1441-
let WaveSizePredicate = isWave32;
1442-
}
1443-
def _e32_dpp8_w64#Gen.Suffix
1444-
: VOPC_DPP8<op{7-0}, ps32, asm_name> {
1445-
let AsmString = asm_name # " vcc, " # AsmDPP8;
1446-
let isAsmParserOnly = 1;
1447-
let WaveSizePredicate = isWave64;
1420+
1421+
defm : VOPCInstAliases<OpName, !substr(Gen.Suffix, 1), NAME, asm_name>;
1422+
1423+
if ps32.Pfl.HasExtDPP then {
1424+
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName #"_e32" #"_dpp");
1425+
defvar AsmDPP = ps32.Pfl.AsmDPP16;
1426+
def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP,
1427+
Gen.Subtarget, asm_name>;
1428+
def _e32_dpp_w32#Gen.Suffix
1429+
: VOPC_DPP16<op{7-0}, psDPP, asm_name> {
1430+
let AsmString = asm_name # " vcc_lo, " # AsmDPP;
1431+
let isAsmParserOnly = 1;
1432+
let WaveSizePredicate = isWave32;
1433+
}
1434+
def _e32_dpp_w64#Gen.Suffix
1435+
: VOPC_DPP16<op{7-0}, psDPP, asm_name> {
1436+
let AsmString = asm_name # " vcc, " # AsmDPP;
1437+
let isAsmParserOnly = 1;
1438+
let WaveSizePredicate = isWave64;
1439+
}
1440+
defvar AsmDPP8 = ps32.Pfl.AsmDPP8;
1441+
def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32, asm_name>;
1442+
def _e32_dpp8_w32#Gen.Suffix
1443+
: VOPC_DPP8<op{7-0}, ps32, asm_name> {
1444+
let AsmString = asm_name # " vcc_lo, " # AsmDPP8;
1445+
let isAsmParserOnly = 1;
1446+
let WaveSizePredicate = isWave32;
1447+
}
1448+
def _e32_dpp8_w64#Gen.Suffix
1449+
: VOPC_DPP8<op{7-0}, ps32, asm_name> {
1450+
let AsmString = asm_name # " vcc, " # AsmDPP8;
1451+
let isAsmParserOnly = 1;
1452+
let WaveSizePredicate = isWave64;
1453+
}
14481454
}
1449-
}
14501455

1451-
if ps64.Pfl.HasExtVOP3DPP then {
1452-
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName #"_e64" #"_dpp");
1453-
def _e64_dpp#Gen.Suffix : VOPC64_DPP16_Dst<{0, op}, psDPP, asm_name>,
1454-
SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget>;
1455-
def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_Dst<{0, op}, ps64, asm_name>;
1456-
}
1457-
} // End AssemblerPredicate = Gen.AssemblerPredicate, DecoderNamespace = Gen.DecoderNamespace
1456+
if ps64.Pfl.HasExtVOP3DPP then {
1457+
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName #"_e64" #"_dpp");
1458+
def _e64_dpp#Gen.Suffix : VOPC64_DPP16_Dst<{0, op}, psDPP, asm_name>,
1459+
SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget>;
1460+
def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_Dst<{0, op}, ps64, asm_name>;
1461+
} // end if ps64.Pfl.HasExtVOP3DPP
1462+
} // End DecoderNamespace
1463+
} // End AssemblerPredicate
14581464
}
14591465

14601466
multiclass VOPC_Real_t16<GFXGen Gen, bits<9> op, string asm_name,
@@ -1514,51 +1520,57 @@ multiclass VOPCX_Real<GFXGen Gen, bits<9> op> {
15141520

15151521
multiclass VOPCX_Real_with_name<GFXGen Gen, bits<9> op, string OpName,
15161522
string asm_name, string pseudo_mnemonic = ""> {
1517-
let AssemblerPredicate = Gen.AssemblerPredicate, DecoderNamespace = Gen.DecoderNamespace in {
1518-
defvar ps32 = !cast<VOPC_Pseudo>(OpName#"_nosdst_e32");
1519-
defvar ps64 = !cast<VOP3_Pseudo>(OpName#"_nosdst_e64");
1520-
def _e32#Gen.Suffix
1521-
: VOPC_Real<ps32, Gen.Subtarget, asm_name>,
1522-
MnemonicAlias<!if(!empty(pseudo_mnemonic), !subst("_nosdst", "", ps32.Mnemonic),
1523-
pseudo_mnemonic),
1523+
defvar ps32 = !cast<VOPC_Pseudo>(OpName#"_nosdst_e32");
1524+
defvar ps64 = !cast<VOP3_Pseudo>(OpName#"_nosdst_e64");
1525+
let AssemblerPredicate = Gen.AssemblerPredicate in {
1526+
// MnemonicAlias and GCNPredicateControl both define the field Predicates,
1527+
// so GCNPredicateControl must come after MnemonicAlias because it contains
1528+
// the predicates we actually want.
1529+
def : MnemonicAlias<!if(!empty(pseudo_mnemonic), !subst("_nosdst", "", ps32.Mnemonic),
1530+
pseudo_mnemonic),
15241531
asm_name, ps32.AsmVariantName>,
1525-
Requires<[Gen.AssemblerPredicate]>,
1526-
VOPCe<op{7-0}> {
1527-
let AsmString = asm_name # "{_e32} " # ps32.AsmOperands;
1528-
}
1529-
def _e64#Gen.Suffix
1530-
: VOP3_Real<ps64, Gen.Subtarget, asm_name>,
1531-
MnemonicAlias<!if(!empty(pseudo_mnemonic), !subst("_nosdst", "", ps64.Mnemonic),
1532-
pseudo_mnemonic),
1532+
GCNPredicateControl;
1533+
def : MnemonicAlias<!if(!empty(pseudo_mnemonic), !subst("_nosdst", "", ps64.Mnemonic),
1534+
pseudo_mnemonic),
15331535
asm_name, ps64.AsmVariantName>,
1534-
Requires<[Gen.AssemblerPredicate]>,
1535-
VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl> {
1536-
let Inst{7-0} = ? ; // sdst
1537-
let AsmString = asm_name # "{_e64} " # ps64.AsmOperands;
1538-
}
1539-
1540-
defm : VOPCXInstAliases<OpName, !substr(Gen.Suffix, 1), NAME, asm_name>;
1536+
GCNPredicateControl;
15411537

1542-
if ps32.Pfl.HasExtDPP then {
1543-
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName#"_nosdst_e32"#"_dpp");
1544-
def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP,
1545-
Gen.Subtarget, asm_name>;
1546-
def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32, asm_name>;
1547-
}
1548-
if ps64.Pfl.HasExtVOP3DPP then {
1549-
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName#"_nosdst_e64"#"_dpp");
1550-
defvar AsmDPP = ps64.Pfl.AsmVOP3DPP16;
1551-
def _e64_dpp#Gen.Suffix
1552-
: VOPC64_DPP16_NoDst<{0, op}, psDPP, asm_name>,
1553-
SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget> {
1554-
let AsmString = asm_name # "{_e64_dpp} " # AsmDPP;
1538+
let DecoderNamespace = Gen.DecoderNamespace in {
1539+
def _e32#Gen.Suffix
1540+
: VOPC_Real<ps32, Gen.Subtarget, asm_name>,
1541+
VOPCe<op{7-0}> {
1542+
let AsmString = asm_name # "{_e32} " # ps32.AsmOperands;
15551543
}
1556-
defvar AsmDPP8 = ps64.Pfl.AsmVOP3DPP8;
1557-
def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_NoDst<{0, op}, ps64, asm_name> {
1558-
let AsmString = asm_name # "{_e64_dpp} " # AsmDPP8;
1544+
def _e64#Gen.Suffix
1545+
: VOP3_Real_Gen<ps64, Gen, asm_name>,
1546+
VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl> {
1547+
let Inst{7-0} = ? ; // sdst
1548+
let AsmString = asm_name # "{_e64} " # ps64.AsmOperands;
15591549
}
1560-
}
1561-
} // End AssemblerPredicate = Gen.AssemblerPredicate, DecoderNamespace = Gen.DecoderNamespace
1550+
1551+
defm : VOPCXInstAliases<OpName, !substr(Gen.Suffix, 1), NAME, asm_name>;
1552+
1553+
if ps32.Pfl.HasExtDPP then {
1554+
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName#"_nosdst_e32"#"_dpp");
1555+
def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP,
1556+
Gen.Subtarget, asm_name>;
1557+
def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32, asm_name>;
1558+
}
1559+
if ps64.Pfl.HasExtVOP3DPP then {
1560+
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName#"_nosdst_e64"#"_dpp");
1561+
defvar AsmDPP = ps64.Pfl.AsmVOP3DPP16;
1562+
def _e64_dpp#Gen.Suffix
1563+
: VOPC64_DPP16_NoDst<{0, op}, psDPP, asm_name>,
1564+
SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget> {
1565+
let AsmString = asm_name # "{_e64_dpp} " # AsmDPP;
1566+
}
1567+
defvar AsmDPP8 = ps64.Pfl.AsmVOP3DPP8;
1568+
def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_NoDst<{0, op}, ps64, asm_name> {
1569+
let AsmString = asm_name # "{_e64_dpp} " # AsmDPP8;
1570+
}
1571+
} // End if ps64.Pfl.HasExtVOP3DPP
1572+
} // End DecoderNamespace
1573+
} // End AssemblerPredicate
15621574
}
15631575

15641576
multiclass VOPCX_Real_t16<GFXGen Gen, bits<9> op, string asm_name,

0 commit comments

Comments
 (0)