History

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.

Michael Matz committed 7 years ago

Commit 982de781 parent f44df9d4 files · +61 −15Browse files

Unified · Split

4 files
  1. include/stdarg.h +10 −0
  2. riscv64-gen.c +34 −14
  3. tccgen.c +15 −1
  4. tcctok.h +2 −0
include/stdarg.h+10−0
@@ -63,6 +63,16 @@ typedef struct { · 62 unmodified lines
6363 #define va_end(ap) ((void)0)
6464 #define va_copy(dest, src) ((dest) = (src))
6565
66+#elif defined __riscv
67+#define __va_reg_size (__riscv_xlen >> 3)
68+#define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \
69+ & -(__alignof__(type)))
70+typedef char *va_list;
71+#define va_start __builtin_va_start
72+#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)))))
73+#define va_copy(dest, src) (dest) = (src)
74+#define va_end(ap) ((void)0)
75+
6676 #else /* __i386__ */
6777 typedef char *va_list;
6878 /* only correct for i386 */
riscv64-gen.c+34−14
@@ -418,12 +418,15 @@ ST_FUNC void gfunc_call(int nb_args) · 417 unmodified lines
418418 sv->type.t &= ~VT_ARRAY; // XXX this should be done in tccgen.c
419419 size = type_size(&sv->type, &align);
420420 if (size > 16) {
421+ if (align < XLEN)
422+ align = XLEN;
421423 tempspace = (tempspace + align - 1) & -align;
422424 tempofs = tempspace;
423425 tempspace += size;
424426 size = align = 8;
425427 byref = 1;
426− } else if (size > 8)
428+ }
429+ if (size > 8)
427430 nregs = 2;
428431 else
429432 nregs = 1;
@@ -447,6 +450,8 @@ ST_FUNC void gfunc_call(int nb_args) · 17 unmodified lines
447450 }
448451 } else {
449452 info[i] = 32;
453+ if (align < XLEN)
454+ align = XLEN;
450455 stack_adj += (size + align - 1) & -align;
451456 if (!sa)
452457 force_stack = 1;
@@ -478,6 +483,8 @@ ST_FUNC void gfunc_call(int nb_args) · 25 unmodified lines
478483 size = align = 8;
479484 }
480485 if (info[i] & 32) {
486+ if (align < XLEN)
487+ align = XLEN;
481488 /* Once we support offseted regs we can do this:
482489 vset(&vtop->type, TREG_SP | VT_LVAL, ofs);
483490 to construct the lvalue for the outgoing stack slot,
@@ -537,7 +544,7 @@ ST_FUNC void gfunc_call(int nb_args) · 53 unmodified lines
537544 EI(0x13, 0, 2, 2, stack_adj + tempspace); // addi sp, sp, adj
538545 }
539546
540−static int func_sub_sp_offset;
547+static int func_sub_sp_offset, num_va_regs;
541548
542549 ST_FUNC void gfunc_prolog(CType *func_type)
543550 {
@@ -552,9 +559,6 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 8 unmodified lines
552559 loc = -16; // for ra and s0
553560 func_sub_sp_offset = ind;
554561 ind += 5 * 4;
555− if (sym->f.func_type == FUNC_ELLIPSIS) {
556− tcc_error("unimp: vararg prologue");
557− }
558562
559563 aireg = afreg = 0;
560564 addr = 0; // XXX not correct
@@ -569,10 +573,17 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 8 unmodified lines
569573 }
570574 /* define parameters */
571575 while ((sym = sym->next) != NULL) {
576+ int byref = 0;
572577 type = &sym->type;
573578 size = type_size(type, &align);
579+ if (size > 2 * XLEN) {
580+ type = &char_pointer_type;
581+ size = align = byref = 8;
582+ }
574583 if (size > 2 * XLEN) {
575584 from_stack:
585+ if (align < XLEN)
586+ align = XLEN;
576587 addr = (addr + align - 1) & -align;
577588 param_addr = addr;
578589 addr += size;
@@ -603,8 +614,16 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 24 unmodified lines
603614 (*pareg)++;
604615 }
605616 }
606− sym_push(sym->v & ~SYM_FIELD, type,
607− VT_LOCAL | lvalue_type(type->t), param_addr);
617+ sym_push(sym->v & ~SYM_FIELD, &sym->type,
618+ (byref ? VT_LLOCAL : VT_LOCAL) | lvalue_type(sym->type.t),
619+ param_addr);
620+ }
621+ num_va_regs = 0;
622+ if (func_type->ref->f.func_type == FUNC_ELLIPSIS) {
623+ for (; aireg < 8; aireg++) {
624+ num_va_regs++;
625+ ES(0x23, 3, 8, 10 + aireg, -8 + num_va_regs * 8); // sd aX, loc(s0)
626+ }
608627 }
609628 }
610629
@@ -620,7 +639,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, · 9 unmodified lines
620639 if (size > 16)
621640 return 0;
622641 if (size > 8)
623− ret->t = VT_LDOUBLE;
642+ ret->t = VT_LLONG;
624643 else if (size > 4)
625644 ret->t = VT_LLONG;
626645 else if (size > 2)
@@ -660,6 +679,7 @@ ST_FUNC void gfunc_epilog(void) · 33 unmodified lines
660679 {
661680 int v, saved_ind, d, large_ofs_ind;
662681
682+ loc = (loc - num_va_regs * 8);
663683 d = v = (-loc + 15) & -16;
664684
665685 if (v >= (1 << 11)) {
@@ -668,13 +688,13 @@ ST_FUNC void gfunc_epilog(void) · 2 unmodified lines
668688 EI(0x13, 0, 5, 5, (v-16) << 20 >> 20); // addi t0, t0, lo(v)
669689 o(0x33 | (2 << 7) | (2 << 15) | (5 << 20)); //add sp, sp, t0
670690 }
671− EI(0x03, 3, 1, 2, d - 8); // ld ra, v-8(sp)
672− EI(0x03, 3, 8, 2, d - 16); // ld s0, v-16(sp)
691+ EI(0x03, 3, 1, 2, d - 8 - num_va_regs * 8); // ld ra, v-8(sp)
692+ EI(0x03, 3, 8, 2, d - 16 - num_va_regs * 8); // ld s0, v-16(sp)
673693 EI(0x13, 0, 2, 2, d); // addi sp, sp, v
674694 EI(0x67, 0, 0, 1, 0); // jalr x0, 0(x1), aka ret
675695 if (v >= (1 << 11)) {
676696 large_ofs_ind = ind;
677− EI(0x13, 0, 8, 2, d); // addi s0, sp, d
697+ EI(0x13, 0, 8, 2, d - num_va_regs * 8); // addi s0, sp, d
678698 o(0x37 | (5 << 7) | ((0x800 + (v-16)) & 0xfffff000)); //lui t0, upper(v)
679699 EI(0x13, 0, 5, 5, (v-16) << 20 >> 20); // addi t0, t0, lo(v)
680700 o(0x33 | (2 << 7) | (2 << 15) | (5 << 20) | (0x20 << 25)); //sub sp, sp, t0
@@ -684,10 +704,10 @@ ST_FUNC void gfunc_epilog(void) · 3 unmodified lines
684704
685705 ind = func_sub_sp_offset;
686706 EI(0x13, 0, 2, 2, -d); // addi sp, sp, -d
687− ES(0x23, 3, 2, 1, d - 8); // sd ra, d-8(sp)
688− ES(0x23, 3, 2, 8, d - 16); // sd s0, d-16(sp)
707+ ES(0x23, 3, 2, 1, d - 8 - num_va_regs * 8); // sd ra, d-8(sp)
708+ ES(0x23, 3, 2, 8, d - 16 - num_va_regs * 8); // sd s0, d-16(sp)
689709 if (v < (1 << 11))
690− EI(0x13, 0, 8, 2, d); // addi s0, sp, d
710+ EI(0x13, 0, 8, 2, d - num_va_regs * 8); // addi s0, sp, d
691711 else
692712 gjmp_addr(large_ofs_ind);
693713 if ((ind - func_sub_sp_offset) != 5*4)
tccgen.c+15−1
@@ -5159,6 +5159,20 @@ ST_FUNC void unary(void) · 5158 unmodified lines
51595159 }
51605160 }
51615161 break;
5162+#ifdef TCC_TARGET_RISCV64
5163+ case TOK_builtin_va_start:
5164+ parse_builtin_params(0, "ee");
5165+ r = vtop->r & VT_VALMASK;
5166+ if (r == VT_LLOCAL)
5167+ r = VT_LOCAL;
5168+ if (r != VT_LOCAL)
5169+ tcc_error("__builtin_va_start expects a local variable");
5170+ vtop->r = r;
5171+ vtop->type = char_pointer_type;
5172+ vtop->c.i = 0;
5173+ vstore();
5174+ break;
5175+#endif
51625176 #ifdef TCC_TARGET_X86_64
51635177 #ifdef TCC_TARGET_PE
51645178 case TOK_builtin_va_start:
@@ -5972,7 +5986,7 @@ static void expr_cond(void) · 807 unmodified lines
59725986
59735987 if (c < 0) {
59745988 r1 = gv(rc);
5975− move_reg(r2, r1, type.t);
5989+ move_reg(r2, r1, islv ? VT_PTR : type.t);
59765990 vtop->r = r2;
59775991 gsym(tt);
59785992 }
tcctok.h+2−0
@@ -158,6 +158,8 @@ · 157 unmodified lines
158158 #elif defined TCC_TARGET_ARM64
159159 DEF(TOK___va_start, "__va_start")
160160 DEF(TOK___va_arg, "__va_arg")
161+#elif defined TCC_TARGET_RISCV64
162+ DEF(TOK_builtin_va_start, "__builtin_va_start")
161163 #endif
162164
163165 /* pragma */

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