使用 LLVM 分配和访问堆数组

发布于 2025-01-16 05:25:54 字数 2364 浏览 0 评论 0 原文

从万花筒教程和堆栈交换问题开始(问题)我尝试使用 LLVM 输出一些数组创建和访问代码。这个想法是有一个“alloca”堆栈变量“a”,它保存一个 double* 指向用 malloc 分配的数组。 生成的代码失败,我相信主要问题是我在 C++ 中调用“CreateInBoundsGEP”。

所以我一句话的主要问题是“如何调用 CreateInBoundsGEP 以便它输出正确的 IR 代码?”

我尝试的内容如下:

我的分配代码是作为上述问题中 llvm c++ 接口的“CreateMalloc”调用的输出而创建的。

%a = alloca double*, align 8
%malloccall = tail call i8* @malloc(i32 48)
%0 = bitcast i8* %malloccall to double*
store double* %0, double** %a, align 8

这段代码对我来说看起来不错,但在使用 verifyFunction() 检查时它已经导致错误/警告。

Call parameter type does not match function signature!
i32 48

遗憾的是它没有告诉我正确的参数类型是什么(i64?)。 IR 参考根本没有提到“malloc”函数调用,而是提到了“malloc”IR 操作(参考)!

我的主要问题(如果之前没有捕获的话也会导致内存错误)发生在对数组的写访问上。

我的第一次尝试是直接从引用的堆栈交换问题 1

//ret is the base adress of the pointer, ie "a"
//rhs is the Value* to the right hand side that is assigned
//index is the Value* to the array index 
auto element_ptr = Builder->CreateInBoundsGEP(ret, index, "acc_tmp");
Builder->CreateStore(rhs, element_ptr);

哪个输出(对于 a[1]=5 作为输入代码)

%acc_tmp = getelementptr inbounds double*, double** %a, i32 1
store double 5.000000e+00, double** %acc_tmp, align 8

这会创建一个“verifyFunction”错误,我可以看到“double**”可能应该是“double*” ”。 由于我还收到了弃用警告,因此我决定尝试使用类型参数的 CreateInBoundsGEP。 由于文档没有告诉我“Type”应该是元素类型还是指针类型,所以我尝试了两者

auto element_ptr = Builder->CreateInBoundsGEP(rhs->getType()->getPointerTo(), ret, index, "acc_tmp");

auto element_ptr = Builder->CreateInBoundsGEP(rhs->getType(), ret, index, "acc_tmp");

两者都不起作用,第一个版本输出与不传递类型相同的代码,第二个版本导致

