[llvm] [Mips][ASM] Optimize SW+ADDIU (PR #144997)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 20 01:43:34 PDT 2025


https://github.com/yingopq created https://github.com/llvm/llvm-project/pull/144997

We want to optimize
        `sw      $4, 0($2)
         addiu   $2, $2, 4
         bne     $2, $3, $BB0_1`
to
        `addiu   $2, $2, 4
         sw      $4, -4($2)
         bne     $2, $3, $BB0_1`,
so that the sw can be placed into delay slot.

Fix #132685.

>From 1c055e8ca72274a13a906d77b7e7d272eaf009ed Mon Sep 17 00:00:00 2001
From: Ying Huang <ying.huang at oss.cipunited.com>
Date: Fri, 20 Jun 2025 04:34:53 -0400
Subject: [PATCH] [Mips][ASM] Optimize SW+ADDIU

We want to optimize
        `sw      $4, 0($2)
         addiu   $2, $2, 4
         bne     $2, $3, $BB0_1`
to
        `addiu   $2, $2, 4
         sw      $4, -4($2)
         bne     $2, $3, $BB0_1`,
so that the sw can be placed into delay slot.

Fix #132685.
---
 .../Target/Mips/AsmParser/MipsAsmParser.cpp   | 124 +++++++++++++++++-
 llvm/test/MC/Mips/sw-add-bne.s                |  13 ++
 2 files changed, 135 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/MC/Mips/sw-add-bne.s

diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index 640ae52d05dd1..2aeb868ad3794 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -146,6 +146,19 @@ class MipsAsmParser : public MCTargetAsmParser {
                        // nullptr, which indicates that no function is currently
                        // selected. This usually happens after an '.end func'
                        // directive.
+  // Because we want do `sw $4, 0($2)
+  //                     addiu $2, $2, 4
+  //                     bne $2, $3, $BB0_1`
+  // to
+  //                    `addiu $2, $2, 4
+  //                     sw $4, -4($2)
+  //                     bne $2, $3, $BB0_1`,
+  // so that the sw can be placed into delay slot.
+  // If true, reprents inst `addiu` following inst `sw`, and save inst
+  // `sw`. Later we will check if inst 'bne' following inst `addiu`.
+  bool saveCurInst;
+  MCInst CurInst;
+
   bool IsLittleEndian;
   bool IsPicEnabled;
   bool IsCpRestoreSet;
@@ -351,6 +364,9 @@ class MipsAsmParser : public MCTargetAsmParser {
   bool expandSaaAddr(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
                      const MCSubtargetInfo *STI);
 
+  MipsAsmParser::MacroExpanderResultTy expandSW(MCInst &Inst, SMLoc IDLoc,
+                                                MCStreamer &Out,
+                                                const MCSubtargetInfo *STI);
   bool reportParseError(const Twine &ErrorMsg);
   bool reportParseError(SMLoc Loc, const Twine &ErrorMsg);
 
@@ -550,6 +566,7 @@ class MipsAsmParser : public MCTargetAsmParser {
       report_fatal_error("-mno-odd-spreg requires the O32 ABI");
 
     CurrentFn = nullptr;
+    saveCurInst = false;
 
     CurForbiddenSlotAttr = false;
     IsPicEnabled = getContext().getObjectFileInfo()->isPositionIndependent();
@@ -2572,8 +2589,82 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
     if ((Inst.getNumOperands() == 3) && Inst.getOperand(0).isReg() &&
         Inst.getOperand(1).isReg() && Inst.getOperand(2).isImm()) {
       int64_t ImmValue = Inst.getOperand(2).getImm();
-      if (isInt<16>(ImmValue))
-        return MER_NotAMacro;
+      if (isInt<16>(ImmValue)) {
+        if (saveCurInst == true) {
+          AsmToken ID = getTok();
+          saveCurInst = false;
+          bool doLex = false;
+
+          // If this is a line comment we can drop it safely.
+          while (getLexer().is(AsmToken::EndOfStatement)) {
+            doLex = true;
+            getLexer().Lex();
+          }
+
+          // Get last inst `sw` register info and offset value.
+          MipsTargetStreamer &TOut = getTargetStreamer();
+          MCRegister FirstReg = CurInst.getOperand(0).getReg();
+          MCRegister BaseReg = CurInst.getOperand(1).getReg();
+          MCOperand &OffsetImmOp = CurInst.getOperand(2);
+          unsigned OffsetValue = OffsetImmOp.getImm();
+
+          // Optimize `sw $4, 0($2)
+          //           addiu $2, $2, 4
+          //           bne $2, $3, $BB0_1`
+          // to
+          //          `addiu $2, $2, 4
+          //           sw $4, -4($2)
+          //           bne $2, $3, $BB0_1`.
+          // If match sw+addiu+bne, then emit addiu+sw.
+          if (getTok().getString() == "bne") {
+            if (OffsetValue != 0) {
+              // Back to initial location before return.
+              if (doLex == true)
+                getLexer().UnLex(ID);
+              // If not match, we need to emit the last reserved instruction
+              // `sw`.
+              TOut.emitRRI(CurInst.getOpcode(), FirstReg, BaseReg, OffsetValue,
+                           IDLoc, STI);
+              return MER_NotAMacro;
+            }
+
+            // Get inst `addiu` register info and imm value.
+            MCRegister destReg = Inst.getOperand(0).getReg();
+            MCRegister srcReg = Inst.getOperand(1).getReg();
+            unsigned addImm = Inst.getOperand(2).getImm();
+
+            if (destReg == srcReg && BaseReg == destReg && addImm == 4) {
+              // Emit addiu+sw.
+              TOut.emitRRI(Inst.getOpcode(), destReg, srcReg, addImm, IDLoc,
+                           STI);
+              TOut.emitRRI(CurInst.getOpcode(), FirstReg, BaseReg,
+                           OffsetValue - addImm, IDLoc, STI);
+              // Back to initial location before return.
+              if (doLex == true)
+                getLexer().UnLex(ID);
+              return MER_Success;
+            } else {
+              // Back to initial location before return.
+              if (doLex == true)
+                getLexer().UnLex(ID);
+              // If not match, we need to emit the last reserved instruction
+              // `sw`.
+              TOut.emitRRI(CurInst.getOpcode(), FirstReg, BaseReg, OffsetValue,
+                           IDLoc, STI);
+              return MER_NotAMacro;
+            }
+          } else {
+            // Back to initial location before return.
+            if (doLex == true)
+              getLexer().UnLex(ID);
+            // If not match, we need to emit the last reserved instruction `sw`.
+            TOut.emitRRI(CurInst.getOpcode(), FirstReg, BaseReg, OffsetValue,
+                         IDLoc, STI);
+            return MER_NotAMacro;
+          }
+        } else
+          return MER_NotAMacro;
+      }
       return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail
                                                          : MER_Success;
     }
@@ -2646,6 +2737,8 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
   case Mips::SaaAddr:
   case Mips::SaadAddr:
     return expandSaaAddr(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
+  case Mips::SW:
+    return expandSW(Inst, IDLoc, Out, STI);
   }
 }
 
@@ -5280,6 +5373,33 @@ bool MipsAsmParser::expandDMULMacro(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
   return false;
 }
 
+// Check if match sw+addiu.
+MipsAsmParser::MacroExpanderResultTy
+MipsAsmParser::expandSW(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+                        const MCSubtargetInfo *STI) {
+  AsmToken ID = getTok();
+  bool doLex = false;
+
+  // If this is a line comment we can drop it safely.
+  while (getLexer().is(AsmToken::EndOfStatement)) {
+    getLexer().Lex();
+    doLex = true;
+  }
+  // If match sw+addiu, then save current Inst,
+  // and back to initial location before return.
+  if (getTok().getString() == "addiu") {
+    if (doLex == true)
+      getLexer().UnLex(ID);
+    CurInst = Inst;
+    saveCurInst = true;
+    return MER_Success;
+  } else {
+    if (doLex == true)
+      getLexer().UnLex(ID);
+    return MER_NotAMacro;
+  }
+}
+
 // Expand 'ld $<reg> offset($reg2)' to 'lw $<reg>, offset($reg2);
 //                                      lw $<reg+1>>, offset+4($reg2)'
 // or expand 'sd $<reg> offset($reg2)' to 'sw $<reg>, offset($reg2);
diff --git a/llvm/test/MC/Mips/sw-add-bne.s b/llvm/test/MC/Mips/sw-add-bne.s
new file mode 100644
index 0000000000000..b4a739db7419b
--- /dev/null
+++ b/llvm/test/MC/Mips/sw-add-bne.s
@@ -0,0 +1,13 @@
+# RUN: llvm-mc -assemble -mcpu=mips32r6 -arch=mipsel -filetype=obj %s -o tmp.o
+# RUN: llvm-objdump -d tmp.o | FileCheck %s --check-prefix=MIPSELR6
+
+# MIPSELR6:      00000000 <xxx>:
+# MIPSELR6-NEXT: addiu $2, $2, 0x4 <xxx+0x4>
+# MIPSELR6-NEXT: sw $4, -0x4($2)
+# MIPSELR6-NEXT: bne $2, $3, 0x0 <xxx>
+# MIPSELR6-NEXT: nop <xxx>
+xxx:
+$BB0_1:                                 # %for.body
+        sw      $4, 0($2)
+        addiu   $2, $2, 4
+        bne     $2, $3, $BB0_1



More information about the llvm-commits mailing list