Returning more than two scalars from C code


(Bryan Chan) #1

I tried to google for an answer but couldn't find anything. What is the
correct way to do the following on Linux?

  @_silgen_name("foo")
  func foo(theInt: UInt)
    -> (a: UInt, b: UInt, c: UInt)

  var (d, e, f) = foo(aNum)

Where foo is:

  typedef struct {
    long a;
    long b;
    long c;
  } Tuple;

  extern "C" {
    Tuple foo(int i) {
      return Tuple{ i, i, i };
    }
  }

Currently, the call to foo crashes because foo wants to return the tuple
indirectly, but the Swift call expects the three scalar return values in
registers. This example is a generalization of runtime functions such as
swift_class_getInstanceExtents, which happens to work because it only
returns two scalars in RAX and RDX, which is supported by Clang. But my
tests show that three-scalar tuples/structs will cause problems. On
architectures where Clang only supports one scalar return value, the
problem is worse.

Am I doing something wrong or is there already a way to deal with this
(e.g. annotation in Swift code to make it obey C ABI, or vice versa)?

Thanks, Bryan


(Joe Groff) #2

Don't use @_silgen_name. If you want to use a C API from Swift, define a Clang module for its headers, and import the module. See http://clang.llvm.org/docs/Modules.html for documentation on Clang module maps.

-Joe

···

On Mar 22, 2016, at 5:57 AM, Bryan Chan via swift-dev <swift-dev@swift.org> wrote:

I tried to google for an answer but couldn't find anything. What is the correct way to do the following on Linux?

@_silgen_name("foo")
func foo(theInt: UInt)
-> (a: UInt, b: UInt, c: UInt)

var (d, e, f) = foo(aNum)

Where foo is:

typedef struct {
long a;
long b;
long c;
} Tuple;

extern "C" {
Tuple foo(int i) {
return Tuple{ i, i, i };
}
}

Currently, the call to foo crashes because foo wants to return the tuple indirectly, but the Swift call expects the three scalar return values in registers. This example is a generalization of runtime functions such as swift_class_getInstanceExtents, which happens to work because it only returns two scalars in RAX and RDX, which is supported by Clang. But my tests show that three-scalar tuples/structs will cause problems. On architectures where Clang only supports one scalar return value, the problem is worse.

Am I doing something wrong or is there already a way to deal with this (e.g. annotation in Swift code to make it obey C ABI, or vice versa)?


(Joe Groff) #3

The runtime functions are hacked in various unsavory ways to give them Swift-like calling conventions. Many of them also have important semantics that the compiler needs to be aware of, so if they aren't exported as standard library API in some way, you really shouldn't interact with them directly. (swift_class_getInstanceExtents happens to be OK, but what are you trying to do with it?)

-Joe

···

On Mar 22, 2016, at 11:30 AM, Bryan Chan <bryan.chan@ca.ibm.com> wrote:

jgroff@apple.com wrote on 2016-03-22 12:05:06 PM: > > > On Mar 22, 2016, at 5:57 AM, Bryan Chan via swift-dev <swift-dev@swift.org > > wrote:
>
> > I tried to google for an answer but couldn't find anything. What is
> > the correct way to do the following on Linux?
> >
> > @_silgen_name("foo")
> > func foo(theInt: UInt)
> > -> (a: UInt, b: UInt, c: UInt)
> >
> > var (d, e, f) = foo(aNum)
> >
[snip]
> >
> > Currently, the call to foo crashes because foo wants to return the
> > tuple indirectly, but the Swift call expects the three scalar return
> > values in registers. This example is a generalization of runtime
> > functions such as swift_class_getInstanceExtents, which happens to
> > work because it only returns two scalars in RAX and RDX, which is
> > supported by Clang. But my tests show that three-scalar tuples/
> > structs will cause problems. On architectures where Clang only
> > supports one scalar return value, the problem is worse.
> >
> > Am I doing something wrong or is there already a way to deal with
> > this (e.g. annotation in Swift code to make it obey C ABI, or vice versa)?
>
> Don't use @_silgen_name. If you want to use a C API from Swift,
> define a Clang module for its headers, and import the module. See
> http://clang.llvm.org/docs/Modules.html for documentation on Clang
> module maps.

