diff --git a/src/cmd/smlrc/cgmips.c b/src/cmd/smlrc/cgmips.c index edc7e03..300c8f3 100644 --- a/src/cmd/smlrc/cgmips.c +++ b/src/cmd/smlrc/cgmips.c @@ -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 diff --git a/src/cmd/smlrc/cgx86.c b/src/cmd/smlrc/cgx86.c index 419587c..9fcf438 100644 --- a/src/cmd/smlrc/cgx86.c +++ b/src/cmd/smlrc/cgx86.c @@ -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, diff --git a/src/cmd/smlrc/smlrc.c b/src/cmd/smlrc/smlrc.c index d65021a..987bcd2 100644 --- a/src/cmd/smlrc/smlrc.c +++ b/src/cmd/smlrc/smlrc.c @@ -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("")); +#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);