Skip to content

Commit 44bea05

Browse files
authored
Merge pull request #76029 from kubamracek/embedded-traps-unique
[embedded] Make assert helper functions always inlined to avoid trap basic blocks from merging
2 parents d311533 + 2fa625e commit 44bea05

File tree

4 files changed

+92
-19
lines changed

4 files changed

+92
-19
lines changed

stdlib/public/core/AssertCommon.swift

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,15 @@ internal func _fatalErrorFlags() -> UInt32 {
8484
/// This function should be used only in the implementation of user-level
8585
/// assertions.
8686
///
87-
/// This function should not be inlined because it is cold and inlining just
88-
/// bloats code.
87+
/// This function should not be inlined in desktop Swift because it is cold and
88+
/// inlining just bloats code. In Embedded Swift, we force inlining as this
89+
/// function is typically just a trap (in release configurations).
8990
@usableFromInline
91+
#if !$Embedded
9092
@inline(never)
93+
#else
94+
@inline(__always)
95+
#endif
9196
@_semantics("programtermination_point")
9297
internal func _assertionFailure(
9398
_ prefix: StaticString, _ message: StaticString,
@@ -122,10 +127,15 @@ internal func _assertionFailure(
122127
/// This function should be used only in the implementation of user-level
123128
/// assertions.
124129
///
125-
/// This function should not be inlined because it is cold and inlining just
126-
/// bloats code.
130+
/// This function should not be inlined in desktop Swift because it is cold and
131+
/// inlining just bloats code. In Embedded Swift, we force inlining as this
132+
/// function is typically just a trap (in release configurations).
127133
@usableFromInline
134+
#if !$Embedded
128135
@inline(never)
136+
#else
137+
@inline(__always)
138+
#endif
129139
@_semantics("programtermination_point")
130140
@_unavailableInEmbedded
131141
internal func _assertionFailure(
@@ -155,10 +165,15 @@ internal func _assertionFailure(
155165
/// This function should be used only in the implementation of user-level
156166
/// assertions.
157167
///
158-
/// This function should not be inlined because it is cold and inlining just
159-
/// bloats code.
168+
/// This function should not be inlined in desktop Swift because it is cold and
169+
/// inlining just bloats code. In Embedded Swift, we force inlining as this
170+
/// function is typically just a trap (in release configurations).
160171
@usableFromInline
172+
#if !$Embedded
161173
@inline(never)
174+
#else
175+
@inline(__always)
176+
#endif
162177
@_semantics("programtermination_point")
163178
@_unavailableInEmbedded
164179
internal func _assertionFailure(
@@ -199,10 +214,15 @@ internal func _assertionFailure(
199214
/// This function should be used only in the implementation of stdlib
200215
/// assertions.
201216
///
202-
/// This function should not be inlined because it is cold and it inlining just
203-
/// bloats code.
217+
/// This function should not be inlined in desktop Swift because it is cold and
218+
/// inlining just bloats code. In Embedded Swift, we force inlining as this
219+
/// function is typically just a trap (in release configurations).
204220
@usableFromInline
221+
#if !$Embedded
205222
@inline(never)
223+
#else
224+
@inline(__always)
225+
#endif
206226
@_semantics("programtermination_point")
207227
internal func _fatalErrorMessage(
208228
_ prefix: StaticString, _ message: StaticString,
@@ -288,10 +308,17 @@ func _undefined<T>(
288308
/// Called when falling off the end of a switch and the type can be represented
289309
/// as a raw value.
290310
///
291-
/// This function should not be inlined because it is cold and inlining just
292-
/// bloats code. It doesn't take a source location because it's most important
311+
/// This function should not be inlined in desktop Swift because it is cold and
312+
/// inlining just bloats code. In Embedded Swift, we force inlining as this
313+
/// function is typically just a trap (in release configurations).
314+
///
315+
/// It doesn't take a source location because it's most important
293316
/// in release builds anyway (old apps that are run on new OSs).
317+
#if !$Embedded
294318
@inline(never)
319+
#else
320+
@inline(__always)
321+
#endif
295322
@usableFromInline // COMPILER_INTRINSIC
296323
internal func _diagnoseUnexpectedEnumCaseValue<SwitchedValue, RawValue>(
297324
type: SwitchedValue.Type,
@@ -309,10 +336,17 @@ internal func _diagnoseUnexpectedEnumCaseValue<SwitchedValue, RawValue>(
309336
/// Called when falling off the end of a switch and the value is not safe to
310337
/// print.
311338
///
312-
/// This function should not be inlined because it is cold and inlining just
313-
/// bloats code. It doesn't take a source location because it's most important
339+
/// This function should not be inlined in desktop Swift because it is cold and
340+
/// inlining just bloats code. In Embedded Swift, we force inlining as this
341+
/// function is typically just a trap (in release configurations).
342+
///
343+
/// It doesn't take a source location because it's most important
314344
/// in release builds anyway (old apps that are run on new OSs).
345+
#if !$Embedded
315346
@inline(never)
347+
#else
348+
@inline(__always)
349+
#endif
316350
@usableFromInline // COMPILER_INTRINSIC
317351
internal func _diagnoseUnexpectedEnumCase<SwitchedValue>(
318352
type: SwitchedValue.Type
@@ -331,10 +365,15 @@ internal func _diagnoseUnexpectedEnumCase<SwitchedValue>(
331365
/// and the module containing the unavailable function was compiled with
332366
/// `-unavailable-decl-optimization=stub`.
333367
///
334-
/// This function should not be inlined because it is cold and inlining just
335-
/// bloats code.
368+
/// This function should not be inlined in desktop Swift because it is cold and
369+
/// inlining just bloats code. In Embedded Swift, we force inlining as this
370+
/// function is typically just a trap (in release configurations).
336371
@backDeployed(before: SwiftStdlib 5.9)
372+
#if !$Embedded
337373
@inline(never)
374+
#else
375+
@inline(__always)
376+
#endif
338377
@_semantics("unavailable_code_reached")
339378
@usableFromInline // COMPILER_INTRINSIC
340379
internal func _diagnoseUnavailableCodeReached() -> Never {

test/embedded/traps-fatalerror-ir.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public func test() {
1414

1515
// CHECK-MESSAGE: define {{.*}}void @"$s4main4testyyF"(){{.*}} {
1616
// CHECK-MESSAGE: entry:
17-
// CHECK-MESSAGE: {{.*}}call {{.*}}void @"$ss17_assertionFailure__
17+
// CHECK-MESSAGE: {{.*}}call {{.*}}void @"${{(ss17_assertionFailure__|ss31_embeddedReportFatalErrorInFile)}}
1818
// CHECK-MESSAGE-SAME: Fatal error
1919
// CHECK-MESSAGE-SAME: task failed successfully
2020
// CHECK-MESSAGE-SAME: traps-fatalerror-ir.swift

test/embedded/traps-multiple-preconditions-ir.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ public func test(i: Int) {
2222

2323
// "Non-production builds" - We expect 4 separate _assertionFailure() calls with different values
2424
// CHECK-MESSAGE: define {{.*}}void @"$s4main4test1iySi_tF"(i64 %0) {{.*}}{
25-
// CHECK-MESSAGE: call {{.*}}@"$ss17_assertionFailure
25+
// CHECK-MESSAGE: call {{.*}}@"${{(ss17_assertionFailure__|ss31_embeddedReportFatalErrorInFile)}}
2626
// CHECK-MESSAGE: unreachable
27-
// CHECK-MESSAGE: call {{.*}}@"$ss17_assertionFailure
27+
// CHECK-MESSAGE: call {{.*}}@"${{(ss17_assertionFailure__|ss31_embeddedReportFatalErrorInFile)}}
2828
// CHECK-MESSAGE: unreachable
29-
// CHECK-MESSAGE: call {{.*}}@"$ss17_assertionFailure
29+
// CHECK-MESSAGE: call {{.*}}@"${{(ss17_assertionFailure__|ss31_embeddedReportFatalErrorInFile)}}
3030
// CHECK-MESSAGE: unreachable
31-
// CHECK-MESSAGE: call {{.*}}@"$ss17_assertionFailure
31+
// CHECK-MESSAGE: call {{.*}}@"${{(ss17_assertionFailure__|ss31_embeddedReportFatalErrorInFile)}}
3232
// CHECK-MESSAGE: unreachable
3333
// CHECK-MESSAGE: }
3434

test/embedded/traps-unique.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -Osize -enable-experimental-feature Embedded -emit-ir -Xllvm -link-embedded-runtime=0 -disable-access-control | %FileCheck %s
3+
4+
// REQUIRES: swift_in_compiler
5+
// REQUIRES: executable_test
6+
// REQUIRES: optimized_stdlib
7+
// REQUIRES: OS=macosx || OS=linux-gnu
8+
9+
public func foobar(i: Int) {
10+
if i == 1 { _assertionFailure("prefix", "message 1", file: "", line: 0, flags: 0) }
11+
if i == 2 { _assertionFailure("prefix", "message 2", file: "", line: 0, flags: 0) }
12+
}
13+
14+
// CHECK: define {{.*}}@"$s4main6foobar1iySi_tF"{{.*}} {
15+
// CHECK: entry:
16+
// CHECK: switch i64 %0, label %3 [
17+
// CHECK: i64 1, label %1
18+
// CHECK: i64 2, label %2
19+
// CHECK: ]
20+
// CHECK: 1:
21+
// CHECK: tail call void asm sideeffect ""
22+
// CHECK: tail call void @llvm.trap()
23+
// CHECK: unreachable
24+
// CHECK: 2:
25+
// CHECK: tail call void asm sideeffect ""
26+
// CHECK: tail call void @llvm.trap()
27+
// CHECK: unreachable
28+
// CHECK: 3:
29+
// CHECK: ret void
30+
// CHECK: }
31+
32+
// We should not see a call to _asssertionFailure in IR because that means such basic block can be merged with another
33+
// and break the expectations that each trap point is unique.
34+
// CHECK-NOT: @"$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF"

0 commit comments

Comments
 (0)