Is this the solution for runtime functions like
swift_class_getInstanceExtents as well?


(Bryan Chan) #4

> I tried to google for an answer but couldn't find anything. What is
> the correct way to do the following on Linux?
>
> @_silgen_name("foo")
> func foo(theInt: UInt)
> -> (a: UInt, b: UInt, c: UInt)
>
> var (d, e, f) = foo(aNum)
>

[snip]

>
> Currently, the call to foo crashes because foo wants to return the
> tuple indirectly, but the Swift call expects the three scalar return
> values in registers. This example is a generalization of runtime
> functions such as swift_class_getInstanceExtents, which happens to
> work because it only returns two scalars in RAX and RDX, which is
> supported by Clang. But my tests show that three-scalar tuples/
> structs will cause problems. On architectures where Clang only
> supports one scalar return value, the problem is worse.
>
> Am I doing something wrong or is there already a way to deal with
> this (e.g. annotation in Swift code to make it obey C ABI, or vice

versa)?

Don't use @_silgen_name. If you want to use a C API from Swift,
define a Clang module for its headers, and import the module. See
http://clang.llvm.org/docs/Modules.html for documentation on Clang
module maps.

Is this the solution for runtime functions like
swift_class_getInstanceExtents as well?

···

jgroff@apple.com wrote on 2016-03-22 12:05:06 PM: > On Mar 22, 2016, at 5:57 AM, Bryan Chan via swift-dev <swift-dev@swift.org > wrote:


(Joe Groff) #5

Yeah, there's no good way right now to return three scalars from Clang. swift_class_getInstanceExtents and a few other runtime entrypoints like allocBox and allocError use the `TwoWordPair::Return` hack to use types that happen to return in two registers on i386, x86_64, armv7, and arm64. If s390x's C ABI doesn't define any such types, you might need to wait for proper support for Swift calling conventions in Clang. I believe it's on John McCall's near-term todo list to do that.

-Joe

···

On Mar 22, 2016, at 12:06 PM, Bryan Chan <bryan.chan@ca.ibm.com> wrote:

jgroff@apple.com wrote on 2016-03-22 02:37:47 PM:

> The runtime functions are hacked in various unsavory ways to give
> them Swift-like calling conventions. Many of them also have
> important semantics that the compiler needs to be aware of, so if
> they aren't exported as standard library API in some way, you really
> shouldn't interact with them directly.
> (swift_class_getInstanceExtents happens to be OK, but what are you
> trying to do with it?)

I am trying to build Swift on a different architecture (s390x). This
function was causing crashes due to the ABI mismatch, and I also
found that the issue is not 100% fixed on x86 either, so I wondered
if the community has an opinion on the right way to deal with this
in the runtime, or if the answer is simply "don't do this for
3-scalar returns".


(Bryan Chan) #6

I am trying to build Swift on a different architecture (s390x). This
function was causing crashes due to the ABI mismatch, and I also
found that the issue is not 100% fixed on x86 either, so I wondered
if the community has an opinion on the right way to deal with this
in the runtime, or if the answer is simply "don't do this for
3-scalar returns".

Thanks, Bryan

···

jgroff@apple.com wrote on 2016-03-22 02:37:47 PM:

The runtime functions are hacked in various unsavory ways to give
them Swift-like calling conventions. Many of them also have
important semantics that the compiler needs to be aware of, so if
they aren't exported as standard library API in some way, you really
shouldn't interact with them directly.
(swift_class_getInstanceExtents happens to be OK, but what are you
trying to do with it?)


(John McCall) #7

To be clear, you'll still need to implement the swiftcc convention for your target in LLVM/clang, so it will still take some compiler implementation expertise to get right. But at least the compatibility assumptions will be explicit.

John.

···

On Mar 22, 2016, at 12:25 PM, Joe Groff <jgroff@apple.com> wrote:

On Mar 22, 2016, at 12:06 PM, Bryan Chan <bryan.chan@ca.ibm.com <mailto:bryan.chan@ca.ibm.com>> wrote:

