Skip to content

Commit

Permalink
[AMDGPU][MC] Separate VOPC MnemonicAlias from Instruction (#89105)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Sisyph committed Apr 18, 2024
1 parent 68e814d commit 44713f1
Showing 1 changed file with 117 additions and 105 deletions.
222 changes: 117 additions & 105 deletions llvm/lib/Target/AMDGPU/VOPCInstructions.td
Original file line number Diff line number Diff line change
Expand Up @@ -1386,75 +1386,81 @@ multiclass VOPC_Real_Base<GFXGen Gen, bits<9> op> {

multiclass VOPC_Real_with_name<GFXGen Gen, bits<9> op, string OpName,
string asm_name, string pseudo_mnemonic = ""> {
let AssemblerPredicate = Gen.AssemblerPredicate, DecoderNamespace = Gen.DecoderNamespace in {
defvar ps32 = !cast<VOPC_Pseudo>(OpName#"_e32");
defvar ps64 = !cast<VOP3_Pseudo>(OpName#"_e64");
def _e32#Gen.Suffix :
// 32 and 64 bit forms of the instruction have _e32 and _e64
// respectively appended to their assembly mnemonic.
// _e64 is printed as part of the VOPDstS64orS32 operand, whereas
// the destination-less 32bit forms add it to the asmString here.
VOPC_Real<ps32, Gen.Subtarget, asm_name#"_e32">,
VOPCe<op{7-0}>,
MnemonicAlias<!if(!empty(pseudo_mnemonic), ps32.Mnemonic,
pseudo_mnemonic),
asm_name, ps32.AsmVariantName>,
Requires<[Gen.AssemblerPredicate]>;
def _e64#Gen.Suffix :
VOP3_Real<ps64, Gen.Subtarget, asm_name>,
VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl>,
MnemonicAlias<!if(!empty(pseudo_mnemonic), ps64.Mnemonic,
pseudo_mnemonic),
defvar ps32 = !cast<VOPC_Pseudo>(OpName#"_e32");
defvar ps64 = !cast<VOP3_Pseudo>(OpName#"_e64");
let AssemblerPredicate = Gen.AssemblerPredicate in {
// MnemonicAlias and GCNPredicateControl both define the field Predicates,
// so GCNPredicateControl must come after MnemonicAlias because it contains
// the predicates we actually want.
def : MnemonicAlias<!if(!empty(pseudo_mnemonic), ps32.Mnemonic,
pseudo_mnemonic),
asm_name, ps32.AsmVariantName>,
GCNPredicateControl;
def : MnemonicAlias<!if(!empty(pseudo_mnemonic), ps64.Mnemonic,
pseudo_mnemonic),
asm_name, ps64.AsmVariantName>,
Requires<[Gen.AssemblerPredicate]> {
// Encoding used for VOPC instructions encoded as VOP3 differs from
// VOP3e by destination name (sdst) as VOPC doesn't have vector dst.
bits<8> sdst;
let Inst{7-0} = sdst;
}

defm : VOPCInstAliases<OpName, !substr(Gen.Suffix, 1), NAME, asm_name>;

if ps32.Pfl.HasExtDPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName #"_e32" #"_dpp");
defvar AsmDPP = ps32.Pfl.AsmDPP16;
def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP,
Gen.Subtarget, asm_name>;
def _e32_dpp_w32#Gen.Suffix
: VOPC_DPP16<op{7-0}, psDPP, asm_name> {
let AsmString = asm_name # " vcc_lo, " # AsmDPP;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
def _e32_dpp_w64#Gen.Suffix
: VOPC_DPP16<op{7-0}, psDPP, asm_name> {
let AsmString = asm_name # " vcc, " # AsmDPP;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave64;
GCNPredicateControl;

let DecoderNamespace = Gen.DecoderNamespace in {
def _e32#Gen.Suffix :
// 32 and 64 bit forms of the instruction have _e32 and _e64
// respectively appended to their assembly mnemonic.
// _e64 is printed as part of the VOPDstS64orS32 operand, whereas
// the destination-less 32bit forms add it to the asmString here.
VOPC_Real<ps32, Gen.Subtarget, asm_name#"_e32">,
VOPCe<op{7-0}>;
def _e64#Gen.Suffix :
VOP3_Real_Gen<ps64, Gen, asm_name>,
VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl> {
// Encoding used for VOPC instructions encoded as VOP3 differs from
// VOP3e by destination name (sdst) as VOPC doesn't have vector dst.
bits<8> sdst;
let Inst{7-0} = sdst;
}
defvar AsmDPP8 = ps32.Pfl.AsmDPP8;
def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32, asm_name>;
def _e32_dpp8_w32#Gen.Suffix
: VOPC_DPP8<op{7-0}, ps32, asm_name> {
let AsmString = asm_name # " vcc_lo, " # AsmDPP8;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
def _e32_dpp8_w64#Gen.Suffix
: VOPC_DPP8<op{7-0}, ps32, asm_name> {
let AsmString = asm_name # " vcc, " # AsmDPP8;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave64;

defm : VOPCInstAliases<OpName, !substr(Gen.Suffix, 1), NAME, asm_name>;

if ps32.Pfl.HasExtDPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName #"_e32" #"_dpp");
defvar AsmDPP = ps32.Pfl.AsmDPP16;
def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP,
Gen.Subtarget, asm_name>;
def _e32_dpp_w32#Gen.Suffix
: VOPC_DPP16<op{7-0}, psDPP, asm_name> {
let AsmString = asm_name # " vcc_lo, " # AsmDPP;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
def _e32_dpp_w64#Gen.Suffix
: VOPC_DPP16<op{7-0}, psDPP, asm_name> {
let AsmString = asm_name # " vcc, " # AsmDPP;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave64;
}
defvar AsmDPP8 = ps32.Pfl.AsmDPP8;
def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32, asm_name>;
def _e32_dpp8_w32#Gen.Suffix
: VOPC_DPP8<op{7-0}, ps32, asm_name> {
let AsmString = asm_name # " vcc_lo, " # AsmDPP8;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave32;
}
def _e32_dpp8_w64#Gen.Suffix
: VOPC_DPP8<op{7-0}, ps32, asm_name> {
let AsmString = asm_name # " vcc, " # AsmDPP8;
let isAsmParserOnly = 1;
let WaveSizePredicate = isWave64;
}
}
}

if ps64.Pfl.HasExtVOP3DPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName #"_e64" #"_dpp");
def _e64_dpp#Gen.Suffix : VOPC64_DPP16_Dst<{0, op}, psDPP, asm_name>,
SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget>;
def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_Dst<{0, op}, ps64, asm_name>;
}
} // End AssemblerPredicate = Gen.AssemblerPredicate, DecoderNamespace = Gen.DecoderNamespace
if ps64.Pfl.HasExtVOP3DPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName #"_e64" #"_dpp");
def _e64_dpp#Gen.Suffix : VOPC64_DPP16_Dst<{0, op}, psDPP, asm_name>,
SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget>;
def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_Dst<{0, op}, ps64, asm_name>;
} // end if ps64.Pfl.HasExtVOP3DPP
} // End DecoderNamespace
} // End AssemblerPredicate
}

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

multiclass VOPCX_Real_with_name<GFXGen Gen, bits<9> op, string OpName,
string asm_name, string pseudo_mnemonic = ""> {
let AssemblerPredicate = Gen.AssemblerPredicate, DecoderNamespace = Gen.DecoderNamespace in {
defvar ps32 = !cast<VOPC_Pseudo>(OpName#"_nosdst_e32");
defvar ps64 = !cast<VOP3_Pseudo>(OpName#"_nosdst_e64");
def _e32#Gen.Suffix
: VOPC_Real<ps32, Gen.Subtarget, asm_name>,
MnemonicAlias<!if(!empty(pseudo_mnemonic), !subst("_nosdst", "", ps32.Mnemonic),
pseudo_mnemonic),
defvar ps32 = !cast<VOPC_Pseudo>(OpName#"_nosdst_e32");
defvar ps64 = !cast<VOP3_Pseudo>(OpName#"_nosdst_e64");
let AssemblerPredicate = Gen.AssemblerPredicate in {
// MnemonicAlias and GCNPredicateControl both define the field Predicates,
// so GCNPredicateControl must come after MnemonicAlias because it contains
// the predicates we actually want.
def : MnemonicAlias<!if(!empty(pseudo_mnemonic), !subst("_nosdst", "", ps32.Mnemonic),
pseudo_mnemonic),
asm_name, ps32.AsmVariantName>,
Requires<[Gen.AssemblerPredicate]>,
VOPCe<op{7-0}> {
let AsmString = asm_name # "{_e32} " # ps32.AsmOperands;
}
def _e64#Gen.Suffix
: VOP3_Real<ps64, Gen.Subtarget, asm_name>,
MnemonicAlias<!if(!empty(pseudo_mnemonic), !subst("_nosdst", "", ps64.Mnemonic),
pseudo_mnemonic),
GCNPredicateControl;
def : MnemonicAlias<!if(!empty(pseudo_mnemonic), !subst("_nosdst", "", ps64.Mnemonic),
pseudo_mnemonic),
asm_name, ps64.AsmVariantName>,
Requires<[Gen.AssemblerPredicate]>,
VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl> {
let Inst{7-0} = ? ; // sdst
let AsmString = asm_name # "{_e64} " # ps64.AsmOperands;
}

defm : VOPCXInstAliases<OpName, !substr(Gen.Suffix, 1), NAME, asm_name>;
GCNPredicateControl;

if ps32.Pfl.HasExtDPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName#"_nosdst_e32"#"_dpp");
def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP,
Gen.Subtarget, asm_name>;
def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32, asm_name>;
}
if ps64.Pfl.HasExtVOP3DPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName#"_nosdst_e64"#"_dpp");
defvar AsmDPP = ps64.Pfl.AsmVOP3DPP16;
def _e64_dpp#Gen.Suffix
: VOPC64_DPP16_NoDst<{0, op}, psDPP, asm_name>,
SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget> {
let AsmString = asm_name # "{_e64_dpp} " # AsmDPP;
let DecoderNamespace = Gen.DecoderNamespace in {
def _e32#Gen.Suffix
: VOPC_Real<ps32, Gen.Subtarget, asm_name>,
VOPCe<op{7-0}> {
let AsmString = asm_name # "{_e32} " # ps32.AsmOperands;
}
defvar AsmDPP8 = ps64.Pfl.AsmVOP3DPP8;
def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_NoDst<{0, op}, ps64, asm_name> {
let AsmString = asm_name # "{_e64_dpp} " # AsmDPP8;
def _e64#Gen.Suffix
: VOP3_Real_Gen<ps64, Gen, asm_name>,
VOP3a_gfx11_gfx12<{0, op}, ps64.Pfl> {
let Inst{7-0} = ? ; // sdst
let AsmString = asm_name # "{_e64} " # ps64.AsmOperands;
}
}
} // End AssemblerPredicate = Gen.AssemblerPredicate, DecoderNamespace = Gen.DecoderNamespace

defm : VOPCXInstAliases<OpName, !substr(Gen.Suffix, 1), NAME, asm_name>;

if ps32.Pfl.HasExtDPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName#"_nosdst_e32"#"_dpp");
def _e32_dpp#Gen.Suffix : VOPC_DPP16_SIMC<op{7-0}, psDPP,
Gen.Subtarget, asm_name>;
def _e32_dpp8#Gen.Suffix : VOPC_DPP8<op{7-0}, ps32, asm_name>;
}
if ps64.Pfl.HasExtVOP3DPP then {
defvar psDPP = !cast<VOP_DPP_Pseudo>(OpName#"_nosdst_e64"#"_dpp");
defvar AsmDPP = ps64.Pfl.AsmVOP3DPP16;
def _e64_dpp#Gen.Suffix
: VOPC64_DPP16_NoDst<{0, op}, psDPP, asm_name>,
SIMCInstr<psDPP.PseudoInstr, Gen.Subtarget> {
let AsmString = asm_name # "{_e64_dpp} " # AsmDPP;
}
defvar AsmDPP8 = ps64.Pfl.AsmVOP3DPP8;
def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_NoDst<{0, op}, ps64, asm_name> {
let AsmString = asm_name # "{_e64_dpp} " # AsmDPP8;
}
} // End if ps64.Pfl.HasExtVOP3DPP
} // End DecoderNamespace
} // End AssemblerPredicate
}

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

0 comments on commit 44713f1

Please sign in to comment.