Skip to content

[AMDGPU][MC] Fix out-of-range MFMA tuple register-name assertion - #215147

Merged
shiltian merged 1 commit into
mainfrom
users/shiltian/fix-disam-out-of-range-mfma-tuple
Aug 10, 2026
Merged

[AMDGPU][MC] Fix out-of-range MFMA tuple register-name assertion#215147
shiltian merged 1 commit into
mainfrom
users/shiltian/fix-disam-out-of-range-mfma-tuple

Conversation

@shiltian

@shiltian shiltian commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Fixes #215007.


This PR was assisted by AI but I reviewed all the changes.

@shiltian

shiltian commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-backend-amdgpu

Author: Shilei Tian (shiltian)

Changes

Fixes #215007.


This PR was assisted by AI but I reviewed all the changes.


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

3 Files Affected:

  • (modified) llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp (+51-34)
  • (modified) llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h (+2-2)
  • (modified) llvm/test/MC/Disassembler/AMDGPU/decode-err.txt (+16)
diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
index d05997cacba0a..ca1ec70327ff2 100644
--- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
+++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
@@ -962,11 +962,11 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
   if (SIInstrFlags::isSDWA(*MCII, MI))
     convertSDWAInst(MI);
 
-  if (SIInstrFlags::isMAI(*MCII, MI))
-    convertMAIInst(MI);
+  if (SIInstrFlags::isMAI(*MCII, MI) && !convertMAIInst(MI))
+    return MCDisassembler::Fail;
 
-  if (SIInstrFlags::isWMMA(*MCII, MI))
-    convertWMMAInst(MI);
+  if (SIInstrFlags::isWMMA(*MCII, MI) && !convertWMMAInst(MI))
+    return MCDisassembler::Fail;
 
   int VDstIn_Idx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
                                               AMDGPU::OpName::vdst_in);
