sys/platform.hpp
ir/context.cpp
ir/context.hpp
+ ir/type.cpp
+ ir/type.hpp
ir/unit.cpp
ir/unit.hpp
ir/constant.cpp
ir/function.cpp
ir/function.hpp)
- if (GBE_COMPILE_UTEST)
+ if (GBE_COMPILE_UTESTS)
set (GBE_SRC
${GBE_SRC}
utest/utest_test_utest.cpp
utest/utest_context.cpp
utest/utest.cpp
utest/utest.hpp)
- endif (GBE_COMPILE_UTEST)
+ endif (GBE_COMPILE_UTESTS)
endif (GBE_USE_BLOB)
include_directories (.)
add_library (gbe SHARED ${GBE_SRC})
-if (GBE_COMPILE_UTEST)
+if (GBE_COMPILE_UTESTS)
set (TESTER_SRC utest/tester.cpp)
add_executable (tester utest/tester.cpp)
target_link_libraries (tester gbe)
-endif (GBE_COMPILE_UTEST)
+endif (GBE_COMPILE_UTESTS)
#include "sys/condition.cpp"
#include "sys/platform.cpp"
#include "ir/context.cpp"
+#include "ir/type.cpp"
#include "ir/unit.cpp"
#include "ir/constant.cpp"
#include "ir/instruction.cpp"
#if GBE_COMPILE_UTESTS
#include "utest/utest.cpp"
#include "utest/utest_test_utest.cpp"
+#include "utest/utest_context.cpp"
#endif /* GBE_COMPILE_UTESTS */
void Context::input(Register reg) {
GBE_ASSERTM(fn != NULL, "No function currently defined");
GBE_ASSERTM(reg < fn->file.regNum(), "Out-of-bound register");
- fn->input.push_back(reg);
+ fn->inputs.push_back(reg);
}
void Context::output(Register reg) {
GBE_ASSERTM(fn != NULL, "No function currently defined");
GBE_ASSERTM(reg < fn->file.regNum(), "Out-of-bound register");
- fn->output.push_back(reg);
+ fn->outputs.push_back(reg);
}
void Context::startBlock(void) {
/**
* \file function.cpp
- *
* \author Benjamin Segovia <benjamin.segovia@intel.com>
*/
#include "ir/function.hpp"
+#include "sys/string.hpp"
namespace gbe {
namespace ir {
- Function::Function(void) {}
+ Function::Function(const std::string &name) : name(name) {}
+
Function::~Function(void) {
for (auto it = blocks.begin(); it != blocks.end(); ++it)
GBE_DELETE(*it);
}
+
LabelIndex Function::newLabel(void) {
GBE_ASSERTM(labels.size() < 0xffff,
"Too many labels are defined (65536 only are supported)");
labels.push_back(NULL);
return index;
}
+
+ std::ostream &Function::outImmediate(std::ostream &out, ImmediateIndex index) const {
+ GBE_ASSERT(index < immediates.size());
+ const Immediate imm = immediates[index];
+ switch (imm.type) {
+ case TYPE_BOOL: return out << !!imm.data.u8;
+ case TYPE_S8: return out << imm.data.s8;
+ case TYPE_U8: return out << imm.data.u8;
+ case TYPE_S16: return out << imm.data.s16;
+ case TYPE_U16: return out << imm.data.u16;
+ case TYPE_S32: return out << imm.data.s32;
+ case TYPE_U32: return out << imm.data.u32;
+ case TYPE_S64: return out << imm.data.s64;
+ case TYPE_U64: return out << imm.data.u64;
+ case TYPE_HALF: return out << "half(" << imm.data.u16 << ")";
+ case TYPE_FLOAT: return out << imm.data.f32;
+ case TYPE_DOUBLE: return out << imm.data.f64;
+ };
+ return out;
+ }
+
+ std::ostream &operator<< (std::ostream &out, const Function &fn)
+ {
+ out << ".decl_function " << fn.getName() << std::endl << std::endl;
+ out << fn.getRegisterFile();
+ out << "## " << fn.inputNum() << " input register"
+ << plural(fn.inputNum()) << " ##" << std::endl;
+ for (uint32_t i = 0; i < fn.inputNum(); ++i)
+ out << "decl_input %" << fn.getInput(i) << std::endl;
+ out << "## " << fn.outputNum() << " output register"
+ << plural(fn.outputNum()) << " ##" << std::endl;
+ for (uint32_t i = 0; i < fn.outputNum(); ++i)
+ out << "decl_output %" << fn.getOutput(i) << std::endl;
+ out << "## " << fn.blockNum() << " block"
+ << plural(fn.blockNum()) << " ##" << std::endl;
+ for (uint32_t i = 0; i < fn.blockNum(); ++i) {
+ const BasicBlock &bb = fn.getBlock(i);
+ bb.map([&out, &fn] (const Instruction &insn) {
+ out << insn.proxy(fn) << std::endl;
+ });
+ out << std::endl;
+ }
+ out << ".end_function" << std::endl;
+ return out;
+ }
+
BasicBlock::BasicBlock(Function &fn) : fn(fn) {}
BasicBlock::~BasicBlock(void) {
for (auto it = instructions.begin(); it != instructions.end(); ++it)
#include "sys/list.hpp"
#include "sys/alloc.hpp"
+#include <ostream>
+
namespace gbe {
namespace ir {
/*! Releases all the instructions */
~BasicBlock(void);
/*! Append a new instruction in the stream */
- void append(Instruction &insn) {
- instructions.push_back(&insn);
- }
+ void append(Instruction &insn) { instructions.push_back(&insn); }
/*! Return the number of instruction in the block */
INLINE uint32_t insnNum(void) { return instructions.size(); }
+ /*! Apply the given functor on all instructions */
+ template <typename T>
+ INLINE void map(const T &functor) const {
+ for (auto it = instructions.begin(); it != instructions.end(); ++it)
+ functor(**it);
+ }
private:
friend class Function; //!< Owns the basic blocks
list<Instruction*> instructions; //!< Sequence of instructions in the block
{
public:
/*! Create an empty function */
- Function(void);
+ Function(const std::string &name);
/*! Release everything *including* the basic block pointers */
~Function(void);
+ /*! Get the function name */
+ const std::string &getName(void) const { return name; }
/*! Extract the register from the register file */
INLINE RegisterData getRegisterData(Register ID) const { return file.get(ID); }
/*! Get the register index from the tuple vector */
INLINE Register getRegister(Tuple ID, uint32_t which) const {
return file.get(ID, which);
}
+ /*! Get the register file */
+ INLINE const RegisterFile &getRegisterFile(void) const { return file; }
/*! Get the given value ie immediate from the function */
INLINE Immediate getImmediate(uint32_t ID) const {
- GBE_ASSERTM(ID < immediates.size(), "Out-of-bound immediate");
+ GBE_ASSERT(ID < immediateNum());
return immediates[ID];
}
/*! Allocate a new instruction (with the growing pool) */
INLINE void deleteInstruction(Instruction *insn) {
insnPool.deallocate(insn);
}
+ /*! Get input register */
+ INLINE Register getInput(uint32_t ID) const {
+ GBE_ASSERT(ID < inputNum());
+ return inputs[ID];
+ }
+ /*! Get output register */
+ INLINE Register getOutput(uint32_t ID) const {
+ GBE_ASSERT(ID < outputNum());
+ return outputs[ID];
+ }
+ /*! Get block ID */
+ INLINE const BasicBlock &getBlock(uint32_t ID) const {
+ GBE_ASSERT(ID < blockNum());
+ GBE_ASSERT(blocks[ID] != NULL);
+ return *blocks[ID];
+ }
/*! Create a new label (still not bound to a basic block) */
LabelIndex newLabel(void);
/*! Number of registers in the register file */
INLINE uint32_t labelNum(void) const { return labels.size(); }
/*! Number of immediate values in the function */
INLINE uint32_t immediateNum(void) const { return immediates.size(); }
-
+ /*! Get the number of input register */
+ INLINE uint32_t inputNum(void) const { return inputs.size(); }
+ /*! Get the number of output register */
+ INLINE uint32_t outputNum(void) const { return outputs.size(); }
+ /*! Number of blocks in the function */
+ INLINE uint32_t blockNum(void) const { return blocks.size(); }
+ /*! Output an immediate value in a stream */
+ std::ostream &outImmediate(std::ostream &out, ImmediateIndex index) const;
private:
friend class Context; //!< Can freely modify a function
- vector<Register> input; //!< Input registers of the function
- vector<Register> output; //!< Output registers of the function
+ std::string name; //!< Function name
+ vector<Register> 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
vector<BasicBlock*> blocks; //!< All chained basic blocks
GBE_CLASS(Function);
};
+ /*! Output the function string in the given stream */
+ std::ostream &operator<< (std::ostream &out, const Function &fn);
+
} /* namespace ir */
} /* namespace gbe */
Instruction convert(void) const {
return Instruction(reinterpret_cast<const char *>(&this->opcode));
}
+ /*! Output the opcode in the given stream */
+ INLINE void outOpcode(std::ostream &out) const {
+ switch (opcode) {
+#define DECL_INSN(OPCODE, CLASS) case OP_##OPCODE: out << #OPCODE; break;
+#include "instruction.hxx"
+#undef DECL_INSN
+ };
+ }
+
/*! Instruction opcode */
Opcode opcode;
};
}
INLINE Type getType(void) const { return this->type; }
INLINE bool wellFormed(const Function &fn, std::string &whyNot) const;
+ INLINE void out(std::ostream &out, const Function &fn) const;
Type type; //!< Type of the instruction
Register dst; //!< Index of the register in the register file
Register src[srcNum]; //!< Indices of the sources
}
INLINE Type getType(void) const { return this->type; }
INLINE bool wellFormed(const Function &fn, std::string &whyNot) const;
+ INLINE void out(std::ostream &out, const Function &fn) const;
Type type; //!< Type of the instruction
Register dst; //!< Dst is the register index
Tuple src; //!< 3 sources do not fit in 8 bytes -> use a tuple
return src;
}
INLINE bool wellFormed(const Function &fn, std::string &whyNot) const;
+ INLINE void out(std::ostream &out, const Function &fn) const;
Register dst; //!< Converted value
Register src; //!< To convert
Type dstType; //!< Type to convert to
}
INLINE bool isPredicated(void) const { return hasPredicate; }
INLINE bool wellFormed(const Function &fn, std::string &why) const;
+ INLINE void out(std::ostream &out, const Function &fn) const;
Register predicate; //!< Predication means conditional branch
LabelIndex labelIndex; //!< Index of the label the branch targets
bool hasPredicate; //!< Is it predicated?
INLINE uint32_t getValueNum(void) const { return valueNum; }
INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
INLINE bool wellFormed(const Function &fn, std::string &why) const;
+ INLINE void out(std::ostream &out, const Function &fn) const;
Type type; //!< Type to store
Register offset; //!< First source is the offset where to store
Tuple values; //!< Values to load
INLINE Type getValueType(void) const { return type; }
INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
INLINE bool wellFormed(const Function &fn, std::string &why) const;
+ INLINE void out(std::ostream &out, const Function &fn) const;
Type type; //!< Type to store
Register offset; //!< First source is the offset where to store
Tuple values; //!< Values to store
public:
INLINE TextureInstruction(void) { this->opcode = OP_TEX; }
INLINE bool wellFormed(const Function &fn, std::string &why) const;
+ INLINE void out(std::ostream &out, const Function &fn) const {
+ this->outOpcode(out);
+ out << " ... TODO";
+ }
};
class ALIGNED_INSTRUCTION LoadImmInstruction :
public BasePolicy, public NoSrcPolicy
{
public:
- INLINE LoadImmInstruction(Type type,
- Register dst,
- ImmediateIndex immediateIndex)
+ INLINE LoadImmInstruction(Type type, Register dst, ImmediateIndex index)
{
this->dst = dst;
this->opcode = OP_LOADI;
- this->immediateIndex = immediateIndex;
+ this->immediateIndex = index;
this->type = type;
}
INLINE Immediate getImmediate(const Function &fn) const {
}
INLINE Type getType(void) const { return this->type; }
bool wellFormed(const Function &fn, std::string &why) const;
+ INLINE void out(std::ostream &out, const Function &fn) const;
Register dst; //!< RegisterData to store into
ImmediateIndex immediateIndex; //!< Index in the vector of immediates
Type type; //!< Type of the immediate
this->memSpace = memSpace;
}
bool wellFormed(const Function &fn, std::string &why) const;
+ INLINE void out(std::ostream &out, const Function &fn) const {
+ this->outOpcode(out);
+ out << "." << memSpace;
+ }
MemorySpace memSpace; //!< The loads and stores to order
};
}
INLINE LabelIndex getLabelIndex(void) const { return labelIndex; }
INLINE bool wellFormed(const Function &fn, std::string &why) const;
+ INLINE void out(std::ostream &out, const Function &fn) const;
LabelIndex labelIndex; //!< Index of the label
};
* defined (i.e. not out-of-bound)
*/
static INLINE bool checkRegisterData(RegisterData::Family family,
- const Register ID,
- const Function &fn,
- std::string &whyNot)
+ const Register ID,
+ const Function &fn,
+ std::string &whyNot)
{
if (UNLIKELY(uint16_t(ID) >= fn.regNum())) {
whyNot = "Out-of-bound destination register index";
return true;
}
+ /////////////////////////////////////////////////////////////////////////
+ // Implements all the output stream methods
+ /////////////////////////////////////////////////////////////////////////
+ template <uint32_t srcNum>
+ INLINE void NaryInstruction<srcNum>::out(std::ostream &out, const Function &fn) const {
+ this->outOpcode(out);
+ out << "." << this->getType()
+ << " %" << this->getDstIndex(fn, 0);
+ for (uint32_t i = 0; i < srcNum; ++i)
+ out << " %" << this->getSrcIndex(fn, i);
+ }
+
+ INLINE void TernaryInstruction::out(std::ostream &out, const Function &fn) const {
+ this->outOpcode(out);
+ out << "." << this->getType()
+ << " %" << this->getDstIndex(fn, 0)
+ << " %" << this->getSrcIndex(fn, 0)
+ << " %" << this->getSrcIndex(fn, 1)
+ << " %" << this->getSrcIndex(fn, 2);
+ }
+
+ INLINE void ConvertInstruction::out(std::ostream &out, const Function &fn) const {
+ this->outOpcode(out);
+ out << "." << this->getDstType()
+ << "." << this->getSrcType()
+ << " %" << this->getDstIndex(fn, 0)
+ << " %" << this->getSrcIndex(fn, 0)
+ << " %" << this->getSrcIndex(fn, 1);
+ }
+
+ INLINE void LoadInstruction::out(std::ostream &out, const Function &fn) const {
+ this->outOpcode(out);
+ out << "." << type << "." << memSpace << " {";
+ for (uint32_t i = 0; i < valueNum; ++i)
+ out << this->getDstIndex(fn, i);
+ out << "}";
+ out << " %" << this->getSrcIndex(fn, 0);
+ }
+
+ INLINE void StoreInstruction::out(std::ostream &out, const Function &fn) const {
+ this->outOpcode(out);
+ out << "." << type << "." << memSpace;
+ out << " %" << this->getSrcIndex(fn, 0) << " {";
+ for (uint32_t i = 0; i < valueNum; ++i)
+ out << this->getSrcIndex(fn, i+1);
+ out << "}";
+ }
+
+ INLINE void LabelInstruction::out(std::ostream &out, const Function &fn) const {
+ this->outOpcode(out);
+ out << " $" << labelIndex;
+ }
+
+ INLINE void BranchInstruction::out(std::ostream &out, const Function &fn) const {
+ this->outOpcode(out);
+ if (hasPredicate)
+ out << "<%" << this->getSrcIndex(fn, 0) << ">";
+ out << " -> label$" << labelIndex;
+ }
+
+ INLINE void LoadImmInstruction::out(std::ostream &out, const Function &fn) const {
+ this->outOpcode(out);
+ out << "." << type;
+ out << " %" << this->getSrcIndex(fn,0);
+ out << " " << fn.outImmediate(out, immediateIndex);
+ }
+
} /* namespace internal */
+ std::ostream &operator<< (std::ostream &out, MemorySpace memSpace) {
+ switch (memSpace) {
+ case MEM_GLOBAL: return out << "global";
+ case MEM_LOCAL: return out << "local";
+ case MEM_CONSTANT: return out << "constant";
+ case MEM_PRIVATE: return out << "private";
+ };
+ return out;
+ }
+
///////////////////////////////////////////////////////////////////////////
// Implements the various instrospection functions
///////////////////////////////////////////////////////////////////////////
END_FUNCTION(Instruction, bool)
#undef CALL
+#undef DECL_INSN
#undef END_FUNCTION
#undef START_FUNCTION
// CVT
Instruction CVT(Type dstType, Type srcType, Register dst, Register src) {
- internal::ConvertInstruction insn(dstType, srcType, dst, src);
+ const internal::ConvertInstruction insn(dstType, srcType, dst, src);
return insn.convert();
}
// BRA
Instruction BRA(LabelIndex labelIndex) {
- internal::BranchInstruction insn(labelIndex);
+ const internal::BranchInstruction insn(labelIndex);
return insn.convert();
}
Instruction BRA(LabelIndex labelIndex, Register pred) {
- internal::BranchInstruction insn(labelIndex, pred);
+ const internal::BranchInstruction insn(labelIndex, pred);
return insn.convert();
}
// LOADI
Instruction LOADI(Type type, Register dst, ImmediateIndex value) {
- internal::LoadImmInstruction insn(type, dst, value);
+ const internal::LoadImmInstruction insn(type, dst, value);
return insn.convert();
}
return insn.convert();
}
+ std::ostream &operator<< (std::ostream &out, const Instruction::Proxy &proxy)
+ {
+ const Instruction &insn = proxy.insn;
+ const Function &fn = proxy.fn;
+ switch (insn.getOpcode()) {
+#define DECL_INSN(OPCODE, CLASS) \
+ case OP_##OPCODE: \
+ reinterpret_cast<const internal::CLASS&>(insn).out(out, fn); \
+ break;
+#include "instruction.hxx"
+#undef DECL_INSN
+ };
+ return out;
+ }
+
} /* namespace ir */
} /* namespace gbe */
MEM_PRIVATE //!< Per thread private memory
};
+ /*! Output the memory space */
+ std::ostream &operator<< (std::ostream &out, MemorySpace memSpace);
+
/*! A label is identified with an unsigned short */
TYPE_SAFE(LabelIndex, uint16_t)
template <typename T> INLINE bool isMemberOf(void) const {
return T::isClassOf(*this);
}
+ /*! Since we need the function to get all the instruction information, we
+ * build a small temporary structure to forward both the instruction and
+ * the function
+ */
+ struct Proxy {
+ INLINE Proxy(const Function &fn, const Instruction &insn) :
+ fn(fn), insn(insn) {}
+ const Function &fn;
+ const Instruction &insn;
+ };
+ /*! Build a proxy from the instruction */
+ INLINE Proxy proxy(const Function &fn) const { return Proxy(fn, *this); }
+
protected:
enum { opaqueSize = sizeof(uint64_t)-sizeof(uint8_t) };
Opcode opcode; //!< Idendifies the instruction
char opaque[opaqueSize]; //!< Remainder of it
};
- /*! To output the instruction in any stream */
- std::ostream &operator<< (std::ostream &out, const Instruction &insn);
+ /*! Output the instruction string in the given stream */
+ std::ostream &operator<< (std::ostream &out, const Instruction::Proxy &proxy);
// Check that the instruction is properly formed by the compiler
static_assert(sizeof(Instruction)==sizeof(uint64_t), "Bad instruction size");
/**
* \file register.cpp
- *
* \author Benjamin Segovia <benjamin.segovia@intel.com>
*/
#include "ir/register.hpp"
+#include "sys/string.hpp"
namespace gbe {
namespace ir {
+
+ std::ostream &operator<< (std::ostream &out, const RegisterData ®Data)
+ {
+ switch (regData.family) {
+ case RegisterData::BOOL: return out << "bool";
+ case RegisterData::BYTE: return out << "byte";
+ case RegisterData::WORD: return out << "word";
+ case RegisterData::DWORD: return out << "dword";
+ case RegisterData::QWORD: return out << "qword";
+ };
+ return out;
+ }
+
+ std::ostream &operator<< (std::ostream &out, const RegisterFile &file)
+ {
+ out << "## " << file.regNum() << " register"
+ << plural(file.regNum()) << " ##" << std::endl;
+ for (uint32_t i = 0; i < file.regNum(); ++i) {
+ const RegisterData reg = file.get(Register(i));
+ out << ".decl." << reg << " %" << i << std::endl;
+ }
+ return out;
+ }
+
} /* namespace ir */
} /* namespace gbe */
GBE_CLASS(RegisterData);
};
+ /*! Output the register file string in the given stream */
+ std::ostream &operator<< (std::ostream &out, const RegisterData ®Data);
+
/*! Register is the position of the index of the register data in the register
* file. We enforce type safety with this class
*/
GBE_CLASS(RegisterFile);
};
+ /*! Output the register file string in the given stream */
+ std::ostream &operator<< (std::ostream &out, const RegisterFile &file);
+
} /* namespace ir */
} /* namespace gbe */
#include "sys/platform.hpp"
#include "ir/register.hpp"
+#include <ostream>
+
namespace gbe {
namespace ir {
TYPE_DOUBLE //!< 64 bits floating point value
};
+ /*! Output a string for the type in the given stream */
+ std::ostream &operator<< (std::ostream &out, const Type &type);
+
/*! Get the register family for each type */
INLINE RegisterData::Family getFamily(Type type) {
switch (type) {
auto it = functions.find(name);
if (it != functions.end())
return NULL;
- Function *fn = GBE_NEW(Function);
+ Function *fn = GBE_NEW(Function, name);
functions[name] = fn;
return fn;
}
union {
int8_t s8;
uint8_t u8;
- int16_t i16;
+ int16_t s16;
uint16_t u16;
- int32_t i32;
+ int32_t s32;
uint32_t u32;
- int64_t i64;
+ int64_t s64;
uint64_t u64;
float f32;
double f64;
#include <string>
#include <sstream>
#include <fstream>
+#include <ostream>
namespace std
{
bool contains(const char *haystack, const char *needle);
/*! Tokenize a string (like strtok_r does) */
char* tokenize(char *s1, const char *s2, char **lasts);
+ /*! To append s or not */
+ INLINE const char *plural(uint32_t value) { return value > 1 ? "s" : ""; }
} /* namespace gbe */
#endif /* __GBE_STRING_HPP__ */
} /* namespace gbe */
/*! RegisterData a new unit test */
-#define UTEST_REGISTER(FN) static const gbe::UTest __##NAME##__(FN, #FN);
+#define UTEST_REGISTER(FN) static const gbe::UTest __##FN##__(FN, #FN);
/*! No assert is expected */
#define UTEST_EXPECT_SUCCESS(EXPR) \
ctx.BRA(label);
ctx.endFunction();
ctx.endFunction();
+#if 0
+ std::cout << *unit.getFunction("hop") << std::endl;
+ std::cout << *unit.getFunction("bip") << std::endl;
+#endif
}
static void labelUsedTwice(void) {
Unit unit;