LDouble toString() always returns 0.00 #445

Open
duckinator opened this Issue Jun 19, 2012 · 19 comments

Comments

Projects
None yet
4 participants
@duckinator
Collaborator

duckinator commented Jun 19, 2012

LDouble toString(), as of 11da703, always returns 0.00

LDouble: cover from long double implements Number {

    toString: func -> String {
        "%.2Lf" format(this)
    }
// <snip>
}

It seems something's funky with "%.2Lf", but I'm not sure what.

@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Jun 19, 2012

Member

abs?

Member

nddrylliog commented Jun 19, 2012

abs?

@duckinator

This comment has been minimized.

Show comment Hide comment
@duckinator

duckinator Jun 19, 2012

Collaborator

Woops. Fixed. Should've been toString()

Collaborator

duckinator commented Jun 19, 2012

Woops. Fixed. Should've been toString()

@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Nov 18, 2012

Member

Confirmed: this is an ooc printf bug, the C printf version works fine:

main: func {

    a: LDouble = 3.234

    "ooc printf" println()

    "%.2Lf" printfln(a)
    "%.2lf" printfln(a)
    "%.2f" printfln(a)

    "C printf" println()

    printf("%.2Lf\n", a)
    printf("%.2lf\n", a)
    printf("%.2f\n", a)

}

displays:

$ rock -r test.ooc
ooc printf
0.00
0.00
-0.00
C printf
3.23
0.00
0.00
Member

nddrylliog commented Nov 18, 2012

Confirmed: this is an ooc printf bug, the C printf version works fine:

main: func {

    a: LDouble = 3.234

    "ooc printf" println()

    "%.2Lf" printfln(a)
    "%.2lf" printfln(a)
    "%.2f" printfln(a)

    "C printf" println()

    printf("%.2Lf\n", a)
    printf("%.2lf\n", a)
    printf("%.2f\n", a)

}

displays:

$ rock -r test.ooc
ooc printf
0.00
0.00
-0.00
C printf
3.23
0.00
0.00
@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Nov 18, 2012

Member

