From c746299c66eb461912a1be54c994db956378ba6e Mon Sep 17 00:00:00 2001 From: Benjamin Segovia Date: Sun, 20 May 2012 17:39:17 +0000 Subject: [PATCH] s/FunctionInput/FunctionArgument/g --- backend/src/backend/context.cpp | 58 +++++----- backend/src/backend/gen_context.cpp | 16 +-- backend/src/backend/sim_context.cpp | 18 +-- backend/src/ir/context.cpp | 6 +- backend/src/ir/context.hpp | 7 +- backend/src/ir/function.cpp | 20 ++-- backend/src/ir/function.hpp | 52 ++++----- backend/src/ir/lowering.cpp | 210 ++++++++++++++++++++++++---------- backend/src/ir/unit.hpp | 8 ++ backend/src/ir/value.cpp | 30 ++--- backend/src/ir/value.hpp | 14 +-- backend/src/llvm/llvm_gen_backend.cpp | 10 +- 12 files changed, 272 insertions(+), 177 deletions(-) diff --git a/backend/src/backend/context.cpp b/backend/src/backend/context.cpp index a67e417..7262553 100644 --- a/backend/src/backend/context.cpp +++ b/backend/src/backend/context.cpp @@ -81,17 +81,17 @@ namespace gbe kernel->curbeSize += this->simdWidth * sizeof(uint16_t); // Go over the arguments and find the related patch locations - const uint32_t inputNum = fn.inputNum(); - for (uint32_t inputID = 0u; inputID < inputNum; ++inputID) { - const ir::FunctionInput &input = fn.getInput(inputID); + const uint32_t argNum = fn.argNum(); + for (uint32_t argID = 0u; argID < argNum; ++argID) { + const ir::FunctionArgument &arg = fn.getInput(argID); // For pointers and values, we have nothing to do. We just push the values - if (input.type == ir::FunctionInput::GLOBAL_POINTER || - input.type == ir::FunctionInput::CONSTANT_POINTER || - input.type == ir::FunctionInput::VALUE) { - kernel->curbeSize = ALIGN(kernel->curbeSize, input.size); - const PatchInfo patch(GBE_CURBE_KERNEL_ARGUMENT, inputID, kernel->curbeSize); + if (arg.type == ir::FunctionArgument::GLOBAL_POINTER || + arg.type == ir::FunctionArgument::CONSTANT_POINTER || + arg.type == ir::FunctionArgument::VALUE) { + kernel->curbeSize = ALIGN(kernel->curbeSize, arg.size); + const PatchInfo patch(GBE_CURBE_KERNEL_ARGUMENT, argID, kernel->curbeSize); kernel->patches.push_back(patch); - kernel->curbeSize += input.size; + kernel->curbeSize += arg.size; } } @@ -168,31 +168,31 @@ namespace gbe } void Context::buildArgList(void) { - kernel->argNum = fn.inputNum(); + kernel->argNum = fn.argNum(); kernel->args = GBE_NEW_ARRAY(KernelArgument, kernel->argNum); - for (uint32_t inputID = 0; inputID < kernel->argNum; ++inputID) { - const auto &input = fn.getInput(inputID); - switch (input.type) { - case ir::FunctionInput::VALUE: - case ir::FunctionInput::STRUCTURE: - kernel->args[inputID].type = GBE_ARG_VALUE; - kernel->args[inputID].size = input.size; + for (uint32_t argID = 0; argID < kernel->argNum; ++argID) { + const auto &arg = fn.getInput(argID); + switch (arg.type) { + case ir::FunctionArgument::VALUE: + case ir::FunctionArgument::STRUCTURE: + kernel->args[argID].type = GBE_ARG_VALUE; + kernel->args[argID].size = arg.size; break; - case ir::FunctionInput::GLOBAL_POINTER: - kernel->args[inputID].type = GBE_ARG_GLOBAL_PTR; - kernel->args[inputID].size = sizeof(void*); + case ir::FunctionArgument::GLOBAL_POINTER: + kernel->args[argID].type = GBE_ARG_GLOBAL_PTR; + kernel->args[argID].size = sizeof(void*); break; - case ir::FunctionInput::CONSTANT_POINTER: - kernel->args[inputID].type = GBE_ARG_CONSTANT_PTR; - kernel->args[inputID].size = sizeof(void*); + case ir::FunctionArgument::CONSTANT_POINTER: + kernel->args[argID].type = GBE_ARG_CONSTANT_PTR; + kernel->args[argID].size = sizeof(void*); break; - case ir::FunctionInput::LOCAL_POINTER: - kernel->args[inputID].type = GBE_ARG_LOCAL_PTR; - kernel->args[inputID].size = sizeof(void*); + case ir::FunctionArgument::LOCAL_POINTER: + kernel->args[argID].type = GBE_ARG_LOCAL_PTR; + kernel->args[argID].size = sizeof(void*); break; - case ir::FunctionInput::IMAGE: - kernel->args[inputID].type = GBE_ARG_IMAGE; - kernel->args[inputID].size = sizeof(void*); + case ir::FunctionArgument::IMAGE: + kernel->args[argID].type = GBE_ARG_IMAGE; + kernel->args[argID].size = sizeof(void*); break; } } diff --git a/backend/src/backend/gen_context.cpp b/backend/src/backend/gen_context.cpp index 7aaf3be..ca95a9e 100644 --- a/backend/src/backend/gen_context.cpp +++ b/backend/src/backend/gen_context.cpp @@ -212,14 +212,14 @@ namespace gbe else NOT_SUPPORTED; - // Allocate all input parameters - const uint32_t inputNum = fn.inputNum(); - for (uint32_t inputID = 0; inputID < inputNum; ++inputID) { - const FunctionInput &input = fn.getInput(inputID); - GBE_ASSERT(input.type == FunctionInput::GLOBAL_POINTER || - input.type == FunctionInput::CONSTANT_POINTER || - input.type == FunctionInput::VALUE); - allocatePayloadReg(GBE_CURBE_KERNEL_ARGUMENT, inputID, input.reg); + // Allocate all arg parameters + const uint32_t argNum = fn.argNum(); + for (uint32_t argID = 0; argID < argNum; ++argID) { + const FunctionArgument &arg = fn.getInput(argID); + GBE_ASSERT(arg.type == FunctionArgument::GLOBAL_POINTER || + arg.type == FunctionArgument::CONSTANT_POINTER || + arg.type == FunctionArgument::VALUE); + allocatePayloadReg(GBE_CURBE_KERNEL_ARGUMENT, argID, arg.reg); } // First we build the set of all used registers diff --git a/backend/src/backend/sim_context.cpp b/backend/src/backend/sim_context.cpp index 40eb362..c61e073 100644 --- a/backend/src/backend/sim_context.cpp +++ b/backend/src/backend/sim_context.cpp @@ -113,16 +113,16 @@ namespace gbe } while (0) void SimContext::emitCurbeLoad(void) { - // Right now curbe is only made of input argument stuff - const uint32_t inputNum = fn.inputNum(); - for (uint32_t inputID = 0; inputID < inputNum; ++inputID) { - const ir::FunctionInput &input = fn.getInput(inputID); - const ir::Register reg = input.reg; - const int32_t offset = kernel->getCurbeOffset(GBE_CURBE_KERNEL_ARGUMENT, inputID); + // Right now curbe is only made of arg argument stuff + const uint32_t argNum = fn.argNum(); + for (uint32_t argID = 0; argID < argNum; ++argID) { + const ir::FunctionArgument &arg = fn.getInput(argID); + const ir::Register reg = arg.reg; + const int32_t offset = kernel->getCurbeOffset(GBE_CURBE_KERNEL_ARGUMENT, argID); // XXX add support for these items - GBE_ASSERT (input.type != ir::FunctionInput::STRUCTURE && - input.type != ir::FunctionInput::IMAGE && - input.type != ir::FunctionInput::LOCAL_POINTER); + GBE_ASSERT (arg.type != ir::FunctionArgument::STRUCTURE && + arg.type != ir::FunctionArgument::IMAGE && + arg.type != ir::FunctionArgument::LOCAL_POINTER); GBE_ASSERT(offset >= 0); o << "LOAD(_" << uint32_t(reg) << ", curbe + " << offset << ");\n"; } diff --git a/backend/src/ir/context.cpp b/backend/src/ir/context.cpp index 14648a1..d6000b4 100644 --- a/backend/src/ir/context.cpp +++ b/backend/src/ir/context.cpp @@ -92,11 +92,11 @@ namespace ir { return index; } - void Context::input(FunctionInput::Type type, Register reg, uint32_t elementSize) { + void Context::input(FunctionArgument::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"); - FunctionInput *input = GBE_NEW(FunctionInput, type, reg, elementSize); - fn->inputs.push_back(input); + FunctionArgument *arg = GBE_NEW(FunctionArgument, type, reg, elementSize); + fn->args.push_back(arg); } void Context::output(Register reg) { diff --git a/backend/src/ir/context.hpp b/backend/src/ir/context.hpp index 3cd3867..5809545 100644 --- a/backend/src/ir/context.hpp +++ b/backend/src/ir/context.hpp @@ -77,7 +77,7 @@ namespace ir { /*! Create a new label for the current function */ LabelIndex label(void); /*! Append a new input register for the function */ - void input(FunctionInput::Type type, Register reg, uint32_t elemSz = 0u); + void input(FunctionArgument::Type type, Register reg, uint32_t elemSz = 0u); /*! Append a new output register for the function */ void output(Register reg); /*! Get the immediate value */ @@ -109,10 +109,7 @@ namespace ir { } /*! Return the family of registers that contain pointer */ INLINE RegisterFamily getPointerFamily(void) const { - if (this->getPointerSize() == POINTER_32_BITS) - return FAMILY_DWORD; - else - return FAMILY_QWORD; + return unit.getPointerFamily(); } #define DECL_THREE_SRC_INSN(NAME) \ INLINE void NAME(Type type, \ diff --git a/backend/src/ir/function.cpp b/backend/src/ir/function.cpp index 67ad9f5..662ba2a 100644 --- a/backend/src/ir/function.cpp +++ b/backend/src/ir/function.cpp @@ -34,7 +34,7 @@ namespace ir { 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); + for (auto it = args.begin(); it != args.end(); ++it) GBE_DELETE(*it); } void Function::sortLabels(void) { @@ -162,17 +162,17 @@ namespace ir { { out << ".decl_function " << fn.getName() << std::endl; out << fn.getRegisterFile(); - out << "## " << fn.inputNum() << " input register" - << plural(fn.inputNum()) << " ##" << std::endl; - for (uint32_t i = 0; i < fn.inputNum(); ++i) { - const FunctionInput &input = fn.getInput(i); + out << "## " << fn.argNum() << " input register" + << plural(fn.argNum()) << " ##" << std::endl; + for (uint32_t i = 0; i < fn.argNum(); ++i) { + const FunctionArgument &input = fn.getInput(i); out << "decl_input."; switch (input.type) { - case FunctionInput::GLOBAL_POINTER: out << "global"; break; - case FunctionInput::LOCAL_POINTER: out << "local"; break; - case FunctionInput::CONSTANT_POINTER: out << "constant"; break; - case FunctionInput::VALUE: out << "value"; break; - case FunctionInput::STRUCTURE: + case FunctionArgument::GLOBAL_POINTER: out << "global"; break; + case FunctionArgument::LOCAL_POINTER: out << "local"; break; + case FunctionArgument::CONSTANT_POINTER: out << "constant"; break; + case FunctionArgument::VALUE: out << "value"; break; + case FunctionArgument::STRUCTURE: out << "structure." << input.size; break; default: break; diff --git a/backend/src/ir/function.hpp b/backend/src/ir/function.hpp index 47539bc..a74a02b 100644 --- a/backend/src/ir/function.hpp +++ b/backend/src/ir/function.hpp @@ -114,14 +114,12 @@ namespace ir { GBE_CLASS(BasicBlock); }; - /*! In fine, function inputs (arguments) can be pushed from the constant + /*! In fine, function input arguments can be pushed from the constant * buffer if they are structures. Other arguments can be images (textures) * and will also require special treatment. */ - struct FunctionInput - { - enum Type - { + struct FunctionArgument { + enum Type { GLOBAL_POINTER = 0, // __global CONSTANT_POINTER = 1, // __constant LOCAL_POINTER = 2, // __local @@ -129,8 +127,8 @@ namespace ir { STRUCTURE = 4, // struct foo IMAGE = 5 // image*d_t }; - /*! Create a function input */ - INLINE FunctionInput(Type type, Register reg, uint32_t size) : + /*! Create a function input argument */ + INLINE FunctionArgument(Type type, Register reg, uint32_t size) : type(type), reg(reg), size(size) {} Type type; /*! Gives the type of argument we have */ Register reg; /*! Holds the argument */ @@ -188,19 +186,19 @@ namespace ir { /*! Fast allocation / deallocation of instructions */ DECL_POOL(Instruction, insnPool); /*! Get input argument */ - INLINE const FunctionInput &getInput(uint32_t ID) const { - GBE_ASSERT(ID < inputNum() && inputs[ID] != NULL); - return *inputs[ID]; + INLINE const FunctionArgument &getInput(uint32_t ID) const { + GBE_ASSERT(ID < argNum() && args[ID] != NULL); + return *args[ID]; } - INLINE FunctionInput &getInput(uint32_t ID) { - GBE_ASSERT(ID < inputNum() && inputs[ID] != NULL); - return *inputs[ID]; + INLINE FunctionArgument &getInput(uint32_t ID) { + GBE_ASSERT(ID < argNum() && args[ID] != NULL); + return *args[ID]; } /*! Get input argument from the register (linear research). Return NULL if * this is not an input argument */ - INLINE const FunctionInput *getInput(const Register ®) const { - for (auto it = inputs.begin(); it != inputs.end(); ++it) + INLINE const FunctionArgument *getInput(const Register ®) const { + for (auto it = args.begin(); it != args.end(); ++it) if ((*it)->reg == reg) return *it; return NULL; } @@ -263,8 +261,8 @@ namespace ir { 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 argument register */ + INLINE uint32_t argNum(void) const { return args.size(); } /*! Get the number of output register */ INLINE uint32_t outputNum(void) const { return outputs.size(); } /*! Number of blocks in the function */ @@ -284,16 +282,16 @@ namespace ir { (*it)->foreach(functor); } private: - friend class Context; //!< Can freely modify a function - std::string name; //!< Function name - vector inputs;//!< Input registers of the function - vector outputs; //!< Output registers of the function - vector labels; //!< Each label points to a basic block - vector immediates; //!< All immediate values in the function - vector blocks; //!< All chained basic blocks - RegisterFile file; //!< RegisterDatas used by the instructions - Profile profile; //!< Current function profile - GBE_CLASS(Function); //!< Use gbe allocators + friend class Context; //!< Can freely modify a function + std::string name; //!< Function name + vector args;//!< Input registers of the function + vector outputs; //!< Output registers of the function + vector labels; //!< Each label points to a basic block + vector immediates; //!< All immediate values in the function + vector blocks; //!< All chained basic blocks + RegisterFile file; //!< RegisterDatas used by the instructions + Profile profile; //!< Current function profile + GBE_CLASS(Function); //!< Use gbe allocators }; /*! Output the function string in the given stream */ diff --git a/backend/src/ir/lowering.cpp b/backend/src/ir/lowering.cpp index fd3f86d..6c65eae 100644 --- a/backend/src/ir/lowering.cpp +++ b/backend/src/ir/lowering.cpp @@ -25,7 +25,7 @@ #include "ir/context.hpp" #include "ir/value.hpp" #include "ir/liveness.hpp" -#include "ir/argument_analysis.hpp" +#include "ir/constant_push.hpp" #include "sys/set.hpp" namespace gbe { @@ -70,6 +70,28 @@ namespace ir { GBE_DELETE(ctx); } + /*! Characterizes how the argument is used (directly read, indirectly read, + * written) + */ + enum ArgUse { + ARG_DIRECT_READ = 0, + ARG_INDIRECT_READ = 1, + ARG_WRITTEN = 2 + }; + + /*! Just to book keep the sequence of instructions that directly load an input + * argument + */ + struct LoadAddImm { + Instruction *load; //!< Load from the argument + Instruction *add; //!< Can be NULL if we only have load(arg) + Instruction *loadImm; //!< Can also be NULL + uint64_t offset; //!< Offset where to load in the structure + }; + + /*! List of direct loads */ + typedef vector LoadAddImmSeq; + /*! Helper class to lower function arguments if required */ class FunctionArgumentLowerer { @@ -78,18 +100,24 @@ namespace ir { FunctionArgumentLowerer(Unit &unit); /*! Free everything we needed */ ~FunctionArgumentLowerer(void); - /*! Perform the function argument substitution if needed */ + /*! Perform all function arguments substitution if needed */ void lower(const std::string &name); - /*! Inspect and possibly the given function argument */ - void lower(FunctionInput &input); + /*! Lower the given function argument accesses */ + void lower(FunctionArgument &arg); + /*! Inspect the given function argument to see how it is used. If this is + * direct loads only, we also output the list of instructions used for each + * load + */ + ArgUse getArgUse(FunctionArgument &arg); /*! Recursively look if there is a store in the given use */ bool useStore(const ValueDef &def, set &visited); /*! Look if the pointer use only load with immediate offsets */ - bool matchLoadImm(const FunctionInput &input, uint64_t &offset); + bool matchLoadAddImm(const FunctionArgument &arg); Liveness *liveness; //!< To compute the function graph FunctionDAG *dag; //!< Contains complete dependency information Unit &unit; //!< The unit we process Function *fn; //!< Function to patch + LoadAddImmSeq seq; //!< All the direct loads }; FunctionArgumentLowerer::FunctionArgumentLowerer(Unit &unit) : @@ -106,12 +134,11 @@ namespace ir { GBE_SAFE_DELETE(liveness); this->liveness = GBE_NEW(ir::Liveness, *fn); this->dag = GBE_NEW(ir::FunctionDAG, *this->liveness); - std::cout << *this->dag; - const uint32_t inputNum = fn->inputNum(); - for (uint32_t inputID = 0; inputID < inputNum; ++inputID) { - FunctionInput &input = fn->getInput(inputID); - if (input.type != FunctionInput::STRUCTURE) continue; - this->lower(input); + const uint32_t argNum = fn->argNum(); + for (uint32_t argID = 0; argID < argNum; ++argID) { + FunctionArgument &arg = fn->getInput(argID); + if (arg.type != FunctionArgument::STRUCTURE) continue; + this->lower(arg); } } @@ -132,72 +159,137 @@ namespace ir { continue; else { const uint32_t dstNum = insn->getDstNum(); - for (uint32_t dstID = 0; dstID < dstNum; ++dstID) { + for (uint32_t dstID = 0; dstID < dstNum; ++dstID) if (this->useStore(ValueDef(insn, dstID), visited) == true) return true; - } } } return false; } - bool FunctionArgumentLowerer::matchLoadImm(const FunctionInput &input, uint64_t &offset) { - const UseSet &useSet = dag->getUse(&input); - offset = 0; - for (const auto &use : useSet) { - const Instruction *insn = use->getInstruction(); - const uint32_t srcID = use->getSrcID(); + INLINE uint64_t getOffsetFromImm(const Immediate &imm) { + switch (imm.type) { + case TYPE_DOUBLE: + case TYPE_FLOAT: + case TYPE_S64: + case TYPE_U64: + case TYPE_U32: + case TYPE_U16: + case TYPE_U8: return imm.data.u64; + case TYPE_S32: return int64_t(imm.data.s32); + case TYPE_S16: return int64_t(imm.data.s16); + case TYPE_S8: return int64_t(imm.data.s8); + case TYPE_BOOL: + case TYPE_HALF: NOT_SUPPORTED; return 0; + } + return 0; + } + + bool matchLoad(Instruction *insn, + Instruction *add, + Instruction *loadImm, + uint64_t offset, + LoadAddImm &loadAddImm) + { + const Opcode opcode = insn->getOpcode(); + + if (opcode == OP_LOAD) { + LoadInstruction *load = cast(insn); + if (load->getAddressSpace() != MEM_PRIVATE) + return false; + loadAddImm.load = insn; + loadAddImm.add = add; + loadAddImm.loadImm = loadImm; + loadAddImm.offset = offset; + return true; + } else + return false; + } + + bool FunctionArgumentLowerer::matchLoadAddImm(const FunctionArgument &arg) { + LoadAddImmSeq tmpSeq; + + // Inspect all uses of the function argument pointer + const UseSet &useSet = dag->getUse(&arg); + for (auto use : useSet) { + Instruction *insn = const_cast(use->getInstruction()); const Opcode opcode = insn->getOpcode(); - // load dst ptr -> it is fine - if (opcode == OP_LOAD) continue; - - // add dst ptr other -> we must inspect other to see if it comes from - // LOADI - if (opcode == OP_ADD) { - const uint32_t otherID = srcID ^ 1; - const DefSet &defSet = dag->getDef(insn, otherID); - const uint32_t defNum = defSet.size(); - if (defNum == 0) continue; // undefined value - if (defNum > 1) return false; // only *one* LOADI is allowed - - // Only accept one LOADI as definition - const ValueDef *otherDef = *defSet.begin(); - if (otherDef->getType() != ValueDef::DEF_INSN_DST) return false; - const Instruction *otherInsn = otherDef->getInstruction(); - if (otherInsn->getOpcode() != OP_LOADI) return false; - const LoadImmInstruction *loadImm = cast(otherInsn); - offset = loadImm->getImmediate().data.u64; + + // load dst arg + LoadAddImm loadAddImm; + if (matchLoad(insn, NULL, NULL, 0, loadAddImm)) { + tmpSeq.push_back(loadAddImm); + continue; + } + + // add.ptr_type dst ptr other + if (opcode != OP_ADD) return false; + BinaryInstruction *add = cast(insn); + const Type addType = add->getType(); + const RegisterFamily family = getFamily(addType); + if (family != unit.getPointerFamily()) return false; + if (addType == TYPE_FLOAT) return false; + + // step 1 -> check that the other source comes from a load immediate + const uint32_t srcID = use->getSrcID(); + const uint32_t otherID = srcID ^ 1; + const DefSet &defSet = dag->getDef(insn, otherID); + const uint32_t defNum = defSet.size(); + if (defNum == 0 || defNum > 1) continue; // undefined or more than one def + const ValueDef *otherDef = *defSet.begin(); + if (otherDef->getType() != ValueDef::DEF_INSN_DST) return false; + Instruction *otherInsn = const_cast(otherDef->getInstruction()); + if (otherInsn->getOpcode() != OP_LOADI) return false; + LoadImmInstruction *loadImm = cast(otherInsn); + const Immediate imm = loadImm->getImmediate(); + const uint64_t offset = getOffsetFromImm(imm); + + // step 2 -> check that the results of the add are loads from private + // memory + const UseSet &addUseSet = dag->getUse(add, 0); + for (auto addUse : addUseSet) { + Instruction *insn = const_cast(addUse->getInstruction()); + + // We finally find something like load dst arg+imm + LoadAddImm loadAddImm; + if (matchLoad(insn, add, loadImm, offset, loadAddImm)) { + tmpSeq.push_back(loadAddImm); + continue; + } } } + + // OK, the argument only need direct loads. We can now append all the + // direct load definitions we found + for (const auto &loadImmSeq : tmpSeq) + seq.push_back(loadImmSeq); return true; } - void FunctionArgumentLowerer::lower(FunctionInput &input) + ArgUse FunctionArgumentLowerer::getArgUse(FunctionArgument &arg) { - // case 1 - we may store something to the structure argument. Right now we - // abort but we will need to spill the structures into register (actually - // all argument that may be also indirectly read (due to aliasing problems) + // case 1 - we may store something to the structure argument set visited; - GBE_ASSERTM(this->useStore(ValueDef(&input), visited) == false, - "A store to a structure argument " - "(i.e. not a char/short/int/float argument) has been found. " - "This is not supported yet"); - - // case 2 - we look for the patterns: - // LOAD(ptr) or LOAD(ptr+imm) - // if all patterns are like this, we know we can safely use the push - // constant and we save the analysis result for the final backend code - // generation - uint64_t offset; - if (this->matchLoadImm(input, offset) == true) { + if (this->useStore(ValueDef(&arg), visited)) + return ARG_WRITTEN; + // case 2 - we look for the patterns: LOAD(ptr) or LOAD(ptr+imm) + if (this->matchLoadAddImm(arg)) + return ARG_DIRECT_READ; - return; - } + // case 3 - LOAD(ptr+runtime_value) + return ARG_INDIRECT_READ; + } - // case 3 - LOAD(ptr+runtime_value) is *not* supported yet - GBE_ASSERTM(false, "Only direct loads of structure arguments are " - "supported now."); + void FunctionArgumentLowerer::lower(FunctionArgument &arg) { + const ArgUse argUse = this->getArgUse(arg); + GBE_ASSERTM(argUse != ARG_WRITTEN, + "TODO A store to a structure argument " + "(i.e. not a char/short/int/float argument) has been found. " + "This is not supported yet"); + GBE_ASSERTM(argUse != ARG_INDIRECT_READ, + "TODO Only direct loads of structure arguments are " + "supported now"); } void lowerFunctionArguments(Unit &unit, const std::string &functionName) { diff --git a/backend/src/ir/unit.hpp b/backend/src/ir/unit.hpp index 6045609..7473020 100644 --- a/backend/src/ir/unit.hpp +++ b/backend/src/ir/unit.hpp @@ -25,6 +25,7 @@ #define __GBE_IR_UNIT_HPP__ #include "ir/constant.hpp" +#include "ir/register.hpp" #include "sys/hash_map.hpp" namespace gbe { @@ -68,6 +69,13 @@ namespace ir { } /*! Return the size of the pointers manipulated */ INLINE PointerSize getPointerSize(void) const { return pointerSize; } + /*! Return the family of registers that contain pointer */ + INLINE RegisterFamily getPointerFamily(void) const { + if (this->getPointerSize() == POINTER_32_BITS) + return FAMILY_DWORD; + else + return FAMILY_QWORD; + } private: hash_map functions; //!< All the defined functions ConstantSet constantSet; //!< All the constants defined in the unit diff --git a/backend/src/ir/value.cpp b/backend/src/ir/value.cpp index 4aa6f5a..e2c1c87 100644 --- a/backend/src/ir/value.cpp +++ b/backend/src/ir/value.cpp @@ -63,7 +63,7 @@ namespace ir { /*! Initialize liveOut with the instruction destination values */ void initializeInstructionDst(void); /*! Initialize liveOut with the function argument */ - void initializeFunctionInputAndSpecialReg(void); + void initializeFunctionArgumentAndSpecialReg(void); /*! Iterate to completely transfer the liveness and get the def sets */ void iterateLiveOut(void); }; @@ -75,7 +75,7 @@ namespace ir { liveness(liveness), dag(dag) { this->initializeInstructionDst(); - this->initializeFunctionInputAndSpecialReg(); + this->initializeFunctionArgumentAndSpecialReg(); this->iterateLiveOut(); } @@ -107,7 +107,7 @@ namespace ir { if (fn.isEntryBlock(bb) == false) return; // Is it a function input? - const FunctionInput *input = fn.getInput(reg); + const FunctionArgument *input = fn.getInput(reg); if (input != NULL) { ValueDef *def = (ValueDef *) dag.getDefAddress(input); udChain.insert(def); @@ -161,9 +161,9 @@ namespace ir { }); } - void LiveOutSet::initializeFunctionInputAndSpecialReg(void) { + void LiveOutSet::initializeFunctionArgumentAndSpecialReg(void) { const Function &fn = liveness.getFunction(); - const uint32_t inputNum = fn.inputNum(); + const uint32_t argNum = fn.argNum(); // The first block must also transfer the function arguments const BasicBlock &top = fn.getTopBlock(); @@ -173,14 +173,14 @@ namespace ir { // 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; + for (uint32_t argID = 0; argID < argNum; ++argID) { + const FunctionArgument &arg = fn.getInput(argID); + const Register reg = arg.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) == true) continue; - ValueDef *def = (ValueDef*) this->dag.getDefAddress(&input); + ValueDef *def = (ValueDef*) this->dag.getDefAddress(&arg); auto it = blockDefMap->find(reg); GBE_ASSERT(it != blockDefMap->end()); it->second->insert(def); @@ -299,10 +299,10 @@ namespace ir { }); // 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); + const uint32_t argNum = fn.argNum(); + for (uint32_t argID = 0; argID < argNum; ++argID) { + const FunctionArgument &arg = fn.getInput(argID); + ValueDef *valueDef = this->newValueDef(&arg); defName.insert(std::make_pair(*valueDef, valueDef)); duGraph.insert(std::make_pair(*valueDef, duEmpty)); } @@ -482,7 +482,7 @@ namespace ir { const UseSet &FunctionDAG::getUse(const Instruction *insn, uint32_t dstID) const { return this->getUse(ValueDef(insn, dstID)); } - const UseSet &FunctionDAG::getUse(const FunctionInput *input) const { + const UseSet &FunctionDAG::getUse(const FunctionArgument *input) const { return this->getUse(ValueDef(input)); } const UseSet &FunctionDAG::getUse(const Register ®) const { @@ -502,7 +502,7 @@ namespace ir { GBE_ASSERT(it != defName.end() && it->second != NULL); return it->second; } - const ValueDef *FunctionDAG::getDefAddress(const FunctionInput *input) const { + const ValueDef *FunctionDAG::getDefAddress(const FunctionArgument *input) const { const ValueDef def(input); auto it = defName.find(def); GBE_ASSERT(it != defName.end() && it->second != NULL); diff --git a/backend/src/ir/value.hpp b/backend/src/ir/value.hpp index 731ceda..32cf5c2 100644 --- a/backend/src/ir/value.hpp +++ b/backend/src/ir/value.hpp @@ -56,7 +56,7 @@ namespace ir { this->data.dstID = dstID; } /*! Build a value from a function argument */ - explicit ValueDef(const FunctionInput *input) : type(DEF_FN_INPUT) { + explicit ValueDef(const FunctionArgument *input) : type(DEF_FN_INPUT) { this->data.input = input; } /*! Build a value from a special register */ @@ -76,7 +76,7 @@ namespace ir { return data.dstID; } /*! Get the function input (only if this is a function argument) */ - INLINE const FunctionInput *getFunctionInput(void) const { + INLINE const FunctionArgument *getFunctionArgument(void) const { GBE_ASSERT(type == DEF_FN_INPUT); return data.input; } @@ -105,7 +105,7 @@ namespace ir { uint32_t dstID; //isPointerTy() == false) - ctx.input(ir::FunctionInput::VALUE, reg, getTypeByteSize(unit, type)); + ctx.input(ir::FunctionArgument::VALUE, reg, getTypeByteSize(unit, type)); else { PointerType *pointerType = dyn_cast(type); // By value structure if (PAL.paramHasAttr(argID, Attribute::ByVal)) { Type *pointed = pointerType->getElementType(); const size_t structSize = getTypeByteSize(unit, pointed); - ctx.input(ir::FunctionInput::STRUCTURE, reg, structSize); + ctx.input(ir::FunctionArgument::STRUCTURE, reg, structSize); } // Regular user provided pointer (global, local or constant) else { @@ -642,13 +642,13 @@ namespace gbe const uint32_t ptrSize = getTypeByteSize(unit, type); switch (addrSpace) { case ir::MEM_GLOBAL: - ctx.input(ir::FunctionInput::GLOBAL_POINTER, reg, ptrSize); + ctx.input(ir::FunctionArgument::GLOBAL_POINTER, reg, ptrSize); break; case ir::MEM_LOCAL: - ctx.input(ir::FunctionInput::LOCAL_POINTER, reg, ptrSize); + ctx.input(ir::FunctionArgument::LOCAL_POINTER, reg, ptrSize); break; case ir::MEM_CONSTANT: - ctx.input(ir::FunctionInput::CONSTANT_POINTER, reg, ptrSize); + ctx.input(ir::FunctionArgument::CONSTANT_POINTER, reg, ptrSize); break; default: GBE_ASSERT(addrSpace != ir::MEM_PRIVATE); } -- 2.7.4