You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LLVM 15 API生成ptr类型无效IR问题求助(OCaml实现)

问题:LLVM 15不透明指针下ptr*类型无效的编译错误

我正在使用LLVM 15与OCaml开发一款类Pascal语法的自定义语言编译器。当创建包含ptr元素的结构体,通过getelementptr获取其字段引用并执行存储操作时,生成了含ptr类型的无效IR。手动将ptr改为ptr后可正常编译,现咨询:

  1. 为何ptr*不被允许(C中指针的指针是合法的);
  2. 如何在OCaml代码中修复该问题(也可提供C++ API方案)。不透明指针已带来诸多困扰。

附相关代码及错误信息

OCaml代码

let frame = named_struct_type llvm.context "frame1" in
struct_set_body frame ([| pointer_type2 llvm.ctx |]) false;
let frame_ptr = build_alloca frame ("frame_ptr") llvm.builder in
let base = build_struct_gep2 frame frame_ptr 0 "frame_elem_ptr" llvm.builder in
ignore (build_store v base llvm.builder);

其中v为类型ptr的函数参数auxiliary。

生成的IR

%frame = type { ptr }
  %frame_ptr = alloca %frame, align 8
  %frame_elem_ptr = getelementptr inbounds %frame, %frame* %frame_ptr, i32 0, i32 0
  store ptr %auxiliary, ptr* %frame_elem_ptr, align 8

编译错误

llc-15: error: llc-15: llvm_ir.ll:54:28: error: ptr* is invalid - use ptr instead

解答

1. 为何ptr*不被允许?

LLVM的不透明指针(Opaque Pointers)模型和C语言的指针逻辑存在本质差异:

  • C语言中,int**这类多级指针是语法层面的层级表示,用来明确“指向指针的指针”;
  • 但LLVM的ptr是无类型的不透明指针,它统一指代所有指针类型,不管是一级、二级还是更高级,都不需要通过加星号来区分。在不透明指针模型里,根本不存在ptr*这种类型,所有指针都只用ptr表示,因此编译器会报错。

你手动修改后能正常编译,就是因为符合了不透明指针模型的规则。

2. 代码修复方案

OCaml API修复

问题出在build_struct_gep2是适配旧类型指针模型的API,生成了ptr*这种不符合不透明指针规范的类型。修改方式如下:

let frame = named_struct_type llvm.context "frame1" in
-- 直接使用不透明ptr类型定义结构体元素
struct_set_body frame ([| llvm.ptr_type llvm.context |]) false;
let frame_ptr = build_alloca frame ("frame_ptr") llvm.builder in
-- 使用适配不透明指针的build_struct_gep替代build_struct_gep2
let base = build_struct_gep frame frame_ptr 0 "frame_elem_ptr" llvm.builder in
-- 如果仍存在类型不匹配,通过bitcast强制转为不透明ptr
let base_ptr = build_bitcast base (llvm.ptr_type llvm.context) "base_ptr" llvm.builder in
ignore (build_store v base_ptr llvm.builder);

关键改动:

  • 用llvm.ptr_type创建标准不透明指针类型,替换可能基于旧模型的pointer_type2;
  • 优先使用不带数字后缀的build_struct_gep(LLVM 15 OCaml绑定中,这类API默认适配不透明指针);
  • 若仍有类型问题,通过build_bitcast将返回值转为纯ptr类型。

C++ API修复

在C++中,直接使用不透明指针的原生API即可避免错误:

#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/StructType.h"
#include "llvm/IR/Type.h"

using namespace llvm;

// 示例代码片段
LLVMContext &Ctx = ...; // 获取上下文
IRBuilder<> Builder(Ctx);

// 创建包含不透明ptr元素的结构体
StructType *FrameTy = StructType::create(Ctx, {PointerType::getUnqual(Ctx)}, "frame1");

// 分配结构体空间,返回ptr类型
Value *FramePtr = Builder.CreateAlloca(FrameTy, nullptr, "frame_ptr");
// 获取结构体第0个字段的指针,返回ptr类型
Value *FrameElemPtr = Builder.CreateStructGEP(FrameTy, FramePtr, 0, "frame_elem_ptr");
// 执行存储操作,两个参数均为ptr类型
Builder.CreateStore(Auxiliary, FrameElemPtr); // Auxiliary是ptr类型的参数

核心逻辑:

  • 用PointerType::getUnqual(Ctx)创建不透明指针类型;
  • CreateStructGEP在不透明指针模型下直接返回ptr类型,无需额外转换;
  • 存储操作的源和目标均为ptr类型,完全符合LLVM 15的IR规范。

内容的提问来源于stack exchange,提问作者lil_papa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 19:53:12