| Index: lib/Target/JSBackend/Relooper.h
|
| diff --git a/lib/Target/JSBackend/Relooper.h b/lib/Target/JSBackend/Relooper.h
|
| deleted file mode 100644
|
| index 35acad0f2d6603158e80d6f609164a879383b051..0000000000000000000000000000000000000000
|
| --- a/lib/Target/JSBackend/Relooper.h
|
| +++ /dev/null
|
| @@ -1,270 +0,0 @@
|
| -/*
|
| -This is an optimized C++ implemention of the Relooper algorithm originally
|
| -developed as part of Emscripten. This implementation includes optimizations
|
| -added since the original academic paper [1] was published about it, and is
|
| -written in an LLVM-friendly way with the goal of inclusion in upstream
|
| -LLVM.
|
| -
|
| -[1] Alon Zakai. 2011. Emscripten: an LLVM-to-JavaScript compiler. In Proceedings of the ACM international conference companion on Object oriented programming systems languages and applications companion (SPLASH '11). ACM, New York, NY, USA, 301-312. DOI=10.1145/2048147.2048224 http://doi.acm.org/10.1145/2048147.2048224
|
| -*/
|
| -
|
| -#include <assert.h>
|
| -#include <stdio.h>
|
| -#include <stdarg.h>
|
| -
|
| -#ifdef __cplusplus
|
| -
|
| -#include <map>
|
| -#include <deque>
|
| -#include <set>
|
| -
|
| -struct Block;
|
| -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
|
| - Break = 1,
|
| - 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
|
| - bool Labeled; // If a break or continue, whether we need to use a label
|
| - const char *Condition; // The condition for which we branch. For example, "my_var == 1". Conditions are checked one by one. One of the conditions should have NULL as the condition, in which case it is the default
|
| - const char *Code; // If provided, code that is run right before the branch is taken. This is useful for phis
|
| -
|
| - Branch(const char *ConditionInit, const char *CodeInit=NULL);
|
| - ~Branch();
|
| -
|
| - // Prints out the branch
|
| - void Render(Block *Target, bool SetLabel);
|
| -};
|
| -
|
| -typedef std::set<Block*> BlockSet;
|
| -typedef std::map<Block*, Branch*> BlockBranchMap;
|
| -
|
| -// Represents a basic block of code - some instructions that end with a
|
| -// control flow modifier (a branch, return or throw).
|
| -struct Block {
|
| - // Branches become processed after we finish the shape relevant to them. For example,
|
| - // when we recreate a loop, branches to the loop start become continues and are now
|
| - // processed. When we calculate what shape to generate from a set of blocks, we ignore
|
| - // processed branches.
|
| - // Blocks own the Branch objects they use, and destroy them when done.
|
| - BlockBranchMap BranchesOut;
|
| - BlockSet BranchesIn;
|
| - BlockBranchMap ProcessedBranchesOut;
|
| - BlockSet ProcessedBranchesIn;
|
| - 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; // 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);
|
| - ~Block();
|
| -
|
| - void AddBranchTo(Block *Target, const char *Condition, const char *Code=NULL);
|
| -
|
| - // Prints out the instructions code and branchings
|
| - void Render(bool InLoop);
|
| -};
|
| -
|
| -// Represents a structured control flow shape, one of
|
| -//
|
| -// Simple: No control flow at all, just instructions. If several
|
| -// blocks, then
|
| -//
|
| -// Multiple: A shape with more than one entry. If the next block to
|
| -// be entered is among them, we run it and continue to
|
| -// the next shape, otherwise we continue immediately to the
|
| -// next shape.
|
| -//
|
| -// Loop: An infinite loop.
|
| -//
|
| -// Emulated: Control flow is managed by a switch in a loop. This
|
| -// is necessary in some cases, for example when control
|
| -// flow is not known until runtime (indirect branches,
|
| -// setjmp returns, etc.)
|
| -//
|
| -
|
| -struct SimpleShape;
|
| -struct LabeledShape;
|
| -struct MultipleShape;
|
| -struct LoopShape;
|
| -struct EmulatedShape;
|
| -
|
| -struct Shape {
|
| - int Id; // A unique identifier. Used to identify loops, labels are Lx where x is the Id. Defined when added to relooper
|
| - Shape *Next; // The shape that will appear in the code right after this one
|
| - Shape *Natural; // The shape that control flow gets to naturally (if there is Next, then this is Next)
|
| -
|
| - enum ShapeType {
|
| - Simple,
|
| - Multiple,
|
| - Loop,
|
| - Emulated
|
| - };
|
| - ShapeType Type;
|
| -
|
| - Shape(ShapeType TypeInit) : Id(-1), Next(NULL), Type(TypeInit) {}
|
| - virtual ~Shape() {}
|
| -
|
| - virtual void Render(bool InLoop) = 0;
|
| -
|
| - static SimpleShape *IsSimple(Shape *It) { return It && It->Type == Simple ? (SimpleShape*)It : NULL; }
|
| - static MultipleShape *IsMultiple(Shape *It) { return It && It->Type == Multiple ? (MultipleShape*)It : NULL; }
|
| - static LoopShape *IsLoop(Shape *It) { return It && It->Type == Loop ? (LoopShape*)It : NULL; }
|
| - static LabeledShape *IsLabeled(Shape *It) { return IsMultiple(It) || IsLoop(It) ? (LabeledShape*)It : NULL; }
|
| - static EmulatedShape *IsEmulated(Shape *It) { return It && It->Type == Emulated ? (EmulatedShape*)It : NULL; }
|
| -};
|
| -
|
| -struct SimpleShape : public Shape {
|
| - Block *Inner;
|
| -
|
| - SimpleShape() : Shape(Simple), Inner(NULL) {}
|
| - void Render(bool InLoop) {
|
| - Inner->Render(InLoop);
|
| - if (Next) Next->Render(InLoop);
|
| - }
|
| -};
|
| -
|
| -// A shape that may be implemented with a labeled loop.
|
| -struct LabeledShape : public Shape {
|
| - bool Labeled; // If we have a loop, whether it needs to be labeled
|
| -
|
| - LabeledShape(ShapeType TypeInit) : Shape(TypeInit), Labeled(false) {}
|
| -};
|
| -
|
| -// Blocks with the same id were split and are identical, so we just care about ids in Multiple entries
|
| -typedef std::map<int, Shape*> IdShapeMap;
|
| -
|
| -struct MultipleShape : public LabeledShape {
|
| - IdShapeMap InnerMap; // entry block ID -> shape
|
| - int Breaks; // If we have branches on us, we need a loop (or a switch). This is a counter of requirements,
|
| - // if we optimize it to 0, the loop is unneeded
|
| - bool UseSwitch; // Whether to switch on label as opposed to an if-else chain
|
| -
|
| - MultipleShape() : LabeledShape(Multiple), Breaks(0), UseSwitch(false) {}
|
| -
|
| - void RenderLoopPrefix();
|
| - void RenderLoopPostfix();
|
| -
|
| - void Render(bool InLoop);
|
| -};
|
| -
|
| -struct LoopShape : public LabeledShape {
|
| - Shape *Inner;
|
| -
|
| - LoopShape() : LabeledShape(Loop), Inner(NULL) {}
|
| - void Render(bool InLoop);
|
| -};
|
| -
|
| -// TODO EmulatedShape is only partially functional. Currently it can be used for the
|
| -// entire set of blocks being relooped, but not subsets.
|
| -struct EmulatedShape : public LabeledShape {
|
| - Block *Entry;
|
| - BlockSet Blocks;
|
| -
|
| - EmulatedShape() : LabeledShape(Emulated) { Labeled = true; }
|
| - void Render(bool InLoop);
|
| -};
|
| -
|
| -// Implements the relooper algorithm for a function's blocks.
|
| -//
|
| -// Usage:
|
| -// 1. Instantiate this struct.
|
| -// 2. Call AddBlock with the blocks you have. Each should already
|
| -// have its branchings in specified (the branchings out will
|
| -// be calculated by the relooper).
|
| -// 3. Call Render().
|
| -//
|
| -// Implementation details: The Relooper instance has
|
| -// ownership of the blocks and shapes, and frees them when done.
|
| -struct Relooper {
|
| - std::deque<Block*> Blocks;
|
| - std::deque<Shape*> Shapes;
|
| - Shape *Root;
|
| - bool Emulate;
|
| - bool MinSize;
|
| - int BlockIdCounter;
|
| - int ShapeIdCounter;
|
| -
|
| - Relooper();
|
| - ~Relooper();
|
| -
|
| - void AddBlock(Block *New, int Id=-1);
|
| -
|
| - // Calculates the shapes
|
| - void Calculate(Block *Entry);
|
| -
|
| - // Renders the result.
|
| - void Render();
|
| -
|
| - // Sets the global buffer all printing goes to. Must call this or MakeOutputBuffer.
|
| - // XXX: this is deprecated, see MakeOutputBuffer
|
| - static void SetOutputBuffer(char *Buffer, int Size);
|
| -
|
| - // Creates an internal output buffer. Must call this or SetOutputBuffer. Size is
|
| - // a hint for the initial size of the buffer, it can be resized later one demand.
|
| - // For that reason this is more recommended than SetOutputBuffer.
|
| - static void MakeOutputBuffer(int Size);
|
| -
|
| - static char *GetOutputBuffer();
|
| -
|
| - // Sets asm.js mode on or off (default is off)
|
| - static void SetAsmJSMode(int On);
|
| -
|
| - // Sets whether we must emulate everything with switch-loop code
|
| - void SetEmulate(int E) { Emulate = E; }
|
| -
|
| - // Sets us to try to minimize size
|
| - void SetMinSize(bool MinSize_) { MinSize = MinSize_; }
|
| -};
|
| -
|
| -typedef std::map<Block*, BlockSet> BlockBlockSetMap;
|
| -
|
| -#if DEBUG
|
| -struct Debugging {
|
| - static void Dump(BlockSet &Blocks, const char *prefix=NULL);
|
| - static void Dump(Shape *S, const char *prefix=NULL);
|
| -};
|
| -#endif
|
| -
|
| -#endif // __cplusplus
|
| -
|
| -// C API - useful for binding to other languages
|
| -
|
| -#ifdef _WIN32
|
| - #ifdef RELOOPERDLL_EXPORTS
|
| - #define RELOOPERDLL_API __declspec(dllexport)
|
| - #else
|
| - #define RELOOPERDLL_API __declspec(dllimport)
|
| - #endif
|
| -#else
|
| - #define RELOOPERDLL_API
|
| -#endif
|
| -
|
| -#ifdef __cplusplus
|
| -extern "C" {
|
| -#endif
|
| -
|
| -RELOOPERDLL_API void rl_set_output_buffer(char *buffer, int size);
|
| -RELOOPERDLL_API void rl_make_output_buffer(int size);
|
| -RELOOPERDLL_API void rl_set_asm_js_mode(int on);
|
| -RELOOPERDLL_API void *rl_new_block(const char *text, const char *branch_var);
|
| -RELOOPERDLL_API void rl_delete_block(void *block);
|
| -RELOOPERDLL_API void rl_block_add_branch_to(void *from, void *to, const char *condition, const char *code);
|
| -RELOOPERDLL_API void *rl_new_relooper();
|
| -RELOOPERDLL_API void rl_delete_relooper(void *relooper);
|
| -RELOOPERDLL_API void rl_relooper_add_block(void *relooper, void *block);
|
| -RELOOPERDLL_API void rl_relooper_calculate(void *relooper, void *entry);
|
| -RELOOPERDLL_API void rl_relooper_render(void *relooper);
|
| -
|
| -#ifdef __cplusplus
|
| -}
|
| -#endif
|
| -
|
|
|