Been debugging this for a while, I think ooc varargs have an issue with larger-than-8 bytes (64 bits) values. That would explain that this debug code:

            if (info@ precision >= 0)
                tmp append("." + info@ precision toString())
            if (info@ longdouble)
                tmp append("L")
            tmp append("f")

            "tmp = %s" printfln(tmp)

            T := va@ getNextType()
            match T {
              case LDouble =>
                ld := argNext(va, LDouble) as LDouble
                printf("ld = %.2Lf\n", ld)
                res append(tmp toString() cformat(ld))
              case Double =>
                res append(tmp toString() cformat(argNext(va, Double) as Double))
              case => // assume everything else is Float
                res append(tmp toString() cformat(argNext(va, Float) as Float))

Outputs this:

tmp = %.2Lf
ld = 2421947388463276794519050671392130485877789785034669850353933964614497513443678967029502567876346724116037405041617137142728457144651841445284156695455634709277306757174026395992538385710908699709913109140639071885141323609256957105898090518496271308408252515089298200656764591620687756183374140345878357987953192487652288930968248053786773288037328456065003225647755777389422018951101929341834830143542645967520033114117385100407631740445656594070303876544327897329738924365321584301108964785520292709288234172931358596681023227244023324770766962157221733705763661869534101838241639594786748269983456517542900180411969617523812929048670012447000989232633716911424693495105439378648762648352050786798857897599976766603738067978671456150031382227848364047945013782586743669152955213422462255912475152682931666034129513891418080922163695224221051797320075140767020174087520235143864778583907126102505834285436036969956947700797622065998790464363851078252236565557666986760158201873884448083940039623072599231724753282404406632374901944958550917525249853453336570736617345868954082445213186835876615875382435275209469709908417445766538183003226348812463327403320731587701602107684074780353728833743387604950084848389293068866466009876176012921628585417029198275782175830478923312409586662298219473980735113932042614682390261129234112912809257764315472541968804706455067996220653242318639998129160160244558273972399514220206672664000929479765243650602421396073663215509721146748175307450764454244661870479959086803330300984666436155186185248797887989199086348742943774066123095828985689503956654929491665483640024341525440223317290489504565432550258475333028424787657900635255628981308246203017931268489064372749115707103759619693986385150950533311100760689338232005878463018314900692772387750519317316191300961722485277726263977379599309424600331498009560659368343129982555585225797083347498820232715635689300908739959517845595268106093031933501674012581893186923386563856601715922835130991599501720281012935181368333138219736313177178326485838538803871899175898949547938367855774906802252055470910751196335532950408978563840606964827258471353996781090283810621974023208727485663181406302048854905204763818330309325022483814543210145713061563353242092365832427043032073739531637265710734331004256803048080345148359494175210300790883684063791591390788100426336305476506032828321409934637376956903292153842571258438373286784248896289676242667060850338037760.00

..because I think what we're seeing here as an LDouble is not in fact [LDouble lower 8 bytes][LDouble upper 8 bytes] but rather [LDouble lower 8 bytes][garbage / next Class info]

Member

nddrylliog commented Nov 18, 2012

Been debugging this for a while, I think ooc varargs have an issue with larger-than-8 bytes (64 bits) values. That would explain that this debug code:

            if (info@ precision >= 0)
                tmp append("." + info@ precision toString())
            if (info@ longdouble)
                tmp append("L")
            tmp append("f")

            "tmp = %s" printfln(tmp)

            T := va@ getNextType()
            match T {
              case LDouble =>
                ld := argNext(va, LDouble) as LDouble
                printf("ld = %.2Lf\n", ld)
                res append(tmp toString() cformat(ld))
              case Double =>
                res append(tmp toString() cformat(argNext(va, Double) as Double))
              case => // assume everything else is Float
                res append(tmp toString() cformat(argNext(va, Float) as Float))

Outputs this:

tmp = %.2Lf
ld = 2421947388463276794519050671392130485877789785034669850353933964614497513443678967029502567876346724116037405041617137142728457144651841445284156695455634709277306757174026395992538385710908699709913109140639071885141323609256957105898090518496271308408252515089298200656764591620687756183374140345878357987953192487652288930968248053786773288037328456065003225647755777389422018951101929341834830143542645967520033114117385100407631740445656594070303876544327897329738924365321584301108964785520292709288234172931358596681023227244023324770766962157221733705763661869534101838241639594786748269983456517542900180411969617523812929048670012447000989232633716911424693495105439378648762648352050786798857897599976766603738067978671456150031382227848364047945013782586743669152955213422462255912475152682931666034129513891418080922163695224221051797320075140767020174087520235143864778583907126102505834285436036969956947700797622065998790464363851078252236565557666986760158201873884448083940039623072599231724753282404406632374901944958550917525249853453336570736617345868954082445213186835876615875382435275209469709908417445766538183003226348812463327403320731587701602107684074780353728833743387604950084848389293068866466009876176012921628585417029198275782175830478923312409586662298219473980735113932042614682390261129234112912809257764315472541968804706455067996220653242318639998129160160244558273972399514220206672664000929479765243650602421396073663215509721146748175307450764454244661870479959086803330300984666436155186185248797887989199086348742943774066123095828985689503956654929491665483640024341525440223317290489504565432550258475333028424787657900635255628981308246203017931268489064372749115707103759619693986385150950533311100760689338232005878463018314900692772387750519317316191300961722485277726263977379599309424600331498009560659368343129982555585225797083347498820232715635689300908739959517845595268106093031933501674012581893186923386563856601715922835130991599501720281012935181368333138219736313177178326485838538803871899175898949547938367855774906802252055470910751196335532950408978563840606964827258471353996781090283810621974023208727485663181406302048854905204763818330309325022483814543210145713061563353242092365832427043032073739531637265710734331004256803048080345148359494175210300790883684063791591390788100426336305476506032828321409934637376956903292153842571258438373286784248896289676242667060850338037760.00

..because I think what we're seeing here as an LDouble is not in fact [LDouble lower 8 bytes][LDouble upper 8 bytes] but rather [LDouble lower 8 bytes][garbage / next Class info]

@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Nov 18, 2012

Member

After a few more tests, it seems that even the lower 16 bytes (my bad) are not even preserved. More tests coming up.

Member

nddrylliog commented Nov 18, 2012

After a few more tests, it seems that even the lower 16 bytes (my bad) are not even preserved. More tests coming up.

@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Nov 18, 2012

Member

Here's one of my favorite (that's on rock 0.9.4-prealpha5):

main: func {

    a: LDouble = 3.324

    printf("direct  - %.2Lf\n", a);

    regular(a)
    vararg(a)

}

regular: func (a: LDouble) {
    printf("regular - %.2Lf\n", a);
}

vararg: func (args: ...) {
    a: LDouble = args iterator() next(LDouble)
    printf("vararg  - %.2Lf\n", a);
}

Outputs:

$ rock -r test3
direct  - 3.32
regular - 3.32
vararg  - 0.00

So now I'm going to try and figure out exactly what the varargs code does here.

Member

nddrylliog commented Nov 18, 2012

Here's one of my favorite (that's on rock 0.9.4-prealpha5):

