2014-04-01 26 views
7

当在函数中使用结构参数,铛会改变函数签名。而不是使用一个结构类型,签名将是一个相同大小的强制int。在我的编译器项目中,我使用llvm结构类型作为方法签名(这看起来更合理)。为什么锵强迫结构参数整数

这不会是一个问题,除了通过LLVM使用该结构时,或得到的组件产生的强制类型是不同的并且不呼叫兼容这一事实。这导致我的编译器不能与具有struct的C函数ABI兼容。

为什么铛做到这一点?这是在C ABI中指定的东西吗?

这里有一个简单的例子C源文件:

struct TwoInt { int a, b; }; 

struct EightChar { char a, b, c, d, e, f, g, h; }; 

void doTwoInt(struct TwoInt a) {} 

void doEightChar(struct EightChar a) {} 

int main() 
{ 
     struct TwoInt ti; 
     struct EightChar fc; 

     doTwoInt(ti); 
     doEightChar(fc); 

     return 0; 
} 

从锵

%struct.TwoInt = type { i32, i32 } 
%struct.EightChar = type { i8, i8, i8, i8, i8, i8, i8, i8 } 

define void @doTwoInt(i64 %a.coerce) nounwind uwtable { 
    %a = alloca %struct.TwoInt, align 8 
    %1 = bitcast %struct.TwoInt* %a to i64* 
    store i64 %a.coerce, i64* %1, align 1 
    ret void 
} 

define void @doEightChar(i64 %a.coerce) nounwind uwtable { 
    %a = alloca %struct.EightChar, align 8 
    %1 = bitcast %struct.EightChar* %a to i64* 
    store i64 %a.coerce, i64* %1, align 1 
    ret void 
} 

define i32 @main() nounwind uwtable { 
    %1 = alloca i32, align 4 
    %ti = alloca %struct.TwoInt, align 4 
    %fc = alloca %struct.EightChar, align 1 
    store i32 0, i32* %1 
    %2 = bitcast %struct.TwoInt* %ti to i64* 
    %3 = load i64* %2, align 1 
    call void @doTwoInt(i64 %3) 
    %4 = bitcast %struct.EightChar* %fc to i64* 
    %5 = load i64* %4, align 1 
    call void @doEightChar(i64 %5) 
    ret i32 0 
} 

所得LLVM-IR我会一直期待(什么我的编译器输出):

%TwoInt = type { i32, i32 } 
%EightChar = type { i8, i8, i8, i8, i8, i8, i8, i8 } 

define void @doTwoInt(%TwoInt %a) { 
    %1 = alloca i32 
    %2 = alloca %TwoInt 
    store %TwoInt %a, %TwoInt* %2 
    ret void 
} 

define void @doEightChar(%EightChar %a) { 
    %1 = alloca i32 
    %2 = alloca %EightChar 
    store %EightChar %a, %EightChar* %2 
    ret void 
} 

define i32 @main() { 
    %1 = alloca i32 
    %ti = alloca %TwoInt 
    %fc = alloca %EightChar 
    %2 = load %TwoInt* %ti 
    call void @doTwoInt(%TwoInt %2) 
    %3 = load %EightChar* %fc 
    call void @doEightChar(%EightChar %3) 
    ret i32 0 
} 
+0

铛如何开始?你的操作系统和ABI是什么? ABI不是在C/C++标准中定义的,而是由操作系统及其库文件定义的,并且有可能您的编译器不按照ABI工作。 – osgx

+0

链接到更详细的网页很好的概述:什么是应用程序二进制接口(ABI)?(https://stackoverflow.com/questions/2171177/what-is-an-application-binary-interface-abi) –

回答

6

两个月前,有在llvmdev线程:[LLVMdev] "Struct parameters being converted to other types"由Jaymie圣recker,1月14日19点50分04秒CST 2013年,她遇到了类似的问题:“当与结构参数的函数或返回类型编译clang -O0 -emit-llvm,所产生的位码变化很大程度上取决于结构的类型。”,和铛转向结构为指针,载体,通过它作为数加倍,或者合并到单个I64类型Anton Korobeynikovreplied at Jan 15 00:41:43 CST 2013

的结构被降低到的东西,其对应于C/C++ ABI平台上对于

传递结构以适当的方式。所以,铛根据您的操作系统,库和本地编译器使用的方式做结构传递。这样做是为了让你构建模块,这将与当地的图书馆工作。我认为,你的编译器项目使用错误的ABI。

您可以修复你的编译器项目使用的平台ABI(转换结构就像是由铛完成),也可以定义自己的ABI和调整铛使用它。

+2

我想真正的问题是为什么在llvm-ir级完成“类型降低”而不是程序集?前端编译器编写者是否有理由管理ABI而不是LLVM的本地代码生成器? – Justin

+1

@Justin:LLVM IR无法表示正确降低呼叫所需的ABI规则。所以这个任务留给前端来生成精确的ABI特定的IR序列。 –

+0

@EliBendersky所以[Calling Conventions](http://llvm.org/docs/LangRef.html#calling-conventions)IR属性不足以指定参数如何传递?文件在这一点上并不完全清楚。 – Justin