【发布时间】:2021-05-21 09:46:33
【问题描述】:
我正在阅读 Clang++ 生成的以下代码的 LLVM IR 代码:
class Shape {
public:
// pure virtual function providing interface framework.
virtual int getArea(char* me) = 0;
void setWidth(int w) {
width = w;
}
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
// Derived classes
class Rectangle: public Shape {
public:
int getArea(char * me) {
return (width * height);
}
};
产生以下 LLVM IR:
%class.Rectangle = type { %class.Shape }
%class.Shape = type { i32 (...)**, i32, i32 }
这是什么“ i32 (...)** ”?它有什么作用?
从“i32 (...)**”的外观来看,这看起来像函数指针,但用于位转换对象。
像这样:
define linkonce_odr dso_local void @_ZN9RectangleC2Ev(%class.Rectangle* %0) unnamed_addr #5 comdat align 2 {
%2 = alloca %class.Rectangle*, align 8
store %class.Rectangle* %0, %class.Rectangle** %2, align 8
%3 = load %class.Rectangle*, %class.Rectangle** %2, align 8
%4 = bitcast %class.Rectangle* %3 to %class.Shape*
call void @_ZN5ShapeC2Ev(%class.Shape* %4) #3
%5 = bitcast %class.Rectangle* %3 to i32 (...)***
store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV9Rectangle, i32 0, inrange i32 0, i32 2) to i32 (...)**), i32 (...)*** %5, align 8
ret void
}
【问题讨论】:
-
i32 (...)*是一个指向返回i32的可变参数函数的指针。在这里你有双指针。这可能应该理解为一个函数数组,即这看起来像虚拟调用的 vtable 实现。这也解释了可变参数(...)参数,因为 vtable 涵盖了所有可能的函数签名。虽然我不确定它为什么返回i32。我认为@_ZN9RectangleC2Ev是一个构造函数。该代码是否在实例上设置了适当的 vtable?我不确定,代码是一些奇怪的实现细节。 -
@freakish 你在很多层面上让我感到困惑。将虚函数的返回类型更改为任何东西,它仍然是“i32(...)**”,我从@_ZN9RectangleC2Ev 了解到的是,它创建了一个形状对象并将其存储到“i32(...)*** ”。指针是右指针。 i8* 应该可以完成这项工作,但它会将 Shape 对象存储到 i32 (...)** 中。
标签: c++ clang llvm clang++ llvm-ir