// Liveness is computed per function
class Function;
+ /*! To choose the iteration direction, we either look at predecessors or
+ * successors
+ */
+ enum DataFlowDirection {
+ DF_PRED = 0,
+ DF_SUCC = 1
+ };
+
/*! Compute liveness of each register */
class Liveness : public NonCopyable
{
/*! Gives for each block the variables alive at entry / exit */
typedef map<const BasicBlock*, BlockInfo*> Info;
/*! Return the complete liveness info */
- INLINE const Info &getLiveness(void) const { return liveness; }
+ INLINE const Info &getLivenessInfo(void) const { return liveness; }
/*! Return the complete block info */
INLINE const BlockInfo &getBlockInfo(const BasicBlock &bb) const {
auto it = liveness.find(&bb);
}
/*! Return the function the liveness was computed on */
INLINE const Function &getFunction(void) const { return fn; }
- private:
- /*! Store the liveness of all blocks */
- Info liveness;
- /*! Compute the liveness for this function */
- Function &fn;
- /*! Initialize UEVar and VarKill per block */
- void initBlock(const BasicBlock &bb);
- /*! Initialize UEVar and VarKill per instruction */
- void initInstruction(BlockInfo &info, const Instruction &insn);
- /*! Now really compute LiveOut based on UEVar and VarKill */
- void computeLiveOut(void);
- /*! Actually do something for each successor of *all* blocks */
- template <typename T>
- void forEachSuccessor(const T &functor) {
+ /*! Actually do something for each successor / predecessor of *all* blocks */
+ template <DataFlowDirection dir, typename T>
+ void foreach(const T &functor) {
// Iterate on all blocks
for (auto it = liveness.begin(); it != liveness.end(); ++it) {
BlockInfo &info = *it->second;
const BasicBlock &bb = info.bb;
- const BlockSet set = bb.getSuccessorSet();
+ const BlockSet *set = NULL;
+ if (dir == DF_SUCC)
+ set = &bb.getSuccessorSet();
+ else
+ set = &bb.getPredecessorSet();
// Iterate over all successors
- for (auto other = set.begin(); other != set.end(); ++other) {
+ for (auto other = set->begin(); other != set->end(); ++other) {
auto otherInfo = liveness.find(*other);
GBE_ASSERT(otherInfo != liveness.end() && otherInfo->second != NULL);
functor(info, *otherInfo->second);
}
}
}
+ private:
+ /*! Store the liveness of all blocks */
+ Info liveness;
+ /*! Compute the liveness for this function */
+ Function &fn;
+ /*! Initialize UEVar and VarKill per block */
+ void initBlock(const BasicBlock &bb);
+ /*! Initialize UEVar and VarKill per instruction */
+ void initInstruction(BlockInfo &info, const Instruction &insn);
+ /*! Now really compute LiveOut based on UEVar and VarKill */
+ void computeLiveOut(void);
};
/*! Output a nice ASCII reprensation of the liveness */
class LiveOutSet
{
public:
- LiveOutSet(const Liveness &liveness, const FunctionDAG &dag);
+ LiveOutSet(Liveness &liveness, const FunctionDAG &dag);
~LiveOutSet(void);
/*! One set per register */
typedef set<const ValueDef*> RegDefSet;
typedef map<Register, RegDefSet*> BlockDefMap;
/*! All the block definitions map in the functions */
typedef map<const BasicBlock*, BlockDefMap*> FunctionDefMap;
- FunctionDefMap defMap; //!< All per-block data
- const Liveness &liveness; //!< Contains LiveOut information
- const FunctionDAG &dag; //!< Structure we are building
+ /*! Performs the double look-up to get the set of defs per register */
+ RegDefSet &getDefSet(const BasicBlock *bb, const Register ®) {
+ auto bbIt = defMap.find(bb);
+ GBE_ASSERT(bbIt != defMap.end());
+ auto defIt = bbIt->second->find(reg);
+ GBE_ASSERT(defIt != bbIt->second->end() && defIt->second != NULL);
+ return *defIt->second;
+ }
+ /*! Build a UD-chain as the union of the predecessor chains */
+ void fillUDChain(UDChain &udChain, const BasicBlock &bb, const Register ®);
+ /*! Fast per register definition set allocation */
DECL_POOL(RegDefSet, regDefSetPool);
+ /*! Fast register sets allocation */
DECL_POOL(BlockDefMap, blockDefMapPool);
+ FunctionDefMap defMap; //!< All per-block data
+ Liveness &liveness; //!< Contains LiveOut information
+ const FunctionDAG &dag; //!< Structure we are building
+ private:
+ /*! Initialize liveOut with the instruction destination values */
+ void initializeInstructionDst(void);
+ /*! Initialize liveOut with the function argument */
+ void initializeFunctionInput(void);
+ /*! Iterate to completely transfer the liveness and get the def sets */
+ void iterateLiveOut(void);
};
- LiveOutSet::LiveOutSet(const Liveness &liveness, const FunctionDAG &dag) :
+ LiveOutSet::LiveOutSet(Liveness &liveness, const FunctionDAG &dag) :
liveness(liveness), dag(dag)
{
+ this->initializeInstructionDst();
+ this->initializeFunctionInput();
+ this->iterateLiveOut();
+ }
+
+ void LiveOutSet::initializeInstructionDst(void) {
const Function &fn = liveness.getFunction();
- // Iterate over each block
+ // Iterate over each block and initialize the liveOut data
fn.foreachBlock([&](const BasicBlock &bb) {
GBE_ASSERT(defMap.find(&bb) == defMap.end());
for (uint32_t dstID = 0; dstID < dstNum; ++dstID) {
const Register reg = insn.getDstIndex(fn, dstID);
// We only take the most recent definition
- if (defined.contains(reg) == false) continue;
+ if (defined.contains(reg) == true) continue;
// Not in LiveOut, so does not matter
if (info.inLiveOut(reg) == false) continue;
+ defined.insert(reg);
// Insert the outgoing definition for this register
auto regDefSet = blockDefMap->find(reg);
- const ValueDef *def = this->dag.getDefAddress(insn, dstID);
+ const ValueDef *def = this->dag.getDefAddress(&insn, dstID);
GBE_ASSERT(regDefSet != blockDefMap->end() && def != NULL);
+ // May be NULL if there is no definition
regDefSet->second->insert(def);
}
});
});
+
+ // The first block must also transfer the function arguments
+ const BasicBlock &top = fn.getBlock(0);
+ auto info = this->liveness.getBlockInfo(top);
+ auto blockDefMapIt = defMap.find(&top);
+ GBE_ASSERT(blockDefMapIt != defMap.end());
+ auto blockDefMap = blockDefMapIt->second;
+ const uint32_t inputNum = fn.inputNum();
+ for (uint32_t inputID = 0; inputID < inputNum; ++inputID) {
+ const FunctionInput &input = fn.getInput(inputID);
+ const Register reg = input.reg;
+ // Do not transfer dead values
+ if (info.inLiveOut(reg) == false) continue;
+ // If we overwrite it, do not transfer the initial value
+ if (info.inVarKill(reg) == false) continue;
+ const ValueDef *def = this->dag.getDefAddress(&input);
+ GBE_ASSERT(blockDefMap->contains(reg) == false);
+ auto regDefSet = this->newRegDefSet();
+ regDefSet->insert(def);
+ blockDefMap->insert(std::make_pair(reg, regDefSet));
+ }
+ }
+
+ void LiveOutSet::initializeFunctionInput(void) {
+ const Function &fn = liveness.getFunction();
+ const uint32_t inputNum = fn.inputNum();
+
+ // The first block must also transfer the function arguments
+ const BasicBlock &top = fn.getBlock(0);
+ const Liveness::BlockInfo &info = this->liveness.getBlockInfo(top);
+ GBE_ASSERT(defMap.contains(&top) == true);
+ auto blockDefMap = defMap.find(&top)->second;
+
+ // Insert all the values that are not overwritten in the block and alive at
+ // the end of it
+ for (uint32_t inputID = 0; inputID < inputNum; ++inputID) {
+ const FunctionInput &input = fn.getInput(inputID);
+ const Register reg = input.reg;
+ // Do not transfer dead values
+ if (info.inLiveOut(reg) == false) continue;
+ // If we overwrite it, do not transfer the initial value
+ if (info.inVarKill(reg) == false) continue;
+ const ValueDef *def = this->dag.getDefAddress(&input);
+ GBE_ASSERT(blockDefMap->contains(reg) == false);
+ auto regDefSet = this->newRegDefSet();
+ regDefSet->insert(def);
+ blockDefMap->insert(std::make_pair(reg, regDefSet));
+ }
+ }
+
+ void LiveOutSet::iterateLiveOut(void) {
+ bool changed = true;
+
+ while (changed) {
+ changed = false;
+
+ // Compute the union of the current liveout definitions with the previous
+ // ones. Do not take into account the killed values though
+ liveness.foreach<DF_PRED>([&](Liveness::BlockInfo &curr,
+ const Liveness::BlockInfo &pred)
+ {
+ const BasicBlock &bb = curr.bb;
+ const BasicBlock &pbb = pred.bb;
+ for (auto it = curr.liveOut.begin(); it != curr.liveOut.end(); ++it) {
+ const Register reg = *it;
+ if (pred.inLiveOut(reg) == false) continue;
+ if (curr.inVarKill(reg) == true) continue;
+ RegDefSet &currSet = this->getDefSet(&bb, reg);
+ RegDefSet &predSet = this->getDefSet(&pbb, reg);
+
+ // Transfer the values
+ for (auto it = predSet.begin(); it != predSet.end(); ++it) {
+ if (currSet.contains(*it)) continue;
+ changed = true;
+ currSet.insert(*it);
+ }
+ }
+ });
+ }
}
LiveOutSet::~LiveOutSet(void) {
}
}
- FunctionDAG::FunctionDAG(const Liveness &liveness) {
+ FunctionDAG::FunctionDAG(Liveness &liveness) {
const Function &fn = liveness.getFunction();
- LiveOutSet p(liveness, *this);
+
// We first start with empty chains
- udEmpty = this->newUDChain(); udEmpty->second = NULL;
- duEmpty = this->newDUChain(); duEmpty->second = NULL;
+ udEmpty = this->newUDChain();
+ duEmpty = this->newDUChain();
// First create the chains and insert them in their respective maps
fn.foreachInstruction([this, udEmpty, duEmpty](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);
+ ValueUse *valueUse = this->newValueUse(&insn, srcID);
+ useName.insert(std::make_pair(*valueUse, valueUse));
udGraph.insert(std::make_pair(*valueUse, udEmpty));
}
// destinations == value defs
const uint32_t dstNum = insn.getDstNum();
for (uint32_t dstID = 0; dstID < dstNum; ++dstID) {
- ValueDef *valueDef = this->newValueDef(insn, dstID);
+ ValueDef *valueDef = this->newValueDef(&insn, dstID);
+ defName.insert(std::make_pair(*valueDef, valueDef));
duGraph.insert(std::make_pair(*valueDef, duEmpty));
}
});
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);
+ ValueDef *valueDef = this->newValueDef(&input);
+ defName.insert(std::make_pair(*valueDef, valueDef));
duGraph.insert(std::make_pair(*valueDef, duEmpty));
}
+
+ // We create the liveOutSet to help us transfer the definitions
+ const LiveOutSet liveOutSet(liveness, *this);
}
/*! Helper to deallocate objects */
set<void*> destroyed;
// Release the empty ud-chains and du-chains
- PTR_RELEASE(ValueUse, udEmpty->second);
- PTR_RELEASE(ValueDef, duEmpty->second);
PTR_RELEASE(UDChain, udEmpty);
PTR_RELEASE(DUChain, duEmpty);
// We free all the ud-chains
for (auto it = udGraph.begin(); it != udGraph.end(); ++it) {
- auto udChain = it->second;
- auto defs = udChain->first;
- for (auto def = defs.begin(); def != defs.end(); ++def)
+ auto defs = it->second;
+ for (auto def = defs->begin(); def != defs->end(); ++def)
PTR_RELEASE(ValueDef, *def);
- PTR_RELEASE(ValueUse, udChain->second);
- PTR_RELEASE(UDChain, udChain);
+ PTR_RELEASE(UDChain, defs);
}
// We free all the du-chains
for (auto it = duGraph.begin(); it != duGraph.end(); ++it) {
- auto duChain = it->second;
- auto uses = duChain->first;
- for (auto use = uses.begin(); use != uses.end(); ++use)
+ auto uses = it->second;
+ for (auto use = uses->begin(); use != uses->end(); ++use)
PTR_RELEASE(ValueUse, *use);
- PTR_RELEASE(ValueDef, duChain->second);
- PTR_RELEASE(DUChain, duChain);
+ PTR_RELEASE(DUChain, uses);
}
}
#undef PTR_RELEASE
- const DUChain &FunctionDAG::getDUChain(const Instruction &insn, uint32_t dstID) const {
+ const DUChain &FunctionDAG::getUse(const Instruction *insn, uint32_t dstID) const {
const ValueDef def(insn, dstID);
auto it = duGraph.find(def);
GBE_ASSERT(it != duGraph.end());
return *it->second;
}
- const DUChain &FunctionDAG::getDUChain(const FunctionInput &input) const {
+ const DUChain &FunctionDAG::getUse(const FunctionInput *input) const {
const ValueDef def(input);
auto it = duGraph.find(def);
GBE_ASSERT(it != duGraph.end());
return *it->second;
}
- const UDChain &FunctionDAG::getUDChain(const Instruction &insn, uint32_t srcID) const {
+ const UDChain &FunctionDAG::getDef(const Instruction *insn, uint32_t srcID) const {
const ValueUse use(insn, srcID);
auto it = udGraph.find(use);
GBE_ASSERT(it != udGraph.end());
return *it->second;
}
- const ValueUseSet &FunctionDAG::getUse(const Instruction &insn, uint32_t dstID) const {
- const DUChain &chain = this->getDUChain(insn, dstID);
- return chain.first;
- }
- const ValueUseSet &FunctionDAG::getUse(const FunctionInput &input) const {
- const DUChain &chain = this->getDUChain(input);
- return chain.first;
- }
- const ValueDefSet &FunctionDAG::getDef(const Instruction &insn, uint32_t srcID) const {
- const UDChain &chain = this->getUDChain(insn, srcID);
- return chain.first;
- }
- const ValueDef *FunctionDAG::getDefAddress(const Instruction &insn, uint32_t dstID) const {
- const DUChain &chain = this->getDUChain(insn, dstID);
- return chain.second;
+ const ValueDef *FunctionDAG::getDefAddress(const Instruction *insn, uint32_t dstID) const {
+ const ValueDef def(insn, dstID);
+ auto it = defName.find(def);
+ GBE_ASSERT(it != defName.end() && it->second != NULL);
+ return it->second;
}
- const ValueDef *FunctionDAG::getDefAddress(const FunctionInput &input) const {
- const DUChain &chain = this->getDUChain(input);
- return chain.second;
+ const ValueDef *FunctionDAG::getDefAddress(const FunctionInput *input) const {
+ const ValueDef def(input);
+ auto it = defName.find(def);
+ GBE_ASSERT(it != defName.end() && it->second != NULL);
+ return it->second;
}
- const ValueUse *FunctionDAG::getUseAddress(const Instruction &insn, uint32_t srcID) const {
- const UDChain &chain = this->getUDChain(insn, srcID);
- return chain.second;
+ const ValueUse *FunctionDAG::getUseAddress(const Instruction *insn, uint32_t srcID) const {
+ const ValueUse use(insn, srcID);
+ auto it = useName.find(use);
+ GBE_ASSERT(it != useName.end() && it->second != NULL);
+ return it->second;
}
} /* namespace ir */
} /* namespace gbe */
INSTRUCTION_DST = 1
};
/*! Build a value from an instruction destination */
- ValueDef(const Instruction &insn, uint32_t dstID = 0u) :
+ ValueDef(const Instruction *insn, uint32_t dstID = 0u) :
type(INSTRUCTION_DST)
{
- this->data.insn = &insn;
+ this->data.insn = insn;
this->data.dstID = dstID;
}
/*! Build a value from a function argument */
- ValueDef(const FunctionInput &input) : type(FUNCTION_INPUT) {
- this->data.input = &input;
+ ValueDef(const 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 const Instruction &getInstruction(void) const {
+ INLINE const Instruction *getInstruction(void) const {
GBE_ASSERT(type == INSTRUCTION_DST);
- return *data.insn;
+ return data.insn;
}
/*! Get the destination ID (only if this is a instruction value) */
INLINE uint32_t getDstID(void) const {
return data.dstID;
}
/*! Get the function input (only if this is a function argument) */
- INLINE const FunctionInput &getFunctionInput(void) const {
+ INLINE const FunctionInput *getFunctionInput(void) const {
GBE_ASSERT(type == FUNCTION_INPUT);
- return *data.input;
+ return data.input;
}
private:
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();
+ 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();
+ 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 = def1.getDstID();
{
public:
/*! Build a value use */
- ValueUse(const Instruction &insn, uint32_t srcID = 0u) :
- insn(&insn), srcID(srcID) {}
+ 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; }
+ const Instruction *getInstruction(void) const { return insn; }
/*! Get the source index for this use */
uint32_t getSrcID(void) const { return srcID; }
private:
/*! 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();
+ 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 = use1.getSrcID();
}
/*! All uses of a definition */
- typedef set<ValueUse*> ValueUseSet;
- typedef std::pair<ValueUseSet, ValueDef*> DUChain;
+ typedef set<ValueUse*> DUChain;
/*! All possible definitions for a use */
- typedef set<ValueDef*> ValueDefSet;
- typedef std::pair<ValueDefSet, ValueUse*> UDChain;
+ typedef set<ValueDef*> UDChain;
/*! Get the chains (in both directions) for the complete program */
class FunctionDAG
{
public:
/*! Build the complete DU/UD graphs for the program included in liveness */
- FunctionDAG(const Liveness &liveness);
+ FunctionDAG(Liveness &liveness);
/*! Free all the resources */
~FunctionDAG(void);
/*! Get the du-chain for the given instruction and destination */
- const DUChain &getDUChain(const Instruction &insn, uint32_t dstID) const;
+ const DUChain &getUse(const Instruction *insn, uint32_t dstID) const;
/*! Get the du-chain for the given function input */
- const DUChain &getDUChain(const FunctionInput &input) const;
+ const DUChain &getUse(const FunctionInput *input) const;
/*! Get the ud-chain for the instruction and source */
- const UDChain &getUDChain(const Instruction &insn, uint32_t srcID) const;
- /*! Get the use set for the given definition */
- const ValueUseSet &getUse(const Instruction &insn, uint32_t dstID) const;
- /*! Get the use set for the function argument */
- const ValueUseSet &getUse(const FunctionInput &input) const;
- /*! Get the definition set for the given source */
- const ValueDefSet &getDef(const Instruction &insn, uint32_t srcID) const;
+ const UDChain &getDef(const Instruction *insn, uint32_t srcID) const;
/*! Get the pointer to the definition *as stored in the DAG* */
- const ValueDef *getDefAddress(const Instruction &insn, uint32_t dstID) const;
+ const ValueDef *getDefAddress(const Instruction *insn, uint32_t dstID) const;
/*! Get the pointer to the definition *as stored in the DAG* */
- const ValueDef *getDefAddress(const FunctionInput &input) const;
+ const ValueDef *getDefAddress(const FunctionInput *input) const;
/*! Get the pointer to the use *as stored in the DAG* */
- const ValueUse *getUseAddress(const Instruction &insn, uint32_t srcID) const;
+ const ValueUse *getUseAddress(const Instruction *insn, uint32_t srcID) const;
/*! The UDChain for each definition use */
typedef map<ValueUse, UDChain*> UDGraph;
/*! The DUChain for each definition */
private:
UDGraph udGraph; //!< All the UD chains
DUGraph duGraph; //!< All the DU chains
- UDChain *udEmpty; //!< For all empty ud chains
- DUChain *duEmpty; //!< For all empty du chains
+ UDChain *udEmpty; //!< Void use set
+ DUChain *duEmpty; //!< Void def set
+ map<ValueUse, ValueUse*> useName; //!< Get the ValueUse pointer from the value
+ map<ValueDef, ValueDef*> defName; //!< Get the ValueDef pointer from the value
DECL_POOL(ValueDef, valueDefPool); //!< Fast ValueDef allocation
DECL_POOL(ValueUse, valueUsePool); //!< Fast ValueUse allocation
DECL_POOL(UDChain, udChainPool); //!< Fast UDChain allocation