Skip to content

[SPARC][IAS] Reject unknown/unavailable mnemonics early in ParseInstruction #96021

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

Conversation

koachan
Copy link
Contributor

@koachan koachan commented Jun 19, 2024

Validate and reject any unknown or unavailable instruction mnemonics early
in ParseInstruction, before any operand parsing is performed. Some operands
(mainly memory ones) can be parsed slightly differently in V8 and V9
assembly language, so by rejecting unknown or unavailable instructions early
we can prevent the error message from being shadowed by the one raised during
operand parsing.

As a side effect this also allows us to tell unknown and unavailable
mnemonics apart, and issue a suggestion in appropriate cases.

This is based on the approach taken by the MIPS backend.

koachan added 2 commits June 19, 2024 11:31
Created using spr 1.3.5
@llvmbot llvmbot added backend:Sparc mc Machine (object) code labels Jun 19, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 19, 2024

@llvm/pr-subscribers-backend-sparc

@llvm/pr-subscribers-mc

Author: Koakuma (koachan)

Changes

This enables ParseForAllFeatures to report the correct error message
when trying to assemble instructions not available in V8 mode.


Full diff: https://github.com/llvm/llvm-project/pull/96021.diff

3 Files Affected:

  • (modified) llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp (+2-1)
  • (modified) llvm/test/MC/Sparc/sparc-asm-errors.s (+1-1)
  • (modified) llvm/test/MC/Sparc/sparcv9-instructions.s (+26-26)
diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
index 3d8637bb8c359..34531fff31e8e 100644
--- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -1189,7 +1189,8 @@ ParseStatus SparcAsmParser::parseCallTarget(OperandVector &Operands) {
 ParseStatus SparcAsmParser::parseOperand(OperandVector &Operands,
                                          StringRef Mnemonic) {
 
-  ParseStatus Res = MatchOperandParserImpl(Operands, Mnemonic);
+  ParseStatus Res =
+      MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true);
 
   // If there wasn't a custom match, try the generic matcher below. Otherwise,
   // there was a match, but an error occurred, in which case, just return that
diff --git a/llvm/test/MC/Sparc/sparc-asm-errors.s b/llvm/test/MC/Sparc/sparc-asm-errors.s
index 780f4e7fad787..2b3a2eb2bfae6 100644
--- a/llvm/test/MC/Sparc/sparc-asm-errors.s
+++ b/llvm/test/MC/Sparc/sparc-asm-errors.s
@@ -11,7 +11,7 @@
         ! V9: unknown membar tag
         membar #BadTag
 
-        ! V8: instruction requires a CPU feature not currently enabled
+        ! V8: unexpected token
         ! V9: invalid membar mask number
         membar -127
 
diff --git a/llvm/test/MC/Sparc/sparcv9-instructions.s b/llvm/test/MC/Sparc/sparcv9-instructions.s
index a7761c10c509b..68ae2ac5c98a4 100644
--- a/llvm/test/MC/Sparc/sparcv9-instructions.s
+++ b/llvm/test/MC/Sparc/sparcv9-instructions.s
@@ -537,112 +537,112 @@
         ! V9: stxa %g0, [%g2+%i5] #ASI_SNF   ! encoding: [0xc0,0xf0,0x90,0x7d]
         stxa %g0, [%g2 + %i5] #ASI_SNF
 
-        ! V8:      error: invalid operand for instruction
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], 1
         ! V9: prefetch  [%i1+3968], #one_read  ! encoding: [0xc3,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], 1
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], #n_reads
         ! V9: prefetch  [%i1+3968], #n_reads  ! encoding: [0xc1,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], #n_reads
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], #one_read
         ! V9: prefetch  [%i1+3968], #one_read  ! encoding: [0xc3,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], #one_read
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], #n_writes
         ! V9: prefetch  [%i1+3968], #n_writes  ! encoding: [0xc5,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], #n_writes
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], #one_write
         ! V9: prefetch  [%i1+3968], #one_write  ! encoding: [0xc7,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], #one_write
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], #page
         ! V9: prefetch  [%i1+3968], #page  ! encoding: [0xc9,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], #page
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], #unified
         ! V9: prefetch  [%i1+3968], #unified  ! encoding: [0xe3,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], #unified
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], #n_reads_strong
         ! V9: prefetch  [%i1+3968], #n_reads_strong  ! encoding: [0xe9,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], #n_reads_strong
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], #one_read_strong
         ! V9: prefetch  [%i1+3968], #one_read_strong  ! encoding: [0xeb,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], #one_read_strong
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], #n_writes_strong
         ! V9: prefetch  [%i1+3968], #n_writes_strong  ! encoding: [0xed,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], #n_writes_strong
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + 0xf80 ], #one_write_strong
         ! V9: prefetch  [%i1+3968], #one_write_strong  ! encoding: [0xef,0x6e,0x6f,0x80]
         prefetch  [ %i1 + 0xf80 ], #one_write_strong
 
