> On Dec 13, 2017, at 12:46 PM, John McCall <rjmcc...@apple.com> wrote: > >> >> On Dec 13, 2017, at 3:22 PM, Saleem Abdulrasool <compn...@compnerd.org >> <mailto:compn...@compnerd.org>> wrote: >> >> >> >>> On Dec 13, 2017, at 12:14 PM, John McCall <rjmcc...@apple.com >>> <mailto:rjmcc...@apple.com>> wrote: >>> >>>> >>>> On Dec 13, 2017, at 2:56 PM, Saleem Abdulrasool <compn...@compnerd.org >>>> <mailto:compn...@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.
_______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev