Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 99 additions & 115 deletions include/PHIGateAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,123 +13,109 @@
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

#include <memory>
#include <unordered_map>
#include <variant>

namespace llvm {

/**
* @brief Path Expression Representation
*
* This section defines the classes to represent the gating path expressions
* as described in the paper. A path expression can be a simple edge, a union
* of paths, a concatenation of paths, or a special empty/not-taken symbol.
* @brief Simple path expression representation without variants
*/

struct PathExpr;

/**
* @brief Represents a simple path edge, often a conditional branch.
*/
struct EdgeExpr {
struct PathExpr {
enum ExprType {
EDGE,
UNION,
CONCAT,
LAMBDA,
EMPTY
} Type;

// For EDGE
const Instruction *Branch;
unsigned SuccessorIndex; // which successor path is taken

EdgeExpr(const Instruction *TI, unsigned Idx)
: Branch(TI), SuccessorIndex(Idx) {}

void print(raw_ostream &OS) const;
};

/**
* @brief Represents the union of two paths (e.g., from an if-then-else structure).
*/
struct UnionExpr {
std::shared_ptr<PathExpr> Lhs;
std::shared_ptr<PathExpr> Rhs;

UnionExpr(std::shared_ptr<PathExpr> L, std::shared_ptr<PathExpr> R)
: Lhs(L), Rhs(R) {}

void print(raw_ostream &OS) const;
};

/**
* @brief Represents the concatenation of two paths.
*/
struct ConcatExpr {
std::shared_ptr<PathExpr> Lhs;
std::shared_ptr<PathExpr> Rhs;

ConcatExpr(std::shared_ptr<PathExpr> L, std::shared_ptr<PathExpr> R)
: Lhs(L), Rhs(R) {}
void print(raw_ostream &OS) const;
};

/**
* @brief Represents an unconditional path (Lambda) or a path not taken (Empty/Phi).
*/
enum class SpecialExprType { Lambda, Empty };

/**
* @brief Special path expression for Lambda or Empty (not-taken) paths.
*/
struct SpecialExpr {
SpecialExprType Type;
// The predecessor basic block this path enters through.
// This is used to map phi-node arguments correctly.
unsigned SuccessorIndex;

// For UNION/CONCAT
PathExpr *Lhs;
PathExpr *Rhs;

// For LAMBDA
const BasicBlock *Predecessor;

SpecialExpr(SpecialExprType T, const BasicBlock *Pred = nullptr)
: Type(T), Predecessor(Pred) {}

void print(raw_ostream &OS) const;
};

/**
* @brief The main PathExpr variant that holds one of the above types.
*/
struct PathExpr {
std::variant<EdgeExpr, UnionExpr, ConcatExpr, SpecialExpr> V;

PathExpr(const decltype(V) &val) : V(val) {}

// Helper to print the expression recursively.

PathExpr() : Type(EMPTY), Branch(nullptr), SuccessorIndex(0), Lhs(nullptr), Rhs(nullptr), Predecessor(nullptr) {}
PathExpr(ExprType T) : Type(T), Branch(nullptr), SuccessorIndex(0), Lhs(nullptr), Rhs(nullptr), Predecessor(nullptr) {}

~PathExpr() {
delete Lhs;
delete Rhs;
}

static PathExpr* createEdge(const Instruction *branch, unsigned idx) {
PathExpr *expr = new PathExpr(EDGE);
expr->Branch = branch;
expr->SuccessorIndex = idx;
return expr;
}

static PathExpr* createUnion(PathExpr *lhs, PathExpr *rhs) {
PathExpr *expr = new PathExpr(UNION);
expr->Lhs = lhs;
expr->Rhs = rhs;
return expr;
}

static PathExpr* createConcat(PathExpr *lhs, PathExpr *rhs) {
PathExpr *expr = new PathExpr(CONCAT);
expr->Lhs = lhs;
expr->Rhs = rhs;
return expr;
}

static PathExpr* createLambda(const BasicBlock *pred = nullptr) {
PathExpr *expr = new PathExpr(LAMBDA);
expr->Predecessor = pred;
return expr;
}

static PathExpr* createEmpty() {
return new PathExpr(EMPTY);
}

void print(raw_ostream &OS) const {
std::visit([&OS](auto &&arg) { arg.print(OS); }, V);
switch (Type) {
case EDGE:
OS << "Edge(" << Branch->getParent()->getName() << " -> " << SuccessorIndex << ")";
break;
case UNION:
OS << "(";
Lhs->print(OS);
OS << " U ";
Rhs->print(OS);
OS << ")";
break;
case CONCAT:
OS << "(";
Lhs->print(OS);
OS << " . ";
Rhs->print(OS);
OS << ")";
break;
case LAMBDA:
OS << "Lambda";
if (Predecessor) {
OS << "[pred:" << Predecessor->getName() << "]";
}
break;
case EMPTY:
OS << "Empty";
break;
}
}
};

//-----------------------------------------------------------------------------
/**
* @brief Implements the algorithm from "Efficient Building and Placing of Gating Functions" by Tu and Padua.
*/
class PHIGateAnalyzer {
public:
/**
* @brief Result structure for a basic block that needs a gating function.
*/
struct GateInfo {
// The final gating path expression, representing the gamma-function.
std::shared_ptr<PathExpr> GammaFunction;
// The path expression for the loop-carried value, for mu-functions.
std::shared_ptr<PathExpr> MuFunction;

void print(raw_ostream &OS) const {
if (GammaFunction) {
OS << " Gamma: ";
GammaFunction->print(OS);
OS << "\n";
}
if (MuFunction) {
OS << " Mu: ";
MuFunction->print(OS);
OS << "\n";
}
}
};

PHIGateAnalyzer(Function &F, DominatorTree &DT) : F(F), DT(DT) {}

std::unordered_map<const BasicBlock *, SmallVector<const Value *>>
Expand All @@ -143,59 +129,57 @@ class PHIGateAnalyzer {
* Maps a node to its parent in the disjoint-set forest.
*/
DenseMap<DomTreeNode *, DomTreeNode *> Parent;

/**
* @brief The path expression from a node to its parent in the forest.
*/
DenseMap<DomTreeNode *, std::shared_ptr<PathExpr>> R;
DenseMap<DomTreeNode *, PathExpr *> R;

/**
* @brief GP(v): The gating path from idom(v) to v.
*/
DenseMap<const BasicBlock *, std::shared_ptr<PathExpr>> GP;
DenseMap<const BasicBlock *, PathExpr *> GP;

/**
* @brief G*(v): The gating path for loop-carried values at v.
*/
DenseMap<const BasicBlock *, std::shared_ptr<PathExpr>> G_star;
DenseMap<const BasicBlock *, PathExpr *> G_star;

/**
* @brief Phi(v): Flag indicating if v needs a gating function.
*/
DenseMap<const BasicBlock *, bool> NeedsPhi;

/**
* @brief X(v): Flag indicating if v is in the initial definition set.
*/
DenseMap<const BasicBlock *, bool> IsInitialDef;

// --- Algorithm Helper Functions ---

// The core analysis engine.
DenseMap<const BasicBlock *, GateInfo>
run(const SmallPtrSet<const BasicBlock *, 8> &InitialDefs);

void initialize(const SmallPtrSet<const BasicBlock *, 8> &InitialDefs);

// Implements EVAL(e) from the paper using path compression.
// Returns a pair: <NeedsPhi, PathExpression>
std::pair<bool, std::shared_ptr<PathExpr>> EVAL(DomTreeNode *Node);
std::pair<bool, PathExpr *> EVAL(DomTreeNode *Node);

// Implements LINK(u, v)
void LINK(DomTreeNode *u, DomTreeNode *v);

// Implements UPDATE(v, P)
void UPDATE(DomTreeNode *v, std::shared_ptr<PathExpr> P);
void UPDATE(DomTreeNode *v, PathExpr *P);

// Helper to find the root of a node in the forest.
DomTreeNode *FIND(DomTreeNode *Node);

// Helper to create a path expression for a single edge.
std::shared_ptr<PathExpr> createEdgeExpr(const BasicBlock *From,
const BasicBlock *To);
PathExpr *createEdgeExpr(const BasicBlock *From, const BasicBlock *To);

// Helper to merge two path expressions with the union operator.
std::shared_ptr<PathExpr> mergePaths(std::shared_ptr<PathExpr> P1,
std::shared_ptr<PathExpr> P2);
PathExpr *mergePaths(PathExpr *P1, PathExpr *P2);

// New helper to resolve a PathExpr into a list of Value* gates.
void collectGates(std::shared_ptr<PathExpr> Expr,
// Helper to resolve a PathExpr into a list of Value* gates.
void collectGates(PathExpr *Expr,
SmallVectorImpl<const Value *> &Gates,
SmallPtrSetImpl<const Value *> &Visited) const;

Expand Down
7 changes: 5 additions & 2 deletions include/ProgramSlice.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@
#include "llvm/Support/Error.h"

// #include "llvm/Transforms/IPO/FunctionMerging.h"
#include "PHIGateAnalyzer.h"

namespace llvm {

class ProgramSlice {
public:
/// Constructs a ProgramSlice object.
ProgramSlice(Instruction &I, Function &F, FunctionAnalysisManager &FAM);
ProgramSlice(Instruction &I, Function &F, FunctionAnalysisManager &FAM,
std::unordered_map<const BasicBlock *,
SmallVector<const Value *>> &predicates);

/// Checks if current slice can be outlined into a standalone function.
uint canOutline(AAResults *AA, TargetLibraryInfo &TLI,
Expand All @@ -44,7 +47,7 @@ class ProgramSlice {
std::map<Instruction *, Instruction *> getInstructionInSlice();

/// Outlines the given slice into a standalone Function.
Function *outline();
Function *outline(unsigned int *counter);

/// A function to simplify basic blocks of a function using the same
/// method as the SimplifyCFGPass
Expand Down
Loading