Deutsch   English   Français   Italiano  
<vckf9d$178f2$1@dont-email.me>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!2.eu.feeder.erje.net!3.eu.feeder.erje.net!feeder.erje.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: kegs@provalid.com (Kent Dickey)
Newsgroups: comp.arch
Subject: Re: is Vax addressing sane today
Date: Fri, 20 Sep 2024 18:35:26 -0000 (UTC)
Organization: provalid.com
Lines: 139
Message-ID: <vckf9d$178f2$1@dont-email.me>
References: <vbd6b9$g147$1@dont-email.me> <09ce1622b872f0b0fa944e868a8c97be@www.novabbs.org> <vbnisc$2hb59$1@dont-email.me> <2024Sep10.094353@mips.complang.tuwien.ac.at>
Injection-Date: Fri, 20 Sep 2024 20:35:26 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="863bba4f1586ce69d3db47d38665160e";
	logging-data="1286626"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX1/xwtLduab67e3RxGHcKsPf"
Cancel-Lock: sha1:FidbYmj1XGATu3RtY6fmoHOLa6o=
Originator: kegs@provalid.com (Kent Dickey)
X-Newsreader: trn 4.0-test76 (Apr 2, 2001)
Bytes: 7508

In article <2024Sep10.094353@mips.complang.tuwien.ac.at>,
Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
>Brett <ggtgp@yahoo.com> writes:
>>Speaking of complex things, have you looked at Swift output, as it checks
>>all operations for overflow?
>>
>>You could add an exception type for that, saving huge numbers of correctly
>>predicted branch instructions.
>>
>>The future of programming languages is type safe with checks, you need to
>>get on that bandwagon early.
>
>MIPS got on that bandwagon early.  It has, e.g., add (which traps on
>signed overflow) in addition to addu (which performs modulo
>arithmetic).  It has been abandoned and replaced by RISC-V several
>years ago.
>
>Alpha got on that bandwagon early.  It's a descendent of MIPS, but it
>renamed add into addv, and addu into add.  It has been canceled around
>the year 2000.

[ More details about architectures without trapping overflow instructions ]

Trapping on overflow is basically useless other than as a debug aid,
which clearly nobody values.  If you take Rust's approach, and only
detect overflow in debug builds, then you already don't care about
performance.

If you want to do almost anything at all other than core dump on
overflow, you need to branch to recovery code.  And although it's
theoretically possible to recover from the trap, it's worse than any
other approach.  So it's added hardware that's HARDER for software to
use.  No surprise it's gone away.

IA64 went down this road--trapping on speculation failures.  It was a
huge disaster--trying to recover through an exception handler mechanism
is slow and painful, for the reasons I'll lay out for overflow
exceptions.

Let's look at how you might want to handle overflows when they happen:

1) Your language supports seemlessly transitioning to BigInts on
	overflow.  Then each operation that could overflow needs to call
	a special bit of code to change to BigInt and then continue the
	calculation.  This code must exist, even if a trapping
	instruction doesn't need an explicit branch to it.  Some
	mechanism is needed to call this code.

2) You need to call an exception handler, and the routine with the overflow
	is ended.  We need to know which exception handler to call.

3) You want to clamp the value to a reasonable range and continue.  The
	reasonable values need to be looked up somewhere.

4) You just want to crash the program.  If a debugger is attached, it can
	say where the overflow occurred.

Trapping on overflow instructions really are only useful for #4.  Let's
look at how the other cases could be handled, with a) meaning using
branches, and b) mean using a trapping instruction.

1a) (BigInt): After doing an operation which could overflow, use a
	conditional branch to jump to code to convert to BigInt, which
	then jumps back.  Overhead is basically the branch-on-overflow
	instruction.

1b) (BigInt with traps). Hardware traps to the OS, which needs to prepare
	the required structures describing the exception (all regs and
	the address), and then call the signal handler.  The signal
	handler needs to look up the address of the trap with a table
	describing what to do for this particular operation which
	overflowed.  Each table entry needs to describe, in detail, what
	registers are involved (the sources and the dest), and where to
	return once the BigInt has been created.  This requires massive
	changes to the compiler (and possibly linker) to prepare these
	tables.  The compiler must guarantee that changing the dest
	register to a pointer to BigInt works properly (otherwise,
	special code needs to be emitted for each potentially trapping
	instruction to try to recover).

2a) (Try/Catch): After doing an operation which could overflow, use a
	conditional branch to jump to the catch block.

2b) (Try/Catch with traps).  Repeat all the OS work and call the signal
	handler.  Now, it just needs a table entry describing where to
	jump to to enter the catch block.  Almost all the complexity of
	1b), but without needing the register details.

3a) (Clamp): After doing an operation which could overflow, use a
	conditional branch to do the MIN/MAX operations to bring it back
	within range and then jump back.

3b) (Clamp with trap): Basically the same as 1b), but there's an alternative
	if the clamps are global (MAX_INT/MIN_INT).  The exception handler
	can read the instruction which trapped, figure out the source and
	dest registers, re-do the calculation, and clamp the destination
	to MIN or MAX, and return to just after the instruction which
	trapped.

4a) (Crash): Every operation could overflow needs a conditional branch
	after it to branch to a crashing instruction (or a branch over
	an undefined instruction if there's no overflow).

4b) (Crash with trap): Use operations which trap on overflow.  This takes
	no new instructions and costs no performance.

Basically, all a) cases are:

	op_with_might_overflow();
	if(overflow_happened) {
		handle the overflow
	}

Trapping-on-overflow instructions are clearly useless for languages
which care about overflow.  To save one branch instruction, an entry is
needed to describe how to handle the overflow, which is certainly larger
than a branch instruction.  And the code to "handle the overflow" is
needed in any case.  And this assume some sort of instant lookup--of the
1000 overflow instructions, we need a hash table to look up the address,
which is more overhead.

Trapping on overflow instructions are useful as a debug aid for
languages which don't care about overflow--but then you're optimizing
something nearly useless.  It also might be helpful if global clamping
to MIN/MAX was useful (and I don't think it is).

Instruction sets which make detecting overflow difficult (say, RISC-V),
would do well to make branch-on-overflow efficient and easy.  But adding
trap-on-overflow instructions is a waste of effort.

Note that using traps on data access violations which are "fixed" by
signal handlers CAN work out.  They are slow, but as long as the
exception handler can fix the access violation and return right to the
instruction which failed (without needing to know ANYTHING about that
instruction in particular), this can work fine.  But integer overflow
doesn't work like that--it's generally not possible to figure out
in the trap handler what to do without more information.

Kent