Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions lib/AST/ExtInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ UnexpectedClangTypeError::checkClangType(SILFunctionTypeRepresentation silRep,
if (isBlock && !type->isBlockPointerType())
return {{Kind::NotBlockPointer, type}};
if (!isBlock && !(type->isFunctionPointerType()
|| type->isFunctionReferenceType()))
|| type->isFunctionReferenceType()
|| type->isFunctionType()))
return {{Kind::NotFunctionPointerOrReference, type}};
return std::nullopt;
}
Expand Down Expand Up @@ -121,8 +122,8 @@ void UnexpectedClangTypeError::dump() {
return;
}
case Kind::NotFunctionPointerOrReference: {
e << ("Expected function pointer/reference type for @convention(c) function"
" but found:\n");
e << ("Expected function or function pointer/reference type for "
"@convention(c) function but found:\n");
type->dump();
return;
}
Expand Down
25 changes: 24 additions & 1 deletion lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,20 @@ void SignatureExpansion::expandExternalSignatureTypes() {
// Generate function info for this signature.
auto extInfo = clang::FunctionType::ExtInfo();

if (auto clangTy = FnType->getClangTypeInfo().getType()) {
const clang::FunctionType *fnTy = nullptr;

if (auto theFnTy = clangTy->getAs<clang::FunctionType>())
fnTy = theFnTy;
else if (auto ptrTy = clangTy->getAs<clang::PointerType>())
fnTy = ptrTy->getPointeeType()->getAs<clang::FunctionType>();
else if (auto refTy = clangTy->getAs<clang::ReferenceType>())
fnTy = refTy->getPointeeType()->getAs<clang::FunctionType>();

if (fnTy)
extInfo = fnTy->getExtInfo();
}

bool isCXXMethod =
FnType->getRepresentation() == SILFunctionTypeRepresentation::CXXMethod;
auto &FI = isCXXMethod ?
Expand Down Expand Up @@ -2438,9 +2452,18 @@ Signature SignatureExpansion::getSignature() {
(FnType->getLanguage() == SILFunctionLanguage::C) &&
"C function type without C function info");

auto callingConv =
// If we have foreign type information from Clang, take the calling
// convention from there. Otherwise, pick one based on the function
// type representation.
llvm::CallingConv::ID callingConv;

if (ForeignInfo.ClangInfo != nullptr) {
callingConv = ForeignInfo.ClangInfo->getEffectiveCallingConvention();
} else {
callingConv =
expandCallingConv(IGM, FnType->getRepresentation(), FnType->isAsync(),
FnType->isCalleeAllocatedCoroutine());
}

Signature result;
result.Type = llvmType;
Expand Down
7 changes: 7 additions & 0 deletions lib/SIL/IR/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4033,6 +4033,13 @@ static CanSILFunctionType getSILFunctionTypeForClangDecl(

if (auto func = dyn_cast<clang::FunctionDecl>(clangDecl)) {
auto clangType = func->getType().getTypePtr();

if (clangType) {
// Pass the Clang type through, so we can extract information from it
// later on.
extInfoBuilder = extInfoBuilder.withClangFunctionType(clangType);
}

AbstractionPattern origPattern =
foreignInfo.self.isImportAsMember()
? AbstractionPattern::getCFunctionAsMethod(origType, clangType,
Expand Down
16 changes: 16 additions & 0 deletions test/IRGen/Inputs/calling_conventions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef CALLING_CONVENTIONS_H_
#define CALLING_CONVENTIONS_H_

int cdecl_fn(int a, int b, int c);

typedef int (*cdecl_fn_ptr_t)(int a, int b, int c);

extern cdecl_fn_ptr_t cdecl_fn_ptr;

int __attribute__((swiftcall)) swiftcc_fn(int a, int b, int c);

typedef int (__attribute__((swiftcall)) *swiftcc_fn_ptr_t)(int a, int b, int c);

extern swiftcc_fn_ptr_t swiftcc_fn_ptr;

#endif /* CALLING_CONVENTIONS_H_ */
8 changes: 8 additions & 0 deletions test/IRGen/Inputs/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,11 @@ module CFBridgedType {
module RawLayoutCXX {
header "raw_layout_cxx.h"
}

module Win32CallingConventions {
header "win32_calling_conventions.h"
}

module CallingConventions {
header "calling_conventions.h"
}
22 changes: 22 additions & 0 deletions test/IRGen/Inputs/win32_calling_conventions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef STDCALL_FUNCTION_H_
#define STDCALL_FUNCTION_H_

int __stdcall stdcall_fn(int a, int b, int c);

typedef int (__stdcall *stdcall_fn_ptr_t)(int a, int b, int c);

extern stdcall_fn_ptr_t stdcall_fn_ptr;

int __fastcall fastcall_fn(int a, int b, int c);

typedef int (__fastcall *fastcall_fn_ptr_t)(int a, int b, int c);

extern fastcall_fn_ptr_t fastcall_fn_ptr;

int __vectorcall vectorcall_fn(int a, int b, int c);

typedef int (__vectorcall *vectorcall_fn_ptr_t)(int a, int b, int c);

extern vectorcall_fn_ptr_t vectorcall_fn_ptr;

#endif /* STDCALL_FUNCTION_H_ */
17 changes: 17 additions & 0 deletions test/IRGen/calling_conventions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RUN: %target-swift-frontend -module-name calling_conventions -use-clang-function-types -parse-as-library -I %S/Inputs -emit-ir %s | %FileCheck %s

import CallingConventions

func foo() {
// CHECK: call i32 @cdecl_fn(i32 1, i32 2, i32 3)
_ = cdecl_fn(1, 2, 3)

// CHECK: call i32 %{{[0-9]+}}(i32 4, i32 5, i32 6)
_ = cdecl_fn_ptr(4, 5, 6)

// CHECK: call swiftcc i32 @swiftcc_fn(i32 1, i32 2, i32 3)
_ = swiftcc_fn(1, 2, 3)

// CHECK: call swiftcc i32 %{{[0-9]+}}(i32 4, i32 5, i32 6)
_ = swiftcc_fn_ptr(4, 5, 6)
}
2 changes: 1 addition & 1 deletion test/IRGen/unexploded-calls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ public func g(_ s : S) {
// CHECK: [[ALLOCA]].g._value = getelementptr inbounds{{.*}} %TSf, ptr [[ALLOCA]].g, i32 0, i32 0
// CHECK: store float %1, ptr [[ALLOCA]].g._value, align 4
// CHECK: %[[LOAD:.*]] = load %struct.S, ptr [[ALLOCA]], align 4
// CHECK: call void @f(%struct.S %[[LOAD]])
// CHECK: call arm_aapcs_vfpcc void @f(%struct.S %[[LOAD]])
// CHECK: }

25 changes: 25 additions & 0 deletions test/IRGen/win32_calling_conventions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// RUN: %swift-frontend-plain -target i686-unknown-windows-msvc -module-name win32_calling_conventions -use-clang-function-types -parse-as-library -I %S/Inputs -emit-ir %s | %FileCheck %s

// REQUIRES: OS=windows-msvc

import Win32CallingConventions

func foo() {
// CHECK: call x86_stdcallcc i32 @cdecl_fn(i32 1, i32 2, i32 3)
stdcall_fn(1, 2, 3)

// CHECK: call x86_stdcallcc i32 %{{[0-9]+}}(i32 4, i32 5, i32 6)
stdcall_fn_ptr(4, 5, 6)

// CHECK: call x86_fastcallcc i32 @cdecl_fn(i32 1, i32 2, i32 3)
fastcall_fn(1, 2, 3)

// CHECK: call x86_fastcallcc i32 %{{[0-9]+}}(i32 4, i32 5, i32 6)
fastcall_fn_ptr(4, 5, 6)

// CHECK: call x86_vectorcallcc i32 @cdecl_fn(i32 1, i32 2, i32 3)
vectorcall_fn(1, 2, 3)

// CHECK: call x86_vectorcallcc i32 %{{[0-9]+}}(i32 4, i32 5, i32 6)
vectorcall_fn_ptr(4, 5, 6)
}