Preserving and Applying CC in Imported Decls

Hey guys,

I have another fun case that things go wrong in :-). We do not preserve the calling convention information when importing function decls via the ClangImporter. I have a pretty simple example in apple/swift#13404. Importing the following:

float frand(void);
float fadd(float f, float g) { return f + g; }

and using this in swift as:

func f -> Float { return fadd(frand(), frand()); }

will result in the fadd call being elided due to the UB in the CC mismatch. Im pretty sure that we should be preserving CC information when importing the interface, probably in `VisitFunctionDecl` in ImportDecl.cpp (although, I believe it can also be lazily computed). Im not sure which really would be the best thing to do here.

This can show up on other targets when interfaces uses `__attribute__((__pcs__))` or `__attribute__((__fastcall__))`, `__attribute__((__vectorcall__))`, `__attribute__((__regparm__([1-3])))`, `__attribute__((__stdcall__))`, `__attribute__((__thiscall__))`.

Without enhancing SIL, I'm not sure we have a good option besides refusing to import function declarations with non-standard CCs.

I don't think we really want to change AST function types to handle arbitrary imported calling conventions, but we could change SILFunctionType to be able to store a Clang CC. However, this will require a little bit of extra work in that, if someone tries to pass around the address of a fastcall function as a @convention(c) function, we will have to introduce a thunk. I believe we already do similar kinds of thunking in SILGen, though.

This is slightly problematic as Linux ARM HF and Windows ARM both use a non-C default (arm_aapcs_vfpcc) which is the test case in the mentioned PR. That is, even without the attributes the declarations above have a non-C CC.

I don't think that we are supporting arbitrary calling conventions per se. This only becomes a problem at the FFI layer, where we want to convert the swift CC to the foreign CC. The IRGen at that point will generate UB which will truncate the implementation when the LLVM optimizer runs. I think that we should at least support AAPCS in both, the standard and VFP, variants at the very least.

Supporting two C calling conventions is not easier than supporting arbitrary C calling conventions. All the complexity is in how and where we represent those CCs. I'm hesitant to introduce this complexity (and non-portability) into the core language, which is why I'm suggesting just introducing it into SIL. But I explicitly do not want us to hard-code specific non-standard conventions from C outside of maybe attribute parsing; we should generalize the representation to support arbitrary CCs. I don't think this is hard at the SIL level.

Hmm, I think that we might be looking at different problems. I want to support the de facto standard CC on the target. If you consider Windows ARM, “c” is entirely invalid. The equivalent of “c” is arm_aapcs_vfpcc. However, there are other cases where we do need a secondary CC. As an example of that, the AEABI RT function calls are always made as AAPCS, but on Linux ARM HF targets (e.g. armv7-unknown-linux-gnueabihf), the default CC is the VFP variant of AAPCS, so we do need a secondary CC there for some library calls. We usually get lucky as the function calls there are formed by the backend which knows the CC necessary for the call there.

In general, the importer has a lot of flexibility when importing declarations and very little flexibility when importing types, especially pointer types. We can only import one kind of function pointer type as a @convention(c) function type; everything else needs to be imported as an opaque pointer unless we actually bite the bullet and enhance the AST @convention system to support more C conventions. For maximum expressivity, that function pointer type needs to be the type most commonly used for function pointers on the platform, assuming there is one. It doesn't really matter if that's not the default calling convention for function *declarations* because we can always pass around a specific variant-CC function as a @convention(c) function value by introducing a thunk; function-pointer equality won't work, but probably nobody cares. What we can't do is turn an arbitrary variant-CC function *pointer* into a @convention(c) function pointer. But the correctness of all this relies on SIL being able to fully represent the C calling convention.

In the case of support of a target which does not support the C calling convention but expects all calls to be of a specific convention, we currently fall apart. It sounds like you would prefer that the approach to handle that would be to map `@convention(c)` to that alternate calling convention? For importing declarations, we currently do not preserve the calling convention at all. As a result, right now, FFI calls into C may introduce UB in the IR.

