[swift-dev] Preserving and Applying CC in Imported Decls

Saleem Abdulrasool compnerd at compnerd.org
Wed Dec 13 17:42:40 CST 2017



> On Dec 13, 2017, at 12:46 PM, John McCall <rjmccall at apple.com> wrote:
> 
>> 
>> On Dec 13, 2017, at 3:22 PM, Saleem Abdulrasool <compnerd at compnerd.org <mailto:compnerd at compnerd.org>> wrote:
>> 
>> 
>> 
>>> On Dec 13, 2017, at 12:14 PM, John McCall <rjmccall at apple.com <mailto:rjmccall at apple.com>> wrote:
>>> 
>>>> 
>>>> On Dec 13, 2017, at 2:56 PM, Saleem Abdulrasool <compnerd at compnerd.org <mailto:compnerd at 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.  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?

> John.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20171213/484e8d81/attachment.html>


More information about the swift-dev mailing list