wiremod / wire-cpu

Legacy CPU/GPU/SPU as a separate addon.
Apache License 2.0
8 stars 6 forks source link

HL-ZASM Passing and returning stack objects. #4

Open Yevano opened 10 years ago

Yevano commented 10 years ago

Incorrect code is generated for passing structs and arrays on the stack to functions and for returning them. In the case of passing, the caller just passes the first byte of the array or struct. The callee code is actually generated correctly and would be able to receive the object if it were passed correctly. In the case of returning, the first element of the object is stored in eax and no copying is done.

If the compiler was never meant to have these features, it should at least throw an error rather than passing/returning the first byte of the object.

EDIT: Seems like arrays of structs aren't indexed correctly (index isn't aligned to the size of the struct) and reading arrays of structs won't copy structs onto the stack either.

Xandaros commented 10 years ago

That explains a lot, thanks for figuring it out. When I asked @PhoenixBlack to add structs, they seemed to be a bit wonky, but I was not able to actually figure it out. To be honest, I never really used HL-ZASM and only ever used ZASM2, so it never bothered me enough to care.

It appears it is just not able to determine the size of structs correctly. You might want to try to pass them as pointers, that might work.

AbigailBuccaneer commented 10 years ago

% cat test.txt

#pragma set OutputFinalListing true

struct vec2
{
    float x;
    float y;
};

void distance(vec2 v) {
    v.x + v.y;
}

vec2 v;
v.x = 3;
v.y = 4;
distance(v);

Output:

distance:
// distance(v)
     0 enter -0
__1:
     3 rstack EAX,EBP:4
     7 rstack EBX,EBP:3
    11 add EBX,EAX
// v.x+v.y
    13 sstack EBP:3,EBX
__0:
    17 leave 
    18 ret 
v:
    19 alloc 2
    21 mov EAX,0
    24 add EAX,19
// v.x=3
    27 mov #EAX,3
    30 mov EAX,1
    33 add EAX,19
// v.y=4
    36 mov #EAX,4
// distance arg wiremod/wire#1 (vec2 v)
    39 push wiremod/wire#19
    42 mov ECX,1
// distance(...)
    45 call 0
    48 add ESP,1
AbigailBuccaneer commented 10 years ago
#pragma set OutputFinalListing true

struct vec2
{
    float x;
    float y;
};

vec2 rotate(vec2 u)
{
    vec2 v;
    v.x = -u.y;
    v.y = u.x;
};

vec2 u;
vec2 v;
u.x = 3;
u.y = 4;
v = rotate(u);
rotate:
; rotate(u)
     0 enter 2
__1:
     3 rstack EAX,EBP:4
; v.x=-u.y
     7 sstack EBP:-2,EAX
    11 rstack EAX,EBP:3
; v.y=u.x
    15 sstack EBP:-1,EAX
__0:
    19 leave 
    20 ret 
u:
    21 alloc 2
v:
    23 alloc 2
    25 mov EAX,0
    28 add EAX,21
; u.x=3
    31 mov #EAX,3
    34 mov EAX,1
    37 add EAX,21
; u.y=4
    40 mov #EAX,4
    43 push wiremod/wire#21
    46 mov ECX,1
; rotate(...)
    49 call 0
    52 add ESP,1
; v=rotate(u)
    55 mov wiremod/wire#23,EAX