Unlock The Secret: How To Subtract In MIPS Without Using SUB – You’ll Never Guess The Trick

16 min read

Ever tried to do a subtraction in MIPS and the sub instruction just isn’t there?
On top of that, you’re not alone. A lot of beginners hit that wall when they open a textbook that only shows add, addi, and a handful of other ops. The short answer: you can still subtract—just get a little creative with two’s‑complement and the add instruction you already have Easy to understand, harder to ignore..


What Is Subtract‑Without‑sub in MIPS

In plain English, “subtract without sub” means using the instructions that are available—primarily add and addi—to achieve the same result as a subtraction. MIPS doesn’t force you to use a dedicated subtract opcode; it gives you the building blocks to do the math yourself That's the part that actually makes a difference..

Two’s‑Complement Basics

MIPS, like virtually every modern CPU, stores integers in two’s‑complement form. That little trick lets you turn a subtraction into an addition:

A - B  ==  A + (‑B)

So if you can get the negative of a number, you can just add it. In real terms, the negative of a 32‑bit value is obtained by inverting every bit (not) and then adding one (addi $t, $t, 1). That’s the core idea behind all the tricks you’ll see.

Why MIPS Doesn’t Need a Separate sub

The original MIPS ISA designers kept the instruction set lean. Adding a separate subtract opcode would have been redundant—add already does the job once you have the two’s‑complement representation of the subtrahend. The hardware can perform both operations in a single cycle; the assembler just gives you a convenient mnemonic.


Why It Matters / Why People Care

You might wonder, “Why bother?” Here are three real‑world reasons:

  1. Embedded environments – Some tiny MIPS cores (think microcontrollers) ship with a reduced instruction set that omits sub. If you’re writing firmware for such a chip, you need the workaround anyway.
  2. Learning the fundamentals – Understanding two’s‑complement arithmetic sharpens your grasp of how computers actually do math. It’s the kind of low‑level insight that makes debugging easier later on.
  3. Assembler tricks – Even when sub exists, you might want to generate the same machine code manually (e.g., for a custom assembler or a teaching tool). Knowing the pattern helps you read raw binaries.

In practice, the ability to subtract without a dedicated opcode shows you’re thinking like a computer, not just a high‑level programmer Most people skip this — try not to..


How It Works (or How to Do It)

Below is the step‑by‑step recipe most textbooks gloss over. I’ll break it into bite‑size chunks, each with a tiny example And that's really what it comes down to..

1. Load the operands

Assume you have two registers, $s0 (minuend) and $s1 (subtrahend). If the values are in memory, use lw first:

lw  $s0, 0($a0)   # load A
lw  $s1, 0($a1)   # load B

2. Compute the two’s‑complement of the subtrahend

Two ways to do this: the classic “invert‑then‑add‑one” or the handy nor‑plus‑addi combo.

Method A – NOT + ADDI

nor $t0, $zero, $s1   # $t0 = ~B  (NOR with $zero is NOT)
addi $t0, $t0, 1      # $t0 = -B

Method B – XOR with -1 + ADDI (some like it because xor is often faster on certain pipelines)

xori $t0, $s1, -1     # $t0 = ~B
addi $t0, $t0, 1      # $t0 = -B

Either way, $t0 now holds the negative of $s1 That's the part that actually makes a difference..

3. Add the negated subtrahend to the minuend

Now the real subtraction happens:

add $t1, $s0, $t0     # $t1 = A + (-B) = A - B

$t1 holds the result. If you need to store it back:

sw  $t1, 0($a2)       # store result

4. One‑instruction shortcut using subu pseudo‑op

If your assembler supports pseudo‑ops, you can write:

sub $t1, $s0, $s1     # expands to the sequence above

But the point of this article is the manual expansion, which works even when sub is disabled.

5. Handling overflow

MIPS offers two subtraction instructions: sub (traps on overflow) and subu (ignores overflow). When you emulate subtraction with add, you’ll get the unsigned behavior automatically—no overflow exception. If you need signed overflow detection, you must add extra checks:

# Detect signed overflow after A - B
xor $t2, $s0, $s1      # sign bits differ?
xor $t3, $s0, $t1      # sign of result vs. sign of A
and $t4, $t2, $t3
bgez $t4, no_overflow  # if $t4 >= 0, no overflow
# overflow handling code here
no_overflow:

That’s a bit more advanced, but worth knowing if you’re writing a compiler backend.


Common Mistakes / What Most People Get Wrong

