Skip to content

[Mips][ASM] Optimize SW+ADDIU #144997

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 1 commit into
base: main
Choose a base branch
from
Open

Conversation

yingopq
Copy link
Contributor

@yingopq yingopq commented Jun 20, 2025

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.

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 llvm#132685.
@llvmbot llvmbot added backend:MIPS mc Machine (object) code labels Jun 20, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 20, 2025

@llvm/pr-subscribers-backend-mips

@llvm/pr-subscribers-mc

Author: None (yingopq)

Changes

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.


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

2 Files Affected:

  • (modified) llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp (+122-2)
  • (added) llvm/test/MC/Mips/sw-add-bne.s (+13)
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

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

Successfully merging this pull request may close these issues.

MIPS/ASM: may optimize SW + ADDIU
2 participants