History

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 a82aff333774f3bd38841d3c167f1add8c473c1c fixes fd6d2180c5c801bb0b4c5dde27d61503059fc97d (slightly)

grischka committed 3 years ago

Commit c29420a1 parent 022fb425 files · +154 −100Browse files

Unified · Split

5 files
  1. i386-gen.c +7 −6
  2. tccgen.c +62 −49
  3. tests/tests2/131_return_struct_in_reg.c +59 −38
  4. tests/tests2/131_return_struct_in_reg.expect +20 −3
  5. x86_64-gen.c +6 −4
i386-gen.c+7−6
@@ -31,10 +31,10 @@ · 30 unmodified lines
31#define RC_INT 0x0001 /* generic integer register */31#define RC_INT 0x0001 /* generic integer register */
32#define RC_FLOAT 0x0002 /* generic float register */32#define RC_FLOAT 0x0002 /* generic float register */
33#define RC_EAX 0x000433#define RC_EAX 0x0004
34#define RC_ST0 0x0008 34#define RC_EDX 0x0008
35#define RC_ECX 0x001035#define RC_ECX 0x0010
36#define RC_EDX 0x002036#define RC_EBX 0x0020
37#define RC_EBX 0x004037#define RC_ST0 0x0040
38 38
39#define RC_IRET RC_EAX /* function return: integer register */39#define RC_IRET RC_EAX /* function return: integer register */
40#define RC_IRE2 RC_EDX /* function return: second integer register */40#define RC_IRE2 RC_EDX /* function return: second integer register */
@@ -380,14 +380,15 @@ static const uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX }; · 339 unmodified lines
380ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)380ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
381{381{
382#if defined(TCC_TARGET_PE) || TARGETOS_FreeBSD || TARGETOS_OpenBSD382#if defined(TCC_TARGET_PE) || TARGETOS_FreeBSD || TARGETOS_OpenBSD
383 int size, align;383 int size, align, nregs;
384 *ret_align = 1; // Never have to re-align return values for x86384 *ret_align = 1; // Never have to re-align return values for x86
385 *regsize = 4;385 *regsize = 4;
386 size = type_size(vt, &align);386 size = type_size(vt, &align);
387 if (size > 8 || (size & (size - 1)))387 if (size > 8 || (size & (size - 1)))
388 return 0;388 return 0;
389 nregs = 1;
389 if (size == 8)390 if (size == 8)
390 ret->t = VT_LLONG;391 ret->t = VT_INT, nregs = 2;
391 else if (size == 4)392 else if (size == 4)
392 ret->t = VT_INT;393 ret->t = VT_INT;
393 else if (size == 2)394 else if (size == 2)
@@ -395,7 +396,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int · 1 unmodified line
395 else396 else
396 ret->t = VT_BYTE;397 ret->t = VT_BYTE;
397 ret->ref = NULL;398 ret->ref = NULL;
398 return 1;399 return nregs;
399#else400#else
400 *ret_align = 1; // Never have to re-align return values for x86401 *ret_align = 1; // Never have to re-align return values for x86
401 return 0;402 return 0;
tccgen.c+62−49
@@ -1687,14 +1687,22 @@ static void pop_local_syms(Sym *b, int keep) · 1686 unmodified lines
1687 sym_pop(&local_stack, b, keep);1687 sym_pop(&local_stack, b, keep);
1688}1688}
1689 1689
1690static void incr_bf_adr(int o)1690/* increment an lvalue pointer */
1691static void incr_offset(int offset)
1691{1692{
1692 vtop->type = char_pointer_type;1693 int t = vtop->type.t;
1693 gaddrof();1694 gaddrof(); /* remove VT_LVAL */
1694 vpushs(o);1695 vtop->type.t = VT_PTRDIFF_T; /* set scalar type */
1696 vpushs(offset);
1695 gen_op('+');1697 gen_op('+');
1696 vtop->type.t = VT_BYTE | VT_UNSIGNED;
1697 vtop->r |= VT_LVAL;1698 vtop->r |= VT_LVAL;
1699 vtop->type.t = t;
1700}
1701
1702static void incr_bf_adr(int o)
1703{
1704 vtop->type.t = VT_BYTE | VT_UNSIGNED;
1705 incr_offset(o);
1698}1706}
1699 1707
1700/* single-byte load mode for packed or otherwise unaligned bitfields */1708/* single-byte load mode for packed or otherwise unaligned bitfields */
@@ -1860,8 +1868,18 @@ ST_FUNC int gv(int rc) · 159 unmodified lines
1860 r2_ok = !rc2 || ((vtop->r2 < VT_CONST) && (reg_classes[vtop->r2] & rc2));1868 r2_ok = !rc2 || ((vtop->r2 < VT_CONST) && (reg_classes[vtop->r2] & rc2));
1861 1869
1862 if (!r_ok || !r2_ok) {1870 if (!r_ok || !r2_ok) {
1863 if (!r_ok)1871
1864 r = get_reg(rc);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
1865 if (rc2) {1883 if (rc2) {
1866 int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T;1884 int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T;
1867 int original_type = vtop->type.t;1885 int original_type = vtop->type.t;
@@ -1885,12 +1903,7 @@ ST_FUNC int gv(int rc) · 17 unmodified lines
1885 vdup();1903 vdup();
1886 vtop[-1].r = r; /* save register value */1904 vtop[-1].r = r; /* save register value */
1887 /* increment pointer to get second word */1905 /* increment pointer to get second word */
1888 vtop->type.t = VT_PTRDIFF_T;1906 incr_offset(PTR_SIZE);
1889 gaddrof();
1890 vpushs(PTR_SIZE);
1891 gen_op('+');
1892 vtop->r |= VT_LVAL;
1893 vtop->type.t = load_type;
1894 } else {1907 } else {
1895 /* move registers */1908 /* move registers */
1896 if (!r_ok)1909 if (!r_ok)
@@ -3748,14 +3761,8 @@ ST_FUNC void vstore(void) · 1851 unmodified lines
3748 vtop[-1].type.t = load_type;3761 vtop[-1].type.t = load_type;
3749 store(r, vtop - 1);3762 store(r, vtop - 1);
3750 vswap();3763 vswap();
3751 /* convert to int to increment easily */3764 incr_offset(PTR_SIZE);
3752 vtop->type.t = VT_PTRDIFF_T;
3753 gaddrof();
3754 vpushs(PTR_SIZE);
3755 gen_op('+');
3756 vtop->r |= VT_LVAL;
3757 vswap();3765 vswap();
3758 vtop[-1].type.t = load_type;
3759 /* XXX: it works because r2 is spilled last ! */3766 /* XXX: it works because r2 is spilled last ! */
3760 store(vtop->r2, vtop - 1);3767 store(vtop->r2, vtop - 1);
3761 } else {3768 } else {
@@ -6003,7 +6010,6 @@ special_math_val: · 2241 unmodified lines
6003 indir();6010 indir();
6004 qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE);6011 qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE);
6005 test_lvalue();6012 test_lvalue();
6006 gaddrof();
6007 /* expect pointer on structure */6013 /* expect pointer on structure */
6008 if ((vtop->type.t & VT_BTYPE) != VT_STRUCT)6014 if ((vtop->type.t & VT_BTYPE) != VT_STRUCT)
6009 expect("struct or union");6015 expect("struct or union");
@@ -6014,16 +6020,15 @@ special_math_val: · 4 unmodified lines
6014 expect("field name");6020 expect("field name");
6015 s = find_field(&vtop->type, tok, &cumofs);6021 s = find_field(&vtop->type, tok, &cumofs);
6016 /* add field offset to pointer */6022 /* add field offset to pointer */
6017 vtop->type = char_pointer_type; /* change type to 'char *' */6023 incr_offset(cumofs);
6018 vpushi(cumofs);
6019 gen_op('+');
6020 /* change type to field type, and set to lvalue */6024 /* change type to field type, and set to lvalue */
6021 vtop->type = s->type;6025 vtop->type = s->type;
6022 vtop->type.t |= qualifiers;6026 vtop->type.t |= qualifiers;
6023 /* an array is never an lvalue */6027 /* an array is never an lvalue */
6024 if (!(vtop->type.t & VT_ARRAY)) {6028 if (vtop->type.t & VT_ARRAY) {
6025 vtop->r |= VT_LVAL;6029 vtop->r &= ~VT_LVAL;
6026#ifdef CONFIG_TCC_BCHECK6030#ifdef CONFIG_TCC_BCHECK
6031 } else {
6027 /* if bound checking, the referenced pointer must be checked */6032 /* if bound checking, the referenced pointer must be checked */
6028 if (tcc_state->do_bounds_check)6033 if (tcc_state->do_bounds_check)
6029 vtop->r |= VT_MUSTBOUND;6034 vtop->r |= VT_MUSTBOUND;
@@ -6128,10 +6133,20 @@ special_math_val: · 98 unmodified lines
6128#endif6133#endif
6129 } else {6134 } else {
6130 /* return value */6135 /* 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;
6132 vsetc(&ret.type, r, &ret.c);6146 vsetc(&ret.type, r, &ret.c);
6133 vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */
6134 }6147 }
6148 vsetc(&ret.type, ret.r, &ret.c);
6149 vtop->r2 = ret.r2;
6135 6150
6136 /* handle packed struct return */6151 /* handle packed struct return */
6137 if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {6152 if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {
@@ -6140,9 +6155,9 @@ special_math_val: · 2 unmodified lines
6140 size = type_size(&s->type, &align);6155 size = type_size(&s->type, &align);
6141 /* We're writing whole regs often, make sure there's enough6156 /* We're writing whole regs often, make sure there's enough
6142 space. Assume register size is power of 2. */6157 space. Assume register size is power of 2. */
6143 if (regsize > align)6158 size = (size + regsize - 1) & -regsize;
6144 align = regsize;6159 if (ret_align > align)
6145 loc &= -align;6160 align = ret_align;
6146 loc = (loc - size) & -align;6161 loc = (loc - size) & -align;
6147 addr = loc;6162 addr = loc;
6148 offset = 0;6163 offset = 0;
@@ -6619,11 +6634,12 @@ static void gfunc_return(CType *func_type) · 470 unmodified lines
6619 vstore();6634 vstore();
6620 } else {6635 } else {
6621 /* returning structure packed into registers */6636 /* returning structure packed into registers */
6622 int size, addr, align, rc;6637 int size, addr, align, rc, n;
6623 size = type_size(func_type,&align);6638 size = type_size(func_type,&align);
6624 if ((vtop->r != (VT_LOCAL | VT_LVAL) ||6639 if ((align & (ret_align - 1))
6625 (vtop->c.i & (ret_align-1)))6640 && ((vtop->r & VT_VALMASK) < VT_CONST /* pointer to struct */
6626 && (align & (ret_align-1))) {6641 || (vtop->c.i & (ret_align - 1))
6642 )) {
6627 loc = (loc - size) & -ret_align;6643 loc = (loc - size) & -ret_align;
6628 addr = loc;6644 addr = loc;
6629 type = *func_type;6645 type = *func_type;
@@ -6635,22 +6651,19 @@ static void gfunc_return(CType *func_type) · 5 unmodified lines
6635 }6651 }
6636 vtop->type = ret_type;6652 vtop->type = ret_type;
6637 rc = RC_RET(ret_type.t);6653 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();
6639 gv(rc);6657 gv(rc);
6640 else {6658 vswap();
6641 for (;;) {6659 incr_offset(regsize);
6642 vdup();6660 /* We assume that when a structure is returned in multiple
6643 gv(rc);6661 registers, their classes are consecutive values of the
6644 vpop();6662 suite s(n) = 2^n */
6645 if (--ret_nregs == 0)6663 rc <<= 1;
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 }
6653 }6664 }
6665 gv(rc);
6666 vtop -= ret_nregs - 1;
6654 }6667 }
6655 } else {6668 } else {
6656 gv(RC_RET(func_type->t));6669 gv(RC_RET(func_type->t));
tests/tests2/131_return_struct_in_reg.c+59−38
@@ -1,49 +1,70 @@
1#include<stdio.h>1#include<stdio.h>
2 2
3#define DATA 0x1234567890abcdll, 0x5a5aa5a5f0f00f0fll3struct s1 {
4 unsigned char a:4, b:4;
5} g1 = { 0x05, 0x0a };
4 6
5struct s {7struct s2 {
6 long long int a;8 unsigned char a, b;
7 long long int b;9} g2 = { 0x12, 0x34 };
8};
9 10
10struct {11struct s4 {
11 struct s d;12 unsigned short a, b;
12} g = { { DATA } }, *gp = &g;13} g4 = { 0x1245, 0x5678 };
13 14
14struct s15struct s8 {
15foo1(void)16 unsigned a, b;
16{17} g8 = { 0x12345678, 0x9abcdef0 };
17 struct s d = { DATA };
18 struct s *p = &d;
19 long long int x = 0;
20 return *p;
21}
22 18
23struct s19/* returned in 2 registers on riscv64 */
24foo2(void)20struct s16 {
25{21 unsigned long long a, b;
26 long long int unused = 0;22} g16 = { 0x123456789abcdef0ULL, 0xfedcba9876543210ULL };
27 return gp->d;
28}
29 23
30struct s24/* Homogeneous float aggregate on ARM hard-float */
31foo3(void)25struct s_f4 {
32{26 double a, b, c, d;
33 struct s d = { DATA };27} g_f4 = { 1,2,3,4 };
34 long long int unused = 0;28
35 return d;29#define def(S) \
30struct 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; \
36}39}
37 40
38int41def(1)
39main(void)42def(2)
43def(4)
44def(8)
45def(16)
46def(_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
55int main()
40{56{
41 struct s d;57 for (int x = 0;;) {
42 d = foo1();58 chk(1,x);
43 printf("%llx %llx\n", d.a, d.b);59 chk(2,x);
44 d = foo2();60 chk(4,x);
45 printf("%llx %llx\n", d.a, d.b);61 chk(8,x);
46 d = foo3();62 chk(16,x);
47 printf("%llx %llx\n", d.a, d.b);63 struct s_f4 l_f4 = f_f4(x);
48 return 0;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;
49}70}
tests/tests2/131_return_struct_in_reg.expect+20−3
@@ -1,3 +1,20 @@
11234567890abcd 5a5aa5a5f0f00f0f105 0a
21234567890abcd 5a5aa5a5f0f00f0f212 34
31234567890abcd 5a5aa5a5f0f00f0f31245 5678
412345678 9abcdef0
5123456789abcdef0 fedcba9876543210
61.0 2.0 3.0 4.0
7
805 0a
912 34
101245 5678
1112345678 9abcdef0
12123456789abcdef0 fedcba9876543210
131.0 2.0 3.0 4.0
14
1505 0a
1612 34
171245 5678
1812345678 9abcdef0
19123456789abcdef0 fedcba9876543210
201.0 2.0 3.0 4.0
x86_64-gen.c+6−4
@@ -33,8 +33,8 @@ · 32 unmodified lines
33#define RC_INT 0x0001 /* generic integer register */33#define RC_INT 0x0001 /* generic integer register */
34#define RC_FLOAT 0x0002 /* generic float register */34#define RC_FLOAT 0x0002 /* generic float register */
35#define RC_RAX 0x000435#define RC_RAX 0x0004
36#define RC_RCX 0x000836#define RC_RDX 0x0008
37#define RC_RDX 0x001037#define RC_RCX 0x0010
38#define RC_RSI 0x002038#define RC_RSI 0x0020
39#define RC_RDI 0x004039#define RC_RDI 0x0040
40#define RC_ST0 0x0080 /* only for long double */40#define RC_ST0 0x0080 /* only for long double */
@@ -1223,9 +1223,11 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) · 1182 unmodified lines
1223ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)1223ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
1224{1224{
1225 int size, align, reg_count;1225 int size, align, reg_count;
1226 if (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) == x86_64_mode_memory)
1227 return 0;
1226 *ret_align = 1; // Never have to re-align return values for x86-641228 *ret_align = 1; // Never have to re-align return values for x86-64
1227 *regsize = 8;1229 *regsize = 8 * reg_count; /* the (virtual) regsize is 16 for VT_QLONG/QFLOAT */
1228 return (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) != x86_64_mode_memory);1230 return 1;
1229}1231}
1230 1232
1231#define REGN 61233#define REGN 6

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t