/*
* 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.1 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 .
*
* Author: Benjamin Segovia
*/
/**
* \file value.hpp
* \author Benjamin Segovia
*/
#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 {
DEF_FN_ARG = 0,
DEF_FN_PUSHED = 1,
DEF_INSN_DST = 2,
DEF_SPECIAL_REG = 3
};
/*! Build a value from an instruction destination */
explicit ValueDef(const Instruction *insn, uint32_t dstID = 0u) :
type(DEF_INSN_DST)
{
this->data.insn = insn;
this->data.dstID = dstID;
}
/*! Build a value from a function argument */
explicit ValueDef(const FunctionArgument *arg) : type(DEF_FN_ARG) {
this->data.arg = arg;
}
/*! Build a value from a pushed register */
explicit ValueDef(const PushLocation *pushed) : type(DEF_FN_PUSHED) {
this->data.pushed = pushed;
}
/*! Build a value from a special register */
explicit ValueDef(const Register ®) : type(DEF_SPECIAL_REG) {
this->data.regID = uint32_t(reg);
}
/*! 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 {
GBE_ASSERT(type == DEF_INSN_DST);
return data.insn;
}
/*! Get the destination ID (only if this is a instruction value) */
INLINE uint32_t getDstID(void) const {
GBE_ASSERT(type == DEF_INSN_DST);
return data.dstID;
}
/*! Get the function input (only if this is a function argument) */
INLINE const FunctionArgument *getFunctionArgument(void) const {
GBE_ASSERT(type == DEF_FN_ARG);
return data.arg;
}
/*! Get the pushed location */
INLINE const PushLocation *getPushLocation(void) const {
GBE_ASSERT(type == DEF_FN_PUSHED);
return data.pushed;
}
/*! Get the special register */
INLINE Register getSpecialReg(void) const {
GBE_ASSERT(type == DEF_SPECIAL_REG);
return Register(data.regID);
}
/*! Retrieve the register associated to the definition */
INLINE Register getRegister(void) const {
if (type == DEF_SPECIAL_REG)
return Register(data.regID);
else if (type == DEF_FN_ARG)
return data.arg->reg;
else if (type == DEF_FN_PUSHED)
return data.pushed->getRegister();
else
return data.insn->getDst(data.dstID);
}
private:
/*! Instruction or function argument */
union Data {
/*! Instruction destination or ... */
struct {
const Instruction *insn; //getSrc(srcID); }
private:
const Instruction *insn; //!< Instruction where the value is used
uint32_t srcID; //!< Index of the source in the instruction
GBE_CLASS(ValueUse); // Use gbe allocators
};
/*! 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 = use1.getSrcID();
return src0 < src1;
}
/*! All uses of a definition */
typedef set UseSet;
/*! All possible definitions for a use */
typedef set DefSet;
/*! Get the chains (in both directions) for the complete program. This data
* structure is unfortunately way too brutal. Using std::sets all over the
* place just burns a huge amount of memory. There is work to do to decrease
* the memory footprint
*/
class FunctionDAG : public NonCopyable
{
public:
/*! Build the complete DU/UD graphs for the program included in liveness */
FunctionDAG(Liveness &liveness);
/*! Free all the resources */
~FunctionDAG(void);
/*! Get the du-chain for the definition */
const UseSet &getUse(const ValueDef &def) const;
/*! Get the du-chain for the given instruction and destination */
const UseSet &getUse(const Instruction *insn, uint32_t dstID) const;
/*! Get the du-chain for the given function input */
const UseSet &getUse(const FunctionArgument *arg) const;
/*! Get the du-chain for the given pushed location */
const UseSet &getUse(const PushLocation *pushed) const;
/*! Get the du-chain for the given special register */
const UseSet &getUse(const Register ®) const;
/*! Get the ud-chain for the given use */
const DefSet &getDef(const ValueUse &use) const;
/*! Get the ud-chain for the instruction and source */
const DefSet &getDef(const Instruction *insn, uint32_t srcID) const;
/*! Get the pointer to the definition *as stored in the DAG* */
const ValueDef *getDefAddress(const ValueDef &def) const;
/*! Get the pointer to the definition *as stored in the DAG* */
const ValueDef *getDefAddress(const PushLocation *pushed) const;
/*! Get the pointer to the definition *as stored in the DAG* */
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 FunctionArgument *input) const;
/*! Get the pointer to the definition *as stored in the DAG* */
const ValueDef *getDefAddress(const Register ®) const;
/*! Get the pointer to the use *as stored in the DAG* */
const ValueUse *getUseAddress(const Instruction *insn, uint32_t srcID) const;
/*! Get the set of all uses for the register */
const UseSet *getRegUse(const Register ®) const;
/*! Get the set of all definitions for the register */
const DefSet *getRegDef(const Register ®) const;
/*! Get the function we have the graph for */
INLINE const Function &getFunction(void) const { return fn; }
/*! The DefSet for each definition use */
typedef map UDGraph;
/*! The UseSet for each definition */
typedef map DUGraph;
private:
UDGraph udGraph; //!< All the UD chains
DUGraph duGraph; //!< All the DU chains
DefSet *udEmpty; //!< Void use set
UseSet *duEmpty; //!< Void def set
ValueDef *undefined; //!< Undefined value
map useName; //!< Get the ValueUse pointer from the value
map defName; //!< Get the ValueDef pointer from the value
map regUse; //!< All uses of registers
map regDef; //!< All defs of registers
DECL_POOL(ValueDef, valueDefPool); //!< Fast ValueDef allocation
DECL_POOL(ValueUse, valueUsePool); //!< Fast ValueUse allocation
DECL_POOL(DefSet, udChainPool); //!< Fast DefSet allocation
DECL_POOL(UseSet, duChainPool); //!< Fast UseSet allocation
const Function &fn; //!< Function we are referring to
GBE_CLASS(FunctionDAG); // Use internal allocators
};
/*! Pretty print of the function DAG */
std::ostream &operator<< (std::ostream &out, const FunctionDAG &dag);
} /* namespace ir */
} /* namespace gbe */
#endif /* __GBE_IR_VALUE_HPP__ */