128 bit integers is on topic

D

Dik T. Winter

> And while I'm not sure who has
> the most inflated currency at the moment, a favorite example (before
> it was devalued) used to be the Turkish Lira - where you could not
> represent the GDP of the United States (in TRY) in a 64 bit integer,

Yes, I still remember giving a 10 million Lira gratuity after a lunch with
four people. Currently, however, it is Zimbabwe, but they regularly
devalue. Of all times it is Hungary in around 1946. I have a banknote of
1,000,000,000,000,000,000 pengö. (The largest Zimbabwe banknote I have is
of 100,000,000,000 Dollars, they have still a long way to go, but of
course, they devalued in 2007.)
 
K

Keith Thompson

Richard Heathfield said:
I don't agree that the implementation has such power of veto over the
machine, and I'd be interested to see your C&V.

It's not power over the machine, it's the implementation's power over
itself.

C99 6.10.2p2:

A preprocessing directive of the form
# include <h-char-sequence> new-line
searches a sequence of implementation-defined places for a header
identified uniquely by the specified sequence between the < and >
delimiters, and causes the replacement of that directive by the
entire contents of the header. How the places are specified or the
header identified is implementation-defined.

A header, as I'm sure you'll agree, needn't be a file.
An implementation could search for <> headers in a single "place",
which could be a table of headers internal to the compiler. Or it
could just be a single directory, containing actual header files,
that's part of the implementation, with users of the implementation
not permitted to mess with that directory.

Thus an implementation could easily restrict the headers usable
with the <> syntax to a fixed set, consisting of the 24 standard
headers plus zero or more implementation-defined ones.

What part of the standard would such an implementation violate?

The standard neither defines nor implies any mechanism for a
programmer to create a header other than a header file, and does not
require #include <...> to be able to access headers that are files.

A strictly-conforming program "shall not produce output dependent
on any unspecified, undefined, or implementation-defined behavior"
(C99 4p5). Surely a program that contains the line

#include <myheader.h>

depends on the implementation-defined behavior of that directive.

From which I conclude that no strictly conforming program may contain
the line

#include <int128.h>

and therefore that a conforming implementation may define such a
header for its own purposes.

The alternative would require all conforming extensions to use
only identifiers in the implementation's namespace. Furthermore,
since there are no reserved header names other than the 24 standard
ones, no conforming implementation would be able to provide *any*
additional headers, since they would all intrude on the programmer's
namespace.
That's common convention and good practice, but I'm not convinced that
it's legislated.

Not directly, but I think the standard does imply, in effect, that
the standard can do what it likes with the #include <...> namespace;
since it's permitted to define what <...> means, it can define it
to refer to a place or places over which it has complete control.
 
K

Keith Thompson

Old Wolf said:
Huh? Whether or not gcc supports something,
has absolutely no relevance to its topicality.

I think that was jacob trying to be sarcastic.
 
N

Noob

jacob said:
I found that the SSE registers couldn't do integer operations since they
somehow are thought as holding double or floats

Huh??

"""
4.6.2 128-Bit Packed SIMD Data Types

The 128-bit packed SIMD data types were introduced into the IA-32 architecture
in the SSE extensions and used with SSE2, SSE3 and SSSE3 extensions. They are
operated on primarily in the 128-bit XMM registers and memory. The fundamental
128-bit packed data types are packed bytes, packed words, packed doublewords,
and packed quadwords (see Figure 4-8). When performing SIMD operations on these
fundamental data types in XMM registers, these data types are interpreted as
containing packed or scalar single-precision floating-point or double-precision
floating-point values, or as containing packed byte, word, doubleword, or
quadword integer values.
"""

11.4.2 SSE2 64-Bit and 128-Bit SIMD Integer Instructions

e.g. PADDQ

http://en.wikipedia.org/wiki/X86_instruction_listings#SSE2_SIMD_Integer_Instructions

comp.lang.asm.x86 is a better place to discuss x86 and AMD64 programming.
 
B