I think that the FFI to declarations is far more common than the FFI to a function pointer, which is why I am focusing on the imported declaration rather than the imported types. I do agree that supporting additional conventions in the SIL layer would be good for the imported function pointer case. Am I missing something and is the `@convention` used for the imported declarations too?

···

On Dec 13, 2017, at 12:46 PM, John McCall <rjmccall@apple.com> wrote:

On Dec 13, 2017, at 3:22 PM, Saleem Abdulrasool <compnerd@compnerd.org <mailto:compnerd@compnerd.org>> wrote:

On Dec 13, 2017, at 12:14 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Dec 13, 2017, at 2:56 PM, Saleem Abdulrasool <compnerd@compnerd.org <mailto:compnerd@compnerd.org>> wrote:

John.

Hey guys,

I have another fun case that things go wrong in :-). We do not preserve the calling convention information when importing function decls via the ClangImporter. I have a pretty simple example in apple/swift#13404. Importing the following:

float frand(void);
float fadd(float f, float g) { return f + g; }

and using this in swift as:

func f -> Float { return fadd(frand(), frand()); }

will result in the fadd call being elided due to the UB in the CC mismatch. Im pretty sure that we should be preserving CC information when importing the interface, probably in `VisitFunctionDecl` in ImportDecl.cpp (although, I believe it can also be lazily computed). Im not sure which really would be the best thing to do here.

This can show up on other targets when interfaces uses `__attribute__((__pcs__))` or `__attribute__((__fastcall__))`, `__attribute__((__vectorcall__))`, `__attribute__((__regparm__([1-3])))`, `__attribute__((__stdcall__))`, `__attribute__((__thiscall__))`.

Without enhancing SIL, I'm not sure we have a good option besides refusing to import function declarations with non-standard CCs.

I don't think we really want to change AST function types to handle arbitrary imported calling conventions, but we could change SILFunctionType to be able to store a Clang CC. However, this will require a little bit of extra work in that, if someone tries to pass around the address of a fastcall function as a @convention(c) function, we will have to introduce a thunk. I believe we already do similar kinds of thunking in SILGen, though.

This is slightly problematic as Linux ARM HF and Windows ARM both use a non-C default (arm_aapcs_vfpcc) which is the test case in the mentioned PR. That is, even without the attributes the declarations above have a non-C CC.

I don't think that we are supporting arbitrary calling conventions per se. This only becomes a problem at the FFI layer, where we want to convert the swift CC to the foreign CC. The IRGen at that point will generate UB which will truncate the implementation when the LLVM optimizer runs. I think that we should at least support AAPCS in both, the standard and VFP, variants at the very least.

Supporting two C calling conventions is not easier than supporting arbitrary C calling conventions. All the complexity is in how and where we represent those CCs. I'm hesitant to introduce this complexity (and non-portability) into the core language, which is why I'm suggesting just introducing it into SIL. But I explicitly do not want us to hard-code specific non-standard conventions from C outside of maybe attribute parsing; we should generalize the representation to support arbitrary CCs. I don't think this is hard at the SIL level.

Hmm, I think that we might be looking at different problems. I want to support the de facto standard CC on the target. If you consider Windows ARM, “c” is entirely invalid.

@convention(c) cannot be "entirely invalid". @convention(c) means the platform's C calling convention, which I promise does always exist. The code "int foo(void); int main() { foo(); }" does actually compile on Windows ARM, and it uses a calling convention; that is the platform's C calling convention.

The equivalent of “c” is arm_aapcs_vfpcc. However, there are other cases where we do need a secondary CC. As an example of that, the AEABI RT function calls are always made as AAPCS, but on Linux ARM HF targets (e.g. armv7-unknown-linux-gnueabihf), the default CC is the VFP variant of AAPCS, so we do need a secondary CC there for some library calls. We usually get lucky as the function calls there are formed by the backend which knows the CC necessary for the call there.

I think you might be confusing "the C calling convention" with some other concept — maybe the default LLVM calling convention? I believe it's true that LLVM has backends, notably ARM, where the maintainers made the (IMO questionable) decision to have the default LLVM CC be the same across operating systems instead of considering the full target triple. That just means that frontends have an obligation to set the target's actual CC on every C call and function. I would readily believe that Swift IRGen has bugs — maybe even pervasive ones — where we fail to do that.

