Skip to content

[RISCV] Add support for handling one tied operand in the source instruction for compress patterns #143660

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
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

hchandel
Copy link
Contributor

This update enables compress patterns to handle one tied operand in source instructions, which was previously unsupported. Qualcomm's uC extension Xqci includes several instructions with tied operands that can be compressed into smaller forms. This change adds the necessary support to enable such compression. Additionally, a compress pattern for the qc.muliadd instruction has been implemented.

Harsh Chandel added 2 commits June 11, 2025 11:24
…uction for compress patterns

Change-Id: I69b8aac8fcf674d214cd00691b428555b61d4ebe
Change-Id: Iba6ea3a80163c9553dd821668ebe6409302da552
@llvmbot llvmbot added backend:RISC-V tablegen mc Machine (object) code labels Jun 11, 2025
@hchandel hchandel requested review from topperc and svs-quic June 11, 2025 06:28
@llvmbot
Copy link
Member

llvmbot commented Jun 11, 2025

@llvm/pr-subscribers-mc
@llvm/pr-subscribers-tablegen

@llvm/pr-subscribers-backend-risc-v

Author: quic_hchandel (hchandel)

Changes

This update enables compress patterns to handle one tied operand in source instructions, which was previously unsupported. Qualcomm's uC extension Xqci includes several instructions with tied operands that can be compressed into smaller forms. This change adds the necessary support to enable such compression. Additionally, a compress pattern for the qc.muliadd instruction has been implemented.


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

3 Files Affected:

  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td (+5)
  • (modified) llvm/test/MC/RISCV/xqciac-valid.s (+16-5)
  • (modified) llvm/utils/TableGen/CompressInstEmitter.cpp (+30-9)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index dba035bab928c..ce5de3291a672 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -1556,6 +1556,11 @@ def : CompressPat<(QC_E_ADDI X2, X2, simm10_lsb0000nonzero:$imm),
                   (C_ADDI16SP X2, simm10_lsb0000nonzero:$imm)>;
 } // let isCompressOnly = true, Predicates = [HasVendorXqcilia, IsRV32]
 