@@ -1065,33 +1065,50 @@ void AMDGPUDisassembler::convertSDWAInst(MCInst &MI) const {
 
 /// Adjust the register values used by V_MFMA_F8F6F4_f8_f8 instructions to the
 /// appropriate subregister for the used format width.
-static void adjustMFMA_F8F6F4OpRegClass(const MCRegisterInfo &MRI,
+///
+/// \returns false if the operand cannot be narrowed down to \p NumRegs, which
+/// means the encoding is malformed.
+static bool adjustMFMA_F8F6F4OpRegClass(const MCRegisterInfo &MRI,
                                         MCOperand &MO, uint8_t NumRegs) {
+  // A malformed encoding can select an operand that is not a register at all.
+  if (!MO.isReg())
+    return false;
+
+  MCRegister NewReg;
   switch (NumRegs) {
   case 4:
-    return MO.setReg(MRI.getSubReg(MO.getReg(), AMDGPU::sub0_sub1_sub2_sub3));
+    NewReg = MRI.getSubReg(MO.getReg(), AMDGPU::sub0_sub1_sub2_sub3);
+    break;
   case 6:
-    return MO.setReg(
-        MRI.getSubReg(MO.getReg(), AMDGPU::sub0_sub1_sub2_sub3_sub4_sub5));
+    NewReg = MRI.getSubReg(MO.getReg(), AMDGPU::sub0_sub1_sub2_sub3_sub4_sub5);
+    break;
   case 8:
-    if (MCRegister NewReg = MRI.getSubReg(
-            MO.getReg(), AMDGPU::sub0_sub1_sub2_sub3_sub4_sub5_sub6_sub7)) {
-      MO.setReg(NewReg);
-    }
-    return;
-  case 12: {
+    NewReg = MRI.getSubReg(MO.getReg(),
+                           AMDGPU::sub0_sub1_sub2_sub3_sub4_sub5_sub6_sub7);
+    // For mfma f8/f8 is the widest format, so the operand already has the
+    // requested width and there is no subregister to select.
+    if (!NewReg)
+      return true;
+    break;
+  case 12:
     // There is no 384-bit subreg index defined.
-    MCRegister BaseReg = MRI.getSubReg(MO.getReg(), AMDGPU::sub0);
-    MCRegister NewReg = MRI.getMatchingSuperReg(
-        BaseReg, AMDGPU::sub0, &MRI.getRegClass(AMDGPU::VReg_384RegClassID));
-    return MO.setReg(NewReg);
-  }
+    if (MCRegister BaseReg = MRI.getSubReg(MO.getReg(), AMDGPU::sub0)) {
+      NewReg = MRI.getMatchingSuperReg(
+          BaseReg, AMDGPU::sub0, &MRI.getRegClass(AMDGPU::VReg_384RegClassID));
+    }
+    break;
   case 16:
     // No-op in cases where one operand is still f8/bf8.
-    return;
+    return true;
   default:
     llvm_unreachable("Unexpected size for mfma/wmma f8f6f4 operand");
   }
+
+  if (!NewReg)
+    return false;
+
+  MO.setReg(NewReg);
+  return true;
 }
 
 /// f8f6f4 instructions have different pseudos depending on the used formats. In
@@ -1099,11 +1116,11 @@ static void adjustMFMA_F8F6F4OpRegClass(const MCRegisterInfo &MRI,
 /// classes which assume using an fp8/bf8 format for both operands. The actual
 /// register class depends on the format in blgp and cbsz operands. Adjust the
 /// register classes depending on the used format.
-void AMDGPUDisassembler::convertMAIInst(MCInst &MI) const {
+bool AMDGPUDisassembler::convertMAIInst(MCInst &MI) const {
   int BlgpIdx =
       AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::blgp);
   if (BlgpIdx == -1)
-    return;
+    return true;
 
   int CbszIdx =
       AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::cbsz);
@@ -1115,24 +1132,24 @@ void AMDGPUDisassembler::convertMAIInst(MCInst &MI) const {
       AMDGPU::getMFMA_F8F6F4_WithFormatArgs(CBSZ, BLGP, MI.getOpcode());
   if (!AdjustedRegClassOpcode ||
       AdjustedRegClassOpcode->Opcode == MI.getOpcode())
-    return;
+    return true;
 
   MI.setOpcode(AdjustedRegClassOpcode->Opcode);
   int Src0Idx =
       AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src0);
   int Src1Idx =
       AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src1);
-  adjustMFMA_F8F6F4OpRegClass(MRI, MI.getOperand(Src0Idx),
-                              AdjustedRegClassOpcode->NumRegsSrcA);
-  adjustMFMA_F8F6F4OpRegClass(MRI, MI.getOperand(Src1Idx),
-                              AdjustedRegClassOpcode->NumRegsSrcB);
+  return adjustMFMA_F8F6F4OpRegClass(MRI, MI.getOperand(Src0Idx),
+                                     AdjustedRegClassOpcode->NumRegsSrcA) &&
+         adjustMFMA_F8F6F4OpRegClass(MRI, MI.getOperand(Src1Idx),
+                                     AdjustedRegClassOpcode->NumRegsSrcB);
 }
 
-void AMDGPUDisassembler::convertWMMAInst(MCInst &MI) const {
+bool AMDGPUDisassembler::convertWMMAInst(MCInst &MI) const {
   int FmtAIdx =
       AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::matrix_a_fmt);
   if (FmtAIdx == -1)
-    return;
+    return true;
 
   int FmtBIdx =
       AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::matrix_b_fmt);
@@ -1144,17 +1161,17 @@ void AMDGPUDisassembler::convertWMMAInst(MCInst &MI) const {
       AMDGPU::getWMMA_F8F6F4_WithFormatArgs(FmtA, FmtB, MI.getOpcode());
   if (!AdjustedRegClassOpcode ||
       AdjustedRegClassOpcode->Opcode == MI.getOpcode())
-    return;
+    return true;
 
   MI.setOpcode(AdjustedRegClassOpcode->Opcode);
   int Src0Idx =
       AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src0);
   int Src1Idx =
       AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src1);