In general, the importer has a lot of flexibility when importing declarations and very little flexibility when importing types, especially pointer types. We can only import one kind of function pointer type as a @convention(c) function type; everything else needs to be imported as an opaque pointer unless we actually bite the bullet and enhance the AST @convention system to support more C conventions. For maximum expressivity, that function pointer type needs to be the type most commonly used for function pointers on the platform, assuming there is one. It doesn't really matter if that's not the default calling convention for function *declarations* because we can always pass around a specific variant-CC function as a @convention(c) function value by introducing a thunk; function-pointer equality won't work, but probably nobody cares. What we can't do is turn an arbitrary variant-CC function *pointer* into a @convention(c) function pointer. But the correctness of all this relies on SIL being able to fully represent the C calling convention.

In the case of support of a target which does not support the C calling convention but expects all calls to be of a specific convention, we currently fall apart. It sounds like you would prefer that the approach to handle that would be to map `@convention(c)` to that alternate calling convention? For importing declarations, we currently do not preserve the calling convention at all. As a result, right now, FFI calls into C may introduce UB in the IR.

Yes, we clearly have a responsibility to call things with the right calling convention, and we should not import types and declarations which we cannot meet that responsibility for. I am trying to describe the correct technical design for that, which is:
  - In the importer, we do not need to assign a specific convention to the type of an imported function declaration.
  - In the importer, we should import function pointer types as @convention(c) function types if they use the target's C calling convention and as opaque pointer types otherwise.
  - SILFunctionType should have the ability to express a calling convention more precisely than just @convention(c). IRGen can just use this value when explicit. For @convention(c), IRGen can ask Clang for the correct LLVM CC to use.
  - SIL type lowering should assign function declarations their actual C calling convention if they use a non-standard calling convention.
  - SILGen may need to introduce thunks when passing around such functions as @convention(c) function values. Code for this already exists in order to allow C functions to be passed around as native function values.

John.

···

On Dec 13, 2017, at 6:42 PM, Saleem Abdulrasool <compnerd@compnerd.org> wrote:

On Dec 13, 2017, at 12:46 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Dec 13, 2017, at 3:22 PM, Saleem Abdulrasool <compnerd@compnerd.org <mailto:compnerd@compnerd.org>> wrote:

On Dec 13, 2017, at 12:14 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Dec 13, 2017, at 2:56 PM, Saleem Abdulrasool <compnerd@compnerd.org <mailto:compnerd@compnerd.org>> wrote:

I think that the FFI to declarations is far more common than the FFI to a function pointer, which is why I am focusing on the imported declaration rather than the imported types. I do agree that supporting additional conventions in the SIL layer would be good for the imported function pointer case. Am I missing something and is the `@convention` used for the imported declarations too?

John.

Hey guys,

I have another fun case that things go wrong in :-). We do not preserve
the calling convention information when importing function decls via the
ClangImporter. I have a pretty simple example in apple/swift#13404.
Importing the following:

float frand(void);
float fadd(float f, float g) { return f + g; }

and using this in swift as:

func f -> Float { return fadd(frand(), frand()); }

will result in the fadd call being elided due to the UB in the CC
mismatch. Im pretty sure that we should be preserving CC information when
importing the interface, probably in `VisitFunctionDecl` in ImportDecl.cpp
(although, I believe it can also be lazily computed). Im not sure which
really would be the best thing to do here.

This can show up on other targets when interfaces uses
`__attribute__((__pcs__))` or `__attribute__((__fastcall__))`,
`__attribute__((__vectorcall__))`, `__attribute__((__regparm__([1-3])))`,
`__attribute__((__stdcall__))`, `__attribute__((__thiscall__))`.

Without enhancing SIL, I'm not sure we have a good option besides refusing
to import function declarations with non-standard CCs.

I don't think we really want to change AST function types to handle
arbitrary imported calling conventions, but we could change SILFunctionType
to be able to store a Clang CC. However, this will require a little bit of
extra work in that, if someone tries to pass around the address of a
fastcall function as a @convention(c) function, we will have to introduce a
thunk. I believe we already do similar kinds of thunking in SILGen, though.