BGB / cr88192

jacob navia said:
BGB / cr88192 a écrit :


I use RDX:RAX register pair. I found that the SSE registers couldn't do
integer operations (even in 64 Bit only) since they somehow are thought
as holding double or floats

How do you use the SSE stuff?


there are some operations for SSE registers (SSE2 and later) which can do
integer operations.

but, for many operations, the SSE regs are used more as a way of shuffling
things around, with many of the actual operations falling back to the use of
memory and/or integer instructions.


I don't use RDX:RAX for a few reasons:
it would not be very friendly to my register allocator;
this pair would only only handle a single 128-bit register (and only on
x86-64);
....


so, in general, for my uses it is more convinient to use SSE registers and
make my codegen "pretend" that it has a full set of 128-bit integer
operations on the CPU.
 
S

Seebs

No, it doesn't say that. Read again

"The inclusion of any extension that may cause a strictly conforming program
to become invalid renders an implementation nonconforming."

The question, I guess, is whether the extension in question may cause a
strictly conforming program to become invalid.

As I recall, the extension under discussion was the inclusion of a new
type, "int128".

The C standard says (7.26) "all external names described below are reserved no
matter what headers are included by the program", and under 7.26.8 (stdint.h)
describes "typedef names beginning with int or uint and ending with _t".

However, the name "int128" is not covered by this reservation of future
namespace. As a result, a strictly-conforming program may use the name
"int128" for any purpose, whether as a typedef, a struct tag, or as a
variable name, and if a compiler were to do something else with that name,
that would indeed render the implementation nonconforming, if it does so
without the use of some feature (such as a system header not in the standard
list) which prevents it from affecting strictly-conforming programs.

-s
 
J

jacob navia

Mark McIntyre a écrit :
You mean the one titled "Common Extensions"? And which goes on to stress
that the material therein causes an implementation to be nonconforming?

No, it doesn't say that. Read again
 
K

Keith Thompson

Seebs said:
"The inclusion of any extension that may cause a strictly conforming program
to become invalid renders an implementation nonconforming."

The question, I guess, is whether the extension in question may cause a
strictly conforming program to become invalid.

As I recall, the extension under discussion was the inclusion of a new
type, "int128".

The C standard says (7.26) "all external names described below are
reserved no matter what headers are included by the program", and
under 7.26.8 (stdint.h) describes "typedef names beginning with int
or uint and ending with _t".

However, the name "int128" is not covered by this reservation of
future namespace. As a result, a strictly-conforming program may
use the name "int128" for any purpose, whether as a typedef, a
struct tag, or as a variable name, and if a compiler were to do
something else with that name, that would indeed render the
implementation nonconforming, if it does so without the use of some
feature (such as a system header not in the standard list) which
prevents it from affecting strictly-conforming programs.

I *think* that lcc-win's int128 becomes visible only with a #include
<int128.h>, or something similar. If so, then it (probably) doesn't
break any strictly conforming programs or cause lcc-win to be
nonconforming.
 
J

jacob navia

Seebs a écrit :
"The inclusion of any extension that may cause a strictly conforming program
to become invalid renders an implementation nonconforming."

The question, I guess, is whether the extension in question may cause a
strictly conforming program to become invalid.

As I recall, the extension under discussion was the inclusion of a new
type, "int128".

The C standard says (7.26) "all external names described below are reserved no
matter what headers are included by the program", and under 7.26.8 (stdint.h)
describes "typedef names beginning with int or uint and ending with _t".

However, the name "int128" is not covered by this reservation of future
namespace. As a result, a strictly-conforming program may use the name
"int128" for any purpose, whether as a typedef, a struct tag, or as a
variable name, and if a compiler were to do something else with that name,
that would indeed render the implementation nonconforming, if it does so
without the use of some feature (such as a system header not in the standard
list) which prevents it from affecting strictly-conforming programs.

-s

To use the type int128 in your programs you have to include "int128.h"
what is not in the list of standard headers.

