编译器如何引用未装箱的类型?

问题描述 投票:0回答:1

我目前正在用 python 构建我的第一个编译器。我已经完成了词法分析器、解析器和分析器。我打算使用 llvmlite 库来发出 ir。我在将动态类型语言转换为静态类型 llvm ir 时遇到问题。我目前的做法是:

  1. 在分析过程中,如果可能,我会静态推断类型,并将这些信息添加到我的 ast 节点中。
  2. 在代码生成过程中,我尝试将动态值放入一个简单的 llvm 结构中,并使用类型标记(i32 const)和指向数据的通用指针。然后我的所有函数都可以将这些框作为参数,并且我在继续我的函数体之前“简单地”拆箱它们

我意识到我可能有点不知所措。我可以对值进行装箱,但在拆箱它们并在我的函数中使用它们时遇到问题 - 同时仍然遵守 llvm 的 SSA。我目前正在打开类型标签并相应地为我的参数创建变量。这是代码:

... 

; x is a parameter
switch i32 %type_tag, label %done [ 
  i32 1, label %handle_int_x 
  i32 2, label %handle_float_x 
  i32 3, label %handle_bool_x 
  i32 4, label %handle_string_x 
] 
handle_int_x:
  %int_ptr = bitcast i8* %value_ptr to i32* ; Cast pointer to i32*
  %unboxed_int = load i32, i32* %int_ptr ; Load the integer value 
  store i32 %unboxed_int, i32* %x_int 

...

运行此开关块后,我将有 4 个不同的变量(每种类型一个),参数将位于其中之一 - 取决于运行的开关块。我的问题是,我如何引用函数内的参数?假设我想返回

x + y
我如何知道要使用哪个变量,
x_int
x_float
(或其他类型)?每次引用参数时,我是否要在框的类型标记上添加另一个 switch 语句?这似乎根本不可持续。实际的编译器是如何处理这个问题的?

我考虑过使用 phi 节点,但它们还要求每个分支返回一种类型,而在我的情况下,我有很多类型。

有没有一种方法可以将所有这些变量统一为一个?我想简单地通过参数的名称来引用参数,而不必计算每次引用时它位于哪个变量中。

实际编译器如何引用未装箱的变量(在动态设置中)?

compiler-construction llvm-ir boxing
1个回答
0
投票

在继续我的函数体之前,我“简单地”拆箱它们

这不是这样做的方法。

如果您想这样做,您最终将不得不为每种可能的参数类型组合生成一个版本的函数体,从而为您提供 tp 不同版本的函数体,其中 t 是函数体的数量您的语言中的类型,p 是参数的数量(尽管您的类型推断可能会稍微减少该数量)。这甚至没有考虑到您的函数可能包含对返回类型也未知的其他函数的调用。

通常的做法是,仅当对需要拆箱值的原始操作应用时才对值进行拆箱,然后将结果放回装箱值中。

同时仍遵守 llvm 的 SSA

通常,在生成 LLVM 代码时,您会将所有内容放入

alloca
中,然后让 LLVM 负责将它们转换为寄存器。这样你就不用担心SSA了。这不会帮助您解决当前的问题,但仍然会让您的生活更轻松。

© www.soinside.com 2019 - 2024. All rights reserved.