This is slightly problematic as Linux ARM HF and Windows ARM both use a
non-C default (arm_aapcs_vfpcc) which is the test case in the mentioned
PR. That is, even without the attributes the declarations above have a
non-C CC.

I don't think that we are supporting arbitrary calling conventions per
se. This only becomes a problem at the FFI layer, where we want to convert
the swift CC to the foreign CC. The IRGen at that point will generate UB
which will truncate the implementation when the LLVM optimizer runs. I
think that we should at least support AAPCS in both, the standard and VFP,
variants at the very least.

Supporting two C calling conventions is not easier than supporting
arbitrary C calling conventions. All the complexity is in how and where we
represent those CCs. I'm hesitant to introduce this complexity (and
non-portability) into the core language, which is why I'm suggesting just
introducing it into SIL. But I explicitly do not want us to hard-code
specific non-standard conventions from C outside of maybe attribute
parsing; we should generalize the representation to support arbitrary CCs.
I don't think this is hard at the SIL level.

Hmm, I think that we might be looking at different problems. I want to
support the de facto standard CC on the target. If you consider Windows
ARM, “c” is entirely invalid.

@convention(c) cannot be "entirely invalid". @convention(c) means the
platform's C calling convention, which I promise does always exist. The
code "int foo(void); int main() { foo(); }" does actually compile on
Windows ARM, and it uses a calling convention; that is the platform's C
calling convention.

Ah, I was interpreting it to be equivalent to LLVM's notion of the C
calling convention which is not the same as you describe it. On Windows
ARM, the C convention requires an additional annotation of the function
call.

The equivalent of “c” is arm_aapcs_vfpcc. However, there are other cases
where we do need a secondary CC. As an example of that, the AEABI RT
function calls are always made as AAPCS, but on Linux ARM HF targets (e.g.
armv7-unknown-linux-gnueabihf), the default CC is the VFP variant of
AAPCS, so we do need a secondary CC there for some library calls. We
usually get lucky as the function calls there are formed by the backend
which knows the CC necessary for the call there.

I think you might be confusing "the C calling convention" with some other
concept — maybe the default LLVM calling convention? I believe it's true
that LLVM has backends, notably ARM, where the maintainers made the (IMO
questionable) decision to have the default LLVM CC be the same across
operating systems instead of considering the full target triple. That just
means that frontends have an obligation to set the target's actual CC on
every C call and function. I would readily believe that Swift IRGen has
bugs — maybe even pervasive ones — where we fail to do that.

Yes, this is the scenario that I was describing - the need for the frontend
to annotate the call with he correct calling convention for the target
(which is equivalent to swift's notion of `@convention(c)`). However, the
CC annotation is entirely missing even for uses of the declarations as the
information is not preserved during the import stage.

In general, the importer has a lot of flexibility when importing
declarations and very little flexibility when importing types, especially
pointer types. We can only import one kind of function pointer type as a
@convention(c) function type; everything else needs to be imported as an
opaque pointer unless we actually bite the bullet and enhance the AST
@convention system to support more C conventions. For maximum
expressivity, that function pointer type needs to be the type most commonly
used for function pointers on the platform, assuming there is one. It
doesn't really matter if that's not the default calling convention for
function *declarations* because we can always pass around a specific
variant-CC function as a @convention(c) function value by introducing a
thunk; function-pointer equality won't work, but probably nobody cares.
What we can't do is turn an arbitrary variant-CC function *pointer* into a
@convention(c) function pointer. But the correctness of all this relies on
SIL being able to fully represent the C calling convention.

In the case of support of a target which does not support the C calling
convention but expects all calls to be of a specific convention, we
currently fall apart. It sounds like you would prefer that the approach to
handle that would be to map `@convention(c)` to that alternate calling
convention? For importing declarations, we currently do not preserve the
calling convention at all. As a result, right now, FFI calls into C may
introduce UB in the IR.

Yes, we clearly have a responsibility to call things with the right
calling convention, and we should not import types and declarations which
we cannot meet that responsibility for. I am trying to describe the
correct technical design for that, which is:

Great, so we agree on this :-).

  - In the importer, we do not need to assign a specific convention to the