So, my implementation is conforming. All this polemic has no sense.
 
K

Keith Thompson

jacob navia said:
To use the type int128 in your programs you have to include "int128.h"
what is not in the list of standard headers.

So, my implementation is conforming. All this polemic has no sense.

Your implementation may well be conforming, but the fact that you
have to include "int128.h" (or <int128.h>) to use int128 doesn't
prove it; it could still be non-conforming for other reasons.
I haven't seen enough information to know one way or the other
(and I'm not currently able to install lcc-win to find out).

I don't mean to imply that it's non-conforming, merely that I
don't know.

Is the documentation for this extension available somewhere without
installing lcc-win?

Do you provide both signed and unsigned 128-bit types? Are all the
operations available for predefined types available for the 128-bit
types? Do you have a syntax for literals? Formats for *printf
and *scanf? Are the 128-bit types accounted for in <stdint.h>?
Do you have int128_t and uint128_t typedefs? Are intmax_t and
uintmax_t 128 bits?

Are they implemented as "extended integer types", as described in
the standard? If not, do you plan to work in that direction?

Note that your implementation could still be conforming even if
the answers to all the above questions are no. But if you were to
implement your 128-bit types within the framework already defined
by the C99 standard, rather than as an implementation-specific
extension, you could set a valuable precedent.
 
S

Seebs

To use the type int128 in your programs you have to include "int128.h"
what is not in the list of standard headers.
Okay.

So, my implementation is conforming. All this polemic has no sense.

Agreed that, at least in this respect, it is conforming.

However.

It is pretty stupid to use a name other than "int128_t" for that
type. The types have consistent names for a reason; using an inconsistent
name makes life harder for your users.

-s
 
S

Seebs

If the 128-bit type is int128_t I think the implementation must
include it the term "integer types" and so intmax_t must be this type
(or wider).

I'd say that's a quality of implementation issue; I don't see any reason
to prohibit implementations from having types which hold values which can
be transparently converted to and from integral type, but which are in fact
not integral types according to the implementation's list of supported
integral types. :)
I may be wrong in the premise (it comes from a quick search of the
standard) and there may be no requirement for intmax_t to encompass
int128_t if it exists, but this is the place to find out.

I don't think the name changes whether or not the type is an integral
type. If there IS a 128-bit integral type, defined in <stdint.h>, then
it should be int128_t and so on... But I don't see anything prohibiting
you from having something that isn't quite a fully implemented 128-bit
integral type, and naming it int128_t, as long as it's in some non-standard
header.

All the stuff about intmax_t, etcetera, applies only as long as programs
are conforming... And in practice, IMHO, the quality of implementation issue
is such that a developer doesn't care if you call it i_love_my_cat_t, if it
looks and acts like a 128-bit integer, intmax_t should be at least 128 bits,
and the preprocessor should handle it. :)

-s
 
B

Ben Bacarisse

Seebs said:
Agreed that, at least in this respect, it is conforming.

However.

It is pretty stupid to use a name other than "int128_t" for that
type. The types have consistent names for a reason; using an inconsistent
name makes life harder for your users.

I think, on balance, that I agree, but I can see a reason for another
form of name.

If the 128-bit type is int128_t I think the implementation must
include it the term "integer types" and so intmax_t must be this type
(or wider). This means that the pre-processor must have the potential
to do its arithmetic in this type (indeed it must act as if it does)
and that intmax_t itself will be more costly than some programmers
might expect. In other words I can see some justification for
excluding this type from the "normal" set.

I may be wrong in the premise (it comes from a quick search of the
standard) and there may be no requirement for intmax_t to encompass
int128_t if it exists, but this is the place to find out.
 
J

jacob navia

Ben Bacarisse a écrit :
I think, on balance, that I agree, but I can see a reason for another
form of name.

If the 128-bit type is int128_t I think the implementation must
include it the term "integer types" and so intmax_t must be this type
(or wider). This means that the pre-processor must have the potential
to do its arithmetic in this type (indeed it must act as if it does)
and that intmax_t itself will be more costly than some programmers
might expect. In other words I can see some justification for
excluding this type from the "normal" set.

