我正在研究使用llvm c ++ api编写的玩具语言,我正在尝试实现数组。我尝试了几种不同的东西,但都没有效果很好。
这就是我的目标:
[8 x [8 x [8 x [...]
)理想情况下,它们会像swift中的数组一样。
目前我正在使用basic array type。这将检查所有框,除了可以将一维数组传递给函数并从函数返回时,必须通过指针传递多维(嵌套)数组。这意味着我不仅必须将返回的指针bitcast到正确的类型,然后遍历每个元素并将其存储在适当的位置。很快,这变得非常混乱,但也很慢。
据我所知,你不能有嵌套的向量。例如。这不起作用:
<8 x <8 x i32>>
最后,我尝试使用malloc分配适当的空间,然后只使用指针。这与我目前的解决方案有许多相同的问题。
采用以下示例:
%1 = alloca [5 x i32], align 16
%2 = alloca i32*, align 8
%3 = getelementptr inbounds [5 x i32], [5 x i32]* %1, i32 0, i32 0
%4 = call i32* @_Z8getArrayPi(i32* %3)
store i32* %4, i32** %2, align 8
无法将指针%4
存储到%1
中,因此必须创建新的分配。否则(使用嵌套数组)需要复制每个元素,并且会出现与当前解决方案相同的问题。另外,理想情况下编译器会处理所有指针,因此它看起来就像是该语言用户的数组。
如果不清楚 - 我的问题是如何实现数组,以便我可以完成上面列出的所有事情(无需复制每个元素)。
答案 0 :(得分:2)
序言
我认为alloca
是正确的方法,如果它们将是固定大小的,但你必须编写相当多的样板来实现保证(C ++样式)省略来优化函数返回。
现在问题在于所有权语义,如果你想完美地完成它,你需要确定它们的生命周期并确定它们是否需要堆分配或者只能逃避堆栈分配。但是现在让我们忽略优化。 Swift / ARC实现在幕后非常混乱,并且使用了大量优化,因此您不一定要对其进行建模,更不用说Swift / ObjC ARC代码之间的差距和“非托管”代码。
简单的解决方案“像Swift”
如果你不想处理它,假设你知道函数的所有可能的退出路径,你可以在堆上使用某种形式的运行时分配你的数组,并提供侵入式引用计数语义。这是Swift使用的模型(顶部有大量优化) - 您堆分配每个数组并实现一个控制块来跟踪数组的引用计数和大小(例如,如果您想要动态边界检查)。在这种情况下,您将使用简单的pass-by-reference语义,如下所示:
Value
来跟踪那些)被传入,你就会提高引用数量。这几乎是它的基础,是一个非常非常愚蠢的ARC工作方式。现在需要考虑的事情:
我建议从一个refcounted对象开始,该对象将成为您所用语言管理的所有内容的基础,包括您的数组类型,并随身携带某种类型的信息。 (就像NSObject
中libobjc4
的一个复杂得多的版本。