#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <deque>
#include <list>
#include <map>
#include <memory>
#include <set>
#include "wasm-builder.h"
#include "wasm.h"
namespace CFG {
class RelooperBuilder : public wasm::Builder {
wasm::Index labelHelper;
public:
RelooperBuilder(wasm::Module& wasm, wasm::Index labelHelper)
: wasm::Builder(wasm), labelHelper(labelHelper) {}
wasm::LocalGet* makeGetLabel() {
return makeLocalGet(labelHelper, wasm::Type::i32);
}
wasm::LocalSet* makeSetLabel(wasm::Index value) {
return makeLocalSet(labelHelper, makeConst(wasm::Literal(int32_t(value))));
}
wasm::Binary* makeCheckLabel(wasm::Index value) {
return makeBinary(
wasm::EqInt32, makeGetLabel(), makeConst(wasm::Literal(int32_t(value))));
}
wasm::Break* makeBlockBreak(int id) {
return wasm::Builder::makeBreak(getBlockBreakName(id));
}
wasm::Break* makeShapeContinue(int id) {
return wasm::Builder::makeBreak(getShapeContinueName(id));
}
wasm::Name getBlockBreakName(int id) {
return wasm::Name(std::string("block$") + std::to_string(id) + "$break");
}
wasm::Name getShapeContinueName(int id) {
return wasm::Name(std::string("shape$") + std::to_string(id) + "$continue");
}
};
struct Relooper;
struct Block;
struct Shape;
struct Branch {
enum FlowType {
Direct = 0, Break = 1,
Continue = 2
};
Shape* Ancestor = nullptr;
Branch::FlowType Type;
wasm::Expression* Condition;
std::unique_ptr<std::vector<wasm::Index>> SwitchValues;
wasm::Expression* Code;
Branch(wasm::Expression* ConditionInit, wasm::Expression* CodeInit = nullptr);
Branch(std::vector<wasm::Index>&& ValuesInit,
wasm::Expression* CodeInit = nullptr);
wasm::Expression*
Render(RelooperBuilder& Builder, Block* Target, bool SetLabel);
};
template<typename T> struct InsertOrderedSet {
std::map<T, typename std::list<T>::iterator> Map;
std::list<T> List;
typedef typename std::list<T>::iterator iterator;
iterator begin() { return List.begin(); }
iterator end() { return List.end(); }
void erase(const T& val) {
auto it = Map.find(val);
if (it != Map.end()) {
List.erase(it->second);
Map.erase(it);
}
}
void erase(iterator position) {
Map.erase(*position);
List.erase(position);
}
void insert(const T& val) {
auto it = Map.find(val);
if (it == Map.end()) {
List.push_back(val);
Map.insert(std::make_pair(val, --List.end()));
}
}
size_t size() const { return Map.size(); }
bool empty() const { return Map.empty(); }
void clear() {
Map.clear();
List.clear();
}
size_t count(const T& val) const { return Map.count(val); }
InsertOrderedSet() = default;
InsertOrderedSet(const InsertOrderedSet& other) { *this = other; }
InsertOrderedSet& operator=(const InsertOrderedSet& other) {
clear();
for (auto i : other.List) {
insert(i); }
return *this;
}
};
template<typename Key, typename T> struct InsertOrderedMap {
std::map<Key, typename std::list<std::pair<Key, T>>::iterator> Map;
std::list<std::pair<Key, T>> List;
T& operator[](const Key& k) {
auto it = Map.find(k);
if (it == Map.end()) {
List.push_back(std::make_pair(k, T()));
auto e = --List.end();
Map.insert(std::make_pair(k, e));
return e->second;
}
return it->second->second;
}
typedef typename std::list<std::pair<Key, T>>::iterator iterator;
iterator begin() { return List.begin(); }
iterator end() { return List.end(); }
void erase(const Key& k) {
auto it = Map.find(k);
if (it != Map.end()) {
List.erase(it->second);
Map.erase(it);
}
}
void erase(iterator position) { erase(position->first); }
void clear() {
Map.clear();
List.clear();
}
void swap(InsertOrderedMap<Key, T>& Other) {
Map.swap(Other.Map);
List.swap(Other.List);
}
size_t size() const { return Map.size(); }
bool empty() const { return Map.empty(); }
size_t count(const Key& k) const { return Map.count(k); }
InsertOrderedMap() = default;
InsertOrderedMap(InsertOrderedMap& other) {
abort(); }
InsertOrderedMap& operator=(const InsertOrderedMap& other) {
abort(); }
bool operator==(const InsertOrderedMap& other) {
return Map == other.Map && List == other.List;
}
bool operator!=(const InsertOrderedMap& other) { return !(*this == other); }
};
typedef InsertOrderedSet<Block*> BlockSet;
typedef InsertOrderedMap<Block*, Branch*> BlockBranchMap;
struct Block {
Relooper* relooper;
BlockBranchMap BranchesOut;
BlockSet BranchesIn;
BlockBranchMap ProcessedBranchesOut;
BlockSet ProcessedBranchesIn;
Shape* Parent = nullptr; int Id = -1; wasm::Expression* Code;
wasm::Expression* SwitchCondition;
bool IsCheckedMultipleEntry;
Block(Relooper* relooper,
wasm::Expression* CodeInit,
wasm::Expression* SwitchConditionInit = nullptr);
void AddBranchTo(Block* Target,
wasm::Expression* Condition,
wasm::Expression* Code = nullptr);
void AddSwitchBranchTo(Block* Target,
std::vector<wasm::Index>&& Values,
wasm::Expression* Code = nullptr);
wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop);
};
struct SimpleShape;
struct MultipleShape;
struct LoopShape;
struct Shape {
int Id = -1;
Shape* Next = nullptr;
Shape* Natural;
enum ShapeType { Simple, Multiple, Loop };
ShapeType Type;
Shape(ShapeType TypeInit) : Type(TypeInit) {}
virtual ~Shape() = default;
virtual wasm::Expression* Render(RelooperBuilder& Builder, 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;
}
};
struct SimpleShape : public Shape {
Block* Inner = nullptr;
SimpleShape() : Shape(Simple) {}
wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop) override;
};
typedef std::map<int, Shape*> IdShapeMap;
struct MultipleShape : public Shape {
IdShapeMap InnerMap;
MultipleShape() : Shape(Multiple) {}
wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop) override;
};
struct LoopShape : public Shape {
Shape* Inner = nullptr;
BlockSet Entries;
LoopShape() : Shape(Loop) {}
wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop) override;
};
struct Relooper {
wasm::Module* Module;
std::deque<std::unique_ptr<Block>> Blocks;
std::deque<std::unique_ptr<Branch>> Branches;
std::deque<std::unique_ptr<Shape>> Shapes;
Shape* Root;
bool MinSize;
int BlockIdCounter;
int ShapeIdCounter;
Relooper(wasm::Module* ModuleInit);
Block* AddBlock(wasm::Expression* CodeInit,
wasm::Expression* SwitchConditionInit = nullptr);
Branch* AddBranch(wasm::Expression* ConditionInit,
wasm::Expression* CodeInit);
Branch* AddBranch(std::vector<wasm::Index>&& ValuesInit,
wasm::Expression* CodeInit = nullptr);
SimpleShape* AddSimpleShape();
MultipleShape* AddMultipleShape();
LoopShape* AddLoopShape();
void Calculate(Block* Entry);
wasm::Expression* Render(RelooperBuilder& Builder);
void SetMinSize(bool MinSize_) { MinSize = MinSize_; }
};
typedef InsertOrderedMap<Block*, BlockSet> BlockBlockSetMap;
#ifdef RELOOPER_DEBUG
struct Debugging {
static void Dump(Block* Curr, const char* prefix = NULL);
static void Dump(BlockSet& Blocks, const char* prefix = NULL);
static void Dump(Shape* S, const char* prefix = NULL);
};
#endif
}