I may be wrong in the premise (it comes from a quick search of the
standard) and there may be no requirement for intmax_t to encompass
int128_t if it exists, but this is the place to find out.

I have to gather more experience with this type since there are some
unresolved issues:

printf format?
scanf format?
Other issues (like the one you mention)
I have to implement the unsigned types, etc.

I will do the integration first in the 64 bit version of
lcc-win. In that version they are supported "natively"
(without operator overloading).
 
B

BGB / cr88192

jacob navia said:
Ben Bacarisse a écrit :

I have to gather more experience with this type since there are some
unresolved issues:

printf format?
scanf format?
Other issues (like the one you mention)
I have to implement the unsigned types, etc.


yeah, printf format and scanf format are a problem in my case as well.

in my case, I have not addressed them, since I don't implement my own C
runtime, and instead have typically depended on certain external libs (such
as MSVCRT, ...).


the cost then, is that printf does not support 128-bit ints, or even 64-bit
ints in a "standard" way.


however, providing ones' own C runtime creates a big mess of potential
issues, such as memory from 'malloc', open files, ... not necessarily
working if passed to/from code not compiled with said compiler, ...


as well as possible issues in static-land.

one idea:
I could use a different naming convention (known specifically to my
framework), to patch parts of the runtime, and then at runtime my framework
could detect and use these patched functions (without so much conflict with
the real standard library, and without having to replace the whole thing).

this could also allow statically-compiled code to choose to use either
library.

for example:
BSRT__printf
BSRT__sscanf
BSRT__cabs
....

I will do the integration first in the 64 bit version of
lcc-win. In that version they are supported "natively"
(without operator overloading).


in my compiler, they are supported natively in both 32 and 64 bit mode.

however, there is remaining issue with their integration with code outside
of my compiler.

I am just left with the thought that they "should" now pass on Win64, for
example, because I pass them the same as other SSE types, which is the same
as how MSVC on x64 apparently passes both SIMD types and struct types: by
reference...

in 32-bit mode, I pass them on the stack, and will have to verify that this
is correct in 32-bit mode as well...


originally, I passed them directly on the stack in Win64, but then
discovered that this was apparently incorrect, and these issues have been
internally addressed via kludges (something I call "vrefs" or "virtual
references", which are like a C++ references, only added silently by the
compiler to gloss over the calling convention...).
 
J

jacob navia

BGB / cr88192 a écrit :
yeah, printf format and scanf format are a problem in my case as well.

in my case, I have not addressed them, since I don't implement my own C
runtime, and instead have typically depended on certain external libs (such
as MSVCRT, ...).
the cost then, is that printf does not support 128-bit ints, or even 64-bit
ints in a "standard" way.

That's why I was forced to rewrite printf.
however, providing ones' own C runtime creates a big mess of potential
issues, such as memory from 'malloc', open files, ... not necessarily
working if passed to/from code not compiled with said compiler, ...

Sure, writing the runtime is a big mess. It is very difficult to do.
as well as possible issues in static-land.

one idea:
I could use a different naming convention (known specifically to my
framework), to patch parts of the runtime, and then at runtime my framework
could detect and use these patched functions (without so much conflict with
the real standard library, and without having to replace the whole thing).

Very easy. You need just to change the linker, and put your static
library before the import library of crtdll.dll Then you rewrite only
the functions you need to replace.
this could also allow statically-compiled code to choose to use either
library.

for example:
BSRT__printf
BSRT__sscanf
BSRT__cabs
...




in my compiler, they are supported natively in both 32 and 64 bit mode.

Well, in 32 bits you have to generate a function call anyway, so it doesn't
make any difference. In 64 bits there are no function calls and the
code can be generated directly.

[snip]
originally, I passed them directly on the stack in Win64, but then
discovered that this was apparently incorrect, and these issues have been
internally addressed via kludges (something I call "vrefs" or "virtual
references", which are like a C++ references, only added silently by the
compiler to gloss over the calling convention...).

