It is the hardware's job to provide a useful set of instructions. It is the compiler's job to translate the abstract high level language to those instructions.
The hardware stores and manipulates patterns of bits. Meaning is only assigned to a pattern of bits when we perform an operation on it. If we perform a "signed divide" operation on two registers we are telling the hardware or library function to assume the bits in those registers represent signed numbers. If we perform an addition operation on two registers we are telling the hardware to assume those bit patterns represent numbers, we are not however telling it if those numbers are signed or unsigned. The hardware has no reason to know or care about that.
Two's complement is the most popular format for signed integers because it requires the least additional work from the hardware. In particular if addition, subtraction and non-widening multiplication are implemented with modulo 2n wraparound (which is the easiest way to implement them) then those same operations can be used for both signed and unsigned arithmetic.
That said, there are operations that are different for signed and unsigned numbers and the compiler or assembler programmer needs to be aware of them.
Comparison and overflow detection
Equality comparison is the same in signed and unsigned arithemtic. However inequality comparisons are not. 255 is after all greater than zero while -1 is smaller than zero. Similarly overflow detection is different, the calculation of 255+255 in 8 bit unsigned arithmetic would overflow, but the calculation of (-1) + (-1) in 8 bit signed arithmetic would not.
However most CPUs do not have dedicated signed and unsigned comparison operations. Instead most CPUs have a set of flags where some flags are meaningful for unsigned operations and different flags are meaningful for signed operations.
The flags may be set as a result of a regular arithmetic operation. Most CPUs also have a dedicated compare operation which effectively performs a subtraction and sets the flags but discards the result.
For example the set of flags from arm32 is (and these are fairly typical).
- Z: zero, used to detect if the result was zero (for a compare instruction this means the operands were equal)
- C: Carry, used when constructing larger arithmetic operations out of smaller ones. Also used to detect overflow in unsigned arithmetic.
- V: Overflow, Set when a signed arithmetic operation overflows.
- N: Negative, Set if the most significant bit of the result is set. That is set when the result of a signed arithmetic operation is negative.
The CPU does not know or care whether the user is performing a signed or unsigned operation, it always sets all the flags based on a set of simple rules. It is up to the compiler (or programmer if writing in assembler) to know what flags are meaningful for their operation and choose an appropriate conditional instruction.
The conditional instructions in turn look at various combinations of these flags. Conditional instructions intended for use in code working on unsigned values look at the C and Z flags, while conditional instructions intended for use in code working on signed values look at the V, Z and N flags.
Widening
Converting a number from a smaller type to a larger one is known as widening. For unsigned numbers the extra bits must be filled with zero. For signed numbers the extra bits must be filled with copies of the sign bit.
Some architectures may have dedicated instructions for widening or may incorporate widening functionality into other instructions. For example on 32-bit arm all arithmetic instructions work on 32-bit words. On the original arm CPU the "load byte" instruction always zero-extended the byte. However with armv4 additional load instructions were added, so signed bytes and signed and unsigned halfwords could be loaded and extended in a single operation.
Similarly recent versions of 32-bit arm have specific sign extension instructions which discard the upper part of a register and replace it's contents with a sign or zero extension of the lower part.
In other cases, widening may be performed using more generic instructions. This may include shift instructions and bitwise operations. For example extending a single word value into a double word value may use a shift by one bit less than the word size (e.g. 31 for a 32-bit word size) to construct a new word consisting entirely of duplicates of the first words signed bit.
Widening multiply
A widening multiply typically produces a result twice as big as it's arguments. For example a 32x32 widening multiply would normally produce a 64-bit result. In some cases there may be a single instruction that performs the complete widening multiply, in others a "multiply high" instruction may be provided that only provides the top part of the result.
Widening multiply is useful in a number of applications including fixed-point arithmetic and as a building block to perform arithmetic on numbers wider than the word size.
When processors offer widening multiply they usually offer separate versions of it for signed and unsigned operation.
bit shifts
Bit shifts can be used to multiply or divide numbers by powers of two.
Shifting "left" to make a number larger is the same for both signed and unsigned numbers. However shifting "right" to make a number smaller is different, for unsigned numbers the extra places should be filled with zeros, while for signed numbers they should be filled with copies of the signed bit.
Most CPUs offer separate right shift instructions for signed and unsigned operation. These are known (presumably for historical reasons) as "logical shift" (for unsigned operations) and "arithmetic shift" for signed operations.
Be aware that some higher level languages, particularly C and older versions of C++ leave the behaviour of shift implementations on negative numbers implementation defined.
Division
Division is different for signed and unsigned numbers as can be readily seen. (-2)/(-1) = 2 but 254 / 255 = 0.
In my experience, many CPUs do not offer any division instructions at all, but when division instructions are provided, usually both signed and unsigned versions are available.