Skip to content

Commit

Permalink
Merge pull request #1134 from z88dk/feature/struct_assignment
Browse files Browse the repository at this point in the history
(sccz80) Struct assignment
  • Loading branch information
suborb committed Apr 15, 2019
2 parents 80bef4b + cf58621 commit 55c28d8
Show file tree
Hide file tree
Showing 11 changed files with 435 additions and 60 deletions.
32 changes: 23 additions & 9 deletions lib/z80rules.1
Original file line number Diff line number Diff line change
Expand Up @@ -516,15 +516,6 @@
=
pop de

pop bc
ld hl,%1 ;const
add hl,sp
ld sp,hl
=
ld hl,%eval(%1 2 +) ;const
add hl,sp
ld sp,hl

exx
ld hl,%1 ;const
add hl,sp
Expand Down Expand Up @@ -4056,3 +4047,26 @@
ld de,0
ld a,h
or l

ld hl,%1
push hl
ld hl,%2 ;const
add hl,sp
ex de,hl
pop bc
=
ld hl,%eval(%2 2 -) ;const
add hl,sp
ex de,hl
ld bc,%1

ld hl,%1 ;const
add hl,sp
ld sp,hl
ld hl,%2 ;const
add hl,sp
ld sp,hl
=
ld hl,%eval(65536 %1 %2 + %) ;const
add hl,sp
ld sp,hl
40 changes: 4 additions & 36 deletions src/sccz80/callfunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,6 @@ void callfunction(SYMBOL *ptr, Type *fnptr_type)
zcarryconv();
expr = KIND_INT;
type = type_int;
} else if ( expr == KIND_STRUCT ) {
errorfmt("Cannot pass structure as function parameter (argument number %d)",0, argnumber);
}
if ( functype->funcattrs.oldstyle == 0 && argnumber <= array_len(functype->parameters)) {
int proto_argnumber;
Expand Down Expand Up @@ -285,41 +283,11 @@ void callfunction(SYMBOL *ptr, Type *fnptr_type)
printf_format_option |= format_option;
}
}
if ( function_pointer_call == 0 || ( fnptr_type->kind == KIND_CPTR ) ) {
if (expr == KIND_DOUBLE) {
dpush();
nargs += 6;
} else if (expr == KIND_LONG || expr == KIND_CPTR) {
lpush();
nargs += 4;
} else if ( expr == KIND_CHAR && functype->flags & SDCCDECL && argnumber <= array_len(functype->parameters ) ) {
push_char_sdcc_style();
nargs += 1;
} else {
zpush();
nargs += 2;
}
if ( function_pointer_call == 0 || fnptr_type->kind == KIND_CPTR ) {
nargs += push_function_argument(expr, type, functype->flags & SDCCDECL && argnumber <= array_len(functype->parameters));
} else {
if (expr == KIND_LONG || expr == KIND_CPTR) {
if ( tmpfiles[argnumber+1] != NULL ) {
swap(); /* MSW -> hl */
swapstk(); /* MSW -> stack, addr -> hl */
zpushde(); /* LSW -> stack, addr = hl */
}
nargs += 4;
last_argument_size = 4;
} else if (expr == KIND_DOUBLE) {
dpush_under(KIND_INT);
nargs += 6;
last_argument_size = 6;
mainpop();
} else {
if ( tmpfiles[argnumber+1] != NULL ) {
swapstk();
}
nargs += 2;
last_argument_size = 2;
}
last_argument_size = push_function_argument_fnptr(expr, type, functype->flags & SDCCDECL && argnumber <= array_len(functype->parameters), tmpfiles[argnumber+1] == NULL);
nargs += last_argument_size;
}
}
restore_input();
Expand Down
82 changes: 80 additions & 2 deletions src/sccz80/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ void putstk(LVALUE *lval)
case KIND_CHAR:
callrts("lp_pchar");
break;
case KIND_STRUCT:
warningfmt("incompatible-pointer-types","Cannot assign a __far struct");
default:
callrts("lp_pint");
}
Expand All @@ -442,6 +444,11 @@ void putstk(LVALUE *lval)
LoadAccum();
ol("ld\t(de),a");
break;
case KIND_STRUCT:
zpop();
outfmt("\tld\tbc,%d\n",lval->ltype->size);
ol("ldir");
break;
default:
zpop();
callrts("l_pint");
Expand Down Expand Up @@ -537,6 +544,8 @@ void indirect(LVALUE* lval)
case KIND_DOUBLE:
callrts("lp_gdoub");
break;
case KIND_STRUCT:
warningfmt("incompatible-pointer-types","Cannot retrieve a struct via __far");
default:
callrts("lp_gint");
}
Expand Down Expand Up @@ -566,6 +575,8 @@ void indirect(LVALUE* lval)
case KIND_DOUBLE:
callrts("dload");
break;
case KIND_STRUCT:
break;
default:
ot("call\tl_gint\t;");
#ifdef USEFRAME
Expand Down Expand Up @@ -661,9 +672,76 @@ void dpush(void)
Zsp -= 6;
}