jgroff@apple.com <mailto:jgroff@apple.com> wrote on 2016-03-22 02:37:47 PM:

> The runtime functions are hacked in various unsavory ways to give
> them Swift-like calling conventions. Many of them also have
> important semantics that the compiler needs to be aware of, so if
> they aren't exported as standard library API in some way, you really
> shouldn't interact with them directly.
> (swift_class_getInstanceExtents happens to be OK, but what are you
> trying to do with it?)

I am trying to build Swift on a different architecture (s390x). This
function was causing crashes due to the ABI mismatch, and I also
found that the issue is not 100% fixed on x86 either, so I wondered
if the community has an opinion on the right way to deal with this
in the runtime, or if the answer is simply "don't do this for
3-scalar returns".

Yeah, there's no good way right now to return three scalars from Clang. swift_class_getInstanceExtents and a few other runtime entrypoints like allocBox and allocError use the `TwoWordPair::Return` hack to use types that happen to return in two registers on i386, x86_64, armv7, and arm64. If s390x's C ABI doesn't define any such types, you might need to wait for proper support for Swift calling conventions in Clang. I believe it's on John McCall's near-term todo list to do that.


(Jordan Rose) #8

To be clear, @_silgen_name is unsupported for general use (generally true of anything that starts with an underscore). We use it in the standard library for certain things that can't be expressed in C, but there are plenty of places that can be expressed in C that maybe should be using the SwiftShims headers instead. We use it in tests because of laziness. You should really not use it for production code.

Jordan

···

On Mar 22, 2016, at 12:06, Bryan Chan via swift-dev <swift-dev@swift.org> wrote:

jgroff@apple.com wrote on 2016-03-22 02:37:47 PM:

> The runtime functions are hacked in various unsavory ways to give
> them Swift-like calling conventions. Many of them also have
> important semantics that the compiler needs to be aware of, so if
> they aren't exported as standard library API in some way, you really
> shouldn't interact with them directly.
> (swift_class_getInstanceExtents happens to be OK, but what are you
> trying to do with it?)

I am trying to build Swift on a different architecture (s390x). This
function was causing crashes due to the ABI mismatch, and I also
found that the issue is not 100% fixed on x86 either, so I wondered
if the community has an opinion on the right way to deal with this
in the runtime, or if the answer is simply "don't do this for
3-scalar returns".


(John McCall) #9

Thanks for your responses so far. It took me a while to fully appreciate
what all this means.

I have read through John's mail thread on llvm-dev about adding the swiftcc
convention to LLVM/Clang. I don't think that discussion mentioned adding
Clang support for C++ functions returning aggregates in multiple registers
for targets that currently use sret, because, in John's words, "we don't
use the Swift CC to call C functions." But aren't these runtime functions
using TwoWordPair::Return doing exactly that?

One of the reasons to implement a swiftcall CC attribute in Clang is precisely
so that we can make the C declaration request the use of the Swift CC directly.

On i386 and ARM, the TwoWordPair::Return type is masqueraded as a 64-bit
unsigned long long so that the returned values are passed in a register
pair. This trick is not portable, and infeasible on at least s390x.

You will need to implement the Swift CC for your target.

A portable solution would be to implement such runtime functions in Swift,
and make them retrieve the needed results from two calls to C++, instead
of one call to a C++ function that returns a pair. The Swift function
can then return value pairs as usual. This seems much cleaner and simpler.

We're not going to implement every single runtime function in Swift.

John.

···

On Mar 30, 2016, at 12:09 PM, Bryan Chan <bryan.chan@ca.ibm.com> wrote:

Bryan