type of an imported function declaration.

I don't understand how this works when we may need to annotate the function
call to match the C calling convention.

  - In the importer, we should import function pointer types as
@convention(c) function types if they use the target's C calling convention
and as opaque pointer types otherwise.

Fair enough.

  - SILFunctionType should have the ability to express a calling
convention more precisely than just @convention(c). IRGen can just use
this value when explicit. For @convention(c), IRGen can ask Clang for the
correct LLVM CC to use.

Agreed that the calls should be able to declare this more precisely. Do we
want to round trip back to clang to get the LLVM CC for this call?
Especially if this is the "C" CC?

  - SIL type lowering should assign function declarations their actual C
calling convention if they use a non-standard calling convention.

Yes.

  - SILGen may need to introduce thunks when passing around such functions
as @convention(c) function values. Code for this already exists in order
to allow C functions to be passed around as native function values.

This sounds pretty good and would broaden the abilities for swift to FFI to
existing code.

John.

I think that the FFI to declarations is far more common than the FFI to a
function pointer, which is why I am focusing on the imported declaration
rather than the imported types. I do agree that supporting additional
conventions in the SIL layer would be good for the imported function
pointer case. Am I missing something and is the `@convention` used for the
imported declarations too?

John.

--

Saleem Abdulrasool
compnerd (at) compnerd (dot) org

···

On Wed, Dec 13, 2017 at 4:14 PM, John McCall <rjmccall@apple.com> wrote:

On Dec 13, 2017, at 6:42 PM, Saleem Abdulrasool <compnerd@compnerd.org> > wrote:
On Dec 13, 2017, at 12:46 PM, John McCall <rjmccall@apple.com> wrote:
On Dec 13, 2017, at 3:22 PM, Saleem Abdulrasool <compnerd@compnerd.org> > wrote:
On Dec 13, 2017, at 12:14 PM, John McCall <rjmccall@apple.com> wrote:
On Dec 13, 2017, at 2:56 PM, Saleem Abdulrasool <compnerd@compnerd.org> > wrote:

Hey guys,

I have another fun case that things go wrong in :-). We do not preserve the calling convention information when importing function decls via the ClangImporter. I have a pretty simple example in apple/swift#13404. Importing the following:

float frand(void);
float fadd(float f, float g) { return f + g; }

and using this in swift as:

func f -> Float { return fadd(frand(), frand()); }

will result in the fadd call being elided due to the UB in the CC mismatch. Im pretty sure that we should be preserving CC information when importing the interface, probably in `VisitFunctionDecl` in ImportDecl.cpp (although, I believe it can also be lazily computed). Im not sure which really would be the best thing to do here.

This can show up on other targets when interfaces uses `__attribute__((__pcs__))` or `__attribute__((__fastcall__))`, `__attribute__((__vectorcall__))`, `__attribute__((__regparm__([1-3])))`, `__attribute__((__stdcall__))`, `__attribute__((__thiscall__))`.

Without enhancing SIL, I'm not sure we have a good option besides refusing to import function declarations with non-standard CCs.

I don't think we really want to change AST function types to handle arbitrary imported calling conventions, but we could change SILFunctionType to be able to store a Clang CC. However, this will require a little bit of extra work in that, if someone tries to pass around the address of a fastcall function as a @convention(c) function, we will have to introduce a thunk. I believe we already do similar kinds of thunking in SILGen, though.

This is slightly problematic as Linux ARM HF and Windows ARM both use a non-C default (arm_aapcs_vfpcc) which is the test case in the mentioned PR. That is, even without the attributes the declarations above have a non-C CC.

I don't think that we are supporting arbitrary calling conventions per se. This only becomes a problem at the FFI layer, where we want to convert the swift CC to the foreign CC. The IRGen at that point will generate UB which will truncate the implementation when the LLVM optimizer runs. I think that we should at least support AAPCS in both, the standard and VFP, variants at the very least.