Mistake #1 – Forgetting to add the “+1”

People often invert the bits and think they’re done. Without the extra addi $t0, $t0, 1, you’ve just computed the one’s‑complement, which is off by one for every negative number. The result ends up being A + (~B), not A - B.

It sounds simple, but the gap is usually here Easy to understand, harder to ignore..

Mistake #2 – Using sub as a macro and assuming it works on reduced cores

Some reduced‑instruction MIPS cores still accept the mnemonic sub because the assembler expands it, but the hardware will raise an illegal‑instruction exception. If you’re targeting such a core, you must write the explicit sequence yourself.

Mistake #3 – Mixing signed and unsigned registers

add treats its operands as unsigned when it comes to overflow detection (i.Here's the thing — e. , it never traps). If you later compare the result with a signed value using slt, you could get a surprising sign‑bit flip. Keep the data type consistent throughout the routine.

Mistake #4 – Overlooking pipeline hazards

On a classic 5‑stage MIPS pipeline, the nor/xori result isn’t ready until the MEM stage. If you immediately use it in the next add, you’ll need a stall or a NOP. Modern superscalar cores hide this, but on older hardware you’ll see a one‑cycle bubble.

The official docs gloss over this. That's a mistake.


Practical Tips / What Actually Works

  • Use a temporary register – Reserve $t0 (or any $t register) for the negated value. It keeps the original $s1 intact for later reuse That alone is useful..

  • Combine NOT and ADDI in one line – Some assemblers let you write addi $t0, $s1, -1 followed by sub $t0, $zero, $t0. It’s a little less readable but saves a register.

  • put to work addu for speed – If you don’t care about overflow, addu is the same as add but avoids the extra check the hardware might perform.

  • Write a macro – In your .asm file, define:

    .macro SUB_NO_SUB dest, src1, src2
        xori $at, \src2, -1
        addiu $at, $at, 1
        addu \dest, \src1, $at
    .end_macro
    

    Then call SUB_NO_SUB $t1, $s0, $s1. - Test with edge cases – Try subtracting 0, subtracting a larger number (to get a negative result), and subtracting 0x80000000 (the most negative 32‑bit int). It’s clean, reusable, and works on any MIPS core.
    Those will reveal any sign‑extension bugs in your code.


FAQ

Q: Can I use addiu instead of addi for the “+1” step?
A: Yes. addiu treats the immediate as unsigned, but adding 1 never overflows, so both work identically here That alone is useful..

Q: What if my MIPS core lacks the nor instruction?
A: Use xor with -1 (xori $t0, $s1, -1). It produces the same bitwise NOT result Small thing, real impact..

Q: Is there a performance difference between the NOT+ADD method and using subu directly?
A: On a fully pipelined core, subu is a single‑cycle operation, while NOT+ADD takes two cycles (plus any stalls). If you’re writing tight loops, the difference can matter. Otherwise, readability wins.

Q: How do I subtract an immediate value without subi?
A: Negate the immediate at assembly time (addi $t0, $zero, -IMM) and then add it to the register. Example: addi $t0, $zero, -5 then add $t1, $s0, $t0.

Q: Does this technique work for 64‑bit MIPS (MIPS64)?
A: Absolutely. The same two’s‑complement logic applies; just use the 64‑bit registers ($t0$t9 still refer to the low 64 bits). If you need the high half, you’ll have to handle it separately Worth keeping that in mind..


And that’s it. Which means subtracting without a dedicated sub instruction is just a few extra lines of assembly, but the concept behind it—two’s‑complement arithmetic—lies at the heart of every integer operation a CPU does. Once you’ve got the pattern down, you’ll find it pops up in other places: implementing absolute value, doing conditional negation, or even building a tiny ALU in a teaching lab.

So next time you open a MIPS file and see no sub around, remember: you’ve already got everything you need. Just flip the bits, add one, and let add do the heavy lifting. Happy coding!

A Quick Reference Cheat‑Sheet

Goal Instruction(s) Notes
Subtract two registers subu $d, $s, $t (or sub $d, $s, $t) Fastest, one‑cycle on modern cores
Subtract register from immediate addi $d, $s, -IMM Immediate must fit in 16‑bit signed field
Subtract two’s‑complement manually xori $t, $s, -1<br>addiu $t, $t, 1<br>addu $d, $t, $t2 Works on any MIPS core, useful for teaching
Negate a register xori $t, $s, -1<br>addiu $t, $t, 1 Equivalent to subu $t, $zero, $s
Subtract with overflow check sub $d, $s, $t Overflow flag set in HI/LO?
Subtract without overflow check subu $d, $s, $t Faster, no overflow trap

When to Stick With the Built‑In sub

  • Performance‑critical loops: sub is a single‑cycle operation; the “flip‑bits‑then‑add” trick takes two cycles.
  • Code clarity: Future readers (or yourself in six months) will immediately understand sub $t0, $t1, $t2.
  • Debugging: Most debuggers and simulators highlight sub as a single arithmetic step; custom macros can be harder to trace.

In contrast, the manual two’s‑complement method shines when:

  • Instruction set is limited (e.g., very small cores or teaching simulators).
  • You want to expose the underlying math to students or for documentation.
  • You’re writing a code generator that must output only a subset of instructions.

TL;DR

  • Subtracting on MIPS is fundamentally a two’s‑complement addition.
  • If the core offers sub/subu, use it—clean, fast, and unmistakable.
  • If you’re forced to work with only add/addi/xori, flip the subtrahend, add one, then add to the minuend.
  • Wrap the pattern in a macro (or inline function in C) to keep your source tidy.
  • Remember that subu (unsigned) is just the same as sub but without the overflow exception—pick the one that fits your safety requirements.

Final Thoughts

Subtracting without a dedicated sub instruction might feel like a hack, but it’s a direct window into how CPUs actually perform arithmetic. The two’s‑complement trick is universal: it works on 8‑bit microcontrollers, 32‑bit MIPS, 64‑bit RISC‑V, and even on the most exotic DSPs. Mastering it gives you a deeper appreciation for the elegance of binary math and the power of assembly language.

So, the next time you’re staring at a stripped‑down MIPS core or a minimalist assembler, remember: you don’t need a “sub” instruction to subtract. Worth adding: just invert the bits, add one, and let the adder do the rest. Happy hacking!

The “Add‑One‑and‑Negate” Pattern in Real‑World Code

Even though most production‑grade MIPS cores ship with sub/subu, you’ll still encounter the add‑one‑and‑negate idiom in a few practical places:

Context Why the pattern appears Example
Boot‑loaders & firmware Early‑stage code runs before the full instruction decoder is enabled; only a minimal subset of the ISA is guaranteed to work. asm\n # Zero‑initialize a register without using `move`\n li $t0, 0 # may not be available yet\n xori $t0, $zero, -1 # invert zero → all‑ones\n addiu $t0, $t0, 1 # +1 → 0 again, but now $t0 is known to be zero\n
Self‑modifying code generators A JIT that emits instructions on the fly may be constrained to a “safe” instruction set that the host guarantees to be present.
Cross‑ISA macros When writing portable assembly that targets both MIPS and a sibling ISA that lacks a sub (some older MIPS‑derived micro‑controllers), a macro that expands to the generic two‑step sequence keeps the source single‑sourced. , MARS, SPIM) let students experiment with a “restricted” instruction set to force them to think about the underlying arithmetic. g. ```asm\n .
Educational tools Many teaching simulators (e. A lab assignment may explicitly forbid sub and ask students to implement subtraction with only add/xori. macro SUB dst, src1, src2\n xori \dst, \src2, -1\n addiu \dst, \dst, 1\n addu \dst, \src1, \dst\n .

In each of these scenarios the “extra” instruction isn’t a performance penalty—it’s a trade‑off for portability, boot‑time simplicity, or pedagogical clarity.


Edge Cases Worth Knowing

  1. Subtracting a value that doesn’t fit in a 16‑bit signed immediate
    The addi $d,$s,-IMM form only works when IMM fits in the signed 16‑bit field (-32768 … 32767). If you need to subtract a 32‑bit constant, you must load the constant into a register first (using lui/ori or a literal pool) and then apply the two‑step method or a subu.

  2. Subtracting from the zero register
    sub $t0, $zero, $t1 is perfectly legal and yields -$t1. That said, using the manual method can be a tiny bit slower because you need a temporary register to hold the negated value. If you have a spare register, the macro above works fine; otherwise, you can cheat with addu $t0, $zero, $zero (a no‑op) followed by the two‑step sequence Turns out it matters..

  3. Subtraction with a carry‑in
    Some DSP‑style extensions expose a carry flag that can be added to the result (addu $d,$s,$t; addc $d,$d,$carry). The two‑step method can be adapted by adding the carry after the addiu $t,$t,1 step, effectively computing a - b + carry That's the part that actually makes a difference..

  4. Signed vs. unsigned overflow handling
    The only semantic difference between sub and subu is the exception that may be raised on overflow. The hardware does not set any status bits that you can read later; the exception is delivered directly to the exception handler. If you need to detect overflow without trapping, you must test the sign bits before and after the operation:

    # Detect signed overflow of a - b
    sub   $t0, $a0, $a1          # result in $t0, may trap
    xor   $t1, $a0, $a1          # sign bits differ?
    xor   $t2, $a0, $t0          # sign of a vs. result differ?
    
    
    This pattern works regardless of whether you used the built‑in `sub` or the manual two‑step version.
    
    

A Minimal Macro Library for “Subtraction‑Only” Environments

Below is a tiny, self‑contained macro set you can paste at the top of any MIPS source file. Even so, it assumes the presence of addu, addiu, xori, and a single temporary register ($at – the assembler temporary). If you cannot use $at, replace it with any caller‑saved register ($t0‑$t7) Easy to understand, harder to ignore..

# -------------------------------------------------
# Macro: NEG dst, src
#   dst = -src  (two's complement)
# -------------------------------------------------
.macro NEG dst, src
    xori  \dst, \src, -1   # invert bits
    addiu \dst, \dst, 1    # add one
.endm

# -------------------------------------------------
# Macro: SUB dst, src1, src2
#   dst = src1 - src2
#   Uses $at as a scratch register.
# -------------------------------------------------
.macro SUB dst, src1, src2
    NEG   $at, \src2       # $at = -src2
    addu  \dst, \src1, $at # dst = src1 + (-src2)
.endm

# -------------------------------------------------
# Macro: SUBU dst, src1, src2
#   Unsigned subtraction (no overflow trap)
# -------------------------------------------------
.macro SUBU dst, src1, src2
    NEG   $at, \src2
    addu  \dst, \src1, $at
.endm

With these three macros you can write high‑level‑looking arithmetic in an environment that only guarantees the addition family of instructions. The macros expand to exactly the same number of instructions as a hand‑written sequence, but they keep the source readable and maintainable.

Honestly, this part trips people up more than it should.


Conclusion

Subtraction on MIPS is not a mysterious operation hidden behind a special hardware path; it is simply addition of the two’s‑complement negation of the subtrahend. Modern cores expose sub/subu for convenience and performance, but the underlying principle remains the same and is fully accessible with the core instruction set (add, addu, addiu, xori) That's the whole idea..

Understanding this equivalence gives you several practical advantages:

  • Portability – You can target any MIPS‑compatible core, even one stripped down to a handful of arithmetic instructions.
  • Pedagogy – Demonstrating subtraction as “invert‑bits‑then‑add‑one” makes the abstract concept of two’s‑complement concrete for students.
  • Flexibility – When writing code generators, boot‑loaders, or highly constrained firmware, you can fall back on the generic pattern without worrying about missing opcodes.
  • Safety – By choosing sub vs. subu you control whether overflow triggers an exception, and you can manually detect overflow when needed.

So, whether you’re optimizing a tight inner loop on a high‑performance MIPS processor or teaching the fundamentals of binary arithmetic to a classroom of eager novices, remember that the simplest, most universal way to subtract is to add the negated operand. Keep the one‑cycle sub in your toolbox for the cases where it’s available, but never be surprised when a couple of clever bit‑twiddles and an addu get the job done just as reliably. Happy coding!

In short, subtraction on MIPS is nothing more exotic than the classic two’s‑complement trick: invert the bits of the number you want to subtract, add one, and then add that to the minuend. Whether you hand‑write the bit‑twiddling sequence or let the assembler expand a SUB macro, the hardware is doing the same thing it would do for a dedicated sub instruction. This insight not only simplifies the mental model you give to students, but also gives you a clear, portable fallback for any MIPS core that might lack the full arithmetic repertoire And it works..

Real talk — this step gets skipped all the time.

So next time you’re faced with a stripped‑down MIPS core, a bootloader, or a teaching exercise, remember that the “magic” of subtraction is just a bitwise complement plus an addition. Keep that in mind, and you’ll always be able to write correct, efficient code—no matter what instruction set you’re handed Surprisingly effective..

Latest Batch

New Picks

Picked for You

Other Perspectives

Thank you for reading about Unlock The Secret: How To Subtract In MIPS Without Using SUB – You’ll Never Guess The Trick. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home