Merge pull request #85505 from DougGregor/c-funcs-for-embedded-runtime

Use @c instead of @_cdecl in the Embedded Swift runtime
This commit is contained in:
Doug Gregor
2025-11-13 23:41:03 -08:00
committed by GitHub
11 changed files with 138 additions and 66 deletions

View File

@@ -403,6 +403,11 @@ void SwiftARCContract::getAnalysisUsage(llvm::AnalysisUsage &AU) const {
llvm::PreservedAnalyses
SwiftARCContractPass::run(llvm::Function &F,
llvm::FunctionAnalysisManager &AM) {
// Don't touch those functions that implement reference counting in the
// runtime.
if (!allowArcOptimizations(F.getName()))
return PreservedAnalyses::all();
bool changed = SwiftARCContractImpl(F).run();
if (!changed)
return PreservedAnalyses::all();

View File

@@ -1015,6 +1015,12 @@ void SwiftARCOpt::getAnalysisUsage(llvm::AnalysisUsage &AU) const {
static bool runSwiftARCOpts(Function &F, SwiftRCIdentity &RC) {
bool Changed = false;
// Don't touch those functions that implement reference counting in the
// runtime.
if (!allowArcOptimizations(F.getName()))
return Changed;
ARCEntryPointBuilder B(F);
// First thing: canonicalize swift_retain and similar calls so that nothing

View File

@@ -26,6 +26,62 @@ enum RT_Kind {
#include "LLVMSwift.def"
};
inline RT_Kind classifyFunctionName(StringRef name) {
return llvm::StringSwitch<RT_Kind>(name)
#define SWIFT_FUNC(Name, MemBehavior, TextualName) \
.Case("swift_" #TextualName, RT_ ## Name)
#define SWIFT_INTERNAL_FUNC_NEVER_NONATOMIC(Name, MemBehavior, TextualName) \
.Case("__swift_" #TextualName, RT_ ## Name)
#include "LLVMSwift.def"
// Identify "Client" versions of reference counting entry points.
#define SWIFT_FUNC(Name, MemBehavior, TextualName) \
.Case("swift_" #TextualName "Client", RT_ ## Name)
#define SWIFT_INTERNAL_FUNC_NEVER_NONATOMIC(Name, MemBehavior, TextualName) \
.Case("__swift_" #TextualName "Client", RT_ ## Name)
#include "LLVMSwift.def"
// Support non-atomic versions of reference counting entry points.
#define SWIFT_FUNC(Name, MemBehavior, TextualName) \
.Case("swift_nonatomic_" #TextualName, RT_ ## Name)
#define OBJC_FUNC(Name, MemBehavior, TextualName) \
.Case("objc_nonatomic_" #TextualName, RT_ ## Name)
#define SWIFT_INTERNAL_FUNC_NEVER_NONATOMIC(Name, MemBehavior, TextualName)
#include "LLVMSwift.def"
.Default(RT_Unknown);
}
/// Whether to allow ARC optimizations for a function with the given name.
inline bool allowArcOptimizations(StringRef name) {
switch (classifyFunctionName(name)) {
case RT_UnknownObjectRetainN:
case RT_BridgeRetainN:
case RT_RetainN:
case RT_UnknownObjectReleaseN:
case RT_BridgeReleaseN:
case RT_ReleaseN:
case RT_UnknownObjectRetain:
case RT_UnknownObjectRelease:
case RT_Retain:
case RT_ObjCRetain:
case RT_ObjCRelease:
case RT_RetainUnowned:
case RT_Release:
case RT_BridgeRetain:
case RT_BridgeRelease:
return false;
case RT_Unknown:
case RT_NoMemoryAccessed:
case RT_CheckUnowned:
case RT_AllocObject:
case RT_FixLifetime:
case RT_EndBorrow:
return true;
}
}
/// Take a look at the specified instruction and classify it into what kind of
/// runtime entrypoint it is, if any.
inline RT_Kind classifyInstruction(const llvm::Instruction &I) {
@@ -57,29 +113,7 @@ inline RT_Kind classifyInstruction(const llvm::Instruction &I) {
if (F == nullptr)
return RT_Unknown;
return llvm::StringSwitch<RT_Kind>(F->getName())
#define SWIFT_FUNC(Name, MemBehavior, TextualName) \
.Case("swift_" #TextualName, RT_ ## Name)
#define SWIFT_INTERNAL_FUNC_NEVER_NONATOMIC(Name, MemBehavior, TextualName) \
.Case("__swift_" #TextualName, RT_ ## Name)
#include "LLVMSwift.def"
// Identify "Client" versions of reference counting entry points.
#define SWIFT_FUNC(Name, MemBehavior, TextualName) \
.Case("swift_" #TextualName "Client", RT_ ## Name)
#define SWIFT_INTERNAL_FUNC_NEVER_NONATOMIC(Name, MemBehavior, TextualName) \
.Case("__swift_" #TextualName "Client", RT_ ## Name)
#include "LLVMSwift.def"
// Support non-atomic versions of reference counting entry points.
#define SWIFT_FUNC(Name, MemBehavior, TextualName) \
.Case("swift_nonatomic_" #TextualName, RT_ ## Name)
#define OBJC_FUNC(Name, MemBehavior, TextualName) \
.Case("objc_nonatomic_" #TextualName, RT_ ## Name)
#define SWIFT_INTERNAL_FUNC_NEVER_NONATOMIC(Name, MemBehavior, TextualName)
#include "LLVMSwift.def"
.Default(RT_Unknown);
return classifyFunctionName(F->getName());
}
} // end namespace swift

View File

@@ -1025,7 +1025,8 @@ SerializedKind_t SILDeclRef::getSerializedKind() const {
// @objc thunks for top-level functions are serializable since they're
// referenced from @convention(c) conversions inside inlinable
// functions.
return IsSerialized;
if (isThunk())
return IsSerialized;
}
// Declarations imported from Clang modules are serialized if

View File

@@ -149,14 +149,14 @@ func alignedAlloc(size: Int, alignment: Int) -> UnsafeMutableRawPointer? {
return unsafe r
}
@_cdecl("swift_coroFrameAlloc")
@c
public func swift_coroFrameAlloc(_ size: Int, _ type: UInt) -> UnsafeMutableRawPointer? {
return unsafe alignedAlloc(
size: size,
alignment: _swift_MinAllocationAlignment)
}
@_cdecl("swift_slowAlloc")
@c
public func swift_slowAlloc(_ size: Int, _ alignMask: Int) -> UnsafeMutableRawPointer? {
let alignment: Int
if alignMask == -1 {
@@ -167,12 +167,12 @@ public func swift_slowAlloc(_ size: Int, _ alignMask: Int) -> UnsafeMutableRawPo
return unsafe alignedAlloc(size: size, alignment: alignment)
}
@_cdecl("swift_slowDealloc")
@c
public func swift_slowDealloc(_ ptr: UnsafeMutableRawPointer, _ size: Int, _ alignMask: Int) {
unsafe free(ptr)
}
@_cdecl("swift_allocObject")
@c
public func swift_allocObject(metadata: Builtin.RawPointer, requiredSize: Int, requiredAlignmentMask: Int) -> Builtin.RawPointer {
return unsafe swift_allocObject(metadata: UnsafeMutablePointer<ClassMetadata>(metadata), requiredSize: requiredSize, requiredAlignmentMask: requiredAlignmentMask)._rawValue
}
@@ -185,7 +185,7 @@ func swift_allocObject(metadata: UnsafeMutablePointer<ClassMetadata>, requiredSi
return unsafe object
}
@_cdecl("swift_deallocUninitializedObject")
@c
public func swift_deallocUninitializedObject(object: Builtin.RawPointer, allocatedSize: Int, allocatedAlignMask: Int) {
unsafe swift_deallocObject(
object: UnsafeMutablePointer<HeapObject>(object),
@@ -193,7 +193,7 @@ public func swift_deallocUninitializedObject(object: Builtin.RawPointer, allocat
allocatedAlignMask: allocatedAlignMask)
}
@_cdecl("swift_deallocObject")
@c
public func swift_deallocObject(object: Builtin.RawPointer, allocatedSize: Int, allocatedAlignMask: Int) {
unsafe swift_deallocObject(object: UnsafeMutablePointer<HeapObject>(object), allocatedSize: allocatedSize, allocatedAlignMask: allocatedAlignMask)
}
@@ -202,7 +202,7 @@ func swift_deallocObject(object: UnsafeMutablePointer<HeapObject>, allocatedSize
unsafe free(UnsafeMutableRawPointer(object))
}
@_cdecl("swift_deallocClassInstance")
@c
public func swift_deallocClassInstance(object: Builtin.RawPointer, allocatedSize: Int, allocatedAlignMask: Int) {
unsafe swift_deallocClassInstance(object: UnsafeMutablePointer<HeapObject>(object), allocatedSize: allocatedSize, allocatedAlignMask: allocatedAlignMask)
}
@@ -215,7 +215,7 @@ func swift_deallocClassInstance(object: UnsafeMutablePointer<HeapObject>, alloca
unsafe free(UnsafeMutableRawPointer(object))
}
@_cdecl("swift_deallocPartialClassInstance")
@c
public func swift_deallocPartialClassInstance(object: Builtin.RawPointer, metadata: Builtin.RawPointer, allocatedSize: Int, allocatedAlignMask: Int) {
unsafe swift_deallocPartialClassInstance(object: UnsafeMutablePointer<HeapObject>(object), metadata: UnsafeMutablePointer<ClassMetadata>(metadata), allocatedSize: allocatedSize, allocatedAlignMask: allocatedAlignMask)
}
@@ -229,7 +229,7 @@ func swift_deallocPartialClassInstance(object: UnsafeMutablePointer<HeapObject>,
}
}
@_cdecl("swift_initStaticObject")
@c
public func swift_initStaticObject(metadata: Builtin.RawPointer, object: Builtin.RawPointer) -> Builtin.RawPointer {
return unsafe swift_initStaticObject(metadata: UnsafeMutablePointer<ClassMetadata>(metadata), object: UnsafeMutablePointer<HeapObject>(object))._rawValue
}
@@ -240,7 +240,7 @@ func swift_initStaticObject(metadata: UnsafeMutablePointer<ClassMetadata>, objec
return unsafe object
}
@_cdecl("swift_initStackObject")
@c
public func swift_initStackObject(metadata: Builtin.RawPointer, object: Builtin.RawPointer) -> Builtin.RawPointer {
return unsafe swift_initStackObject(metadata: UnsafeMutablePointer<ClassMetadata>(metadata), object: UnsafeMutablePointer<HeapObject>(object))._rawValue
}
@@ -254,7 +254,7 @@ func swift_initStackObject(metadata: UnsafeMutablePointer<ClassMetadata>, object
@unsafe
public var _emptyBoxStorage: (Int, Int) = (/*isa*/0, /*refcount*/-1)
@_cdecl("swift_allocEmptyBox")
@c
public func swift_allocEmptyBox() -> Builtin.RawPointer {
let box = unsafe Builtin.addressof(&_emptyBoxStorage)
swift_retain(object: box)
@@ -275,11 +275,11 @@ func isValidPointerForNativeRetain(object: Builtin.RawPointer) -> Bool {
return true
}
@_cdecl("swift_setDeallocating")
@c
public func swift_setDeallocating(object: Builtin.RawPointer) {
}
@_cdecl("swift_dynamicCastClass")
@c
public func swift_dynamicCastClass(object: UnsafeMutableRawPointer, targetMetadata: UnsafeRawPointer) -> UnsafeMutableRawPointer? {
let sourceObj = unsafe object.assumingMemoryBound(to: HeapObject.self)
var type = unsafe _swift_embedded_get_heap_object_metadata_pointer(sourceObj).assumingMemoryBound(to: ClassMetadata.self)
@@ -293,7 +293,7 @@ public func swift_dynamicCastClass(object: UnsafeMutableRawPointer, targetMetada
return unsafe object
}
@_cdecl("swift_dynamicCastClassUnconditional")
@c
public func swift_dynamicCastClassUnconditional(object: UnsafeMutableRawPointer, targetMetadata: UnsafeRawPointer,
file: UnsafePointer<CChar>, line: CUnsignedInt, column: CUnsignedInt) -> UnsafeMutableRawPointer {
guard let result = unsafe swift_dynamicCastClass(object: object, targetMetadata: targetMetadata) else {
@@ -302,7 +302,7 @@ public func swift_dynamicCastClassUnconditional(object: UnsafeMutableRawPointer,
return unsafe result
}
@_cdecl("swift_isEscapingClosureAtFileLocation")
@c
public func swift_isEscapingClosureAtFileLocation(object: Builtin.RawPointer, filename: UnsafePointer<CChar>, filenameLength: Int32, line: Int32, column: Int32, verificationType: CUnsignedInt) -> Bool {
let objectBits = UInt(Builtin.ptrtoint_Word(object))
if objectBits == 0 { return false }
@@ -313,14 +313,14 @@ public func swift_isEscapingClosureAtFileLocation(object: Builtin.RawPointer, fi
return false
}
@_cdecl("swift_isUniquelyReferenced_native")
@c
public func swift_isUniquelyReferenced_native(object: Builtin.RawPointer) -> Bool {
if !isValidPointerForNativeRetain(object: object) { return false }
return unsafe swift_isUniquelyReferenced_nonNull_native(object: UnsafeMutablePointer<HeapObject>(object))
}
@_cdecl("swift_isUniquelyReferenced_nonNull_native")
@c
public func swift_isUniquelyReferenced_nonNull_native(object: Builtin.RawPointer) -> Bool {
return unsafe swift_isUniquelyReferenced_nonNull_native(object: UnsafeMutablePointer<HeapObject>(object))
}
@@ -330,7 +330,7 @@ func swift_isUniquelyReferenced_nonNull_native(object: UnsafeMutablePointer<Heap
return unsafe loadAcquire(refcount) == 1
}
@_cdecl("swift_retain")
@c
@discardableResult
public func swift_retain(object: Builtin.RawPointer) -> Builtin.RawPointer {
if !isValidPointerForNativeRetain(object: object) { return object }
@@ -340,7 +340,7 @@ public func swift_retain(object: Builtin.RawPointer) -> Builtin.RawPointer {
}
// Cannot use UnsafeMutablePointer<HeapObject>? directly in the function argument or return value as it causes IRGen crashes
@_cdecl("swift_retain_n")
@c
public func swift_retain_n(object: Builtin.RawPointer, n: UInt32) -> Builtin.RawPointer {
if !isValidPointerForNativeRetain(object: object) { return object }
@@ -359,20 +359,20 @@ func swift_retain_n_(object: UnsafeMutablePointer<HeapObject>, n: UInt32) -> Uns
return unsafe object
}
@_cdecl("swift_bridgeObjectRetain")
@c
@discardableResult
public func swift_bridgeObjectRetain(object: Builtin.RawPointer) -> Builtin.RawPointer {
return swift_bridgeObjectRetain_n(object: object, n: 1)
}
@_cdecl("swift_bridgeObjectRetain_n")
@c
public func swift_bridgeObjectRetain_n(object: Builtin.RawPointer, n: UInt32) -> Builtin.RawPointer {
let objectBits = UInt(Builtin.ptrtoint_Word(object))
let untaggedObject = unsafe Builtin.inttoptr_Word((objectBits & HeapObject.bridgeObjectToPlainObjectMask)._builtinWordValue)
return swift_retain_n(object: untaggedObject, n: n)
}
@_cdecl("swift_release")
@c
public func swift_release(object: Builtin.RawPointer) {
if !isValidPointerForNativeRetain(object: object) { return }
@@ -380,7 +380,7 @@ public func swift_release(object: Builtin.RawPointer) {
unsafe swift_release_n_(object: o, n: 1)
}
@_cdecl("swift_release_n")
@c
public func swift_release_n(object: Builtin.RawPointer, n: UInt32) {
if !isValidPointerForNativeRetain(object: object) { return }
@@ -419,19 +419,19 @@ func swift_release_n_(object: UnsafeMutablePointer<HeapObject>?, n: UInt32) {
}
}
@_cdecl("swift_bridgeObjectRelease")
@c
public func swift_bridgeObjectRelease(object: Builtin.RawPointer) {
swift_bridgeObjectRelease_n(object: object, n: 1)
}
@_cdecl("swift_bridgeObjectRelease_n")
@c
public func swift_bridgeObjectRelease_n(object: Builtin.RawPointer, n: UInt32) {
let objectBits = UInt(Builtin.ptrtoint_Word(object))
let untaggedObject = unsafe Builtin.inttoptr_Word((objectBits & HeapObject.bridgeObjectToPlainObjectMask)._builtinWordValue)
swift_release_n(object: untaggedObject, n: n)
}
@_cdecl("swift_retainCount")
@c
public func swift_retainCount(object: Builtin.RawPointer) -> Int {
if !isValidPointerForNativeRetain(object: object) { return 0 }
let o = unsafe UnsafeMutablePointer<HeapObject>(object)
@@ -478,12 +478,12 @@ fileprivate func storeRelaxed(_ atomic: UnsafeMutablePointer<Int>, newValue: Int
/// Exclusivity checking
@_cdecl("swift_beginAccess")
@c
public func swift_beginAccess(pointer: UnsafeMutableRawPointer, buffer: UnsafeMutableRawPointer, flags: UInt, pc: UnsafeMutableRawPointer) {
// TODO: Add actual exclusivity checking.
}
@_cdecl("swift_endAccess")
@c
public func swift_endAccess(buffer: UnsafeMutableRawPointer) {
// TODO: Add actual exclusivity checking.
}
@@ -492,7 +492,7 @@ public func swift_endAccess(buffer: UnsafeMutableRawPointer) {
// Once
@_cdecl("swift_once")
@c
public func swift_once(predicate: UnsafeMutablePointer<Int>, fn: (@convention(c) (UnsafeMutableRawPointer)->()), context: UnsafeMutableRawPointer) {
let checkedLoadAcquire = { predicate in
let value = unsafe loadAcquire(predicate)
@@ -519,12 +519,12 @@ public func swift_once(predicate: UnsafeMutablePointer<Int>, fn: (@convention(c)
// Misc
@_cdecl("swift_deletedMethodError")
@c
public func swift_deletedMethodError() -> Never {
Builtin.int_trap()
}
@_silgen_name("swift_willThrow") // This is actually expected to be swiftcc (@_silgen_name and not @_cdecl).
@_silgen_name("swift_willThrow") // This is actually expected to be swiftcc (@_silgen_name and not @c).
public func swift_willThrow() throws {
}
@@ -540,7 +540,7 @@ public func swift_stdlib_random(_ buf: UnsafeMutableRawPointer, _ nbytes: Int) {
unsafe arc4random_buf(buf: buf, nbytes: nbytes)
}
@_cdecl("swift_clearSensitive")
@c
@inline(never)
public func swift_clearSensitive(buf: UnsafeMutableRawPointer, nbytes: Int) {
// TODO: use memset_s if available
@@ -552,7 +552,6 @@ public func swift_clearSensitive(buf: UnsafeMutableRawPointer, nbytes: Int) {
}
}
@usableFromInline
@inline(never)
func _embeddedReportFatalError(prefix: StaticString, message: StaticString) {
print(prefix, terminator: "")
@@ -560,7 +559,6 @@ func _embeddedReportFatalError(prefix: StaticString, message: StaticString) {
print(message)
}
@usableFromInline
@inline(never)
func _embeddedReportFatalErrorInFile(prefix: StaticString, message: StaticString, file: StaticString, line: UInt) {
print(file, terminator: ":")
@@ -570,7 +568,6 @@ func _embeddedReportFatalErrorInFile(prefix: StaticString, message: StaticString
print(message)
}
@usableFromInline
@inline(never)
func _embeddedReportFatalErrorInFile(prefix: StaticString, message: UnsafeBufferPointer<UInt8>, file: StaticString, line: UInt) {
print(file, terminator: ":")

View File

@@ -6,4 +6,4 @@ func zerome(ptr: UnsafeMutablePointer<Int>) {
}
// Verify that the asmname is "memset", not a C++-mangled version
// CHECK: sil [serialized] [asmname "memset"] [clang memset] @$sSo6memsetySvSgAB_s5Int32VSitFTo : $@convention(c) (Optional<UnsafeMutableRawPointer>, Int32, Int) -> Optional<UnsafeMutableRawPointer>
// CHECK: sil [asmname "memset"] [clang memset] @$sSo6memsetySvSgAB_s5Int32VSitFTo : $@convention(c) (Optional<UnsafeMutableRawPointer>, Int32, Int) -> Optional<UnsafeMutableRawPointer>

View File

@@ -35,4 +35,4 @@ public func test() {
// CHECK-LABEL: sil {{.*}}[asmname "{{.*}}test{{.*}}"] [clang DeletedSpecialMembers.test] @$sSo21DeletedSpecialMembersV4tests5Int32VyFTo : $@convention(cxx_method) (DeletedSpecialMembers) -> Int32
// CHECK-LABEL: sil [serialized] [asmname "{{.*}}mutate{{.*}}"] [clang mutateIt] @$sSo8mutateItyySo21DeletedSpecialMembersVFTo : $@convention(c) (DeletedSpecialMembers) -> ()
// CHECK-LABEL: sil [asmname "{{.*}}mutate{{.*}}"] [clang mutateIt] @$sSo8mutateItyySo21DeletedSpecialMembersVFTo : $@convention(c) (DeletedSpecialMembers) -> ()

View File

@@ -33,7 +33,7 @@ func requiresThunk() {
acceptSwiftFunc(orange)
}
// CHECK-LABEL: sil [serialized] [asmname "cauliflower"] [ossa] @$s5cdecl8broccoliyS2iFTo : $@convention(c) (Int) -> Int {
// CHECK-LABEL: sil [asmname "cauliflower"] [ossa] @$s5cdecl8broccoliyS2iFTo : $@convention(c) (Int) -> Int {
// CHECK-NOT: apply
// CHECK: return
@c(cauliflower)

View File

@@ -10,7 +10,7 @@ func withCName(_ x: Int) -> Int
@_extern(c, "take_c_func_ptr")
func takeCFuncPtr(_ f: @convention(c) (Int) -> Int)
// CHECK-DAG: sil [serialized] [asmname "public_visible"] @$s8extern_c16publicVisibilityyS2iFTo : $@convention(c) (Int) -> Int
// CHECK-DAG: sil [asmname "public_visible"] @$s8extern_c16publicVisibilityyS2iFTo : $@convention(c) (Int) -> Int
@_extern(c, "public_visible")
public func publicVisibility(_ x: Int) -> Int

View File

@@ -26,9 +26,6 @@
// Never referenced.
// LIBRARY-IR-NOT: @"$es23_swiftEmptyArrayStorageSi_S3itvp" = linkonce_odr {{(protected |dllexport )?}}global
// Note: referenced by swift_allocEmptyBox.
// LIBRARY-IR: @"$es16_emptyBoxStorageSi_Sitvp" = linkonce_odr {{(protected |dllexport )?}}global
// LIBRARY-IR-NOT: define {{.*}}@"$e7Library5helloSaySiGyF"()
public func hello() -> [Int] {
getArray()

View File

@@ -0,0 +1,32 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// Library module
// SIL checking
// RUN: %target-swift-frontend %t/Library.swift -parse-as-library -entry-point-function-name Library_main -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -emit-sil -emit-module-path %t/Modules/Library.swiftmodule -o - | %FileCheck -check-prefix LIBRARY-SIL %s
// RUN: %target-swift-frontend %t/Application.swift -I %t/Modules -parse-as-library -entry-point-function-name Application_main -enable-experimental-feature Embedded -emit-sil -o - | %FileCheck -check-prefix APPLICATION-SIL %s
// REQUIRES: swift_in_compiler
// REQUIRES: swift_feature_Embedded
// REQUIRES: swift_feature_DeferredCodeGen
//--- Library.swift
func internalFunc() { }
// LIBRARY-SIL: sil [asmname "swift_dosomething"] @$e7Library17swift_dosomethingyyFTo : $@convention(c) () -> () {
@c
public func swift_dosomething() {
internalFunc()
}
//--- Application.swift
import Library
// APPLICATION-SIL-LABEL: sil @$e11Application4testyyF : $@convention(thin) () -> ()
public func test() {
// CHECK: function_ref @$e7Library17swift_dosomethingyyFTo : $@convention(c) () -> ()
swift_dosomething()
}