diff --git a/oscar64/Errors.h b/oscar64/Errors.h index 7a4a69a..a2f9fe1 100644 --- a/oscar64/Errors.h +++ b/oscar64/Errors.h @@ -50,6 +50,7 @@ enum ErrorID EERR_ASM_INVALID_MODE, EERR_PRAGMA_PARAMETER, ERRR_PREPROCESSOR, + ERRR_INVALID_CASE, EERR_INVALID_PREPROCESSOR, }; diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index dda2e17..2004926 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -546,6 +546,118 @@ void InterCodeGenerator::TranslateAssembler(InterCodeModule* mod, Expression* ex assert(offset == osize); } +void InterCodeGenerator::BuildSwitchTree(InterCodeProcedure* proc, InterCodeBasicBlock* block, ExValue v, const SwitchNodeArray& nodes, int left, int right, InterCodeBasicBlock* dblock) +{ + if (right - left < 5) + { + for (int i = left; i < right; i++) + { + InterCodeBasicBlock* cblock = new InterCodeBasicBlock(); + proc->Append(cblock); + + InterInstruction* vins = new InterInstruction(); + vins->mCode = IC_CONSTANT; + vins->mConst.mType = IT_INT16; + vins->mConst.mIntConst = nodes[i].mValue; + vins->mDst.mType = IT_INT16; + vins->mDst.mTemp = proc->AddTemporary(vins->mDst.mType); + block->Append(vins); + + InterInstruction* cins = new InterInstruction(); + cins->mCode = IC_RELATIONAL_OPERATOR; + cins->mOperator = IA_CMPEQ; + cins->mSrc[0].mType = vins->mDst.mType; + cins->mSrc[0].mTemp = vins->mDst.mTemp; + cins->mSrc[1].mType = vins->mDst.mType; + cins->mSrc[1].mTemp = v.mTemp; + cins->mDst.mType = IT_BOOL; + cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); + + block->Append(cins); + + InterInstruction* bins = new InterInstruction(); + bins->mCode = IC_BRANCH; + bins->mSrc[0].mType = IT_BOOL; + bins->mSrc[0].mTemp = cins->mDst.mTemp; + block->Append(bins); + + block->Close(nodes[i].mBlock, cblock); + + block = cblock; + } + + InterInstruction* jins = new InterInstruction(); + jins->mCode = IC_JUMP; + + block->Append(jins); + block->Close(dblock, nullptr); + } + else + { + int center = (left + right + 1) >> 1; + + InterCodeBasicBlock* cblock = new InterCodeBasicBlock(); + proc->Append(cblock); + + InterCodeBasicBlock* rblock = new InterCodeBasicBlock(); + proc->Append(rblock); + + InterCodeBasicBlock* lblock = new InterCodeBasicBlock(); + proc->Append(lblock); + + InterInstruction* vins = new InterInstruction(); + vins->mCode = IC_CONSTANT; + vins->mConst.mType = IT_INT16; + vins->mConst.mIntConst = nodes[center].mValue; + vins->mDst.mType = IT_INT16; + vins->mDst.mTemp = proc->AddTemporary(vins->mDst.mType); + block->Append(vins); + + InterInstruction* cins = new InterInstruction(); + cins->mCode = IC_RELATIONAL_OPERATOR; + cins->mOperator = IA_CMPEQ; + cins->mSrc[0].mType = vins->mDst.mType; + cins->mSrc[0].mTemp = vins->mDst.mTemp; + cins->mSrc[1].mType = vins->mDst.mType; + cins->mSrc[1].mTemp = v.mTemp; + cins->mDst.mType = IT_BOOL; + cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); + + block->Append(cins); + + InterInstruction* bins = new InterInstruction(); + bins->mCode = IC_BRANCH; + bins->mSrc[0].mType = IT_BOOL; + bins->mSrc[0].mTemp = cins->mDst.mTemp; + block->Append(bins); + + block->Close(nodes[center].mBlock, cblock); + + InterInstruction* rins = new InterInstruction(); + rins->mCode = IC_RELATIONAL_OPERATOR; + rins->mOperator = IA_CMPLS; + rins->mSrc[0].mType = vins->mDst.mType; + rins->mSrc[0].mTemp = vins->mDst.mTemp; + rins->mSrc[1].mType = vins->mDst.mType; + rins->mSrc[1].mTemp = v.mTemp; + rins->mDst.mType = IT_BOOL; + rins->mDst.mTemp = proc->AddTemporary(rins->mDst.mType); + + cblock->Append(rins); + + InterInstruction* rbins = new InterInstruction(); + rbins->mCode = IC_BRANCH; + rbins->mSrc[0].mType = IT_BOOL; + rbins->mSrc[0].mTemp = rins->mDst.mTemp; + cblock->Append(rbins); + + cblock->Close(lblock, rblock); + + BuildSwitchTree(proc, lblock, v, nodes, left, center, dblock); + BuildSwitchTree(proc, rblock, v, nodes, center + 1, right, dblock); + } +} + InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, Expression* exp, InterCodeBasicBlock* breakBlock, InterCodeBasicBlock* continueBlock, InlineMapper* inlineMapper) { Declaration* dec; @@ -2529,41 +2641,33 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* InterCodeBasicBlock* eblock = new InterCodeBasicBlock(); proc->Append(eblock); + SwitchNodeArray switchNodes({ 0 }); + Expression* sexp = exp->mRight; while (sexp) { Expression* cexp = sexp->mLeft; if (cexp->mType == EX_CASE) { - InterCodeBasicBlock* cblock = new InterCodeBasicBlock(); - proc->Append(cblock); - InterCodeBasicBlock* nblock = new InterCodeBasicBlock(); proc->Append(nblock); - vr = TranslateExpression(procType, proc, sblock, cexp->mLeft, breakBlock, continueBlock, inlineMapper); - vr = Dereference(proc, sblock, vr); - vr = CoerceType(proc, sblock, vr, TheSignedIntTypeDeclaration); + SwitchNode snode; + snode.mBlock = nblock; + snode.mValue = 0; - InterInstruction * cins = new InterInstruction(); - cins->mCode = IC_RELATIONAL_OPERATOR; - cins->mOperator = IA_CMPEQ; - cins->mSrc[0].mType = InterTypeOf(vr.mType);; - cins->mSrc[0].mTemp = vr.mTemp; - cins->mSrc[1].mType = InterTypeOf(vl.mType);; - cins->mSrc[1].mTemp = vl.mTemp; - cins->mDst.mType = IT_BOOL; - cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); + if (cexp->mLeft->mType == EX_CONSTANT && cexp->mLeft->mDecValue->mType == DT_CONST_INTEGER) + snode.mValue = cexp->mLeft->mDecValue->mInteger; + else + mErrors->Error(cexp->mLeft->mLocation, ERRR_INVALID_CASE, "Integral constant expected"); - sblock->Append(cins); - - InterInstruction * bins = new InterInstruction(); - bins->mCode = IC_BRANCH; - bins->mSrc[0].mType = IT_BOOL; - bins->mSrc[0].mTemp = cins->mDst.mTemp; - sblock->Append(bins); - - sblock->Close(nblock, cblock); + int i = 0; + while (i < switchNodes.Size() && switchNodes[i].mValue < snode.mValue) + i++; + if (i < switchNodes.Size() && switchNodes[i].mValue == snode.mValue) + mErrors->Error(exp->mLeft->mLocation, ERRR_INVALID_CASE, "Duplicate case constant"); + else + switchNodes.Insert(i, snode); if (block) { @@ -2574,7 +2678,6 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* block->Close(nblock, nullptr); } - sblock = cblock; block = nblock; } else if (cexp->mType == EX_DEFAULT) @@ -2605,14 +2708,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* sexp = sexp->mRight; } - InterInstruction* jins = new InterInstruction(); - jins->mCode = IC_JUMP; - - sblock->Append(jins); - if (dblock) - sblock->Close(dblock, nullptr); - else - sblock->Close(eblock, nullptr); + BuildSwitchTree(proc, sblock, vl, switchNodes, 0, switchNodes.Size(), dblock ? dblock : eblock); if (block) { diff --git a/oscar64/InterCodeGenerator.h b/oscar64/InterCodeGenerator.h index c0ecaa7..77d1d88 100644 --- a/oscar64/InterCodeGenerator.h +++ b/oscar64/InterCodeGenerator.h @@ -42,6 +42,16 @@ protected: {} }; + struct SwitchNode + { + int mValue; + InterCodeBasicBlock* mBlock; + }; + + typedef GrowingArray SwitchNodeArray; + + void BuildSwitchTree(InterCodeProcedure* proc, InterCodeBasicBlock* block, ExValue v, const SwitchNodeArray& nodes, int left, int right, InterCodeBasicBlock* dblock); + ExValue Dereference(InterCodeProcedure* proc, InterCodeBasicBlock*& block, ExValue v, int level = 0); ExValue CoerceType(InterCodeProcedure* proc, InterCodeBasicBlock*& block, ExValue v, Declaration * type); ExValue TranslateExpression(Declaration * procType, InterCodeProcedure * proc, InterCodeBasicBlock*& block, Expression* exp, InterCodeBasicBlock* breakBlock, InterCodeBasicBlock* continueBlock, InlineMapper * inlineMapper);