fixes, improvements, __interrupt

Fixes/workarounds:
- octal escape sequence is to be terminated no later than after three
octal digits:
"\1011" is now parsed equivalently to "A1"
- workaround truncation of immediate operands to 16 bits in MIPS
instructions addi[u], subi[u], slti[u], andi, ori, xori in RetroBSD's as
(disabled since as is being fixed).

Improvements:
- warn on string literal truncation when initializing array of char
- generate trap/break-less form of MIPS div[u]

New:
- experimental support for __interrupt functions (x86/huge only)
This commit is contained in:
Alexey Frunze
2014-05-03 18:55:18 -07:00
parent e0ba612250
commit a2bc88bdb6
3 changed files with 225 additions and 21 deletions

View File

@@ -37,6 +37,11 @@ either expressed or implied, of the FreeBSD Project.
/* */
/*****************************************************************************/
// Works around bugs in RetroBSD's as instruction reordering
#define REORDER_WORKAROUND
// Works around bugs in RetroBSD's as immediate operand truncation to 16 bits
//#define INSTR_IMM_WORKAROUND
int UseGp = 0;
void GenInit(void)
@@ -47,7 +52,7 @@ void GenInit(void)
CodeHeader = "\t.text";
DataHeader = "\t.data";
UseLeadingUnderscores = 0;
#ifndef NO_REORDER_WORKAROUND
#ifdef REORDER_WORKAROUND
FileHeader = "\t.set\tnoreorder";
#else
FileHeader = "\t.set\treorder";
@@ -65,8 +70,10 @@ int GenInitParams(int argc, char** argv, int* idx)
}
else if (!strcmp(argv[*idx], "-v"))
{
// RetroBSD's cc may supply this parameter. Just need to consume it.
return 1;
}
return 0;
}
@@ -294,7 +301,7 @@ void GenPrintInstr(int instr, int val)
#define MipsOpLabelGpOption 0x83
#define MipsOpIndLocal MipsOpIndRegFp
#ifndef NO_REORDER_WORKAROUND
#ifdef REORDER_WORKAROUND
void GenNop(void)
{
puts2("\tnop");
@@ -363,7 +370,7 @@ void GenPrintInstr1Operand(int instr, int instrval, int operand, int operandval)
GenPrintOperand(operand, operandval);
GenPrintNewLine();
#ifndef NO_REORDER_WORKAROUND
#ifdef REORDER_WORKAROUND
if (instr == MipsInstrJ || instr == MipsInstrJAL)
GenNop();
#endif
@@ -387,10 +394,61 @@ void GenPrintInstr3Operands(int instr, int instrval,
int operand2, int operand2val,
int operand3, int operand3val)
{
#ifdef INSTR_IMM_WORKAROUND
int useAt = 0;
#endif
if (operand3 == MipsOpConst && operand3val == 0 &&
(instr == MipsInstrAddU || instr == MipsInstrSubU))
return;
#ifdef INSTR_IMM_WORKAROUND
if (operand3 == MipsOpConst)
{
unsigned imm = truncUint(operand3val);
switch (instr)
{
// signed imm16:
// addi[u], subi[u], slti[u]
case MipsInstrAddU:
case MipsInstrSLT:
case MipsInstrSLTU:
if (imm > 0x7FFF && imm < 0xFFFF8000) // if not (-0x8000 <= imm <= 0x7FFF)
useAt = 1;
break;
case MipsInstrSubU:
// subi[u] will be transformed into addi[u] and the immediate will be negated,
// hence the immediate range is shifted by 1
if (imm > 0x8000 && imm < 0xFFFF8001) // if not (-0x7FFF <= imm <= 0x8000)
useAt = 1;
break;
// unsigned imm16:
// andi, ori, xori
case MipsInstrAnd:
case MipsInstrOr:
case MipsInstrXor:
if (imm > 0xFFFF)
useAt = 1;
break;
// also: various trap instructions
default:
break;
}
}
if (useAt)
{
puts2("\t.set\tnoat");
GenPrintInstr2Operands(MipsInstrLI, 0,
MipsOpRegAt, 0,
MipsOpConst, operand3val);
operand3 = MipsOpRegAt;
}
#endif
GenPrintInstr(instr, instrval);
GenPrintOperand(operand1, operand1val);
GenPrintOperandSeparator();
@@ -399,7 +457,14 @@ void GenPrintInstr3Operands(int instr, int instrval,
GenPrintOperand(operand3, operand3val);
GenPrintNewLine();
#ifndef NO_REORDER_WORKAROUND
#ifdef INSTR_IMM_WORKAROUND
if (useAt)
{
puts2("\t.set\tat");
}
#endif
#ifdef REORDER_WORKAROUND
if (instr == MipsInstrBEQ || instr == MipsInstrBNE)
GenNop();
#endif
@@ -1133,11 +1198,13 @@ void GenExpr0(void)
{
int reg = GenPopReg(MipsOpRegT0);
if (tok == '/' || tok == '%')
GenPrintInstr2Operands(MipsInstrDiv, 0,
GenPrintInstr3Operands(MipsInstrDiv, 0,
MipsOpRegZero, 0,
reg, 0,
MipsOpRegV0, 0);
else
GenPrintInstr2Operands(MipsInstrDivU, 0,
GenPrintInstr3Operands(MipsInstrDivU, 0,
MipsOpRegZero, 0,
reg, 0,
MipsOpRegV0, 0);
if (tok == '%' || tok == tokUMod)
@@ -1240,11 +1307,13 @@ void GenExpr0(void)
GenReadIndirect(MipsOpRegT1, reg, v);
if (tok == tokAssignDiv || tok == tokAssignMod)
GenPrintInstr2Operands(MipsInstrDiv, 0,
GenPrintInstr3Operands(MipsInstrDiv, 0,
MipsOpRegZero, 0,
MipsOpRegT1, 0,
MipsOpRegV0, 0);
else
GenPrintInstr2Operands(MipsInstrDivU, 0,
GenPrintInstr3Operands(MipsInstrDivU, 0,
MipsOpRegZero, 0,
MipsOpRegT1, 0,
MipsOpRegV0, 0);
if (tok == tokAssignMod || tok == tokAssignUMod)
@@ -1604,11 +1673,11 @@ void GenFin(void)
"\taddiu\t$3, $3, 1");
printf2("\tbne\t$4, $0, "); GenPrintNumLabel(lbl);
puts2("");
#ifndef NO_REORDER_WORKAROUND
#ifdef REORDER_WORKAROUND
GenNop();
#endif
puts2("\tj\t$31");
#ifndef NO_REORDER_WORKAROUND
#ifdef REORDER_WORKAROUND
GenNop();
#endif

View File

@@ -803,6 +803,79 @@ void GenFxnEpilog(void)
GenPrintInstrNoOperand(X86InstrRet);
}
#ifdef CAN_COMPILE_32BIT
/*
struct INTREGS
{
unsigned short gs, fs, es, ds;
unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned short ss, ip, cs, flags;
};
void __interrupt isr(struct INTREGS** ppRegs)
{
// **ppRegs (input/output values of registers) can be modified to
// handle software interrupts requested via the int instruction and
// communicate data via registers
// *ppRegs (directly related to the stack pointer) can be modified to
// return to a different location & implement preemptive scheduling,
// e.g. save *ppRegs of the interrupted task somewhere, update *ppRegs
// with a value from another interrupted task.
}
*/
void GenIsrProlog(void)
{
// The CPU has already done these:
// push flags
// push cs
// push ip
puts2("\tpush\tss");
puts2("\tpushad");
puts2("\tpush\tds\n"
"\tpush\tes\n"
"\tpush\tfs\n"
"\tpush\tgs");
// The context has been saved
puts2("\txor\teax, eax\n\tmov\tax, ss"); // mov r32, sreg leaves top 16 bits undefined on pre-Pentium CPUs
puts2("\txor\tebx, ebx\n\tmov\tbx, sp"); // top 16 bits of esp can contain garbage as well
puts2("\tshl\teax, 4\n\tadd\teax, ebx");
puts2("\tpush\teax"); // pointer to the structure with register values
puts2("\tsub\teax, 4\n\tpush\teax"); // pointer to the pointer to the structure with register values
puts2("\tpush\teax"); // fake return address allowing to use the existing bp-relative addressing of locals and params
puts2("\tpush\tebp\n"
"\tmov\tebp, esp");
}
void GenIsrEpilog(void)
{
puts2("\tdb\t0x66\n\tleave");
puts2("\tpop\teax"); // fake return address
puts2("\tpop\teax"); // pointer to the pointer to the structure with register values
puts2("\tpop\tebx"); // pointer to the structure with register values
puts2("\tror\tebx, 4\n\tmov\tds, bx\n\tshr\tebx, 28"); // ds:bx = pointer to the structure with register values
puts2("\tmov\tax, [bx+4*10]\n\tmov\tbx, [bx+4*5]\n\tsub\tbx, 4*10"); // ax:bx = proper pointer (with original segment) to the struct...
puts2("\tmov\tss, ax\n\tmov\tsp, bx"); // restore ss:sp that we had after push gs
// The context is now going to be restored
puts2("\tpop\tgs\n"
"\tpop\tfs\n"
"\tpop\tes\n"
"\tpop\tds");
puts2("\tpopad");
puts2("\tpop\tss");
puts2("\tiret");
}
#endif
void GenReadIdent(int opSz, int label)
{
GenPrintInstr2Operands(X86InstrMov, 0,

View File

@@ -302,6 +302,7 @@ int vfprintf(FILE*, char*, void*);
#define tokTag 0x91
#define tokMemberIdent 0x92
#define tokEnumPtr 0x93
#define tokIntr 0x94
#define FormatFlat 0
#define FormatSegmented 1
@@ -368,6 +369,8 @@ void GenJumpIfNotEqual(int val, int Label);
void GenFxnProlog(void);
void GenFxnEpilog(void);
void GenIsrProlog(void);
void GenIsrEpilog(void);
void GenLocalAlloc(int Size);
@@ -614,8 +617,10 @@ unsigned truncUint(unsigned n)
// Truncate n to SizeOfWord * 8 bits
if (SizeOfWord == 2)
n &= ~(~0u << 8 << 8);
#ifdef CAN_COMPILE_32BIT
else if (SizeOfWord == 4)
n &= ~(~0u << 8 << 12 << 12);
#endif
return n;
}
@@ -628,11 +633,13 @@ int truncInt(int n)
un &= ~(~0u << 8 << 8);
un |= (((un >> 8 >> 7) & 1) * ~0u) << 8 << 8;
}
#ifdef CAN_COMPILE_32BIT
else if (SizeOfWord == 4)
{
un &= ~(~0u << 8 << 12 << 12);
un |= (((un >> 8 >> 12 >> 11) & 1) * ~0u) << 8 << 12 << 12;
}
#endif
return uint2int(un);
}
@@ -902,7 +909,8 @@ char* rws[] =
"static", "switch", "unsigned", "void", "while", "asm", "auto",
"const", "double", "enum", "float", "goto", "inline", "long",
"register", "restrict", "short", "struct", "typedef", "union",
"volatile", "_Bool", "_Complex", "_Imaginary"
"volatile", "_Bool", "_Complex", "_Imaginary",
"__interrupt"
};
unsigned char rwtk[] =
@@ -912,7 +920,8 @@ unsigned char rwtk[] =
tokStatic, tokSwitch, tokUnsigned, tokVoid, tokWhile, tok_Asm, tokAuto,
tokConst, tokDouble, tokEnum, tokFloat, tokGoto, tokInline, tokLong,
tokRegister, tokRestrict, tokShort, tokStruct, tokTypedef, tokUnion,
tokVolatile, tok_Bool, tok_Complex, tok_Imagin
tokVolatile, tok_Bool, tok_Complex, tok_Imagin,
tokIntr
};
int GetTokenByWord(char* word)
@@ -1368,11 +1377,10 @@ void GetString(char terminator, int SkipNewLines)
c = (c * 8) & 0xFF;
c += *p - '0';
ShiftCharN(1);
cnt++;
// octal escape sequence is terminated after three octal digits
if (++cnt == 3)
break;
}
if (!cnt)
//error("Unsupported or invalid character/string constant\n");
errorChrStr();
c -= (c >= 0x80 && CHAR_MIN) * 0x100;
ch = c;
}
@@ -1530,11 +1538,13 @@ int GetNumber(void)
}
// Ensure the constant fits into 16(32) bits
if ((SizeOfWord == 2 && n >> 8 >> 8) || // equiv. to SizeOfWord == 2 && n > 0xFFFF
if (
(SizeOfWord == 2 && n >> 8 >> 8) // equiv. to SizeOfWord == 2 && n > 0xFFFF
#ifdef CAN_COMPILE_32BIT
(SizeOfWord == 2 && lSuffix) || // long (which must have at least 32 bits) isn't supported in 16-bit models
|| (SizeOfWord == 2 && lSuffix) // long (which must have at least 32 bits) isn't supported in 16-bit models
|| (SizeOfWord == 4 && n >> 8 >> 12 >> 12) // equiv. to SizeOfWord == 4 && n > 0xFFFFFFFF
#endif
(SizeOfWord == 4 && n >> 8 >> 12 >> 12)) // equiv. to SizeOfWord == 4 && n > 0xFFFFFFFF
)
error("Constant too big for %d-bit type\n", SizeOfWord * 8);
TokenValueInt = uint2int(n);
@@ -1542,8 +1552,13 @@ int GetNumber(void)
// Unsuffixed (with 'u') integer constants (octal, decimal, hex)
// fitting into 15(31) out of 16(32) bits are signed ints
if (!uSuffix &&
((SizeOfWord == 2 && !(n >> 8 >> 7)) || // equiv. to SizeOfWord == 2 && n <= 0x7FFF
(SizeOfWord == 4 && !(n >> 8 >> 12 >> 11)))) // equiv. to SizeOfWord == 4 && n <= 0x7FFFFFFF
(
(SizeOfWord == 2 && !(n >> 15)) // equiv. to SizeOfWord == 2 && n <= 0x7FFF
#ifdef CAN_COMPILE_32BIT
|| (SizeOfWord == 4 && !(n >> 8 >> 12 >> 11)) // equiv. to SizeOfWord == 4 && n <= 0x7FFFFFFF
#endif
)
)
return tokNumInt;
// Unlike octal and hex constants, decimal constants are always
@@ -5600,6 +5615,11 @@ int ParseDerived(int tok)
{
int stars = 0;
int params = 0;
#ifndef MIPS
#ifdef CAN_COMPILE_32BIT
int isInterrupt = 0;
#endif
#endif
while (tok == '*')
{
@@ -5607,6 +5627,19 @@ int ParseDerived(int tok)
tok = GetToken();
}
#ifndef MIPS
#ifdef CAN_COMPILE_32BIT
if (tok == tokIntr)
{
// __interrupt is supported in the huge mode(l) only
if (OutputFormat != FormatSegHuge)
errorDecl();
isInterrupt = 1;
tok = GetToken();
}
#endif
#endif
if (tok == '(')
{
tok = GetToken();
@@ -5642,7 +5675,15 @@ int ParseDerived(int tok)
tok = GetToken();
else
PushSyntax2(tokIdent, AddIdent("<something>"));
#ifndef MIPS
#ifdef CAN_COMPILE_32BIT
if (isInterrupt)
PushSyntax2('(', 1);
else // fallthrough
#endif
#endif
PushSyntax('(');
ParseLevel++;
ParamLevel++;
ParseFxnParams(tok);
@@ -5897,6 +5938,9 @@ int InitArray(int synPtr, int tok)
int undoIdents = IdentTableLen;
int slen = StringTableLen;
if (elementsRequired * ((unsigned)TokenStringLen > elementsRequired))
warning("String literal truncated\n");
tok = ParseExpr(tok, &gotUnary, &synPtr2, &constExpr, &exprVal, ',', 0);
if (!gotUnary ||
@@ -6576,7 +6620,16 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
GenLabel(IdentTable + SyntaxStack[lastSyntaxPtr][1], Static);
CurFxnEpilogLabel = LabelCnt++;
#ifndef MIPS
#ifdef CAN_COMPILE_32BIT
if (SyntaxStack[lastSyntaxPtr + 1][1] & 1)
GenIsrProlog();
else // fallthrough
#endif
#endif
GenFxnProlog();
GenJumpUncond(locAllocLabel + 1);
GenNumLabel(locAllocLabel);
@@ -6623,7 +6676,16 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
}
GenNumLabel(CurFxnEpilogLabel);
#ifndef MIPS
#ifdef CAN_COMPILE_32BIT
if (SyntaxStack[lastSyntaxPtr + 1][1] & 1)
GenIsrEpilog();
else // fallthrough
#endif
#endif
GenFxnEpilog();
GenNumLabel(locAllocLabel + 1);
if (CurFxnMinLocalOfs)
GenLocalAlloc(-CurFxnMinLocalOfs);