The swift didn't conform the calling convention for ppc64le


(bluedream) #1

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?


(Dmitri Gribenko) #2

+John

···

On Mon, Mar 7, 2016 at 10:16 PM, bluedream via swift-dev <swift-dev@swift.org> wrote:

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?

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Joe Groff) #3

Swift does not use the C calling convention.

-Joe

···

On Mar 7, 2016, at 10:16 PM, bluedream via swift-dev <swift-dev@swift.org> wrote:

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?

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev


(Joe Groff) #4

…except for things that come from or are explicitly exported as C entry points.

-Joe

···

On Mar 8, 2016, at 9:57 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

Swift does not use the C calling convention.