Supporting two C calling conventions is not easier than supporting arbitrary C calling conventions. All the complexity is in how and where we represent those CCs. I'm hesitant to introduce this complexity (and non-portability) into the core language, which is why I'm suggesting just introducing it into SIL. But I explicitly do not want us to hard-code specific non-standard conventions from C outside of maybe attribute parsing; we should generalize the representation to support arbitrary CCs. I don't think this is hard at the SIL level.

Hmm, I think that we might be looking at different problems. I want to support the de facto standard CC on the target. If you consider Windows ARM, “c” is entirely invalid.

@convention(c) cannot be "entirely invalid". @convention(c) means the platform's C calling convention, which I promise does always exist. The code "int foo(void); int main() { foo(); }" does actually compile on Windows ARM, and it uses a calling convention; that is the platform's C calling convention.

Ah, I was interpreting it to be equivalent to LLVM's notion of the C calling convention which is not the same as you describe it. On Windows ARM, the C convention requires an additional annotation of the function call.

The equivalent of “c” is arm_aapcs_vfpcc. However, there are other cases where we do need a secondary CC. As an example of that, the AEABI RT function calls are always made as AAPCS, but on Linux ARM HF targets (e.g. armv7-unknown-linux-gnueabihf), the default CC is the VFP variant of AAPCS, so we do need a secondary CC there for some library calls. We usually get lucky as the function calls there are formed by the backend which knows the CC necessary for the call there.

I think you might be confusing "the C calling convention" with some other concept — maybe the default LLVM calling convention? I believe it's true that LLVM has backends, notably ARM, where the maintainers made the (IMO questionable) decision to have the default LLVM CC be the same across operating systems instead of considering the full target triple. That just means that frontends have an obligation to set the target's actual CC on every C call and function. I would readily believe that Swift IRGen has bugs — maybe even pervasive ones — where we fail to do that.

Yes, this is the scenario that I was describing - the need for the frontend to annotate the call with he correct calling convention for the target (which is equivalent to swift's notion of `@convention(c)`). However, the CC annotation is entirely missing even for uses of the declarations as the information is not preserved during the import stage.

It's not in the Clang AST, either. Clang function types only carry a calling convention when they're explicitly using a non-standard convention. This is all fine except that we shouldn't just be ignoring non-standard conventions in the importer.

In general, the importer has a lot of flexibility when importing declarations and very little flexibility when importing types, especially pointer types. We can only import one kind of function pointer type as a @convention(c) function type; everything else needs to be imported as an opaque pointer unless we actually bite the bullet and enhance the AST @convention system to support more C conventions. For maximum expressivity, that function pointer type needs to be the type most commonly used for function pointers on the platform, assuming there is one. It doesn't really matter if that's not the default calling convention for function *declarations* because we can always pass around a specific variant-CC function as a @convention(c) function value by introducing a thunk; function-pointer equality won't work, but probably nobody cares. What we can't do is turn an arbitrary variant-CC function *pointer* into a @convention(c) function pointer. But the correctness of all this relies on SIL being able to fully represent the C calling convention.

In the case of support of a target which does not support the C calling convention but expects all calls to be of a specific convention, we currently fall apart. It sounds like you would prefer that the approach to handle that would be to map `@convention(c)` to that alternate calling convention? For importing declarations, we currently do not preserve the calling convention at all. As a result, right now, FFI calls into C may introduce UB in the IR.

Yes, we clearly have a responsibility to call things with the right calling convention, and we should not import types and declarations which we cannot meet that responsibility for. I am trying to describe the correct technical design for that, which is:

Great, so we agree on this :-).

  - In the importer, we do not need to assign a specific convention to the type of an imported function declaration.

I don't understand how this works when we may need to annotate the function call to match the C calling convention.

SIL knows how to map a Swift declaration back to a Clang declaration and use its type to guide SIL type lowering. There's a somewhat obscure set of assumptions at work here.

  - In the importer, we should import function pointer types as @convention(c) function types if they use the target's C calling convention and as opaque pointer types otherwise.

Fair enough.

  - SILFunctionType should have the ability to express a calling convention more precisely than just @convention(c). IRGen can just use this value when explicit. For @convention(c), IRGen can ask Clang for the correct LLVM CC to use.

