Surprisingly, I was looking for a version that identifies if the target arch is 64bit, and there's no such thing!
I need to know if the target has 64bit registers and can perform 64bit arithmetic. It's surprising there's nothing that identifies this.
Please add a new predefined version.
Comment #1 by dkorpel — 2024-02-26T17:56:56Z
The usual check for this is `static if (size_t.sizeof == 8)`.
Comment #2 by turkeyman — 2024-02-26T19:16:58Z
That would tell you if you have 64bit address space. Not the same thing.
Comment #3 by dkorpel — 2024-02-27T11:59:36Z
It usually is, so people tend to use it that way. Are you programming for the Nintendo 64 perhaps? :)
I'm looking how other languages check for 64-bit registers, and in C, it seems like people also query sizes of pointer / integer types, or query a specific ISA (like x86-64): https://stackoverflow.com/a/33867847/8411666
So without precedence, the name could be something like 'D_64bitRegister' or 'D_64bitArithmetic'. But what do you want to do with this information exactly? Is this to provide your own alternative 64-bit emulation when there's no 'native' 64-bit math?
Because that could be tricky: consider WebAssembly without wasm64. It has 32-bit pointers and 64-bit math instructions, but it's not an actual processor architecture: the speed depends on the execution environment, so would 'D_64bitRegister' be set in that case?
Comment #4 by turkeyman — 2024-02-27T12:38:59Z
> It usually is, so people tend to use it that way.
But it's not actually the same thing, and people using it that way have likely written a bug...
> Are you programming for the Nintendo 64 perhaps? :)
I do have a lifetime of experience writing software for such 64bit systems with 32bit pointers. They are a real thing that exists.
> [...] or query a specific ISA [...]
Yes, in C++ we wrangle this information ourselves from whatever material the compiler makes available to determine the facts. Everyone has such a global header file that does this wrangling. I'm specifically looking to avoid that here.
> Is this to provide your own alternative 64-bit emulation when there's no 'native' 64-bit math?
Exactly; if there are no 64bit registers, it can be the case that some alternative algorithm is superior. There do exist algorithms that only work efficiently with 64bits.
> [...] consider WebAssembly without wasm64 [...] would 'D_64bitRegister' be set in that case?
Maybe not define it for webasm since 32bit machines can run web browsers too. I mean, you're running in a web browser; your concern about maximising architectural perf is already forfeit.
It's difficult to imagine a case where this could be used where it's a compatibility issue; it's basically for optimisation opportunities, and nothing else.
Comment #5 by dkorpel — 2024-02-27T13:19:07Z
> It's difficult to imagine a case where this could be used where it's a compatibility issue; it's basically for optimisation opportunities, and nothing else.
Since versions are usually about compatibility (i.e. `version(HasFeatureX) useFeatureX()`), perhaps it would be better to define a 'fast int' type in druntime, somewhat similar to C's `int_fast32_t` or `intmax_t`, but one that represents the largest integer type with native math instructions (excluding SIMD). That would also generalize better to 16 and 128 bit. Would that work?
Comment #6 by turkeyman — 2024-02-27T15:00:33Z
I think that's over-complicating it. Version is fine.
Comment #7 by bugzilla — 2024-03-26T04:46:02Z
https://dlang.org/spec/version.html
Says:
```
D_LP64 Pointers are 64 bits (command line switch -m64). (Do not confuse this with C's LP64 model)
D_X32 Pointers are 32 bits, but words are still 64 bits (x32 ABI) (This can be defined in parallel to X86_64)
```
What the implementation actually does is:
```
if (tgt.isX86_64)
{
VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86_64");
VersionCondition.addPredefinedGlobalIdent("X86_64");
}
else
{
VersionCondition.addPredefinedGlobalIdent("D_InlineAsm"); //legacy
VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86");
VersionCondition.addPredefinedGlobalIdent("X86");
}
if (tgt.isLP64)
VersionCondition.addPredefinedGlobalIdent("D_LP64");
else if (tgt.isX86_64)
VersionCondition.addPredefinedGlobalIdent("X32");
```
Note how something simple turned into a monstrosity that nobody can figure out, and the documentation is both wrong and incomplete. Sigh.
I suspect that the undocumented X32 is what Manu is looking for, but dmd never generates it. Does gdc or ldc?
Comment #8 by ibuclaw — 2024-03-26T14:36:55Z
(In reply to Dennis from comment #1)
> The usual check for this is `static if (size_t.sizeof == 8)`.
`version(D_LP64)` would be a better alternative to that.
Comment #9 by ibuclaw — 2024-03-26T15:06:52Z
(In reply to Walter Bright from comment #7)
> https://dlang.org/spec/version.html
>
> Says:
>
> ```
> D_LP64 Pointers are 64 bits (command line switch -m64). (Do not confuse
> this with C's LP64 model)
> D_X32 Pointers are 32 bits, but words are still 64 bits (x32 ABI) (This
> can be defined in parallel to X86_64)
> ```
Introduced by https://github.com/dlang/dlang.org/pull/175
As one comment pointed out:
"""
X32 is a specific implementation for x86-64 hardware, but the description refers to an abstract concept
"""
Adding "x32 ABI" was the compromise, but I don't think it's explicit enough.
Pick any wiki, and the description is better:
"""
X32 is an alternative ABI for x86-64 that uses the full 64-bit x86-64 instruction and register set and 32-bit pointers and longs.
"""
https://sourceware.org/glibc/wiki/x32
"""
The x32 ABI provides 32-bit integers, long and pointers (ILP32) on Intel and AMD 64-bit hardware
"""
https://en.wikipedia.org/wiki/X32_ABI
> Note how something simple turned into a monstrosity that nobody can figure
> out, and the documentation is both wrong and incomplete. Sigh.
>
> I suspect that the undocumented X32 is what Manu is looking for, but dmd
> never generates it. Does gdc or ldc?
That is a typo in dmd, introduced by https://github.com/dlang/dmd/pull/12508
D_X32 is predefined by gdc on X32 targets, itself is now a deprecated ABI of X86_64. I had and still have doubts that DMD would support such a `-target` anyway.
A more informative version identifier for it would have been X86_64_X32, but this was added at a time where brevity was preferred over clarity for some reason. Which also left in the spec D_AVX and D_AVX2 (yuck!) instead of X86_64_AVX and X86_64_AVX2.
Comment #10 by ibuclaw — 2024-03-26T15:14:22Z
(In reply to Manu from comment #2)
> That would tell you if you have 64bit address space. Not the same thing.
```
import gcc.builtins : ___builtin_machine_int;
static if (__builtin_machine_int.sizeof == 8):
```
This issue is strictly about the arch, and pointer width/ABI matters is explicitly NOT what this request is about.
The thing Iain shows:
```
import gcc.builtins : ___builtin_machine_int;
static if (__builtin_machine_int.sizeof == 8):
```
This is what should be expressed by a standard version token present for all compilers/architectures.
On the tangent regarding X32; it is deprecated for linux, but cross compilers will need to express this concept for all time.
For my money, D_X32 should continue to exist, and the spec adjusted to require this constant for all targets where 32bit pointers are used on a 64bit arch, which would include the X32 ABI for X86, but also similar ABI's for other architectures too.
It's not strictly necessary, because we can test size_t.sizeof, but since it's already there and removing it would be a breaking change, the spec could be slightly adjusted to make it generally useful.
Comment #13 by robert.schadek — 2024-12-13T19:33:27Z