| @@ -1687,14 +1687,22 @@ static void pop_local_syms(Sym *b, int keep) · 1686 unmodified lines |
| 1687 | 1687 | sym_pop(&local_stack, b, keep); |
| 1688 | 1688 | } |
| 1689 | 1689 | |
| 1690 | | −static void incr_bf_adr(int o) |
| 1690 | +/* increment an lvalue pointer */ |
| 1691 | +static void incr_offset(int offset) |
| 1691 | 1692 | { |
| 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); |
| 1695 | 1697 | gen_op('+'); |
| 1696 | | − vtop->type.t = VT_BYTE | VT_UNSIGNED; |
| 1697 | 1698 | 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); |
| 1698 | 1706 | } |
| 1699 | 1707 | |
| 1700 | 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 | 1868 | r2_ok = !rc2 || ((vtop->r2 < VT_CONST) && (reg_classes[vtop->r2] & rc2)); |
| 1861 | 1869 | |
| 1862 | 1870 | 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 | + |
| 1865 | 1883 | if (rc2) { |
| 1866 | 1884 | int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T; |
| 1867 | 1885 | int original_type = vtop->type.t; |
| @@ -1885,12 +1903,7 @@ ST_FUNC int gv(int rc) · 17 unmodified lines |
| 1885 | 1903 | vdup(); |
| 1886 | 1904 | vtop[-1].r = r; /* save register value */ |
| 1887 | 1905 | /* 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); |
| 1894 | 1907 | } else { |
| 1895 | 1908 | /* move registers */ |
| 1896 | 1909 | if (!r_ok) |
| @@ -3748,14 +3761,8 @@ ST_FUNC void vstore(void) · 1851 unmodified lines |
| 3748 | 3761 | vtop[-1].type.t = load_type; |
| 3749 | 3762 | store(r, vtop - 1); |
| 3750 | 3763 | 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); |
| 3757 | 3765 | vswap(); |
| 3758 | | − vtop[-1].type.t = load_type; |
| 3759 | 3766 | /* XXX: it works because r2 is spilled last ! */ |
| 3760 | 3767 | store(vtop->r2, vtop - 1); |
| 3761 | 3768 | } else { |
| @@ -6003,7 +6010,6 @@ special_math_val: · 2241 unmodified lines |
| 6003 | 6010 | indir(); |
| 6004 | 6011 | qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); |
| 6005 | 6012 | test_lvalue(); |
| 6006 | | − gaddrof(); |
| 6007 | 6013 | /* expect pointer on structure */ |
| 6008 | 6014 | if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) |
| 6009 | 6015 | expect("struct or union"); |
| @@ -6014,16 +6020,15 @@ special_math_val: · 4 unmodified lines |
| 6014 | 6020 | expect("field name"); |
| 6015 | 6021 | s = find_field(&vtop->type, tok, &cumofs); |
| 6016 | 6022 | /* 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); |
| 6020 | 6024 | /* change type to field type, and set to lvalue */ |
| 6021 | 6025 | vtop->type = s->type; |
| 6022 | 6026 | vtop->type.t |= qualifiers; |
| 6023 | 6027 | /* 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; |
| 6026 | 6030 | #ifdef CONFIG_TCC_BCHECK |
| 6031 | + } else { |
| 6027 | 6032 | /* if bound checking, the referenced pointer must be checked */ |
| 6028 | 6033 | if (tcc_state->do_bounds_check) |
| 6029 | 6034 | vtop->r |= VT_MUSTBOUND; |
| @@ -6128,10 +6133,20 @@ special_math_val: · 98 unmodified lines |
| 6128 | 6133 | #endif |
| 6129 | 6134 | } else { |
| 6130 | 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 | 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 | 6151 | /* handle packed struct return */ |
| 6137 | 6152 | if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) { |
| @@ -6140,9 +6155,9 @@ special_math_val: · 2 unmodified lines |
| 6140 | 6155 | size = type_size(&s->type, &align); |
| 6141 | 6156 | /* We're writing whole regs often, make sure there's enough |
| 6142 | 6157 | 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; |
| 6146 | 6161 | loc = (loc - size) & -align; |
| 6147 | 6162 | addr = loc; |
| 6148 | 6163 | offset = 0; |
| @@ -6619,11 +6634,12 @@ static void gfunc_return(CType *func_type) · 470 unmodified lines |
| 6619 | 6634 | vstore(); |
| 6620 | 6635 | } else { |
| 6621 | 6636 | /* returning structure packed into registers */ |
| 6622 | | − int size, addr, align, rc; |
| 6637 | + int size, addr, align, rc, n; |
| 6623 | 6638 | 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 | + )) { |
| 6627 | 6643 | loc = (loc - size) & -ret_align; |
| 6628 | 6644 | addr = loc; |
| 6629 | 6645 | type = *func_type; |
| @@ -6635,22 +6651,19 @@ static void gfunc_return(CType *func_type) · 5 unmodified lines |
| 6635 | 6651 | } |
| 6636 | 6652 | vtop->type = ret_type; |
| 6637 | 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 | 6657 | 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; |
| 6653 | 6664 | } |
| 6665 | + gv(rc); |
| 6666 | + vtop -= ret_nregs - 1; |
| 6654 | 6667 | } |
| 6655 | 6668 | } else { |
| 6656 | 6669 | gv(RC_RET(func_type->t)); |