如何使用llvm实现虚拟表

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

我正在编写一个玩具编译器,并希望我的语言支持虚拟方法,但我不知道如何做到这一点,它似乎不像其他语句一样直接,可以很容易地转换成IR代码而不需要再考虑,v我脑子里的表格概念就像一些图形和线条一样存在,就像一些高级别的说明。这可能足以使用OOP语言,但似乎还不足以写一个。

我试着编写一些C ++代码并将其转换为代码,但遗憾的是我仍无法理解输出。我检查了Clang的源代码,甚至无法弄清楚这部分的位置......(好吧,我得到了代码,它似乎位于lib/CodeGen/CGClass.cpp,但是Clang是一个复杂的项目,我仍然无法理解它是怎么回事实现v表)

所以任何想法如何做到这一点,还是有一些llvm api来帮我实现这个?

llvm llvm-ir
1个回答
1
投票

vtable是一个函数指针数组。在单继承上下文中,每个类都有一个这样的数组,其中数组的元素是类的虚方法。然后,每个对象都包含一个指向其类的vtable的指针,每个虚方法调用只会调用vtable中的相应指针(在将其转换为所需类型之后)。

所以,假设您正在编译一个如下所示的程序:

class A {
  int x,y;

  virtual int foo() { return x+y; }
  virtual int bar() { return x*y; }
}

class B inherits A {
  int z;
  override int bar() { return x*y+z; }
}

int f(A a) {
  return a.foo() + a.bar();
}

然后你可以定义一个名为A_fooA_barB_bar的函数,它们分别使用AB指针并包含A.fooA.barB.bar的代码(确切的命名当然取决于你的名字修改方案)。然后你会生成两个全局的A_vtableB_vtable,看起来像这样:

@A_vtable = global [2 x void (...)*] [
  void (...)* bitcast (i32 (%struct.A*)* @A_foo to void (...)*),
  void (...)* bitcast (i32 (%struct.A*)* @A_bar to void (...)*)
]
@B_vtable = global [2 x void (...)*] [
  void (...)* bitcast (i32 (%struct.A*)* @A_foo to void (...)*),
  void (...)* bitcast (i32 (%struct.B*)* @B_bar to void (...)*)
]

这对应于这个C代码(希望更具可读性):

typedef void (*fpointer_t)();
fpointer_t A_vtable[] = {(fpointer_t) A_foo, (fpointer_t) A_bar};
fpointer_t B_vtable[] = {(fpointer_t) A_foo, (fpointer_t) B_bar};

f然后可以这样翻译:

define i32 @f(%struct.A*) {
  %2 = getelementptr inbounds %struct.A, %struct.A* %0, i64 0, i32 0
  %3 = bitcast %struct.A* %0 to i32 (%struct.A*)***
  %4 = load i32 (%struct.A*)**, i32 (%struct.A*)*** %3
  %5 = load i32 (%struct.A*)*, i32 (%struct.A*)** %4
  %6 = call i32 %5(%struct.A* %0)

  %7 = load void (...)**, void (...)*** %2
  %8 = getelementptr inbounds void (...)*, void (...)** %7, i64 1
  %9 = bitcast void (...)** %8 to i32 (%struct.A*)**
  %10 = load i32 (%struct.A*)*, i32 (%struct.A*)** %9
  %11 = call i32 %10(%struct.A* %0)

  %12 = add nsw i32 %11, %6
  ret i32 %12
}

或者在C:

typedef int (*A_int_method_t)(struct A*);
int f(struct A* a) {
  return ((A_int_method_t) a->vtable[0])(a) + ((A_int_method_t) a->vtable[1])(a);
}
© www.soinside.com 2019 - 2024. All rights reserved.