具有相同名称的不同函数以及如何在 LLVM IR 中调用它们
Different functions with the same name and how to call them in LLVM IR
我正在为一种类似 Pascal 的语言编写玩具编译器。
假设我有如下伪代码:
define main
define foo
define b
writeInteger: 1
call b
define bar
define b
writeInteger: 2
call b
call foo
call bar
其中在 foo
和 bar
中定义了两个不同的 b
函数。
所以foo
里面的b
对应的LLVM IR函数是
define void @b(%foo_type* %foo_frame) {
...
对于 bar
内的 b
是
define void @b.1(%bar_type* %bar_frame) {
...
问题是,当我尝试调用函数 b
时,LLVM 自动假定我正在调用 void @b
,但我无法调用 void @b.1
。
因此,打印结果是 11
但我希望它是 12
。
我使用TheModule->getFunction("b");
命令访问LLVM函数对象。
那么,如何调用 bar
中定义的 b
函数?
更新:
正如 AlexDenisov 指出的那样,我可以将第一个 b 命名为 main_foo_b
,将第二个命名为 main_bar_b
。
这样我就可以调用正确的函数 b
,方法是找出我从代码的哪一部分调用 b。我将尝试通过持有所有函数名称的列表直到现在(尚未关闭)。让我们称之为 function_names_list
.
所以当我调用 main
和 foo
中的 b
函数时,我会调用 main_foo_b
因为 function_names_list=["main","foo"]
。当我调用 main
和 bar
中的 b
函数时,我会调用 main_bar_b
因为 function_names_list=["main","bar"]
。
这可能会解决当前示例的问题。
但在如下示例中:
define main
define f
writeInteger: 1
define g
define f
writeInteger: 2
call f
define h
call f
call g # prints 2
call f # prints 1
call h # prints 1
我还需要检查函数在哪个嵌套级别。通过嵌套级别,我的意思是在我当前有多少封闭函数的内部。 main
有零层嵌套,main_f
、main_g
和 main_h
有 1 层嵌套,main_g_f
有两层嵌套。
我需要检查嵌套级别,因为我需要更改在 h
中调用 f
的方式。我必须将其称为 main_f
而不是main_h_f
。通过知道我尝试调用的 f
处于先前的嵌套级别,然后我可以按顺序使用 function_names_list
(function_names_list[0:n-1]
) 中除一个元素之外的所有元素获取名称 main_f
.
欢迎来到 SO,Nik。
在内部,所有全局值(例如函数、变量和别名)都存在于 LLVM 模块内的类似哈希 table 的存储中,其中名称用作键。为了避免冲突,LLVM 为函数名添加了后缀。
我想在这种情况下您必须添加某种命名空间,即将第一个 b
命名为 main_foo_b
,将第二个命名为 main_bar_b
。这样你就可以清楚地区分'colliding'个名字。
希望对您有所帮助:)
UPD:
现在看来我有点过头了,@arnt的建议听起来更合理。您使用 function_names_list
的解决方案是正确的方向。通常,这通过所谓的 Symbol Table 来解决:一个符号 table 只是一个键值数据结构,它也有一个指向父符号 table 的指针。你的例子中的键是函数名,值是发出的 LLVM 函数。
您从一个全局符号 table(对于整个翻译单元)开始,然后每当您进入一个新范围时,您都会创建一个新符号 table 并将父级设置为“上一个”符号 table。然后,当您需要发出对函数的调用时,您会在当前符号 table 中查找命名函数,如果有 none,则您走上去查看父符号 table.递归执行直到到达全局符号 table,在这种情况下,可以将缺少的函数报告为错误。
这是您的第一个代码片段的示例:
global_table:
scope = <whole translation unit>
parent = null
"main" = <main function>
main_table:
scope = <main function>
parent = global_table
"foo" = <foo function>
"bar" = <bar function>
foo_table:
scope = <foo function>
parent = main_table
"b" = <b function>
bar_table:
scope = <bar function>
parent = main_table
"b" = <b.1 function>
(b
和 b.1
的表是空的,所以为了简洁我跳过了它们)。
然后,根据范围(foo
或 bar
),您将开始查找 foo_table
或 bar_table
,并且应该找到正确的 b
函数。
我正在为一种类似 Pascal 的语言编写玩具编译器。 假设我有如下伪代码:
define main
define foo
define b
writeInteger: 1
call b
define bar
define b
writeInteger: 2
call b
call foo
call bar
其中在 foo
和 bar
中定义了两个不同的 b
函数。
所以foo
里面的b
对应的LLVM IR函数是
define void @b(%foo_type* %foo_frame) {
...
对于 bar
内的 b
是
define void @b.1(%bar_type* %bar_frame) {
...
问题是,当我尝试调用函数 b
时,LLVM 自动假定我正在调用 void @b
,但我无法调用 void @b.1
。
因此,打印结果是 11
但我希望它是 12
。
我使用TheModule->getFunction("b");
命令访问LLVM函数对象。
那么,如何调用 bar
中定义的 b
函数?
更新:
正如 AlexDenisov 指出的那样,我可以将第一个 b 命名为 main_foo_b
,将第二个命名为 main_bar_b
。
这样我就可以调用正确的函数 b
,方法是找出我从代码的哪一部分调用 b。我将尝试通过持有所有函数名称的列表直到现在(尚未关闭)。让我们称之为 function_names_list
.
所以当我调用 main
和 foo
中的 b
函数时,我会调用 main_foo_b
因为 function_names_list=["main","foo"]
。当我调用 main
和 bar
中的 b
函数时,我会调用 main_bar_b
因为 function_names_list=["main","bar"]
。
这可能会解决当前示例的问题。
但在如下示例中:
define main
define f
writeInteger: 1
define g
define f
writeInteger: 2
call f
define h
call f
call g # prints 2
call f # prints 1
call h # prints 1
我还需要检查函数在哪个嵌套级别。通过嵌套级别,我的意思是在我当前有多少封闭函数的内部。 main
有零层嵌套,main_f
、main_g
和 main_h
有 1 层嵌套,main_g_f
有两层嵌套。
我需要检查嵌套级别,因为我需要更改在 h
中调用 f
的方式。我必须将其称为 main_f
而不是main_h_f
。通过知道我尝试调用的 f
处于先前的嵌套级别,然后我可以按顺序使用 function_names_list
(function_names_list[0:n-1]
) 中除一个元素之外的所有元素获取名称 main_f
.
欢迎来到 SO,Nik。
在内部,所有全局值(例如函数、变量和别名)都存在于 LLVM 模块内的类似哈希 table 的存储中,其中名称用作键。为了避免冲突,LLVM 为函数名添加了后缀。
我想在这种情况下您必须添加某种命名空间,即将第一个 b
命名为 main_foo_b
,将第二个命名为 main_bar_b
。这样你就可以清楚地区分'colliding'个名字。
希望对您有所帮助:)
UPD:
现在看来我有点过头了,@arnt的建议听起来更合理。您使用 function_names_list
的解决方案是正确的方向。通常,这通过所谓的 Symbol Table 来解决:一个符号 table 只是一个键值数据结构,它也有一个指向父符号 table 的指针。你的例子中的键是函数名,值是发出的 LLVM 函数。
您从一个全局符号 table(对于整个翻译单元)开始,然后每当您进入一个新范围时,您都会创建一个新符号 table 并将父级设置为“上一个”符号 table。然后,当您需要发出对函数的调用时,您会在当前符号 table 中查找命名函数,如果有 none,则您走上去查看父符号 table.递归执行直到到达全局符号 table,在这种情况下,可以将缺少的函数报告为错误。
这是您的第一个代码片段的示例:
global_table:
scope = <whole translation unit>
parent = null
"main" = <main function>
main_table:
scope = <main function>
parent = global_table
"foo" = <foo function>
"bar" = <bar function>
foo_table:
scope = <foo function>
parent = main_table
"b" = <b function>
bar_table:
scope = <bar function>
parent = main_table
"b" = <b.1 function>
(b
和 b.1
的表是空的,所以为了简洁我跳过了它们)。
然后,根据范围(foo
或 bar
),您将开始查找 foo_table
或 bar_table
,并且应该找到正确的 b
函数。