-  adjustMFMA_F8F6F4OpRegClass(MRI, MI.getOperand(Src0Idx),
-                              AdjustedRegClassOpcode->NumRegsSrcA);
-  adjustMFMA_F8F6F4OpRegClass(MRI, MI.getOperand(Src1Idx),
-                              AdjustedRegClassOpcode->NumRegsSrcB);
+  return adjustMFMA_F8F6F4OpRegClass(MRI, MI.getOperand(Src0Idx),
+                                     AdjustedRegClassOpcode->NumRegsSrcA) &&
+         adjustMFMA_F8F6F4OpRegClass(MRI, MI.getOperand(Src1Idx),
+                                     AdjustedRegClassOpcode->NumRegsSrcB);
 }
 
 struct VOPModifiers {
diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
index d0859d144722f..16019611120cf 100644
--- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
+++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
@@ -124,8 +124,8 @@ class AMDGPUDisassembler : public MCDisassembler {
   void convertVINTERPInst(MCInst &MI) const;
   void convertFMAanyK(MCInst &MI) const;
   void convertSDWAInst(MCInst &MI) const;
-  void convertMAIInst(MCInst &MI) const;
-  void convertWMMAInst(MCInst &MI) const;
+  bool convertMAIInst(MCInst &MI) const;
+  bool convertWMMAInst(MCInst &MI) const;
   void convertDPP8Inst(MCInst &MI) const;
   void convertMIMGInst(MCInst &MI) const;
   void convertVOP3DPPInst(MCInst &MI) const;
diff --git a/llvm/test/MC/Disassembler/AMDGPU/decode-err.txt b/llvm/test/MC/Disassembler/AMDGPU/decode-err.txt
index de9bf7bac9548..e9537d1ec6c24 100644
--- a/llvm/test/MC/Disassembler/AMDGPU/decode-err.txt
+++ b/llvm/test/MC/Disassembler/AMDGPU/decode-err.txt
@@ -1,4 +1,5 @@
 # RUN: llvm-mc -triple=amdgpu9.00 -disassemble -filetype=null < %s 2>&1 | FileCheck -check-prefix=GCN-ERR %s
+# RUN: llvm-mc -triple=amdgpu9.50 -disassemble -filetype=null < %s 2>&1 | FileCheck -check-prefix=GFX950-ERR %s
 # RUN: llvm-mc -triple=amdgpu11.00 -disassemble -show-encoding < %s | FileCheck -check-prefixes=W32 %s
 # RUN: llvm-mc -triple=amdgpu11.00 -mattr=+wavefrontsize64 -disassemble -show-encoding < %s 2>&1 | FileCheck -check-prefixes=W64 %s
 # RUN: llvm-mc -triple=amdgpu12.00 -disassemble -filetype=null < %s 2>&1 | FileCheck -check-prefix=GFX12-ERR %s
@@ -109,6 +110,21 @@
 # GFX90A: [[@LINE+1]]:1: warning: invalid instruction encoding
 0x00,0x00,0x6d,0xd8,0x01,0x00,0x00,0x00
 
+# The f8f6f4 source tuples are narrowed down according to cbsz/blgp, but ttmp
+# registers have no 192-bit tuple.
+# GFX950-ERR: [[@LINE+1]]:1: warning: invalid instruction encoding
+0x00,0x00,0xae,0xd3,0x00,0xe9,0x00,0x64
+
+# Same, except that the source selector is an inline constant, which is not a
+# register at all.
+# GFX950-ERR: [[@LINE+1]]:1: warning: invalid instruction encoding
+0x00,0x00,0xae,0xd3,0xf2,0x00,0x02,0x64
+
+# The wmma source tuples are narrowed down according to the matrix formats, but
+# scalar registers have no 384-bit tuple.
+# GFX1250-ERR: [[@LINE+1]]:1: warning: invalid instruction encoding
+0x00,0x18,0x33,0xcc,0x08,0x30,0xa2,0x04
+
 # This encoding references a missing trailing literal.
 # GFX1250-ERR: [[@LINE+1]]:1: warning: invalid instruction encoding
 0x00,0x00,0x33,0xcc,0xff,0x68,0x02,0x02

Comment on lines +123 to +126
# The wmma source tuples are narrowed down according to the matrix formats, but
# scalar registers have no 384-bit tuple.
# GFX1250-ERR: [[@LINE+1]]:1: warning: invalid instruction encoding
0x00,0x18,0x33,0xcc,0x08,0x30,0xa2,0x04

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Seems like there are 3 size error cases, but only 2 size error tests?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Only 12 could fail here.

@shiltian
shiltian merged commit e337de1 into main Aug 10, 2026
14 checks passed
@shiltian
shiltian deleted the users/shiltian/fix-disam-out-of-range-mfma-tuple branch August 10, 2026 02:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[amdgpu][mc][fuzzer-generated] Out-of-range MFMA tuple reches register-name assertion

2 participants