www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 13957] New: 64 bit C ABI not followed for passing structs

https://issues.dlang.org/show_bug.cgi?id=13957

          Issue ID: 13957
           Summary: 64 bit C ABI not followed for passing structs with
                    floating+integer types
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Keywords: wrong-code
          Severity: critical
          Priority: P1
         Component: DMD
          Assignee: nobody puremagic.com
          Reporter: yebblies gmail.com

I tried, but I can't work out how to fix this.  argtypes.c explicitly ruins
passing of this type of struct by passing by memory if one but not both types
are floating, but disabling that leads to more problems.

There is a bunch of code in elstruct that tries to combine structs into
TYcdouble or TYucent, which obviously results in invalid register allocation
when trying to pass one of these structs.

Disabling that leads to loaddata calling cdrelconst, which somehow manages to
load the double value below correctly then load the address of the struct into
rdx instead of ulong member.

========================================================

import core.stdc.stdarg;

struct S69 {
    double val_0;
    ulong val_1;
}

extern(C++) void cppvararg(char arg0, real arg1, char arg2, S69 arg3, double
arg4, int arg5, char arg6);
extern(C++) void dvararg(char arg0, real arg1, char arg2, S69 arg3, double
arg4, int arg5, char arg6)
{
    checkValues(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
}

extern(C++) void checkValues(char arg0, real arg1, char arg2, S69 arg3, double
arg4, int arg5, char arg6)
{
    import core.stdc.stdio;
    printf("%d\n", arg0);
    printf("%Lf\n", arg1);
    printf("%d\n", arg2);
    printf("%f\n", arg3.val_0);
    printf("%lu\n", arg3.val_1);
    printf("%f\n", arg4);
    printf("%d\n", arg5);
    printf("%d\n", arg6);
    assert(arg0 == 90);
    assert(arg1 == 2);
    assert(arg2 == 91);
    assert(arg3 == S69(4, 92));
    assert(arg4 == 8);
    assert(arg5 == 93);
    assert(arg6 == 94);
}

extern(C++) void cppcall();

void main()
{
    char arg0 = 90;
    real arg1 = 2;
    char arg2 = 91;
    S69 arg3 = S69(4, 92);
    double arg4 = 8;
    int arg5 = 93;
    char arg6 = 94;
    // dvararg(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
    cppvararg(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
    // cppcall();
}

==============================================================

#include <stdarg.h>
#include <stdio.h>

struct S69 {
    double val_0;
    unsigned long val_1;
};

void checkValues(char arg0, long double arg1, char arg2, S69 arg3, double arg4,
int arg5, char arg6);
void cppvararg(char arg0, long double arg1, char arg2, S69 arg3, double arg4,
int arg5, char arg6)
{
    printf("%d\n", arg0);
    printf("%Lf\n", arg1);
    printf("%d\n", arg2);
    printf("%f\n", arg3.val_0);
    printf("%lu\n", arg3.val_1);
    printf("%f\n", arg4);
    printf("%d\n", arg5);
    printf("%d\n", arg6);
    checkValues(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
}

void cppcall()
{
    char arg0 = 90;
    long double arg1 = 2;
    char arg2 = 91;
    S69 arg3 = {4, 92};
    double arg4 = 8;
    int arg5 = 93;
    char arg6 = 94;
    // dvararg(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
    cppvararg(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
}

--
Jan 09 2015