diff options
author | Benjamin Segovia <segovia.benjamin@gmail.com> | 2012-04-16 01:09:16 -0700 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2012-08-10 16:16:26 -0700 |
commit | 9f8ea28a1be64e08c7adc7c9c8e69a802c4a7860 (patch) | |
tree | 0404eb2f907838ef7f1f578e503926cd7e7e986f /backend | |
parent | 366ae87a4364b64f317cf79466a4f296cccc0e90 (diff) | |
download | beignet-9f8ea28a1be64e08c7adc7c9c8e69a802c4a7860.tar.gz |
Added first support for compilation from source. Quick and dirty (since uses system()) but works OK
Diffstat (limited to 'backend')
-rw-r--r-- | backend/src/CMakeLists.txt | 13 | ||||
-rw-r--r-- | backend/src/backend/context.cpp | 17 | ||||
-rw-r--r-- | backend/src/backend/context.hpp | 25 | ||||
-rw-r--r-- | backend/src/backend/gen_program.cpp | 7 | ||||
-rw-r--r-- | backend/src/backend/program.cpp | 42 | ||||
-rw-r--r-- | backend/src/backend/program.h | 5 | ||||
-rw-r--r-- | backend/src/backend/sim/sim_vector.h | 6 | ||||
-rw-r--r-- | backend/src/backend/sim/sim_vector_str.cpp | 6 | ||||
-rw-r--r-- | backend/src/backend/sim_context.cpp | 18 | ||||
-rw-r--r-- | backend/src/backend/sim_program.cpp | 10 | ||||
-rw-r--r-- | backend/src/ir/context.cpp | 1 | ||||
-rw-r--r-- | backend/src/ir/function.cpp | 39 | ||||
-rw-r--r-- | backend/src/ir/function.hpp | 16 | ||||
-rw-r--r-- | backend/src/ir/instruction.cpp | 18 | ||||
-rw-r--r-- | backend/src/ir/instruction.hpp | 3 | ||||
-rw-r--r-- | backend/src/ir/value.hpp | 6 | ||||
-rw-r--r-- | backend/src/llvm/llvm_to_gen.cpp | 18 | ||||
-rw-r--r-- | backend/src/llvm/stdlib.h | 114 | ||||
-rw-r--r-- | backend/src/llvm/stdlib_str.cpp | 120 | ||||
-rw-r--r-- | backend/src/sys/assert.cpp | 2 | ||||
-rw-r--r-- | backend/src/utest/utest_vector.cpp | 2 |
21 files changed, 434 insertions, 54 deletions
diff --git a/backend/src/CMakeLists.txt b/backend/src/CMakeLists.txt index 19a8cdce..26fd6cdf 100644 --- a/backend/src/CMakeLists.txt +++ b/backend/src/CMakeLists.txt @@ -1,9 +1,9 @@ add_subdirectory(llvm) -set (TO_STRINGIFY_FILES simulator sim_vector) +macro (stringify TO_STRINGIFY_PATH TO_STRINGIFY_FILES) foreach (to_stringify_file ${TO_STRINGIFY_FILES}) - set (input_file ${GBE_SOURCE_DIR}/src/backend/sim/${to_stringify_file}.h) - set (output_file ${GBE_SOURCE_DIR}/src/backend/sim/${to_stringify_file}_str.cpp) + set (input_file ${TO_STRINGIFY_PATH}/${to_stringify_file}.h) + set (output_file ${TO_STRINGIFY_PATH}/${to_stringify_file}_str.cpp) set (string_header "\\\"string\\\"") add_custom_command( OUTPUT ${output_file} @@ -18,6 +18,12 @@ foreach (to_stringify_file ${TO_STRINGIFY_FILES}) COMMAND echo "" >> ${output_file} MAIN_DEPENDENCY ${input_file}) endforeach (to_stringify_file) +endmacro (stringify) + +set (TO_STRINGIFY_FILES simulator sim_vector) +stringify ("${GBE_SOURCE_DIR}/src/backend/sim/" "${TO_STRINGIFY_FILES}") +set (TO_STRINGIFY_FILES stdlib) +stringify ("${GBE_SOURCE_DIR}/src/llvm/" "${TO_STRINGIFY_FILES}") if (GBE_USE_BLOB) set (GBE_SRC blob.cpp) @@ -63,6 +69,7 @@ else (GBE_USE_BLOB) ir/function.hpp ir/value.cpp ir/value.hpp + llvm/stdlib_str.cpp backend/context.cpp backend/context.hpp backend/program.cpp diff --git a/backend/src/backend/context.cpp b/backend/src/backend/context.cpp index 7f6ac89d..1a43ccbf 100644 --- a/backend/src/backend/context.cpp +++ b/backend/src/backend/context.cpp @@ -28,17 +28,21 @@ #include "ir/profile.hpp" #include "ir/liveness.hpp" #include "ir/value.hpp" +#include "sys/cvar.hpp" #include <algorithm> namespace gbe { + + IVAR(OCL_SIMD_WIDTH, 8, 16, 32); + Context::Context(const ir::Unit &unit, const std::string &name) : unit(unit), fn(*unit.getFunction(name)), name(name), liveness(NULL), dag(NULL) { GBE_ASSERT(unit.getPointerSize() == ir::POINTER_32_BITS); this->liveness = GBE_NEW(ir::Liveness, (ir::Function&) fn); this->dag = GBE_NEW(ir::FunctionDAG, *this->liveness); - this->simdWidth = 16; /* XXX environment variable for that to start with */ + this->simdWidth = nextHighestPowerOf2(OCL_SIMD_WIDTH); } Context::~Context(void) { GBE_SAFE_DELETE(this->dag); @@ -49,6 +53,7 @@ namespace gbe this->kernel = this->allocateKernel(); this->buildPatchList(); this->buildArgList(); + this->buildUsedLabels(); this->emitCode(); return this->kernel; } @@ -148,6 +153,16 @@ namespace gbe } } + void Context::buildUsedLabels(void) { + usedLabels.clear(); + fn.foreachInstruction([this](const ir::Instruction &insn) { + using namespace ir; + if (insn.getOpcode() != OP_BRA) return; + const LabelIndex index = cast<BranchInstruction>(insn).getLabelIndex(); + usedLabels.insert(index); + }); + } + bool Context::isScalarReg(const ir::Register ®) const { GBE_ASSERT(fn.getProfile() == ir::Profile::PROFILE_OCL); if (fn.getInput(reg) != NULL) diff --git a/backend/src/backend/context.hpp b/backend/src/backend/context.hpp index cbb3c0cd..a88fd1d7 100644 --- a/backend/src/backend/context.hpp +++ b/backend/src/backend/context.hpp @@ -26,6 +26,8 @@ #define __GBE_CONTEXT_HPP__ #include "sys/platform.hpp" +#include "sys/set.hpp" +#include "ir/instruction.hpp" #include <string> namespace gbe { @@ -58,24 +60,33 @@ namespace gbe ~Context(void); /*! Compile the code */ Kernel *compileKernel(void); + /*! Tells if the labels is used */ + INLINE bool isLabelUsed(ir::LabelIndex index) const { + return usedLabels.contains(index); + } + /*! Tells if the register is used */ + bool isRegUsed(const ir::Register ®) const; protected: /*! Build the curbe patch list for the given kernel */ void buildPatchList(void); /*! Build the list of arguments to set to launch the kernel */ void buildArgList(void); + /*! Build the sets of used labels */ + void buildUsedLabels(void); /*! Indicate if a register is scalar or not */ bool isScalarReg(const ir::Register ®) const; /*! Build the instruction stream */ virtual void emitCode(void) = 0; /*! Allocate a new empty kernel */ virtual Kernel *allocateKernel(void) = 0; - const ir::Unit &unit; //!< Unit that contains the kernel - const ir::Function &fn; //!< Function to compile - std::string name; //!< Name of the kernel to compile - Kernel *kernel; //!< Kernel we are building - ir::Liveness *liveness; //!< Liveness info for the variables - ir::FunctionDAG *dag; //!< Complete DAG of values on the function - uint32_t simdWidth; //!< Number of lanes per HW threads + const ir::Unit &unit; //!< Unit that contains the kernel + const ir::Function &fn; //!< Function to compile + std::string name; //!< Name of the kernel to compile + Kernel *kernel; //!< Kernel we are building + ir::Liveness *liveness; //!< Liveness info for the variables + ir::FunctionDAG *dag; //!< Complete DAG of values on the function + set<ir::LabelIndex> usedLabels; //!< Set of all labels actually used + uint32_t simdWidth; //!< Number of lanes per HW threads }; } /* namespace gbe */ diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp index 5029f349..dafacea6 100644 --- a/backend/src/backend/gen_program.cpp +++ b/backend/src/backend/gen_program.cpp @@ -47,11 +47,6 @@ namespace gbe { return ker; } - static gbe_program genProgramNewFromSource(const char *source) { - NOT_IMPLEMENTED; - return NULL; - } - static gbe_program genProgramNewFromBinary(const char *binary, size_t size) { NOT_IMPLEMENTED; return NULL; @@ -65,7 +60,6 @@ namespace gbe { using namespace gbe; GenProgram *program = GBE_NEW(GenProgram); std::string error; - // Try to compile the program if (program->buildFromLLVMFile(fileName, error) == false) { if (err != NULL && errSize != NULL && stringSize > 0u) { @@ -83,7 +77,6 @@ namespace gbe { void genSetupCallBacks(void) { - gbe_program_new_from_source = gbe::genProgramNewFromSource; gbe_program_new_from_binary = gbe::genProgramNewFromBinary; gbe_program_new_from_llvm = gbe::genProgramNewFromLLVM; } diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp index 6ffd1583..08dac6ef 100644 --- a/backend/src/backend/program.cpp +++ b/backend/src/backend/program.cpp @@ -59,21 +59,9 @@ namespace gbe { } BVAR(OCL_OUTPUT_GEN_IR, false); - BVAR(OCL_OUTPUT_LLVM, false); bool Program::buildFromLLVMFile(const char *fileName, std::string &error) { ir::Unit unit; - if (OCL_OUTPUT_LLVM) { - std::ifstream llvmFile; - llvmFile.open(fileName); - if (llvmFile.is_open() == true) { - std::string line; - while (llvmFile.good() == true) { - std::getline(llvmFile ,line); - std::cout << line << std::endl; - } - } - } if (llvmToGen(unit, fileName) == false) { error = std::string(fileName) + " not found"; return false; @@ -100,6 +88,35 @@ namespace gbe { GBE_SAFE_DELETE(program); } + extern std::string stdlib_str; + static gbe_program programNewFromSource(const char *source, + size_t stringSize, + char *err, + size_t *errSize) + { + char clStr[L_tmpnam+1], llStr[L_tmpnam+1]; + const std::string clName = std::string(tmpnam_r(clStr)) + ".cl"; /* unsafe! */ + const std::string llName = std::string(tmpnam_r(llStr)) + ".ll"; /* unsafe! */ + + // Write the source to the cl file + FILE *clFile = fopen(clName.c_str(), "w"); + FATAL_IF(clFile == NULL, "Failed to open temporary file"); + fwrite(stdlib_str.c_str(), strlen(stdlib_str.c_str()), 1, clFile); + fwrite(source, strlen(source), 1, clFile); + fclose(clFile); + + // Now compile the code to llvm using clang + // XXX use popen and stuff instead of that + std::string compileCmd = "clang -emit-llvm -O3 -ccc-host-triple ptx32 -c "; + compileCmd += clName; + compileCmd += " -o "; + compileCmd += llName; + if (UNLIKELY(system(compileCmd.c_str()) != 0)) return NULL; + + // Now build the program from llvm + return gbe_program_new_from_llvm(llName.c_str(), stringSize, err, errSize); + } + static uint32_t programGetKernelNum(gbe_program gbeProgram) { if (gbeProgram == NULL) return 0; const gbe::Program *program = (const gbe::Program*) gbeProgram; @@ -199,6 +216,7 @@ namespace gbe struct CallBackInitializer { CallBackInitializer(void) { + gbe_program_new_from_source = gbe::programNewFromSource; gbe_program_delete = gbe::programDelete; gbe_program_get_kernel_num = gbe::programGetKernelNum; gbe_program_get_kernel_by_name = gbe::programGetKernelByName; diff --git a/backend/src/backend/program.h b/backend/src/backend/program.h index 387fba66..56de46a3 100644 --- a/backend/src/backend/program.h +++ b/backend/src/backend/program.h @@ -75,7 +75,10 @@ enum gbe_curbe_type { }; /*! Create a new program from the given source code (zero terminated string) */ -typedef gbe_program (gbe_program_new_from_source_cb)(const char *source); +typedef gbe_program (gbe_program_new_from_source_cb)(const char *source, + size_t stringSize, + char *err, + size_t *err_size); extern gbe_program_new_from_source_cb *gbe_program_new_from_source; /*! Create a new program from the given blob */ diff --git a/backend/src/backend/sim/sim_vector.h b/backend/src/backend/sim/sim_vector.h index e8970d93..34cec348 100644 --- a/backend/src/backend/sim/sim_vector.h +++ b/backend/src/backend/sim/sim_vector.h @@ -342,13 +342,13 @@ template <uint32_t vectorNum> INLINE void SCATTER(const simd_dw<vectorNum> &offset, const scalar_dw &value, char *base_address) { - SCATTER(simd_dw<vectorNum>(value), offset, base_address); + SCATTER(offset, simd_dw<vectorNum>(value), base_address); } template <uint32_t vectorNum> INLINE void SCATTER(const scalar_dw &offset, const simd_dw<vectorNum> &value, char *base_address) { - SCATTER(value, simd_dw<vectorNum>(offset), base_address); + SCATTER(simd_dw<vectorNum>(offset), value, base_address); } #include <cstdio> /* Gather */ @@ -418,7 +418,7 @@ INLINE void GT_U32(scalar_m &dst, scalar_dw v0, scalar_dw v1) { dst.u = (v0.u > INLINE void LOAD(scalar_dw &dst, const char *ptr) { dst.u = *(const uint32_t *) ptr; } INLINE void STORE(scalar_dw src, char *ptr) { *(uint32_t *) ptr = src.u; } INLINE void LOADI(scalar_dw &dst, uint32_t u) { dst.u = u; } -INLINE void SCATTER(scalar_dw value, scalar_dw offset, char *base) { *(uint32_t*)(base + offset.u) = value.u; } +INLINE void SCATTER(scalar_dw offset, scalar_dw value, char *base) { *(uint32_t*)(base + offset.u) = value.u; } INLINE void GATHER(scalar_dw &dst, scalar_dw offset, const char *base) { dst.u = *(const uint32_t*)(base + offset.u); } ////////////////////////////////////////////////////////////////////////////// diff --git a/backend/src/backend/sim/sim_vector_str.cpp b/backend/src/backend/sim/sim_vector_str.cpp index 7699de47..f900c3fc 100644 --- a/backend/src/backend/sim/sim_vector_str.cpp +++ b/backend/src/backend/sim/sim_vector_str.cpp @@ -368,13 +368,13 @@ std::string sim_vector_str = "INLINE void SCATTER(const simd_dw<vectorNum> &offset,\n" " const scalar_dw &value,\n" " char *base_address) {\n" -" SCATTER(simd_dw<vectorNum>(value), offset, base_address);\n" +" SCATTER(offset, simd_dw<vectorNum>(value), base_address);\n" "}\n" "template <uint32_t vectorNum>\n" "INLINE void SCATTER(const scalar_dw &offset,\n" " const simd_dw<vectorNum> &value,\n" " char *base_address) {\n" -" SCATTER(value, simd_dw<vectorNum>(offset), base_address);\n" +" SCATTER(simd_dw<vectorNum>(offset), value, base_address);\n" "}\n" "#include <cstdio>\n" "/* Gather */\n" @@ -444,7 +444,7 @@ std::string sim_vector_str = "INLINE void LOAD(scalar_dw &dst, const char *ptr) { dst.u = *(const uint32_t *) ptr; }\n" "INLINE void STORE(scalar_dw src, char *ptr) { *(uint32_t *) ptr = src.u; }\n" "INLINE void LOADI(scalar_dw &dst, uint32_t u) { dst.u = u; }\n" -"INLINE void SCATTER(scalar_dw value, scalar_dw offset, char *base) { *(uint32_t*)(base + offset.u) = value.u; }\n" +"INLINE void SCATTER(scalar_dw offset, scalar_dw value, char *base) { *(uint32_t*)(base + offset.u) = value.u; }\n" "INLINE void GATHER(scalar_dw &dst, scalar_dw offset, const char *base) { dst.u = *(const uint32_t*)(base + offset.u); }\n" "\n" "//////////////////////////////////////////////////////////////////////////////\n" diff --git a/backend/src/backend/sim_context.cpp b/backend/src/backend/sim_context.cpp index 280d5712..b01ca7b9 100644 --- a/backend/src/backend/sim_context.cpp +++ b/backend/src/backend/sim_context.cpp @@ -44,10 +44,22 @@ namespace gbe void SimContext::emitRegisters(void) { GBE_ASSERT(fn.getProfile() == ir::PROFILE_OCL); + + // First we build the set of all used registers + set<ir::Register> usedRegs; + fn.foreachInstruction([&usedRegs](const ir::Instruction &insn) { + const uint32_t srcNum = insn.getSrcNum(), dstNum = insn.getDstNum(); + for (uint32_t srcID = 0; srcID < srcNum; ++srcID) + usedRegs.insert(insn.getSrc(srcID)); + for (uint32_t dstID = 0; dstID < dstNum; ++dstID) + usedRegs.insert(insn.getDst(dstID)); + }); + const uint32_t regNum = fn.regNum(); bool lid0 = false, lid1 = false, lid2 = false; // for local id registers for (uint32_t regID = 0; regID < regNum; ++regID) { const ir::Register reg(regID); + if (usedRegs.contains(reg) == false) continue; if (reg == ir::ocl::groupid0 || reg == ir::ocl::groupid1 || reg == ir::ocl::groupid2) @@ -153,13 +165,15 @@ namespace gbe #undef DECL_INSN } if (opcode == OP_LABEL) { - o << "label" << cast<LabelInstruction>(insn).getLabelIndex() << ":\n"; + const LabelInstruction labelInsn = cast<LabelInstruction>(insn); + const LabelIndex index = labelInsn.getLabelIndex(); + if (usedLabels.contains(index) == true) + o << "label" << index << ":\n"; return; } else if (opcode == OP_BRA) { NOT_IMPLEMENTED; return; } else if (opcode == OP_RET) { - std::cout << "BE AWARE OF RET: ONLY ONE RET AT THE END OF THE FUNCTION SHOULD BE OUTPUTTED!"; o << "return;\n"; return; } diff --git a/backend/src/backend/sim_program.cpp b/backend/src/backend/sim_program.cpp index 4df627d3..5c18af7a 100644 --- a/backend/src/backend/sim_program.cpp +++ b/backend/src/backend/sim_program.cpp @@ -45,11 +45,6 @@ namespace gbe { return ker; } - static gbe_program simProgramNewFromSource(const char *source) { - NOT_IMPLEMENTED; - return NULL; - } - static gbe_program simProgramNewFromBinary(const char *binary, size_t size) { NOT_IMPLEMENTED; return NULL; @@ -63,7 +58,7 @@ namespace gbe { using namespace gbe; SimProgram *program = GBE_NEW(SimProgram); std::string error; - /* Try to compile the program */ + // Try to compile the program if (program->buildFromLLVMFile(fileName, error) == false) { if (err != NULL && errSize != NULL && stringSize > 0u) { const size_t msgSize = std::min(error.size(), stringSize-1u); @@ -73,7 +68,7 @@ namespace gbe { GBE_DELETE(program); return NULL; } - /* Everything run fine */ + // Everything run fine return (gbe_program) program; } @@ -81,7 +76,6 @@ namespace gbe { void simSetupCallBacks(void) { - gbe_program_new_from_source = gbe::simProgramNewFromSource; gbe_program_new_from_binary = gbe::simProgramNewFromBinary; gbe_program_new_from_llvm = gbe::simProgramNewFromLLVM; } diff --git a/backend/src/ir/context.cpp b/backend/src/ir/context.cpp index 838ce9ec..7de50ec1 100644 --- a/backend/src/ir/context.cpp +++ b/backend/src/ir/context.cpp @@ -51,6 +51,7 @@ namespace ir { // Check first that all branch instructions point to valid labels for (auto it = usedLabels->begin(); it != usedLabels->end(); ++it) GBE_ASSERTM(*it != LABEL_IS_POINTED, "A label is used and not defined"); + fn->sortLabels(); fn->computeCFG(); GBE_DELETE(usedLabels); const StackElem elem = fnStack.back(); diff --git a/backend/src/ir/function.cpp b/backend/src/ir/function.cpp index a91cec36..e2a233fc 100644 --- a/backend/src/ir/function.cpp +++ b/backend/src/ir/function.cpp @@ -23,6 +23,7 @@ */ #include "ir/function.hpp" #include "sys/string.hpp" +#include "sys/map.hpp" namespace gbe { namespace ir { @@ -37,6 +38,44 @@ namespace ir { GBE_DELETE(*it); } + void Function::sortLabels(void) { + uint32_t last = 0; + + // Compute the new labels and patch the label instruction + map<LabelIndex, LabelIndex> labelMap; + foreachInstruction([&](Instruction &insn) { + if (insn.getOpcode() != OP_LABEL) return; + + // Create the new label + Instruction *newLabel = newInstruction(); + *newLabel = LABEL(LabelIndex(last)); + + // Replace the previous label instruction + LabelInstruction &label = cast<LabelInstruction>(insn); + const LabelIndex index = label.getLabelIndex(); + labelMap.insert(std::make_pair(index, LabelIndex(last++))); + newLabel->replace(&insn); + }); + + // Patch all branch instructions with the new labels + foreachInstruction([&](Instruction &insn) { + if (insn.getOpcode() != OP_BRA) return; + + // Get the current branch instruction + BranchInstruction &bra = cast<BranchInstruction>(insn); + const LabelIndex index = bra.getLabelIndex(); + const LabelIndex newIndex = labelMap.find(index)->second; + + // Insert the patched branch instruction + Instruction *newBra = newInstruction(); + if (bra.isPredicated() == true) + *newBra = BRA(newIndex, bra.getPredicateIndex()); + else + *newBra = BRA(newIndex); + newBra->replace(&insn); + }); + } + LabelIndex Function::newLabel(void) { GBE_ASSERTM(labels.size() < 0xffff, "Too many labels are defined (65536 only are supported)"); diff --git a/backend/src/ir/function.hpp b/backend/src/ir/function.hpp index 165bc6f7..2ae8427d 100644 --- a/backend/src/ir/function.hpp +++ b/backend/src/ir/function.hpp @@ -66,8 +66,10 @@ namespace ir { INLINE void foreach(const T &functor) const { Instruction *curr = first; while (curr) { + // Be aware the current instruction can be destroyed in functor + Instruction *succ = curr->getSuccessor(); functor(*curr); - curr = curr->getSuccessor(); + curr = succ; } } /*! Apply the given functor on all instructions (reverse order) */ @@ -75,8 +77,10 @@ namespace ir { INLINE void rforeach(const T &functor) const { Instruction *curr = last; while (curr) { + // Be aware the current instruction can be destroyed in functor + Instruction *pred = curr->getPredecessor(); functor(*curr); - curr = curr->getPredecessor(); + curr = pred; } } /*! Get the parent function */ @@ -85,9 +89,11 @@ namespace ir { /*! Get the next and previous allocated block */ BasicBlock *getNextBlock(void) const { return this->nextBlock; } BasicBlock *getPrevBlock(void) const { return this->prevBlock; } - /*! Get the first and last instructions */ + /*! Get / set the first and last instructions */ Instruction *getFirstInstruction(void) const { return this->first; } Instruction *getLastInstruction(void) const { return this->last; } + void setFirstInstruction(Instruction *insn) { this->first = insn; } + void setLastInstruction(Instruction *insn) { this->last = insn; } /*! Get successors and predecessors */ const BlockSet &getSuccessorSet(void) const { return successors; } const BlockSet &getPredecessorSet(void) const { return predecessors; } @@ -214,6 +220,10 @@ namespace ir { LabelIndex newLabel(void); /*! Create the control flow graph */ void computeCFG(void); + /*! Sort the labels in increasing orders (ie top block has the smallest + * labels) + */ + void sortLabels(void); /*! Number of registers in the register file */ INLINE uint32_t regNum(void) const { return file.regNum(); } /*! Number of register tuples in the register file */ diff --git a/backend/src/ir/instruction.cpp b/backend/src/ir/instruction.cpp index 6941ac5c..7b04bd25 100644 --- a/backend/src/ir/instruction.cpp +++ b/backend/src/ir/instruction.cpp @@ -884,6 +884,24 @@ END_FUNCTION(Instruction, Register) GBE_ASSERT(bb != NULL); return bb->getParent(); } + Function &Instruction::getFunction(void) { + BasicBlock *bb = this->getParent(); + GBE_ASSERT(bb != NULL); + return bb->getParent(); + } + + void Instruction::replace(Instruction *other) { + Function &fn = other->getFunction(); + BasicBlock *bb = other->getParent(); + if (bb->getFirstInstruction() == other) bb->setFirstInstruction(this); + if (bb->getLastInstruction() == other) bb->setLastInstruction(this); + if (other->predecessor) other->predecessor->successor = this; + if (other->successor) other->successor->predecessor = this; + this->parent = other->parent; + this->predecessor = other->predecessor; + this->successor = other->successor; + fn.deleteInstruction(other); + } #define DECL_MEM_FN(CLASS, RET, PROTOTYPE, CALL) \ RET CLASS::PROTOTYPE const { \ diff --git a/backend/src/ir/instruction.hpp b/backend/src/ir/instruction.hpp index 31acd176..5a485aba 100644 --- a/backend/src/ir/instruction.hpp +++ b/backend/src/ir/instruction.hpp @@ -109,11 +109,14 @@ namespace ir { void setParent(BasicBlock *block) { this->parent = block; } /*! Get the function from the parent basic block */ const Function &getFunction(void) const; + Function &getFunction(void); /*! Check that the instruction is well formed (type properly match, * registers not of bound and so on). If not well formed, provide a reason * in string why */ bool wellFormed(const Function &fn, std::string &why) const; + /*! Replace other by this instruction */ + void replace(Instruction *other); /*! Indicates if the instruction belongs to instruction type T. Typically, T * can be BinaryInstruction, UnaryInstruction, LoadInstruction and so on */ diff --git a/backend/src/ir/value.hpp b/backend/src/ir/value.hpp index 673a2ab2..9d856f94 100644 --- a/backend/src/ir/value.hpp +++ b/backend/src/ir/value.hpp @@ -199,8 +199,12 @@ namespace ir { 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 */ - const Function &getFunction(void) const { return fn; } + INLINE const Function &getFunction(void) const { return fn; } /*! The DefSet for each definition use */ typedef map<ValueUse, DefSet*> UDGraph; /*! The UseSet for each definition */ diff --git a/backend/src/llvm/llvm_to_gen.cpp b/backend/src/llvm/llvm_to_gen.cpp index 802aed2b..9cdbbecf 100644 --- a/backend/src/llvm/llvm_to_gen.cpp +++ b/backend/src/llvm/llvm_to_gen.cpp @@ -27,19 +27,27 @@ #include "llvm/PassManager.h" #include "llvm/Pass.h" #include "llvm/Support/IRReader.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Assembly/PrintModulePass.h" #include "llvm/llvm_gen_backend.hpp" #include "llvm/llvm_to_gen.hpp" +#include "sys/cvar.hpp" #include "sys/platform.hpp" namespace gbe { + BVAR(OCL_OUTPUT_LLVM, false); + BVAR(OCL_OUTPUT_LLVM_BEFORE_EXTRA_PASS, false); + bool llvmToGen(ir::Unit &unit, const char *fileName) { using namespace llvm; // Get the global LLVM context llvm::LLVMContext& c = llvm::getGlobalContext(); + std::string errInfo; + llvm::raw_fd_ostream o("-", errInfo); // Get the module from its file SMDiagnostic Err; @@ -49,14 +57,22 @@ namespace gbe Module &mod = *M.get(); llvm::PassManager passes; + + // Print the code before further optimizations + if (OCL_OUTPUT_LLVM_BEFORE_EXTRA_PASS) + passes.add(createPrintModulePass(&o)); passes.add(createScalarReplAggregatesPass()); // Break up allocas passes.add(createRemoveGEPPass(unit)); passes.add(createConstantPropagationPass()); - passes.add(createDeadInstEliminationPass()); // remove simplified instructions + passes.add(createDeadInstEliminationPass()); // Remove simplified instructions passes.add(createLowerSwitchPass()); passes.add(createPromoteMemoryToRegisterPass()); passes.add(createGVNPass()); // Remove redundancies passes.add(createGenPass(unit)); + + // Print the code extra optimization passes + if (OCL_OUTPUT_LLVM) + passes.add(createPrintModulePass(&o)); passes.run(mod); return true; } diff --git a/backend/src/llvm/stdlib.h b/backend/src/llvm/stdlib.h new file mode 100644 index 00000000..eaf4b171 --- /dev/null +++ b/backend/src/llvm/stdlib.h @@ -0,0 +1,114 @@ +/* + * 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> + */ + +#define DECL_INTERNAL_WORK_ITEM_FN(NAME) \ +__attribute__((pure,const)) unsigned int __gen_ocl_##NAME##0(void); \ +__attribute__((pure,const)) unsigned int __gen_ocl_##NAME##1(void); \ +__attribute__((pure,const)) unsigned int __gen_ocl_##NAME##2(void); +DECL_INTERNAL_WORK_ITEM_FN(get_group_id) +DECL_INTERNAL_WORK_ITEM_FN(get_local_id) +DECL_INTERNAL_WORK_ITEM_FN(get_local_size) +DECL_INTERNAL_WORK_ITEM_FN(get_global_size) +DECL_INTERNAL_WORK_ITEM_FN(get_num_groups) +#undef DECL_INTERNAL_WORK_ITEM_FN + +#define DECL_PUBLIC_WORK_ITEM_FN(NAME) \ +inline unsigned NAME(unsigned int dim) { \ + if (dim == 0) return __gen_ocl_##NAME##0(); \ + else if (dim == 1) return __gen_ocl_##NAME##1(); \ + else if (dim == 2) return __gen_ocl_##NAME##2(); \ + else return 0; \ +} +DECL_PUBLIC_WORK_ITEM_FN(get_group_id) +DECL_PUBLIC_WORK_ITEM_FN(get_local_id) +DECL_PUBLIC_WORK_ITEM_FN(get_local_size) +DECL_PUBLIC_WORK_ITEM_FN(get_global_size) +DECL_PUBLIC_WORK_ITEM_FN(get_num_groups) +#undef DECL_PUBLIC_WORK_ITEM_FN + +inline unsigned int get_global_id(unsigned int dim) { + return get_local_id(dim) + get_local_size(dim) * get_group_id(dim); +} + +__attribute__ ((pure,const,overloadable)) float mad(float a, float b, float c); +__attribute__((overloadable)) inline unsigned select(unsigned src0, unsigned src1, unsigned cond) { + return cond ? src0 : src1; +} +__attribute__((overloadable)) inline int select(int src0, int src1, int cond) { + return cond ? src0 : src1; +} + +typedef float float2 __attribute__((ext_vector_type(2))); +typedef float float3 __attribute__((ext_vector_type(3))); +typedef float float4 __attribute__((ext_vector_type(4))); +typedef int int2 __attribute__((ext_vector_type(2))); +typedef int int3 __attribute__((ext_vector_type(3))); +typedef int int4 __attribute__((ext_vector_type(4))); +typedef int uint2 __attribute__((ext_vector_type(2))); +typedef unsigned uint3 __attribute__((ext_vector_type(3))); +typedef unsigned uint4 __attribute__((ext_vector_type(4))); +typedef bool bool2 __attribute__((ext_vector_type(2))); +typedef bool bool3 __attribute__((ext_vector_type(3))); +typedef bool bool4 __attribute__((ext_vector_type(4))); + +// This will be optimized out by LLVM and will output LLVM select instructions +#define DECL_SELECT4(TYPE4, TYPE, COND_TYPE4, MASK) \ +__attribute__((overloadable)) \ +inline TYPE4 select(TYPE4 src0, TYPE4 src1, COND_TYPE4 cond) { \ + TYPE4 dst; \ + const TYPE x0 = src0.x; /* Fix performance issue with CLANG */ \ + const TYPE x1 = src1.x; \ + const TYPE y0 = src0.y; \ + const TYPE y1 = src1.y; \ + const TYPE z0 = src0.z; \ + const TYPE z1 = src1.z; \ + const TYPE w0 = src0.w; \ + const TYPE w1 = src1.w; \ + \ + dst.x = (cond.x & MASK) ? x1 : x0; \ + dst.y = (cond.y & MASK) ? y1 : y0; \ + dst.z = (cond.z & MASK) ? z1 : z0; \ + dst.w = (cond.w & MASK) ? w1 : w0; \ + return dst; \ +} +DECL_SELECT4(int4, int, int4, 0x80000000) +DECL_SELECT4(float4, float, int4, 0x80000000) +#undef DECL_SELECT4 + +__attribute__((overloadable,always_inline)) inline float2 mad(float2 a, float2 b, float2 c) { + return (float2)(mad(a.x,b.x,c.x), mad(a.y,b.y,c.y)); +} +__attribute__((overloadable,always_inline)) inline float3 mad(float3 a, float3 b, float3 c) { + return (float3)(mad(a.x,b.x,c.x), mad(a.y,b.y,c.y), mad(a.z,b.z,c.z)); +} +__attribute__((overloadable,always_inline)) inline float4 mad(float4 a, float4 b, float4 c) { + return (float4)(mad(a.x,b.x,c.x), mad(a.y,b.y,c.y), + mad(a.z,b.z,c.z), mad(a.w,b.w,c.w)); +} + +#define __private __attribute__((address_space(0))) +#define __global __attribute__((address_space(1))) +#define __constant __attribute__((address_space(2))) +//#define __local __attribute__((address_space(3))) +#define global __global +//#define local __local +#define constant __constant +#define private __private + +#define NULL ((void*)0) diff --git a/backend/src/llvm/stdlib_str.cpp b/backend/src/llvm/stdlib_str.cpp new file mode 100644 index 00000000..41ce7fe6 --- /dev/null +++ b/backend/src/llvm/stdlib_str.cpp @@ -0,0 +1,120 @@ +/* + * 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> + */ + +#include "string" +namespace gbe { +std::string stdlib_str = +"#define DECL_INTERNAL_WORK_ITEM_FN(NAME) \\\n" +"__attribute__((pure,const)) unsigned int __gen_ocl_##NAME##0(void); \\\n" +"__attribute__((pure,const)) unsigned int __gen_ocl_##NAME##1(void); \\\n" +"__attribute__((pure,const)) unsigned int __gen_ocl_##NAME##2(void);\n" +"DECL_INTERNAL_WORK_ITEM_FN(get_group_id)\n" +"DECL_INTERNAL_WORK_ITEM_FN(get_local_id)\n" +"DECL_INTERNAL_WORK_ITEM_FN(get_local_size)\n" +"DECL_INTERNAL_WORK_ITEM_FN(get_global_size)\n" +"DECL_INTERNAL_WORK_ITEM_FN(get_num_groups)\n" +"#undef DECL_INTERNAL_WORK_ITEM_FN\n" +"\n" +"#define DECL_PUBLIC_WORK_ITEM_FN(NAME) \\\n" +"inline unsigned NAME(unsigned int dim) { \\\n" +" if (dim == 0) return __gen_ocl_##NAME##0(); \\\n" +" else if (dim == 1) return __gen_ocl_##NAME##1(); \\\n" +" else if (dim == 2) return __gen_ocl_##NAME##2(); \\\n" +" else return 0; \\\n" +"}\n" +"DECL_PUBLIC_WORK_ITEM_FN(get_group_id)\n" +"DECL_PUBLIC_WORK_ITEM_FN(get_local_id)\n" +"DECL_PUBLIC_WORK_ITEM_FN(get_local_size)\n" +"DECL_PUBLIC_WORK_ITEM_FN(get_global_size)\n" +"DECL_PUBLIC_WORK_ITEM_FN(get_num_groups)\n" +"#undef DECL_PUBLIC_WORK_ITEM_FN\n" +"\n" +"inline unsigned int get_global_id(unsigned int dim) {\n" +" return get_local_id(dim) + get_local_size(dim) * get_group_id(dim);\n" +"}\n" +"\n" +"__attribute__ ((pure,const,overloadable)) float mad(float a, float b, float c);\n" +"__attribute__((overloadable)) inline unsigned select(unsigned src0, unsigned src1, unsigned cond) {\n" +" return cond ? src0 : src1;\n" +"}\n" +"__attribute__((overloadable)) inline int select(int src0, int src1, int cond) {\n" +" return cond ? src0 : src1;\n" +"}\n" +"\n" +"typedef float float2 __attribute__((ext_vector_type(2)));\n" +"typedef float float3 __attribute__((ext_vector_type(3)));\n" +"typedef float float4 __attribute__((ext_vector_type(4)));\n" +"typedef int int2 __attribute__((ext_vector_type(2)));\n" +"typedef int int3 __attribute__((ext_vector_type(3)));\n" +"typedef int int4 __attribute__((ext_vector_type(4)));\n" +"typedef int uint2 __attribute__((ext_vector_type(2)));\n" +"typedef unsigned uint3 __attribute__((ext_vector_type(3)));\n" +"typedef unsigned uint4 __attribute__((ext_vector_type(4)));\n" +"typedef bool bool2 __attribute__((ext_vector_type(2)));\n" +"typedef bool bool3 __attribute__((ext_vector_type(3)));\n" +"typedef bool bool4 __attribute__((ext_vector_type(4)));\n" +"\n" +"// This will be optimized out by LLVM and will output LLVM select instructions\n" +"#define DECL_SELECT4(TYPE4, TYPE, COND_TYPE4, MASK) \\\n" +"__attribute__((overloadable)) \\\n" +"inline TYPE4 select(TYPE4 src0, TYPE4 src1, COND_TYPE4 cond) { \\\n" +" TYPE4 dst; \\\n" +" const TYPE x0 = src0.x; /* Fix performance issue with CLANG */ \\\n" +" const TYPE x1 = src1.x; \\\n" +" const TYPE y0 = src0.y; \\\n" +" const TYPE y1 = src1.y; \\\n" +" const TYPE z0 = src0.z; \\\n" +" const TYPE z1 = src1.z; \\\n" +" const TYPE w0 = src0.w; \\\n" +" const TYPE w1 = src1.w; \\\n" +" \\\n" +" dst.x = (cond.x & MASK) ? x1 : x0; \\\n" +" dst.y = (cond.y & MASK) ? y1 : y0; \\\n" +" dst.z = (cond.z & MASK) ? z1 : z0; \\\n" +" dst.w = (cond.w & MASK) ? w1 : w0; \\\n" +" return dst; \\\n" +"}\n" +"DECL_SELECT4(int4, int, int4, 0x80000000)\n" +"DECL_SELECT4(float4, float, int4, 0x80000000)\n" +"#undef DECL_SELECT4\n" +"\n" +"__attribute__((overloadable,always_inline)) inline float2 mad(float2 a, float2 b, float2 c) {\n" +" return (float2)(mad(a.x,b.x,c.x), mad(a.y,b.y,c.y));\n" +"}\n" +"__attribute__((overloadable,always_inline)) inline float3 mad(float3 a, float3 b, float3 c) {\n" +" return (float3)(mad(a.x,b.x,c.x), mad(a.y,b.y,c.y), mad(a.z,b.z,c.z));\n" +"}\n" +"__attribute__((overloadable,always_inline)) inline float4 mad(float4 a, float4 b, float4 c) {\n" +" return (float4)(mad(a.x,b.x,c.x), mad(a.y,b.y,c.y),\n" +" mad(a.z,b.z,c.z), mad(a.w,b.w,c.w));\n" +"}\n" +"\n" +"#define __private __attribute__((address_space(0)))\n" +"#define __global __attribute__((address_space(1)))\n" +"#define __constant __attribute__((address_space(2)))\n" +"//#define __local __attribute__((address_space(3)))\n" +"#define global __global\n" +"//#define local __local\n" +"#define constant __constant\n" +"#define private __private\n" +"\n" +"#define NULL ((void*)0)\n" +; +} + diff --git a/backend/src/sys/assert.cpp b/backend/src/sys/assert.cpp index d13017cf..ea3d34c2 100644 --- a/backend/src/sys/assert.cpp +++ b/backend/src/sys/assert.cpp @@ -39,7 +39,7 @@ namespace gbe + std::string(file) + ", function " + std::string(fn) + ", line " + std::string(lineString); - // assert(0); + assert(0); throw Exception(str); } } /* namespace gbe */ diff --git a/backend/src/utest/utest_vector.cpp b/backend/src/utest/utest_vector.cpp index 26ef64b8..6d9e77d9 100644 --- a/backend/src/utest/utest_vector.cpp +++ b/backend/src/utest/utest_vector.cpp @@ -353,7 +353,7 @@ static void utestScatterGather(void) LOAD(_##INDEX##g, (const char *) (gatherOffsets+index##INDEX));\ LOAD(_##INDEX##s, (const char *) (scatterOffsets+index##INDEX));\ GATHER(_##INDEX, _##INDEX##g, (const char *) data);\ - SCATTER(_##INDEX, _##INDEX##s, (char *) dst);\ + SCATTER(_##INDEX##s, _##INDEX, (char *) dst);\ for (uint32_t i = 0; i < elemNum(_##INDEX); ++i)\ GBE_ASSERT(data[gatherOffsets[index##INDEX+i] / sizeof(uint32_t)] ==\ dst[scatterOffsets[index##INDEX+i] / sizeof(uint32_t)]); |