ir::ImmediateIndex GenWriter::processSeqConstant(ConstantDataSequential *seq,
int index, ConstTypeId tid) {
if (index >= 0) {
const T data = GET_EFFECT_DATA(seq, index, tid);
return ctx.newImmediate(data);
} else {
vector array;
for(uint32_t i = 0; i < seq->getNumElements(); i++)
array.push_back(GET_EFFECT_DATA(seq, i, tid));
return ctx.newImmediate((T*)&array[0], array.size());
}
}
ir::ImmediateIndex GenWriter::processConstantVector(ConstantVector *cv, int index) {
if (index >= 0) {
Constant *c = cv->getOperand(index);
return processConstantImmIndex(c, -1);
} else {
vector immVector;
for (uint32_t i = 0; i < cv->getNumOperands(); i++)
immVector.push_back(processConstantImmIndex(cv->getOperand(i)));
return ctx.newImmediate(immVector, getType(ctx, cv->getType()->getElementType()));
}
}
ir::ImmediateIndex GenWriter::processConstantImmIndexImpl(Constant *CPV, int32_t index)
{
GBE_ASSERT(dyn_cast(CPV) == NULL);
ConstantDataSequential *seq = dyn_cast(CPV);
if (seq) {
Type *Ty = seq->getElementType();
if (Ty == Type::getInt1Ty(CPV->getContext())) {
return processSeqConstant(seq, index, CONST_INT);
} else if (Ty == Type::getInt8Ty(CPV->getContext())) {
return processSeqConstant(seq, index, CONST_INT);
} else if (Ty == Type::getInt16Ty(CPV->getContext())) {
return processSeqConstant(seq, index, CONST_INT);
} else if (Ty == Type::getInt32Ty(CPV->getContext())) {
return processSeqConstant(seq, index, CONST_INT);
} else if (Ty == Type::getInt64Ty(CPV->getContext())) {
return processSeqConstant(seq, index, CONST_INT);
} else if (Ty == Type::getFloatTy(CPV->getContext())) {
return processSeqConstant(seq, index, CONST_FLOAT);
} else if (Ty == Type::getDoubleTy(CPV->getContext())) {
return processSeqConstant(seq, index, CONST_DOUBLE);
} else if (Ty == Type::getHalfTy(CPV->getContext())) {
GBE_ASSERTM(0, "Const data array never be half float\n");
}
} else
if (dyn_cast(CPV)) {
Type* Ty = CPV->getType();
if(Ty->isVectorTy())
Ty = (cast(Ty))->getElementType();
if (Ty == Type::getInt1Ty(CPV->getContext())) {
const bool b = 0;
return ctx.newImmediate(b);
} else if (Ty == Type::getInt8Ty(CPV->getContext())) {
const uint8_t u8 = 0;
return ctx.newImmediate(u8);
} else if (Ty == Type::getInt16Ty(CPV->getContext())) {
const uint16_t u16 = 0;
return ctx.newImmediate(u16);
} else if (Ty == Type::getInt32Ty(CPV->getContext())) {
const uint32_t u32 = 0;
return ctx.newImmediate(u32);
} else if (Ty == Type::getInt64Ty(CPV->getContext())) {
const uint64_t u64 = 0;
return ctx.newImmediate(u64);
} else if (Ty == Type::getFloatTy(CPV->getContext())) {
const float f32 = 0;
return ctx.newImmediate(f32);
} else if (Ty == Type::getHalfTy(CPV->getContext())) {
const ir::half f16 = 0;
return ctx.newImmediate(f16);
} else if (Ty == Type::getDoubleTy(CPV->getContext())) {
const double f64 = 0;
return ctx.newImmediate(f64);
} else {
GBE_ASSERTM(false, "Unsupporte aggregate zero type.");
return ctx.newImmediate(uint32_t(0));
}
} else {
if (dyn_cast(CPV))
return processConstantVector(dyn_cast(CPV), index);
GBE_ASSERTM(dyn_cast(CPV) == NULL, "Unsupported constant expression");
// Integers
if (ConstantInt *CI = dyn_cast(CPV)) {
Type* Ty = CI->getType();
if (Ty == Type::getInt1Ty(CPV->getContext())) {
const bool b = CI->getZExtValue();
return ctx.newImmediate(b);
} else if (Ty == Type::getInt8Ty(CPV->getContext())) {
const uint8_t u8 = CI->getZExtValue();
return ctx.newImmediate(u8);
} else if (Ty == Type::getInt16Ty(CPV->getContext())) {
const uint16_t u16 = CI->getZExtValue();
return ctx.newImmediate(u16);
} else if (Ty == Type::getInt32Ty(CPV->getContext())) {
const uint32_t u32 = CI->getZExtValue();
return ctx.newImmediate(u32);
} else if (Ty == Type::getInt64Ty(CPV->getContext())) {
const uint64_t u64 = CI->getZExtValue();
return ctx.newImmediate(u64);
} else {
if (CI->getValue().getActiveBits() > 64) {
ctx.getUnit().setValid(false);
return ctx.newImmediate(uint64_t(0));
}
return ctx.newImmediate(uint64_t(CI->getZExtValue()));
}
}
// NULL pointers
if(isa(CPV)) {
if (ctx.getPointerFamily() == ir::FAMILY_QWORD)
return ctx.newImmediate(uint64_t(0));
else
return ctx.newImmediate(uint32_t(0));
}
const Type::TypeID typeID = CPV->getType()->getTypeID();
if (isa(CPV)) {
Type* Ty = CPV->getType();
if (Ty == Type::getInt1Ty(CPV->getContext())) return ctx.newImmediate(false);
if (Ty == Type::getInt8Ty(CPV->getContext())) return ctx.newImmediate((uint8_t)0);
if (Ty == Type::getInt16Ty(CPV->getContext())) return ctx.newImmediate((uint16_t)0);
if (Ty == Type::getInt32Ty(CPV->getContext())) return ctx.newImmediate((uint32_t)0);
if (Ty == Type::getInt64Ty(CPV->getContext())) return ctx.newImmediate((uint64_t)0);
if (Ty == Type::getFloatTy(CPV->getContext())) return ctx.newImmediate((float)0);
if (Ty == Type::getHalfTy(CPV->getContext())) return ctx.newImmediate((ir::half)0);
if (Ty == Type::getDoubleTy(CPV->getContext())) return ctx.newImmediate((double)0);
GBE_ASSERT(0 && "Unsupported undef value type.\n");
}
// Floats and doubles
switch (typeID) {
case Type::FloatTyID:
case Type::HalfTyID:
case Type::DoubleTyID:
{
ConstantFP *FPC = cast(CPV);
GBE_ASSERT(isa(CPV) == false);
if (FPC->getType() == Type::getFloatTy(CPV->getContext())) {
const float f32 = FPC->getValueAPF().convertToFloat();
return ctx.newImmediate(f32);
} else if (FPC->getType() == Type::getDoubleTy(CPV->getContext())) {
const double f64 = FPC->getValueAPF().convertToDouble();
return ctx.newImmediate(f64);
} else {
llvm::APFloat apf = FPC->getValueAPF();
llvm::APInt api = apf.bitcastToAPInt();
uint64_t v64 = api.getZExtValue();
uint16_t v16 = static_cast(v64);
const ir::half f16(v16);
return ctx.newImmediate(f16);
}
}
break;
default:
GBE_ASSERTM(false, "Unsupported constant type");
break;
}
}
GBE_ASSERTM(false, "Unsupported constant type");
return ctx.newImmediate(uint64_t(0));
}
ir::ImmediateIndex GenWriter::processConstantImmIndex(Constant *CPV, int32_t index) {
if (dyn_cast(CPV) == NULL)
return processConstantImmIndexImpl(CPV, index);
CPV->dump();
GBE_ASSERT(0 && "unsupported constant.\n");
return ctx.newImmediate((uint32_t)0);
}
const ir::Immediate &GenWriter::processConstantImm(Constant *CPV, int32_t index) {
ir::ImmediateIndex immIndex = processConstantImmIndex(CPV, index);
return ctx.getFunction().getImmediate(immIndex);
}
ir::ImmediateIndex GenWriter::newImmediate(Constant *CPV, uint32_t index) {
return processConstantImmIndex(CPV, index);
}
void GenWriter::newRegister(Value *value, Value *key, bool uniform) {
auto type = value->getType();
auto typeID = type->getTypeID();
switch (typeID) {
case Type::IntegerTyID:
case Type::FloatTyID:
case Type::HalfTyID:
case Type::DoubleTyID:
case Type::PointerTyID:
regTranslator.newScalar(value, key, 0, uniform);
break;
case Type::VectorTyID:
{
auto vectorType = cast(type);
const uint32_t elemNum = vectorType->getNumElements();
for (uint32_t elemID = 0; elemID < elemNum; ++elemID)
regTranslator.newScalar(value, key, elemID, uniform);
break;
}
case Type::StructTyID:
{
auto structType = cast(type);
const uint32_t elemNum = structType->getNumElements();
for (uint32_t elemID = 0; elemID < elemNum; ++elemID)
regTranslator.newScalar(value, key, elemID, uniform);
break;
}
default: NOT_SUPPORTED;
};
}
ir::Register GenWriter::getConstantRegister(Constant *c, uint32_t elemID) {
GBE_ASSERT(c != NULL);
if(isa(c)) {
return regTranslator.getScalar(c, elemID);
}
if(isa(c)) {
Type* llvmType = c->getType();
ir::Type dstType = getType(ctx, llvmType);
ir::Register reg = ctx.reg(getFamily(dstType));
ir::ImmediateIndex immIndex;
if(llvmType->isIntegerTy())
immIndex = ctx.newIntegerImmediate(0, dstType);
else if(llvmType->isFloatTy()) {
immIndex = ctx.newFloatImmediate((float)0.0);
} else {
immIndex = ctx.newDoubleImmediate((double)0.0);
}
ctx.LOADI(dstType, reg, immIndex);
return reg;
}
const ir::ImmediateIndex immIndex = this->newImmediate(c, elemID);
const ir::Immediate imm = ctx.getImmediate(immIndex);
const ir::Register reg = ctx.reg(getFamily(imm.getType()));
ctx.LOADI(imm.getType(), reg, immIndex);
return reg;
}
ir::Register GenWriter::getRegister(Value *value, uint32_t elemID) {
//the real value may be constant, so get real value before constant check
regTranslator.getRealValue(value, elemID);
if(isa(value)) {
Constant *c = dyn_cast(value);
return getConstantRegister(c, elemID);
} else
return regTranslator.getScalar(value, elemID);
}
INLINE Value *GenWriter::getPHICopy(Value *PHI) {
const uintptr_t ptr = (uintptr_t) PHI;
return (Value*) (ptr+1);
}
void GenWriter::newLabelIndex(const BasicBlock *bb) {
if (labelMap.find(bb) == labelMap.end()) {
const ir::LabelIndex label = ctx.label();
labelMap[bb] = label;
}
}
void GenWriter::simplifyTerminator(BasicBlock *bb) {
Value *value = bb->getTerminator();
BranchInst *I = NULL;
if ((I = dyn_cast(value)) != NULL) {
if (I->isConditional() == false)
return;
// If the "taken" successor is the next block, we try to invert the
// branch.
BasicBlock *succ = I->getSuccessor(0);
if (std::next(Function::iterator(bb)) != Function::iterator(succ))
return;
// More than one use is too complicated: we skip it
Value *condition = I->getCondition();
if (condition->hasOneUse() == false)
return;
// Right now, we only invert comparison instruction
ICmpInst *CI = dyn_cast(condition);
if (CI != NULL) {
GBE_ASSERT(conditionSet.find(CI) == conditionSet.end());
conditionSet.insert(CI);
return;
}
}
}
void GenWriter::emitBasicBlock(BasicBlock *BB) {
GBE_ASSERT(labelMap.find(BB) != labelMap.end());
ctx.LABEL(labelMap[BB]);
for (auto II = BB->begin(), E = BB->end(); II != E; ++II) {
if(OCL_DEBUGINFO) {
llvm::Instruction * It = dyn_cast(II);
setDebugInfo_CTX(It);
}
visit(*II);
}
}
void GenWriter::emitMovForPHI(BasicBlock *curr, BasicBlock *succ) {
for (BasicBlock::iterator I = succ->begin(); isa(I); ++I) {
PHINode *PN = cast(I);
Value *IV = PN->getIncomingValueForBlock(curr);
Type *llvmType = PN->getType();
const ir::Type type = getType(ctx, llvmType);
Value *PHICopy = this->getPHICopy(PN);
const ir::Register dst = this->getRegister(PHICopy);
if (!isa(IV)) {
// Emit the MOV required by the PHI function. We do it simple and do not
// try to optimize them. A next data flow analysis pass on the Gen IR
// will remove them
Constant *CP = dyn_cast(IV);
if (CP) {
GBE_ASSERT(isa(CP) == false);
ConstantVector *CPV = dyn_cast(CP);
if (CPV && dyn_cast(CPV) &&
isa(extractConstantElem(CPV, 0)))
continue;
ctx.MOV(type, dst, getRegister(CP));
} else if (regTranslator.valueExists(IV,0) || dyn_cast(IV)) {
const ir::Register src = this->getRegister(IV);
ctx.MOV(type, dst, src);
}
assert(!ctx.getBlock()->undefPhiRegs.contains(dst));
ctx.getBlock()->definedPhiRegs.insert(dst);
} else {
// If this is an undefined value, we don't need emit phi copy here.
// But we need to record it. As latter, at liveness's backward analysis,
// we don't need to pass the phi value/register to this BB which the phi
// value is undefined. Otherwise, the phi value's liveness will be extent
// incorrectly and may be extent to the basic block zero which is really bad.
ctx.getBlock()->undefPhiRegs.insert(dst);
}
}
}
/*! To track read image args and write args */
struct ImageArgsInfo{
uint32_t readImageArgs;
uint32_t writeImageArgs;
};
static void collectImageArgs(std::string& accessQual, ImageArgsInfo& imageArgsInfo)
{
if(accessQual.find("read") != std::string::npos)
{
imageArgsInfo.readImageArgs++;
GBE_ASSERT(imageArgsInfo.readImageArgs <= BTI_MAX_READ_IMAGE_ARGS);
}
else if(accessQual.find("write") != std::string::npos)
{
imageArgsInfo.writeImageArgs++;
GBE_ASSERT(imageArgsInfo.writeImageArgs <= BTI_MAX_WRITE_IMAGE_ARGS);
}
else
{
//default is read_only per spec.
imageArgsInfo.readImageArgs++;
GBE_ASSERT(imageArgsInfo.readImageArgs <= BTI_MAX_READ_IMAGE_ARGS);
}
}
void GenWriter::setDebugInfo_CTX(llvm::Instruction * insn)
{
llvm::DebugLoc dg = insn->getDebugLoc();
DebugInfo dbginfo;
dbginfo.line = dg.getLine();
dbginfo.col = dg.getCol();
ctx.setDBGInfo(dbginfo);
}
void GenWriter::emitFunctionPrototype(Function &F)
{
GBE_ASSERTM(F.hasStructRetAttr() == false,
"Returned value for kernel functions is forbidden");
// Loop over the kernel metadatas to set the required work group size.
size_t reqd_wg_sz[3] = {0, 0, 0};
size_t hint_wg_sz[3] = {0, 0, 0};
size_t reqd_sg_sz = 0;
ir::FunctionArgument::InfoFromLLVM llvmInfo;
MDNode *addrSpaceNode = NULL;
MDNode *typeNameNode = NULL;
MDNode *typeBaseNameNode = NULL;
MDNode *accessQualNode = NULL;
MDNode *typeQualNode = NULL;
MDNode *argNameNode = NULL;
std::string functionAttributes;
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39
/* LLVM 3.9 change kernel arg info as function metadata */
addrSpaceNode = F.getMetadata("kernel_arg_addr_space");
accessQualNode = F.getMetadata("kernel_arg_access_qual");
typeNameNode = F.getMetadata("kernel_arg_type");
typeBaseNameNode = F.getMetadata("kernel_arg_base_type");
typeQualNode = F.getMetadata("kernel_arg_type_qual");
argNameNode = F.getMetadata("kernel_arg_name");
MDNode *attrNode;
if ((attrNode = F.getMetadata("vec_type_hint"))) {
GBE_ASSERT(attrNode->getNumOperands() == 2);
functionAttributes += "vec_type_hint";
auto *Op1 = cast(attrNode->getOperand(0));
Value *V = Op1 ? Op1->getValue() : NULL;
ConstantInt *sign =
mdconst::extract(attrNode->getOperand(1));
size_t signValue = sign->getZExtValue();
Type *vtype = V->getType();
Type *stype = vtype;
uint32_t elemNum = 0;
if (vtype->isVectorTy()) {
VectorType *vectorType = cast(vtype);
stype = vectorType->getElementType();
elemNum = vectorType->getNumElements();
}
std::string typeName = getTypeName(ctx, stype, signValue);
std::stringstream param;
char buffer[100] = {0};
param << "(";
param << typeName;
if (vtype->isVectorTy())
param << elemNum;
param << ")";
param >> buffer;
functionAttributes += buffer;
functionAttributes += " ";
}
if ((attrNode = F.getMetadata("reqd_work_group_size"))) {
GBE_ASSERT(attrNode->getNumOperands() == 3);
ConstantInt *x = mdconst::extract(attrNode->getOperand(0));
ConstantInt *y = mdconst::extract(attrNode->getOperand(1));
ConstantInt *z = mdconst::extract(attrNode->getOperand(2));
GBE_ASSERT(x && y && z);
reqd_wg_sz[0] = x->getZExtValue();
reqd_wg_sz[1] = y->getZExtValue();
reqd_wg_sz[2] = z->getZExtValue();
functionAttributes += "reqd_work_group_size";
std::stringstream param;
char buffer[100] = {0};
param << "(";
param << reqd_wg_sz[0];
param << ",";
param << reqd_wg_sz[1];
param << ",";
param << reqd_wg_sz[2];
param << ")";
param >> buffer;
functionAttributes += buffer;
functionAttributes += " ";
}
if ((attrNode = F.getMetadata("work_group_size_hint"))) {
GBE_ASSERT(attrNode->getNumOperands() == 3);
ConstantInt *x = mdconst::extract(attrNode->getOperand(0));
ConstantInt *y = mdconst::extract(attrNode->getOperand(1));
ConstantInt *z = mdconst::extract(attrNode->getOperand(2));
GBE_ASSERT(x && y && z);
hint_wg_sz[0] = x->getZExtValue();
hint_wg_sz[1] = y->getZExtValue();
hint_wg_sz[2] = z->getZExtValue();
functionAttributes += "work_group_size_hint";
std::stringstream param;
char buffer[100] = {0};
param << "(";
param << hint_wg_sz[0];
param << ",";
param << hint_wg_sz[1];
param << ",";
param << hint_wg_sz[2];
param << ")";
param >> buffer;
functionAttributes += buffer;
functionAttributes += " ";
}
if ((attrNode = F.getMetadata("intel_reqd_sub_group_size"))) {
GBE_ASSERT(attrNode->getNumOperands() == 1);
ConstantInt *sz = mdconst::extract(attrNode->getOperand(0));
GBE_ASSERT(sz);
reqd_sg_sz = sz->getZExtValue();
if(!(reqd_sg_sz == 8 || reqd_sg_sz == 16)){
F.getContext().emitError("Required sub group size is illegal!");
ctx.getUnit().setValid(false);
return;
}
functionAttributes += "intel_reqd_sub_group_size";
std::stringstream param;
char buffer[100] = {0};
param << "(";
param << reqd_sg_sz;
param << ")";
param >> buffer;
functionAttributes += buffer;
functionAttributes += " ";
}
#else
/* First find the meta data belong to this function. */
MDNode *node = getKernelFunctionMetadata(&F);
/* because "-cl-kernel-arg-info", should always have meta data. */
if (!F.arg_empty())
assert(node);
for(uint j = 0; node && j < node->getNumOperands() - 1; j++) {
MDNode *attrNode = dyn_cast_or_null(node->getOperand(1 + j));
if (attrNode == NULL) break;
MDString *attrName = dyn_cast_or_null(attrNode->getOperand(0));
if (!attrName) continue;
if (attrName->getString() == "reqd_work_group_size") {
GBE_ASSERT(attrNode->getNumOperands() == 4);
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR <= 35
ConstantInt *x = dyn_cast(attrNode->getOperand(1));
ConstantInt *y = dyn_cast(attrNode->getOperand(2));
ConstantInt *z = dyn_cast(attrNode->getOperand(3));
#else
ConstantInt *x = mdconst::extract(attrNode->getOperand(1));
ConstantInt *y = mdconst::extract(attrNode->getOperand(2));
ConstantInt *z = mdconst::extract(attrNode->getOperand(3));
#endif
GBE_ASSERT(x && y && z);
reqd_wg_sz[0] = x->getZExtValue();
reqd_wg_sz[1] = y->getZExtValue();
reqd_wg_sz[2] = z->getZExtValue();
functionAttributes += attrName->getString();
std::stringstream param;
char buffer[100] = {0};
param <<"(";
param << reqd_wg_sz[0];
param << ",";
param << reqd_wg_sz[1];
param << ",";
param << reqd_wg_sz[2];
param <<")";
param >> buffer;
functionAttributes += buffer;
functionAttributes += " ";
break;
} else if (attrName->getString() == "kernel_arg_addr_space") {
addrSpaceNode = attrNode;
} else if (attrName->getString() == "kernel_arg_access_qual") {
accessQualNode = attrNode;
} else if (attrName->getString() == "kernel_arg_type") {
typeNameNode = attrNode;
} else if (attrName->getString() == "kernel_arg_base_type") {
typeBaseNameNode = attrNode;
} else if (attrName->getString() == "kernel_arg_type_qual") {
typeQualNode = attrNode;
} else if (attrName->getString() == "kernel_arg_name") {
argNameNode = attrNode;
} else if (attrName->getString() == "vec_type_hint") {
GBE_ASSERT(attrNode->getNumOperands() == 3);
functionAttributes += attrName->getString();
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR <= 35
Value* V = attrNode->getOperand(1);
#else
auto *Op1 = cast(attrNode->getOperand(1));
Value *V = Op1 ? Op1->getValue() : NULL;
#endif
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR <= 35
ConstantInt *sign = dyn_cast(attrNode->getOperand(2));
#else
ConstantInt *sign = mdconst::extract(attrNode->getOperand(2));
#endif
size_t signValue = sign->getZExtValue();
Type* vtype = V->getType();
Type* stype = vtype;
uint32_t elemNum = 0;
if(vtype->isVectorTy()) {
VectorType *vectorType = cast(vtype);
stype = vectorType->getElementType();
elemNum = vectorType->getNumElements();
}
std::string typeName = getTypeName(ctx, stype, signValue);
std::stringstream param;
char buffer[100] = {0};
param <<"(";
param << typeName;
if(vtype->isVectorTy())
param << elemNum;
param <<")";
param >> buffer;
functionAttributes += buffer;
functionAttributes += " ";
} else if (attrName->getString() == "work_group_size_hint") {
GBE_ASSERT(attrNode->getNumOperands() == 4);
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR <= 35
ConstantInt *x = dyn_cast(attrNode->getOperand(1));
ConstantInt *y = dyn_cast(attrNode->getOperand(2));
ConstantInt *z = dyn_cast(attrNode->getOperand(3));
#else
ConstantInt *x = mdconst::extract(attrNode->getOperand(1));
ConstantInt *y = mdconst::extract(attrNode->getOperand(2));
ConstantInt *z = mdconst::extract(attrNode->getOperand(3));
#endif
GBE_ASSERT(x && y && z);
hint_wg_sz[0] = x->getZExtValue();
hint_wg_sz[1] = y->getZExtValue();
hint_wg_sz[2] = z->getZExtValue();
functionAttributes += attrName->getString();
std::stringstream param;
char buffer[100] = {0};
param <<"(";
param << hint_wg_sz[0];
param << ",";
param << hint_wg_sz[1];
param << ",";
param << hint_wg_sz[2];
param <<")";
param >> buffer;
functionAttributes += buffer;
functionAttributes += " ";
}
}
#endif /* LLVM 3.9 Function metadata */
ctx.getFunction().setCompileWorkGroupSize(reqd_wg_sz[0], reqd_wg_sz[1], reqd_wg_sz[2]);
if (reqd_sg_sz)
ctx.setSimdWidth(reqd_sg_sz);
ctx.getFunction().setFunctionAttributes(functionAttributes);
// Loop over the arguments and output registers for them
if (!F.arg_empty()) {
uint32_t argID = 0;
ImageArgsInfo imageArgsInfo = {};
Function::arg_iterator I = F.arg_begin(), E = F.arg_end();
// Insert a new register for each function argument
for (; I != E; ++I, ++argID) {
uint32_t opID = argID;
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR < 39
opID += 1;
#endif
const std::string &argName = I->getName().str();
Type *type = I->getType();
if(addrSpaceNode) {
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR <= 35
llvmInfo.addrSpace = (cast(addrSpaceNode->getOperand(opID)))->getZExtValue();
#else
llvmInfo.addrSpace = (mdconst::extract(addrSpaceNode->getOperand(opID)))->getZExtValue();
#endif
}
if(typeNameNode) {
llvmInfo.typeName = (cast(typeNameNode->getOperand(opID)))->getString();
//LLVM 3.9 image's type name include access qual, don't match OpenCL spec, erase them.
std::vector filters = {"__read_only ", "__write_only "};
for (uint32_t i = 0; i < filters.size(); i++) {
size_t pos = llvmInfo.typeName.find(filters[i]);
if (pos != std::string::npos) {
llvmInfo.typeName = llvmInfo.typeName.erase(pos, filters[i].length());
}
}
}
if(typeBaseNameNode){
llvmInfo.typeBaseName = (cast(typeBaseNameNode->getOperand(opID)))->getString();
}
if(accessQualNode) {
llvmInfo.accessQual = (cast(accessQualNode->getOperand(opID)))->getString();
}
if(typeQualNode) {
llvmInfo.typeQual = (cast(typeQualNode->getOperand(opID)))->getString();
}
if(argNameNode){
llvmInfo.argName = (cast