Skip to content

[AMDGPU][AsmParser] Some instructions are indistinguishable to AsmParser #69256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kosarev opened this issue Oct 16, 2023 · 4 comments
Open

Comments

@kosarev
Copy link
Collaborator

kosarev commented Oct 16, 2023

There are instructions in the AMDGPU backend that have identical mnemonics and operands:

$ grep 'BUFFER_ATOMIC_FCMPSWAP_OFFSET_.*gfx10' AMDGPUGenAsmMatcher.inc
  { 460 /* buffer_atomic_fcmpswap */, AMDGPU::BUFFER_ATOMIC_FCMPSWAP_OFFSET_RTN_gfx10, ConvertCustom_cvtMubufAtomic, AMFBS_isGFX6GFX7GFX10Plus_isGFX10Only, { MCK_AV_64, MCK_off, MCK_SReg_128, MCK_SCSrcB32, MCK_Offset, MCK_CPol }, },
  { 460 /* buffer_atomic_fcmpswap */, AMDGPU::BUFFER_ATOMIC_FCMPSWAP_OFFSET_gfx10, ConvertCustom_cvtMubufAtomic, AMFBS_isGFX6GFX7GFX10Plus_isGFX10Only, { MCK_AV_64, MCK_off, MCK_SReg_128, MCK_SCSrcB32, MCK_Offset, MCK_CPol }, },

Note that both the instructions have { MCK_AV_64, MCK_off, MCK_SReg_128, MCK_SCSrcB32, MCK_Offset, MCK_CPol } as their lists of operand kinds. This means that for a set of parsed operands that is suitable for these instructions as determined by calling their corresponding operand class predicates, of these two instructions AsmParser will select the one that is happened to match first. For instructions with identical mnemonics, operands and features the matching order is generally not defined.

Furthermore, where otherwise identical instructions have operands defined in TableGen as having different AsmOperandClasses, the matching order is determined by comparing the names of these AsmOperandClasses:

return ValueName < RHS.ValueName;
Particularly, when both the classes are anonymous, which is often the case in the AMDGPU backend, the matching order will therefore depend on their generated names. Generated names of anonymous TableGen entites have the form anonymous_<n>, where <n> is a number that depends on when during the work of the TableGen's internal machinery this entity was defined relative to other anonymous entities, see RecordKeeper::getNewAnonymousName(). This in turn means that the instruction matching order is generally susceptible to where in .td files used AsmOperandClasses have been defined.

As I side note, we seem to have special code in TableGen that checks specifically for ambiguous matchables (instructions):