static llvm::GetElementPtrInst *llvm::GetElementPtrInst::Create(llvm::Type *, llvm::Value *, ArrayRef<llvm::Value *>, const llvm::Twine &, llvm::Instruction *): Assertion `cast<PointerType>(Ptr->getType()->getScalarType()) ->isOpaqueOrPointeeTypeMatches(PointeeType)' failed.

Starting with the caleidoscope tutorial and a stack exchange question (question) I tried to output some array-creation and access code with LLVM. The idea is to have an "alloca" stack variable "a" which holds a double* pointing to an array allocated with malloc.
The generated code fails, and I believe that the main problem is my Call to "CreateInBoundsGEP" in C++.

So my main question in one sentence is "How to Call CreateInBoundsGEP so that it outputs the right IR code?"

What i tried is the following:

My allocation code is created as output of the llvm c++ interface's "CreateMalloc" call from the question referenced above.

%a = alloca double*, align 8
%malloccall = tail call i8* @malloc(i32 48)
%0 = bitcast i8* %malloccall to double*
store double* %0, double** %a, align 8

This code looks good to me, but it already leads to an error/warning when checked with verifyFunction().

Call parameter type does not match function signature!
i32 48

Sadly it does not tell me, what the right parameter type would be (i64?). The IR reference does not refer to the "malloc"-function call at all but mentions a "malloc" IR-operation instead (reference)!

My main problem (also leading to memory errors if not caught before) occurs with write access to the array.

My first try was copying (more or less) directly from the referenced stack exchange question 1:

//ret is the base adress of the pointer, ie "a"
//rhs is the Value* to the right hand side that is assigned
//index is the Value* to the array index 
auto element_ptr = Builder->CreateInBoundsGEP(ret, index, "acc_tmp");
Builder->CreateStore(rhs, element_ptr);

Which outputs (for a[1]=5 as input code)

%acc_tmp = getelementptr inbounds double*, double** %a, i32 1
store double 5.000000e+00, double** %acc_tmp, align 8

This creates a "verifyFunction" error and I can see that "double**" should probably be "double*".
Since I also got a deprecation warning, I decided to try the CreateInBoundsGEP with a type parameter.
Since the documentation does not tell me whether "Type" should be the element or pointer type, I tried both

auto element_ptr = Builder->CreateInBoundsGEP(rhs->getType()->getPointerTo(), ret, index, "acc_tmp");

Or

auto element_ptr = Builder->CreateInBoundsGEP(rhs->getType(), ret, index, "acc_tmp");

Both do not work, the first version outputs the same code as without passing a type, the second version leads to

static llvm::GetElementPtrInst *llvm::GetElementPtrInst::Create(llvm::Type *, llvm::Value *, ArrayRef<llvm::Value *>, const llvm::Twine &, llvm::Instruction *): Assertion `cast<PointerType>(Ptr->getType()->getScalarType()) ->isOpaqueOrPointeeTypeMatches(PointeeType)' failed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

绅刃 2025-01-23 05:25:55

正如我在最初的问题中注意到的那样,我的指令中有一个指针*太多。最初我不明白为什么会出现这种情况,但后来我在一个看似不相关的问题中找到了我的问题的答案 1

如果直接使用“CreateMalloc”的返回值作为“CreateInBoundsGEP”的参数,我最初从2 可以工作。

然而,就我而言,还涉及一个步骤:我将“CreateMalloc”返回值存储在一个局部变量中,该变量又由分配有“alloca”的指针引用。因此,与原始代码片段相比,我需要一个额外的取消引用步骤来访问我的数组元素。

正如 1 中提到的,LLVM-IR 中的取消引用只是一个“加载”。所以正确的数组访问代码看起来像

//ret is the pointer to(!) the base adress of the array, ie "a"
//rhs is the Value* to the right hand side that is assigned
//index is the Value* holding the array index 
llvm::Value* index = visit(ctx->index).as<llvm::Value*>();
llvm::Value* ret_deref =   Builder->CreateLoad(llvm::Type::getDoubleTy(*TheContext)->getPointerTo(),ret,"deref_tmp");
auto element_ptr = Builder->CreateInBoundsGEP(rhs->getType(), ret_deref, index, "acc_tmp");
Builder->CreateStore(rhs, element_ptr);

As I noticed in my original question, there is one pointer* too much in my instruction. Initially I did not understand why this is the case, but then I found the answer to my problem in a seemingly unrelated question 1:

If you directly use the return value of "CreateMalloc" as argument for a "CreateInBoundsGEP", the Code that I originally copied from 2 will work.

However in my case there is one more step involved: I store the "CreateMalloc" return value in a local variable, which in turn is referenced by a pointer allocated with "alloca". Because of this, I need one additional dereferencing step compared to the original Code Snippet to access my array elements.

As mentioned in 1 a dereference in LLVM-IR is just a "load". So a correct array access code looks like

//ret is the pointer to(!) the base adress of the array, ie "a"
//rhs is the Value* to the right hand side that is assigned
//index is the Value* holding the array index 
llvm::Value* index = visit(ctx->index).as<llvm::Value*>();
llvm::Value* ret_deref =   Builder->CreateLoad(llvm::Type::getDoubleTy(*TheContext)->getPointerTo(),ret,"deref_tmp");
auto element_ptr = Builder->CreateInBoundsGEP(rhs->getType(), ret_deref, index, "acc_tmp");
Builder->CreateStore(rhs, element_ptr);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文