From 6383d05ea1bcdd9a4455e9edcd2724344825acf4 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 29 Jan 2024 15:37:46 -0800 Subject: [PATCH] [embedded] Fix calling convention on embedded runtime APIs (switch @_silgen_name for @_cdecl) --- stdlib/public/core/EmbeddedRuntime.swift | 76 ++++++++++++------- test/embedded/lto-multiple-object-files.swift | 56 ++++++++++++++ 2 files changed, 106 insertions(+), 26 deletions(-) create mode 100644 test/embedded/lto-multiple-object-files.swift diff --git a/stdlib/public/core/EmbeddedRuntime.swift b/stdlib/public/core/EmbeddedRuntime.swift index b1b1888d4b5..a0b518be0ca 100644 --- a/stdlib/public/core/EmbeddedRuntime.swift +++ b/stdlib/public/core/EmbeddedRuntime.swift @@ -48,10 +48,10 @@ public struct HeapObject { /// Forward declarations of C functions -@_silgen_name("posix_memalign") +@_extern(c, "posix_memalign") func posix_memalign(_: UnsafeMutablePointer, _: Int, _: Int) -> CInt -@_silgen_name("free") +@_extern(c, "free") func free(_ p: Builtin.RawPointer) @@ -81,8 +81,12 @@ public func swift_slowDealloc(_ ptr: UnsafeMutableRawPointer, _ size: Int, _ ali free(ptr._rawValue) } -@_silgen_name("swift_allocObject") -public func swift_allocObject(metadata: UnsafeMutablePointer, requiredSize: Int, requiredAlignmentMask: Int) -> UnsafeMutablePointer { +@_cdecl("swift_allocObject") +public func swift_allocObject(metadata: Builtin.RawPointer, requiredSize: Int, requiredAlignmentMask: Int) -> Builtin.RawPointer { + return swift_allocObject(metadata: UnsafeMutablePointer(metadata), requiredSize: requiredSize, requiredAlignmentMask: requiredAlignmentMask)._rawValue +} + +func swift_allocObject(metadata: UnsafeMutablePointer, requiredSize: Int, requiredAlignmentMask: Int) -> UnsafeMutablePointer { let p = swift_slowAlloc(requiredSize, requiredAlignmentMask)! let object = p.assumingMemoryBound(to: HeapObject.self) _swift_embedded_set_heap_object_metadata_pointer(object, metadata) @@ -90,13 +94,21 @@ public func swift_allocObject(metadata: UnsafeMutablePointer, req return object } -@_silgen_name("swift_deallocObject") -public func swift_deallocObject(object: UnsafeMutablePointer, allocatedSize: Int, allocatedAlignMask: Int) { +@_cdecl("swift_deallocObject") +public func swift_deallocObject(object: Builtin.RawPointer, allocatedSize: Int, allocatedAlignMask: Int) { + swift_deallocObject(object: UnsafeMutablePointer(object), allocatedSize: allocatedSize, allocatedAlignMask: allocatedAlignMask) +} + +func swift_deallocObject(object: UnsafeMutablePointer, allocatedSize: Int, allocatedAlignMask: Int) { free(object._rawValue) } -@_silgen_name("swift_deallocClassInstance") -public func swift_deallocClassInstance(object: UnsafeMutablePointer, allocatedSize: Int, allocatedAlignMask: Int) { +@_cdecl("swift_deallocClassInstance") +public func swift_deallocClassInstance(object: Builtin.RawPointer, allocatedSize: Int, allocatedAlignMask: Int) { + swift_deallocClassInstance(object: UnsafeMutablePointer(object), allocatedSize: allocatedSize, allocatedAlignMask: allocatedAlignMask) +} + +func swift_deallocClassInstance(object: UnsafeMutablePointer, allocatedSize: Int, allocatedAlignMask: Int) { if (object.pointee.refcount & HeapObject.doNotFreeBit) != 0 { return } @@ -104,15 +116,23 @@ public func swift_deallocClassInstance(object: UnsafeMutablePointer, free(object._rawValue) } -@_silgen_name("swift_initStaticObject") -public func swift_initStaticObject(metadata: UnsafeMutablePointer, object: UnsafeMutablePointer) -> UnsafeMutablePointer { +@_cdecl("swift_initStaticObject") +public func swift_initStaticObject(metadata: Builtin.RawPointer, object: Builtin.RawPointer) -> Builtin.RawPointer { + return swift_initStaticObject(metadata: UnsafeMutablePointer(metadata), object: UnsafeMutablePointer(object))._rawValue +} + +func swift_initStaticObject(metadata: UnsafeMutablePointer, object: UnsafeMutablePointer) -> UnsafeMutablePointer { _swift_embedded_set_heap_object_metadata_pointer(object, metadata) object.pointee.refcount = HeapObject.immortalRefCount return object } -@_silgen_name("swift_initStackObject") -public func swift_initStackObject(metadata: UnsafeMutablePointer, object: UnsafeMutablePointer) -> UnsafeMutablePointer { +@_cdecl("swift_initStackObject") +public func swift_initStackObject(metadata: Builtin.RawPointer, object: Builtin.RawPointer) -> Builtin.RawPointer { + return swift_initStackObject(metadata: UnsafeMutablePointer(metadata), object: UnsafeMutablePointer(object))._rawValue +} + +func swift_initStackObject(metadata: UnsafeMutablePointer, object: UnsafeMutablePointer) -> UnsafeMutablePointer { _swift_embedded_set_heap_object_metadata_pointer(object, metadata) object.pointee.refcount = 1 | HeapObject.doNotFreeBit return object @@ -122,17 +142,21 @@ public func swift_initStackObject(metadata: UnsafeMutablePointer, /// Refcounting -@_silgen_name("swift_setDeallocating") -public func swift_setDeallocating(object: UnsafeMutablePointer) { +@_cdecl("swift_setDeallocating") +public func swift_setDeallocating(object: Builtin.RawPointer) { } -@_silgen_name("swift_isUniquelyReferenced_nonNull_native") -public func swift_isUniquelyReferenced_nonNull_native(object: UnsafeMutablePointer) -> Bool { +@_cdecl("swift_isUniquelyReferenced_nonNull_native") +public func swift_isUniquelyReferenced_nonNull_native(object: Builtin.RawPointer) -> Bool { + return swift_isUniquelyReferenced_nonNull_native(object: UnsafeMutablePointer(object)) +} + +func swift_isUniquelyReferenced_nonNull_native(object: UnsafeMutablePointer) -> Bool { let refcount = refcountPointer(for: object) return loadAcquire(refcount) == 1 } -@_silgen_name("swift_retain") +@_cdecl("swift_retain") public func swift_retain(object: Builtin.RawPointer) -> Builtin.RawPointer { if Int(Builtin.ptrtoint_Word(object)) == 0 { return object } let o = UnsafeMutablePointer(object) @@ -140,7 +164,7 @@ public func swift_retain(object: Builtin.RawPointer) -> Builtin.RawPointer { } // Cannot use UnsafeMutablePointer? directly in the function argument or return value as it causes IRGen crashes -@_silgen_name("swift_retain_n") +@_cdecl("swift_retain_n") public func swift_retain_n(object: Builtin.RawPointer, n: UInt32) -> Builtin.RawPointer { if Int(Builtin.ptrtoint_Word(object)) == 0 { return object } let o = UnsafeMutablePointer(object) @@ -158,21 +182,21 @@ func swift_retain_n_(object: UnsafeMutablePointer, n: UInt32) -> Uns return object } -@_silgen_name("swift_release") +@_cdecl("swift_release") public func swift_release(object: Builtin.RawPointer) { if Int(Builtin.ptrtoint_Word(object)) == 0 { return } let o = UnsafeMutablePointer(object) swift_release_n_(object: o, n: 1) } -@_silgen_name("swift_release_n") +@_cdecl("swift_release_n") public func swift_release_n(object: Builtin.RawPointer, n: UInt32) { if Int(Builtin.ptrtoint_Word(object)) == 0 { return } let o = UnsafeMutablePointer(object) swift_release_n_(object: o, n: n) } -public func swift_release_n_(object: UnsafeMutablePointer?, n: UInt32) { +func swift_release_n_(object: UnsafeMutablePointer?, n: UInt32) { guard let object else { return } @@ -228,12 +252,12 @@ fileprivate func storeRelease(_ atomic: UnsafeMutablePointer, newValue: Int /// Exclusivity checking -@_silgen_name("swift_beginAccess") +@_cdecl("swift_beginAccess") public func swift_beginAccess(pointer: UnsafeMutableRawPointer, buffer: UnsafeMutableRawPointer, flags: UInt, pc: UnsafeMutableRawPointer) { // TODO: Add actual exclusivity checking. } -@_silgen_name("swift_endAccess") +@_cdecl("swift_endAccess") public func swift_endAccess(buffer: UnsafeMutableRawPointer) { // TODO: Add actual exclusivity checking. } @@ -242,7 +266,7 @@ public func swift_endAccess(buffer: UnsafeMutableRawPointer) { // Once -@_silgen_name("swift_once") +@_cdecl("swift_once") public func swift_once(predicate: UnsafeMutablePointer, fn: (@convention(c) (UnsafeMutableRawPointer)->()), context: UnsafeMutableRawPointer) { let checkedLoadAcquire = { predicate in let value = loadAcquire(predicate) @@ -269,12 +293,12 @@ public func swift_once(predicate: UnsafeMutablePointer, fn: (@convention(c) // Misc -@_silgen_name("swift_deletedMethodError") +@_cdecl("swift_deletedMethodError") public func swift_deletedMethodError() -> Never { Builtin.int_trap() } -@_silgen_name("swift_willThrow") +@_silgen_name("swift_willThrow") // This is actually expected to be swiftcc (@_silgen_name and not @_cdecl). public func swift_willThrow() throws { } diff --git a/test/embedded/lto-multiple-object-files.swift b/test/embedded/lto-multiple-object-files.swift new file mode 100644 index 00000000000..d1fba776f58 --- /dev/null +++ b/test/embedded/lto-multiple-object-files.swift @@ -0,0 +1,56 @@ +// Regression test for a runtime failure that used to happen under some very specific conditions: (1) LTO, (2) Swift +// compiler is used with -num-threads to emit multiple .o files even in WMO mode, (3) the first listed source file +// contains no code that would trigger the use of swift_initStaticObject runtime function (e.g. no array literals), (4) +// another source file does use swift_initStaticObject that doesn't get optimized away (e.g. an array literal in a +// never-inline function, but not an empty array). In that case, we used to have a mismatching calling convention on +// swift_initStaticObject that the LTO pipeline would conclude is invalid IR and replace it with an unconditional trap. + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s + +// RUN: %target-swift-frontend -Osize -lto=llvm-full %t/MyFile1.swift %t/MyFile2.swift -enable-experimental-feature Embedded -emit-bc -num-threads 2 -o %t/MyFile1.o -o %t/MyFile2.o +// RUN: %target-clang -Oz %t/MyFile1.o %t/MyFile2.o -o %t/a.out +// RUN: %target-run %t/a.out | %FileCheck %s + +// REQUIRES: swift_in_compiler +// REQUIRES: executable_test +// REQUIRES: OS=macosx + +// For LTO, the linker dlopen()'s the libLTO library, which is a scenario that +// ASan cannot work in ("Interceptors are not working, AddressSanitizer is +// loaded too late"). +// REQUIRES: no_asan + +// BEGIN MyFile1.swift + +public func foo() { + print("foo") +} + +// BEGIN MyFile2.swift + +public func bar() { + print("bar") +} + +@inline(never) +public func baz(array: [Int]) -> ([Int], [Int]) { + let x = [1, 2, 3] + let y = [3, 4, 5] + return (x, y) +} + +@main +struct Main { + static func main() { + foo() + let (x, y) = baz(array: Array.init(repeating: 0, count: 8)) + let c = x.count + y.count + print(c) + bar() + } +} + +// CHECK: foo +// CHECK-NEXT: 6 +// CHECK-NEXT: bar