DEBUG_WITH_TYPE("ambiguous_instrs", {
However, because different anonymous operand classes are never considered equal, couldMatchAmbiguouslyWith() doesn't flag such cases.

Caught on an attempt to prepare an NFC patch involving adding an anonymous operand class, which led to failures on regression tests.

A subtask of #62629.

@llvmbot
Copy link
Member

llvmbot commented Oct 16, 2023

@llvm/issue-subscribers-backend-amdgpu

Author: Ivan Kosarev (kosarev)

There are instructions in the AMDGPU backend that have identical mnemonics and operands:
$ grep 'BUFFER_ATOMIC_FCMPSWAP_OFFSET_.*gfx10' AMDGPUGenAsmMatcher.inc
  { 460 /* buffer_atomic_fcmpswap */, AMDGPU::BUFFER_ATOMIC_FCMPSWAP_OFFSET_RTN_gfx10, ConvertCustom_cvtMubufAtomic, AMFBS_isGFX6GFX7GFX10Plus_isGFX10Only, { MCK_AV_64, MCK_off, MCK_SReg_128, MCK_SCSrcB32, MCK_Offset, MCK_CPol }, },
  { 460 /* buffer_atomic_fcmpswap */, AMDGPU::BUFFER_ATOMIC_FCMPSWAP_OFFSET_gfx10, ConvertCustom_cvtMubufAtomic, AMFBS_isGFX6GFX7GFX10Plus_isGFX10Only, { MCK_AV_64, MCK_off, MCK_SReg_128, MCK_SCSrcB32, MCK_Offset, MCK_CPol }, },

Note that both the instructions have { MCK_AV_64, MCK_off, MCK_SReg_128, MCK_SCSrcB32, MCK_Offset, MCK_CPol } as their lists of operand kinds. This means that for a set of parsed operands that is suitable for these instructions as determined by calling their corresponding operand class predicates, of these two instructions AsmParser will select the one that is happened to match first. For instructions with identical mnemonics, operands and features the matching order is generally not defined.

Furthermore, where otherwise identical instructions have operands defined in TableGen as having different AsmOperandClasses, the matching order is determined by comparing the names of these AsmOperandClasses:

return ValueName < RHS.ValueName;
Particularly, when both the classes are anonymous, which is often the case in the AMDGPU backend, the matching order will therefore depend on their generated names. Generated names of anonymous TableGen entites have the form anonymous_&lt;n&gt;, where &lt;n&gt; is a number that depends on when during the work of the TableGen's internal machinery this entity was defined relative to other anonymous entities, see RecordKeeper::getNewAnonymousName(). This in turn means that the instruction matching order is generally susceptible to where in .td files used AsmOperandClasses have been defined.

As I side note, we seem to have special code in TableGen that checks specifically for ambiguous matchables (instructions):

DEBUG_WITH_TYPE("ambiguous_instrs", {
However, because different anonymous operand classes are never considered equal, couldMatchAmbiguouslyWith() doesn't flag such cases.

Caught on an attempt to prepare an NFC patch involving adding an anonymous operand class, which led to failures on regression tests.

A subtask of #62629.

@jayfoad
Copy link
Contributor

jayfoad commented Oct 17, 2023

  1. What kind of problems occur when the matching order changes?
  2. How do you think this should be fixed? In the BUFFER_ATOMIC_FCMPSWAP_OFFSET case, I guess the intention was that the RTN form would only match when the glc bit is set, and the non-RTN form would only match when glc is not set.

@kosarev
Copy link
Collaborator Author

kosarev commented Oct 17, 2023

  1. What kind of problems occur when the matching order changes?
  2. How do you think this should be fixed? In the BUFFER_ATOMIC_FCMPSWAP_OFFSET case, I guess the intention was that the RTN form would only match when the glc bit is set, and the non-RTN form would only match when glc is not set.

For instructions that look identical to the AsmParser machinery we may end up matching the wrong instruction, which is what actually happened as I was trying to fix the predicates for DefaultOperands, such as CPol_0 and CPol_GLC1, to take their expected values into account. This required giving them their own special operand classes, because this is where predicates are specified. But since these new classes have different names, this changed the matching order.

(I think I was wrong saying it above that it is the names of the classes themselves that matter. I was investigating this months ago and now that I refresh my memory, I think it's the Name fields of the classes actually, though this doesn't change much in the analysis of the problem.)

Regarding means to fix this, maybe we could start with using the HasPositionOrder field of the TableGen's Instruction class to mitigate the problem with floating matching orders. That would allow us to then fix DefaultOperand predicates and likely make life a bit easier working on other AsmParser tasks involving adding new operand classes. After that we could probably think about fixing the ordering logic in such a way that would not require relying on HasPositionOrder and do the expected thing automatically. Then once the ordering logic is in order, I think it would be nice to improve the ambiguity checks to catch more, preferably all, problems of this sort. And ultimately, I think it would be fair to say that our goal is a simple, reliable and intuitive interface to AsmParser that would eliminate the flow of mistakes and frustration about what and how needs to be done when comes to adding new or changing existing instruction operands -- that's what #62629 attempts to provide.

That apart, it's also possible that we will have to teach the AsmMatcherEmitter backend how to deal with optional operands. It seems it currently just ignores their existence. I don't have any concrete reproducers, but suspect that fixing the ordering logic will require taking them into account.

@kosarev
Copy link
Collaborator Author

kosarev commented Oct 18, 2023

This reproduces the problem. Supposed to be an NFC, but causes failures on check-llvm-mc-amdgpu. Tested on 561fcf5.

diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
index b0b91d831718..7301deb597ae 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
@@ -1038,10 +1038,19 @@ class NamedBitOperand<string Id, string Name = NAME>
 
 class DefaultOperand<CustomOperand Op, int Value>
   : OperandWithDefaultOps<Op.Type, (ops (Op.Type Value))>,
-    CustomOperandProps<1, Op.ParserMatchClass.Name> {
+    CustomOperandProps<1> {
+  let PredicateMethod = Op.ParserMatchClass.PredicateMethod;
+  // Give this operand a class that is identical to that of Op.
+  let ImmTy = Op.ImmTy;
   let PredicateMethod = Op.ParserMatchClass.PredicateMethod;
   let ParserMethod = Op.ParserMatchClass.ParserMethod;
+  let DefaultValue = Op.DefaultValue;
   let PrintMethod = Op.PrintMethod;
+
+  // check-llvm-mc-amdgpu tests fail unless we use the class of Op,
+  // despite both classes being identical in all their attributes
+  // (except the Name fields, which should not matter).
+  // let ParserMatchClass = Op.ParserMatchClass;
 }
 
 class SDWAOperand<string Id, string Name = NAME>
$ ninja check-llvm-mc-amdgpu
...
Failed Tests (17):
  LLVM :: MC/AMDGPU/expressions.s
  LLVM :: MC/AMDGPU/gfx1030_new.s
  LLVM :: MC/AMDGPU/gfx10_asm_mubuf.s
  LLVM :: MC/AMDGPU/gfx10_asm_smem.s
  LLVM :: MC/AMDGPU/gfx11_asm_mubuf.s
  LLVM :: MC/AMDGPU/gfx11_asm_mubuf_alias.s
  LLVM :: MC/AMDGPU/gfx7_asm_mubuf.s
  LLVM :: MC/AMDGPU/gfx8_asm_mubuf.s
  LLVM :: MC/AMDGPU/gfx90a_asm_features.s
  LLVM :: MC/AMDGPU/gfx90a_ldst_acc.s
  LLVM :: MC/AMDGPU/gfx940_asm_features.s
  LLVM :: MC/AMDGPU/gfx9_asm_mubuf.s
  LLVM :: MC/AMDGPU/gfx9_asm_smem.s
  LLVM :: MC/AMDGPU/mubuf-gfx10.s
  LLVM :: MC/AMDGPU/mubuf.s
  LLVM :: MC/AMDGPU/smem.s
  LLVM :: MC/AMDGPU/trap.s


Testing Time: 1.62s
  Passed           : 326
  Expectedly Failed:   1
  Failed           :  17

kosarev added a commit to kosarev/llvm-project that referenced this issue Oct 26, 2023
This resolves AsmParser ambiguity between them and similar instructions
for other subtargets, e.g., V_PK_SUB_U16_vi being identical to
V_PK_SUB_U16_gfx11 on GFX11.

Part of <llvm#69256>.
kosarev added a commit that referenced this issue Oct 27, 2023
…e. (#70334)

This resolves AsmParser ambiguity between them and similar instructions
for other subtargets, e.g., V_PK_SUB_U16_vi being identical to
V_PK_SUB_U16_gfx11 on GFX11.

Part of <#69256>.
kosarev added a commit that referenced this issue Oct 30, 2023
Resolves AsmParser ambiguity, e.g., V_MFMA_I32_32X32X8I8_vi currently
has isGFX908orGFX90A as its subtarget predicate, which makes it
identical to V_MFMA_I32_32X32X8I8_gfx90a_acd on GFX90A.

Part of <#69256>.
@kosarev kosarev changed the title [AMDGPU][AsmParser] Some instructions are indistiguishable to AsmParser [AMDGPU][AsmParser] Some instructions are indistinguishable to AsmParser Nov 6, 2023
kosarev added a commit to kosarev/llvm-project that referenced this issue Nov 7, 2023
…tructions.

Resolves AsmParser ambiguities, e.g., between V_FMA_MIXLO_F16_vi and
V_FMA_MIXLO_F16_gfx11.

Part of <llvm#69256>.
kosarev added a commit that referenced this issue Nov 7, 2023
…tructions. (#71194)

Resolves AsmParser ambiguities, e.g., between V_FMA_MIXLO_F16_vi and
V_FMA_MIXLO_F16_gfx11.

Part of <#69256>.
kosarev added a commit that referenced this issue Nov 10, 2023
…s. (#71799)

CPol and CPol_GLC1 operand classes have identical predicates, which
means AsmParser cannot differentiate between the RTN and non-RTN
variants of the instructions. When it currently selects the wrong
instruction, a hack in cvtSMEMAtomic() corrects the op-code. Using the
new predicated-value operands makes this hack and the whole conversion
function not needed.

Other uses of CPol_GLC1 operands are to be addressed separately.

Resolves about half of the remaining ~1000 pairs of ambiguous
instructions.

Part of <#69256>.
kosarev added a commit that referenced this issue Nov 14, 2023
Resolves AsmParser ambiguities, e.g., between BUFFER_WBINVL1_vi and
BUFFER_WBINVL1_gfx6_gfx7.

Part of <#69256>.
zahiraam pushed a commit to zahiraam/llvm-project that referenced this issue Nov 20, 2023
…s. (llvm#71799)

CPol and CPol_GLC1 operand classes have identical predicates, which
means AsmParser cannot differentiate between the RTN and non-RTN
variants of the instructions. When it currently selects the wrong
instruction, a hack in cvtSMEMAtomic() corrects the op-code. Using the
new predicated-value operands makes this hack and the whole conversion
function not needed.

Other uses of CPol_GLC1 operands are to be addressed separately.

Resolves about half of the remaining ~1000 pairs of ambiguous
instructions.

Part of <llvm#69256>.
zahiraam pushed a commit to zahiraam/llvm-project that referenced this issue Nov 20, 2023
Resolves AsmParser ambiguities, e.g., between BUFFER_WBINVL1_vi and
BUFFER_WBINVL1_gfx6_gfx7.

Part of <llvm#69256>.
kosarev added a commit to kosarev/llvm-project that referenced this issue Nov 22, 2023
Resolves AsmParser ambiguities, e.g., between
BUFFER_ATOMIC_XOR_X2_BOTHEN_vi and BUFFER_ATOMIC_XOR_X2_BOTHEN_RTN_vi.

Part of <llvm#69256>.
kosarev added a commit that referenced this issue Nov 23, 2023
Resolves AsmParser ambiguities, e.g., between
BUFFER_ATOMIC_XOR_X2_BOTHEN_vi and BUFFER_ATOMIC_XOR_X2_BOTHEN_RTN_vi.

Part of <#69256>.
kosarev added a commit that referenced this issue Jan 10, 2024
Resolves AsmParser ambiguities, e.g., between
V_SUBREV_F16_t16_dpp8_gfx11 and V_SUBREV_F16_t16_dpp8_gfx12.

Part of <#69256>.
kosarev added a commit to kosarev/llvm-project that referenced this issue Jan 16, 2024
Resolves AsmParser ambiguities, e.g., between V_DOT4C_I32_I8_dpp_vi and
V_DOT4C_I32_I8_dpp_gfx10. The latter is predicated with isGFX10Only while
the first has no subtarget generation predicates.

Part of <llvm#69256>.
kosarev added a commit that referenced this issue Jan 16, 2024
Resolves AsmParser ambiguities, e.g., between V_DOT4C_I32_I8_dpp_vi and
V_DOT4C_I32_I8_dpp_gfx10. The latter is predicated with isGFX10Only
while the first has no subtarget generation predicates.

Part of <#69256>.
kosarev added a commit that referenced this issue Jan 24, 2024
…tions. (#79131)

As otherwise SGPR+IMM instructions are not distinguishable to SGPR-only
ones in AsmParser, leading to ambiguities.

GFX12 doesn't have special SGPR-only variants, so we still allow
optional immediate offsets for the subtarget.

Also rename the offset operand classes while there.

Part of <#69256>.
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this issue Jan 28, 2024
Resolves AsmParser ambiguities, e.g., between
V_SUBREV_F16_t16_dpp8_gfx11 and V_SUBREV_F16_t16_dpp8_gfx12.

Part of <llvm#69256>.
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this issue Jan 28, 2024
Resolves AsmParser ambiguities, e.g., between V_DOT4C_I32_I8_dpp_vi and
V_DOT4C_I32_I8_dpp_gfx10. The latter is predicated with isGFX10Only
while the first has no subtarget generation predicates.

Part of <llvm#69256>.
qihangkong pushed a commit to rvgpu/llvm that referenced this issue Apr 18, 2024
Resolves AsmParser ambiguity, e.g., V_MFMA_I32_32X32X8I8_vi currently has
isGFX908orGFX90A as its subtarget predicate, which makes it identical to
V_MFMA_I32_32X32X8I8_gfx90a_acd on GFX90A.

Part of <llvm/llvm-project#69256>.
qihangkong pushed a commit to rvgpu/llvm that referenced this issue Apr 18, 2024
CPol and CPol_GLC1 operand classes have identical predicates, which means
AsmParser cannot differentiate between the RTN and non-RTN variants of
the instructions. When it currently selects the wrong instruction, a hack
in cvtSMEMAtomic() corrects the op-code. Using the new predicated-value
operands makes this hack and the whole conversion function not needed.

Other uses of CPol_GLC1 operands are to be addressed separately.

Resolves about half of the remaining ~1000 pairs of ambiguous
instructions.

Part of <llvm/llvm-project#69256>.
qihangkong pushed a commit to rvgpu/llvm that referenced this issue Apr 18, 2024
Resolves AsmParser ambiguities, e.g., between BUFFER_WBINVL1_vi and
BUFFER_WBINVL1_gfx6_gfx7.

Part of <llvm/llvm-project#69256>.
qihangkong pushed a commit to rvgpu/llvm that referenced this issue Apr 18, 2024
…tructions. (#71194)

Resolves AsmParser ambiguities, e.g., between V_FMA_MIXLO_F16_vi and
V_FMA_MIXLO_F16_gfx11.

Part of <llvm/llvm-project#69256>.
qihangkong pushed a commit to rvgpu/llvm that referenced this issue Apr 18, 2024
Resolves AsmParser ambiguities, e.g., between
V_SUBREV_F16_t16_dpp8_gfx11 and V_SUBREV_F16_t16_dpp8_gfx12.

Part of <llvm/llvm-project#69256>.
qihangkong pushed a commit to rvgpu/llvm that referenced this issue Apr 18, 2024
…tions.

As otherwise SGPR+IMM instructions are not distinguishable to SGPR-only
ones in AsmParser, leading to ambiguities.

GFX12 doesn't have special SGPR-only variants, so we still allow optional
immediate offsets for the subtarget.

Also rename the offset operand classes while there.

Part of <llvm/llvm-project#69256>.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants