summaryrefslogtreecommitdiff
path: root/willow/include
diff options
context:
space:
mode:
Diffstat (limited to 'willow/include')
-rw-r--r--willow/include/willow/IR/BasicBlock.h53
-rw-r--r--willow/include/willow/IR/Constant.h57
-rw-r--r--willow/include/willow/IR/ConstantPool.h35
-rw-r--r--willow/include/willow/IR/Diagnostic.h3
-rw-r--r--willow/include/willow/IR/DiagnosticEngine.h24
-rw-r--r--willow/include/willow/IR/Function.h35
-rw-r--r--willow/include/willow/IR/IRBuilder.h70
-rw-r--r--willow/include/willow/IR/Instruction.h13
-rw-r--r--willow/include/willow/IR/Instructions.h58
-rw-r--r--willow/include/willow/IR/Value.h34
10 files changed, 85 insertions, 297 deletions
diff --git a/willow/include/willow/IR/BasicBlock.h b/willow/include/willow/IR/BasicBlock.h
index eb08c5d..7a3a947 100644
--- a/willow/include/willow/IR/BasicBlock.h
+++ b/willow/include/willow/IR/BasicBlock.h
@@ -54,38 +54,12 @@ public:
Instruction *addInstruction(std::unique_ptr<Instruction> inst);
- void push_back(Instruction &inst) {
- assert(!inst.hasParent() && "Instruction is already parented");
- body.push_back(inst);
- inst.setParent(this);
- }
-
- void push_front(Instruction &inst) {
- assert(!inst.hasParent() && "Instruction is already parented");
- body.push_front(inst);
- inst.setParent(this);
- }
-
- Iterator insert(Iterator pos, Instruction &inst) {
- assert(!inst.hasParent() && "Instruction is already parented");
- auto it = body.insert(pos, inst);
- inst.setParent(this);
- return it;
- }
-
- Iterator erase(Iterator pos) {
- Instruction &I = *pos;
- I.setParent(nullptr);
- return body.erase(pos);
- }
+ void push_back(Instruction &inst);
+ void push_front(Instruction &inst);
+ Iterator insert(Iterator pos, Instruction &inst);
- Iterator eraseAndDelete(Iterator pos) {
- Instruction &inst = *pos;
- pos->setParent(nullptr);
- auto it = body.erase(pos);
- delete &inst;
- return it;
- }
+ Iterator erase(Iterator pos);
+ Iterator eraseAndDelete(Iterator pos);
std::optional<Location> getLoc() const { return loc; }
@@ -94,21 +68,8 @@ public:
return predecessors;
}
- void addPred(BasicBlock *bb) {
- auto [it, inserted] = predecessors.try_emplace(bb, 1);
-
- if (!inserted)
- it->second += 1;
- }
-
- void delPred(BasicBlock *bb) {
- auto it = preds().find(bb);
-
- it->second -= 1;
-
- if (it->second <= 0)
- preds().erase(it);
- }
+ void addPred(BasicBlock *bb);
+ void delPred(BasicBlock *bb);
};
} // namespace willow
diff --git a/willow/include/willow/IR/Constant.h b/willow/include/willow/IR/Constant.h
index 4e2a3d7..acdc75c 100644
--- a/willow/include/willow/IR/Constant.h
+++ b/willow/include/willow/IR/Constant.h
@@ -1,14 +1,12 @@
#ifndef WILLOW_INCLUDE_IR_CONSTANT_H
#define WILLOW_INCLUDE_IR_CONSTANT_H
-#include <utility>
#include <willow/IR/Value.h>
namespace willow {
enum class ConstantKind {
Int, //< Integer value with known bits
- Undef, //< Known undef
Poison, //< Known poison
};
@@ -23,7 +21,6 @@ public:
Constant(const Constant &) = delete;
Constant &operator=(const Constant &) = delete;
- bool isUndef() const { return kind == ConstantKind::Undef; }
bool isPoison() const { return kind == ConstantKind::Poison; }
bool isInt() const { return kind == ConstantKind::Int; }
};
@@ -34,29 +31,9 @@ class ConstantInt final : public Constant {
uint64_t bits = 0;
public:
- explicit ConstantInt(Type ty, uint64_t val)
- : Constant(ty, ConstantKind::Int) {
- const size_t w = ty.getNumBits();
- assert(w <= 64 && "Come back when im less lazy");
- // assert(!(val >> w) && "Truncated constant");
-
- if (w == 64)
- bits = val;
- else {
- const uint64_t m = (uint64_t{1} << w) - 1;
- bits = val & m;
- }
- }
-
- int64_t getSExtVal() const {
- const size_t w = getType().getNumBits();
-
- if (w == 64)
- return static_cast<int64_t>(bits);
-
- unsigned sh = 64 - w;
- return (static_cast<int64_t>(bits << sh)) >> sh;
- }
+ explicit ConstantInt(Type ty, uint64_t val);
+
+ int64_t getSExtVal() const;
uint64_t getZExtVal() const { return bits; }
@@ -67,21 +44,10 @@ public:
};
struct Hash {
- size_t operator()(const ConstantInt::Key &k) const noexcept {
- auto h1 = std::hash<TypeImpl *>{}(k.ty);
- auto h2 = std::hash<uint64_t>{}(k.bits);
-
- return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));
- }
+ size_t operator()(const ConstantInt::Key &k) const noexcept;
};
};
-/// Represents a constant value that is entirely undef.
-class UndefVal final : public Constant {
-public:
- explicit UndefVal(Type ty) : Constant(ty, ConstantKind::Undef) {}
-};
-
/// Represents a constant value that is entirely poison.
class PoisonVal final : public Constant {
public:
@@ -90,19 +56,6 @@ public:
} // namespace willow
-// TODO lol
-inline std::ostream& operator<<(std::ostream &os, const willow::Constant& c) {
- if (c.isPoison())
- return os << "poison";
-
- if (c.isUndef())
- return os << "undef";
-
- if (c.isInt()) {
- return os << static_cast<const willow::ConstantInt*>(&c)->getSExtVal();
- }
-
- std::unreachable();
-}
+std::ostream &operator<<(std::ostream &os, const willow::Constant &c);
#endif // WILLOW_INCLUDE_IR_CONSTANT_H
diff --git a/willow/include/willow/IR/ConstantPool.h b/willow/include/willow/IR/ConstantPool.h
index 7d5347b..dd93997 100644
--- a/willow/include/willow/IR/ConstantPool.h
+++ b/willow/include/willow/IR/ConstantPool.h
@@ -1,8 +1,8 @@
#ifndef WILLOW_INCLUDE_IR_CONSTANT_POOL_H
#define WILLOW_INCLUDE_IR_CONSTANT_POOL_H
-#include <memory>
#include <willow/IR/Constant.h>
+#include <memory>
namespace willow {
@@ -14,8 +14,6 @@ public:
/// Get a uniqued integer constant with the specified type and value.
ConstantInt *getInt(Type ty, uint64_t val);
- /// Get a uniqued undef value for the specified type \p ty.
- UndefVal *getUndefVal(Type ty);
/// Get a uniqued poison value for the specified type \p ty.
PoisonVal *getPoisonVal(Type ty);
@@ -25,41 +23,10 @@ private:
ConstantInt::Hash>
icache;
- std::mutex undef_mutex;
- std::unordered_map<TypeImpl *, std::unique_ptr<UndefVal>> ucache;
-
std::mutex poison_mutex;
std::unordered_map<TypeImpl *, std::unique_ptr<PoisonVal>> pcache;
};
-inline ConstantInt *ConstantPool::getInt(Type ty, uint64_t val) {
- assert(ty.isInt() && "Expected integer type");
- ConstantInt::Key &&k{ty.getImpl(), ty.getNumBits()};
- std::lock_guard<std::mutex> lock(int_mutex);
-
- auto [it, _] = icache.try_emplace(k, std::make_unique<ConstantInt>(ty, val));
-
- return it->second.get();
-}
-
-inline UndefVal *ConstantPool::getUndefVal(Type ty) {
- std::lock_guard<std::mutex> lock(undef_mutex);
-
- auto [it, _] =
- ucache.try_emplace(ty.getImpl(), std::make_unique<UndefVal>(ty));
-
- return it->second.get();
-}
-
-inline PoisonVal *ConstantPool::getPoisonVal(Type ty) {
- std::lock_guard<std::mutex> lock(poison_mutex);
-
- auto [it, _] =
- pcache.try_emplace(ty.getImpl(), std::make_unique<PoisonVal>(ty));
-
- return it->second.get();
-}
-
}; // namespace willow
#endif // WILLOW_INCLUDE_IR_CONSTANT_POOL_H
diff --git a/willow/include/willow/IR/Diagnostic.h b/willow/include/willow/IR/Diagnostic.h
index 538704c..68483d9 100644
--- a/willow/include/willow/IR/Diagnostic.h
+++ b/willow/include/willow/IR/Diagnostic.h
@@ -5,6 +5,7 @@
#include <string>
#include <vector>
+#include <ostream>
namespace willow {
@@ -19,4 +20,6 @@ struct Diagnostic {
} // namespace willow
+std::ostream &operator<<(std::ostream &os, const willow::Diagnostic &diagnostic);
+
#endif // WILLOW_INCLUDE_IR_DIAGNOSTIC_H
diff --git a/willow/include/willow/IR/DiagnosticEngine.h b/willow/include/willow/IR/DiagnosticEngine.h
index a8735af..06dcc3c 100644
--- a/willow/include/willow/IR/DiagnosticEngine.h
+++ b/willow/include/willow/IR/DiagnosticEngine.h
@@ -21,11 +21,7 @@ public:
explicit DiagnosticEngine(Handler h) : handler(std::move(h)) {}
void setHandler(Handler h) { handler = std::move(h); }
-
- void report(Diagnostic d) {
- if (handler)
- handler(std::move(d));
- }
+ void report(Diagnostic d);
private:
Handler handler;
@@ -42,23 +38,11 @@ public:
DiagnosticBuilder &operator=(const DiagnosticBuilder &) = delete;
DiagnosticBuilder(DiagnosticEngine &eng, Severity severity,
- std::optional<Location> loc)
- : engine(&eng) {
- diag.severity = severity;
- diag.location = loc;
- }
+ std::optional<Location> loc = std::nullopt);
- DiagnosticBuilder(DiagnosticBuilder &&other) noexcept
- : engine(std::exchange(other.engine, nullptr)),
- diag(std::move(other.diag)), os(std::move(other.os)) {}
+ DiagnosticBuilder(DiagnosticBuilder &&other) noexcept;
- ~DiagnosticBuilder() {
- if (!engine) // was moved from
- return;
-
- diag.message += os.str();
- engine->report(std::move(diag));
- }
+ ~DiagnosticBuilder();
template <typename T>
DiagnosticBuilder &operator<<(T &&x) {
diff --git a/willow/include/willow/IR/Function.h b/willow/include/willow/IR/Function.h
index bd6ef3d..817abd2 100644
--- a/willow/include/willow/IR/Function.h
+++ b/willow/include/willow/IR/Function.h
@@ -8,7 +8,6 @@
#include <memory>
#include <ranges>
#include <string>
-#include <string_view>
#include <utility>
#include <vector>
@@ -83,32 +82,16 @@ public:
std::size_t getNumParams() const { return params.size(); }
- /// \return The SSA values that exist in this block.
- auto getValues() {
- return blocks |
- std::views::transform([](auto &p) -> Value & { return *p; });
- }
- auto getValues() const {
- return blocks |
- std::views::transform([](auto &p) -> const Value & { return *p; });
- }
-
/// Append an existing block, transferring ownership.
/// \param block Basic block to append.
/// \return Raw pointer to the appended block.
- BasicBlock *addBlock(std::unique_ptr<BasicBlock> block) {
- auto p = block.get();
- blocks.push_back(std::move(block));
- p->setParent(this);
- return p;
- }
+ BasicBlock *addBlock(std::unique_ptr<BasicBlock> block);
/// Construct a new block in-place and append it.
/// \return Raw pointer to the appended block.
template <typename... Args>
BasicBlock *createBlock(Args &&...args) {
- blocks.push_back(std::make_unique<BasicBlock>(std::forward<Args>(args)...));
- return blocks.back().get();
+ return addBlock(std::make_unique<BasicBlock>(std::forward<Args>(args)...));
}
Type getReturnType() const {
@@ -119,20 +102,6 @@ public:
}
};
-inline const BasicBlock *Function::entryBlock() const {
- if (blocks.empty())
- return nullptr;
- else
- return blocks.front().get();
-}
-
-inline BasicBlock *Function::entryBlock() {
- if (blocks.empty())
- return nullptr;
- else
- return blocks.front().get();
-}
-
} // namespace willow
#endif // WILLOW_INCLUDE_IR_FUNCTION_H
diff --git a/willow/include/willow/IR/IRBuilder.h b/willow/include/willow/IR/IRBuilder.h
index f2f36f2..1c637a7 100644
--- a/willow/include/willow/IR/IRBuilder.h
+++ b/willow/include/willow/IR/IRBuilder.h
@@ -21,69 +21,75 @@ public:
BasicBlock::Iterator insertion_point)
: insert_point(insertion_point), ctx(ctx) {}
- void SetInsertPoint(BasicBlock::Iterator point) { insert_point = point; }
+ void setInsertPoint(BasicBlock::Iterator point) { insert_point = point; }
- AddInst *BuildAdd(Type type, Value *lhs, Value *rhs,
+ AddInst *buildAdd(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- MulInst *BuildMul(Type type, Value *lhs, Value *rhs,
+ MulInst *buildMul(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- SubInst *BuildSub(Type type, Value *lhs, Value *rhs,
+ SubInst *buildSub(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- DivInst *BuildDiv(Type type, Value *lhs, Value *rhs,
+ DivInst *buildDiv(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- ModInst *BuildMod(Type type, Value *lhs, Value *rhs,
+ ModInst *buildMod(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- ShlInst *BuildShl(Type type, Value *lhs, Value *rhs,
+ ShlInst *buildShl(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- ShrInst *BuildShr(Type type, Value *lhs, Value *rhs,
+ ShrInst *buildShr(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- AshlInst *BuildAshl(Type type, Value *lhs, Value *rhs,
+ AshlInst *buildAshl(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- AshrInst *BuildAshr(Type type, Value *lhs, Value *rhs,
+ AshrInst *buildAshr(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- EqInst *BuildEq(Value *lhs, Value *rhs,
+ EqInst *buildEq(Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- LtInst *BuildLt(Value *lhs, Value *rhs,
+ LtInst *buildLt(Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- GtInst *BuildGt(Value *lhs, Value *rhs,
+ GtInst *buildGt(Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- LeInst *BuildLe(Value *lhs, Value *rhs,
+ LeInst *buildLe(Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- GeInst *BuildGe(Value *lhs, Value *rhs,
+ GeInst *buildGe(Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- AndInst *BuildAnd(Value *lhs, Value *rhs,
+ AndInst *buildAnd(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- OrInst *BuildOr(Value *lhs, Value *rhs,
+ OrInst *buildOr(Type type, Value *lhs, Value *rhs,
std::optional<Location> loc = std::nullopt);
- NotInst *BuildNot(Value *val, std::optional<Location> loc = std::nullopt);
+ NotInst *buildNot(Type type, Value *val,
+ std::optional<Location> loc = std::nullopt);
- JmpInst *BuildJmp(BasicBlock *dst,
+ JmpInst *buildJmp(BasicBlock *dst,
std::optional<Location> loc = std::nullopt);
- BrInst *BuildBr(Value *predicate, BasicBlock *truedst, BasicBlock *falsedst,
+ BrInst *buildBr(Value *predicate, BasicBlock *truedst, BasicBlock *falsedst,
std::optional<Location> loc = std::nullopt);
template <typename... Args>
- CallInst *BuildCall(Type rty, Function *func,
+ CallInst *buildCall(Type rty, Function *func,
std::optional<Location> loc = std::nullopt,
- Args &&...args) {
- auto *inst = new CallInst(rty, func, std::forward<Args>(args)...);
- assert(inst);
- insert_point->insertAfter(*inst);
- insert_point++;
+ Args &&...args);
- return inst;
- }
- RetInst *BuildRet(Value *val, std::optional<Location> loc = std::nullopt);
- RetInst *BuildRet(std::optional<Location> loc = std::nullopt);
+ RetInst *buildRet(Value *val, std::optional<Location> loc = std::nullopt);
+ RetInst *buildRet(std::optional<Location> loc = std::nullopt);
PhiInst *
- BuildPhi(Type ty,
+ buildPhi(Type ty,
std::initializer_list<std::pair<BasicBlock *, Value *>> args,
std::optional<Location> loc = std::nullopt);
- AllocaInst *BuildAlloca(Type ty, std::optional<Location> loc = std::nullopt);
+ AllocaInst *buildAlloca(Type ty, std::optional<Location> loc = std::nullopt);
};
+template <typename... Args>
+CallInst *IRBuilder::buildCall(Type rty, Function *func,
+ std::optional<Location> loc, Args &&...args) {
+ auto *inst = new CallInst(rty, func, std::forward<Args>(args)...);
+ assert(inst);
+ insert_point->insertAfter(*inst);
+ insert_point++;
+
+ return inst;
+}
+
} // namespace willow
#endif // WILLOW_INCLUDE_IR_IR_BUILDER_H*
diff --git a/willow/include/willow/IR/Instruction.h b/willow/include/willow/IR/Instruction.h
index e02e308..34bf584 100644
--- a/willow/include/willow/IR/Instruction.h
+++ b/willow/include/willow/IR/Instruction.h
@@ -83,18 +83,7 @@ private:
std::vector<Value *> operands;
protected:
- void setOperand(std::size_t index, Value *operand) {
- assert(index < operands.size() && "Operand index out of bounds");
- assert(operand && "Operand cannot be null");
- Value *old = operands[index];
- if (old == operand)
- return;
-
- old->delUse(this);
- operands[index] = operand;
- operand->addUse(this);
- }
-
+ void setOperand(std::size_t index, Value *operand);
public:
/// \param op Opcode for this instruction.
/// \param type Type of the result of this instruction.
diff --git a/willow/include/willow/IR/Instructions.h b/willow/include/willow/IR/Instructions.h
index 753ea70..fd48b2c 100644
--- a/willow/include/willow/IR/Instructions.h
+++ b/willow/include/willow/IR/Instructions.h
@@ -11,10 +11,7 @@ namespace willow {
class UnaryInst : public Instruction {
public:
UnaryInst(Opcode op, Type type, Value *value,
- std::optional<Location> loc = std::nullopt)
- : Instruction(op, type, loc) {
- addOperand(value);
- }
+ std::optional<Location> loc = std::nullopt);
Value *getValue() { return getOperand(0); }
const Value *getValue() const { return getOperand(0); }
@@ -24,11 +21,7 @@ public:
class BinaryInst : public Instruction {
public:
BinaryInst(Opcode op, Type type, Value *lhs, Value *rhs,
- std::optional<Location> loc = std::nullopt)
- : Instruction(op, type, loc) {
- addOperand(lhs);
- addOperand(rhs);
- }
+ std::optional<Location> loc = std::nullopt);
Value *getLHS() { return getOperand(0); }
const Value *getLHS() const { return getOperand(0); }
@@ -248,29 +241,14 @@ public:
/// \p true_target. The basic block to jump to if the condition is true
/// \p false_target. The basic block to jump to if the condition is false
BrInst(Type type, Value *condition, BasicBlock *true_target,
- BasicBlock *false_target, std::optional<Location> loc = std::nullopt)
- : Instruction(Opcode::Br, type, loc) {
- addOperand(condition);
- addOperand(true_target);
- addOperand(false_target);
- }
-
- Value *getCondition() { return getOperand(0); }
- const Value *getCondition() const { return getOperand(0); }
-
- BasicBlock *getTrueTarget() {
- return static_cast<BasicBlock *>(getOperand(1));
- }
- const BasicBlock *getTrueTarget() const {
- return static_cast<const BasicBlock *>(getOperand(1));
- }
-
- BasicBlock *getFalseTarget() {
- return static_cast<BasicBlock *>(getOperand(2));
- }
- const BasicBlock *getFalseTarget() const {
- return static_cast<const BasicBlock *>(getOperand(2));
- }
+ BasicBlock *false_target, std::optional<Location> loc = std::nullopt);
+
+ Value *getCondition();
+ const Value *getCondition() const;
+ BasicBlock *getTrueTarget();
+ const BasicBlock *getTrueTarget() const;
+ BasicBlock *getFalseTarget();
+ const BasicBlock *getFalseTarget() const;
};
/// Call another function
@@ -292,12 +270,8 @@ public:
/// Return instruction
class RetInst : public Instruction {
public:
- RetInst(Type voidty, std::optional<Location> loc)
- : Instruction(Opcode::Ret, voidty, loc) {}
- RetInst(Type voidty, Value *val, std::optional<Location> loc = std::nullopt)
- : Instruction(Opcode::Ret, voidty, loc) {
- addOperand(val);
- }
+ RetInst(Type voidty, std::optional<Location> loc);
+ RetInst(Type voidty, Value *val, std::optional<Location> loc = std::nullopt);
};
/// Select a control-flow variant value
@@ -307,13 +281,7 @@ public:
/// \p args List of (predecessor block, value to take) pairs
PhiInst(Type type,
std::initializer_list<std::pair<BasicBlock *, Value *>> args,
- std::optional<Location> loc)
- : Instruction(Opcode::Phi, type, loc) {
- for (auto [bb, v] : args) {
- addOperand(static_cast<Value *>(bb));
- addOperand(v);
- }
- }
+ std::optional<Location> loc = std::nullopt);
auto incomings() {
auto ops = std::span<Value *>{getOperands()};
diff --git a/willow/include/willow/IR/Value.h b/willow/include/willow/IR/Value.h
index e252fa2..dc98373 100644
--- a/willow/include/willow/IR/Value.h
+++ b/willow/include/willow/IR/Value.h
@@ -3,9 +3,7 @@
#include <willow/IR/Types.h>
-#include <cassert>
#include <unordered_map>
-#include <ostream>
namespace willow {
@@ -13,6 +11,8 @@ class Instruction;
class BasicBlock;
class Constant;
+using UseList = std::unordered_map<Instruction *, std::size_t>;
+
enum class ValueKind {
Instruction, ///< the identified result of an instruction
Parameter, ///< the named parameter to a function
@@ -43,27 +43,15 @@ public:
/// Get the instructions that use this value, and the number of times they use
/// it.
- ///
- /// \return map of Instruction* -> num uses
- std::unordered_map<Instruction *, std::size_t> &getUses() { return uses; }
- const std::unordered_map<Instruction *, std::size_t> &getUses() const {
- return uses;
- }
-
- void addUse(Instruction *i) {
- auto [it, inserted] = uses.try_emplace(i, 1);
-
- if (!inserted)
- it->second += 1;
- }
-
- /// Remove a use of the instruction from te use list.
- void delUse(Instruction *instruction) {
- assert(uses.contains(instruction) && "No uses to remove");
- auto it = uses.find(instruction);
- it->second -= 1;
- if (it->second == 0)
- uses.erase(it);
+ UseList &getUses() { return uses; }
+ const UseList &getUses() const { return uses; }
+
+ /// Add the instruction \p i as a user of this value
+ void addUse(Instruction *instruction);
+ /// Remove the instruction \p i as a user of this value
+ void delUse(Instruction *instruction);
+ bool hasUse(Instruction *instruction) const {
+ return uses.contains(instruction);
}
};