main: func {

    a: LDouble = 3.324

    printf("direct  - %.2Lf\n", a);

    regular(a)
    vararg(a)

}

regular: func (a: LDouble) {
    printf("regular - %.2Lf\n", a);
}

vararg: func (args: ...) {
    a: LDouble = args iterator() next(LDouble)
    printf("vararg  - %.2Lf\n", a);
}

Outputs:

$ rock -r test3
direct  - 3.32
regular - 3.32
vararg  - 0.00

So now I'm going to try and figure out exactly what the varargs code does here.

@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Nov 18, 2012

Member

And for reference, here's my second testcase in C, that shows the earlier bytes aren't preserved:

#include <stdio.h>
#include <stdint.h>

int main (int argc, char **argv) {
    long double a = 2421947388463276794519050671392130485877789785034669850353933964614497513443678967029502567876346724116037405041617137142728457144651841445284156695455634709277306757174026395992538385710908699709913109140639071885141323609256957105898090518496271308408252515089298200656764591620687756183374140345878357987953192487652288930968248053786773288037328456065003225647755777389422018951101929341834830143542645967520033114117385100407631740445656594070303876544327897329738924365321584301108964785520292709288234172931358596681023227244023324770766962157221733705763661869534101838241639594786748269983456517542900180411969617523812929048670012447000989232633716911424693495105439378648762648352050786798857897599976766603738067978671456150031382227848364047945013782586743669152955213422462255912475152682931666034129513891418080922163695224221051797320075140767020174087520235143864778583907126102505834285436036969956947700797622065998790464363851078252236565557666986760158201873884448083940039623072599231724753282404406632374901944958550917525249853453336570736617345868954082445213186835876615875382435275209469709908417445766538183003226348812463327403320731587701602107684074780353728833743387604950084848389293068866466009876176012921628585417029198275782175830478923312409586662298219473980735113932042614682390261129234112912809257764315472541968804706455067996220653242318639998129160160244558273972399514220206672664000929479765243650602421396073663215509721146748175307450764454244661870479959086803330300984666436155186185248797887989199086348742943774066123095828985689503956654929491665483640024341525440223317290489504565432550258475333028424787657900635255628981308246203017931268489064372749115707103759619693986385150950533311100760689338232005878463018314900692772387750519317316191300961722485277726263977379599309424600331498009560659368343129982555585225797083347498820232715635689300908739959517845595268106093031933501674012581893186923386563856601715922835130991599501720281012935181368333138219736313177178326485838538803871899175898949547938367855774906802252055470910751196335532950408978563840606964827258471353996781090283810621974023208727485663181406302048854905204763818330309325022483814543210145713061563353242092365832427043032073739531637265710734331004256803048080345148359494175210300790883684063791591390788100426336305476506032828321409934637376956903292153842571258438373286784248896289676242667060850338037760.00l;

    //printf("%.2Lf\n", a);

    printf("Size of a long double: %lu\n", sizeof(long double));
    printf("Size of an uint8_t: %lu\n", sizeof(uint8_t));

    printf("What we get in ooc printf:\n");

    uint8_t *b = (uint8_t*) &a;
    printf("[%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x]\n", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]);

    printf("What we should get:\n");

    long double c = 3.234l;

    uint8_t *d = (uint8_t*) &c;
    printf("[%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x]\n", d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);

    printf("What we might get:\n");

    long double e = (long double) 3.234;

    uint8_t *f = (uint8_t*) &e;
    printf("[%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x]\n", f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9], f[10], f[11], f[12], f[13], f[14], f[15]);
}

