2014-04-01 24 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