diff options
Diffstat (limited to 'src/relooper/Relooper.cpp')
-rw-r--r-- | src/relooper/Relooper.cpp | 84 |
1 files changed, 62 insertions, 22 deletions
diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp index a457914b..aefcad93 100644 --- a/src/relooper/Relooper.cpp +++ b/src/relooper/Relooper.cpp @@ -104,12 +104,14 @@ void Branch::Render(Block *Target, bool SetLabel) { int Block::IdCounter = 1; // 0 is reserved for clearings -Block::Block(const char *CodeInit) : Parent(NULL), Id(Block::IdCounter++), IsCheckedMultipleEntry(false) { +Block::Block(const char *CodeInit, const char *BranchVarInit) : Parent(NULL), Id(Block::IdCounter++), IsCheckedMultipleEntry(false) { Code = strdup(CodeInit); + BranchVar = BranchVarInit ? strdup(BranchVarInit) : NULL; } Block::~Block() { if (Code) free((void*)Code); + if (BranchVar) free((void*)BranchVar); for (BlockBranchMap::iterator iter = ProcessedBranchesOut.begin(); iter != ProcessedBranchesOut.end(); iter++) { delete iter->second; } @@ -189,8 +191,16 @@ void Block::Render(bool InLoop) { } assert(DefaultTarget); // Since each block *must* branch somewhere, this must be set + if (ProcessedBranchesOut.size() > 2) assert(BranchVar); // must have a branch variable if multiple conditions + + bool useSwitch = BranchVar != NULL; + + if (useSwitch) { + PrintIndented("switch (%s) {\n", BranchVar); + } + ministring RemainingConditions; - bool First = true; + bool First = !useSwitch; // when using a switch, there is no special first for (BlockBranchMap::iterator iter = ProcessedBranchesOut.begin();; iter++) { Block *Target; Branch *Details; @@ -208,26 +218,39 @@ void Block::Render(bool InLoop) { bool HasContent = SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent || Details->Code; if (iter != ProcessedBranchesOut.end()) { // If there is nothing to show in this branch, omit the condition - if (HasContent) { - PrintIndented("%sif (%s) {\n", First ? "" : "} else ", Details->Condition); - First = false; + if (useSwitch) { + PrintIndented("%s {\n", Details->Condition); } else { - if (RemainingConditions.size() > 0) RemainingConditions += " && "; - RemainingConditions += "!("; - RemainingConditions += Details->Condition; - RemainingConditions += ")"; + if (HasContent) { + PrintIndented("%sif (%s) {\n", First ? "" : "} else ", Details->Condition); + First = false; + } else { + if (RemainingConditions.size() > 0) RemainingConditions += " && "; + RemainingConditions += "!("; + if (BranchVar) { + RemainingConditions += BranchVar; + RemainingConditions += " == "; + } + RemainingConditions += Details->Condition; + RemainingConditions += ")"; + } } } else { - if (HasContent) { - if (RemainingConditions.size() > 0) { - if (First) { - PrintIndented("if (%s) {\n", RemainingConditions.c_str()); - First = false; - } else { - PrintIndented("} else if (%s) {\n", RemainingConditions.c_str()); + // this is the default + if (useSwitch) { + PrintIndented("default: {\n"); + } else { + if (HasContent) { + if (RemainingConditions.size() > 0) { + if (First) { + PrintIndented("if (%s) {\n", RemainingConditions.c_str()); + First = false; + } else { + PrintIndented("} else if (%s) {\n", RemainingConditions.c_str()); + } + } else if (!First) { + PrintIndented("} else {\n"); } - } else if (!First) { - PrintIndented("} else {\n"); } } } @@ -236,7 +259,13 @@ void Block::Render(bool InLoop) { if (HasFusedContent) { Fused->InnerMap.find(Target)->second->Render(InLoop); } + if (useSwitch && iter != ProcessedBranchesOut.end()) { + PrintIndented("break;\n"); + } if (!First) Indenter::Unindent(); + if (useSwitch) { + PrintIndented("}\n"); + } if (iter == ProcessedBranchesOut.end()) break; } if (!First) PrintIndented("}\n"); @@ -392,7 +421,7 @@ void Relooper::Calculate(Block *Entry) { PrintDebug("Splitting block %d\n", Original->Id); for (BlockSet::iterator iter = Original->BranchesIn.begin(); iter != Original->BranchesIn.end(); iter++) { Block *Prior = *iter; - Block *Split = new Block(Original->Code); + Block *Split = new Block(Original->Code, Original->BranchVar); Parent->Blocks.push_back(Split); PrintDebug(" to %d\n", Split->Id); Split->BranchesIn.insert(Prior); @@ -975,6 +1004,8 @@ void Relooper::Calculate(Block *Entry) { Root = Next; Next = NULL; SHAPE_SWITCH(Root, { + if (Simple->Inner->BranchVar) LastLoop = NULL; // a switch clears out the loop (TODO: only for breaks, not continue) + // If there is a next block, we already know at Simple creation time to make direct branches, // and we can do nothing more. If there is no next however, then Natural is where we will // go to by doing nothing, so we can potentially optimize some branches to direct. @@ -1028,6 +1059,11 @@ void Relooper::Calculate(Block *Entry) { // If we are fusing a Multiple with a loop into this Simple, then visit it now if (Fused && Fused->NeedLoop) { LoopStack.push(Fused); + } + if (Simple->Inner->BranchVar) { + LoopStack.push(NULL); // a switch means breaks are now useless, push a dummy + } + if (Fused) { RECURSE_Multiple(Fused, FindLabeledLoops); } for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) { @@ -1038,14 +1074,18 @@ void Relooper::Calculate(Block *Entry) { if (Details->Ancestor != LoopStack.top() && Details->Labeled) { LabeledShape *Labeled = Shape::IsLabeled(Details->Ancestor); Labeled->Labeled = true; - Details->Labeled = true; } else { Details->Labeled = false; } } } + if (Simple->Inner->BranchVar) { + LoopStack.pop(); + } if (Fused && Fused->NeedLoop) { LoopStack.pop(); + } + if (Fused) { Next = Fused->Next; } else { Next = Root->Next; @@ -1173,8 +1213,8 @@ void rl_set_asm_js_mode(int on) { Relooper::SetAsmJSMode(on); } -void *rl_new_block(const char *text) { - Block *ret = new Block(text); +void *rl_new_block(const char *text, const char *branch_var) { + Block *ret = new Block(text, branch_var); #if DEBUG printf(" void *b%d = rl_new_block(\"// code %d\");\n", ret->Id, ret->Id); __blockDebugMap__[ret] = ret->Id; |