14

All mainstream microprocessors from the 4004 on, have implemented signed integer arithmetic with twos complement and silent wraparound on overflow (by which I mean that the CPU itself will not trap, though might set a flag that code could check). The C language standard allows signed integer arithmetic to trap on overflow, and GCC will do this if you specify -ftrapv.

Which historical CPUs (not necessarily microcomputer) have implemented trap on signed integer overflow (i.e. the CPU itself generates the trap)? I believe Mill does so, but that is still an R&D project, not a shipping CPU.

10
  • 6
    Does the x86 INTO (i.e. “int o”) count? It triggers an interrupt if the overflow flag is set, so can be used as a single-byte suffix anywhere you want to trap on overflow. And, yes, that’s signed overflow, not carry.
    – Tommy
    Feb 4 at 14:58
  • 3
    @Tommy - I'd say not, since it's not intrinsically different from the 'jump on overflow set' instruction that practically every processor with an overflow flag implements, from the MIX on up.
    – dave
    Feb 4 at 16:32
  • 7
    MIPS has add and addi which triggers an exception on signed integer overflow (addu and addiu if you don't want overflow checking signed or unsigned). RISC V has done away with the trapping adds. MC68000 has trapv instruction which triggers an exception if the overflow flag is set (e.g. a preceding add set the overflow flag).
    – Erik Eidt
    Feb 4 at 16:53
  • 1
    @dave: A compact way to check the overflow flag is sort of half way between having overflow-trapping add like MIPS vs. only having conditional branches that don't record a return address. With the latter, you'd need a unique branch target for every possibly-overflowing operation to figure out which one overflowed. That's why x86 and m68k have into and trapv as well as jo or however m68k spells the branch condition. A user-space callo would be equally useful, or more useful in some programs without needing the OS's help. Feb 5 at 5:24
  • 1
    "I believe Mill does so". Yes, Mill has the option to do that. But also has the option to wrap instead, or to produce a result of double the width, which of course can't overflow. To be clear, these are distinct instructions, so you might trap on overflow for one variable but not the other, or whatever the program wants to do. Feb 6 at 8:37

7 Answers 7

17

The VAX optionally enables integer-overflow traps. The Processor Status Word (the half of the Processor Status Longword accessible to unprivileged modes) has trap enables for integer overflow, decimal overflow, and floating-point underflow.

The integer and decimal overflow enable bits in the PSW are set from the entry mask of a subroutine entered by a CALLS/CALLG instruction, and therefore each routine specifies its requirements for trapping.

DEC standard 32, VAX Architecture - see pages 1-25 to 1-27 for processor status, 3-71 on for procedure calls.

16

MIPS has always had trapping on overflow -- the add and sub instructions trap on signed overflow. It also has addu and subu instructions (unsigned, wrapping) that do not trap, so some compilers use them for all addition/subtraction, since with two's complement wrapping signed is the same as wrapping unsigned.

4
  • As a consequence, do DLX and RISC V have it too?
    – davolfman
    Feb 5 at 17:26
  • 4
    RISC-V does not (and is pretty much totally unlike MIPS, having no real connection to it). DLX I don't really know, but mostly seems to be toy, not having traps at all.
    – Chris Dodd
    Feb 5 at 23:51
  • 1
    Real-world MIPS compilers just don't use the "signed" instructions at all, AFAICT. Feb 6 at 15:47
  • 1
    that's why add and addi are very rarely used. Compiler generated almost always use addu/addiu
    – phuclv
    Feb 6 at 17:19
9

SPARC had TADDccTV and TSUBccTV : "Tagged Add (modify icc) Trap on Overflow"

These very rarely used instructions were created for dynamic typing, object oriented languages such as Lisp and Smalltalk.

With these instructions, the two lower bits of 32bits operands are "tags" to indicate if the value is an integer, or instead a pointer to an object structure. Adding an integer with an object would trigger a trap.

Integer overflows would also trigger traps, to allow variable precision integers, short integers are directly encoded in 32bits values, large integers are objects in memory ("fixnum" and "bignum" in Lisp).

8

The AT&T Bellmac 32 microprocessor, first released in 1980, could automatically trap on integer overflow. Bit 22 of its processor status word enables the overflow trap.

5

I think indisputably the most important/influential machine to do this was the IBM S/360 and its compatible successors (370, 390, "z"). Two's-complement overflow stores the truncated result, sets condition code 3, and interrupts IF a bit in the PSW register enables that. In OS/360 if you (or something you use like a language runtime) haven't ESTAEd, this caused an ABEND with IIRC code 0C-something (probably still does, but I haven't used anything after VS2).

S/360 also has packed-decimal arithmetic (aka BCD; standard not an option or extension like some contemporaneous machines), and overflow there similarly interrupts if enabled by a different PSW bit. (Floating-point overflow interrupts unconditionally, as do both integer and decimal zerodivide.)

Another machine I used, the Tandem-then-Compaq-then-HPE NonStop, also had interrupt on several arithmetic conditions (integer-2sC or floating-point overflow or zerodivide) enabled by a (single) bit in the ENV register, see page 85 here. I believe the HP3000 on which NonStop was loosely based was similar. (NonStop only fakes decimal; it has 64-bit-signed-binary arithmetic which can handle magnitudes over 10^18, plus special instructions to scale by powers of 10 and convert from and to decimal character strings.)

2

The 68000 also has a trap-on-overflow instruction.

6
  • 3
    If you're talking about trapv, that's like x86 into: take an exception according to flags. This was discussed in comments. It is more useful for overflow-checking than just a conditional branch, though, because you can figure out which operation overflowed without having a separate branch target for every add/sub + jump-if-overflow. Feb 5 at 5:21
  • 2
    @PeterCordes: Attempting to accurately report which operation overflowed makes optimization difficult; further, in many cases what's needed isn't knowledge of where overflow occurred, but rather that overflow did not cause erroneous results. If code needs to add 256 int32_t values, it may care about whether overflow caused the computation to yield an incorrect total, but be perfectly happy with an implementation that e.g. adds all of the values to produce an int64_t and only traps if the final total is outside the range of int32_t. Such an implementation may be much faster...
    – supercat
    Feb 5 at 17:16
  • 1
    ...than one which had to trap if any intermediate subtotal exceeded the range of int32_t, especially if an integer overflow trap that occurred while processing the leading portion of an array would be required to prevent a memory-fault trap in cases where the latter portion was inaccessible.
    – supercat
    Feb 5 at 17:24
  • 1
    @PeterCordes: If a program reports that an overflow occurred with certain inputs, then feeding those inputs to a build that traps every individual operation against overflow will identify someplace where the program performed an invalid computation. If an optimized build with an "overall" overflow check could run twice as fast as one which checked every operation, and most attempts to run a program don't result in any overflow, the cost of having to occasionally run a program a second time would be less than the savings from using looser overflow semantics.
    – supercat
    Feb 5 at 17:58
  • 2
    @PeterCordes: The notion that safety checks should be omitted from production build is fundamentally misguided and dangerous, especially when applied to code which receives input from untrustworthy sources. Testing by its nature will often be blind to failure modes that weren't anticipated by the programmer, but may be exploited by someone seeking to create maliciously malformed data.
    – supercat
    Feb 5 at 18:01
2

BESM-6, which did not have a separate integer ALU, would trap on overflow by default.

Integer calculations were done by disabling normalization and using either zero exponent (mostly in assembly programming), or an exponent signifying the actual value of the number (typically in Fortran, to facilitate mixing reals and integers in expressions).

Neither representation caused an integer overflow trap, instead the result started to deviate from the chosen representation of an integer, which could cause arbitrary errors later).

However, if the maximum possible exponent were used to represent integers, "integer" operations (*1) would cause an overflow trap when appropriate. I'm not aware of a programming system which used that convention, though.

*1) Integer multiplications and divisions had to be done with short routines performing pre- or post-adjustment of the exponents regardless of the representation, so it could be arranged that in those routines, either the mul/div instruction, or a following exponent adjustment instruction would trap if the result could not be represented as a integer.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .