Hi, all,
I am trying the swift compiler these days in ppc64le, and found that, if the function return type is aggr, the code swift generated didn't conform the ppc64le ABI.
cat test.swift
func test() -> (Bool, Double, Int){
return (true,3.0,3);
}
test();
swiftc test.swift -emit-ir
; ModuleID = '-'
target datalayout = "e-m:e-i64:64-n32:64"
target triple = "powerpc64le-unknown-linux-gnu"
...
define protected signext i32 @main(i32 signext, i8**) #0 {
entry:
%2 = bitcast i8** %1 to i8*
store i32 %0, i32* getelementptr inbounds (%Vs5Int32, %Vs5Int32* @_TZvOs7Process5_argcVs5Int32, i32 0, i32 0), align 4
call void @swift_once(i64* @globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_token3, i8* bitcast (void ()* @globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_func3 to i8*))
store i8* %2, i8** getelementptr inbounds (%Sp, %Sp* @_TZvOs7Process11_unsafeArgvGSpGSpVs4Int8__, i32 0, i32 0), align 8
%3 = call { i1, double, i64 } @_TF4test4testFT_TSbSdSi_()
%4 = extractvalue { i1, double, i64 } %3, 0
%5 = extractvalue { i1, double, i64 } %3, 1
%6 = extractvalue { i1, double, i64 } %3, 2
ret i32 0
}
We can see that, swift emit the { i1, double, i64 } as its return type and llvm will pass the return value of _TF4test4testFT_TSbSdSi_ by register.
objdump -dr test.o
...
4c: R_PPC64_TOC16_HA .toc+0x18
50: 00 00 63 e8 ld r3,0(r3)
50: R_PPC64_TOC16_LO_DS .toc+0x18
54: 60 00 9f e8 ld r4,96(r31)
58: 00 00 83 f8 std r4,0(r3)
5c: 01 00 00 48 bl 5c <main+0x5c>
5c: R_PPC64_REL24 _TF4test4testFT_TSbSdSi_
60: 00 00 00 60 nop
However, for ppc64le ABI, this should be passed by address. See what clang emit the ir for return aggr of this type.
cat test2.cpp
struct A {
bool b;
double d;
long long m;
};
A test();
int main() {
test();
return 0;
}
clang test2.cpp -S -emit-llvm
cat test2.ll
; ModuleID = 'test2.cpp'
target datalayout = "e-m:e-i64:64-n32:64"
target triple = "powerpc64le-unknown-linux-gnu"
%struct.A = type { i8, double, i64 }
; Function Attrs: norecurse
define signext i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca %struct.A, align 8
store i32 0, i32* %1, align 4
call void @_Z4testv(%struct.A* sret %2)
ret i32 0
}
declare void @_Z4testv(%struct.A* sret) #1
Clang frontend will place it as the first parameter of the function. That would cause serious issues if we are linking with code write from other language(i.e. c/c++). Any comments?