mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-29 06:10:09 +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_end(ap) ((void)0)
|
||||||
#define va_copy(dest, src) ((dest) = (src))
|
#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__ */
|
#else /* __i386__ */
|
||||||
typedef char *va_list;
|
typedef char *va_list;
|
||||||
/* only correct for i386 */
|
/* 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
|
sv->type.t &= ~VT_ARRAY; // XXX this should be done in tccgen.c
|
||||||
size = type_size(&sv->type, &align);
|
size = type_size(&sv->type, &align);
|
||||||
if (size > 16) {
|
if (size > 16) {
|
||||||
|
if (align < XLEN)
|
||||||
|
align = XLEN;
|
||||||
tempspace = (tempspace + align - 1) & -align;
|
tempspace = (tempspace + align - 1) & -align;
|
||||||
tempofs = tempspace;
|
tempofs = tempspace;
|
||||||
tempspace += size;
|
tempspace += size;
|
||||||
size = align = 8;
|
size = align = 8;
|
||||||
byref = 1;
|
byref = 1;
|
||||||
} else if (size > 8)
|
}
|
||||||
|
if (size > 8)
|
||||||
nregs = 2;
|
nregs = 2;
|
||||||
else
|
else
|
||||||
nregs = 1;
|
nregs = 1;
|
||||||
@ -447,6 +450,8 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info[i] = 32;
|
info[i] = 32;
|
||||||
|
if (align < XLEN)
|
||||||
|
align = XLEN;
|
||||||
stack_adj += (size + align - 1) & -align;
|
stack_adj += (size + align - 1) & -align;
|
||||||
if (!sa)
|
if (!sa)
|
||||||
force_stack = 1;
|
force_stack = 1;
|
||||||
@ -478,6 +483,8 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||||||
size = align = 8;
|
size = align = 8;
|
||||||
}
|
}
|
||||||
if (info[i] & 32) {
|
if (info[i] & 32) {
|
||||||
|
if (align < XLEN)
|
||||||
|
align = XLEN;
|
||||||
/* Once we support offseted regs we can do this:
|
/* Once we support offseted regs we can do this:
|
||||||
vset(&vtop->type, TREG_SP | VT_LVAL, ofs);
|
vset(&vtop->type, TREG_SP | VT_LVAL, ofs);
|
||||||
to construct the lvalue for the outgoing stack slot,
|
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
|
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)
|
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
|
loc = -16; // for ra and s0
|
||||||
func_sub_sp_offset = ind;
|
func_sub_sp_offset = ind;
|
||||||
ind += 5 * 4;
|
ind += 5 * 4;
|
||||||
if (sym->f.func_type == FUNC_ELLIPSIS) {
|
|
||||||
tcc_error("unimp: vararg prologue");
|
|
||||||
}
|
|
||||||
|
|
||||||
aireg = afreg = 0;
|
aireg = afreg = 0;
|
||||||
addr = 0; // XXX not correct
|
addr = 0; // XXX not correct
|
||||||
@ -569,10 +573,17 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||||||
}
|
}
|
||||||
/* define parameters */
|
/* define parameters */
|
||||||
while ((sym = sym->next) != NULL) {
|
while ((sym = sym->next) != NULL) {
|
||||||
|
int byref = 0;
|
||||||
type = &sym->type;
|
type = &sym->type;
|
||||||
size = type_size(type, &align);
|
size = type_size(type, &align);
|
||||||
|
if (size > 2 * XLEN) {
|
||||||
|
type = &char_pointer_type;
|
||||||
|
size = align = byref = 8;
|
||||||
|
}
|
||||||
if (size > 2 * XLEN) {
|
if (size > 2 * XLEN) {
|
||||||
from_stack:
|
from_stack:
|
||||||
|
if (align < XLEN)
|
||||||
|
align = XLEN;
|
||||||
addr = (addr + align - 1) & -align;
|
addr = (addr + align - 1) & -align;
|
||||||
param_addr = addr;
|
param_addr = addr;
|
||||||
addr += size;
|
addr += size;
|
||||||
@ -603,8 +614,16 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||||||
(*pareg)++;
|
(*pareg)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sym_push(sym->v & ~SYM_FIELD, type,
|
sym_push(sym->v & ~SYM_FIELD, &sym->type,
|
||||||
VT_LOCAL | lvalue_type(type->t), param_addr);
|
(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)
|
if (size > 16)
|
||||||
return 0;
|
return 0;
|
||||||
if (size > 8)
|
if (size > 8)
|
||||||
ret->t = VT_LDOUBLE;
|
ret->t = VT_LLONG;
|
||||||
else if (size > 4)
|
else if (size > 4)
|
||||||
ret->t = VT_LLONG;
|
ret->t = VT_LLONG;
|
||||||
else if (size > 2)
|
else if (size > 2)
|
||||||
@ -660,6 +679,7 @@ ST_FUNC void gfunc_epilog(void)
|
|||||||
{
|
{
|
||||||
int v, saved_ind, d, large_ofs_ind;
|
int v, saved_ind, d, large_ofs_ind;
|
||||||
|
|
||||||
|
loc = (loc - num_va_regs * 8);
|
||||||
d = v = (-loc + 15) & -16;
|
d = v = (-loc + 15) & -16;
|
||||||
|
|
||||||
if (v >= (1 << 11)) {
|
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)
|
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
|
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, 1, 2, d - 8 - num_va_regs * 8); // ld ra, v-8(sp)
|
||||||
EI(0x03, 3, 8, 2, d - 16); // ld s0, v-16(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(0x13, 0, 2, 2, d); // addi sp, sp, v
|
||||||
EI(0x67, 0, 0, 1, 0); // jalr x0, 0(x1), aka ret
|
EI(0x67, 0, 0, 1, 0); // jalr x0, 0(x1), aka ret
|
||||||
if (v >= (1 << 11)) {
|
if (v >= (1 << 11)) {
|
||||||
large_ofs_ind = ind;
|
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)
|
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)
|
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
|
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;
|
ind = func_sub_sp_offset;
|
||||||
EI(0x13, 0, 2, 2, -d); // addi sp, sp, -d
|
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, 1, d - 8 - num_va_regs * 8); // sd ra, d-8(sp)
|
||||||
ES(0x23, 3, 2, 8, d - 16); // sd s0, d-16(sp)
|
ES(0x23, 3, 2, 8, d - 16 - num_va_regs * 8); // sd s0, d-16(sp)
|
||||||
if (v < (1 << 11))
|
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
|
else
|
||||||
gjmp_addr(large_ofs_ind);
|
gjmp_addr(large_ofs_ind);
|
||||||
if ((ind - func_sub_sp_offset) != 5*4)
|
if ((ind - func_sub_sp_offset) != 5*4)
|
||||||
|
16
tccgen.c
16
tccgen.c
@ -5159,6 +5159,20 @@ ST_FUNC void unary(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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_X86_64
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
case TOK_builtin_va_start:
|
case TOK_builtin_va_start:
|
||||||
@ -5972,7 +5986,7 @@ static void expr_cond(void)
|
|||||||
|
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
r1 = gv(rc);
|
r1 = gv(rc);
|
||||||
move_reg(r2, r1, type.t);
|
move_reg(r2, r1, islv ? VT_PTR : type.t);
|
||||||
vtop->r = r2;
|
vtop->r = r2;
|
||||||
gsym(tt);
|
gsym(tt);
|
||||||
}
|
}
|
||||||
|
2
tcctok.h
2
tcctok.h
@ -158,6 +158,8 @@
|
|||||||
#elif defined TCC_TARGET_ARM64
|
#elif defined TCC_TARGET_ARM64
|
||||||
DEF(TOK___va_start, "__va_start")
|
DEF(TOK___va_start, "__va_start")
|
||||||
DEF(TOK___va_arg, "__va_arg")
|
DEF(TOK___va_arg, "__va_arg")
|
||||||
|
#elif defined TCC_TARGET_RISCV64
|
||||||
|
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* pragma */
|
/* pragma */
|
||||||
|
Loading…
Reference in New Issue
Block a user