1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-20 11:33:24 +02:00
llvm-mirror/lib/Target/WebAssembly/Relooper.h
JF Bastien 8905d63bd8 [WebAssembly] Add Relooper
This is just an initial checkin of an implementation of the Relooper algorithm, in preparation for WebAssembly codegen to utilize. It doesn't do anything yet by itself.

The Relooper algorithm takes an arbitrary control flow graph and generates structured control flow from that, utilizing a helper variable when necessary to handle irreducibility. The WebAssembly backend will be able to use this in order to generate an AST for its binary format.

Author: azakai

Reviewers: jfb, sunfish

Subscribers: jevinskie, arsenm, jroelofs, llvm-commits

Differential revision: http://reviews.llvm.org/D11691

llvm-svn: 245142
2015-08-15 01:23:28 +00:00

215 lines
7.2 KiB
C++

//===-- Relooper.h - Top-level interface for WebAssembly ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===-------------------------------------------------------------------===//
///
/// \file
/// \brief This defines an optimized C++ implemention of the Relooper
/// algorithm, originally developed as part of Emscripten, which
/// generates a structured AST from arbitrary control flow.
///
//===-------------------------------------------------------------------===//
#include <llvm/ADT/MapVector.h>
#include <llvm/ADT/SetVector.h>
#include <llvm/Support/Casting.h>
#include <cassert>
#include <cstdio>
#include <cstdarg>
#include <deque>
#include <list>
#include <map>
#include <memory>
#include <set>
namespace llvm {
namespace Relooper {
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 nullptr, 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 nullptr, 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 nullptr as the
// condition, in which case it is the default
// FIXME: move from char* to LLVM data structures
const char *Code; // If provided, code that is run right before the branch is
// taken. This is useful for phis
// FIXME: move from char* to LLVM data structures
Branch(const char *ConditionInit, const char *CodeInit = nullptr);
~Branch();
};
typedef SetVector<Block *> BlockSet;
typedef MapVector<Block *, Branch *> BlockBranchMap;
typedef MapVector<Block *, std::unique_ptr<Branch>> OwningBlockBranchMap;
///
/// 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.
OwningBlockBranchMap BranchesOut;
BlockSet BranchesIn;
OwningBlockBranchMap 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)
// FIXME: move from char* to LLVM data structures
const char *BranchVar; // A variable whose value determines where we go; if
// this is not nullptr, emit a switch on that variable
// FIXME: move from char* to LLVM data structures
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 = nullptr);
};
///
/// Represents a structured control flow shape
///
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)
/// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
enum ShapeKind { SK_Simple, SK_Multiple, SK_Loop };
private:
ShapeKind Kind;
public:
ShapeKind getKind() const { return Kind; }
Shape(ShapeKind KindInit) : Id(-1), Next(nullptr), Kind(KindInit) {}
};
///
/// Simple: No control flow at all, just instructions.
///
struct SimpleShape : public Shape {
Block *Inner;
SimpleShape() : Shape(SK_Simple), Inner(nullptr) {}
static bool classof(const Shape *S) { return S->getKind() == SK_Simple; }
};
///
/// 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(ShapeKind KindInit) : Shape(KindInit), 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;
///
/// 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.
///
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(SK_Multiple), Breaks(0), UseSwitch(false) {}
static bool classof(const Shape *S) { return S->getKind() == SK_Multiple; }
};
///
/// Loop: An infinite loop.
///
struct LoopShape : public LabeledShape {
Shape *Inner;
LoopShape() : LabeledShape(SK_Loop), Inner(nullptr) {}
static bool classof(const Shape *S) { return S->getKind() == SK_Loop; }
};
///
/// Implements the relooper algorithm for a function's blocks.
///
/// 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 MinSize;
int BlockIdCounter;
int ShapeIdCounter;
Relooper();
~Relooper();
void AddBlock(Block *New, int Id = -1);
// Calculates the shapes
void Calculate(Block *Entry);
// Sets us to try to minimize size
void SetMinSize(bool MinSize_) { MinSize = MinSize_; }
};
typedef MapVector<Block *, BlockSet> BlockBlockSetMap;
} // namespace Relooper
} // namespace llvm