-        ! V8:      error: invalid operand for instruction
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], 1
         ! V9: prefetch  [%i1+%i2], #one_read  ! encoding: [0xc3,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], 1
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], #n_reads
         ! V9: prefetch  [%i1+%i2], #n_reads  ! encoding: [0xc1,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], #n_reads
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], #one_read
         ! V9: prefetch  [%i1+%i2], #one_read  ! encoding: [0xc3,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], #one_read
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], #n_writes
         ! V9: prefetch  [%i1+%i2], #n_writes  ! encoding: [0xc5,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], #n_writes
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], #one_write
         ! V9: prefetch  [%i1+%i2], #one_write  ! encoding: [0xc7,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], #one_write
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], #page
         ! V9: prefetch  [%i1+%i2], #page  ! encoding: [0xc9,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], #page
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], #unified
         ! V9: prefetch  [%i1+%i2], #unified  ! encoding: [0xe3,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], #unified
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], #n_reads_strong
         ! V9: prefetch  [%i1+%i2], #n_reads_strong  ! encoding: [0xe9,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], #n_reads_strong
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], #one_read_strong
         ! V9: prefetch  [%i1+%i2], #one_read_strong  ! encoding: [0xeb,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], #one_read_strong
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], #n_writes_strong
         ! V9: prefetch  [%i1+%i2], #n_writes_strong  ! encoding: [0xed,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], #n_writes_strong
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetch  [ %i1 + %i2 ], #one_write_strong
         ! V9: prefetch  [%i1+%i2], #one_write_strong  ! encoding: [0xef,0x6e,0x40,0x1a]
         prefetch  [ %i1 + %i2 ], #one_write_strong
@@ -657,22 +657,22 @@
         ! V9: prefetcha [%i1+3968] %asi, #one_read    ! encoding: [0xc3,0xee,0x6f,0x80]
         prefetcha  [ %i1 + 0xf80 ] %asi, #one_read
 
-        ! V8:      error: invalid operand for instruction
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetcha  [ %i1 + %i2 ] #ASI_SNF, 1
         ! V9: prefetcha [%i1+%i2] #ASI_SNF, #one_read ! encoding: [0xc3,0xee,0x50,0x7a]
         prefetcha  [ %i1 + %i2 ] #ASI_SNF, 1
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetcha  [ %i1 + %i2 ] #ASI_SNF, #one_read
         ! V9: prefetcha [%i1+%i2] #ASI_SNF, #one_read ! encoding: [0xc3,0xee,0x50,0x7a]
         prefetcha  [ %i1 + %i2 ] #ASI_SNF, #one_read
 
-        ! V8:      error: invalid operand for instruction
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetcha  [ %i1 + %i2 ] 131, 1
         ! V9: prefetcha [%i1+%i2] #ASI_SNF, #one_read ! encoding: [0xc3,0xee,0x50,0x7a]
         prefetcha  [ %i1 + %i2 ] 131, 1
 
-        ! V8:      error: unexpected token
+        ! V8:      error: instruction requires a CPU feature not currently enabled
         ! V8-NEXT: prefetcha  [ %i1 + %i2 ] 131, #one_read
         ! V9: prefetcha [%i1+%i2] #ASI_SNF, #one_read ! encoding: [0xc3,0xee,0x50,0x7a]
         prefetcha  [ %i1 + %i2 ] 131, #one_read

@@ -11,7 +11,7 @@
! V9: unknown membar tag
membar #BadTag

! V8: instruction requires a CPU feature not currently enabled
! V8: unexpected token
! V9: invalid membar mask number
membar -127
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The membar error messages seems to regress, seems like it prioritizes the parse error over the fact that membar is not available on V8? Am I missing something in the patch?

Copy link
Contributor

@s-barannikov s-barannikov Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are many places where ParseStatus is not handled correctly.
In this case, it is

    if (!parseOperand(Operands, Name).isSuccess()) {
      SMLoc Loc = getLexer().getLoc();
      return Error(Loc, "unexpected token");
    }

It should propagate the error returned by parseOperand instead of issuing another one.
Something like:

    ParseStatus R = parseOperand(Operands, Name);
    if (R.isFailure())
      return true;
    if (R.isNoMatch())
      return TokError( "unexpected token");
    // success, proceed to the next operand

or

    ParseStatus R = parseOperand(Operands, Name);
    if (R.isNoMatch())
      return TokError( "unexpected token");
    if (!R.isSuccess())
      return R;
    // success, proceed to the next operand

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears changing this line reveals other bugs. It may be worth making this change separately, before enabling ParseForAllFeatures.