The output was:

$ ./test2
Size of a long double: 16
Size of an uint8_t: 1
What we get in ooc printf:
[ 0][ 0][ 0][ 0][ 0][ 0][ 0][a0][ce][5f][ 0][ 0][ 0][ 0][ 0][ 0]
What we should get:
[42][60][e5][d0][22][db][f9][ce][ 0][40][ 0][ 0][ 0][ 0][ 0][ 0]
What we might get:
[ 0][60][e5][d0][22][db][f9][ce][ 0][40][ 0][ 0][ 0][ 0][ 0][ 0]
Member

nddrylliog commented Nov 18, 2012

And for reference, here's my second testcase in C, that shows the earlier bytes aren't preserved:

#include <stdio.h>
#include <stdint.h>

int main (int argc, char **argv) {
    long double a = 2421947388463276794519050671392130485877789785034669850353933964614497513443678967029502567876346724116037405041617137142728457144651841445284156695455634709277306757174026395992538385710908699709913109140639071885141323609256957105898090518496271308408252515089298200656764591620687756183374140345878357987953192487652288930968248053786773288037328456065003225647755777389422018951101929341834830143542645967520033114117385100407631740445656594070303876544327897329738924365321584301108964785520292709288234172931358596681023227244023324770766962157221733705763661869534101838241639594786748269983456517542900180411969617523812929048670012447000989232633716911424693495105439378648762648352050786798857897599976766603738067978671456150031382227848364047945013782586743669152955213422462255912475152682931666034129513891418080922163695224221051797320075140767020174087520235143864778583907126102505834285436036969956947700797622065998790464363851078252236565557666986760158201873884448083940039623072599231724753282404406632374901944958550917525249853453336570736617345868954082445213186835876615875382435275209469709908417445766538183003226348812463327403320731587701602107684074780353728833743387604950084848389293068866466009876176012921628585417029198275782175830478923312409586662298219473980735113932042614682390261129234112912809257764315472541968804706455067996220653242318639998129160160244558273972399514220206672664000929479765243650602421396073663215509721146748175307450764454244661870479959086803330300984666436155186185248797887989199086348742943774066123095828985689503956654929491665483640024341525440223317290489504565432550258475333028424787657900635255628981308246203017931268489064372749115707103759619693986385150950533311100760689338232005878463018314900692772387750519317316191300961722485277726263977379599309424600331498009560659368343129982555585225797083347498820232715635689300908739959517845595268106093031933501674012581893186923386563856601715922835130991599501720281012935181368333138219736313177178326485838538803871899175898949547938367855774906802252055470910751196335532950408978563840606964827258471353996781090283810621974023208727485663181406302048854905204763818330309325022483814543210145713061563353242092365832427043032073739531637265710734331004256803048080345148359494175210300790883684063791591390788100426336305476506032828321409934637376956903292153842571258438373286784248896289676242667060850338037760.00l;

    //printf("%.2Lf\n", a);

    printf("Size of a long double: %lu\n", sizeof(long double));
    printf("Size of an uint8_t: %lu\n", sizeof(uint8_t));

    printf("What we get in ooc printf:\n");

    uint8_t *b = (uint8_t*) &a;
    printf("[%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x]\n", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]);

    printf("What we should get:\n");

    long double c = 3.234l;

    uint8_t *d = (uint8_t*) &c;
    printf("[%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x]\n", d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);

    printf("What we might get:\n");

    long double e = (long double) 3.234;

    uint8_t *f = (uint8_t*) &e;
    printf("[%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x][%2x]\n", f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9], f[10], f[11], f[12], f[13], f[14], f[15]);
}

The output was:

