ir/register.cpp
ir/register.hpp
ir/function.cpp
- ir/function.hpp)
+ ir/function.hpp
+ ir/value.cpp
+ ir/value.hpp)
if (GBE_COMPILE_UTESTS)
set (GBE_SRC
void Context::input(FunctionInput::Type type, Register reg, uint32_t elementSize) {
GBE_ASSERTM(fn != NULL, "No function currently defined");
GBE_ASSERTM(reg < fn->file.regNum(), "Out-of-bound register");
- const FunctionInput input(type, reg, elementSize);
+ FunctionInput *input = GBE_NEW(FunctionInput, type, reg, elementSize);
fn->inputs.push_back(input);
}
}
// Append the instruction in the stream
- Instruction *insnPtr = fn->newInstruction();
-
- *insnPtr = insn;
+ Instruction *insnPtr = fn->newInstruction(insn);
#if GBE_DEBUG
std::string whyNot;
GBE_ASSERTM(insn.wellFormed(*fn, whyNot), whyNot.c_str());
Function::~Function(void) {
for (auto it = blocks.begin(); it != blocks.end(); ++it)
GBE_DELETE(*it);
+ for (auto it = inputs.begin(); it != inputs.end(); ++it)
+ GBE_DELETE(*it);
}
LabelIndex Function::newLabel(void) {
void Function::computeCFG(void) {
// Clear possible previously computed CFG
- this->apply([this](BasicBlock &bb) {
+ this->foreachBlock([this](BasicBlock &bb) {
bb.successors.clear();
bb.predecessors.clear();
});
// Update it. Do not forget that a branch can also jump to the next block
BasicBlock *jumpToNext = NULL;
- this->apply([this, &jumpToNext](BasicBlock &bb) {
+ this->foreachBlock([this, &jumpToNext](BasicBlock &bb) {
if (jumpToNext) {
jumpToNext->successors.insert(&bb);
bb.predecessors.insert(jumpToNext);
<< plural(fn.blockNum()) << " ##" << std::endl;
for (uint32_t i = 0; i < fn.blockNum(); ++i) {
const BasicBlock &bb = fn.getBlock(i);
- bb.apply([&out, &fn] (const Instruction &insn) {
+ bb.foreach([&out, &fn] (const Instruction &insn) {
out << insn << std::endl;
});
out << std::endl;
this->first = this->last = NULL;
}
BasicBlock::~BasicBlock(void) {
- this->apply([this] (Instruction &insn) {
+ this->foreach([this] (Instruction &insn) {
this->fn.deleteInstruction(&insn);
});
}
}
/*! Apply the given functor on all instructions */
template <typename T>
- INLINE void apply(const T &functor) const {
+ INLINE void foreach(const T &functor) const {
Instruction *curr = first;
while (curr) {
functor(*curr);
return index;
}
/*! Allocate a new instruction (with the growing pool) */
- INLINE Instruction *newInstruction(void) {
- return new (insnPool.allocate()) Instruction();
+ template <typename... Args>
+ INLINE Instruction *newInstruction(Args... args) {
+ return new (insnPool.allocate()) Instruction(args...);
}
/*! Deallocate an instruction (with the growing pool) */
INLINE void deleteInstruction(Instruction *insn) {
}
/*! Get input argument */
INLINE const FunctionInput &getInput(uint32_t ID) const {
- GBE_ASSERT(ID < inputNum());
- return inputs[ID];
+ GBE_ASSERT(ID < inputNum() && inputs[ID] != NULL);
+ return *inputs[ID];
}
/*! Get output register */
INLINE Register getOutput(uint32_t ID) const {
void outImmediate(std::ostream &out, ImmediateIndex index) const;
/*! Apply the given functor on all basic blocks */
template <typename T>
- INLINE void apply(const T &functor) const {
+ INLINE void foreachBlock(const T &functor) const {
for (auto it = blocks.begin(); it != blocks.end(); ++it)
functor(**it);
}
+ /*! Apply the given functor on all instructions */
+ template <typename T>
+ INLINE void foreachInstruction(const T &functor) const {
+ for (auto it = blocks.begin(); it != blocks.end(); ++it)
+ (*it)->foreach(functor);
+ }
+
private:
friend class Context; //!< Can freely modify a function
std::string name; //!< Function name
- vector<FunctionInput> inputs; //!< Input registers of the function
+ vector<FunctionInput*> inputs;//!< Input registers of the function
vector<Register> outputs; //!< Output registers of the function
vector<BasicBlock*> labels; //!< Each label points to a basic block
vector<Immediate> immediates; //!< All immediate values in the function
*
* \author Benjamin Segovia <benjamin.segovia@intel.com>
*/
-#ifndef __GBE_IR_VALUE_HPP__
-#define __GBE_IR_VALUE_HPP__
+#ifndef __GBE_IR_IMMEDIATE_HPP__
+#define __GBE_IR_IMMEDIATE_HPP__
#include "ir/type.hpp"
#include "sys/platform.hpp"
} /* namespace ir */
} /* namespace gbe */
-#endif /* __GBE_IR_VALUE_HPP__ */
+#endif /* __GBE_IR_IMMEDIATE_HPP__ */
Liveness::Liveness(Function &fn) : fn(fn) {
// Initialize UEVar and VarKill for each block
- fn.apply([this](const BasicBlock &bb) { this->initBlock(bb); });
+ fn.foreachBlock([this](const BasicBlock &bb) { this->initBlock(bb); });
// Now with iterative analysis, we compute liveout sets
this->computeLiveOut();
}
GBE_ASSERT(liveness.find(&bb) == liveness.end());
BlockInfo *info = GBE_NEW(BlockInfo, bb);
// Traverse all instructions to handle UEVar and VarKill
- bb.apply([this, info](const Instruction &insn) {
+ bb.foreach([this, info](const Instruction &insn) {
this->initInstruction(*info, insn);
});
liveness[&bb] = info;
static void printBlock(std::ostream &out, const Liveness::BlockInfo &info) {
const BasicBlock &bb = info.bb;
const Function &fn = bb.getParent();
- bb.apply([&out, &info](const Instruction &insn) {
+ bb.foreach([&out, &info](const Instruction &insn) {
printInstruction(out, info, insn);
});
// At the end of block, we also output the variables actually alive at the
out << std::endl << std::endl; // skip a line
// Print liveness in each block
- fn.apply([&out, &liveness] (const BasicBlock &bb) {
+ fn.foreachBlock([&out, &liveness] (const BasicBlock &bb) {
const Liveness::Info &info = liveness.getLiveness();
auto it = info.find(&bb);
GBE_ASSERT(it != info.end());
--- /dev/null
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Benjamin Segovia <benjamin.segovia@intel.com>
+ */
+
+/**
+ * \file value.cpp
+ * \author Benjamin Segovia <benjamin.segovia@intel.com>
+ */
+
+#include "ir/value.hpp"
+#include "ir/liveness.hpp"
+
+namespace gbe {
+namespace ir {
+
+ GraphUseDef::GraphUseDef(const Liveness &liveness) {
+ const Function &fn = liveness.getFunction();
+
+ // First create the chains and insert them in their respective maps
+ fn.foreachInstruction([this](const Instruction &insn) {
+ // sources == value uses
+ const uint32_t srcNum = insn.getSrcNum();
+ for (uint32_t srcID = 0; srcID < srcNum; ++srcID) {
+ ValueUse *valueUse = this->newValueUse(insn, srcID);
+ UDChain *udChain = this->newUDChain();
+ udChain->first = valueUse;
+ udGraph.insert(std::make_pair(*valueUse, udChain));
+ }
+ // destinations == value defs
+ const uint32_t dstNum = insn.getDstNum();
+ for (uint32_t dstID = 0; dstID < dstNum; ++dstID) {
+ ValueDef *valueDef = this->newValueDef(insn, dstID);
+ DUChain *duChain = this->newDUChain();
+ duChain->first = valueDef;
+ duGraph.insert(std::make_pair(*valueDef, duChain));
+ }
+ });
+
+ // Function arguments are also value definitions
+ const uint32_t inputNum = fn.inputNum();
+ for (uint32_t inputID = 0; inputID < inputNum; ++inputID) {
+ const FunctionInput &input = fn.getInput(inputID);
+ ValueDef *valueDef = this->newValueDef(input);
+ DUChain *duChain = this->newDUChain();
+ duChain->first = valueDef;
+ duGraph.insert(std::make_pair(*valueDef, duChain));
+ }
+ }
+
+} /* namespace ir */
+} /* namespace gbe */
+
--- /dev/null
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Benjamin Segovia <benjamin.segovia@intel.com>
+ */
+
+/**
+ * \file value.hpp
+ * \author Benjamin Segovia <benjamin.segovia@intel.com>
+ */
+#ifndef __GBE_IR_VALUE_HPP__
+#define __GBE_IR_VALUE_HPP__
+
+#include "ir/instruction.hpp"
+#include "ir/function.hpp"
+#include "sys/set.hpp"
+#include "sys/map.hpp"
+
+namespace gbe {
+namespace ir {
+
+ // Make UD-Chain and DU-Chain computations faster and easier
+ class Liveness;
+
+ /*! A value definition is a destination of an instruction or a function
+ * argument. Since we support multiple destinations, we also add the
+ * destination ID.
+ */
+ class ValueDef
+ {
+ public:
+ /*! Discriminates the kind of values */
+ enum Type : uint32_t {
+ FUNCTION_INPUT = 0,
+ INSTRUCTION_DST = 1
+ };
+ /*! Build a value from an instruction destination */
+ ValueDef(Instruction &insn, uint32_t dstID = 0u) : type(INSTRUCTION_DST) {
+ this->data.insn = &insn;
+ this->data.dstID = dstID;
+ }
+ /*! Build a value from a function argument */
+ ValueDef(FunctionInput &input) : type(FUNCTION_INPUT) {
+ this->data.input = &input;
+ }
+ /*! Get the type of the value */
+ INLINE Type getType(void) const { return type; }
+ /*! Get the instruction (only if this is a instruction value) */
+ INLINE Instruction *getInstruction(void) const {
+ GBE_ASSERT(type == INSTRUCTION_DST);
+ return data.insn;
+ }
+ /*! Get the destination ID (only if this is a instruction value) */
+ INLINE uint32_t getDstID(void) const {
+ GBE_ASSERT(type == INSTRUCTION_DST);
+ return data.dstID;
+ }
+ /*! Get the function input (only if this is a function argument) */
+ INLINE FunctionInput *getFunctionInput(void) const {
+ GBE_ASSERT(type == FUNCTION_INPUT);
+ return data.input;
+ }
+
+ private:
+ /*! Instruction or function argument */
+ union Data {
+ /*! Instruction destination or ... */
+ struct {
+ Instruction *insn; //<! Instruction itself
+ uint32_t dstID; //<! Which destination we take into account
+ };
+ /*! ... function argument */
+ FunctionInput *input;
+ } data;
+ /*!< Function argument or instruction dst? */
+ Type type;
+ };
+
+ /*! Compare two value definitions (used in maps) */
+ INLINE bool operator < (const ValueDef &def0, const ValueDef &def1) {
+ const ValueDef::Type type0 = def0.getType();
+ const ValueDef::Type type1 = def1.getType();
+ if (type0 != type1) return uint32_t(type0) < uint32_t(type1);
+ if (type0 == ValueDef::FUNCTION_INPUT) {
+ const FunctionInput *in0 = def0.getFunctionInput();
+ const FunctionInput *in1 = def1.getFunctionInput();
+ return uintptr_t(in0) < uintptr_t(in1);
+ } else {
+ const Instruction *insn0 = def0.getInstruction();
+ const Instruction *insn1 = def1.getInstruction();
+ if (insn0 != insn1) return uintptr_t(insn0) < uintptr_t(insn1);
+ const uint32_t dst0 = def0.getDstID();
+ const uint32_t dst1 = def0.getDstID();
+ return dst0 < dst1;
+ }
+ }
+
+ /*! A value use describes a instruction source. This is the place where a
+ * value is used
+ */
+ class ValueUse
+ {
+ public:
+ /*! Build a value use */
+ ValueUse(const Instruction &insn, uint32_t srcID = 0u) :
+ insn(&insn), srcID(srcID) {}
+ /*! Get the instruction of the use */
+ const Instruction *getInstruction(void) const { return insn; }
+ /*! Get the source index for this use */
+ uint32_t getSrcID(void) const { return srcID; }
+ private:
+ const Instruction *insn; //!< Instruction where the value is used
+ uint32_t srcID; //!< Index of the source in the instruction
+ };
+
+ /*! Compare two value uses (used in maps) */
+ INLINE bool operator < (const ValueUse &use0, const ValueUse &use1) {
+ const Instruction *insn0 = use0.getInstruction();
+ const Instruction *insn1 = use1.getInstruction();
+ if (insn0 != insn1) return uintptr_t(insn0) < uintptr_t(insn1);
+ const uint32_t src0 = use0.getSrcID();
+ const uint32_t src1 = use0.getSrcID();
+ return src0 < src1;
+ }
+
+ /*! All uses of a definition */
+ typedef std::pair<ValueDef*, set<ValueUse*>> DUChain;
+ /*! All possible definitions for a use */
+ typedef std::pair<ValueUse*, set<ValueDef*>> UDChain;
+
+ /*! Get the chains (in both directions) for the complete program */
+ class GraphUseDef
+ {
+ public:
+ /*! Build the complete DU/UD graphs for the program included in liveness */
+ GraphUseDef(const Liveness &liveness);
+ /*! The UDChain for each definition use */
+ typedef map<ValueUse, UDChain*> UDGraph;
+ /*! The DUChain for each definition */
+ typedef map<ValueDef, DUChain*> DUGraph;
+ private:
+ UDGraph udGraph; //!< All the UD chains
+ DUGraph duGraph; //!< All the DU chains
+ GrowingPool<ValueUse> valueUsePool; //!< Allocate the value uses
+ GrowingPool<ValueDef> valueDefPool; //!< Allocate the value defs
+ GrowingPool<UDChain> udChainPool; //!< Allocate all the ud-chains
+ GrowingPool<DUChain> duChainPool; //!< Allocate all the du-chains
+#define DECL_ALLOCATE_DEALLOCATE(TYPE, POOL) \
+ template <typename... Args> \
+ INLINE TYPE *new##TYPE(Args... args) { \
+ return new (POOL.allocate()) TYPE(args...); \
+ } \
+ INLINE void delete##TYPE(TYPE *ptr) { POOL.deallocate(ptr); }
+ DECL_ALLOCATE_DEALLOCATE(ValueDef, valueDefPool)
+ DECL_ALLOCATE_DEALLOCATE(ValueUse, valueUsePool)
+ DECL_ALLOCATE_DEALLOCATE(UDChain, udChainPool)
+ DECL_ALLOCATE_DEALLOCATE(DUChain, duChainPool)
+#undef DECL_ALLOCATE_DEALLOCATE
+ GBE_CLASS(GraphUseDef);
+ };
+
+} /* namespace ir */
+} /* namespace gbe */
+
+#endif /* __GBE_IR_VALUE_HPP__ */
+