+let Predicates = [HasVendorXqciac, IsRV32] in {
+def : CompressPat<(QC_MULIADD GPRC:$rd, GPRC:$rs1, uimm5:$imm5),
+                  (QC_C_MULIADD GPRC:$rd, GPRC:$rs1, uimm5:$imm5)>;
+}
+
 let isCompressOnly = true, Predicates = [HasVendorXqcibi, IsRV32] in {
 def : CompressPat<(QC_E_BEQI GPRNoX0:$rs1, simm5nonzero:$imm5, bare_simm13_lsb0:$imm12),
                   (QC_BEQI GPRNoX0:$rs1, simm5nonzero:$imm5, bare_simm13_lsb0:$imm12)>;
diff --git a/llvm/test/MC/RISCV/xqciac-valid.s b/llvm/test/MC/RISCV/xqciac-valid.s
index 438c4cafe0dfe..1afebc75cb45a 100644
--- a/llvm/test/MC/RISCV/xqciac-valid.s
+++ b/llvm/test/MC/RISCV/xqciac-valid.s
@@ -1,24 +1,27 @@
 # Xqciac - Qualcomm uC Load-Store Address Calculation Extension
 # RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqciac -M no-aliases -show-encoding \
-# RUN:     | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
+# RUN:     | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST,CHECK-NOALIAS %s
 # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqciac < %s \
 # RUN:     | llvm-objdump --mattr=+experimental-xqciac -M no-aliases --no-print-imm-hex -d - \
 # RUN:     | FileCheck -check-prefix=CHECK-INST %s
 # RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqciac -show-encoding \
-# RUN:     | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST %s
+# RUN:     | FileCheck -check-prefixes=CHECK-ENC,CHECK-INST,CHECK-ALIAS %s
 # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqciac < %s \
 # RUN:     | llvm-objdump --mattr=+experimental-xqciac --no-print-imm-hex -d - \
 # RUN:     | FileCheck -check-prefix=CHECK-INST %s
 
-# CHECK-INST: qc.c.muliadd    a0, a1, 0
+# CHECK-NOALIAS: qc.c.muliadd    a0, a1, 0
+# CHECK-ALIAS: qc.muliadd    a0, a1, 0
 # CHECK-ENC: encoding: [0x8a,0x21]
 qc.c.muliadd x10, x11, 0
 
-# CHECK-INST: qc.c.muliadd    a0, a1, 31
+# CHECK-NOALIAS: qc.c.muliadd    a0, a1, 31
+# CHECK-ALIAS: qc.muliadd    a0, a1, 31
 # CHECK-ENC: encoding: [0xea,0x3d]
 qc.c.muliadd x10, x11, 31
 
-# CHECK-INST: qc.c.muliadd    a0, a1, 16
+# CHECK-NOALIAS: qc.c.muliadd    a0, a1, 16
+# CHECK-ALIAS: qc.muliadd    a0, a1, 16
 # CHECK-ENC: encoding: [0xaa,0x21]
 qc.c.muliadd x10, x11, 16
 
@@ -47,3 +50,11 @@ qc.shladd x10, x11, x12, 4
 # CHECK-INST: qc.shladd       a0, a1, a2, 31
 # CHECK-ENC: encoding: [0x0b,0xb5,0xc5,0x7e]
 qc.shladd x10, x11, x12, 31
+
+# Check that compress pattern for qc.muliadd works
+
+# CHECK-NOALIAS: qc.c.muliadd    a0, a1, 16
+# CHECK-ALIAS: qc.muliadd    a0, a1, 16
+# CHECK-ENC: encoding: [0xaa,0x21]
+qc.muliadd x10, x11, 16
+
diff --git a/llvm/utils/TableGen/CompressInstEmitter.cpp b/llvm/utils/TableGen/CompressInstEmitter.cpp
index 4a0b6d79c53d9..515d27c04158a 100644
--- a/llvm/utils/TableGen/CompressInstEmitter.cpp
+++ b/llvm/utils/TableGen/CompressInstEmitter.cpp
@@ -75,6 +75,7 @@
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/TableGenBackend.h"
+#include <limits>
 #include <set>
 #include <vector>
 using namespace llvm;
@@ -123,7 +124,7 @@ class CompressInstEmitter {
   const RecordKeeper &Records;
   const CodeGenTarget Target;
   std::vector<CompressPat> CompressPatterns;
-
+  unsigned SourceLastTiedOp; // postion of the last tied operand in Source Inst
   void addDagOperandMapping(const Record *Rec, const DagInit *Dag,
                             const CodeGenInstruction &Inst,
                             IndexedMap<OpData> &OperandMap, bool IsSourceInst);
@@ -219,12 +220,16 @@ void CompressInstEmitter::addDagOperandMapping(const Record *Rec,
   // are represented.
   unsigned TiedCount = 0;
   unsigned OpNo = 0;
+  if (IsSourceInst)
+    SourceLastTiedOp = std::numeric_limits<unsigned int>::max();
   for (const auto &Opnd : Inst.Operands) {
     int TiedOpIdx = Opnd.getTiedRegister();
     if (-1 != TiedOpIdx) {
       // Set the entry in OperandMap for the tied operand we're skipping.
       OperandMap[OpNo].Kind = OperandMap[TiedOpIdx].Kind;
       OperandMap[OpNo].Data = OperandMap[TiedOpIdx].Data;
+      if (IsSourceInst)
+        SourceLastTiedOp = OpNo;
       ++OpNo;
       ++TiedCount;
       continue;
@@ -289,15 +294,23 @@ void CompressInstEmitter::addDagOperandMapping(const Record *Rec,
 static bool verifyDagOpCount(const CodeGenInstruction &Inst, const DagInit *Dag,
                              bool IsSource) {
   unsigned NumMIOperands = 0;
-  for (const auto &Op : Inst.Operands)
+
+  // Use this to count number of tied Operands in Source Inst in this function.
+  // This counter is required here to error out when there is a Source
+  // Inst with two or more tied operands.
+  unsigned SourceInstTiedOpCount = 0;
+  for (const auto &Op : Inst.Operands) {
     NumMIOperands += Op.MINumOperands;
+    if (Op.getTiedRegister() != -1)
+      SourceInstTiedOpCount++;
+  }
 
   if (Dag->getNumArgs() == NumMIOperands)
     return true;
 
-  // Source instructions are non compressed instructions and don't have tied
-  // operands.
-  if (IsSource)
+  // Source instructions are non compressed instructions and have atmost one
+  // tied operand.
+  if (IsSource && (SourceInstTiedOpCount >= 2))
     PrintFatalError(Inst.TheDef->getLoc(),
                     "Input operands for Inst '" + Inst.TheDef->getName() +
                         "' and input Dag operand count mismatch");
@@ -422,10 +435,18 @@ void CompressInstEmitter::createInstOperandMapping(
       assert(DestDag->getArgNameStr(DagArgIdx) ==
                  SourceDag->getArgNameStr(SourceOp->getValue()) &&
              "Incorrect operand mapping detected!\n");
-      DestOperandMap[OpNo].Data.Operand = SourceOp->getValue();
-      SourceOperandMap[SourceOp->getValue()].Data.Operand = OpNo;
-      LLVM_DEBUG(dbgs() << "    " << SourceOp->getValue() << " ====> " << OpNo
-                        << "\n");
+
+      // Following four lines ensure the correct handling of a single tied
+      // operand in the Source Inst. SourceDagOp points to the position of
+      // appropriate Dag argument which is not correct in presence of tied
+      // operand in the Source Inst and must be incremented by 1 to reflect
+      // correct position of the operand in Source Inst
+      unsigned SourceDagOp = SourceOp->getValue();
+      if (SourceDagOp >= SourceLastTiedOp)
+        SourceDagOp++;
+      DestOperandMap[OpNo].Data.Operand = SourceDagOp;
+      SourceOperandMap[SourceDagOp].Data.Operand = OpNo;
+      LLVM_DEBUG(dbgs() << "    " << SourceDagOp << " ====> " << OpNo << "\n");
     }
   }
 }

@hchandel hchandel requested review from lenary and pgodeq June 11, 2025 06:28
Change-Id: I190e56d22e85e8ae5b07931840f879b3e8afb4fe
Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

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

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:RISC-V mc Machine (object) code tablegen
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants