c++ - llvm getelementptr 得到错误的值
问题描述
我正在学习 llvm getelementptr 指令,并尝试从结构中获取元素。我的结构是这样的,
struct Foo {
int32_t a;
int32_t b;
int32_t c;
};
对应的 llvm 类型:
Type *getType() {
vector<Type *> tps;
tps.push_back(Type::getInt32Ty(TheContext));
tps.push_back(Type::getInt32Ty(TheContext));
tps.push_back(Type::getInt32Ty(TheContext));
StructType *tp = StructType::create(TheContext, tps, "foo_type");
return tp;
}
和一个测试功能,
%foo_type = type { i32, i32, i32 }
define i32 @_func_(%foo_type) {
entry:
%1 = alloca %foo_type
store %foo_type %0, %foo_type* %1
%2 = getelementptr %foo_type, %foo_type* %1, i32 0, i32 1
%3 = load i32, i32* %2
ret i32 %3
}
但是通过运行编译函数,我总是得到第三个元素,即 Foo::c,而不是 Foo::b,那么我的代码有什么问题?我认为问题可能出在商店说明上。
编辑 2019.12.13
通过将指针作为参数传递,我得到了正确的答案
define i32 @_func_(%foo_type*) {
entry:
%1 = alloca %foo_type*
store %foo_type* %0, %foo_type** %1
%ptr = load %foo_type*, %foo_type** %1
%2 = getelementptr %foo_type, %foo_type* %ptr, i32 0, i32 1
%3 = load i32, i32* %2
ret i32 %3
}
所以问题一定FP(f)
是实际上并没有传递f
给以前版本中的编译函数。
解决方案
如果你用 c 编写函数并让 clang 为它发出 IR,你会看到:
struct Foo {
int a;
int b;
int c;
};
int bar(Foo f) {
return f.b;
}
define dso_local i32 @_Z3bar3Foo(i64, i32) #0 {
%3 = alloca %struct.Foo, align 4
%4 = alloca { i64, i32 }, align 4
%5 = getelementptr inbounds { i64, i32 }, { i64, i32 }* %4, i32 0, i32 0
store i64 %0, i64* %5, align 4
%6 = getelementptr inbounds { i64, i32 }, { i64, i32 }* %4, i32 0, i32 1
store i32 %1, i32* %6, align 4
%7 = bitcast %struct.Foo* %3 to i8*
%8 = bitcast { i64, i32 }* %4 to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %7, i8* align 4 %8, i64 12, i1 false)
%9 = getelementptr inbounds %struct.Foo, %struct.Foo* %3, i32 0, i32 1
%10 = load i32, i32* %9, align 4
ret i32 %10
}
这意味着bar(Foo())
实际上是接受int64
和int32
作为参数,而不是Foo
本身。它可能是一些我不太了解的 c/cpp ABI。
但是通过指针传递时,就没有这样的问题,所以它按预期工作。
推荐阅读
- jquery - jQuery - 将输入附加到标签中
- android - 在 FragmentPagerAdapter 中改造 GET
- jquery - JQGrid 按列排序仅在使用分页后有效
- c# - 无法使用 as 运算符或简单转换将列表转换或转换为另一个列表
- jquery-selectors - 在 Cypress 中优化选择器
- ffmpeg - ffmpeg 从顶部屏幕裁剪视频
- node.js - 使用 NodeJS 承诺在 DynamoDB 中创建记录
- html - 带有不可点击链接的轮播,而是点击上一个链接
- c++ - 对数字范围使用 boost
- python - 使用 selenium 遍历列表