-#include <stdlib.h>
+#include "stdlib.h"
__kernel unsigned int add(unsigned int x, unsigned int y)
{
return x + y;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
struct big{
unsigned int a, b;
};
return p;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void test_cmp(__global bool *dst, int x, int y, float z, float w)
{
dst[0] = (x < y) + (z > w);
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void cmp_cvt(__global int *dst, int x, int y)
{
dst[0] = x + y < get_local_id(0) ;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void cycle(global int *dst)
{
int x, y;
dst[0] = x;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void extract(__global int4 *dst, __global int4 *src, int c)
{
const int4 from = src[0];
dst[0] = (int4)(from.x, 1, 2, 3);
}
+
-#include <stdlib.h>
+#include "stdlib.h"
void write(__global int *dst)
{
write(dst);
dst[x] = 1;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
struct struct0
{
int hop[5];
dst[0].y += y;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void test_global_id(__global int *dst, __global int *p)
{
p[get_global_id(0)] = get_local_id(0);
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void insert(__global int4 *dst, __global int4 *src, int c)
{
dst[0] = src[0];
}
+
-#include <stdlib.h>
-__kernel void add(__global int *dst, unsigned int x)
+#include "stdlib.h"
+
+struct big { int x[10]; };
+
+__kernel void add(__global int *dst, unsigned int x, struct big b)
{
for (int i = 0; i < x; ++i) dst[i]++;
}
+
target datalayout = "e-p:32:32-i64:64:64-f64:64:64-n1:8:16:32:64"
target triple = "ptx32--"
-define ptx_kernel void @add(i32* nocapture %dst, i32 %x) nounwind noinline {
+%struct.big = type { [10 x i32] }
+
+define ptx_kernel void @add(i32 addrspace(1)* nocapture %dst, i32 %x, %struct.big* nocapture byval %b) nounwind noinline {
entry:
%cmp2 = icmp eq i32 %x, 0
br i1 %cmp2, label %for.end, label %for.body
for.body: ; preds = %for.body, %entry
%i.03 = phi i32 [ %inc1, %for.body ], [ 0, %entry ]
- %arrayidx = getelementptr inbounds i32* %dst, i32 %i.03
- %0 = load i32* %arrayidx, align 4, !tbaa !1
+ %arrayidx = getelementptr inbounds i32 addrspace(1)* %dst, i32 %i.03
+ %0 = load i32 addrspace(1)* %arrayidx, align 4, !tbaa !1
%inc = add nsw i32 %0, 1
- store i32 %inc, i32* %arrayidx, align 4, !tbaa !1
+ store i32 %inc, i32 addrspace(1)* %arrayidx, align 4, !tbaa !1
%inc1 = add nsw i32 %i.03, 1
%exitcond = icmp eq i32 %inc1, %x
br i1 %exitcond, label %for.end, label %for.body
!opencl.kernels = !{!0}
-!0 = metadata !{void (i32*, i32)* @add}
+!0 = metadata !{void (i32 addrspace(1)*, i32, %struct.big*)* @add}
!1 = metadata !{metadata !"int", metadata !2}
!2 = metadata !{metadata !"omnipotent char", metadata !3}
!3 = metadata !{metadata !"Simple C/C++ TBAA", null}
-#include <stdlib.h>
+#include "stdlib.h"
__attribute__((pure, overloadable)) int mad(int,int,int);
__attribute__((pure, overloadable)) float mad(float,float,float);
__attribute__((pure, overloadable)) float4 mad(float4,float4,float4);
}
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void test_select(__global int4 *dst,
__global int4 *src0,
const int4 from = select(src0[0], src0[1], src0[1]);
dst[0] = from;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void short_write(__global short *dst, short x, short y)
{
dst[0] = x + y;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void shuffle(__global int4 *dst, __global int4 *src, int c)
{
const int4 from = src[0];
dst[0] = from.xywz;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void simple_float4(__global float4 *dst, __global float4 *src)
{
dst[get_global_id(0)] = src[get_global_id(0)];
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void simple_float4(__global float4 *dst, __global float4 *src)
{
dst[get_global_id(0)] = src[get_global_id(0)] * src[get_global_id(0)];
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void simple_float4(__global float4 *dst, __global float4 *src, bool b)
{
dst[get_global_id(0)] += (float4) (src[2].x, 1.f, 2.f, 3.f);
}
+
return dst;
}
+#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
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void store(__global int *dst, __local int *dst0, int x)
{
dst[0] = 1;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
struct my_struct {
int a;
int b[2];
mem[0] = s.a + array[x].a + array[x+1].b[0] + g[x] + g[3];
}
+
-#include <stdlib.h>
+#include "stdlib.h"
struct my_struct {
int a;
int b[2];
mem[0] = hop;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void test_select(__global int *dst, __global int *src)
{
dst[get_global_id(0)] = 2;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void undefined(__global int *dst)
{
int x;
dst[0] = 1;
}
+
-#include <stdlib.h>
+#include "stdlib.h"
__kernel void hop() {}
+
return index;
}
- void Context::input(Register reg) {
+ void Context::input(FunctionInput::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");
- fn->inputs.push_back(reg);
+ const FunctionInput input(type, reg, elementSize);
+ fn->inputs.push_back(input);
}
void Context::output(Register reg) {
/*! Create a new label for the current function */
LabelIndex label(void);
/*! Append a new input register for the function */
- void input(Register reg);
+ void input(FunctionInput::Type type, Register reg, uint32_t elemSz = 0u);
/*! Append a new output register for the function */
void output(Register reg);
/*! Get the immediate value */
/*! LOAD with the destinations directly specified */
template <typename... Args>
- void LOAD(Type type, Register offset, MemorySpace space, bool dwAligned, Args...values)
+ void LOAD(Type type, Register offset, AddressSpace space, bool dwAligned, Args...values)
{
const Tuple index = this->tuple(values...);
const uint16_t valueNum = std::tuple_size<std::tuple<Args...>>::value;
/*! STORE with the sources directly specified */
template <typename... Args>
- void STORE(Type type, Register offset, MemorySpace space, bool dwAligned, Args...values)
+ void STORE(Type type, Register offset, AddressSpace space, bool dwAligned, Args...values)
{
const Tuple index = this->tuple(values...);
const uint16_t valueNum = std::tuple_size<std::tuple<Args...>>::value;
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;
+ for (uint32_t i = 0; i < fn.inputNum(); ++i) {
+ const FunctionInput &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:
+ out << "structure." << input.elementSize;
+ break;
+ default: break;
+ }
+ out << " %" << input.reg << std::endl;
+ }
out << "## " << fn.outputNum() << " output register"
<< plural(fn.outputNum()) << " ##" << std::endl;
for (uint32_t i = 0; i < fn.outputNum(); ++i)
GBE_CLASS(BasicBlock);
};
+ /*! In fine, function inputs (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
+ {
+ GLOBAL_POINTER = 0, /* __global */
+ CONSTANT_POINTER = 1, /* __constant */
+ LOCAL_POINTER = 2, /* __local */
+ VALUE = 3, /* int, float */
+ STRUCTURE = 4 /* struct foo */
+ };
+ /*! Create a function input */
+ INLINE FunctionInput(Type type, Register reg, uint32_t elementSize = 0u) :
+ type(type), reg(reg), elementSize(elementSize) {}
+ Type type; /*! Gives the type of argument we have */
+ Register reg; /*! Holds the argument */
+ uint32_t elementSize; /*! Only for structure arguments */
+ };
+
/*! A function is no more that a set of declared registers and a set of
* basic blocks
*/
INLINE void deleteInstruction(Instruction *insn) {
insnPool.deallocate(insn);
}
- /*! Get input register */
- INLINE Register getInput(uint32_t ID) const {
+ /*! Get input argument */
+ INLINE const FunctionInput &getInput(uint32_t ID) const {
GBE_ASSERT(ID < inputNum());
return inputs[ID];
}
private:
friend class Context; //!< Can freely modify a function
std::string name; //!< Function name
- vector<Register> inputs; //!< Input registers of the function
+ vector<FunctionInput> 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
LoadInstruction(Type type,
Tuple dstValues,
Register offset,
- MemorySpace memSpace,
+ AddressSpace addrSpace,
uint32_t valueNum,
bool dwAligned)
{
this->type = type;
this->offset = offset;
this->values = dstValues;
- this->memSpace = memSpace;
+ this->addrSpace = addrSpace;
this->valueNum = valueNum;
this->dwAligned = dwAligned ? 1 : 0;
}
INLINE uint32_t getDstNum(void) const { return valueNum; }
INLINE Type getValueType(void) const { return type; }
INLINE uint32_t getValueNum(void) const { return valueNum; }
- INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
+ INLINE AddressSpace getAddressSpace(void) const { return addrSpace; }
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
- MemorySpace memSpace; //!< Where to load
+ AddressSpace addrSpace; //!< Where to load
uint8_t valueNum:7; //!< Number of values to load
uint8_t dwAligned:1; //!< DWORD aligned is what matters with GEN
};
StoreInstruction(Type type,
Tuple values,
Register offset,
- MemorySpace memSpace,
+ AddressSpace addrSpace,
uint32_t valueNum,
bool dwAligned)
{
this->type = type;
this->offset = offset;
this->values = values;
- this->memSpace = memSpace;
+ this->addrSpace = addrSpace;
this->valueNum = valueNum;
this->dwAligned = dwAligned ? 1 : 0;
}
INLINE uint32_t getSrcNum(void) const { return valueNum + 1u; }
INLINE uint32_t getValueNum(void) const { return valueNum; }
INLINE Type getValueType(void) const { return type; }
- INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
+ INLINE AddressSpace getAddressSpace(void) const { return addrSpace; }
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
- MemorySpace memSpace; //!< Where to store
+ AddressSpace addrSpace; //!< Where to store
uint8_t valueNum:7; //!< Number of values to store
uint8_t dwAligned:1; //!< DWORD aligned is what matters with GEN
};
public BasePolicy, public NoSrcPolicy, public NoDstPolicy
{
public:
- INLINE FenceInstruction(MemorySpace memSpace) {
+ INLINE FenceInstruction(AddressSpace addrSpace) {
this->opcode = OP_FENCE;
- this->memSpace = memSpace;
+ this->addrSpace = addrSpace;
}
bool wellFormed(const Function &fn, std::string &why) const;
INLINE void out(std::ostream &out, const Function &fn) const {
this->outOpcode(out);
- out << "." << memSpace;
+ out << "." << addrSpace;
}
- MemorySpace memSpace; //!< The loads and stores to order
+ AddressSpace addrSpace; //!< The loads and stores to order
};
class ALIGNED_INSTRUCTION LabelInstruction :
INLINE void LoadInstruction::out(std::ostream &out, const Function &fn) const {
this->outOpcode(out);
- out << "." << type << "." << memSpace << (dwAligned ? "." : ".un") << "aligned";
+ out << "." << type << "." << addrSpace << (dwAligned ? "." : ".un") << "aligned";
out << " {";
for (uint32_t i = 0; i < valueNum; ++i)
out << "%" << this->getDstIndex(fn, i) << (i != (valueNum-1) ? " " : "");
INLINE void StoreInstruction::out(std::ostream &out, const Function &fn) const {
this->outOpcode(out);
- out << "." << type << "." << memSpace << (dwAligned ? "." : ".un") << "aligned";
+ out << "." << type << "." << addrSpace << (dwAligned ? "." : ".un") << "aligned";
out << " %" << this->getSrcIndex(fn, 0) << " {";
for (uint32_t i = 0; i < valueNum; ++i)
out << "%" << this->getSrcIndex(fn, i+1) << (i != (valueNum-1) ? " " : "");
} /* namespace internal */
- std::ostream &operator<< (std::ostream &out, MemorySpace memSpace) {
- switch (memSpace) {
+ std::ostream &operator<< (std::ostream &out, AddressSpace addrSpace) {
+ switch (addrSpace) {
case MEM_GLOBAL: return out << "global";
case MEM_LOCAL: return out << "local";
case MEM_CONSTANT: return out << "constant";
DECL_MEM_FN(ConvertInstruction, Type, getDstType(void), getDstType())
DECL_MEM_FN(StoreInstruction, Type, getValueType(void), getValueType())
DECL_MEM_FN(StoreInstruction, uint32_t, getValueNum(void), getValueNum())
-DECL_MEM_FN(StoreInstruction, MemorySpace, getAddressSpace(void), getAddressSpace())
+DECL_MEM_FN(StoreInstruction, AddressSpace, getAddressSpace(void), getAddressSpace())
DECL_MEM_FN(LoadInstruction, Type, getValueType(void), getValueType())
DECL_MEM_FN(LoadInstruction, uint32_t, getValueNum(void), getValueNum())
-DECL_MEM_FN(LoadInstruction, MemorySpace, getAddressSpace(void), getAddressSpace())
+DECL_MEM_FN(LoadInstruction, AddressSpace, getAddressSpace(void), getAddressSpace())
DECL_MEM_FN(LoadImmInstruction, Immediate, getImmediate(const Function &fn), getImmediate(fn))
DECL_MEM_FN(LoadImmInstruction, Type, getType(void), getType())
DECL_MEM_FN(LabelInstruction, LabelIndex, getLabelIndex(void), getLabelIndex())
Instruction NAME(Type type, \
Tuple tuple, \
Register offset, \
- MemorySpace space, \
+ AddressSpace space, \
uint32_t valueNum, \
bool dwAligned) \
{ \
#undef DECL_EMIT_FUNCTION
// FENCE
- Instruction FENCE(MemorySpace space) {
+ Instruction FENCE(AddressSpace space) {
const internal::FenceInstruction insn(space);
return insn.convert();
}
};
/*! Different memory spaces */
- enum MemorySpace : uint8_t {
+ enum AddressSpace : uint8_t {
MEM_GLOBAL = 0, //!< Global memory (a la OCL)
MEM_LOCAL, //!< Local memory (thread group memory)
MEM_CONSTANT, //!< Immutable global memory
};
/*! Output the memory space */
- std::ostream &operator<< (std::ostream &out, MemorySpace memSpace);
+ std::ostream &operator<< (std::ostream &out, AddressSpace addrSpace);
/*! A label is identified with an unsigned short */
TYPE_SAFE(LabelIndex, uint16_t)
/*! Give the number of values the instruction is storing (srcNum-1) */
uint32_t getValueNum(void) const;
/*! Address space that is manipulated here */
- MemorySpace getAddressSpace(void) const;
+ AddressSpace getAddressSpace(void) const;
/*! DWORD aligned means untyped read for Gen. That is what matters */
bool isDWORDAligned(void) const;
/*! Return true if the given instruction is an instance of this class */
/*! Number of values loaded (ie number of destinations) */
uint32_t getValueNum(void) const;
/*! Address space that is manipulated here */
- MemorySpace getAddressSpace(void) const;
+ AddressSpace getAddressSpace(void) const;
/*! DWORD aligned means untyped read for Gen. That is what matters */
bool isDWORDAligned(void) const;
/*! Return true if the given instruction is an instance of this class */
/*! loadi.type dst value */
Instruction LOADI(Type type, Register dst, ImmediateIndex value);
/*! load.type.space {dst1,...,dst_valueNum} offset value */
- Instruction LOAD(Type type, Tuple dst, Register offset, MemorySpace space, uint32_t valueNum, bool dwAligned);
+ Instruction LOAD(Type type, Tuple dst, Register offset, AddressSpace space, uint32_t valueNum, bool dwAligned);
/*! store.type.space offset {src1,...,src_valueNum} value */
- Instruction STORE(Type type, Tuple src, Register offset, MemorySpace space, uint32_t valueNum, bool dwAligned);
+ Instruction STORE(Type type, Tuple src, Register offset, AddressSpace space, uint32_t valueNum, bool dwAligned);
/*! fence.space */
- Instruction FENCE(MemorySpace space);
+ Instruction FENCE(AddressSpace space);
/*! label labelIndex */
Instruction LABEL(LabelIndex labelIndex);
/*! texture instruction TODO */
}
}
+ /*! To pretty print the livfeness info */
static const uint32_t prettyInsnStrSize = 48;
static const uint32_t prettyRegStrSize = 5;
- enum RegisterUse
- {
- USE_NONE = 0,
- USE_READ = 1,
- USE_WRITTEN = 2
+ /*! Describe how the register is used */
+ static const uint32_t USE_NONE = 0;
+ static const uint32_t USE_READ = 1 << 0;
+ static const uint32_t USE_WRITTEN = 1 << 1;
+
+ enum UsePosition {
+ POS_BEFORE = 0,
+ POS_HERE = 1,
+ POS_AFTER = 2
};
- /*! "next" includes the provided instruction */
- static INLINE RegisterUse nextUse(const Instruction &insn, Register reg) {
+ /*! Compute the use of a register in all direction in a block */
+ template <UsePosition pos>
+ static INLINE uint32_t usage(const Instruction &insn, Register reg) {
const Function &fn = insn.getParent()->getParent();
const Instruction *curr = &insn;
+ uint32_t use = USE_NONE;
+
+ // Skip the current element if you are looking forward or backward
+ if (curr && pos == POS_BEFORE)
+ curr = curr->getPredecessor();
+ else if (curr && pos == POS_AFTER)
+ curr = curr->getSuccessor();
while (curr) {
for (uint32_t srcID = 0; srcID < curr->getSrcNum(); ++srcID) {
const Register src = curr->getSrcIndex(fn, srcID);
- if (src == reg) return USE_READ;
+ if (src == reg) {
+ use |= USE_READ;
+ break;
+ }
}
for (uint32_t dstID = 0; dstID < curr->getDstNum(); ++dstID) {
const Register dst = curr->getDstIndex(fn, dstID);
- if (dst == reg) return USE_WRITTEN;
+ if (dst == reg) {
+ use |= USE_WRITTEN;
+ break;
+ }
}
- curr = curr->getSuccessor();
+ if (use != USE_NONE)
+ break;
+ if (pos == POS_BEFORE)
+ curr = curr->getPredecessor();
+ else if (pos == POS_AFTER)
+ curr = curr->getSuccessor();
+ else
+ curr = NULL;
}
- return USE_NONE;
- }
- /*! "previous" does not include the provided instruction */
- static INLINE RegisterUse previousUse(const Instruction &insn, Register reg) {
- return USE_NONE;
+ return use;
}
/*! Just print spaceNum spaces */
{
for (uint32_t regID = 0; regID < fn.regNum(); ++regID) {
const Register reg(regID);
+ // Use in that instruction means alive
+ if (usage<POS_HERE>(insn, reg) != USE_NONE) {
+ printAlive(out);
+ continue;
+ }
// Non-killed and liveout == alive in the complete block
- if (info.inLiveOut(reg) == true && info.inVarKill(reg) == false)
+ if (info.inLiveOut(reg) == true && info.inVarKill(reg) == false) {
printAlive(out);
- // We must look for the last use of the instruction
- else if (info.inLiveOut(reg) == false) {
-
- } else
- printDead(out);
+ continue;
+ }
+ // It is going to be read
+ const uint32_t nextUsage = usage<POS_AFTER>(insn, reg);
+ if ((nextUsage & USE_READ) != USE_NONE) {
+ printAlive(out);
+ continue;
+ }
+ // It is not written and alive at the end of the block
+ if ((nextUsage & USE_WRITTEN) == USE_NONE && info.inLiveOut(reg) == true) {
+ printAlive(out);
+ continue;
+ }
+ printDead(out);
}
}
out << std::endl;
return type;
}
+ /*! OCL to Gen-IR address type */
+ static INLINE ir::AddressSpace addressSpaceLLVMToGen(unsigned llvmMemSpace) {
+ switch (llvmMemSpace) {
+ case 0: return ir::MEM_PRIVATE;
+ case 1: return ir::MEM_GLOBAL;
+ case 2: return ir::MEM_CONSTANT;
+ case 4: return ir::MEM_LOCAL;
+ }
+ GBE_ASSERT(false);
+ return ir::MEM_GLOBAL;
+ }
/*! Handle the LLVM IR Value to Gen IR register translation. This has 2 roles:
* - Split the LLVM vector into several scalar values
void GenWriter::emitFunctionPrototype(Function &F)
{
GBE_ASSERTM(F.hasStructRetAttr() == false,
- "Returned value for kernel functions");
+ "Returned value for kernel functions is forbidden");
// Loop over the arguments and output registers for them
if (!F.arg_empty()) {
Function::arg_iterator I = F.arg_begin(), E = F.arg_end();
+ const AttrListPtr &PAL = F.getAttributes();
// Insert a new register for each function argument
- for (; I != E; ++I) {
- const Type *type = I->getType();
+ uint32_t argID = 1; // Start at one actually
+ for (; I != E; ++I, ++argID) {
+ Type *type = I->getType();
GBE_ASSERT(isScalarType(type) == true);
const ir::Register reg = regTranslator.newScalar(I);
- ctx.input(reg);
+ if (type->isPointerTy() == false)
+ ctx.input(ir::FunctionInput::VALUE, reg);
+ else {
+ PointerType *pointerType = dyn_cast<PointerType>(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);
+ }
+ // Regular user provided pointer (global, local or constant)
+ else {
+ const uint32_t addr = pointerType->getAddressSpace();
+ const ir::AddressSpace addrSpace = addressSpaceLLVMToGen(addr);
+ switch (addrSpace) {
+ case ir::MEM_GLOBAL:
+ ctx.input(ir::FunctionInput::GLOBAL_POINTER, reg);
+ break;
+ case ir::MEM_LOCAL:
+ ctx.input(ir::FunctionInput::LOCAL_POINTER, reg);
+ break;
+ case ir::MEM_CONSTANT:
+ ctx.input(ir::FunctionInput::CONSTANT_POINTER, reg);
+ break;
+ default: GBE_ASSERT(addrSpace != ir::MEM_PRIVATE);
+ }
+ }
+ }
}
}
// structure
const Type *type = F.getReturnType();
GBE_ASSERTM(type->isVoidTy() == true,
- "Returned value for kernel functions");
+ "Returned value for kernel functions is forbidden");
#if GBE_DEBUG
// Variable number of arguments is not supported
NOT_SUPPORTED;
}
- static INLINE ir::MemorySpace addressSpaceLLVMToGen(unsigned llvmMemSpace) {
- switch (llvmMemSpace) {
- case 0: return ir::MEM_PRIVATE;
- case 1: return ir::MEM_GLOBAL;
- case 4: return ir::MEM_LOCAL;
- }
- GBE_ASSERT(false);
- return ir::MEM_GLOBAL;
- }
-
static INLINE Value *getLoadOrStoreValue(LoadInst &I) {
return &I;
}
Value *llvmValues = getLoadOrStoreValue(I);
Type *llvmType = llvmValues->getType();
const bool dwAligned = (I.getAlignment() % 4) == 0;
- const ir::MemorySpace memSpace = addressSpaceLLVMToGen(llvmSpace);
+ const ir::AddressSpace addrSpace = addressSpaceLLVMToGen(llvmSpace);
const ir::Register ptr = this->getRegister(llvmPtr);
// Scalar is easy. We neednot build register tuples
const ir::Type type = getType(ctx, llvmType);
const ir::Register values = this->getRegister(llvmValues);
if (isLoad)
- ctx.LOAD(type, ptr, memSpace, dwAligned, values);
+ ctx.LOAD(type, ptr, addrSpace, dwAligned, values);
else
- ctx.STORE(type, ptr, memSpace, dwAligned, values);
+ ctx.STORE(type, ptr, addrSpace, dwAligned, values);
}
// A vector type requires to build a tuple
else {
// Emit the instruction
const ir::Type type = getType(ctx, elemType);
if (isLoad)
- ctx.LOAD(type, tuple, ptr, memSpace, elemNum, dwAligned);
+ ctx.LOAD(type, tuple, ptr, addrSpace, elemNum, dwAligned);
else
- ctx.STORE(type, tuple, ptr, memSpace, elemNum, dwAligned);
+ ctx.STORE(type, tuple, ptr, addrSpace, elemNum, dwAligned);
}
}