Merge pull request #121 from alliedmodders/fix-variadic
Fix returning strings from variadic functions.
This commit is contained in:
commit
7f25e28d01
|
@ -598,6 +598,8 @@ SC_FUNC void addr2cell(void);
|
||||||
SC_FUNC void char2addr(void);
|
SC_FUNC void char2addr(void);
|
||||||
SC_FUNC void charalign(void);
|
SC_FUNC void charalign(void);
|
||||||
SC_FUNC void addconst(cell value);
|
SC_FUNC void addconst(cell value);
|
||||||
|
SC_FUNC void move_alt(void);
|
||||||
|
SC_FUNC void load_hidden_arg();
|
||||||
|
|
||||||
/* Code generation functions for arithmetic operators.
|
/* Code generation functions for arithmetic operators.
|
||||||
*
|
*
|
||||||
|
|
|
@ -5230,6 +5230,18 @@ static symbol *fetchlab(char *name)
|
||||||
return sym;
|
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
|
/* doreturn
|
||||||
*
|
*
|
||||||
* Global references: rettype (altered)
|
* 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
|
* 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)
|
* 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);
|
arraysize=calc_arraysize(dim,numdim,0);
|
||||||
memcopy(arraysize*sizeof(cell)); /* source already in PRI */
|
memcopy(arraysize*sizeof(cell)); /* source already in PRI */
|
||||||
/* moveto1(); is not necessary, callfunction() does a popreg() */
|
/* moveto1(); is not necessary, callfunction() does a popreg() */
|
||||||
|
|
|
@ -363,6 +363,12 @@ SC_FUNC void alignframe(int numbytes)
|
||||||
code_idx+=opcodes(5)+opargs(4);
|
code_idx+=opcodes(5)+opargs(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SC_FUNC void load_i()
|
||||||
|
{
|
||||||
|
stgwrite("\tload.i\n");
|
||||||
|
code_idx+=opcodes(1);
|
||||||
|
}
|
||||||
|
|
||||||
/* rvalue
|
/* rvalue
|
||||||
*
|
*
|
||||||
* Generate code to get the value of a symbol into "primary".
|
* Generate code to get the value of a symbol into "primary".
|
||||||
|
@ -374,8 +380,7 @@ SC_FUNC void rvalue(value *lval)
|
||||||
sym=lval->sym;
|
sym=lval->sym;
|
||||||
if (lval->ident==iARRAYCELL) {
|
if (lval->ident==iARRAYCELL) {
|
||||||
/* indirect fetch, address already in PRI */
|
/* indirect fetch, address already in PRI */
|
||||||
stgwrite("\tload.i\n");
|
load_i();
|
||||||
code_idx+=opcodes(1);
|
|
||||||
} else if (lval->ident==iARRAYCHAR) {
|
} else if (lval->ident==iARRAYCHAR) {
|
||||||
/* indirect fetch of a character from a pack, address already in PRI */
|
/* indirect fetch of a character from a pack, address already in PRI */
|
||||||
stgwrite("\tlodb.i ");
|
stgwrite("\tlodb.i ");
|
||||||
|
@ -448,6 +453,52 @@ SC_FUNC void address(symbol *sym,regid reg)
|
||||||
code_idx+=opcodes(1)+opargs(1);
|
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
|
/* store
|
||||||
*
|
*
|
||||||
* Saves the contents of "primary" into a memory cell, either directly
|
* 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);
|
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
|
/* Push primary or the alternate register onto the stack
|
||||||
*/
|
*/
|
||||||
SC_FUNC void pushreg(regid reg)
|
SC_FUNC void pushreg(regid reg)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user