@koachan koachan changed the title [SPARC][IAS] Enable ParseForAllFeatures in MatchOperandParserImpl [SPARC][IAS] Reject unknown/unavailable mnemonics early in ParseInstruction Jul 10, 2024
@koachan
Copy link
Contributor Author

koachan commented Jul 10, 2024

Hmmm, so, change of approach - I decided to follow what the MIPS backend does and validate all mnemonics early in ParseInstruction, before any operand parsing is done.
This gets IAS to emit the correct error message for missing instructions.

The misuse of ParseStatus returns still needs to be addressed, but at least I think with this approach it should no longer be a blocker for this particular issue?

Copy link
Contributor

@s-barannikov s-barannikov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The downside of this approach is that you lose the ability to report the missing features (unless you implement it yourself, which would be a code duplication), that would allow to produce better diagnostics like "instruction requires: LeonCASA".

Also, sometimes a mnemonic is valid in both modes, but certain operand combinations are only allowed in V9, e.g. swapa with r+i addressing mode. In this case you still rely on MatchOperandParserImpl & MatchInstructionImpl, which can produce different / broken diagnostics.

I'd still vote for ParseForAllFeatures, but I don't insist since people are unlikely to see these diagnostics anyway.

@koachan
Copy link
Contributor Author

koachan commented Jul 11, 2024

Merging this for now, but to clarify a little:

The downside of this approach is that you lose the ability to report the missing features (unless you implement it yourself, which would be a code duplication), that would allow to produce better diagnostics like "instruction requires: LeonCASA".

It seems that there are no autogenerated and/or common functions that can report what is exactly the missing feature. A quick look at the other backends also shows that the ones that do support reporting that implements it by themselves (unless I'm missing something here?).

Also, sometimes a mnemonic is valid in both modes, but certain operand combinations are only allowed in V9, e.g. swapa with r+i addressing mode. In this case you still rely on MatchOperandParserImpl & MatchInstructionImpl, which can produce different / broken diagnostics.

Yeah, this is what is bugging me too.
As far as I understand it, MatchInstructionImpl is only called at the very end of the process, after all the operands have been parsed. On the other hand, since some operand combinations are only allowed in V9, operand parsing can fail early.
So this is what will happen when parsing, say, a prefetcha with r+i addressing mode when targeting V8 (e.g. prefetcha [%i1+1] %asi, 2, invalid instruction with invalid operand):

  1. MatchOperandParserImpl is called. This will return a NoMatch[1], which will cause IAS to continue to the generic matcher in parseOperand...
  2. Which then fails because the %asi token in the r+i addressing isn't recognized in V8 mode.

In the end the error that will go out is one from the operand check, instead of the mnemonic check - since IAS haven't gotten far enough to reach MatchInstructionImpl yet - unless there is a way to defer the error from the operand check until just after MatchInstructionImpl is done (is it possible?).
Rejecting the mnemonic early should be okay since by the time IAS reaches MatchOperandParserImpl/MatchInstructionImpl we are already sure that we have a valid mnemonic, and any other errors that is going to be raised won't be related to mnemonics.

On cases like swapa the mnemonic check will succeed either way, so it is up to the operand checks to decide whether the full instruction makes sense for a given ISA or not.

[1] MatchOperandParserImpl return value does not differentiate between unavailable mnemonic, unknown mnemonic, or not being able to find a custom parser, so in all three cases parseOperand will just fall through to the generic matcher, so at least in this particular case there is no difference between ParseForAllFeatures being enabled or not.

@koachan koachan changed the base branch from users/koachan/spr/main.sparcias-enable-parseforallfeatures-in-matchoperandparserimpl to main July 11, 2024 04:33
@koachan koachan merged commit a92bcb2 into main Jul 11, 2024
4 of 6 checks passed
@koachan koachan deleted the users/koachan/spr/sparcias-enable-parseforallfeatures-in-matchoperandparserimpl branch July 11, 2024 04:33
aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this pull request Jul 14, 2024
…uction

Validate and reject any unknown or unavailable instruction mnemonics early
in ParseInstruction, before any operand parsing is performed. Some operands
(mainly memory ones) can be parsed slightly differently in V8 and V9
assembly language, so by rejecting unknown or unavailable instructions early
we can prevent the error message from being shadowed by the one raised during
operand parsing.

As a side effect this also allows us to tell unknown and unavailable
mnemonics apart, and issue a suggestion in appropriate cases.

This is based on the approach taken by the MIPS backend.

Reviewers: brad0, rorth, s-barannikov, jrtc27

Reviewed By: s-barannikov

Pull Request: llvm#96021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:Sparc mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants