Merge pull request #42 from alexfru/master

Smaller C fixes.
This commit is contained in:
Serge Vakulenko
2015-04-25 18:12:46 -07:00
3 changed files with 489 additions and 72 deletions

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2012-2014, Alexey Frunze Copyright (c) 2012-2015, Alexey Frunze
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -637,14 +637,22 @@ void GenFxnProlog(void)
} }
STATIC STATIC
void GenLocalAlloc(int size) void GenGrowStack(int size)
{ {
if (!size)
return;
GenPrintInstr3Operands(MipsInstrSubU, 0, GenPrintInstr3Operands(MipsInstrSubU, 0,
MipsOpRegSp, 0, MipsOpRegSp, 0,
MipsOpRegSp, 0, MipsOpRegSp, 0,
MipsOpConst, size); MipsOpConst, size);
} }
STATIC
void GenFxnProlog2(void)
{
GenGrowStack(-CurFxnMinLocalOfs);
}
STATIC STATIC
void GenFxnEpilog(void) void GenFxnEpilog(void)
{ {
@@ -669,6 +677,12 @@ void GenFxnEpilog(void)
MipsOpRegRa, 0); MipsOpRegRa, 0);
} }
STATIC
int GenMaxLocalsSize(void)
{
return 0x7FFFFFFF;
}
STATIC STATIC
int GenGetBinaryOperatorInstr(int tok) int GenGetBinaryOperatorInstr(int tok)
{ {
@@ -1706,7 +1720,7 @@ void GenExpr0(void)
GenPushReg(); GenPushReg();
gotUnary = 0; gotUnary = 0;
if (maxCallDepth != 1 && v < 16) if (maxCallDepth != 1 && v < 16)
GenLocalAlloc(16 - v); GenGrowStack(16 - v);
paramOfs = v - 4; paramOfs = v - 4;
if (maxCallDepth == 1 && paramOfs >= 0 && paramOfs <= 12) if (maxCallDepth == 1 && paramOfs >= 0 && paramOfs <= 12)
{ {
@@ -1760,7 +1774,7 @@ void GenExpr0(void)
} }
else else
{ {
GenLocalAlloc(16); GenGrowStack(16);
} }
if (stack[i - 1][0] == tokIdent) if (stack[i - 1][0] == tokIdent)
{ {
@@ -1774,7 +1788,7 @@ void GenExpr0(void)
} }
if (v < 16) if (v < 16)
v = 16; v = 16;
GenLocalAlloc(-v); GenGrowStack(-v);
break; break;
case tokUnaryStar: case tokUnaryStar:
@@ -2399,4 +2413,3 @@ void GenFin(void)
} }
#endif #endif
} }

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2012-2014, Alexey Frunze Copyright (c) 2012-2015, Alexey Frunze
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -827,8 +827,10 @@ void GenFxnProlog(void)
} }
STATIC STATIC
void GenLocalAlloc(int size) void GenGrowStack(int size)
{ {
if (!size)
return;
#ifdef CAN_COMPILE_32BIT #ifdef CAN_COMPILE_32BIT
if (SizeOfWord == 4 && if (SizeOfWord == 4 &&
OutputFormat != FormatSegHuge && OutputFormat != FormatSegHuge &&
@@ -860,6 +862,12 @@ void GenLocalAlloc(int size)
X86OpConst, size); X86OpConst, size);
} }
STATIC
void GenFxnProlog2(void)
{
GenGrowStack(-CurFxnMinLocalOfs);
}
STATIC STATIC
void GenFxnEpilog(void) void GenFxnEpilog(void)
{ {
@@ -867,6 +875,16 @@ void GenFxnEpilog(void)
GenPrintInstrNoOperand(X86InstrRet); GenPrintInstrNoOperand(X86InstrRet);
} }
STATIC
int GenMaxLocalsSize(void)
{
#ifdef CAN_COMPILE_32BIT
if (SizeOfWord == 4 && OutputFormat != FormatSegHuge)
return 0x7FFFFFFF;
#endif
return 0x7FFF;
}
#ifdef CAN_COMPILE_32BIT #ifdef CAN_COMPILE_32BIT
/* /*
struct INTREGS struct INTREGS
@@ -2654,8 +2672,7 @@ void GenExpr1(void)
GenPrintInstr1Operand(X86InstrCall, 0, GenPrintInstr1Operand(X86InstrCall, 0,
X86OpRegAWord, 0); X86OpRegAWord, 0);
} }
if (v) GenGrowStack(-v);
GenLocalAlloc(-v);
break; break;
case '(': case '(':
@@ -2759,8 +2776,7 @@ void GenExpr0(void)
#endif #endif
GenPrintInstr1Operand(X86InstrCall, 0, GenPrintInstr1Operand(X86InstrCall, 0,
X86OpRegAWord, 0); X86OpRegAWord, 0);
if (v) GenGrowStack(-v);
GenLocalAlloc(-v);
break; break;
case tokUnaryStar: case tokUnaryStar:
@@ -3318,6 +3334,109 @@ void GenFin(void)
puts2(CodeFooter); puts2(CodeFooter);
} }
#ifndef NO_STRUCT_BY_VAL
if (StructPushLabel)
{
char s[1 + 2 + (2 + CHAR_BIT * sizeof StructPushLabel) / 3];
char *p = s + sizeof s;
*--p = '\0';
p = lab2str(p, StructPushLabel);
*--p = '_';
*--p = '_';
if (OutputFormat != FormatFlat)
puts2(CodeHeader);
GenLabel(p, 1);
GenFxnProlog();
if (SizeOfWord == 2)
{
puts2("\tmov\tdx, [bp+2]\n" // dx = return address
"\tmov\tsi, [bp+4]\n" // si = &struct
"\tmov\tcx, [bp+6]\n" // cx = sizeof(struct)
"\tmov\tbp, [bp]\n" // restore bp
"\tmov\tax, cx\n" // ax = sizeof(struct)
"\tinc\tax\n" // ax = sizeof(struct) + 1
"\tand\tax, -2\n" // ax = sizeof(struct) rounded up to multiple of 2 bytes
"\tadd\tsp, 4*2\n" // remove bp, return address and 2 args from stack
"\tsub\tsp, ax"); // allocate stack space for struct
puts2("\tmov\tdi, sp\n" // di = where struct should be copied to
"\tcld\n"
"\trep\tmovsb\n" // copy
"\tpop\tax\n" // return first 2 bytes of struct in ax
"\tpush\tax\n"
"\tpush\tbyte 0\n" // caller will remove this 0 and first 2 bytes of struct from stack (as 2 args)
"\tpush\tdx\n" // and then it will push ax (first 2 bytes of struct) back
"\tret"); // actually return to return address saved in dx
}
#ifdef CAN_COMPILE_32BIT
else if (OutputFormat != FormatSegHuge)
{
// Copying the pushed structure to the stack backwards
// (from higher to lower addresses) in order to correctly
// grow the stack on Windows, page by page
puts2("\tmov\tedx, [ebp+4]\n" // edx = return address
"\tmov\tesi, [ebp+8]\n" // esi = &struct
"\tmov\tecx, [ebp+12]\n" // ecx = sizeof(struct)
"\tmov\tebp, [ebp]\n" // restore ebp
"\tlea\teax, [ecx + 3]\n" // eax = sizeof(struct) + 3
"\tand\teax, -4\n" // eax = sizeof(struct) rounded up to multiple of 4 bytes
"\tadd\tesp, 4*4\n" // remove ebp, return address and 2 args from stack
"\tsub\tesp, eax"); // allocate stack space for struct
puts2("\tlea\tesi, [esi + ecx - 1]\n" // esi = &last byte of struct
"\tlea\tedi, [esp + ecx - 1]\n" // edi = where it should be copied to
"\tstd\n"
"\trep\tmovsb\n" // copy
"\tcld\n"
"\tmov\teax, [esp]\n" // return first 4 bytes of struct in eax
"\tpush\t0\n" // caller will remove this 0 and first 4 bytes of struct from stack (as 2 args)
"\tpush\tedx\n" // and then it will push eax (first 4 bytes of struct) back
"\tret"); // actually return to return address saved in edx
}
else
{
puts2("\tmov\tedx, [ebp+4]\n" // edx = return address (seg:ofs)
"\tmov\tesi, [ebp+8]\n" // esi = &struct (phys)
"\tror\tesi, 4\n"
"\tmov\tds, si\n"
"\tshr\tesi, 28\n" // ds:si = &struct (seg:ofs)
"\tmov\tecx, [ebp+12]\n" // ecx = sizeof(struct)
"\tmov\tebp, [ebp]\n" // restore ebp
"\tlea\teax, [ecx + 3]\n" // eax = sizeof(struct) + 3
"\tand\teax, -4\n" // eax = sizeof(struct) rounded up to multiple of 4 bytes
"\tadd\tsp, 4*4\n" // remove ebp, return address and 2 args from stack
"\tsub\tsp, ax"); // allocate stack space for struct
puts2("\tmov\tax, ss\n"
"\tmov\tes, ax\n" // es = ss
"\tmov\tdi, sp\n" // es:di = where struct should be copied to (seg:ofs)
"\tcld\n"
"\trep\tmovsb\n" // copy; limit to ~64KB since stack size itself is ~64KB max
"\tpop\teax\n" // return first 4 bytes of struct in eax
"\tpush\teax\n"
"\tpush\teax\n" // caller will remove this and first 4 bytes of struct from stack (as 2 args)
"\tpush\tedx\n" // and then it will push eax (first 4 bytes of struct) back
"\tretf"); // actually return to return address saved in edx
}
#endif
// GenFxnEpilog();
if (OutputFormat != FormatFlat)
puts2(CodeFooter);
}
#endif
#ifdef USE_SWITCH_TAB #ifdef USE_SWITCH_TAB
if (SwitchJmpLabel) if (SwitchJmpLabel)
{ {
@@ -3477,4 +3596,3 @@ void GenFin(void)
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2012-2014, Alexey Frunze Copyright (c) 2012-2015, Alexey Frunze
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@ either expressed or implied, of the FreeBSD Project.
/* */ /* */
/* Produces 16/32-bit 80386 assembly output for NASM. */ /* Produces 16/32-bit 80386 assembly output for NASM. */
/* Produces 32-bit MIPS assembly output for gcc/as. */ /* Produces 32-bit MIPS assembly output for gcc/as. */
/* Produces 32-bit TR3200 assembly output for vasm. */
/* */ /* */
/* Main file */ /* Main file */
/* */ /* */
@@ -55,6 +56,20 @@ either expressed or implied, of the FreeBSD Project.
#define NO_FUNC_ #define NO_FUNC_
#define NO_EXTRA_WARNS #define NO_EXTRA_WARNS
#define NO_FOR_DECL #define NO_FOR_DECL
#define NO_STRUCT_BY_VAL
#endif
// Passing and returning structures by value is currenly supported
// on x86 only
#ifdef MIPS
#ifndef NO_STRUCT_BY_VAL
#define NO_STRUCT_BY_VAL
#endif
#endif
#ifdef TR3200
#ifndef NO_STRUCT_BY_VAL
#define NO_STRUCT_BY_VAL
#endif
#endif #endif
#ifndef __SMALLER_C__ #ifndef __SMALLER_C__
@@ -404,12 +419,14 @@ void GenJumpIfEqual(int val, int Label);
STATIC STATIC
void GenFxnProlog(void); void GenFxnProlog(void);
STATIC STATIC
void GenFxnProlog2(void);
STATIC
void GenFxnEpilog(void); void GenFxnEpilog(void);
void GenIsrProlog(void); void GenIsrProlog(void);
void GenIsrEpilog(void); void GenIsrEpilog(void);
STATIC STATIC
void GenLocalAlloc(int Size); int GenMaxLocalsSize(void);
STATIC STATIC
unsigned GenStrData(int generatingCode, unsigned requiredLen); unsigned GenStrData(int generatingCode, unsigned requiredLen);
@@ -631,21 +648,20 @@ int SizeOfWord = 2; // in chars (char can be a multiple of octets); ints and poi
// TBD??? implement a function to allocate N labels with overflow checks // TBD??? implement a function to allocate N labels with overflow checks
int LabelCnt = 1; // label counter for jumps int LabelCnt = 1; // label counter for jumps
int StructCpyLabel = 0; // label of the function to copy structures/unions int StructCpyLabel = 0; // label of the function to copy structures/unions
int StructPushLabel = 0; // label of the function to push structures/unions onto the stack
// call stack (from higher to lower addresses): // call stack (from higher to lower addresses):
// param n // arg n
// ... // ...
// param 1 // arg 1
// return address // return address
// saved xbp register // saved xbp register
// local var 1 // local var 1
// ... // ...
// local var n // local var n
int CurFxnSyntaxPtr = 0; int CurFxnSyntaxPtr = 0;
int CurFxnParamCnt = 0;
int CurFxnParamCntMin = 0; int CurFxnParamCntMin = 0;
int CurFxnParamCntMax = 0; int CurFxnParamCntMax = 0;
int CurFxnParamOfs = 0; // positive
int CurFxnLocalOfs = 0; // negative int CurFxnLocalOfs = 0; // negative
int CurFxnMinLocalOfs = 0; // negative int CurFxnMinLocalOfs = 0; // negative
@@ -2173,7 +2189,11 @@ int GetToken(void)
#endif #endif
#include "cgmips.c" #include "cgmips.c"
#else #else
#ifdef TR3200
#include "cgtr3k2.c"
#else
#include "cgx86.c" #include "cgx86.c"
#endif // #ifdef TR3200
#endif // #ifdef MIPS #endif // #ifdef MIPS
// expr.c code // expr.c code
@@ -3106,6 +3126,26 @@ void simplifyConstExpr(int val, int isConst, int* ExprTypeSynPtr, int top, int b
del(bottom, top - bottom); del(bottom, top - bottom);
} }
STATIC
int AllocLocal(unsigned size)
{
// Let's calculate variable's relative on-stack location
int oldOfs = CurFxnLocalOfs;
// Note: local vars are word-aligned on the stack
CurFxnLocalOfs = uint2int((CurFxnLocalOfs - size) & ~(SizeOfWord - 1u));
if (CurFxnLocalOfs >= oldOfs ||
CurFxnLocalOfs != truncInt(CurFxnLocalOfs) ||
CurFxnLocalOfs < -GenMaxLocalsSize())
//error("AllocLocal(): Local variables take too much space\n");
errorVarSize();
if (CurFxnMinLocalOfs > CurFxnLocalOfs)
CurFxnMinLocalOfs = CurFxnLocalOfs;
return CurFxnLocalOfs;
}
// DONE: sizeof(type) // DONE: sizeof(type)
// DONE: "sizeof expr" // DONE: "sizeof expr"
// DONE: constant expressions // DONE: constant expressions
@@ -3253,7 +3293,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
break; break;
default: default:
#ifdef CAN_COMPILE_32BIT #ifdef CAN_COMPILE_32BIT
if (castSize && castSize != SizeOfWord && -castSize != SizeOfWord) if (castSize && castSize != SizeOfWord)
{ {
if (castSize == 2) if (castSize == 2)
{ {
@@ -3269,7 +3309,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
s -= 0x10000; s -= 0x10000;
} }
} }
else else // fallthrough
#endif #endif
{ {
// cast to int/unsigned/pointer // cast to int/unsigned/pointer
@@ -4006,45 +4046,142 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
int tmpSynPtr, c; int tmpSynPtr, c;
int minParams, maxParams; int minParams, maxParams;
int firstParamSynPtr; int firstParamSynPtr;
#ifndef NO_STRUCT_BY_VAL
int oldIdx, oldSp;
unsigned structSize = 0;
int retStruct = 0;
int retOfs = 0;
#endif
exprval(idx, ExprTypeSynPtr, ConstExpr); exprval(idx, ExprTypeSynPtr, ConstExpr);
if (!GetFxnInfo(*ExprTypeSynPtr, &minParams, &maxParams, ExprTypeSynPtr, &firstParamSynPtr)) if (!GetFxnInfo(*ExprTypeSynPtr, &minParams, &maxParams, ExprTypeSynPtr, &firstParamSynPtr))
//error("exprval(): function or function pointer expected\n"); //error("exprval(): function or function pointer expected\n");
errorOpType(); errorOpType();
// DONE: validate the number of function parameters // DONE: validate the number of function arguments
// DONE: warnings on int<->pointer substitution in params // DONE: warnings on int<->pointer substitution in params/args
// evaluate function parameters #ifndef NO_STRUCT_BY_VAL
// If a structure is returned, allocate space for it on the stack
// and pass its location as the first (implicit) argument.
if (ParseLevel &&
*ExprTypeSynPtr >= 0 &&
SyntaxStack[*ExprTypeSynPtr][0] == tokStructPtr)
{
unsigned sz = GetDeclSize(*ExprTypeSynPtr, 0);
// Make sure the return structure type is complete
if (!sz)
errorOpType();
retOfs = AllocLocal(sz);
// Transform fxn(args) into fxn(pretval, args)
ins(*idx + 1, ',');
ins2(*idx + 1, tokLocalOfs, retOfs);
retStruct = 1;
}
#endif
// evaluate function arguments
c = 0; c = 0;
while (stack[*idx][0] != '(') while (stack[*idx][0] != '(')
{ {
// add a comma after the first (last to be pushed) parameter, #ifndef NO_STRUCT_BY_VAL
// so all parameters can be pushed whenever a comma is encountered int gotStructs;
#endif
// add a comma after the first (last to be pushed) argument,
// so all arguments can be pushed whenever a comma is encountered
if (!c) if (!c)
ins(*idx + 1, ','); ins(*idx + 1, ',');
#ifndef NO_STRUCT_BY_VAL
oldIdx = *idx;
oldSp = sp;
#endif
exprval(idx, &tmpSynPtr, ConstExpr); exprval(idx, &tmpSynPtr, ConstExpr);
//error("exprval(): function parameters cannot be of type 'void'\n"); //error("exprval(): function arguments cannot be of type 'void'\n");
#ifdef NO_STRUCT_BY_VAL
scalarTypeCheck(tmpSynPtr); scalarTypeCheck(tmpSynPtr);
#else
nonVoidTypeCheck(tmpSynPtr);
// If the argument is a structure, push it by calling a dedicated function
gotStructs = tmpSynPtr >= 0 && SyntaxStack[tmpSynPtr][0] == tokStructPtr;
if (gotStructs)
{
unsigned sz = GetDeclSize(tmpSynPtr, 0);
int i = oldIdx - (oldSp - sp);
stack[i][0] = ')';
stack[i][1] = SizeOfWord * 2;
if (!StructPushLabel)
StructPushLabel = LabelCnt++;
// The code generator expects functions to return values.
// If a function argument is a value produced by another function,
// as is the case here, the code generator will naturally
// want/need to push something of the size of the machine word.
// This works perfectly with non-structures.
// But we only want to push the structure without pushing any other words.
// In order to avoid involving changes in the code generator,
// we make the function that pushes structures onto the stack
// push all words but the first one. The dedicated function will
// return this word and the code generator will push it.
// This is ugly.
ins2(i, tokIdent, AddNumericIdent__(StructPushLabel));
ins(i, ',');
i = *idx + 1;
ins(i, ',');
ins2(i, tokNumUint, uint2int(sz));
ins2(i, '(', SizeOfWord * 2);
if (sz > (unsigned)GenMaxLocalsSize())
errorVarSize();
// Structures will be padded to machine word boundary when pushed
sz = (sz + SizeOfWord - 1) & ~(SizeOfWord - 1u);
// Count the cumulative size of the pushed structures, excluding
// the first words that will be pushed by the code generator
if (structSize + sz < structSize)
errorVarSize();
structSize += sz - SizeOfWord;
if (structSize > (unsigned)GenMaxLocalsSize())
errorVarSize();
// TBD??? complete overflow checks (an expression may contain more than one call)?
}
#endif
if (++c > maxParams) if (++c > maxParams)
error("Too many function parameters\n"); error("Too many function arguments\n");
#ifndef NO_STRUCT_BY_VAL
#ifndef CHECK_FXN_ARGS
#define CHECK_FXN_ARGS
#endif
#endif
#ifndef NO_EXTRA_WARNS #ifndef NO_EXTRA_WARNS
// Issue a warning if the parameter has to be a pointer but isn't and vice versa. #ifndef CHECK_FXN_ARGS
#define CHECK_FXN_ARGS
#endif
#endif
#ifdef CHECK_FXN_ARGS
// Issue a warning if the argument has to be a pointer but isn't and vice versa.
// DONE: struct type compat checks
// TBD??? Compare pointer types deeply as in compatCheck()??? // TBD??? Compare pointer types deeply as in compatCheck()???
// TBD??? Issue a similar warning for return values and initializers??? // TBD??? Issue a similar warning for return values and initializers???
if (c <= minParams) if (c <= minParams)
{ {
int t;
#ifndef NO_EXTRA_WARNS
int gotPtr = tmpSynPtr < 0; int gotPtr = tmpSynPtr < 0;
int needPtr; int needPtr;
int t;
if (!gotPtr) if (!gotPtr)
{ {
t = SyntaxStack[tmpSynPtr][0]; t = SyntaxStack[tmpSynPtr][0];
gotPtr = (t == '*') | (t == '[') | (t == '('); // arrays and functions decay to pointers gotPtr = (t == '*') | (t == '[') | (t == '('); // arrays and functions decay to pointers
} }
#endif
// Find the type of the formal parameter in the function declaration // Find the type of the formal parameter in the function declaration
while ((t = SyntaxStack[firstParamSynPtr][0]) != tokIdent) while ((t = SyntaxStack[firstParamSynPtr][0]) != tokIdent)
{ {
@@ -4061,6 +4198,17 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
firstParamSynPtr++; firstParamSynPtr++;
} }
firstParamSynPtr++; firstParamSynPtr++;
#ifndef NO_STRUCT_BY_VAL
gotStructs += (SyntaxStack[firstParamSynPtr][0] == tokStructPtr) * 2;
if (gotStructs)
{
// Structures must be of the same type
if (gotStructs != 3 ||
SyntaxStack[tmpSynPtr][1] != SyntaxStack[firstParamSynPtr][1])
errorOpType();
}
#endif
#ifndef NO_EXTRA_WARNS
needPtr = SyntaxStack[firstParamSynPtr][0] == '*'; needPtr = SyntaxStack[firstParamSynPtr][0] == '*';
if (needPtr != gotPtr && if (needPtr != gotPtr &&
// Make an exception for integer constants equal to 0, treat them as NULL pointers // Make an exception for integer constants equal to 0, treat them as NULL pointers
@@ -4070,9 +4218,10 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
!stack[*idx + 1][1] !stack[*idx + 1][1]
) )
) )
warning("Expected %spointer in parameter %d\n", needPtr ? "" : "non-", c); warning("Expected %spointer in argument %d\n", needPtr ? "" : "non-", c);
#endif
} }
#endif // NO_EXTRA_WARNS #endif // CHECK_FXN_ARGS
if (stack[*idx][0] == ',') if (stack[*idx][0] == ',')
--*idx; --*idx;
@@ -4080,10 +4229,31 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
--*idx; --*idx;
if (c < minParams) if (c < minParams)
error("Too few function parameters\n"); error("Too few function arguments\n");
// store the cumulative parameter size in the function call operators // store the cumulative argument size in the function call operators
stack[1 + *idx][1] = stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = c * SizeOfWord; {
int i = oldIdxRight + 1 - (oldSpRight - sp);
#ifndef NO_STRUCT_BY_VAL
// Count the implicit param/arg for returned structure
c += retStruct;
#endif
stack[1 + *idx][1] = stack[i][1] = c * SizeOfWord;
#ifndef NO_STRUCT_BY_VAL
// Correct the value by which the stack pointer
// will be incremented after the call
stack[i][1] += structSize;
// If a structure is returned, transform
// fxn(pretval, args) into *(fxn(pretval, args), pretval)
if (retStruct)
{
ins(i + 1, tokUnaryStar);
ins(i + 1, tokComma);
ins2(i + 1, tokLocalOfs, retOfs);
ins(i + 1, tokVoid);
}
#endif
}
*ConstExpr = 0; *ConstExpr = 0;
} }
@@ -4093,6 +4263,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
case tokComma: case tokComma:
{ {
int oldIdxLeft, oldSpLeft; int oldIdxLeft, oldSpLeft;
int retStruct = 0;
s = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]); s = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
oldIdxLeft = *idx; oldIdxLeft = *idx;
oldSpLeft = sp; oldSpLeft = sp;
@@ -4103,6 +4274,8 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
exprval(idx, ExprTypeSynPtr, &constExpr[0]); exprval(idx, ExprTypeSynPtr, &constExpr[0]);
*ConstExpr = constExpr[0] && constExpr[1]; *ConstExpr = constExpr[0] && constExpr[1];
*ExprTypeSynPtr = RightExprTypeSynPtr; *ExprTypeSynPtr = RightExprTypeSynPtr;
retStruct = RightExprTypeSynPtr >= 0 && SyntaxStack[RightExprTypeSynPtr][0] == tokStructPtr;
if (*ConstExpr) if (*ConstExpr)
{ {
// both subexprs are const, remove both and comma // both subexprs are const, remove both and comma
@@ -4110,10 +4283,27 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
} }
else if (constExpr[0]) else if (constExpr[0])
{ {
// only left subexpr is const, remove it and comma // only left subexpr is const, remove it
del(*idx + 1, oldIdxLeft - (oldSpLeft - sp) - *idx); del(*idx + 1, oldIdxLeft - (oldSpLeft - sp) - *idx);
if (!retStruct)
// Ensure non-lvalue-ness of the result by changing comma to unary plus
// and thus hiding dereference, if any
stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUnaryPlus;
else
// However, (something, struct).member should still be allowed,
// so, comma needs to produce lvalue
del(oldIdxRight + 1 - (oldSpRight - sp), 1); del(oldIdxRight + 1 - (oldSpRight - sp), 1);
} }
else if (retStruct)
{
// However, (something, struct).member should still be allowed,
// so, comma needs to produce lvalue. Swap comma and structure dereference.
int i = oldIdxRight + 1 - (oldSpRight - sp);
stack[i][0] = tokUnaryStar;
stack[i][1] = stack[i - 1][1];
stack[i - 1][0] = tokComma;
}
} }
break; break;
@@ -4322,8 +4512,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
--*idx; --*idx;
exprval(idx, ExprTypeSynPtr, ConstExpr); exprval(idx, ExprTypeSynPtr, ConstExpr);
if (*ExprTypeSynPtr >= 0 && SyntaxStack[*ExprTypeSynPtr][0] == '*') decayArray(ExprTypeSynPtr, 0);
*ExprTypeSynPtr = -(*ExprTypeSynPtr + 1); // TBD!!! shouldn't this be done elsewhere?
if (*ExprTypeSynPtr >= 0 || if (*ExprTypeSynPtr >= 0 ||
SyntaxStack[-*ExprTypeSynPtr][0] != tokStructPtr) SyntaxStack[-*ExprTypeSynPtr][0] != tokStructPtr)
@@ -4393,6 +4582,9 @@ STATIC
int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int* ConstVal, int option, int option2) int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int* ConstVal, int option, int option2)
{ {
int identFirst = tok == tokIdent; int identFirst = tok == tokIdent;
#ifndef NO_STRUCT_BY_VAL
int oldOfs = CurFxnLocalOfs;
#endif
*ConstVal = *ConstExpr = 0; *ConstVal = *ConstExpr = 0;
*ExprTypeSynPtr = SymVoidSynPtr; *ExprTypeSynPtr = SymVoidSynPtr;
@@ -4544,6 +4736,11 @@ int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int*
} }
ExprLevel--; ExprLevel--;
#ifndef NO_STRUCT_BY_VAL
// Reclaim stack space used by temporary structure/union objects
// returned by functions
CurFxnLocalOfs = oldOfs;
#endif
return tok; return tok;
} }
@@ -4570,7 +4767,7 @@ void DetermineVaListType(void)
char testbuf[3][CHAR_BIT * sizeof(void*) + 1]; char testbuf[3][CHAR_BIT * sizeof(void*) + 1];
// TBD!!! This is not good. Really need the va_something macros. // TBD!!! This is not good. Really need the va_something macros.
// Test whether va_list is a pointer to the first optional parameter or // Test whether va_list is a pointer to the first optional argument or
// an array of one element containing said pointer // an array of one element containing said pointer
testptr[0] = &testptr[1]; testptr[0] = &testptr[1];
testptr[1] = &testptr[0]; testptr[1] = &testptr[0];
@@ -5576,7 +5773,7 @@ int ParseBase(int tok, int base[2])
} }
else if (ParamLevel) else if (ParamLevel)
{ {
// structure/union/enum declarations aren't supported in function parameters // new structure/union/enum declarations aren't supported in function parameters
errorDecl(); errorDecl();
} }
@@ -5595,7 +5792,7 @@ int ParseBase(int tok, int base[2])
{ {
unsigned structInfo[4], sz, alignment, tmp; unsigned structInfo[4], sz, alignment, tmp;
// structure/union/enum declarations aren't supported in expressions and function parameters // new structure/union/enum declarations aren't supported in expressions and function parameters
if (ExprLevel || ParamLevel) if (ExprLevel || ParamLevel)
errorDecl(); errorDecl();
@@ -6378,11 +6575,13 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
isFxn = SyntaxStack[lastSyntaxPtr + 1][0] == '('; isFxn = SyntaxStack[lastSyntaxPtr + 1][0] == '(';
#ifdef NO_STRUCT_BY_VAL
if (isFxn && if (isFxn &&
SyntaxStack[SyntaxStackCnt - 1][0] == tokStructPtr && SyntaxStack[SyntaxStackCnt - 1][0] == tokStructPtr &&
SyntaxStack[SyntaxStackCnt - 2][0] == ')') SyntaxStack[SyntaxStackCnt - 2][0] == ')')
// structure returning isn't supported currently // structure returning isn't supported currently
errorDecl(); errorDecl();
#endif
isArray = SyntaxStack[lastSyntaxPtr + 1][0] == '['; isArray = SyntaxStack[lastSyntaxPtr + 1][0] == '[';
isIncompleteArr = isArray && SyntaxStack[lastSyntaxPtr + 2][1] == 0; isIncompleteArr = isArray && SyntaxStack[lastSyntaxPtr + 2][1] == 0;
@@ -6734,26 +6933,9 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
if (isLocal) if (isLocal)
{ {
int oldOfs;
// Let's calculate variable's relative on-stack location
oldOfs = CurFxnLocalOfs;
// Note: local vars are word-aligned on the stack
CurFxnLocalOfs = uint2int((CurFxnLocalOfs + 0u - sz) & ~(SizeOfWord - 1u));
if (CurFxnLocalOfs >= oldOfs || CurFxnLocalOfs != truncInt(CurFxnLocalOfs))
//error("ParseDecl(): Local variables take too much space\n");
errorVarSize();
#ifdef CAN_COMPILE_32BIT
if (OutputFormat == FormatSegHuge && CurFxnLocalOfs < -0x7FFF)
errorVarSize();
#endif
// Now that the size of the local is certainly known, // Now that the size of the local is certainly known,
// update its offset in the offset token // update its offset in the offset token
SyntaxStack[lastSyntaxPtr + 1][1] = CurFxnLocalOfs; SyntaxStack[lastSyntaxPtr + 1][1] = AllocLocal(sz);
if (CurFxnMinLocalOfs > CurFxnLocalOfs)
CurFxnMinLocalOfs = CurFxnLocalOfs;
#ifndef NO_ANNOTATIONS #ifndef NO_ANNOTATIONS
DumpDecl(lastSyntaxPtr, 0); DumpDecl(lastSyntaxPtr, 0);
@@ -6808,6 +6990,7 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
// Since a local integer variable always takes as much space as a whole int, // Since a local integer variable always takes as much space as a whole int,
// we can optimize code generation a bit by storing the initializer as an int. // we can optimize code generation a bit by storing the initializer as an int.
// This is an old accidental optimization and I preserve it for now. // This is an old accidental optimization and I preserve it for now.
// Note, this implies a little-endian CPU.
stack[sp - 1][1] = SizeOfWord; stack[sp - 1][1] = SizeOfWord;
} }
@@ -6841,6 +7024,14 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
ParseLevel++; ParseLevel++;
GetFxnInfo(lastSyntaxPtr, &CurFxnParamCntMin, &CurFxnParamCntMax, &CurFxnReturnExprTypeSynPtr, NULL); // get return type GetFxnInfo(lastSyntaxPtr, &CurFxnParamCntMin, &CurFxnParamCntMax, &CurFxnReturnExprTypeSynPtr, NULL); // get return type
#ifndef NO_STRUCT_BY_VAL
// Make sure the return structure type is complete
if (CurFxnReturnExprTypeSynPtr >= 0 &&
SyntaxStack[CurFxnReturnExprTypeSynPtr][0] == tokStructPtr &&
!GetDeclSize(CurFxnReturnExprTypeSynPtr, 0))
errorDecl();
#endif
if (OutputFormat != FormatFlat) if (OutputFormat != FormatFlat)
puts2(CodeHeader); puts2(CodeHeader);
@@ -6913,8 +7104,7 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
GenFxnEpilog(); GenFxnEpilog();
GenNumLabel(locAllocLabel + 1); GenNumLabel(locAllocLabel + 1);
if (CurFxnMinLocalOfs) GenFxnProlog2();
GenLocalAlloc(-CurFxnMinLocalOfs);
GenJumpUncond(locAllocLabel); GenJumpUncond(locAllocLabel);
if (OutputFormat != FormatFlat) if (OutputFormat != FormatFlat)
puts2(CodeFooter); puts2(CodeFooter);
@@ -7061,11 +7251,13 @@ void ParseFxnParams(int tok)
errorUnexpectedVoid(); errorUnexpectedVoid();
} }
#ifdef NO_STRUCT_BY_VAL
if (SyntaxStack[SyntaxStackCnt - 1][0] == tokStructPtr && if (SyntaxStack[SyntaxStackCnt - 1][0] == tokStructPtr &&
t != '*' && t != '*' &&
t != ']') t != ']')
// structure passing and returning isn't supported currently // structure passing and returning isn't supported currently
errorDecl(); errorDecl();
#endif
if (tok == ')') if (tok == ')')
break; break;
@@ -7083,6 +7275,7 @@ STATIC
void AddFxnParamSymbols(int SyntaxPtr) void AddFxnParamSymbols(int SyntaxPtr)
{ {
int i; int i;
unsigned paramOfs = 2 * SizeOfWord; // ret addr, xbp
if (SyntaxPtr < 0 || if (SyntaxPtr < 0 ||
SyntaxPtr > SyntaxStackCnt - 3 || SyntaxPtr > SyntaxStackCnt - 3 ||
@@ -7092,11 +7285,29 @@ void AddFxnParamSymbols(int SyntaxPtr)
errorInternal(6); errorInternal(6);
CurFxnSyntaxPtr = SyntaxPtr; CurFxnSyntaxPtr = SyntaxPtr;
CurFxnParamCnt = 0;
CurFxnParamOfs = 2 * SizeOfWord; // ret addr, xbp
CurFxnLocalOfs = 0; CurFxnLocalOfs = 0;
CurFxnMinLocalOfs = 0; CurFxnMinLocalOfs = 0;
#ifndef NO_STRUCT_BY_VAL
if (CurFxnReturnExprTypeSynPtr >= 0 &&
SyntaxStack[CurFxnReturnExprTypeSynPtr][0] == tokStructPtr)
{
// The function returns a struct/union via an implicit param/arg (pointer to struct/union)
// before its first formal param/arg, add this implicit param/arg
#ifndef NO_ANNOTATIONS
int paramPtr = SyntaxStackCnt;
#endif
PushSyntax2(tokIdent, AddIdent("@")); // special implicit param/arg (pretval) pointing to structure receptacle
PushSyntax2(tokLocalOfs, paramOfs);
PushSyntax('*');
PushSyntax2(tokStructPtr, SyntaxStack[CurFxnReturnExprTypeSynPtr][1]);
paramOfs += SizeOfWord;
#ifndef NO_ANNOTATIONS
DumpDecl(paramPtr, 0);
#endif
}
#endif
SyntaxPtr += 2; // skip "ident(" SyntaxPtr += 2; // skip "ident("
for (i = SyntaxPtr; i < SyntaxStackCnt; i++) for (i = SyntaxPtr; i < SyntaxStackCnt; i++)
@@ -7105,7 +7316,7 @@ void AddFxnParamSymbols(int SyntaxPtr)
if (tok == tokIdent) if (tok == tokIdent)
{ {
int sz; unsigned sz;
#ifndef NO_ANNOTATIONS #ifndef NO_ANNOTATIONS
int paramPtr; int paramPtr;
#endif #endif
@@ -7119,19 +7330,28 @@ void AddFxnParamSymbols(int SyntaxPtr)
if (SyntaxStack[i + 1][0] == tokEllipsis) // "ident(something,...)" = no more params if (SyntaxStack[i + 1][0] == tokEllipsis) // "ident(something,...)" = no more params
break; break;
// Make sure the parameter is not an incomplete structure
sz = GetDeclSize(i, 0); sz = GetDeclSize(i, 0);
if (sz == 0) if (sz == 0)
//error("Internal error: AddFxnParamSymbols(): GetDeclSize() = 0\n"); //error("Internal error: AddFxnParamSymbols(): GetDeclSize() = 0\n");
errorInternal(8); //errorInternal(8);
errorDecl();
// Let's calculate this parameter's relative on-stack location // Let's calculate this parameter's relative on-stack location
CurFxnParamOfs = (CurFxnParamOfs + SizeOfWord - 1) / SizeOfWord * SizeOfWord;
#ifndef NO_ANNOTATIONS #ifndef NO_ANNOTATIONS
paramPtr = SyntaxStackCnt; paramPtr = SyntaxStackCnt;
#endif #endif
PushSyntax2(SyntaxStack[i][0], SyntaxStack[i][1]); PushSyntax2(SyntaxStack[i][0], SyntaxStack[i][1]);
PushSyntax2(tokLocalOfs, CurFxnParamOfs); PushSyntax2(tokLocalOfs, paramOfs);
CurFxnParamOfs += sz;
if (sz + SizeOfWord - 1 < sz)
errorVarSize();
sz = (sz + SizeOfWord - 1) & ~(SizeOfWord - 1u);
if (paramOfs + sz < paramOfs)
errorVarSize();
paramOfs += sz;
if (paramOfs > (unsigned)GenMaxLocalsSize())
errorVarSize();
// Duplicate this parameter in the symbol table // Duplicate this parameter in the symbol table
i++; i++;
@@ -7140,7 +7360,6 @@ void AddFxnParamSymbols(int SyntaxPtr)
tok = SyntaxStack[i][0]; tok = SyntaxStack[i][0];
if (tok == tokIdent || tok == ')') if (tok == tokIdent || tok == ')')
{ {
CurFxnParamCnt++;
#ifndef NO_ANNOTATIONS #ifndef NO_ANNOTATIONS
DumpDecl(paramPtr, 0); DumpDecl(paramPtr, 0);
#endif #endif
@@ -7269,10 +7488,77 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
errorUnexpectedToken(tok); errorUnexpectedToken(tok);
if (gotUnary) if (gotUnary)
//error("ParseStatement(): cannot return a value of type 'void'\n"); //error("ParseStatement(): cannot return a value of type 'void'\n");
#ifdef NO_STRUCT_BY_VAL
scalarTypeCheck(synPtr); scalarTypeCheck(synPtr);
#else
nonVoidTypeCheck(synPtr);
#endif
} }
if (gotUnary) if (gotUnary)
{
#ifndef NO_STRUCT_BY_VAL
int structs = (synPtr >= 0 && SyntaxStack[synPtr][0] == tokStructPtr) +
(CurFxnReturnExprTypeSynPtr >= 0 && SyntaxStack[CurFxnReturnExprTypeSynPtr][0] == tokStructPtr) * 2;
if (structs)
{
if (structs != 3 ||
SyntaxStack[synPtr][1] != SyntaxStack[CurFxnReturnExprTypeSynPtr][1])
errorOpType();
// Transform "return *pstruct" into structure assignment ("*pretval = *pstruct")
// via function call "fxn(sizeof *pretval, pstruct, pretval)".
// There are a couple of differences to how this is implemented in the assignment operator:
// - the structure dereference has already been dropped from *pstruct by ParseExpr(),
// so it isn't removed here
// - we don't add the structure dereference on top of the value returned by "fxn()"
// because the return statement is not an expression that can be an operand into another
// operator
ins(0, ',');
ins2(0, tokUnaryStar, SizeOfWord); // dereference to extract the implicit param/arg (pretval) from the stack
ins2(0, tokLocalOfs, SyntaxStack[FindSymbol("@") + 1][1]); // special implicit param/arg (pretval) pointing to structure receptacle
ins2(0, '(', SizeOfWord * 3);
push(',');
push2(tokNumUint, GetDeclSize(synPtr, 0));
push(',');
if (!StructCpyLabel)
StructCpyLabel = LabelCnt++;
push2(tokIdent, AddNumericIdent__(StructCpyLabel));
push2(')', SizeOfWord * 3);
}
else // fallthrough
#endif
{
// If return value (per function declaration) is a scalar type smaller than machine word,
// properly zero- or sign-extend the returned value to machine word size.
// TBD??? Move this cast to the caller?
int castSize = GetDeclSize(CurFxnReturnExprTypeSynPtr, 1);
if (castSize != SizeOfWord &&
(synPtr < 0 || castSize != GetDeclSize(synPtr, 1)))
{
switch (castSize)
{
case 1:
push(tokUChar);
break;
case -1:
push(tokSChar);
break;
#ifdef CAN_COMPILE_32BIT
case 2:
push(tokUShort);
break;
case -2:
push(tokShort);
break;
#endif
}
}
}
GenExpr(); GenExpr();
}
GenJumpUncond(CurFxnEpilogLabel); GenJumpUncond(CurFxnEpilogLabel);
tok = GetToken(); tok = GetToken();
} }
@@ -7572,7 +7858,7 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
GenNumLabel(labelAfter); GenNumLabel(labelAfter);
#ifndef NO_FOR_DECL #ifndef NO_FOR_DECL
// undo any declarations done in the for() parameter set. // undo any declarations made in the first clause of for
if (decl) if (decl)
{ {
UndoNonLabelIdents(undoIdents); // remove all identifier names, except those of labels UndoNonLabelIdents(undoIdents); // remove all identifier names, except those of labels
@@ -7931,7 +8217,7 @@ int main(int argc, char** argv)
GenInit(); GenInit();
// Parse the command line parameters // Parse the command line arguments
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
{ {
// DONE: move code-generator-specific options to // DONE: move code-generator-specific options to