From 6bbc4c8dbd4e29b03e9a8e3b995a2845edda3db4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 17 Aug 2014 10:00:51 -0700 Subject: [PATCH] Fix returning strings from variadic functions. --- compiler/libpc300/sc.h | 2 ++ compiler/libpc300/sc1.c | 18 +++++++++++- compiler/libpc300/sc4.c | 61 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/compiler/libpc300/sc.h b/compiler/libpc300/sc.h index ff0da2e9..ab5faa11 100755 --- a/compiler/libpc300/sc.h +++ b/compiler/libpc300/sc.h @@ -598,6 +598,8 @@ SC_FUNC void addr2cell(void); SC_FUNC void char2addr(void); SC_FUNC void charalign(void); SC_FUNC void addconst(cell value); +SC_FUNC void move_alt(void); +SC_FUNC void load_hidden_arg(); /* Code generation functions for arithmetic operators. * diff --git a/compiler/libpc300/sc1.c b/compiler/libpc300/sc1.c index d8429f5e..dbd577ba 100755 --- a/compiler/libpc300/sc1.c +++ b/compiler/libpc300/sc1.c @@ -5230,6 +5230,18 @@ static symbol *fetchlab(char *name) return sym; } +static int is_variadic(symbol *sym) +{ + assert(sym->ident==iFUNCTN); + arginfo *arg = sym->dim.arglist; + while (arg->ident) { + if (arg->ident == iVARARGS) + return TRUE; + arg++; + } + return FALSE; +} + /* doreturn * * Global references: rettype (altered) @@ -5329,7 +5341,11 @@ static void doreturn(void) * it stays on the heap for the moment, and it is removed -usually- at * the end of the expression/statement, see expression() in SC3.C) */ - address(sub,sALT); /* ALT = destination */ + if (is_variadic(curfunc)) { + load_hidden_arg(); + } else { + address(sub,sALT); /* ALT = destination */ + } arraysize=calc_arraysize(dim,numdim,0); memcopy(arraysize*sizeof(cell)); /* source already in PRI */ /* moveto1(); is not necessary, callfunction() does a popreg() */ diff --git a/compiler/libpc300/sc4.c b/compiler/libpc300/sc4.c index b0249589..982d3a32 100755 --- a/compiler/libpc300/sc4.c +++ b/compiler/libpc300/sc4.c @@ -363,6 +363,12 @@ SC_FUNC void alignframe(int numbytes) code_idx+=opcodes(5)+opargs(4); } +SC_FUNC void load_i() +{ + stgwrite("\tload.i\n"); + code_idx+=opcodes(1); +} + /* rvalue * * Generate code to get the value of a symbol into "primary". @@ -374,8 +380,7 @@ SC_FUNC void rvalue(value *lval) sym=lval->sym; if (lval->ident==iARRAYCELL) { /* indirect fetch, address already in PRI */ - stgwrite("\tload.i\n"); - code_idx+=opcodes(1); + load_i(); } else if (lval->ident==iARRAYCHAR) { /* indirect fetch of a character from a pack, address already in PRI */ stgwrite("\tlodb.i "); @@ -448,6 +453,52 @@ SC_FUNC void address(symbol *sym,regid reg) code_idx+=opcodes(1)+opargs(1); } +static void addr_reg(int val, regid reg) +{ + if (reg == sPRI) + stgwrite("\taddr.pri "); + else + stgwrite("\taddr.alt "); + outval(val, TRUE); + code_idx += opcodes(1) + opargs(1); +} + +// Load the number of arguments into PRI. Frame layout: +// base + 0*sizeof(cell) == previous "base" +// base + 1*sizeof(cell) == function return address +// base + 2*sizeof(cell) == number of arguments +// base + 3*sizeof(cell) == first argument of the function +static void load_argcount(regid reg) +{ + if (reg == sPRI) + stgwrite("\tload.s.pri "); + else + stgwrite("\tload.s.alt "); + outval(2 * sizeof(cell), TRUE); + code_idx += opcodes(1) + opargs(1); +} + +// Load the hidden array argument into ALT. +SC_FUNC void load_hidden_arg() +{ + pushreg(sPRI); + + // Compute an address to the first argument, then add the argument count + // to find the address after the final argument: + // addr.alt 0xc ; Compute &first_arg + // load.s.alt 0x8 ; Load arg count in bytes + // add ; Compute (&first_arg) + argcount + // load.i ; Load *(&first_arg + argcount) + // move.alt ; Move result into ALT. + addr_reg(0xc, sALT); + load_argcount(sPRI); + ob_add(); + load_i(); + move_alt(); + + popreg(sPRI); +} + /* store * * Saves the contents of "primary" into a memory cell, either directly @@ -602,6 +653,12 @@ SC_FUNC void moveto1(void) code_idx+=opcodes(1)+opargs(0); } +SC_FUNC void move_alt(void) +{ + stgwrite("\tmove.alt\n"); + code_idx+=opcodes(1)+opargs(0); +} + /* Push primary or the alternate register onto the stack */ SC_FUNC void pushreg(regid reg)