/* Push an argument for a function pointer call: regular or far pointer */
int push_function_argument(Kind expr, Type *type, int push_sdccchar)
{
if (expr == KIND_DOUBLE) {
dpush();
return type_double->size;
} else if (expr == KIND_LONG || expr == KIND_CPTR) {
lpush();
return 4;
} else if ( expr == KIND_CHAR && push_sdccchar ) {
ol("ld\tb,l");
ol("push\tbc");
ol("inc\tsp");
Zsp--;
return 1;
} else if (expr == KIND_STRUCT) {
swap(); /* de = stack address */
vconst(-type->size);
ol("add\thl,sp");
ol("ld\tsp,hl");
Zsp -= type->size;
swap();
outfmt("\tld\tbc,%d\n",type->size);
ol("ldir");
return type->size;
}
// Default push the word
zpush();
return 2;
}

/* Push an argument for a function pointer call */
int push_function_argument_fnptr(Kind expr, Type *type, int push_sdccchar, int is_last_argument)
{
if (expr == KIND_LONG || expr == KIND_CPTR) {
if ( !is_last_argument ) {
swap(); /* MSW -> hl */
swapstk(); /* MSW -> stack, addr -> hl */
zpushde(); /* LSW -> stack, addr = hl */
}
return 4;
} else if (expr == KIND_DOUBLE) {
dpush_under(KIND_INT);
mainpop();
return 6;
} else if (expr == KIND_STRUCT ) {
// 13 bytes
swap(); // de = address of struct
ol("pop\tbc"); // return address
vconst(-type->size);
ol("add\thl,sp");
ol("ld\tsp,hl");
ol("push\tbc");
Zsp -= type->size;
swap();
outfmt("\tld\tbc,%d\n",type->size);
ol("ldir");
mainpop();
return type->size;
}
if ( !is_last_argument ) {
swapstk();
}
return 2;
}



/* Push the primary floating point register, preserving
the top value */

void dpush_under(int val_type)
{
if ( val_type == KIND_LONG ) {
Expand Down Expand Up @@ -787,7 +865,7 @@ void callstk(Type *type, int n, int isfarptr, int last_argument_size)
}
loadargc(n);
callrts("l_farcall");
} else if ( type->flags & FASTCALL && last_argument_size != 6 ) {
} else if ( type->flags & FASTCALL && last_argument_size < 6 ) {
int label = getlabel();
// TOS = address, dehl = parameter
// More than one argument, TOS = last parameter, hl = function
Expand Down
3 changes: 3 additions & 0 deletions src/sccz80/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,6 @@ extern void intrinsic_out(SYMBOL *sym);
extern void zentercritical(void);
extern void zleavecritical(void);
extern int zcriticaloffset(void);
extern int push_function_argument(Kind expr, Type *type, int push_sdccchar);
extern int push_function_argument_fnptr(Kind expr, Type *type, int push_sdccchar, int is_last_argument);

28 changes: 18 additions & 10 deletions src/sccz80/declparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,22 @@ static int32_t needsub(void)
}


