Comment #0 by simon.vanbernem — 2022-06-18T22:39:20Z
Microsoft states in their C++ x64 calling convention that structs with a maximum size of 8 bytes should be passed by value through registers (POD or not doesn't matter). Dmd gets this wrong, and passes them by reference instead, when calling a function marked with extern(C++) that has non-POD arguments of size 8. The called C++ function will then interpret the pointers in the registers as values and compute nosense.
Ldc doesn't have this bug and does the right thing.
For example, for the following definitions:
void imgui_draw_rectangle(ImVec2 min, ImVec2 max);
struct ImVec2{
float x, y;
~this(){}
}
calling imgui_draw_rectangle will load the addresses of min and max into rdx and rcx, instead of loading their values into rdx and rcx.
(https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#parameter-passing)
Comment #1 by bugzilla — 2022-11-24T02:27:59Z
Compilable example:
struct FF {
float x, y;
~this();
}
void draw(FF min, FF max);
void test(FF *a, FF *b) {
draw(*a, *b);
}
If `~this();` is commented out, the arguments are passed to draw by value.
Comment #2 by dlang-bot — 2022-11-24T02:39:19Z
@WalterBright created dlang/dmd pull request #14651 "fix Issue 23195 - Win64 function ABI bug for small non-POD arguments" fixing this issue:
- fix Issue 23195 - Win64 function ABI bug for small non-POD arguments
https://github.com/dlang/dmd/pull/14651
(In reply to simon.vanbernem from comment #0)
> Microsoft states in their C++ x64 calling convention that structs with a
> maximum size of 8 bytes should be passed by value through registers (POD or
> not doesn't matter).
> [...]
> (https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-
> 170#parameter-passing)
Microsoft's documentation is doesn't match the behavior of their compiler. Having a destructor does not affect whether a struct is passed by ref or not, but having a copy constructor does (contrary to the documentation).
Comment #5 by kinke — 2022-11-24T23:24:30Z
(In reply to Walter Bright from comment #4)
> Microsoft's documentation is doesn't match the behavior of their compiler.
> Having a destructor does not affect whether a struct is passed by ref or
> not, but having a copy constructor does (contrary to the documentation).
That's right. Note that there's another special case for the MSVC++ ABI: POD structs with any ctor are returned via struct-return (the hidden result pointer). https://github.com/ldc-developers/ldc/blob/05fb6d5acaef1a97129317ce8f0dd712e03aee7f/gen/abi/win64.cpp#L59-L80
Comment #6 by dlang-bot — 2023-02-09T07:39:08Z
dlang/dmd pull request #14651 "fix Issue 23195 - Win64 function ABI bug for small non-POD arguments" was merged into master:
- 9a6324fa38859c5ad67592f590234cbb36ccfbb2 by Walter Bright:
fix Issue 23195 - Win64 function ABI bug for small non-POD arguments
https://github.com/dlang/dmd/pull/14651