blob: d15d2153996d725829b5d61e4e99f8f8f934bac6 [file] [log] [blame]
JF Bastiend4698e12015-08-15 01:23:28 +00001//===-- 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 <cstdio>
23#include <cstdarg>
24#include <deque>
25#include <list>
26#include <map>
27#include <memory>
28#include <set>
29
30namespace llvm {
31
32namespace Relooper {
33
34struct Block;
35struct Shape;
36
37///
38/// Info about a branching from one block to another
39///
40struct 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
71typedef SetVector<Block *> BlockSet;
72typedef MapVector<Block *, Branch *> BlockBranchMap;
73typedef 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///
79struct 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///
112struct 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
122private:
123 ShapeKind Kind;
124
125public:
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///
134struct 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///
145struct 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
153typedef 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///
161struct 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///
176struct 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///
185/// Implements the relooper algorithm for a function's blocks.
186///
187/// Implementation details: The Relooper instance has
188/// ownership of the blocks and shapes, and frees them when done.
189///
190struct Relooper {
191 std::deque<Block *> Blocks;
192 std::deque<Shape *> Shapes;
193 Shape *Root;
194 bool MinSize;
195 int BlockIdCounter;
196 int ShapeIdCounter;
197
198 Relooper();
199 ~Relooper();
200
201 void AddBlock(Block *New, int Id = -1);
202
203 // Calculates the shapes
204 void Calculate(Block *Entry);
205
206 // Sets us to try to minimize size
207 void SetMinSize(bool MinSize_) { MinSize = MinSize_; }
208};
209
210typedef MapVector<Block *, BlockSet> BlockBlockSetMap;
211
212} // namespace Relooper
213
214} // namespace llvm