Skip to content

Commit

Permalink
Fix calling convention for struct
Browse files Browse the repository at this point in the history
  • Loading branch information
shinh committed Dec 11, 2016
1 parent 5f3b752 commit 3dd51a8
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 8 deletions.
30 changes: 25 additions & 5 deletions gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -959,15 +959,13 @@ static int emit_args(Vector *vals) {
int r = 0;
for (int i = 0; i < vec_len(vals); i++) {
Node *v = vec_get(vals, i);
if (v->ty->kind == KIND_STRUCT) {
emit_addr(v);
emit_expr(v);
if (is_large_struct(v->ty)) {
r += push_struct(v->ty->size);
} else if (is_flotype(v->ty)) {
emit_expr(v);
push_xmm(0);
r += 8;
} else {
emit_expr(v);
push("rax");
r += 8;
}
Expand Down Expand Up @@ -1090,7 +1088,29 @@ static void emit_return(Node *node) {
SAVE;
if (node->retval) {
emit_expr(node->retval);
maybe_booleanize_retval(node->retval->ty);
if (is_large_struct(node->retval->ty)) {
push("rcx");
push("r11");
int i = 0;
emit("movq -8(#rbp), #rcx");
for (; i < node->retval->ty->size; i += 8) {
emit("movq %d(#rax), #r11", i);
emit("movq #r11, %d(#rcx)", i);
}
for (; i < node->retval->ty->size; i += 4) {
emit("movq %d(#rax), #r11", i);
emit("movq #r11, %d(#rcx)", i);
}
for (; i < node->retval->ty->size; i++) {
emit("movq %d(#rax), #r11", i);
emit("movq #r11, %d(#rcx)", i);
}
emit("mov #rcx, #rax");
pop("r11");
pop("rcx");
} else {
maybe_booleanize_retval(node->retval->ty);
}
}
emit_ret();
}
Expand Down
21 changes: 18 additions & 3 deletions parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -795,9 +795,16 @@ static Node *read_alignof_operand() {
* Function arguments
*/

static Vector *read_func_args(Vector *params) {
static Vector *read_func_args(Type *ty) {
Vector *params = ty->params;
Vector *args = make_vector();
int i = 0;
if (is_large_struct(ty->rettype)) {
Node *retval = ast_lvar(ty->rettype, make_tempname());
retval = ast_uop(AST_ADDR, make_ptr_type(ty->rettype), retval);
vec_push(args, retval);
i++;
}
for (;;) {
if (next_token(')')) break;
Node *arg = conv(read_assignment_expr());
Expand All @@ -824,10 +831,10 @@ static Vector *read_func_args(Vector *params) {
static Node *read_funcall(Node *fp) {
if (fp->kind == AST_ADDR && fp->operand->kind == AST_FUNCDESG) {
Node *desg = fp->operand;
Vector *args = read_func_args(desg->ty->params);
Vector *args = read_func_args(desg->ty);
return ast_funcall(desg->ty, desg->fname, args);
}
Vector *args = read_func_args(fp->ty->ptr->params);
Vector *args = read_func_args(fp->ty->ptr);
return ast_funcptr_call(fp, args);
}

Expand Down Expand Up @@ -2349,6 +2356,14 @@ static Node *read_funcdef() {
read_oldstyle_param_type(params);
functype->params = param_types(params);
}
if (is_large_struct(functype->rettype)) {
Vector *new_params = make_vector();
vec_push(new_params,
ast_lvar(make_ptr_type(functype->rettype), make_tempname()));
vec_append(new_params, params);
params = new_params;
functype->params = param_types(params);
}
functype->isstatic = (sclass == S_STATIC);
ast_gvar(functype, name);
expect('{');
Expand Down
40 changes: 40 additions & 0 deletions test/struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,10 @@ struct abi_check {
struct abi_check_nest z;
};

typedef struct abi_check_small {
int x;
};

static int struct_arg_func(struct abi_check s1, struct abi_check s2) {
int r = s1.x + s1.y + s1.z.a + s1.z.b + s1.z.c;
r -= s2.x + s2.y + s2.z.a + s2.z.b + s2.z.c;
Expand Down Expand Up @@ -361,6 +365,40 @@ static void struct_global(void) {
expect(14, sn.c);
}

static struct abi_check return_struct_func(int x, int y, int a, int b, int c) {
struct abi_check s;
s.x = x;
s.y = y;
s.z.a = a;
s.z.b = b;
s.z.c = c;
return s;
}

static int sum_struct(int base, struct abi_check s) {
return base + s.x + s.y + s.z.a + s.z.b + s.z.c;
}

static void struct_return(void) {
struct abi_check s = return_struct_func(42, 43, 44, 45, 46);
expect(42, s.x);
expect(43, s.y);
expect(44, s.z.a);
expect(45, s.z.b);
expect(46, s.z.c);
expect(21, sum_struct(6, return_struct_func(1, 2, 3, 4, 5)));
expect(55, sum_struct(sum_struct(0, return_struct_func(1, 2, 3, 4, 5)),
return_struct_func(6, 7, 8, 9, 10)));
}

static int struct_arg_func_small(int v, struct abi_check_small s) {
return v + s.x;
}

static void struct_call_small(void) {
expect(43, struct_arg_func_small(1, (struct abi_check_small){ 42 }));
}

void testmain() {
print("struct");
t1();
Expand Down Expand Up @@ -392,4 +430,6 @@ void testmain() {
struct_call();
struct_local();
struct_global();
struct_return();
struct_call_small();
}

0 comments on commit 3dd51a8

Please sign in to comment.