0

Let's assume we have the following binary numbers with their representation:

| bin | unsigned | signed   |
|:---:|----------|----------|
| 110 | 6        | -2       |
| 111 | 7        | -1       |

Now regardless if signed or unsigned, 111 + 110 = 1101, Now I can interpret the result 1101 as signed or unsigned which is:

| bin  | unsigned | signed   |
|:----:|----------|----------|
| 1101 | 13       | -3       |

Which matches the decimal operation:

6+7 = 13
-1-2 = -3

There was no difference between doing a signed addition or unsigned addition. So why would CPUs have different circuits/instructions for such operation?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Which CPU instruction sets have different signed and unsigned add? Some instructions may have sign-extension modes for immediate arguments, or be able to set different flags, but it's hard to say without a concrete example. – trent Feb 17 '20 at 03:28
  • 1
    @trentcl: Presumably only one's complement machines have different `add` instructions. (If you don't count stuff like MIPS `add` vs. `addu`; `add` traps on 2's complement signed overflow, so compilers use `addu` for everything, signed and unsigned. It's not *really* signed vs. unsigned, it's just plain add with/without an additional trap on signed overflow.) I could imagine some machines with limited flags having different adds that set an "overflow" flag according to signed overflow or unsigned carry (aka overflow), depending on the opcode, instead of having different flags that both get set – Peter Cordes Feb 17 '20 at 03:31
  • @trentcl so in my `add` example, the only reason to have 2 diff (signed and unsigned) instructions is to see where the overflow is? meaning in the the sign word overflow happens when the `sign` bit is passed (i.e 1 before the max bit), in the unsigned world overflow happens when the max bit is passed, correct? –  Feb 17 '20 at 03:36

2 Answers2

2

Because 2's complement add/sub is the same binary operation as unsigned add/sub. But for comparison (and division and widening multiply), interpretation of the MSB as a sign bit or not matters.

Some CPUs just have a cmp instruction that sets all flags, and then you get your branch instruction checks a specific flag condition (predicate). Other CPUs without flags / condition codes (like MIPS and RISC-V) need predicates in their compare-into-register instructions.

SIMD compare instructions on x86 / ARM are also compare-into-register, not setting multiple different flags, so they also have the predicate as part of the compare instruction (like cmpps takes an immediate byte with the predicate, or for integer there's pcmpgtd / pcmpeqd.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • @Josh: division isn't, it's usually narrowing. e.g. MIPS has special LO and HI registers for the double-width input of division, and the double-width output of multiply. [In MIPS, what is HI and LO](//stackoverflow.com/q/2320196). x86's widening aka full multiply instructions are `mul` and `imul` (the one-operand forms), and do 32 x 32 => 64-bit multiply (or 64x64 => 128), putting the result in a pair of registers. [Why is imul used for multiplying unsigned numbers?](//stackoverflow.com/q/42587607) shows the "normal" vs. widening versions: only the high half cares about sign interpretation – Peter Cordes Feb 18 '20 at 01:47
  • In addition, overflow behavior is often different. MIPS' unsigned uses non-signalling wrap-around while signed overflow produces an exception. –  Feb 18 '20 at 17:22
  • @PaulA.Clayton: MIPS mnemonics are kind of misnamed. `addu` is the "normal" wrapping add that compilers use for everything. You only ever use `add` when you *want* to trap on signed overflow. That's the only difference, and there's no problem using `addu` on signed values. I don't consider `addu` vs. `add` to be unsigned vs. signed, I consider `add` as MIPS's optional way of exposing signed-overflow detection. IIRC, even MIPS's own asm manual suggests that the mnemonics are misleading. – Peter Cordes Feb 19 '20 at 01:31
  • The C programming language defined signed addition overflow as undefined (allowing overflow exceptions [or nasal demons]). Wrap-around appears to be mainly used for address calculation (and facilitating a single comparison for an in-range check); other overflows are usually errors. Since overflow is checked based on a signed interpretation (adding one to the maximum positive integer will overflow even though the carry-out into the most significant bit would be a correct representation for unsigned). –  Feb 19 '20 at 22:23
  • @PaulA.Clayton: But compilers want to be able to treat integer `+` as associative. You can only do that if creating different temporaries that didn't exist in the source won't introduce new traps. Yes it appears MIPS was designed with the assumption that checked addition would be the normal case, with mnemonics naively based on what you might want for a non-optimizing C compiler. – Peter Cordes Feb 19 '20 at 23:36
2

It depends on the binary representation. This is a major point of 2s-complement representation -- when using 2s complement, signed and unsigned addition, subtraction, and mulitplication of fixed-width operands and same width results are identical, so you can use the same hardware instructions for both.

If you use 1s complement or sign magnitude, you need slight differences between signed and unsigned operations.

Division is different here, as are widening operations.