Sujet : Re: Computer architects leaving Intel...
De : kegs (at) *nospam* provalid.com (Kent Dickey)
Groupes : comp.archDate : 14. Sep 2024, 14:08:05
Autres entêtes
Organisation : provalid.com
Message-ID : <vc41rl$1fhjd$1@dont-email.me>
References : 1 2 3 4
User-Agent : trn 4.0-test76 (Apr 2, 2001)
In article <
UxpCO.174965$Hld5.7714@fx15.iad>,
Scott Lurndal <
slp53@pacbell.net> wrote:
Bernd Linsel <bl1-thispartdoesnotbelonghere@gmx.com> writes:
On 05.09.24 19:04, Terje Mathisen wrote:
One of my alternatives are
>
unsigned u = start; // Cannot be less than zero
if (u) {
u++;
do {
u--;
data[u]...
while (u);
}
>
This typically results in effectively the same asm code as the signed
version, except for a bottom JGE (Jump (signed) Greater or Equal instead
of JA (Jump Above or Equal, but my version is far more verbose.
>
Alternatively, if you don't need all N bits of the unsigned type, then
you can subtract and check if the top bit is set in the result:
>
for (unsigned u = start; (u & TOPBIT) == 0; u--)
>
Terje
>
>
What about:
>
for (unsigned u = start; u != ~0u; --u)
>
This is the form we use most when we need
to work in reverse.
>
...
>
or even
>
for (unsigned u = start; (int)u >= 0; --u)
...
>
?
>
I've compared all variants for x86_64 with -O3 -fexpensive-optimizations
on godbolt.org:
- 32 bit version: https://godbolt.org/z/TMhhx3nch
- 64 bit version: https://godbolt.org/z/8oxzTf5Gf
>
>
No significant differences in code generation for unsigned vs. signed.
This discussion wandered into many subthreads, but I only want to make
one post and chose here.
When you write code working on signed numbers and do something like:
(a < 0) || (a >= max)
Then the compiler realizes if you treat 'a' as unsigned, this is just:
(unsigned)a >= max
since any negative number, treated as unsigned, will be larger than the
largest positive signed number. So, to do loops which count down and
have any stride using an unsigned loop count:
for(u = start; u <= start; u -= step)
With the usual caveats (start must be a valid signed number, and step
cannot be so large that start + step crosses the signed boundary).
But: unsigned numbers in C have some dangers, which no one here has
mentioned. Some code presented comes CLOSE to being wrong, but gets
lucky. With "int" being 32-bits, C promotion rules around unsigned
ints, signed ints, and unsigned 64-bit can create trouble.
uint64_t dval; uint32_t uval; int a;
val32 = 1 dval = 1; a = 1;
dval = val32 - 2 + dval;
C will do (val32 - 2) first, with is (1U - 2) which is 0xffff_ffff, and
then add dval, and the result is 0x1_0000_0000.
Signed numbers don't have this risk, so if you're doing known small loops,
you can just use ints. If you're doing possibly large loops, just use
int64_t.
Bringing it back to "architecture" Like Anton Ertl has said, LP64 for
C/C++ is a mistake. It should always have been ILP64, and this nonsense
would go away. Any new architecture should make C ILP64 (looking at you
RISC-V, missing yet another opportunity to not make the same mistakes as
everyone else).
Kent