Smaller C: improvements
All architectures: - "return" statement at function's end doesn't jump to immediately following epilog anymore - zero and non-zero constants are recognized in conditional expressions of "if", "do/while" and "for" statements, no code generated to evaluate these constant conditions and related unnecessary jumps aren't generated anymore either - in "for (clause-1; expr-2; expr-3) body", "expr-3" and "body" are now reordered to the more natural code flow "body expr-3", thereby getting rid of unnecessary jumps MIPS code generator: - function prologue/epilogue shortened further - RA is not explicitly saved/restored in leaf functions - assignment of 0 (e.g. "int a = 0;") is done from register 0 directly, avoiding a load of a constant
This commit is contained in:
@@ -516,13 +516,16 @@ void GenJumpIfNotZero(int label)
|
||||
}
|
||||
|
||||
fpos_t GenPrologPos;
|
||||
int GenLeaf;
|
||||
|
||||
STATIC
|
||||
void GenWriteFrameSize(void)
|
||||
{
|
||||
unsigned size = -CurFxnMinLocalOfs;
|
||||
int pfx = size ? ' ' : '#';
|
||||
printf2("\t%csubu\t$29, $29, %10u\n", pfx, size); // 10 chars are enough for 32-bit unsigned ints
|
||||
unsigned size = 8/*RA + FP*/ - CurFxnMinLocalOfs;
|
||||
printf2("\tsubu\t$29, $29, %10u\n", size); // 10 chars are enough for 32-bit unsigned ints
|
||||
printf2("\tsw\t$30, %10u($29)\n", size - 8);
|
||||
printf2("\taddu\t$30, $29, %10u\n", size - 8);
|
||||
printf2("\t%csw\t$31, 4($30)\n", GenLeaf ? '#' : ' ');
|
||||
}
|
||||
|
||||
STATIC
|
||||
@@ -538,23 +541,6 @@ void GenUpdateFrameSize(void)
|
||||
STATIC
|
||||
void GenFxnProlog(void)
|
||||
{
|
||||
GenPrintInstr3Operands(MipsInstrSubU, 0,
|
||||
MipsOpRegSp, 0,
|
||||
MipsOpRegSp, 0,
|
||||
MipsOpConst, 8);
|
||||
|
||||
GenPrintInstr2Operands(MipsInstrSW, 0,
|
||||
MipsOpRegRa, 0,
|
||||
MipsOpIndRegSp, 4);
|
||||
|
||||
GenPrintInstr2Operands(MipsInstrSW, 0,
|
||||
MipsOpRegFp, 0,
|
||||
MipsOpIndRegSp, 0);
|
||||
|
||||
GenPrintInstr2Operands(MipsInstrMov, 0,
|
||||
MipsOpRegFp, 0,
|
||||
MipsOpRegSp, 0);
|
||||
|
||||
if (CurFxnParamCntMax)
|
||||
{
|
||||
int i, cnt = CurFxnParamCntMax;
|
||||
@@ -563,9 +549,11 @@ void GenFxnProlog(void)
|
||||
for (i = 0; i < cnt; i++)
|
||||
GenPrintInstr2Operands(MipsInstrSW, 0,
|
||||
MipsOpRegA0 + i, 0,
|
||||
MipsOpIndRegFp, 8 + 4 * i);
|
||||
MipsOpIndRegSp, 4 * i);
|
||||
}
|
||||
|
||||
GenLeaf = 1; // will be reset to 0 if a call is generated
|
||||
|
||||
fgetpos(OutFile, &GenPrologPos);
|
||||
GenWriteFrameSize();
|
||||
}
|
||||
@@ -586,22 +574,19 @@ void GenFxnEpilog(void)
|
||||
{
|
||||
GenUpdateFrameSize();
|
||||
|
||||
GenPrintInstr2Operands(MipsInstrMov, 0,
|
||||
MipsOpRegSp, 0,
|
||||
MipsOpRegFp, 0);
|
||||
if (!GenLeaf)
|
||||
GenPrintInstr2Operands(MipsInstrLW, 0,
|
||||
MipsOpRegRa, 0,
|
||||
MipsOpIndRegFp, 4);
|
||||
|
||||
GenPrintInstr2Operands(MipsInstrLW, 0,
|
||||
MipsOpRegFp, 0,
|
||||
MipsOpIndRegSp, 0);
|
||||
|
||||
GenPrintInstr2Operands(MipsInstrLW, 0,
|
||||
MipsOpRegRa, 0,
|
||||
MipsOpIndRegSp, 4);
|
||||
MipsOpIndRegFp, 0);
|
||||
|
||||
GenPrintInstr3Operands(MipsInstrAddU, 0,
|
||||
MipsOpRegSp, 0,
|
||||
MipsOpRegSp, 0,
|
||||
MipsOpConst, 8);
|
||||
MipsOpConst, 8/*RA + FP*/ - CurFxnMinLocalOfs);
|
||||
|
||||
GenPrintInstr1Operand(MipsInstrJ, 0,
|
||||
MipsOpRegRa, 0);
|
||||
@@ -1053,6 +1038,8 @@ void GenPopReg(void)
|
||||
|
||||
#define tokRevIdent 0x100
|
||||
#define tokRevLocalOfs 0x101
|
||||
#define tokAssign0 0x102
|
||||
#define tokNum0 0x103
|
||||
|
||||
STATIC
|
||||
void GenPrep(int* idx)
|
||||
@@ -1103,6 +1090,7 @@ void GenPrep(int* idx)
|
||||
stack[oldIdxRight + 1][0] = tokNumInt; // reduce the number of cases since tokNumInt and tokNumUint are handled the same way
|
||||
// fallthrough
|
||||
case tokNumInt:
|
||||
case tokNum0:
|
||||
case tokIdent:
|
||||
case tokLocalOfs:
|
||||
break;
|
||||
@@ -1142,6 +1130,16 @@ void GenPrep(int* idx)
|
||||
break;
|
||||
|
||||
case '=':
|
||||
if (oldIdxRight + 1 == sp - 1 &&
|
||||
(stack[oldIdxRight][0] == tokNumInt || stack[oldIdxRight][0] == tokNumUint) &&
|
||||
truncUint(stack[oldIdxRight][1]) == 0)
|
||||
{
|
||||
// Special case for assigning 0 while throwing away the expression result value
|
||||
// TBD??? ,
|
||||
stack[oldIdxRight][0] = tokNum0; // this zero constant will not be loaded into a register
|
||||
stack[oldIdxRight + 1][0] = tokAssign0; // change '=' to tokAssign0
|
||||
}
|
||||
// fallthrough
|
||||
case tokAssignAdd:
|
||||
case tokAssignSub:
|
||||
case tokAssignMul:
|
||||
@@ -1536,7 +1534,7 @@ void GenExpr0(void)
|
||||
int paramOfs = 0;
|
||||
int t = sp - 1;
|
||||
|
||||
if (stack[t][0] == tokIf || stack[t][0] == tokIfNot)
|
||||
if (stack[t][0] == tokIf || stack[t][0] == tokIfNot || stack[t][0] == tokReturn)
|
||||
t--;
|
||||
GenPrep(&t);
|
||||
|
||||
@@ -1575,7 +1573,7 @@ void GenExpr0(void)
|
||||
case tokGoto: printf2(" # sh-circ-goto "); break;
|
||||
case tokLogAnd: printf2(" # short-circuit && target\n"); break;
|
||||
case tokLogOr: printf2(" # short-circuit || target\n"); break;
|
||||
case tokIf: case tokIfNot: break;
|
||||
case tokIf: case tokIfNot: case tokReturn: break;
|
||||
default: printf2(" # %s\n", GetTokenName(tok)); break;
|
||||
}
|
||||
#endif
|
||||
@@ -1675,6 +1673,7 @@ void GenExpr0(void)
|
||||
break;
|
||||
|
||||
case ')':
|
||||
GenLeaf = 0;
|
||||
if (maxCallDepth != 1)
|
||||
{
|
||||
if (v >= 4)
|
||||
@@ -2021,6 +2020,21 @@ void GenExpr0(void)
|
||||
GenExtendRegIfNeeded(GenWreg, v);
|
||||
break;
|
||||
|
||||
case tokAssign0: // assignment of 0, while throwing away the expression result value
|
||||
if (stack[i - 1][0] == tokRevLocalOfs)
|
||||
{
|
||||
GenWriteLocal(MipsOpRegZero, v, stack[i - 1][1]);
|
||||
}
|
||||
else if (stack[i - 1][0] == tokRevIdent)
|
||||
{
|
||||
GenWriteIdent(MipsOpRegZero, v, stack[i - 1][1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
GenWriteIndirect(GenWreg, MipsOpRegZero, v);
|
||||
}
|
||||
break;
|
||||
|
||||
case '<': GenCmp(&i, 0x00); break;
|
||||
case tokLEQ: GenCmp(&i, 0x01); break;
|
||||
case '>': GenCmp(&i, 0x02); break;
|
||||
@@ -2116,6 +2130,8 @@ void GenExpr0(void)
|
||||
case tokRevIdent:
|
||||
case tokRevLocalOfs:
|
||||
case tokComma:
|
||||
case tokReturn:
|
||||
case tokNum0:
|
||||
break;
|
||||
|
||||
case tokIf:
|
||||
|
||||
@@ -1783,7 +1783,7 @@ void GenExpr1(void)
|
||||
int s = sp - 1;
|
||||
int i;
|
||||
|
||||
if (stack[s][0] == tokIf || stack[s][0] == tokIfNot)
|
||||
if (stack[s][0] == tokIf || stack[s][0] == tokIfNot || stack[s][0] == tokReturn)
|
||||
s--;
|
||||
GenFuse(&s);
|
||||
|
||||
@@ -1860,6 +1860,8 @@ void GenExpr1(void)
|
||||
case tokIfNot:
|
||||
printf2("IF!");
|
||||
break;
|
||||
case tokReturn:
|
||||
break;
|
||||
default:
|
||||
printf2("%s", GetTokenName(tok));
|
||||
switch (tok)
|
||||
@@ -2667,6 +2669,7 @@ void GenExpr1(void)
|
||||
case '(':
|
||||
case tokIf:
|
||||
case tokIfNot:
|
||||
case tokReturn:
|
||||
break;
|
||||
|
||||
case tokVoid:
|
||||
@@ -2708,7 +2711,7 @@ void GenExpr0(void)
|
||||
case tokGoto: printf2("; sh-circ-goto "); break;
|
||||
case tokLogAnd: printf2("; short-circuit && target\n"); break;
|
||||
case tokLogOr: printf2("; short-circuit || target\n"); break;
|
||||
case tokIf: case tokIfNot: break;
|
||||
case tokIf: case tokIfNot: case tokReturn: break;
|
||||
default: printf2("; %s\n", GetTokenName(tok)); break;
|
||||
}
|
||||
#endif
|
||||
@@ -3104,6 +3107,7 @@ void GenExpr0(void)
|
||||
case tokComma:
|
||||
case ',':
|
||||
case '(':
|
||||
case tokReturn:
|
||||
break;
|
||||
|
||||
case tokIf:
|
||||
|
||||
@@ -188,7 +188,7 @@ int fsetpos(FILE*, fpos_t*);
|
||||
#endif
|
||||
|
||||
#ifndef MAX_IDENT_TABLE_LEN
|
||||
#define MAX_IDENT_TABLE_LEN (4096+656+32) // must be greater than MAX_IDENT_LEN
|
||||
#define MAX_IDENT_TABLE_LEN (4096+656+64) // must be greater than MAX_IDENT_LEN
|
||||
#endif
|
||||
|
||||
#ifndef SYNTAX_STACK_MAX
|
||||
@@ -338,7 +338,7 @@ int fsetpos(FILE*, fpos_t*);
|
||||
#define SymFuncPtr 3
|
||||
|
||||
#ifndef STACK_SIZE
|
||||
#define STACK_SIZE 128
|
||||
#define STACK_SIZE 129
|
||||
#endif
|
||||
|
||||
#define SymFxn 1
|
||||
@@ -651,6 +651,7 @@ char* CurFxnName = NULL;
|
||||
#ifndef NO_FUNC_
|
||||
int CurFxnNameLabel = 0;
|
||||
#endif
|
||||
int Main; // if inside main()
|
||||
|
||||
int ParseLevel = 0; // Parse level/scope (file:0, fxn:1+)
|
||||
int ParamLevel = 0; // 1+ if parsing params, 0 otherwise
|
||||
@@ -6927,7 +6928,6 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
|
||||
int undoSymbolsPtr = SyntaxStackCnt;
|
||||
int undoIdents = IdentTableLen;
|
||||
int i;
|
||||
int Main;
|
||||
|
||||
#ifndef NO_ANNOTATIONS
|
||||
DumpDecl(lastSyntaxPtr, 0);
|
||||
@@ -6993,6 +6993,7 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
|
||||
{
|
||||
sp = 0;
|
||||
push(tokNumInt);
|
||||
push(tokReturn); // value produced by generated code is used
|
||||
GenExpr();
|
||||
}
|
||||
|
||||
@@ -7452,15 +7453,20 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
}
|
||||
}
|
||||
}
|
||||
push(tokReturn); // value produced by generated code is used
|
||||
GenExpr();
|
||||
}
|
||||
GenJumpUncond(CurFxnEpilogLabel);
|
||||
tok = GetToken();
|
||||
// If this return is the last statement in the function, the epilogue immediately
|
||||
// follows and there's no need to jump to it.
|
||||
if (!(tok == '}' && ParseLevel == 1 && !Main))
|
||||
GenJumpUncond(CurFxnEpilogLabel);
|
||||
}
|
||||
else if (tok == tokWhile)
|
||||
{
|
||||
int labelBefore = LabelCnt++;
|
||||
int labelAfter = LabelCnt++;
|
||||
int forever = 0;
|
||||
#ifndef NO_ANNOTATIONS
|
||||
GenStartCommentLine(); printf2("while\n");
|
||||
#endif
|
||||
@@ -7485,6 +7491,14 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
|
||||
GenNumLabel(labelBefore);
|
||||
|
||||
if (constExpr)
|
||||
{
|
||||
// Special cases for while(0) and while(1)
|
||||
if (!(forever = truncInt(exprVal)))
|
||||
GenJumpUncond(labelAfter);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (stack[sp - 1][0])
|
||||
{
|
||||
case '<':
|
||||
@@ -7501,16 +7515,20 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
GenExpr();
|
||||
break;
|
||||
default:
|
||||
push(tokReturn); // value produced by generated code is used
|
||||
GenExpr();
|
||||
GenJumpIfZero(labelAfter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tok = GetToken();
|
||||
brkCntTarget[0] = labelAfter; // break target
|
||||
brkCntTarget[1] = labelBefore; // continue target
|
||||
tok = ParseStatement(tok, brkCntTarget, casesIdx);
|
||||
|
||||
// Special case for while(0)
|
||||
if (!(constExpr && !forever))
|
||||
GenJumpUncond(labelBefore);
|
||||
GenNumLabel(labelAfter);
|
||||
}
|
||||
@@ -7560,6 +7578,14 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
|
||||
GenNumLabel(labelWhile);
|
||||
|
||||
if (constExpr)
|
||||
{
|
||||
// Special cases for while(0) and while(1)
|
||||
if (truncInt(exprVal))
|
||||
GenJumpUncond(labelBefore);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (stack[sp - 1][0])
|
||||
{
|
||||
case '<':
|
||||
@@ -7576,10 +7602,12 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
GenExpr();
|
||||
break;
|
||||
default:
|
||||
push(tokReturn); // value produced by generated code is used
|
||||
GenExpr();
|
||||
GenJumpIfNotZero(labelBefore);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GenNumLabel(labelAfter);
|
||||
|
||||
@@ -7611,6 +7639,14 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
//error("ParseStatement(): unexpected 'void' expression in 'if ( expression )'\n");
|
||||
scalarTypeCheck(synPtr);
|
||||
|
||||
if (constExpr)
|
||||
{
|
||||
// Special cases for if(0) and if(1)
|
||||
if (!truncInt(exprVal))
|
||||
GenJumpUncond(labelAfterIf);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (stack[sp - 1][0])
|
||||
{
|
||||
case '<':
|
||||
@@ -7627,10 +7663,12 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
GenExpr();
|
||||
break;
|
||||
default:
|
||||
push(tokReturn); // value produced by generated code is used
|
||||
GenExpr();
|
||||
GenJumpIfZero(labelAfterIf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tok = GetToken();
|
||||
tok = ParseStatement(tok, BrkCntTarget, casesIdx);
|
||||
@@ -7658,6 +7696,9 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
int labelExpr3 = LabelCnt++;
|
||||
int labelBody = LabelCnt++;
|
||||
int labelAfter = LabelCnt++;
|
||||
int cond = -1;
|
||||
static int expr3Stack[STACK_SIZE / 2][2];
|
||||
static int expr3Sp;
|
||||
#ifndef NO_FOR_DECL
|
||||
int decl = 0;
|
||||
int undoSymbolsPtr = 0, undoLocalOfs = 0, undoIdents = 0;
|
||||
@@ -7709,6 +7750,13 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
//error("ParseStatement(): unexpected 'void' expression in 'for ( ; expression ; )'\n");
|
||||
scalarTypeCheck(synPtr);
|
||||
|
||||
if (constExpr)
|
||||
{
|
||||
// Special cases for for(...; 0; ...) and for(...; 1; ...)
|
||||
cond = truncInt(exprVal) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (stack[sp - 1][0])
|
||||
{
|
||||
case '<':
|
||||
@@ -7725,30 +7773,74 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
GenExpr();
|
||||
break;
|
||||
default:
|
||||
push(tokReturn); // value produced by generated code is used
|
||||
GenExpr();
|
||||
GenJumpIfZero(labelAfter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
GenJumpUncond(labelBody);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Special case for for(...; ; ...)
|
||||
cond = 1;
|
||||
}
|
||||
if (!cond)
|
||||
// Special case for for(...; 0; ...)
|
||||
GenJumpUncond(labelAfter);
|
||||
|
||||
GenNumLabel(labelExpr3);
|
||||
tok = GetToken();
|
||||
if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
|
||||
//error("ParseStatement(): ')' expected after 'for ( expression ; expression ; expression'\n");
|
||||
errorUnexpectedToken(tok);
|
||||
if (gotUnary)
|
||||
{
|
||||
GenExpr();
|
||||
}
|
||||
GenJumpUncond(labelBefore);
|
||||
|
||||
GenNumLabel(labelBody);
|
||||
// Try to reorder expr3 with body to reduce the number of jumps, favor small expr3's
|
||||
if (gotUnary && sp <= 16 && (unsigned)sp <= sizeof expr3Stack / sizeof expr3Stack[0] - expr3Sp)
|
||||
{
|
||||
int cnt = sp;
|
||||
// Stash the stack containing expr3
|
||||
memcpy(expr3Stack + expr3Sp, stack, cnt * sizeof stack[0]);
|
||||
expr3Sp += cnt;
|
||||
|
||||
// Body
|
||||
tok = GetToken();
|
||||
brkCntTarget[0] = labelAfter; // break target
|
||||
brkCntTarget[1] = labelExpr3; // continue target
|
||||
tok = ParseStatement(tok, brkCntTarget, casesIdx);
|
||||
GenJumpUncond(labelExpr3);
|
||||
|
||||
// Unstash expr3 and generate code for it
|
||||
expr3Sp -= cnt;
|
||||
memcpy(stack, expr3Stack + expr3Sp, cnt * sizeof stack[0]);
|
||||
sp = cnt;
|
||||
GenNumLabel(labelExpr3);
|
||||
GenExpr();
|
||||
|
||||
// Special case for for(...; 0; ...)
|
||||
if (cond)
|
||||
GenJumpUncond(labelBefore);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gotUnary)
|
||||
{
|
||||
GenJumpUncond(labelBody);
|
||||
// expr3
|
||||
GenNumLabel(labelExpr3);
|
||||
GenExpr();
|
||||
GenJumpUncond(labelBefore);
|
||||
GenNumLabel(labelBody);
|
||||
}
|
||||
|
||||
// Body
|
||||
tok = GetToken();
|
||||
brkCntTarget[0] = labelAfter; // break target
|
||||
brkCntTarget[1] = gotUnary ? labelExpr3 : (cond ? labelBefore : labelAfter); // continue target
|
||||
tok = ParseStatement(tok, brkCntTarget, casesIdx);
|
||||
|
||||
// Special case for for(...; 0; ...)
|
||||
if (brkCntTarget[1] != labelAfter)
|
||||
GenJumpUncond(brkCntTarget[1]);
|
||||
}
|
||||
|
||||
GenNumLabel(labelAfter);
|
||||
|
||||
@@ -7818,6 +7910,7 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
//error("ParseStatement(): unexpected 'void' expression in 'switch ( expression )'\n");
|
||||
scalarTypeCheck(synPtr);
|
||||
|
||||
push(tokReturn); // value produced by generated code is used
|
||||
GenExpr();
|
||||
|
||||
tok = GetToken();
|
||||
|
||||
Reference in New Issue
Block a user