static void swallow_bitfield(void)
static void swallow_bitfield(Type *type)
{
double val;
Kind valtype;
if (cmatch(':')) {
constexpr(&val, &valtype, 1);
warningfmt("unsupported-feature","Bitfields not supported by compiler");
if ( !kind_is_integer(type->kind) ) {
errorfmt("Cannot define a bitfield on non-integer type",1);
} else {
constexpr(&val, &valtype, 1);
if ( val > 16 ) {
errorfmt("Cannot define a bitfield on non-integer type",1);
} else {
type->bit_size = val;
}
warningfmt("unsupported-feature","Bitfields not supported by compiler");
}
}
}

Expand Down Expand Up @@ -356,7 +365,7 @@ Type *parse_struct(Type *type, char isstruct)
break;
}
// Swallow bitfields
swallow_bitfield();
swallow_bitfield(elem);

// It was a flexible member, this needs to be last in the sturct
if ( elem->size <= 0 ) {
Expand Down Expand Up @@ -495,6 +504,11 @@ static void parse_trailing_modifiers(Type *type)
if( type->parameters && array_len(type->parameters) != 1 ) {
warningfmt("sdcc-compat", "SDCC only supports a single parameter for __z88dk_fastcall\n");
}
if( type->parameters && array_len(type->parameters) &&
((Type *)array_get_byindex(type->parameters, array_len(type->parameters) - 1))->kind == KIND_STRUCT ) {
errorfmt("__z88dk_fastcall doesn't support struct as only parameter\n",1);
continue;
}
type->flags |= FASTCALL;
type->flags &= ~FLOATINGDECL;
} else if (amatch("__z88dk_callee") || amatch("__CALLEE__")) {
Expand Down Expand Up @@ -643,12 +657,6 @@ Type *parse_parameter_list(Type *return_type)
strcpy(ptr->name, param->name);
param = ptr;
}
if ( param->kind == KIND_STRUCT ) {
Type *ptr = make_pointer(param);
warningfmt("conversion","Cannot pass a struct by value, converting to pointer to struct");
strcpy(ptr->name, param->name);
param = ptr;
}
if ( param->kind == KIND_ELLIPSES) {
if ( array_len(func->parameters) ) {
array_add(func->parameters, param);
Expand Down
4 changes: 4 additions & 0 deletions src/sccz80/define.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ struct type_s {
int len; // Length of the array

int32_t value; // For enum, goto position, short call value

// bitfields
int bit_offset;
int bit_size;

// Structures
Type *tag; // Reference to the structure type
Expand Down
10 changes: 7 additions & 3 deletions src/sccz80/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ int heir1(LVALUE* lval)
if (cmatch('=')) {
char *start1, *before1;
if (k == 0) {
needlval();
return 0;
if ( lval->ltype->kind != KIND_STRUCT ) {
needlval();
return 0;
}
}
if (lval->indirect_kind)
smartpush(lval, before);
Expand Down Expand Up @@ -115,7 +117,9 @@ int heir1(LVALUE* lval)
}
}
} else if ( lval->ltype->kind == KIND_STRUCT ) {
errorfmt("Cannot assign to aggregate",0);
if ( lval2.ltype->kind != KIND_STRUCT ) {
errorfmt("Cannot assign to aggregate",0);
}
}
if ( lval2.ltype->kind == KIND_VOID ) {
warningfmt("void","Assigning from a void expression");
Expand Down
52 changes: 52 additions & 0 deletions testsuite/Issue_1132_struct_by_value.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@


struct test {
char c[10];
int x;
int y;
};

static struct test x;
static struct test y;
static struct test *z;

void func_global_assign()
{
x = y;
}

void func_global_assign_to_pointer()
{
*z = y;
}

void func_global_assign_from_pointer()
{
x = *z;
}

void func_local_assign()
{
struct test a;
struct test b;

a = b;
}

void func_local_assign_to_pointer()
{
struct test a;
struct test *b;

*b = a;
}


void func_local_assign_from_pointer()
{
struct test a;
struct test *b;

a = *b;
}

0 comments on commit 55c28d8

Please sign in to comment.