rjmccall@apple.com wrote on 2016-03-22 03:51:52 PM: > > > On Mar 22, 2016, at 12:25 PM, Joe Groff <jgroff@apple.com> wrote:
> > On Mar 22, 2016, at 12:06 PM, Bryan Chan <bryan.chan@ca.ibm.com> wrote:
> >
> > > jgroff@apple.com wrote on 2016-03-22 02:37:47 PM:
> > >
> > > > The runtime functions are hacked in various unsavory ways to give
> > > > them Swift-like calling conventions. Many of them also have
> > > > important semantics that the compiler needs to be aware of, so if
> > > > they aren't exported as standard library API in some way, you really
> > > > shouldn't interact with them directly.
> > > > (swift_class_getInstanceExtents happens to be OK, but what are you
> > > > trying to do with it?)
> > >
> > > I am trying to build Swift on a different architecture (s390x). This
> > > function was causing crashes due to the ABI mismatch, and I also
> > > found that the issue is not 100% fixed on x86 either, so I wondered
> > > if the community has an opinion on the right way to deal with this
> > > in the runtime, or if the answer is simply "don't do this for
> > > 3-scalar returns".
> >
> > Yeah, there's no good way right now to return three scalars from
> > Clang. swift_class_getInstanceExtents and a few other runtime
> > entrypoints like allocBox and allocError use the
> > `TwoWordPair::Return` hack to use types that happen to return in two
> > registers on i386, x86_64, armv7, and arm64. If s390x's C ABI
> > doesn't define any such types, you might need to wait for proper
> > support for Swift calling conventions in Clang. I believe it's on
> > John McCall's near-term todo list to do that.
>
> To be clear, you'll still need to implement the swiftcc convention
> for your target in LLVM/clang, so it will still take some compiler
> implementation expertise to get right. But at least the
> compatibility assumptions will be explicit.


(Bryan Chan) #10

Thanks for your responses so far. It took me a while to fully appreciate
what all this means.

I have read through John's mail thread on llvm-dev about adding the swiftcc
convention to LLVM/Clang. I don't think that discussion mentioned adding
Clang support for C++ functions returning aggregates in multiple registers
for targets that currently use sret, because, in John's words, "we don't
use the Swift CC to call C functions." But aren't these runtime functions
using TwoWordPair::Return doing exactly that?

On i386 and ARM, the TwoWordPair::Return type is masqueraded as a 64-bit
unsigned long long so that the returned values are passed in a register
pair. This trick is not portable, and infeasible on at least s390x.

A portable solution would be to implement such runtime functions in Swift,
and make them retrieve the needed results from two calls to C++, instead
of one call to a C++ function that returns a pair. The Swift function
can then return value pairs as usual. This seems much cleaner and simpler.

Bryan

>
> >
> > > The runtime functions are hacked in various unsavory ways to give
> > > them Swift-like calling conventions. Many of them also have
> > > important semantics that the compiler needs to be aware of, so if
> > > they aren't exported as standard library API in some way, you

really

···

rjmccall@apple.com wrote on 2016-03-22 03:51:52 PM: > On Mar 22, 2016, at 12:25 PM, Joe Groff <jgroff@apple.com> wrote:

> On Mar 22, 2016, at 12:06 PM, Bryan Chan <bryan.chan@ca.ibm.com> wrote:
> > jgroff@apple.com wrote on 2016-03-22 02:37:47 PM:
> > > shouldn't interact with them directly.
> > > (swift_class_getInstanceExtents happens to be OK, but what are you
> > > trying to do with it?)
> >
> > I am trying to build Swift on a different architecture (s390x). This
> > function was causing crashes due to the ABI mismatch, and I also
> > found that the issue is not 100% fixed on x86 either, so I wondered
> > if the community has an opinion on the right way to deal with this
> > in the runtime, or if the answer is simply "don't do this for
> > 3-scalar returns".
>
> Yeah, there's no good way right now to return three scalars from
> Clang. swift_class_getInstanceExtents and a few other runtime
> entrypoints like allocBox and allocError use the
> `TwoWordPair::Return` hack to use types that happen to return in two
> registers on i386, x86_64, armv7, and arm64. If s390x's C ABI
> doesn't define any such types, you might need to wait for proper
> support for Swift calling conventions in Clang. I believe it's on
> John McCall's near-term todo list to do that.

To be clear, you'll still need to implement the swiftcc convention
for your target in LLVM/clang, so it will still take some compiler
implementation expertise to get right. But at least the
compatibility assumptions will be explicit.