我通过llvm在我的OpenCL内核中创建了一个本地数组,称为大小为256 x i32的可查找数组。稍后,我通过llvm插入代码,用值填充数组。我的问题是,当我试图生成访问数组的代码时,我似乎无法正确地隔离指向我想要的元素的指针。如果使用名为平坦的模糊局部变量,则可能会错误地对元素进行索引:
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就是这样创建的(构建器是IRBuilder的一个实例):
std::vector<llvm::Value *> tmp_args;
tmp_args.push_back(builder.getInt32(0));
tmp_args.push_back(flattened);
Value *table_addr = builder.CreateGEP(M.getNamedGlobal(tablename), tmp_args, tablename+"_IDX");在本例中,M是Module对象。产生的table_addr是:
%i32_cllocal_TABLE_IDX = getelementptr [256 x i32] addrspace(3)* @i32_cllocal_TABLE, i32 0, i32 %FLATTENED但是,如果我想用for循环我的代码遍历LLVM中的索引来正确地填充它(省略循环结构,其中"index“是i32循环计数器):
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");在这种情况下,table_addr的转储()是(当index==0):
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这看起来不太正确,但更重要的是,当"index“>0时,我得到了一个断言的SIGABRT:
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.我有点卡住了。我不明白给数组索引的显式值与在运行时计算的一些模糊值之间的区别。任何见解都将不胜感激。
更新:我最后做的是这个(alloc只做了一次,我只是为了视觉目的将它包含在这个代码块中,它实际上在for循环之外):
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);发出此代码(用于索引== 0和1):
%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现在它看起来是正确的,但在我看来,这似乎是一种奇怪的emi代码方式,因为我正在存储,然后立即加载,但是我想这将得到优化,或者我将尝试使用那个mem2reg。谢谢你的帮助@Oak。
发布于 2014-01-09 06:23:25
这个片段有问题:
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");IRBuilder::getInt32创建一个常量int。因此,GEP将始终访问数组中的第一个项,这不是您想要的。这也是为什么IR显示的是恒定表达GEP而不是真正的GEP指令。您需要的是创建一个Value并使用它作为第二个索引--就像在第一个示例中所做的那样。
https://stackoverflow.com/questions/21009523
复制相似问题