Agreed that the calls should be able to declare this more precisely. Do we want to round trip back to clang to get the LLVM CC for this call? Especially if this is the "C" CC?

SILFunctionType should carry the Clang CC. When Swift IRGen asks Clang how to lower a function call/declaration, Clang will tell it what LLVM CC to use; it's one of the fields on CGFunctionInfo.

  - SIL type lowering should assign function declarations their actual C calling convention if they use a non-standard calling convention.

Yes.

  - SILGen may need to introduce thunks when passing around such functions as @convention(c) function values. Code for this already exists in order to allow C functions to be passed around as native function values.

This sounds pretty good and would broaden the abilities for swift to FFI to existing code.

Yeah. This should work well as long as there isn't an API that needs to traffic in non-standard function *pointers*.

John.

···

On Dec 13, 2017, at 8:35 PM, Saleem Abdulrasool <compnerd@compnerd.org> wrote:
On Wed, Dec 13, 2017 at 4:14 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Dec 13, 2017, at 6:42 PM, Saleem Abdulrasool <compnerd@compnerd.org <mailto:compnerd@compnerd.org>> wrote:

On Dec 13, 2017, at 12:46 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Dec 13, 2017, at 3:22 PM, Saleem Abdulrasool <compnerd@compnerd.org <mailto:compnerd@compnerd.org>> wrote:

On Dec 13, 2017, at 12:14 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Dec 13, 2017, at 2:56 PM, Saleem Abdulrasool <compnerd@compnerd.org <mailto:compnerd@compnerd.org>> wrote:

John.

I think that the FFI to declarations is far more common than the FFI to a function pointer, which is why I am focusing on the imported declaration rather than the imported types. I do agree that supporting additional conventions in the SIL layer would be good for the imported function pointer case. Am I missing something and is the `@convention` used for the imported declarations too?

John.

--
Saleem Abdulrasool
compnerd (at) compnerd (dot) org

32-bit Windows needs to do that. Callback functions passed to the Windows API via parameters or struct fields are often __stdcall but the default calling convention is __cdecl.

···

On Dec 13, 2017, at 10:28 PM, John McCall via swift-dev <swift-dev@swift.org> wrote:

On Dec 13, 2017, at 8:35 PM, Saleem Abdulrasool <compnerd@compnerd.org <mailto:compnerd@compnerd.org>> wrote:

On Wed, Dec 13, 2017 at 4:14 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

  - SILGen may need to introduce thunks when passing around such functions as @convention(c) function values. Code for this already exists in order to allow C functions to be passed around as native function values.

This sounds pretty good and would broaden the abilities for swift to FFI to existing code.

Yeah. This should work well as long as there isn't an API that needs to traffic in non-standard function *pointers*.

--
Greg Parker gparker@apple.com Runtime Wrangler

Well, I should've guessed. Fortunately, I don't think we're closing out the possibility of supporting multiple calling conventions in the user-facing type system in the future. We can still import C function declarations without a @convention because a global function can be coerced to an arbitrary CC. Technically, I guess you could argue that there ought to be a preference in the constraint-solver for matching a function declaration with its actual CC, but that's a minor enough source-compatibility problem (overloading based on the @convention of an argument function?) that I feel comfortable ignoring it for now, especially since we don't implement that today.

John.

···

On Dec 18, 2017, at 9:34 PM, Greg Parker <gparker@apple.com> wrote:

On Dec 13, 2017, at 10:28 PM, John McCall via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

On Dec 13, 2017, at 8:35 PM, Saleem Abdulrasool <compnerd@compnerd.org <mailto:compnerd@compnerd.org>> wrote:

On Wed, Dec 13, 2017 at 4:14 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

  - SILGen may need to introduce thunks when passing around such functions as @convention(c) function values. Code for this already exists in order to allow C functions to be passed around as native function values.

This sounds pretty good and would broaden the abilities for swift to FFI to existing code.

Yeah. This should work well as long as there isn't an API that needs to traffic in non-standard function *pointers*.

32-bit Windows needs to do that. Callback functions passed to the Windows API via parameters or struct fields are often __stdcall but the default calling convention is __cdecl.