diff options
Diffstat (limited to 'lib/Target/JSBackend')
-rw-r--r-- | lib/Target/JSBackend/Relooper.cpp | 79 | ||||
-rw-r--r-- | lib/Target/JSBackend/Relooper.h | 8 |
2 files changed, 67 insertions, 20 deletions
diff --git a/lib/Target/JSBackend/Relooper.cpp b/lib/Target/JSBackend/Relooper.cpp index f09c54adf8..c683015891 100644 --- a/lib/Target/JSBackend/Relooper.cpp +++ b/lib/Target/JSBackend/Relooper.cpp @@ -1,3 +1,7 @@ +// We are implementing the Relooper C API, so always export from this file. +#ifndef RELOOPERDLL_EXPORTS +#define RELOOPERDLL_EXPORTS +#endif #include "Relooper.h" @@ -118,7 +122,7 @@ void Branch::Render(Block *Target, bool SetLabel) { if (Code) PrintIndented("%s\n", Code); if (SetLabel) PrintIndented("label = %d;\n", Target->Id); if (Ancestor) { - if (Type != Direct) { + if (Type == Break || Type == Continue) { if (Labeled) { PrintIndented("%s L%d;\n", Type == Break ? "break" : "continue", Ancestor->Id); } else { @@ -283,6 +287,11 @@ void Block::Render(bool InLoop) { Details->Render(Target, SetCurrLabel); if (HasFusedContent) { Fused->InnerMap.find(Target)->second->Render(InLoop); + } else if (Details->Type == Branch::Nested) { + // Nest the parent content here, and remove it from showing up afterwards as Next + assert(Parent->Next); + Parent->Next->Render(InLoop); + Parent->Next = NULL; } if (useSwitch && iter != ProcessedBranchesOut.end()) { PrintIndented("break;\n"); @@ -646,7 +655,7 @@ void Relooper::Calculate(Block *Entry) { Block *Curr = *iter; for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) { Block *Target = iter->first; - if (!contains(Hoisted, Target) && !contains(NextEntries, Target)) { + if (!contains(Hoisted, Target) && !contains(NextEntries, Target)) // abort this hoisting abort = true; break; @@ -1073,12 +1082,48 @@ void Relooper::Calculate(Block *Entry) { 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. if (Simple->Next) { + if (!Simple->Inner->BranchVar && Simple->Inner->ProcessedBranchesOut.size() == 2) { + // If there is a next block, we already know at Simple creation time to make direct branches, + // and we can do nothing more in general. But, we try to optimize the case of a break and + // a direct: This would normally be if (break?) { break; } .. but if we + // make sure to nest the else, we can save the break, if (!break?) { .. } . This is also + // better because the more canonical nested form is easier to further optimize later. The + // downside is more nesting, which adds to size in builds with whitespace. + // Note that we avoid switches, as it complicates control flow and is not relevant + // for the common case we optimize here. + bool Found = false; + bool Abort = false; + for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) { + Block *Target = iter->first; + Branch *Details = iter->second; + if (Details->Type == Branch::Break) { + Found = true; + if (!contains(NaturalBlocks, Target)) Abort = true; + } else if (Details->Type != Branch::Direct) { + Abort = true; + } + } + if (Found && !Abort) { + for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) { + Block *Target = iter->first; + Branch *Details = iter->second; + if (Details->Type == Branch::Break) { + Details->Type = Branch::Direct; + if (MultipleShape *Multiple = Shape::IsMultiple(Details->Ancestor)) { + Multiple->NeedLoop--; + } + } else { + assert(Details->Type == Branch::Direct); + Details->Type = Branch::Nested; + } + } + } + } Next = Simple->Next; } else { + // If there is no next then Natural is where we will + // go to by doing nothing, so we can potentially optimize some branches to direct. for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) { Block *Target = iter->first; Branch *Details = iter->second; @@ -1136,7 +1181,7 @@ void Relooper::Calculate(Block *Entry) { for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) { Block *Target = iter->first; Branch *Details = iter->second; - if (Details->Type != Branch::Direct) { + if (Details->Type == Branch::Break || Details->Type == Branch::Continue) { assert(LoopStack.size() > 0); if (Details->Ancestor != LoopStack.top() && Details->Labeled) { LabeledShape *Labeled = Shape::IsLabeled(Details->Ancestor); @@ -1269,7 +1314,7 @@ VoidIntMap __blockDebugMap__; // maps block pointers in currently running code t extern "C" { -void rl_set_output_buffer(char *buffer, int size) { +RELOOPERDLL_API void rl_set_output_buffer(char *buffer, int size) { #if DEBUG printf("#include \"Relooper.h\"\n"); printf("int main() {\n"); @@ -1279,15 +1324,15 @@ void rl_set_output_buffer(char *buffer, int size) { Relooper::SetOutputBuffer(buffer, size); } -void rl_make_output_buffer(int size) { +RELOOPERDLL_API void rl_make_output_buffer(int size) { Relooper::SetOutputBuffer((char*)malloc(size), size); } -void rl_set_asm_js_mode(int on) { +RELOOPERDLL_API void rl_set_asm_js_mode(int on) { Relooper::SetAsmJSMode(on); } -void *rl_new_block(const char *text, const char *branch_var) { +RELOOPERDLL_API 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); @@ -1297,21 +1342,21 @@ void *rl_new_block(const char *text, const char *branch_var) { return ret; } -void rl_delete_block(void *block) { +RELOOPERDLL_API void rl_delete_block(void *block) { #if DEBUG printf(" rl_delete_block(block_map[%d]);\n", ((Block*)block)->Id); #endif delete (Block*)block; } -void rl_block_add_branch_to(void *from, void *to, const char *condition, const char *code) { +RELOOPERDLL_API void rl_block_add_branch_to(void *from, void *to, const char *condition, const char *code) { #if DEBUG printf(" rl_block_add_branch_to(block_map[%d], block_map[%d], %s%s%s, %s%s%s);\n", ((Block*)from)->Id, ((Block*)to)->Id, condition ? "\"" : "", condition ? condition : "NULL", condition ? "\"" : "", code ? "\"" : "", code ? code : "NULL", code ? "\"" : ""); #endif ((Block*)from)->AddBranchTo((Block*)to, condition, code); } -void *rl_new_relooper() { +RELOOPERDLL_API void *rl_new_relooper() { #if DEBUG printf(" void *block_map[10000];\n"); printf(" void *rl = rl_new_relooper();\n"); @@ -1319,18 +1364,18 @@ void *rl_new_relooper() { return new Relooper; } -void rl_delete_relooper(void *relooper) { +RELOOPERDLL_API void rl_delete_relooper(void *relooper) { delete (Relooper*)relooper; } -void rl_relooper_add_block(void *relooper, void *block) { +RELOOPERDLL_API void rl_relooper_add_block(void *relooper, void *block) { #if DEBUG printf(" rl_relooper_add_block(rl, block_map[%d]);\n", ((Block*)block)->Id); #endif ((Relooper*)relooper)->AddBlock((Block*)block); } -void rl_relooper_calculate(void *relooper, void *entry) { +RELOOPERDLL_API void rl_relooper_calculate(void *relooper, void *entry) { #if DEBUG printf(" rl_relooper_calculate(rl, block_map[%d]);\n", ((Block*)entry)->Id); printf(" rl_relooper_render(rl);\n"); @@ -1342,7 +1387,7 @@ void rl_relooper_calculate(void *relooper, void *entry) { ((Relooper*)relooper)->Calculate((Block*)entry); } -void rl_relooper_render(void *relooper) { +RELOOPERDLL_API void rl_relooper_render(void *relooper) { ((Relooper*)relooper)->Render(); } diff --git a/lib/Target/JSBackend/Relooper.h b/lib/Target/JSBackend/Relooper.h index 85adf359c2..152bae0e6e 100644 --- a/lib/Target/JSBackend/Relooper.h +++ b/lib/Target/JSBackend/Relooper.h @@ -24,9 +24,11 @@ struct Shape; // Info about a branching from one block to another struct Branch { enum FlowType { - Direct = 0, // We will directly reach the right location through other means, no need for continue or break + Direct = 0, // We will directly reach the right location through other means, no need for continue or break Break = 1, - Continue = 2 + Continue = 2, + Nested = 3 // This code is directly reached, but we must be careful to ensure it is nested in an if - it is not reached + // unconditionally, other code paths exist alongside it that we need to make sure do not intertwine }; Shape *Ancestor; // If not NULL, this shape is the relevant one for purposes of getting to the target block. We break or continue on it Branch::FlowType Type; // If Ancestor is not NULL, this says whether to break or continue @@ -59,7 +61,7 @@ struct Block { Shape *Parent; // The shape we are directly inside int Id; // A unique identifier, defined when added to relooper. Note that this uniquely identifies a *logical* block - if we split it, the two instances have the same content *and* the same Id const char *Code; // The string representation of the code in this block. Owning pointer (we copy the input) - const char *BranchVar; // If we have more than one branch out, the variable whose value determines where we go + const char *BranchVar; // A variable whose value determines where we go; if this is not NULL, emit a switch on that variable bool IsCheckedMultipleEntry; // If true, we are a multiple entry, so reaching us requires setting the label variable Block(const char *CodeInit, const char *BranchVarInit); |