Home | History | Annotate | Download | only in WebAssembly
      1 //===-- Relooper.h - Top-level interface for WebAssembly  ----*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===-------------------------------------------------------------------===//
      9 ///
     10 /// \file
     11 /// \brief This defines an optimized C++ implemention of the Relooper
     12 /// algorithm, originally developed as part of Emscripten, which
     13 /// generates a structured AST from arbitrary control flow.
     14 ///
     15 //===-------------------------------------------------------------------===//
     16 
     17 #include "llvm/ADT/MapVector.h"
     18 #include "llvm/ADT/SetVector.h"
     19 #include "llvm/Support/Casting.h"
     20 
     21 #include <cassert>
     22 #include <cstdarg>
     23 #include <cstdio>
     24 #include <deque>
     25 #include <list>
     26 #include <map>
     27 #include <memory>
     28 #include <set>
     29 
     30 namespace llvm {
     31 
     32 namespace Relooper {
     33 
     34 struct Block;
     35 struct Shape;
     36 
     37 ///
     38 /// Info about a branching from one block to another
     39 ///
     40 struct Branch {
     41   enum FlowType {
     42     Direct = 0, // We will directly reach the right location through other
     43                 // means, no need for continue or break
     44     Break = 1,
     45     Continue = 2,
     46     Nested = 3 // This code is directly reached, but we must be careful to
     47                // ensure it is nested in an if - it is not reached
     48     // unconditionally, other code paths exist alongside it that we need to make
     49     // sure do not intertwine
     50   };
     51   Shape
     52       *Ancestor; // If not nullptr, this shape is the relevant one for purposes
     53                  // of getting to the target block. We break or continue on it
     54   Branch::FlowType
     55       Type;     // If Ancestor is not nullptr, this says whether to break or
     56                 // continue
     57   bool Labeled; // If a break or continue, whether we need to use a label
     58   const char *Condition; // The condition for which we branch. For example,
     59                          // "my_var == 1". Conditions are checked one by one.
     60                          // One of the conditions should have nullptr as the
     61                          // condition, in which case it is the default
     62                          // FIXME: move from char* to LLVM data structures
     63   const char *Code; // If provided, code that is run right before the branch is
     64                     // taken. This is useful for phis
     65                     // FIXME: move from char* to LLVM data structures
     66 
     67   Branch(const char *ConditionInit, const char *CodeInit = nullptr);
     68   ~Branch();
     69 };
     70 
     71 typedef SetVector<Block *> BlockSet;
     72 typedef MapVector<Block *, Branch *> BlockBranchMap;
     73 typedef MapVector<Block *, std::unique_ptr<Branch>> OwningBlockBranchMap;
     74 
     75 ///
     76 /// Represents a basic block of code - some instructions that end with a
     77 /// control flow modifier (a branch, return or throw).
     78 ///
     79 struct Block {
     80   // Branches become processed after we finish the shape relevant to them. For
     81   // example, when we recreate a loop, branches to the loop start become
     82   // continues and are now processed. When we calculate what shape to generate
     83   // from a set of blocks, we ignore processed branches. Blocks own the Branch
     84   // objects they use, and destroy them when done.
     85   OwningBlockBranchMap BranchesOut;
     86   BlockSet BranchesIn;
     87   OwningBlockBranchMap ProcessedBranchesOut;
     88   BlockSet ProcessedBranchesIn;
     89   Shape *Parent; // The shape we are directly inside
     90   int Id; // A unique identifier, defined when added to relooper. Note that this
     91           // uniquely identifies a *logical* block - if we split it, the two
     92           // instances have the same content *and* the same Id
     93   const char *Code;      // The string representation of the code in this block.
     94                          // Owning pointer (we copy the input)
     95                          // FIXME: move from char* to LLVM data structures
     96   const char *BranchVar; // A variable whose value determines where we go; if
     97                          // this is not nullptr, emit a switch on that variable
     98                          // FIXME: move from char* to LLVM data structures
     99   bool IsCheckedMultipleEntry; // If true, we are a multiple entry, so reaching
    100                                // us requires setting the label variable
    101 
    102   Block(const char *CodeInit, const char *BranchVarInit);
    103   ~Block();
    104 
    105   void AddBranchTo(Block *Target, const char *Condition,
    106                    const char *Code = nullptr);
    107 };
    108 
    109 ///
    110 /// Represents a structured control flow shape
    111 ///
    112 struct Shape {
    113   int Id; // A unique identifier. Used to identify loops, labels are Lx where x
    114           // is the Id. Defined when added to relooper
    115   Shape *Next;    // The shape that will appear in the code right after this one
    116   Shape *Natural; // The shape that control flow gets to naturally (if there is
    117                   // Next, then this is Next)
    118 
    119   /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
    120   enum ShapeKind { SK_Simple, SK_Multiple, SK_Loop };
    121 
    122 private:
    123   ShapeKind Kind;
    124 
    125 public:
    126   ShapeKind getKind() const { return Kind; }
    127 
    128   Shape(ShapeKind KindInit) : Id(-1), Next(nullptr), Kind(KindInit) {}
    129 };
    130 
    131 ///
    132 /// Simple: No control flow at all, just instructions.
    133 ///
    134 struct SimpleShape : public Shape {
    135   Block *Inner;
    136 
    137   SimpleShape() : Shape(SK_Simple), Inner(nullptr) {}
    138 
    139   static bool classof(const Shape *S) { return S->getKind() == SK_Simple; }
    140 };
    141 
    142 ///
    143 /// A shape that may be implemented with a labeled loop.
    144 ///
    145 struct LabeledShape : public Shape {
    146   bool Labeled; // If we have a loop, whether it needs to be labeled
    147 
    148   LabeledShape(ShapeKind KindInit) : Shape(KindInit), Labeled(false) {}
    149 };
    150 
    151 // Blocks with the same id were split and are identical, so we just care about
    152 // ids in Multiple entries
    153 typedef std::map<int, Shape *> IdShapeMap;
    154 
    155 ///
    156 /// Multiple: A shape with more than one entry. If the next block to
    157 ///           be entered is among them, we run it and continue to
    158 ///           the next shape, otherwise we continue immediately to the
    159 ///           next shape.
    160 ///
    161 struct MultipleShape : public LabeledShape {
    162   IdShapeMap InnerMap; // entry block ID -> shape
    163   int Breaks; // If we have branches on us, we need a loop (or a switch). This
    164               // is a counter of requirements,
    165               // if we optimize it to 0, the loop is unneeded
    166   bool UseSwitch; // Whether to switch on label as opposed to an if-else chain
    167 
    168   MultipleShape() : LabeledShape(SK_Multiple), Breaks(0), UseSwitch(false) {}
    169 
    170   static bool classof(const Shape *S) { return S->getKind() == SK_Multiple; }
    171 };
    172 
    173 ///
    174 /// Loop: An infinite loop.
    175 ///
    176 struct LoopShape : public LabeledShape {
    177   Shape *Inner;
    178 
    179   LoopShape() : LabeledShape(SK_Loop), Inner(nullptr) {}
    180 
    181   static bool classof(const Shape *S) { return S->getKind() == SK_Loop; }
    182 };
    183 
    184 } // namespace Relooper
    185 
    186 } // namespace llvm
    187