Skip to content
This repository was archived by the owner on Nov 22, 2023. It is now read-only.

Commit c29420a

Browse files
author
grischka
committed
tccgen: update "Fix invalid load generated by gfunc_return()"
tccgen.c: - new function incr_offset(int) to increment a lvalue - use it in gv/vstore to load/store from/to two-word types - use it to advance the pointer to struct fields - use it to load/store structs passed in registers - structs: always assume that reg-classes of registers are 2^n - adjust stack space when regsize > sizeof the_struct x86_64-gen.c: - return regsize=16 for VT_QLONG/QFLOAT i386-gen.c: - pass structs of size(8) as two VT_INT rather than one VT_LLONG (both should work now) fixes a82aff3 fixes fd6d218 (slightly)
1 parent 022fb42 commit c29420a

File tree

5 files changed

+154
-100
lines changed

5 files changed

+154
-100
lines changed

i386-gen.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@
3131
#define RC_INT 0x0001 /* generic integer register */
3232
#define RC_FLOAT 0x0002 /* generic float register */
3333
#define RC_EAX 0x0004
34-
#define RC_ST0 0x0008
34+
#define RC_EDX 0x0008
3535
#define RC_ECX 0x0010
36-
#define RC_EDX 0x0020
37-
#define RC_EBX 0x0040
36+
#define RC_EBX 0x0020
37+
#define RC_ST0 0x0040
3838

3939
#define RC_IRET RC_EAX /* function return: integer register */
4040
#define RC_IRE2 RC_EDX /* function return: second integer register */
@@ -380,22 +380,23 @@ static const uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
380380
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
381381
{
382382
#if defined(TCC_TARGET_PE) || TARGETOS_FreeBSD || TARGETOS_OpenBSD
383-
int size, align;
383+
int size, align, nregs;
384384
*ret_align = 1; // Never have to re-align return values for x86
385385
*regsize = 4;
386386
size = type_size(vt, &align);
387387
if (size > 8 || (size & (size - 1)))
388388
return 0;
389+
nregs = 1;
389390
if (size == 8)
390-
ret->t = VT_LLONG;
391+
ret->t = VT_INT, nregs = 2;
391392
else if (size == 4)
392393
ret->t = VT_INT;
393394
else if (size == 2)
394395
ret->t = VT_SHORT;
395396
else
396397
ret->t = VT_BYTE;
397398
ret->ref = NULL;
398-
return 1;
399+
return nregs;
399400
#else
400401
*ret_align = 1; // Never have to re-align return values for x86
401402
return 0;

tccgen.c

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,14 +1687,22 @@ static void pop_local_syms(Sym *b, int keep)
16871687
sym_pop(&local_stack, b, keep);
16881688
}
16891689

1690-
static void incr_bf_adr(int o)
1690+
/* increment an lvalue pointer */
1691+
static void incr_offset(int offset)
16911692
{
1692-
vtop->type = char_pointer_type;
1693-
gaddrof();
1694-
vpushs(o);
1693+
int t = vtop->type.t;
1694+
gaddrof(); /* remove VT_LVAL */
1695+
vtop->type.t = VT_PTRDIFF_T; /* set scalar type */
1696+
vpushs(offset);
16951697
gen_op('+');
1696-
vtop->type.t = VT_BYTE | VT_UNSIGNED;
16971698
vtop->r |= VT_LVAL;
1699+
vtop->type.t = t;
1700+
}
1701+
1702+
static void incr_bf_adr(int o)
1703+
{
1704+
vtop->type.t = VT_BYTE | VT_UNSIGNED;
1705+
incr_offset(o);
16981706
}
16991707

17001708
/* single-byte load mode for packed or otherwise unaligned bitfields */
@@ -1860,8 +1868,18 @@ ST_FUNC int gv(int rc)
18601868
r2_ok = !rc2 || ((vtop->r2 < VT_CONST) && (reg_classes[vtop->r2] & rc2));
18611869

