Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.arch > #117720 > unrolled thread
| Started by | Kragen Javier Sitaker <kragen@canonical.org> |
|---|---|
| First post | 2026-09-01 17:15 -0300 |
| Last post | 2026-09-11 14:28 -0300 |
| Articles | 16 — 7 participants |
Back to article view | Back to comp.arch
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) Kragen Javier Sitaker <kragen@canonical.org> - 2026-09-01 17:15 -0300
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) John Ames <commodorejohn@gmail.com> - 2026-09-01 14:31 -0700
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) BGB <cr88192@gmail.com> - 2026-09-01 17:18 -0500
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) MitchAlsup <user5857@newsgrouper.org.invalid> - 2026-09-02 02:04 +0000
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) John Ames <commodorejohn@gmail.com> - 2026-09-02 08:23 -0700
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) Kragen Javier Sitaker <kragen@canonical.org> - 2026-09-11 13:48 -0300
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) MitchAlsup <user5857@newsgrouper.org.invalid> - 2026-09-11 18:03 +0000
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) Kragen Javier Sitaker <kragen@canonical.org> - 2026-09-02 13:52 -0300
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) MitchAlsup <user5857@newsgrouper.org.invalid> - 2026-09-02 17:41 +0000
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-09-09 11:16 +0000
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) MitchAlsup <user5857@newsgrouper.org.invalid> - 2026-09-02 01:53 +0000
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) EricP <ThatWouldBeTelling@thevillage.com> - 2026-09-05 12:08 -0400
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-09-09 13:36 +0000
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-09-09 10:50 +0000
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) Paul Rubin <no.email@nospam.invalid> - 2026-09-09 22:10 -0700
Re: adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) Kragen Javier Sitaker <kragen@canonical.org> - 2026-09-11 14:28 -0300
| From | Kragen Javier Sitaker <kragen@canonical.org> |
|---|---|
| Date | 2026-09-01 17:15 -0300 |
| Subject | adding overflow and carry to every GPR (was Re: OT: Epic RISC-V rant) |
| Message-ID | <87a4q0afu7.fsf_-_@debian> |
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes: > RISC-V follows its ancestor MIPS (from where it also has many > mnemonics) in this respect. For a new way to add the carry > functionality without adding a condition code register, read > > https://www.complang.tuwien.ac.at/anton/tmp/carry.pdf > > (unpublished). This is a fascinating idea. I guess the MuP21 had a carry bit in every “general-purpose register”, making them 21 bits, but I’ve never seen any other architecture do this, nor a version that separates out overflow bits from carry bits. I also didn’t realize that (base) RISC-V needed 5 instructions *per word* for multi-precision addition. Thank you for sharing your draft! Kragen
[toc] | [next] | [standalone]
| From | John Ames <commodorejohn@gmail.com> |
|---|---|
| Date | 2026-09-01 14:31 -0700 |
| Message-ID | <20260901143106.00006dd7@gmail.com> |
| In reply to | #117720 |
On Tue, 01 Sep 2026 17:15:12 -0300 Kragen Javier Sitaker <kragen@canonical.org> wrote: > > RISC-V follows its ancestor MIPS (from where it also has many > > mnemonics) in this respect. For a new way to add the carry > > functionality without adding a condition code register, read > > > > https://www.complang.tuwien.ac.at/anton/tmp/carry.pdf > > > > (unpublished). > > This is a fascinating idea. I guess the MuP21 had a carry bit in > every “general-purpose register”, making them 21 bits, but I’ve never > seen any other architecture do this, nor a version that separates out > overflow bits from carry bits. > > I also didn’t realize that (base) RISC-V needed 5 instructions *per > word* for multi-precision addition. Hm, that *is* a bit interesting, though the idea of including non- number info in a numeric register drives me a little crazy. (It is, admittedly, no weirder than what you already deal with in floating- point hardware.) The idea I had last time I dabbled with this stuff was to extend the basic add/subtract instructions with an option to save the carry/borrow value in another GPR, instead - but I never gave any thought to how to represent overflow that way. Hmm.
[toc] | [prev] | [next] | [standalone]
| From | BGB <cr88192@gmail.com> |
|---|---|
| Date | 2026-09-01 17:18 -0500 |
| Message-ID | <1177ivo$26r1u$1@dont-email.me> |
| In reply to | #117723 |
On 9/1/2026 4:31 PM, John Ames wrote: > On Tue, 01 Sep 2026 17:15:12 -0300 > Kragen Javier Sitaker <kragen@canonical.org> wrote: > >>> RISC-V follows its ancestor MIPS (from where it also has many >>> mnemonics) in this respect. For a new way to add the carry >>> functionality without adding a condition code register, read >>> >>> https://www.complang.tuwien.ac.at/anton/tmp/carry.pdf >>> >>> (unpublished). >> >> This is a fascinating idea. I guess the MuP21 had a carry bit in >> every “general-purpose register”, making them 21 bits, but I’ve never >> seen any other architecture do this, nor a version that separates out >> overflow bits from carry bits. >> >> I also didn’t realize that (base) RISC-V needed 5 instructions *per >> word* for multi-precision addition. > > Hm, that *is* a bit interesting, though the idea of including non- > number info in a numeric register drives me a little crazy. (It is, > admittedly, no weirder than what you already deal with in floating- > point hardware.) > > The idea I had last time I dabbled with this stuff was to extend the > basic add/subtract instructions with an option to save the carry/borrow > value in another GPR, instead - but I never gave any thought to how to > represent overflow that way. Hmm. > In my case, for my XG3 ISA, which could nominally be considered a RISC-V extension, I ended up re-adding the SR.T and ADC/ADDC mechanism that my ISA originally inherited from SuperH. Granted, this still doesn't address the issue for RISC-V proper. As for me, adding extra/hidden bits to registers is not an idea I take fondly... ( Meanwhile, still dealing with hassles from the unresolved issue of my Twitter/X account having been hacked... And the account recovery process being very much unhelpful about it... Debatable actually if there are any real people in the loop, or if maybe it is just Grok dealing with it and sending out boilerplate responses or similar. )
[toc] | [prev] | [next] | [standalone]
| From | MitchAlsup <user5857@newsgrouper.org.invalid> |
|---|---|
| Date | 2026-09-02 02:04 +0000 |
| Message-ID | <1788314691-5857@newsgrouper.org> |
| In reply to | #117723 |
John Ames <commodorejohn@gmail.com> posted:
> On Tue, 01 Sep 2026 17:15:12 -0300
> Kragen Javier Sitaker <kragen@canonical.org> wrote:
>
> > > RISC-V follows its ancestor MIPS (from where it also has many
> > > mnemonics) in this respect. For a new way to add the carry
> > > functionality without adding a condition code register, read
> > >
> > > https://www.complang.tuwien.ac.at/anton/tmp/carry.pdf
> > >
> > > (unpublished).
> >
> > This is a fascinating idea. I guess the MuP21 had a carry bit in
> > every “general-purpose register”, making them 21 bits, but I’ve never
> > seen any other architecture do this, nor a version that separates out
> > overflow bits from carry bits.
> >
> > I also didn’t realize that (base) RISC-V needed 5 instructions *per
> > word* for multi-precision addition.
>
> Hm, that *is* a bit interesting, though the idea of including non-
> number info in a numeric register drives me a little crazy. (It is,
> admittedly, no weirder than what you already deal with in floating-
> point hardware.)
>
> The idea I had last time I dabbled with this stuff was to extend the
> basic add/subtract instructions with an option to save the carry/borrow
> value in another GPR, instead - but I never gave any thought to how to
> represent overflow that way. Hmm.
That is what CARRY does. The Rd register in CARRY supplies a register
used to carry the additional values from calculation to calculation.
The Immediate in CARRY selects which instruction consume Rd {i},
which instructions generate the next Rd {o} and which do both {io}
and which do neither {}.
For ADD, carry Rd contains only 1 bit, but for others, it contains
"all the bits that did not make it into the standard result". This
makes CARRY suitable for all integer multiprecision arithmetic and
for significant quantities of FP arithmetic.
Standard integer calculations {ADD, MUL, DIV, SL, SR, ROL, ROR, PERM,
and a few more esoteric ints}
CARRY {o} IMUL produces a 128-bit result
CARRY {i} IMUL performs IMAC
CARRY {io} IMUL performs IMAC producing a 128-bit result
Multi-precisions shifts use carry
IEEE 754 augmented FADD and FMUL use CARRY
>
[toc] | [prev] | [next] | [standalone]
| From | John Ames <commodorejohn@gmail.com> |
|---|---|
| Date | 2026-09-02 08:23 -0700 |
| Message-ID | <20260902082315.000009c7@gmail.com> |
| In reply to | #117731 |
On Wed, 02 Sep 2026 02:04:51 GMT
MitchAlsup <user5857@newsgrouper.org.invalid> wrote:
> > The idea I had last time I dabbled with this stuff was to extend the
> > basic add/subtract instructions with an option to save the
> > carry/borrow value in another GPR, instead - but I never gave any
> > thought to how to represent overflow that way. Hmm.
>
> That is what CARRY does. The Rd register in CARRY supplies a register
> used to carry the additional values from calculation to calculation.
> The Immediate in CARRY selects which instruction consume Rd {i},
> which instructions generate the next Rd {o} and which do both {io}
> and which do neither {}.
>
> For ADD, carry Rd contains only 1 bit, but for others, it contains
> "all the bits that did not make it into the standard result". This
> makes CARRY suitable for all integer multiprecision arithmetic and
> for significant quantities of FP arithmetic.
> [...]
> Multi-precisions shifts use carry
Yes, exactly - add/subtract set the designated overflow/carry register
to 1 on a carry/borrow (which can then be added/subtracted from the next
more significant word) but e.g. multiply can set it to the whole most-
significant half of the product, multi-place shifts can catch all the
bits that fall off one end in the other so that rotate becomes shift-
and-OR, etc. Very flexible, especially if you have the capability to
branch on the value of a GPR.
[toc] | [prev] | [next] | [standalone]
| From | Kragen Javier Sitaker <kragen@canonical.org> |
|---|---|
| Date | 2026-09-11 13:48 -0300 |
| Message-ID | <878q57d99d.fsf@debian> |
| In reply to | #117737 |
John Ames <commodorejohn@gmail.com> writes: > On Wed, 02 Sep 2026 02:04:51 GMT > MitchAlsup <user5857@newsgrouper.org.invalid> wrote: >> For ADD, carry Rd contains only 1 bit, but for others, it contains >> “all the bits that did not make it into the standard result”. This >> makes CARRY suitable for all integer multiprecision arithmetic and >> for significant quantities of FP arithmetic. >> [...] >> Multi-precisions shifts use carry > > Yes, exactly - add/subtract set the designated overflow/carry register > to 1 on a carry/borrow (which can then be added/subtracted from the next > more significant word) but e.g. multiply can set it to the whole most- > significant half of the product, multi-place shifts can catch all the > bits that fall off one end in the other so that rotate becomes shift- > and-OR, etc. Very flexible, especially if you have the capability to > branch on the value of a GPR. A bit-shift operation with two source registers is sometimes called a “funnel shift”, which is sort of the inverse of this: <https://www.eevblog.com/forum/programming/funnel-shifter-where-are-useful/> <https://stackoverflow.com/questions/12767113/funnel-shift-what-is-it> <https://github.com/rust-lang/rust/issues/145686> That is, instead of one source register (for a given bit shift size) and two destination registers, a funnel shift has two source registers (plus the amount to shift) and possibly just one destination register. An interesting thing about funnel shifts is that, if both source registers are the same, it provides bit rotation, not just shift. Conceivably you could get the same result from this inverse funnel shift, depending on how you handle the case where the destination register is the same as the CARRY register. Kragen
[toc] | [prev] | [next] | [standalone]
| From | MitchAlsup <user5857@newsgrouper.org.invalid> |
|---|---|
| Date | 2026-09-11 18:03 +0000 |
| Message-ID | <1789149834-5857@newsgrouper.org> |
| In reply to | #117955 |
Kragen Javier Sitaker <kragen@canonical.org> posted: > John Ames <commodorejohn@gmail.com> writes: > > On Wed, 02 Sep 2026 02:04:51 GMT > > MitchAlsup <user5857@newsgrouper.org.invalid> wrote: > >> For ADD, carry Rd contains only 1 bit, but for others, it contains > >> “all the bits that did not make it into the standard result”. This > >> makes CARRY suitable for all integer multiprecision arithmetic and > >> for significant quantities of FP arithmetic. > >> [...] > >> Multi-precisions shifts use carry > > > > Yes, exactly - add/subtract set the designated overflow/carry register > > to 1 on a carry/borrow (which can then be added/subtracted from the next > > more significant word) but e.g. multiply can set it to the whole most- > > significant half of the product, multi-place shifts can catch all the > > bits that fall off one end in the other so that rotate becomes shift- > > and-OR, etc. Very flexible, especially if you have the capability to > > branch on the value of a GPR. > > A bit-shift operation with two source registers is sometimes called a > “funnel shift”, which is sort of the inverse of this: > <https://www.eevblog.com/forum/programming/funnel-shifter-where-are-useful/> > <https://stackoverflow.com/questions/12767113/funnel-shift-what-is-it> > <https://github.com/rust-lang/rust/issues/145686> > > That is, instead of one source register (for a given bit shift size) and > two destination registers, a funnel shift has two source registers (plus > the amount to shift) and possibly just one destination register. > > An interesting thing about funnel shifts is that, if both source > registers are the same, it provides bit rotation, not just shift. > Conceivably you could get the same result from this inverse funnel > shift, depending on how you handle the case where the destination > register is the same as the CARRY register. Yes, CARRY is how one gets shift double-wide in My 66000. So, when we added Rotates, we use a length field (rather than a 2^(3+n) specifier) so, one can rotate a 6-bit field or a 19-bit field in either direction. > Kragen
[toc] | [prev] | [next] | [standalone]
| From | Kragen Javier Sitaker <kragen@canonical.org> |
|---|---|
| Date | 2026-09-02 13:52 -0300 |
| Message-ID | <871pbb8ujd.fsf@debian> |
| In reply to | #117731 |
MitchAlsup <user5857@newsgrouper.org.invalid> writes:
> John Ames <commodorejohn@gmail.com> posted:
>> The idea I had last time I dabbled with this stuff was to extend the
>> basic add/subtract instructions with an option to save the carry/borrow
>> value in another GPR, instead - but I never gave any thought to how to
>> represent overflow that way. Hmm.
>
> That is what CARRY does. The Rd register in CARRY supplies a register
> used to carry the additional values from calculation to calculation.
> The Immediate in CARRY selects which instruction consume Rd {i},
> which instructions generate the next Rd {o} and which do both {io}
> and which do neither {}.
This is on your 66000?
Kragen
[toc] | [prev] | [next] | [standalone]
| From | MitchAlsup <user5857@newsgrouper.org.invalid> |
|---|---|
| Date | 2026-09-02 17:41 +0000 |
| Message-ID | <1788370912-5857@newsgrouper.org> |
| In reply to | #117738 |
Kragen Javier Sitaker <kragen@canonical.org> posted:
> MitchAlsup <user5857@newsgrouper.org.invalid> writes:
> > John Ames <commodorejohn@gmail.com> posted:
> >> The idea I had last time I dabbled with this stuff was to extend the
> >> basic add/subtract instructions with an option to save the carry/borrow
> >> value in another GPR, instead - but I never gave any thought to how to
> >> represent overflow that way. Hmm.
> >
> > That is what CARRY does. The Rd register in CARRY supplies a register
> > used to carry the additional values from calculation to calculation.
> > The Immediate in CARRY selects which instruction consume Rd {i},
> > which instructions generate the next Rd {o} and which do both {io}
> > and which do neither {}.
>
> This is on your 66000?
Yes, indeed.
> Kragen
[toc] | [prev] | [next] | [standalone]
| From | anton@mips.complang.tuwien.ac.at (Anton Ertl) |
|---|---|
| Date | 2026-09-09 11:16 +0000 |
| Message-ID | <2026Sep9.131631@mips.complang.tuwien.ac.at> |
| In reply to | #117723 |
John Ames <commodorejohn@gmail.com> writes:
>Hm, that *is* a bit interesting, though the idea of including non-
>number info in a numeric register drives me a little crazy.
The Carry bit is bit 64 of the addition or subtraction of the
zero-extended operands.
Concerning the signed oVerflow bit, one could store bit 64 of the
addition or subtraction of sign-extended operands instead of the
overflow bit, and then check for a signed overflow by checking if this
bit 64 is different from bit 63. In that way that bit would also be a
"number info".
However, one advantage of storing an overflow bit (i.e., the result of
this xor) is that we can then combine these bits with "or" or "and".
>The idea I had last time I dabbled with this stuff was to extend the
>basic add/subtract instructions with an option to save the carry/borrow
>value in another GPR, instead
That has the disadvantage of occupying a write port in the register
set and in the renamer.
>- but I never gave any thought to how to
>represent overflow that way. Hmm.
A GPR has many bits:-)
- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: https://forth-standard.org/
EuroForth 2026 CFP: http://www.euroforth.org/ef26/cfp.html
[toc] | [prev] | [next] | [standalone]
| From | MitchAlsup <user5857@newsgrouper.org.invalid> |
|---|---|
| Date | 2026-09-02 01:53 +0000 |
| Message-ID | <1788314010-5857@newsgrouper.org> |
| In reply to | #117720 |
Kragen Javier Sitaker <kragen@canonical.org> posted:
> anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
> > RISC-V follows its ancestor MIPS (from where it also has many
> > mnemonics) in this respect. For a new way to add the carry
> > functionality without adding a condition code register, read
> >
> > https://www.complang.tuwien.ac.at/anton/tmp/carry.pdf
> >
> > (unpublished).
>
> This is a fascinating idea. I guess the MuP21 had a carry bit in every
> “general-purpose register”, making them 21 bits, but I’ve never seen any
> other architecture do this, nor a version that separates out overflow
> bits from carry bits.
In comparison, My 66000 can perform multi-wide addition using the CARRY
instruction-modifier.
add256: //R1-R4=Operand 1 R5-R87=Operand 2
CARRY R9,{{o}{io}{io}{i}}
ADD R1,R1,R5 // {o} generates output
ADD R2,R2,R6 // {io} consumes input generates output
ADD R3,R3,R7 // {io} consumes input generates output
ADD R4,R4,R8 // {i} consumes input
// R9 may or may not have been written
RET
> I also didn’t realize that (base) RISC-V needed 5 instructions *per
> word* for multi-precision addition.
While My 66000 only needs 1+epsilon per DoubleWord.
> Thank you for sharing your draft!
>
> Kragen
[toc] | [prev] | [next] | [standalone]
| From | EricP <ThatWouldBeTelling@thevillage.com> |
|---|---|
| Date | 2026-09-05 12:08 -0400 |
| Message-ID | <38XmS.1028$Pwy8.203@fx36.iad> |
| In reply to | #117720 |
> anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
>> RISC-V follows its ancestor MIPS (from where it also has many
>> mnemonics) in this respect. For a new way to add the carry
>> functionality without adding a condition code register, read
>>
>> https://www.complang.tuwien.ac.at/anton/tmp/carry.pdf
>>
>> (unpublished).
Looking at example 3 I think the overflow check can be simplified.
Scheme_Object *ADD_tagged(
Scheme_Object *tagged_a,
Scheme_Object *tagged_b)
{
intptr_t a = ((intptr_t)tagged_a)>>1;
intptr_t b = ((intptr_t)tagged_b)>>1;
intptr_t r;
Scheme_Object *o;
r = (uintptr_t)a + (uintptr_t)b;
o = (Scheme_Object *) ((((uintptr_t)r)<<1)|1);
r = ((intptr_t )o) >> 1;
if (b == (uintptr_t)r - (uintptr_t)a)
return o;
else
return ADD_slow (a , b) ;
}
tagged_a and tagged_b are converted from 63-bit signed integers
to 64-bit signed by the arithmetic right shift,
which also gets rid of the tag lsb.
The add gives a 64-bit signed result, and you want to check if
it can be sign-contracted back to 63 bits,
which is a test if bits r[63] == r[62], which is an XOR.
intptr_t a = ((intptr_t)tagged_a)>>1;
intptr_t b = ((intptr_t)tagged_b)>>1;
intptr_t r, tmp;
r = a + b;
tmp = r << 1;
if ((r ^ tmp) >= 0) // check if bit r[63] == r[62]
return tmp | 1;
else
Add_slow (a, b);
[toc] | [prev] | [next] | [standalone]
| From | anton@mips.complang.tuwien.ac.at (Anton Ertl) |
|---|---|
| Date | 2026-09-09 13:36 +0000 |
| Message-ID | <2026Sep9.153651@mips.complang.tuwien.ac.at> |
| In reply to | #117771 |
EricP <ThatWouldBeTelling@thevillage.com> writes:
>> anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
>>> https://www.complang.tuwien.ac.at/anton/tmp/carry.pdf
>>>
>>> (unpublished).
>
>Looking at example 3 I think the overflow check can be simplified.
>
>Scheme_Object *ADD_tagged(
> Scheme_Object *tagged_a,
> Scheme_Object *tagged_b)
>{
> intptr_t a = ((intptr_t)tagged_a)>>1;
> intptr_t b = ((intptr_t)tagged_b)>>1;
> intptr_t r;
> Scheme_Object *o;
> r = (uintptr_t)a + (uintptr_t)b;
> o = (Scheme_Object *) ((((uintptr_t)r)<<1)|1);
> r = ((intptr_t )o) >> 1;
> if (b == (uintptr_t)r - (uintptr_t)a)
> return o;
> else
> return ADD_slow (a , b) ;
>}
This code in the upper part of Figure 3 is not from me, but from the
Racket 8.6 source code, and footnote 5 explains the following:
|The shown code is derived from the original ADD function by putting
|the untagging at the callee rather than the caller side, expanding the
|macros, and simplifying the resulting code. The C and assembler code
|for the lower part can also be found at
|https://godbolt.org/z/TroqhsrrM
So one can imagine why the Racket 8.6 implementors have not made the
optimization that you suggest, nor the optimization that I suggest.
Also, for Racket 8.6 this was only part of the legacy BC (bytecode)
implementation, with their native-code compiler being where the action
was, but I guess that this missed optimization existed before the
native-code compiler was added (and who knows how this case is handled
there; I did not find it).
>tagged_a and tagged_b are converted from 63-bit signed integers
>to 64-bit signed by the arithmetic right shift,
>which also gets rid of the tag lsb.
>
>The add gives a 64-bit signed result, and you want to check if
>it can be sign-contracted back to 63 bits,
>which is a test if bits r[63] == r[62], which is an XOR.
>
> intptr_t a = ((intptr_t)tagged_a)>>1;
> intptr_t b = ((intptr_t)tagged_b)>>1;
> intptr_t r, tmp;
> r = a + b;
> tmp = r << 1;
> if ((r ^ tmp) >= 0) // check if bit r[63] == r[62]
> return tmp | 1;
> else
> Add_slow (a, b);
Yes, I thought about this optimization, too, but also came up with:
intptr_t a1=(intptr_t) tagged_a;
intptr_t b1=(intptr_t) tagged_b;
intptr_t r ;
if (!__builtin_add_overflow(a1,(b1-1),&r))
return (Scheme_Object *)r;
intptr_t a = ((intptr_t)tagged_a)>>1;
intptr_t b = ((intptr_t)tagged_b)>>1;
return ADD_slow (a , b );
which you see in the lower part of Figure 3.
On AMD64 this compiles to:
leaq -1(%rsi), %rax
addq %rdi, %rax
jo .L8
ret
.L8:
sarq %rsi
sarq %rdi
jmp ADD_slow
I.e., just 4 instructions in the common case (reducible to 3 by
choosing 0 as the tag for small integers).
It's interesting to think about what it would take to enable an
optimizer to optimize the former, or the original Racket code, into
the assembly code above, or what would come out of your code. I guess
that if the BC run-time of Racket were part of the next SPEC CPU
suite, and a Scheme program with lots of small additions in the
reference input, we would see:-).
- anton
--
'Anyone trying for "industrial quality" ISA should avoid undefined behavior.'
Mitch Alsup, <c17fcd89-f024-40e7-a594-88a85ac10d20o@googlegroups.com>
[toc] | [prev] | [next] | [standalone]
| From | anton@mips.complang.tuwien.ac.at (Anton Ertl) |
|---|---|
| Date | 2026-09-09 10:50 +0000 |
| Message-ID | <2026Sep9.125039@mips.complang.tuwien.ac.at> |
| In reply to | #117720 |
Kragen Javier Sitaker <kragen@canonical.org> writes:
>anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
>> RISC-V follows its ancestor MIPS (from where it also has many
>> mnemonics) in this respect. For a new way to add the carry
>> functionality without adding a condition code register, read
>>
>> https://www.complang.tuwien.ac.at/anton/tmp/carry.pdf
>>
>> (unpublished).
>
>This is a fascinating idea. I guess the MuP21 had a carry bit in every
>"general-purpose register", making them 21 bits,
<https://www.ultratechnology.com/mup21.html> says this:
|Internally, MuP21 maintains a 21 bit data/address bus. The MSB bit 20
|is the carry bit in ALU operations.
And it mentions an instruction JCZ without explaining it, but given
that it also has JZ, and the existance of C0 below, I expect that JCZ
is "jump if carry is zero", while JZ corresponds to T0 (jump if T0-T19
is false).
That's pretty much it. I see on
https://www.ultratechnology.com/f21data.pdf that instruction 03,
called C0 jumps if T20 (bit 20 of the TOS) is false, and that the
Forth source would look like "CARRY? IF". F21 is a further
development of uP21.
<https://www.ultratechnology.com/mup21.html> has the instruction JCZ
>Thank you for sharing your draft!
I should finally polish it up with all the parts I left away thanks to
page limits and publish it on arxiv.
- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: https://forth-standard.org/
EuroForth 2026 CFP: http://www.euroforth.org/ef26/cfp.html
[toc] | [prev] | [next] | [standalone]
| From | Paul Rubin <no.email@nospam.invalid> |
|---|---|
| Date | 2026-09-09 22:10 -0700 |
| Message-ID | <87ld99k7xu.fsf@nightsong.com> |
| In reply to | #117904 |
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes: > I should finally polish it up with all the parts I left away thanks to > page limits and publish it on arxiv. I remember we had a discussion of this idea here on clf, some of which spilled to comp.arch. I don't know if it contained anything that would be useful in your paper that's not already in it.
[toc] | [prev] | [next] | [standalone]
| From | Kragen Javier Sitaker <kragen@canonical.org> |
|---|---|
| Date | 2026-09-11 14:28 -0300 |
| Message-ID | <874ifvd7fd.fsf@debian> |
| In reply to | #117904 |
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes: > Kragen Javier Sitaker <kragen@canonical.org> writes: >>Thank you for sharing your draft! > > I should finally polish it up with all the parts I left away thanks to > page limits and publish it on arxiv. I agree wholeheartedly. Kragen
[toc] | [prev] | [standalone]
Back to top | Article view | comp.arch
csiph-web