Well, this is easy... You just copy the object in the stack and pass
a pointer to that stack area in some register. Note that you should copy
since C passes by value!


struct foo {int a,b,c,d;};
struct foo Foo;

void fn(struct foo f);

fn(Foo);

Here fn should work with a COPY of the structure Foo.
 
J

James Kuyper

Ben Bacarisse wrote:
....
If the 128-bit type is int128_t I think the implementation must
include it the term "integer types" and so intmax_t must be this type
(or wider). This means that the pre-processor must have the potential
to do its arithmetic in this type (indeed it must act as if it does)
and that intmax_t itself will be more costly than some programmers
might expect. In other words I can see some justification for
excluding this type from the "normal" set.

Wanting to escape from having to meet that requirement pretty much
completely ignores the purpose of intmax_t (or at least, embodies the
apparent belief that this purpose should not be achieved).
 
K

Keith Thompson

jacob navia said:
I have to gather more experience with this type since there are some
unresolved issues:

printf format?
scanf format?
Other issues (like the one you mention)
I have to implement the unsigned types, etc.

I will do the integration first in the 64 bit version of
lcc-win. In that version they are supported "natively"
(without operator overloading).

So you don't have a 128-bit unsigned type yet?

Ok, given what appears to be the relatively early stage of
development, it's reasonable to postpone integrating the new 128-bit
types into <inttypes.h> and <stdint.h>, and making intmax_t 128 bits.

But if that's your goal, I'd like to encourage you to avoid making
assumptions now that will come back to bite you and your users.
For example, by using the name "int128", you may be encouraging
your users to write non-portable code that depends on that name.
I suggest that one of your goals should be to phase out the
<int128.h> header and the "int128" name.

A reminder: uppercase letters as format specifiers for *printf and
*scanf are reserved for in extensions (C99 7.26.9p1).

And thank you for answering some of the questions I asked elsethread,
even if you couldn't bring yourself to respond to them directly.
 
K

Keith Thompson

Seebs said:
It is pretty stupid to use a name other than "int128_t" for that
type. The types have consistent names for a reason; using an inconsistent
name makes life harder for your users.

int128_t should be a typedef, defined in <stdint.h> and <inttypes.h>.
Which implies that there needs to be another name for the typedef
declaration to use, perhaps something like __int128. It would
be stupid^H^H^H^H^H^H unwise to declare the name "int128_t" in,
say, <int128.h>, since it would conflict with the declaration in
<stdint.h> and <inttypes.h>.
 
K

Keith Thompson

Seebs said:
I don't think the name changes whether or not the type is an
integral type. If there IS a 128-bit integral type, defined in
<stdint.h>, then it should be int128_t and so on... But I don't see
anything prohibiting you from having something that isn't quite a
fully implemented 128-bit integral type, and naming it int128_t, as
long as it's in some non-standard header.
[...]

Integer types aren't *defined* in <stdint.h>. Generally they're
defined by the core language or, in the case of extended types, by
the implementation. <stdint.h> merely defines typedefs (aliases)
for existing integer types.

In this case, the compiler could predefine __int128, and
(eventually) <stdint.h> could declare
typedef int128_t __int128;
typedef int_least128_t __int128;
typedef int_fast128_t __int128;
typedef intmax_t __int128;
and likewise for __uint128.

If the type is actually defined as "int128" in <int128.h> (in
some compiler-specific manner, since there's no way in standard C
to define an integer type), then <stdint.h> would need to #include
<int128.h> to make the name visible -- but that would cause problems,
since #include <stdint.h> would then make the identifier "int128"
visible.

The current somewhat ad-hoc implementation appears to be a valid
extension (and, I have to say, of questionable topicality here),
but some aspects may make it more difficult to integrate the feature
more tightly into the language. I'd like to see this kind of thing
done right, and I hope jacob will keep these issues in mind.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
DewittMill
Top