18621870
if (!r_ok || !r2_ok) {
1863-
if (!r_ok)
1864-
r = get_reg(rc);
1871+
1872+
if (!r_ok) {
1873+
if (1 /* we can 'mov (r),r' in cases */
1874+
&& r < VT_CONST
1875+
&& (reg_classes[r] & rc)
1876+
&& !rc2
1877+
)
1878+
save_reg_upstack(r, 1);
1879+
else
1880+
r = get_reg(rc);
1881+
}
1882+
18651883
if (rc2) {
18661884
int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T;
18671885
int original_type = vtop->type.t;
@@ -1885,12 +1903,7 @@ ST_FUNC int gv(int rc)
18851903
vdup();
18861904
vtop[-1].r = r; /* save register value */
18871905
/* increment pointer to get second word */
1888-
vtop->type.t = VT_PTRDIFF_T;
1889-
gaddrof();
1890-
vpushs(PTR_SIZE);
1891-
gen_op('+');
1892-
vtop->r |= VT_LVAL;
1893-
vtop->type.t = load_type;
1906+
incr_offset(PTR_SIZE);
18941907
} else {
18951908
/* move registers */
18961909
if (!r_ok)
@@ -3748,14 +3761,8 @@ ST_FUNC void vstore(void)
37483761
vtop[-1].type.t = load_type;
37493762
store(r, vtop - 1);
37503763
vswap();
3751-
/* convert to int to increment easily */
3752-
vtop->type.t = VT_PTRDIFF_T;
3753-
gaddrof();
3754-
vpushs(PTR_SIZE);
3755-
gen_op('+');
3756-
vtop->r |= VT_LVAL;
3764+
incr_offset(PTR_SIZE);
37573765
vswap();
3758-
vtop[-1].type.t = load_type;
37593766
/* XXX: it works because r2 is spilled last ! */
37603767
store(vtop->r2, vtop - 1);
37613768
} else {
@@ -6003,7 +6010,6 @@ ST_FUNC void unary(void)
60036010
indir();
60046011
qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE);
60056012
test_lvalue();
6006-
gaddrof();
60076013
/* expect pointer on structure */
60086014
if ((vtop->type.t & VT_BTYPE) != VT_STRUCT)
60096015
expect("struct or union");
@@ -6014,16 +6020,15 @@ ST_FUNC void unary(void)
60146020
expect("field name");
60156021
s = find_field(&vtop->type, tok, &cumofs);
60166022
/* add field offset to pointer */
6017-
vtop->type = char_pointer_type; /* change type to 'char *' */
6018-
vpushi(cumofs);
6019-
gen_op('+');
6023+
incr_offset(cumofs);
60206024
/* change type to field type, and set to lvalue */
60216025
vtop->type = s->type;
60226026
vtop->type.t |= qualifiers;
60236027
/* an array is never an lvalue */
6024-
if (!(vtop->type.t & VT_ARRAY)) {
6025-
vtop->r |= VT_LVAL;
6028+
if (vtop->type.t & VT_ARRAY) {
6029+
vtop->r &= ~VT_LVAL;
60266030
#ifdef CONFIG_TCC_BCHECK
6031+
} else {
60276032
/* if bound checking, the referenced pointer must be checked */
60286033
if (tcc_state->do_bounds_check)
60296034
vtop->r |= VT_MUSTBOUND;
@@ -6128,10 +6133,20 @@ ST_FUNC void unary(void)
61286133
#endif
61296134
} else {
61306135
/* return value */
6131-
for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) {
6136+
n = ret_nregs;
6137+
while (n > 1) {
6138+
int rc = reg_classes[ret.r] & ~(RC_INT | RC_FLOAT);
6139+
/* We assume that when a structure is returned in multiple
6140+
registers, their classes are consecutive values of the
6141+
suite s(n) = 2^n */
6142+
rc <<= --n;
6143+
for (r = 0; r < NB_REGS; ++r)
6144+
if (reg_classes[r] & rc)
6145+
break;
61326146
vsetc(&ret.type, r, &ret.c);
6133-
vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */
61346147
}
6148+
vsetc(&ret.type, ret.r, &ret.c);
6149+
vtop->r2 = ret.r2;
61356150

61366151
/* handle packed struct return */
61376152
if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {
@@ -6140,9 +6155,9 @@ ST_FUNC void unary(void)
61406155
size = type_size(&s->type, &align);
61416156
/* We're writing whole regs often, make sure there's enough
61426157
space. Assume register size is power of 2. */
6143-
if (regsize > align)
6144-
align = regsize;
6145-
loc &= -align;
6158+
size = (size + regsize - 1) & -regsize;
6159+
if (ret_align > align)
6160+
align = ret_align;
61466161
loc = (loc - size) & -align;
61476162
addr = loc;
61486163
offset = 0;
@@ -6619,11 +6634,12 @@ static void gfunc_return(CType *func_type)
66196634
vstore();
66206635
} else {
66216636
/* returning structure packed into registers */
6622-
int size, addr, align, rc;
6637+
int size, addr, align, rc, n;
66236638
size = type_size(func_type,&align);
6624-
if ((vtop->r != (VT_LOCAL | VT_LVAL) ||
6625-
(vtop->c.i & (ret_align-1)))
6626-
&& (align & (ret_align-1))) {
6639+
if ((align & (ret_align - 1))
6640+
&& ((vtop->r & VT_VALMASK) < VT_CONST /* pointer to struct */
6641+
|| (vtop->c.i & (ret_align - 1))
6642+
)) {
66276643
loc = (loc - size) & -ret_align;
66286644
addr = loc;
66296645
type = *func_type;
@@ -6635,22 +6651,19 @@ static void gfunc_return(CType *func_type)
66356651
}
66366652
vtop->type = ret_type;
66376653
rc = RC_RET(ret_type.t);
6638-
if (ret_nregs == 1)
6654+
//printf("struct return: n:%d t:%02x rc:%02x\n", ret_nregs, ret_type.t, rc);
6655+
for (n = ret_nregs; --n > 0;) {
6656+
vdup();
66396657
gv(rc);
6640-
else {
6641-
for (;;) {
6642-
vdup();
6643-
gv(rc);
6644-
vpop();
6645-
if (--ret_nregs == 0)
6646-
break;
6647-
/* We assume that when a structure is returned in multiple
6648-
registers, their classes are consecutive values of the
6649-
suite s(n) = 2^n */
6650-
rc <<= 1;
6651-
vtop->c.i += regsize;
6652-
}
6658+
vswap();
6659+
incr_offset(regsize);
6660+
/* We assume that when a structure is returned in multiple
6661+
registers, their classes are consecutive values of the
6662+
suite s(n) = 2^n */
6663+
rc <<= 1;
66536664
}
6665+
gv(rc);
6666+
vtop -= ret_nregs - 1;
66546667
}
66556668
} else {
66566669
gv(RC_RET(func_type->t));
Lines changed: 59 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,70 @@
11
#include<stdio.h>
22

3-
#define DATA 0x1234567890abcdll, 0x5a5aa5a5f0f00f0fll
3+
struct s1 {
4+
unsigned char a:4, b:4;
5+
} g1 = { 0x05, 0x0a };
46

5-
struct s {
6-
long long int a;
7-
long long int b;
8-
};
7+
struct s2 {
8+
unsigned char a, b;
9+
} g2 = { 0x12, 0x34 };
910

10-
struct {
11-
struct s d;
12-
} g = { { DATA } }, *gp = &g;
11+
struct s4 {
12+
unsigned short a, b;
13+
} g4 = { 0x1245, 0x5678 };
1314

14-
struct s
15-
foo1(void)
16-
{
17-
struct s d = { DATA };
18-
struct s *p = &d;
19-
long long int x = 0;
20-
return *p;
21-
}
15+
struct s8 {
16+
unsigned a, b;
17+
} g8 = { 0x12345678, 0x9abcdef0 };
2218

23-
struct s
24-
foo2(void)
25-
{
26-
long long int unused = 0;
27-
return gp->d;
28-
}
19+
/* returned in 2 registers on riscv64 */
20+
struct s16 {
21+
unsigned long long a, b;
22+
} g16 = { 0x123456789abcdef0ULL, 0xfedcba9876543210ULL };
2923

30-
struct s
31-
foo3(void)
32-
{
33-
struct s d = { DATA };
34-
long long int unused = 0;
35-
return d;
24+
/* Homogeneous float aggregate on ARM hard-float */
25+
struct s_f4 {
26+
double a, b, c, d;
27+
} g_f4 = { 1,2,3,4 };
28+
29+
#define def(S) \
30+
struct s##S f##S(int x) \
31+
{ \
32+
struct s##S l##S = g##S, *p##S = &l##S; \
33+
if (x == 0) \
34+
return g##S; \
35+
else if (x == 1) \
36+
return l##S; \
37+
else \
38+
return *p##S; \
3639
}
3740

38-
int
39-
main(void)
41+
def(1)
42+
def(2)
43+
def(4)
44+
def(8)
45+
def(16)
46+
def(_f4)
47+
48+
#define chk(S,x) \
49+
struct s##S l##S = f##S(x); \
50+
printf("%02llx %02llx\n", \
51+
(unsigned long long)l##S.a, \
52+
(unsigned long long)l##S.b \
53+
);
54+
55+
int main()
4056
{
41-
struct s d;
42-
d = foo1();
43-
printf("%llx %llx\n", d.a, d.b);
44-
d = foo2();
45-
printf("%llx %llx\n", d.a, d.b);
46-
d = foo3();
47-
printf("%llx %llx\n", d.a, d.b);
48-
return 0;
57+
for (int x = 0;;) {
58+
chk(1,x);
59+
chk(2,x);
60+
chk(4,x);
61+
chk(8,x);
62+
chk(16,x);
63+
struct s_f4 l_f4 = f_f4(x);
64+
printf("%.1f %.1f %.1f %.1f\n", l_f4.a, l_f4.b, l_f4.c, l_f4.d);
65+
if (++x > 2)
66+
break;
67+
printf("\n");
68+
}
69+
return 0;
4970
}
Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1-
1234567890abcd 5a5aa5a5f0f00f0f
2-
1234567890abcd 5a5aa5a5f0f00f0f
3-
1234567890abcd 5a5aa5a5f0f00f0f
1+
05 0a
2+
12 34
3+
1245 5678
4+
12345678 9abcdef0
5+
123456789abcdef0 fedcba9876543210
6+
1.0 2.0 3.0 4.0
7+
8+
05 0a
9+
12 34
10+
1245 5678
11+
12345678 9abcdef0
12+
123456789abcdef0 fedcba9876543210
13+
1.0 2.0 3.0 4.0
14+
15+
05 0a
16+
12 34
17+
1245 5678
18+
12345678 9abcdef0
19+
123456789abcdef0 fedcba9876543210
20+
1.0 2.0 3.0 4.0

x86_64-gen.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
#define RC_INT 0x0001 /* generic integer register */
3434
#define RC_FLOAT 0x0002 /* generic float register */
3535
#define RC_RAX 0x0004
36-
#define RC_RCX 0x0008
37-
#define RC_RDX 0x0010
36+
#define RC_RDX 0x0008
37+
#define RC_RCX 0x0010
3838
#define RC_RSI 0x0020
3939
#define RC_RDI 0x0040
4040
#define RC_ST0 0x0080 /* only for long double */
@@ -1223,9 +1223,11 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty)
12231223
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
12241224
{
12251225
int size, align, reg_count;
1226+
if (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) == x86_64_mode_memory)
1227+
return 0;
12261228
*ret_align = 1; // Never have to re-align return values for x86-64
1227-
*regsize = 8;
1228-
return (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) != x86_64_mode_memory);
1229+
*regsize = 8 * reg_count; /* the (virtual) regsize is 16 for VT_QLONG/QFLOAT */
1230+
return 1;
12291231
}
12301232

12311233
#define REGN 6

0 commit comments

Comments
 (0)