$ ./test2
Size of a long double: 16
Size of an uint8_t: 1
What we get in ooc printf:
[ 0][ 0][ 0][ 0][ 0][ 0][ 0][a0][ce][5f][ 0][ 0][ 0][ 0][ 0][ 0]
What we should get:
[42][60][e5][d0][22][db][f9][ce][ 0][40][ 0][ 0][ 0][ 0][ 0][ 0]
What we might get:
[ 0][60][e5][d0][22][db][f9][ce][ 0][40][ 0][ 0][ 0][ 0][ 0][ 0]
@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Nov 18, 2012

Member

Okay.. that explains some of it, see this gist: https://gist.github.com/4107837

The short version is that whenever you have a 'long double' in a struct, suddenly everything becomes double-word-aligned. The bad news is that for ooc varargs, we have no freaking idea if there's a long double involved until we get a call like this:

vararg: func (args: ...) {
    a: LDouble = args iterator() next(LDouble)
    printf("vararg  - %.2Lf\n", a);
}

Because instead of skipping 8 bytes (on 64-bit) for the class pointer (which gives us the type's width), we should skip 16 bytes. If the long double is the first argument, we can have a workaround: check T->size's for the argument, if it's > 8 bytes, skip 16 bytes instead.

But if it's not the first, we're screwed. There's no way we can retrieve the sizes of later types, because if the first arg is <= 8 bytes, we'll already be skipping the wrong amoung of bytes to get to the next type class.

TL;DR without changing the generated structs passed to ooc varargs functions, it's hopeless.

Member

nddrylliog commented Nov 18, 2012

Okay.. that explains some of it, see this gist: https://gist.github.com/4107837

The short version is that whenever you have a 'long double' in a struct, suddenly everything becomes double-word-aligned. The bad news is that for ooc varargs, we have no freaking idea if there's a long double involved until we get a call like this:

vararg: func (args: ...) {
    a: LDouble = args iterator() next(LDouble)
    printf("vararg  - %.2Lf\n", a);
}

Because instead of skipping 8 bytes (on 64-bit) for the class pointer (which gives us the type's width), we should skip 16 bytes. If the long double is the first argument, we can have a workaround: check T->size's for the argument, if it's > 8 bytes, skip 16 bytes instead.

But if it's not the first, we're screwed. There's no way we can retrieve the sizes of later types, because if the first arg is <= 8 bytes, we'll already be skipping the wrong amoung of bytes to get to the next type class.

TL;DR without changing the generated structs passed to ooc varargs functions, it's hopeless.

@alexnask

This comment has been minimized.

Show comment Hide comment
@alexnask

alexnask Nov 18, 2012

Collaborator

Well this is problematic :-/

Collaborator

alexnask commented Nov 18, 2012

Well this is problematic :-/

@alexnask alexnask closed this Nov 18, 2012

@alexnask alexnask reopened this Nov 18, 2012

@alexnask

This comment has been minimized.

Show comment Hide comment
@alexnask

alexnask Nov 18, 2012

Collaborator

Sorry about that, missclick

Collaborator

alexnask commented Nov 18, 2012

Sorry about that, missclick

@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Nov 19, 2012

Member

As I mentioned earlier, one solution would be to change the structure of ooc varargs (and thus break our ABI).

Currently the structure is like this:

[Pointer to T1's class]
[T1 value]
[Pointer to T2's class]
[T2 value]

and so on. What we could do instead is this:

[size_t set to 8 or 16]
[Pointer to T1's class]
[T1 value]
[Pointer to T2's class]
[T2 value]

So if the firs size_t is set to 16, we can set a 'longdouble' flag to true in VarArgsIterator, and it should know to skip 16 bytes instead of 8. However, that requires modification in rock, ie. instead of

    struct { 
        lang_types__Pointer __f1;
        lang_Numbers__LDouble __f2;
    } ____va_args2 = {  
        lang_Numbers__LDouble_class(), 
        a    
    };

it should generate

    struct { 
        lang_Numbers__SizeT __align;
        lang_types__Pointer __f1;
        lang_Numbers__LDouble __f2;
    } ____va_args2 = {  
        16,
        lang_Numbers__LDouble_class(), 
        a    
    };

@shamanas perhaps we could do this in a branch?

Member

nddrylliog commented Nov 19, 2012

As I mentioned earlier, one solution would be to change the structure of ooc varargs (and thus break our ABI).

Currently the structure is like this:

[Pointer to T1's class]
[T1 value]
[Pointer to T2's class]
[T2 value]

and so on. What we could do instead is this:

[size_t set to 8 or 16]
[Pointer to T1's class]
[T1 value]
[Pointer to T2's class]
[T2 value]

So if the firs size_t is set to 16, we can set a 'longdouble' flag to true in VarArgsIterator, and it should know to skip 16 bytes instead of 8. However, that requires modification in rock, ie. instead of

    struct { 
        lang_types__Pointer __f1;
        lang_Numbers__LDouble __f2;
    } ____va_args2 = {  
        lang_Numbers__LDouble_class(), 
        a    
    };

it should generate

    struct { 
        lang_Numbers__SizeT __align;
        lang_types__Pointer __f1;
        lang_Numbers__LDouble __f2;
    } ____va_args2 = {  
        16,
        lang_Numbers__LDouble_class(), 
        a    
    };

@shamanas perhaps we could do this in a branch?

@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Nov 19, 2012

Member

As I mentioned earlier, one solution would be to change the structure of ooc varargs (and thus break our ABI).

Currently the structure is like this:

[Pointer to T1's class]
[T1 value]
[Pointer to T2's class]
[T2 value]

and so on. What we could do instead is this:

[size_t set to 8 or 16]
[Pointer to T1's class]
[T1 value]
[Pointer to T2's class]
[T2 value]

So if the firs size_t is set to 16, we can set a 'longdouble' flag to true in VarArgsIterator, and it should know to skip 16 bytes instead of 8. However, that requires modification in rock, ie. instead of

    struct { 
        lang_types__Pointer __f1;
        lang_Numbers__LDouble __f2;
    } ____va_args2 = {  
        lang_Numbers__LDouble_class(), 
        a    
    };

it should generate

    struct { 
        lang_Numbers__SizeT __align;
        lang_types__Pointer __f1;
        lang_Numbers__LDouble __f2;
    } ____va_args2 = {  
        16,
        lang_Numbers__LDouble_class(), 
        a    
    };

@shamanas perhaps we could do this in a branch?

Member

nddrylliog commented Nov 19, 2012

As I mentioned earlier, one solution would be to change the structure of ooc varargs (and thus break our ABI).

Currently the structure is like this:

[Pointer to T1's class]
[T1 value]
[Pointer to T2's class]
[T2 value]

and so on. What we could do instead is this:

[size_t set to 8 or 16]
[Pointer to T1's class]
[T1 value]
[Pointer to T2's class]
[T2 value]

So if the firs size_t is set to 16, we can set a 'longdouble' flag to true in VarArgsIterator, and it should know to skip 16 bytes instead of 8. However, that requires modification in rock, ie. instead of

    struct { 
        lang_types__Pointer __f1;
        lang_Numbers__LDouble __f2;
    } ____va_args2 = {  
        lang_Numbers__LDouble_class(), 
        a    
    };

it should generate

    struct { 
        lang_Numbers__SizeT __align;
        lang_types__Pointer __f1;
        lang_Numbers__LDouble __f2;
    } ____va_args2 = {  
        16,
        lang_Numbers__LDouble_class(), 
        a    
    };

@shamanas perhaps we could do this in a branch?

@alexnask

This comment has been minimized.

Show comment Hide comment
@alexnask

alexnask Nov 19, 2012

Collaborator

Ok I'll implement this then release 0.9.4
Expect this tonight/tomorrow afternoon

Collaborator

alexnask commented Nov 19, 2012

Ok I'll implement this then release 0.9.4
Expect this tonight/tomorrow afternoon

@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Nov 19, 2012

Member

Imho that can easily be a post-0.9.4 fix. It may have consequences.. introduce other bugs.. not sure we want to cram this as a late fix.

Member

nddrylliog commented Nov 19, 2012

Imho that can easily be a post-0.9.4 fix. It may have consequences.. introduce other bugs.. not sure we want to cram this as a late fix.

@alexnask

This comment has been minimized.

Show comment Hide comment
@alexnask

alexnask Dec 18, 2012

Collaborator

@nddrylliog Is it possible that using VarArgs init and VarArgs _addValue would fix this instead of relying on the C compiler? I mean, it should be consistent across systems too, so it would maybe fix some issues (like the Raspberry Pi one)

Collaborator

alexnask commented Dec 18, 2012

@nddrylliog Is it possible that using VarArgs init and VarArgs _addValue would fix this instead of relying on the C compiler? I mean, it should be consistent across systems too, so it would maybe fix some issues (like the Raspberry Pi one)

@nddrylliog

This comment has been minimized.

Show comment Hide comment
@nddrylliog

nddrylliog Nov 2, 2013

Member

@shamanas took me 11 months to respond, sorry again, but - using VarArgs (or Stick) to construct that seems like too much of a performance downer (I know, I know, premature optimization is evil..).

Just to come back to the fact that you thought about implementing it in a single evening, did you remember that we don't currently know the bitwidths of Float, Double, LDouble at ooc compile time? It all depends on the platform..

Another solution would be, instead of putting the size of each element in our struct, to just do:

  • Offset of 2st element
  • 1st element
  • Offset of 3rd element
  • 2nd element

This looks weird but actually makes sense - the last offset is just the size of the complete struct. And we could use offsetof to compute that reliably, as has been mentioned in #535, but then we'd have to give up anonymous structs I think.

Member

nddrylliog commented Nov 2, 2013

@shamanas took me 11 months to respond, sorry again, but - using VarArgs (or Stick) to construct that seems like too much of a performance downer (I know, I know, premature optimization is evil..).

Just to come back to the fact that you thought about implementing it in a single evening, did you remember that we don't currently know the bitwidths of Float, Double, LDouble at ooc compile time? It all depends on the platform..

Another solution would be, instead of putting the size of each element in our struct, to just do:

  • Offset of 2st element
  • 1st element
  • Offset of 3rd element
  • 2nd element

This looks weird but actually makes sense - the last offset is just the size of the complete struct. And we could use offsetof to compute that reliably, as has been mentioned in #535, but then we'd have to give up anonymous structs I think.

@fasterthanlime

This comment has been minimized.

Show comment Hide comment
@fasterthanlime

fasterthanlime Aug 15, 2014

Collaborator

This issue has been alive for too long.

Collaborator

fasterthanlime commented Aug 15, 2014

This issue has been alive for too long.

@alexnask

This comment has been minimized.

Show comment Hide comment
@alexnask

alexnask Aug 17, 2014

Collaborator

Indeed.
I think the offsetof solution sounds good and is our best bet seeing as we don't know the size of our types at compile-time, as you mentioned above.

I'll take a shot at this tomorrow and report back.

Collaborator

alexnask commented Aug 17, 2014

Indeed.
I think the offsetof solution sounds good and is our best bet seeing as we don't know the size of our types at compile-time, as you mentioned above.

I'll take a shot at this tomorrow and report back.

@alexnask

This comment has been minimized.

Show comment Hide comment
@alexnask

alexnask Aug 19, 2014

Collaborator

@fasterthanlime

Maybe I am mistaken here but wouldn't the offsetof the first element's data - the offsetof the first element's class be the alignment of the struct?

So we could have

  • offsetof(data1) - offsetof(class1) == alignment
  • class1
  • data1
  • class2
  • data2
  • ...

So we get the alignment (sizet/int/whatever) skip "alignment" bytes to get past the first field, read the class, skip alignment - sizeof(Class), read Class size, skip alignment - Class size, etc..

Collaborator

alexnask commented Aug 19, 2014

@fasterthanlime

Maybe I am mistaken here but wouldn't the offsetof the first element's data - the offsetof the first element's class be the alignment of the struct?

So we could have

  • offsetof(data1) - offsetof(class1) == alignment
  • class1
  • data1
  • class2
  • data2
  • ...

So we get the alignment (sizet/int/whatever) skip "alignment" bytes to get past the first field, read the class, skip alignment - sizeof(Class), read Class size, skip alignment - Class size, etc..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment