用于OpenCL本地阵列访问的LLVM-IR GEP

用于OpenCL本地阵列访问的LLVM-IR GEP,opencl,llvm,llvm-ir,Opencl,Llvm,Llvm Ir,我通过llvm在OpenCL内核中创建了一个本地数组,称之为[256 x i32]大小的lookuptable。 稍后,我通过llvm插入代码,用值填充数组。我的问题是,当我试图生成访问数组的代码时,我似乎无法正确地隔离指向所需元素的指针。如果使用一个名为Flatten的模糊局部变量,则可能会错误地索引到元素: Value *xs_ys_mul = builder.CreateMul(shifted_x_size, y_size, "xs_ys_mul"); Value *xs_ys_z_m

我通过llvm在OpenCL内核中创建了一个本地数组,称之为[256 x i32]大小的lookuptable。 稍后,我通过llvm插入代码,用值填充数组。我的问题是,当我试图生成访问数组的代码时,我似乎无法正确地隔离指向所需元素的指针。如果使用一个名为Flatten的模糊局部变量,则可能会错误地索引到元素:

Value *xs_ys_mul   = builder.CreateMul(shifted_x_size, y_size, "xs_ys_mul");
Value *xs_ys_z_mul = builder.CreateMul(xs_ys_mul, z, "xs_ys_z_mul");
Value *xs_y_mul    = builder.CreateMul(shifted_x_size, y, "xs_y_mul");
Value *sum_1       = builder.CreateAdd(xs_ys_z_mul, xs_y_mul, "sum_1");
Value *flattened   = builder.CreateAdd(sum_1, shifted_x, "FLATTENED");
这将是维度平坦的本地工作组id。但这与此无关

GEP是如何创建的(builder是IRBuilder的一个实例):

但是,如果我想通过使用for循环遍历LLVM中的索引来正确填充代码(省略循环结构,其中“index”是i32循环计数器):

这意味着当我去商店的时候:

store_inst = builder.CreateStore(builder.getInt32(tablevalues[index]), table_addr);
我得到这个输出:

store volatile i32 0, i32 addrspace(3)* getelementptr inbounds ([256 x i32] addrspace(3)* @i32_cllocal_TABLE, i32 0, i32 0), align 4
这看起来不对,但更重要的是,当“索引”>0时,我在断言上得到了一个SIGABRT:


它现在看起来是正确的,但对我来说,这似乎是一种奇怪的emi编码方式,因为我正在存储然后立即加载,但我想这会得到优化,或者我会尝试使用mem2reg。感谢@Oak的帮助。

这段代码有问题:

std::vector<llvm::Value *> tmp_args;
tmp_args.push_back(builder.getInt32(0));
tmp_args.push_back(builder.getInt32(index));
Value *table_addr = builder.CreateGEP(M.getNamedGlobal(tablename), tmp_args, tablename+"_IDX");
std::向量tmp_参数;
tmp参数推回(builder.getInt32(0));
tmp_参数push_back(builder.getInt32(index));
Value*table_addr=builder.CreateGEP(M.getNamedGlobal(tablename),tmp_参数,tablename+“_IDX”);

IRBuilder::getInt32
创建一个常量int。因此GEP将始终访问数组中的第一项,这不是您想要的。这也是IR显示实际GEP指令而不是实际GEP指令的原因。您需要创建一个
并将其用作第二个索引,就像您在第一个示例中所做的那样。

我尝试创建一个值并将其传递到CreateGEP,但llvm无法将其识别为值。我甚至尝试获取M.getNamedGlobal(tablename),从ptrtoint转换它,添加偏移量,然后在存储中使用它将其转换回ptr,但没有效果。我要尝试的一件事是,创建一个私有变量,将索引加载到其中,读取索引,然后使用该值将其索引到数组中,这似乎有些过分。当我试图将值填充到本地数组中时,这似乎是一种疯狂的方式。我是个新手,建议?那也没用。这似乎是一个基本的问题,我不理解这里的概念。基本上,我在这里要做的就是用编译时已知的值顺序为数组中的每个元素赋值。唯一的方法是通过数组建立索引,但我无法获得正确的语法@Oak@redratio1使用私有变量的想法非常好——您可以稍后运行mem2reg过程,该过程将优化本地变量,同时保持相同的语义,这就是Clang所做的。在任何一种情况下,如果您有一个特定的代码段不起作用,请将其编辑到您的问题中(或打开一个新问题)-我很难想象代码。
i32 addrspace(3)* getelementptr inbounds ([256 x i32] addrspace(3)* @i32_cllocal_CRC32_TABLE, i32 0, i32 0)
store_inst = builder.CreateStore(builder.getInt32(tablevalues[index]), table_addr);
store volatile i32 0, i32 addrspace(3)* getelementptr inbounds ([256 x i32] addrspace(3)* @i32_cllocal_TABLE, i32 0, i32 0), align 4
Casting.h:194: typename llvm::cast_retty<To, From>::ret_type llvm::cast(const Y&) [with X = llvm::CompositeType, Y = llvm::Type*]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
std::vector<llvm::Value *> tmp_args;
tmp_args.push_back(builder.getInt32(0));
idxInst = builder.CreateAlloca(builder.getInt32Ty(), 0, "idxvalue");
//----- Inside the loop below --------------------------------------
idxStore = builder.CreateStore(builder.getInt32(index), idxInst);
indexValue = builder.CreateLoad(idxInst, "INDEX_VAL");
tmp_args.push_back(indexValue);
table_addr = builder.CreateGEP(table_ptr, tmp_args, "_IDX_PUT");
tmp_args.pop_back();
store_inst = builder.CreateStore(builder.getInt32(tableValues[index]), table_addr, "_ELEM_STORE");
store_inst->setAlignment(4);
%idxvalue = alloca i32
store i32 0, i32* %idxvalue
%INDEX_VAL = load i32* %idxvalue
%i32_cllocal_TABLE_IDX_PUT = getelementptr [256 x i32] addrspace(3)*  @i32_cllocal_TABLE, i32 0, i32 %INDEX_VAL
store volatile i32 0, i32 addrspace(3)* %i32_cllocal_TABLE_IDX_PUT, align 4
store i32 1, i32* %idxvalue
%INDEX_VAL1 = load i32* %idxvalue
%i32_cllocal_TABLE_IDX_PUT2 = getelementptr [256 x i32] addrspace(3)* @i32_cllocal_TABLE, i32 0, i32 %INDEX_VAL1
store volatile i32 1996959894, i32 addrspace(3)* %i32_cllocal_TABLE_IDX_PUT2, align 4
std::vector<llvm::Value *> tmp_args;
tmp_args.push_back(builder.getInt32(0));
tmp_args.push_back(builder.getInt32(index));
Value *table_addr = builder.CreateGEP(M.getNamedGlobal(tablename), tmp_args, tablename+"_IDX");