mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-27 06:10:06 +08:00
riscv: implement stdarg functions
this also fixes passing of params > 16 bytes. In riscv they aren't passed by value on stack, but via reference (and because callees are allowed to modify by-ref params the caller must allocate an own copy per call). This fixes the stdarg parts of 73_arm.c.
This commit is contained in:
parent
f44df9d85b
commit
982de78e8d
@ -63,6 +63,16 @@ typedef struct {
|
||||
#define va_end(ap) ((void)0)
|
||||
#define va_copy(dest, src) ((dest) = (src))
|
||||
|
||||
#elif defined __riscv
|
||||
#define __va_reg_size (__riscv_xlen >> 3)
|
||||
#define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \
|
||||
& -(__alignof__(type)))
|
||||
typedef char *va_list;
|
||||
#define va_start __builtin_va_start
|
||||
#define va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size)))))
|
||||
#define va_copy(dest, src) (dest) = (src)
|
||||
#define va_end(ap) ((void)0)
|
||||
|
||||
#else /* __i386__ */
|
||||
typedef char *va_list;
|
||||
/* only correct for i386 */
|
||||
|
@ -418,12 +418,15 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
sv->type.t &= ~VT_ARRAY; // XXX this should be done in tccgen.c
|
||||
size = type_size(&sv->type, &align);
|
||||
if (size > 16) {
|
||||
if (align < XLEN)
|
||||
align = XLEN;
|
||||
tempspace = (tempspace + align - 1) & -align;
|
||||
tempofs = tempspace;
|
||||
tempspace += size;
|
||||
size = align = 8;
|
||||
byref = 1;
|
||||
} else if (size > 8)
|
||||
}
|
||||
if (size > 8)
|
||||
nregs = 2;
|
||||
else
|
||||
nregs = 1;
|
||||
@ -447,6 +450,8 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
}
|
||||
} else {
|
||||
info[i] = 32;
|
||||
if (align < XLEN)
|
||||
align = XLEN;
|
||||
stack_adj += (size + align - 1) & -align;
|
||||
if (!sa)
|
||||
force_stack = 1;
|
||||
@ -478,6 +483,8 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
size = align = 8;
|
||||
}
|
||||
if (info[i] & 32) {
|
||||
if (align < XLEN)
|
||||
align = XLEN;
|
||||
/* Once we support offseted regs we can do this:
|
||||
vset(&vtop->type, TREG_SP | VT_LVAL, ofs);
|
||||
to construct the lvalue for the outgoing stack slot,
|
||||
@ -537,7 +544,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
EI(0x13, 0, 2, 2, stack_adj + tempspace); // addi sp, sp, adj
|
||||
}
|
||||
|
||||
static int func_sub_sp_offset;
|
||||
static int func_sub_sp_offset, num_va_regs;
|
||||
|
||||
ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
{
|
||||
@ -552,9 +559,6 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
loc = -16; // for ra and s0
|
||||
func_sub_sp_offset = ind;
|
||||
ind += 5 * 4;
|
||||
if (sym->f.func_type == FUNC_ELLIPSIS) {
|
||||
tcc_error("unimp: vararg prologue");
|
||||
}
|
||||
|
||||
aireg = afreg = 0;
|
||||
addr = 0; // XXX not correct
|
||||
@ -569,10 +573,17 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
}
|
||||
/* define parameters */
|
||||
while ((sym = sym->next) != NULL) {
|
||||
int byref = 0;
|
||||
type = &sym->type;
|
||||
size = type_size(type, &align);
|
||||
if (size > 2 * XLEN) {
|
||||
type = &char_pointer_type;
|
||||
size = align = byref = 8;
|
||||
}
|
||||
if (size > 2 * XLEN) {
|
||||
from_stack:
|
||||
if (align < XLEN)
|
||||
align = XLEN;
|
||||
addr = (addr + align - 1) & -align;
|
||||
param_addr = addr;
|
||||
addr += size;
|
||||
@ -603,8 +614,16 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
(*pareg)++;
|
||||
}
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | lvalue_type(type->t), param_addr);
|
||||
sym_push(sym->v & ~SYM_FIELD, &sym->type,
|
||||
(byref ? VT_LLOCAL : VT_LOCAL) | lvalue_type(sym->type.t),
|
||||
param_addr);
|
||||
}
|
||||
num_va_regs = 0;
|
||||
if (func_type->ref->f.func_type == FUNC_ELLIPSIS) {
|
||||
for (; aireg < 8; aireg++) {
|
||||
num_va_regs++;
|
||||
ES(0x23, 3, 8, 10 + aireg, -8 + num_va_regs * 8); // sd aX, loc(s0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -620,7 +639,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret,
|
||||
if (size > 16)
|
||||
return 0;
|
||||
if (size > 8)
|
||||
ret->t = VT_LDOUBLE;
|
||||
ret->t = VT_LLONG;
|
||||
else if (size > 4)
|
||||
ret->t = VT_LLONG;
|
||||
else if (size > 2)
|
||||
@ -660,6 +679,7 @@ ST_FUNC void gfunc_epilog(void)
|
||||
{
|
||||
int v, saved_ind, d, large_ofs_ind;
|
||||
|
||||
loc = (loc - num_va_regs * 8);
|
||||
d = v = (-loc + 15) & -16;
|
||||
|
||||
if (v >= (1 << 11)) {
|
||||
@ -668,13 +688,13 @@ ST_FUNC void gfunc_epilog(void)
|
||||
EI(0x13, 0, 5, 5, (v-16) << 20 >> 20); // addi t0, t0, lo(v)
|
||||
o(0x33 | (2 << 7) | (2 << 15) | (5 << 20)); //add sp, sp, t0
|
||||
}
|
||||
EI(0x03, 3, 1, 2, d - 8); // ld ra, v-8(sp)
|
||||
EI(0x03, 3, 8, 2, d - 16); // ld s0, v-16(sp)
|
||||
EI(0x03, 3, 1, 2, d - 8 - num_va_regs * 8); // ld ra, v-8(sp)
|
||||
EI(0x03, 3, 8, 2, d - 16 - num_va_regs * 8); // ld s0, v-16(sp)
|
||||
EI(0x13, 0, 2, 2, d); // addi sp, sp, v
|
||||
EI(0x67, 0, 0, 1, 0); // jalr x0, 0(x1), aka ret
|
||||
if (v >= (1 << 11)) {
|
||||
large_ofs_ind = ind;
|
||||
EI(0x13, 0, 8, 2, d); // addi s0, sp, d
|
||||
EI(0x13, 0, 8, 2, d - num_va_regs * 8); // addi s0, sp, d
|
||||
o(0x37 | (5 << 7) | ((0x800 + (v-16)) & 0xfffff000)); //lui t0, upper(v)
|
||||
EI(0x13, 0, 5, 5, (v-16) << 20 >> 20); // addi t0, t0, lo(v)
|
||||
o(0x33 | (2 << 7) | (2 << 15) | (5 << 20) | (0x20 << 25)); //sub sp, sp, t0
|
||||
@ -684,10 +704,10 @@ ST_FUNC void gfunc_epilog(void)
|
||||
|
||||
ind = func_sub_sp_offset;
|
||||
EI(0x13, 0, 2, 2, -d); // addi sp, sp, -d
|
||||
ES(0x23, 3, 2, 1, d - 8); // sd ra, d-8(sp)
|
||||
ES(0x23, 3, 2, 8, d - 16); // sd s0, d-16(sp)
|
||||
ES(0x23, 3, 2, 1, d - 8 - num_va_regs * 8); // sd ra, d-8(sp)
|
||||
ES(0x23, 3, 2, 8, d - 16 - num_va_regs * 8); // sd s0, d-16(sp)
|
||||
if (v < (1 << 11))
|
||||
EI(0x13, 0, 8, 2, d); // addi s0, sp, d
|
||||
EI(0x13, 0, 8, 2, d - num_va_regs * 8); // addi s0, sp, d
|
||||
else
|
||||
gjmp_addr(large_ofs_ind);
|
||||
if ((ind - func_sub_sp_offset) != 5*4)
|
||||
|
16
tccgen.c
16
tccgen.c
@ -5159,6 +5159,20 @@ ST_FUNC void unary(void)
|
||||
}
|
||||
}
|
||||
break;
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
case TOK_builtin_va_start:
|
||||
parse_builtin_params(0, "ee");
|
||||
r = vtop->r & VT_VALMASK;
|
||||
if (r == VT_LLOCAL)
|
||||
r = VT_LOCAL;
|
||||
if (r != VT_LOCAL)
|
||||
tcc_error("__builtin_va_start expects a local variable");
|
||||
vtop->r = r;
|
||||
vtop->type = char_pointer_type;
|
||||
vtop->c.i = 0;
|
||||
vstore();
|
||||
break;
|
||||
#endif
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#ifdef TCC_TARGET_PE
|
||||
case TOK_builtin_va_start:
|
||||
@ -5972,7 +5986,7 @@ static void expr_cond(void)
|
||||
|
||||
if (c < 0) {
|
||||
r1 = gv(rc);
|
||||
move_reg(r2, r1, type.t);
|
||||
move_reg(r2, r1, islv ? VT_PTR : type.t);
|
||||
vtop->r = r2;
|
||||
gsym(tt);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user