use register classes (will allow better and simpler code gen - fixed long double handling

tcc-xref
bellard 2001-12-23 00:34:26 +00:00
parent 498551188e
commit 21c35b9443
2 changed files with 183 additions and 142 deletions

View File

@ -21,11 +21,11 @@
/* number of available registers */ /* number of available registers */
#define NB_REGS 4 #define NB_REGS 4
#define NB_REG_CLASSES 2
/* a register can belong to several classes */ /* a register can belong to several classes */
#define REG_CLASS_INT 0x0001 #define RC_INT 0x0001 /* generic integer register */
#define REG_CLASS_FLOAT 0x0002 #define RC_FLOAT 0x0002 /* generic float register */
#define RC_IRET 0x0004 /* function returned integer register */
#define RC_FRET 0x0008 /* function returned float register */
/* pretty names for the registers */ /* pretty names for the registers */
enum { enum {
@ -36,16 +36,15 @@ enum {
}; };
int reg_classes[NB_REGS] = { int reg_classes[NB_REGS] = {
REG_CLASS_INT, /* eax */ /* eax */ RC_INT | RC_IRET,
REG_CLASS_INT, /* ecx */ /* ecx */ RC_INT,
REG_CLASS_INT, /* edx */ /* edx */ RC_INT,
REG_CLASS_FLOAT, /* st0 */ /* st0 */ RC_FLOAT | RC_FRET,
}; };
/* integer return register for functions */ /* return registers for function */
#define FUNC_RET_REG 0 #define REG_IRET REG_EAX
/* float return register for functions */ #define REG_FRET REG_ST0
#define FUNC_RET_FREG 3
/* defined if function parameters must be evaluated in reverse order */ /* defined if function parameters must be evaluated in reverse order */
#define INVERT_FUNC_PARAMS #define INVERT_FUNC_PARAMS
@ -89,40 +88,17 @@ void gen_le32(int c)
g(c >> 24); g(c >> 24);
} }
/* add a new relocation entry to symbol 's' */ /* patch relocation entry with value 'val' */
void greloc(Sym *s, int addr, int type) void greloc_patch1(Reloc *p, int val)
{ {
Reloc *p; switch(p->type) {
p = malloc(sizeof(Reloc)); case RELOC_ADDR32:
if (!p) *(int *)p->addr = val;
error("memory full"); break;
p->type = type; case RELOC_REL32:
p->addr = addr; *(int *)p->addr = val - p->addr - 4;
p->next = (Reloc *)s->c; break;
s->c = (int)p;
}
/* patch each relocation entry with value 'val' */
void greloc_patch(Sym *s, int val)
{
Reloc *p, *p1;
p = (Reloc *)s->c;
while (p != NULL) {
p1 = p->next;
switch(p->type) {
case RELOC_ADDR32:
*(int *)p->addr = val;
break;
case RELOC_REL32:
*(int *)p->addr = val - p->addr - 4;
break;
}
free(p);
p = p1;
} }
s->c = val;
s->r &= ~VT_FORWARD;
} }
/* output a symbol and patch all calls to it */ /* output a symbol and patch all calls to it */
@ -166,6 +142,30 @@ void gen_addr32(int r, int c)
} }
} }
/* generate a modrm reference. 'op_reg' contains the addtionnal 3
opcode bits */
void gen_modrm(int op_reg, int r, int c)
{
op_reg = op_reg << 3;
if ((r & VT_VALMASK) == VT_CONST) {
/* constant memory reference */
o(0x05 | op_reg);
gen_addr32(r, c);
} else if ((r & VT_VALMASK) == VT_LOCAL) {
/* currently, we use only ebp as base */
if (c == (char)c) {
/* short reference */
o(0x45 | op_reg);
g(c);
} else {
oad(0x85 | op_reg, c);
}
} else {
g(0x00 | op_reg | (r & VT_VALMASK));
}
}
/* load 'r' from value 'sv' */ /* load 'r' from value 'sv' */
void load(int r, SValue *sv) void load(int r, SValue *sv)
{ {
@ -183,7 +183,7 @@ void load(int r, SValue *sv)
v1.r = VT_LOCAL | VT_LVAL; v1.r = VT_LOCAL | VT_LVAL;
v1.c.ul = fc; v1.c.ul = fc;
load(r, &v1); load(r, &v1);
v = r; fr = r;
} }
if ((ft & VT_BTYPE) == VT_FLOAT) { if ((ft & VT_BTYPE) == VT_FLOAT) {
o(0xd9); /* flds */ o(0xd9); /* flds */
@ -204,22 +204,14 @@ void load(int r, SValue *sv)
o(0xb70f); /* movzwl */ o(0xb70f); /* movzwl */
else else
o(0x8b); /* movl */ o(0x8b); /* movl */
gen_modrm(r, fr, fc);
if (v == VT_CONST) {
o(0x05 + r * 8); /* 0xXX, r */
gen_addr32(fr, fc);
} else if (v == VT_LOCAL) {
oad(0x85 + r * 8, fc); /* xx(%ebp), r */
} else {
g(0x00 + r * 8 + v); /* (v), r */
}
} else { } else {
if (v == VT_CONST) { if (v == VT_CONST) {
o(0xb8 + r); /* mov $xx, r */ o(0xb8 + r); /* mov $xx, r */
gen_addr32(fr, fc); gen_addr32(fr, fc);
} else if (v == VT_LOCAL) { } else if (v == VT_LOCAL) {
o(0x8d); o(0x8d); /* lea xxx(%ebp), r */
oad(0x85 + r * 8, fc); /* lea xxx(%ebp), r */ gen_modrm(r, VT_LOCAL, fc);
} else if (v == VT_CMP) { } else if (v == VT_CMP) {
oad(0xb8 + r, 0); /* mov $0, r */ oad(0xb8 + r, 0); /* mov $0, r */
o(0x0f); /* setxx %br */ o(0x0f); /* setxx %br */
@ -247,8 +239,7 @@ void store(int r, SValue *v)
fc = v->c.ul; fc = v->c.ul;
fr = v->r & VT_VALMASK; fr = v->r & VT_VALMASK;
bt = ft & VT_BTYPE; bt = ft & VT_BTYPE;
/* XXX: incorrect if reg to reg */ /* XXX: incorrect if float reg to reg */
/* XXX: should not flush float stack */
if (bt == VT_FLOAT) { if (bt == VT_FLOAT) {
o(0xd9); /* fsts */ o(0xd9); /* fsts */
r = 2; r = 2;
@ -267,13 +258,10 @@ void store(int r, SValue *v)
else else
o(0x89); o(0x89);
} }
if (fr == VT_CONST) { if (fr == VT_CONST ||
o(0x05 + r * 8); /* mov r,xxx */ fr == VT_LOCAL ||
gen_addr32(v->r, fc); (v->r & VT_LVAL)) {
} else if (fr == VT_LOCAL) { gen_modrm(r, v->r, fc);
oad(0x85 + r * 8, fc); /* mov r,xxx(%ebp) */
} else if (v->r & VT_LVAL) {
g(fr + r * 8); /* mov r, (fr) */
} else if (fr != r) { } else if (fr != r) {
o(0xc0 + fr + r * 8); /* mov r, fr */ o(0xc0 + fr + r * 8); /* mov r, fr */
} }
@ -298,7 +286,7 @@ void gfunc_param(GFuncContext *c)
/* allocate the necessary size on stack */ /* allocate the necessary size on stack */
oad(0xec81, size); /* sub $xxx, %esp */ oad(0xec81, size); /* sub $xxx, %esp */
/* generate structure store */ /* generate structure store */
r = get_reg(REG_CLASS_INT); r = get_reg(RC_INT);
o(0x89); /* mov %esp, r */ o(0x89); /* mov %esp, r */
o(0xe0 + r); o(0xe0 + r);
vset(VT_INT, r, 0); vset(VT_INT, r, 0);
@ -306,7 +294,7 @@ void gfunc_param(GFuncContext *c)
vstore(); vstore();
c->args_size += size; c->args_size += size;
} else if (is_float(vtop->t)) { } else if (is_float(vtop->t)) {
gv(); /* only one float register */ gv(RC_FLOAT); /* only one float register */
if ((vtop->t & VT_BTYPE) == VT_FLOAT) if ((vtop->t & VT_BTYPE) == VT_FLOAT)
size = 4; size = 4;
else if ((vtop->t & VT_BTYPE) == VT_DOUBLE) else if ((vtop->t & VT_BTYPE) == VT_DOUBLE)
@ -324,7 +312,7 @@ void gfunc_param(GFuncContext *c)
} else { } else {
/* simple type (currently always same size) */ /* simple type (currently always same size) */
/* XXX: implicit cast ? */ /* XXX: implicit cast ? */
r = gv(); r = gv(RC_INT);
o(0x50 + r); /* push r */ o(0x50 + r); /* push r */
c->args_size += 4; c->args_size += 4;
} }
@ -347,7 +335,7 @@ void gfunc_call(GFuncContext *c)
} }
} else { } else {
/* otherwise, indirect call */ /* otherwise, indirect call */
r = gv(); r = gv(RC_INT);
o(0xff); /* call *r */ o(0xff); /* call *r */
o(0xd0 + r); o(0xd0 + r);
} }
@ -383,17 +371,22 @@ int gtst(int inv, int t)
t = gjmp(t); t = gjmp(t);
gsym(vtop->c.i); gsym(vtop->c.i);
} }
} else if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* constant jmp optimization */
if ((vtop->c.i != 0) != inv)
t = gjmp(t);
} else { } else {
/* XXX: floats */ if (is_float(vtop->t)) {
v = gv(); vpushi(0);
o(0x85); gen_op(TOK_NE);
o(0xc0 + v * 9); }
g(0x0f); if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
t = psym(0x85 ^ inv, t); /* constant jmp optimization */
if ((vtop->c.i != 0) != inv)
t = gjmp(t);
} else {
v = gv(RC_INT);
o(0x85);
o(0xc0 + v * 9);
g(0x0f);
t = psym(0x85 ^ inv, t);
}
} }
vtop--; vtop--;
return t; return t;
@ -405,9 +398,9 @@ void gen_opi(int op)
int t, r, fr; int t, r, fr;
vswap(); vswap();
r = gv(); r = gv(RC_INT);
vswap(); vswap();
fr = gv(); fr = gv(RC_INT);
vtop--; vtop--;
if (op == '+') { if (op == '+') {
@ -460,9 +453,9 @@ void gen_opi(int op)
oad(0xbd, t); oad(0xbd, t);
} }
if (op == '%' | op == TOK_UMOD) if (op == '%' | op == TOK_UMOD)
r = 2; r = REG_EDX;
else else
r = 0; r = REG_EAX;
vtop->r = r; vtop->r = r;
} else { } else {
vtop--; vtop--;
@ -477,22 +470,22 @@ void gen_opi(int op)
/* NOTE: currently floats can only be lvalues */ /* NOTE: currently floats can only be lvalues */
void gen_opf(int op) void gen_opf(int op)
{ {
int a, ft, fc, swapped, r; int a, ft, fc, swapped;
/* convert constants to memory references */ /* convert constants to memory references */
if ((vtop[-1].r & (VT_CONST | VT_LVAL)) == VT_CONST) { if ((vtop[-1].r & (VT_CONST | VT_LVAL)) == VT_CONST) {
vswap(); vswap();
gv(); gv(RC_FLOAT);
vswap(); vswap();
} }
if ((vtop[0].r & (VT_CONST | VT_LVAL)) == VT_CONST) if ((vtop[0].r & (VT_CONST | VT_LVAL)) == VT_CONST)
gv(); gv(RC_FLOAT);
/* must put at least one value in the floating point register */ /* must put at least one value in the floating point register */
if ((vtop[-1].r & VT_LVAL) && if ((vtop[-1].r & VT_LVAL) &&
(vtop[0].r & VT_LVAL)) { (vtop[0].r & VT_LVAL)) {
vswap(); vswap();
gv(); gv(RC_FLOAT);
vswap(); vswap();
} }
if (op >= TOK_EQ && op <= TOK_GT) { if (op >= TOK_EQ && op <= TOK_GT) {
@ -520,13 +513,18 @@ void gen_opf(int op)
vtop->r = VT_CMP; vtop->r = VT_CMP;
vtop->c.i = op; vtop->c.i = op;
} else { } else {
swapped = 0;
/* swap the stack if needed so that t1 is the register and t2 is /* swap the stack if needed so that t1 is the register and t2 is
the memory reference */ the memory reference */
swapped = 0;
if (vtop[-1].r & VT_LVAL) { if (vtop[-1].r & VT_LVAL) {
vswap(); vswap();
swapped = 1; swapped = 1;
} }
/* no memory reference possible for long double operations */
if ((vtop->t & VT_BTYPE) == VT_LDOUBLE) {
load(REG_ST0, vtop);
swapped = !swapped;
}
switch(op) { switch(op) {
default: default:
@ -534,34 +532,30 @@ void gen_opf(int op)
a = 0; a = 0;
break; break;
case '-': case '-':
a = 0x20; a = 4;
if (swapped) if (swapped)
a += 8; a++;
break; break;
case '*': case '*':
a = 0x08; a = 1;
break; break;
case '/': case '/':
a = 0x30; a = 6;
if (swapped) if (swapped)
a += 8; a++;
break; break;
} }
ft = vtop->t; ft = vtop->t;
fc = vtop->c.ul; fc = vtop->c.ul;
if ((ft & VT_BTYPE) == VT_DOUBLE) if ((ft & VT_BTYPE) == VT_LDOUBLE) {
o(0xdc); o(0xde); /* fxxxp %st, %st(1) */
else o(0xc1 + (a << 3));
o(0xd8);
r = vtop->r & VT_VALMASK;
if (r == VT_CONST) {
o(0x05 + a);
gen_addr32(vtop->r, fc);
} else if (r == VT_LOCAL) {
oad(0x85 + a, fc);
} else { } else {
g(0x00 + a + r); if ((ft & VT_BTYPE) == VT_DOUBLE)
o(0xdc);
else
o(0xd8);
gen_modrm(a, vtop->r, fc);
} }
vtop--; vtop--;
} }
@ -570,7 +564,7 @@ void gen_opf(int op)
/* convert integers to fp 't' type */ /* convert integers to fp 't' type */
void gen_cvt_itof(int t) void gen_cvt_itof(int t)
{ {
gv(); gv(RC_INT);
if ((vtop->t & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) { if ((vtop->t & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) {
/* unsigned int to float/double/long double */ /* unsigned int to float/double/long double */
o(0x6a); /* push $0 */ o(0x6a); /* push $0 */
@ -599,7 +593,7 @@ void gen_cvt_ftoi(int t)
{ {
int r, size; int r, size;
gv(); gv(RC_FLOAT);
if (t == VT_INT | VT_UNSIGNED && if (t == VT_INT | VT_UNSIGNED &&
t == VT_LLONG | VT_UNSIGNED && t == VT_LLONG | VT_UNSIGNED &&
t == VT_LLONG) t == VT_LLONG)
@ -607,7 +601,7 @@ void gen_cvt_ftoi(int t)
else else
size = 4; size = 4;
r = get_reg(REG_CLASS_INT); r = get_reg(RC_INT);
oad(0x2dd9, (int)&__tcc_int_fpu_control); /* ldcw xxx */ oad(0x2dd9, (int)&__tcc_int_fpu_control); /* ldcw xxx */
oad(0xec81, size); /* sub $xxx, %esp */ oad(0xec81, size); /* sub $xxx, %esp */
if (size == 4) if (size == 4)
@ -626,7 +620,7 @@ void gen_cvt_ftoi(int t)
void gen_cvt_ftof(int t) void gen_cvt_ftof(int t)
{ {
/* all we have to do on i386 is to put the float in a register */ /* all we have to do on i386 is to put the float in a register */
gv(); gv(RC_FLOAT);
} }
/* pop stack value */ /* pop stack value */

113
tcc.c
View File

@ -340,7 +340,7 @@ void gexpr(void);
void decl(int l); void decl(int l);
void decl_initializer(int t, int r, int c, int first, int size_only); void decl_initializer(int t, int r, int c, int first, int size_only);
int decl_initializer_alloc(int t, int sec, int has_init); int decl_initializer_alloc(int t, int sec, int has_init);
int gv(void); int gv(int rc);
void move_reg(int r, int s); void move_reg(int r, int s);
void save_reg(int r); void save_reg(int r);
void vpop(void); void vpop(void);
@ -360,7 +360,9 @@ int pointed_size(int t);
int parse_btype(int *type_ptr); int parse_btype(int *type_ptr);
int type_decl(int *v, int t, int td); int type_decl(int *v, int t, int td);
void error(const char *fmt, ...); void error(const char *fmt, ...);
void vpushi(int v);
void vset(int t, int r, int v); void vset(int t, int r, int v);
void greloc(Sym *s, int addr, int type);
/* true if float/double/long double type */ /* true if float/double/long double type */
static inline int is_float(int t) static inline int is_float(int t)
@ -419,6 +421,36 @@ void *dlsym(void *handle, char *symbol)
#endif #endif
/* add a new relocation entry to symbol 's' */
void greloc(Sym *s, int addr, int type)
{
Reloc *p;
p = malloc(sizeof(Reloc));
if (!p)
error("memory full");
p->type = type;
p->addr = addr;
p->next = (Reloc *)s->c;
s->c = (int)p;
}
/* patch each relocation entry with value 'val' */
void greloc_patch(Sym *s, int val)
{
Reloc *p, *p1;
p = (Reloc *)s->c;
while (p != NULL) {
p1 = p->next;
greloc_patch1(p, val);
free(p);
p = p1;
}
s->c = val;
s->r &= ~VT_FORWARD;
}
static inline int isid(int c) static inline int isid(int c)
{ {
return (c >= 'a' && c <= 'z') || return (c >= 'a' && c <= 'z') ||
@ -1884,7 +1916,7 @@ void vsetc(int t, int r, CValue *vc)
/* cannot let cpu flags if other instruction are generated */ /* cannot let cpu flags if other instruction are generated */
/* XXX: VT_JMP test too ? */ /* XXX: VT_JMP test too ? */
if ((vtop->r & VT_VALMASK) == VT_CMP) if ((vtop->r & VT_VALMASK) == VT_CMP)
gv(); gv(RC_INT);
vtop++; vtop++;
vtop->t = t; vtop->t = t;
vtop->r = r; vtop->r = r;
@ -2028,12 +2060,12 @@ void move_reg(int r, int s)
} }
} }
/* convert a (vtop->t, vtop->c) in register. lvalues are converted as /* store vtop a register belonging to class 'rc'. lvalues are
values. Cannot be used if cannot be converted to register value converted as values. Cannot be used if cannot be converted to
(such as structures). */ register value (such as structures). */
int gv(void) int gv(int rc)
{ {
int r, bit_pos, bit_size, rc, size, align, i; int r, bit_pos, bit_size, size, align, i;
/* NOTE: get_reg can modify vstack[] */ /* NOTE: get_reg can modify vstack[] */
if (vtop->t & VT_BITFIELD) { if (vtop->t & VT_BITFIELD) {
@ -2047,7 +2079,7 @@ int gv(void)
vpushi(32 - bit_size); vpushi(32 - bit_size);
/* NOTE: transformed to SHR if unsigned */ /* NOTE: transformed to SHR if unsigned */
gen_op(TOK_SAR); gen_op(TOK_SAR);
r = gv(); r = gv(rc);
} else { } else {
if (is_float(vtop->t) && if (is_float(vtop->t) &&
(vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
@ -2064,14 +2096,16 @@ int gv(void)
glo += size << 2; glo += size << 2;
} }
r = vtop->r & VT_VALMASK; r = vtop->r & VT_VALMASK;
if (r >= VT_CONST || (vtop->r & VT_LVAL)) { /* need to reload if:
if (is_float(vtop->t)) - constant
rc = REG_CLASS_FLOAT; - lvalue (need to dereference pointer)
else - already a register, but not in the right class */
rc = REG_CLASS_INT; if (r >= VT_CONST ||
(vtop->r & VT_LVAL) ||
!(reg_classes[r] & rc)) {
r = get_reg(rc); r = get_reg(rc);
load(r, vtop);
} }
load(r, vtop);
vtop->r = r; vtop->r = r;
} }
return r; return r;
@ -2620,7 +2654,7 @@ void gen_assign_cast(int dt)
/* store vtop in lvalue pushed on stack */ /* store vtop in lvalue pushed on stack */
void vstore(void) void vstore(void)
{ {
int ft, r, t, size, align, bit_size, bit_pos; int ft, r, t, size, align, bit_size, bit_pos, rc;
GFuncContext gf; GFuncContext gf;
ft = vtop[-1].t; ft = vtop[-1].t;
@ -2675,11 +2709,14 @@ void vstore(void)
/* store result */ /* store result */
vstore(); vstore();
} else { } else {
r = gv(); /* generate value */ rc = RC_INT;
if (is_float(ft))
rc = RC_FLOAT;
r = gv(rc); /* generate value (XXX: move that to store code) */
/* if lvalue was saved on stack, must read it */ /* if lvalue was saved on stack, must read it */
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
SValue sv; SValue sv;
t = get_reg(REG_CLASS_INT); t = get_reg(RC_INT);
sv.t = VT_INT; sv.t = VT_INT;
sv.r = VT_LOCAL | VT_LVAL; sv.r = VT_LOCAL | VT_LVAL;
sv.c.ul = vtop[-1].c.ul; sv.c.ul = vtop[-1].c.ul;
@ -2696,19 +2733,24 @@ void vstore(void)
/* post defines POST/PRE add. c is the token ++ or -- */ /* post defines POST/PRE add. c is the token ++ or -- */
void inc(int post, int c) void inc(int post, int c)
{ {
int r, r1; int r, r1, rc, t;
SValue sv; SValue sv;
test_lvalue(); test_lvalue();
if (post) if (post)
vdup(); /* room for returned value */ vdup(); /* room for returned value */
vdup(); /* save lvalue */ vdup(); /* save lvalue */
r = gv();
if (post) { if (post) {
/* duplicate value */ /* duplicate value */
/* XXX: handle floats */ rc = RC_INT;
r1 = get_reg(REG_CLASS_INT);
sv.t = VT_INT; sv.t = VT_INT;
t = vtop->t & VT_TYPE;
if (is_float(t)) {
rc = RC_FLOAT;
sv.t = t;
}
r = gv(rc);
r1 = get_reg(rc);
sv.r = r; sv.r = r;
sv.c.ul = 0; sv.c.ul = 0;
load(r1, &sv); /* move r to r1 */ load(r1, &sv); /* move r to r1 */
@ -3137,10 +3179,10 @@ Sym *external_sym(int v, int u, int r)
void indir(void) void indir(void)
{ {
if (vtop->r & VT_LVAL)
gv();
if ((vtop->t & VT_BTYPE) != VT_PTR) if ((vtop->t & VT_BTYPE) != VT_PTR)
expect("pointer"); expect("pointer");
if (vtop->r & VT_LVAL)
gv(RC_INT);
vtop->t = pointed_type(vtop->t); vtop->t = pointed_type(vtop->t);
if (!(vtop->t & VT_ARRAY)) /* an array is never an lvalue */ if (!(vtop->t & VT_ARRAY)) /* an array is never an lvalue */
vtop->r |= VT_LVAL; vtop->r |= VT_LVAL;
@ -3442,7 +3484,11 @@ void unary(void)
gfunc_param(&gf); gfunc_param(&gf);
} else { } else {
ret.t = s->t; ret.t = s->t;
ret.r = FUNC_RET_REG; /* return in register */ /* return in register */
if (is_float(ret.t))
ret.r = REG_FRET;
else
ret.r = REG_IRET;
ret.c.i = 0; ret.c.i = 0;
} }
#ifndef INVERT_FUNC_PARAMS #ifndef INVERT_FUNC_PARAMS
@ -3561,7 +3607,7 @@ void eor(void)
/* XXX: better constant handling */ /* XXX: better constant handling */
void expr_eq(void) void expr_eq(void)
{ {
int t, u, c, r1, r2; int t, u, c, r1, r2, rc;
if (const_wanted) { if (const_wanted) {
sum(10); sum(10);
@ -3582,16 +3628,19 @@ void expr_eq(void)
if (tok == '?') { if (tok == '?') {
next(); next();
t = gtst(1, 0); t = gtst(1, 0);
gexpr(); gexpr();
r1 = gv(); /* XXX: float handling ? */
rc = RC_INT;
if (is_float(vtop->t))
rc = RC_FLOAT;
r1 = gv(rc);
vpop(); vpop();
skip(':'); skip(':');
u = gjmp(0); u = gjmp(0);
gsym(t); gsym(t);
expr_eq(); expr_eq();
r2 = gv(); r2 = gv(rc);
move_reg(r1, r2); move_reg(r1, r2);
vtop->r = r1; vtop->r = r1;
gsym(u); gsym(u);
@ -3718,11 +3767,9 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
/* copy structure value to pointer */ /* copy structure value to pointer */
vstore(); vstore();
} else if (is_float(func_vt)) { } else if (is_float(func_vt)) {
/* move return value to float return register */ gv(RC_FRET);
move_reg(FUNC_RET_FREG, gv());
} else { } else {
/* move return value to standard return register */ gv(RC_IRET);
move_reg(FUNC_RET_REG, gv());
} }
vpop(); vpop();
} }
@ -3794,7 +3841,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
next(); next();
skip('('); skip('(');
gexpr(); gexpr();
case_reg = gv(); case_reg = gv(RC_INT);
vpop(); vpop();
skip(')'); skip(')');
a = 0; a = 0;