Skip to content

Commit ef3e804

Browse files
authored
Merge pull request swiftlang#79757 from kubamracek/cp/6.1/embedded-fatalerror-stringinterp
[6.1 cherry-pick] Allow string-interpolating fatalError, assert, assertionFailure, precondition, preconditionFailure in Embedded Swift
2 parents ff866d0 + 95e7843 commit ef3e804

11 files changed

+176
-9
lines changed

include/swift/AST/IRGenOptions.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ class IRGenOptions {
371371
/// Emit names of struct stored properties and enum cases.
372372
unsigned EnableReflectionNames : 1;
373373

374+
unsigned DisableLLVMMergeFunctions : 1;
375+
374376
/// Emit mangled names of anonymous context descriptors.
375377
unsigned EnableAnonymousContextMangledNames : 1;
376378

@@ -568,7 +570,8 @@ class IRGenOptions {
568570
SwiftAsyncFramePointer(SwiftAsyncFramePointerKind::Auto),
569571
HasValueNamesSetting(false), ValueNames(false),
570572
ReflectionMetadata(ReflectionMetadataMode::Runtime),
571-
EnableReflectionNames(true), EnableAnonymousContextMangledNames(false),
573+
EnableReflectionNames(true), DisableLLVMMergeFunctions(false),
574+
EnableAnonymousContextMangledNames(false),
572575
ForcePublicLinkage(false), LazyInitializeClassMetadata(false),
573576
LazyInitializeProtocolConformances(false),
574577
IndirectAsyncFunctionPointer(false),

include/swift/Option/FrontendOptions.td

+3
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,9 @@ def disable_reflection_names : Flag<["-"], "disable-reflection-names">,
617617
HelpText<"Disable emission of names of stored properties and enum cases in"
618618
"reflection metadata">;
619619

620+
def disable_llvm_merge_functions_pass : Flag<["-"], "disable-llvm-merge-functions-pass">,
621+
HelpText<"Disable the MergeFunctionPass LLVM IR pass">;
622+
620623
def function_sections: Flag<["-"], "function-sections">,
621624
Flags<[FrontendOption, NoInteractiveOption]>,
622625
HelpText<"Emit functions to separate sections.">;

lib/Frontend/CompilerInvocation.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -3344,6 +3344,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
33443344
Opts.EnableReflectionNames = false;
33453345
}
33463346

3347+
if (Args.hasArg(OPT_disable_llvm_merge_functions_pass)) {
3348+
Opts.DisableLLVMMergeFunctions = true;
3349+
}
3350+
33473351
if (Args.hasArg(OPT_force_public_linkage)) {
33483352
Opts.ForcePublicLinkage = true;
33493353
}

lib/IRGen/IRGen.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ void swift::performLLVMOptimizations(const IRGenOptions &Opts,
260260
PTO.LoopInterleaving = true;
261261
PTO.LoopVectorization = true;
262262
PTO.SLPVectorization = true;
263-
PTO.MergeFunctions = true;
263+
PTO.MergeFunctions = !Opts.DisableLLVMMergeFunctions;
264264
// Splitting trades code size to enhance memory locality, avoid in -Osize.
265265
DoHotColdSplit = Opts.EnableHotColdSplit && !Opts.optimizeForSize();
266266
level = llvm::OptimizationLevel::Os;
@@ -361,7 +361,8 @@ void swift::performLLVMOptimizations(const IRGenOptions &Opts,
361361
allowlistFiles, ignorelistFiles));
362362
});
363363
}
364-
if (RunSwiftSpecificLLVMOptzns) {
364+
365+
if (RunSwiftSpecificLLVMOptzns && !Opts.DisableLLVMMergeFunctions) {
365366
PB.registerOptimizerLastEPCallback(
366367
[&](ModulePassManager &MPM, OptimizationLevel Level) {
367368
if (Level != OptimizationLevel::O0) {

stdlib/public/core/Assert.swift

+11-5
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
/// fails. The default is the line number where `assert(_:_:file:line:)`
3939
/// is called.
4040
@_transparent
41-
@_unavailableInEmbedded
4241
#if $Embedded
4342
@_disfavoredOverload
4443
#endif
@@ -101,7 +100,6 @@ public func assert(
101100
/// fails. The default is the line number where
102101
/// `precondition(_:_:file:line:)` is called.
103102
@_transparent
104-
@_unavailableInEmbedded
105103
#if $Embedded
106104
@_disfavoredOverload
107105
#endif
@@ -167,7 +165,6 @@ public func precondition(
167165
/// line number where `assertionFailure(_:file:line:)` is called.
168166
@inlinable
169167
@inline(__always)
170-
@_unavailableInEmbedded
171168
#if $Embedded
172169
@_disfavoredOverload
173170
#endif
@@ -229,7 +226,6 @@ public func assertionFailure(
229226
/// - line: The line number to print along with `message`. The default is the
230227
/// line number where `preconditionFailure(_:file:line:)` is called.
231228
@_transparent
232-
@_unavailableInEmbedded
233229
#if $Embedded
234230
@_disfavoredOverload
235231
#endif
@@ -275,16 +271,26 @@ public func preconditionFailure(
275271
/// - line: The line number to print along with `message`. The default is the
276272
/// line number where `fatalError(_:file:line:)` is called.
277273
@_transparent
278-
@_unavailableInEmbedded
279274
#if $Embedded
280275
@_disfavoredOverload
281276
#endif
282277
public func fatalError(
283278
_ message: @autoclosure () -> String = String(),
284279
file: StaticString = #file, line: UInt = #line
285280
) -> Never {
281+
#if !$Embedded
286282
_assertionFailure("Fatal error", message(), file: file, line: line,
287283
flags: _fatalErrorFlags())
284+
#else
285+
if _isDebugAssertConfiguration() {
286+
_assertionFailure("Fatal error", message(), file: file, line: line,
287+
flags: _fatalErrorFlags())
288+
} else {
289+
Builtin.condfail_message(true._value,
290+
StaticString("fatal error").unsafeRawPointer)
291+
Builtin.unreachable()
292+
}
293+
#endif
288294
}
289295

290296
#if $Embedded

stdlib/public/core/AssertCommon.swift

+10-1
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,16 @@ internal func _assertionFailure(
134134
#if !$Embedded
135135
@inline(never)
136136
#else
137+
@_disfavoredOverload
137138
@inline(__always)
138139
#endif
139140
@_semantics("programtermination_point")
140-
@_unavailableInEmbedded
141141
internal func _assertionFailure(
142142
_ prefix: StaticString, _ message: String,
143143
file: StaticString, line: UInt,
144144
flags: UInt32
145145
) -> Never {
146+
#if !$Embedded
146147
prefix.withUTF8Buffer {
147148
(prefix) -> Void in
148149
var message = message
@@ -158,6 +159,14 @@ internal func _assertionFailure(
158159
}
159160
}
160161
}
162+
#else
163+
if _isDebugAssertConfiguration() {
164+
var message = message
165+
message.withUTF8 { (messageUTF8) -> Void in
166+
_embeddedReportFatalErrorInFile(prefix: prefix, message: messageUTF8, file: file, line: line)
167+
}
168+
}
169+
#endif
161170

162171
Builtin.int_trap()
163172
}

stdlib/public/core/EmbeddedPrint.swift

+11
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ public func print(_ object: some CustomStringConvertible, terminator: StaticStri
6363
}
6464
}
6565
66+
func print(_ buf: UnsafeBufferPointer<UInt8>, terminator: StaticString = "\n") {
67+
for c in buf {
68+
putchar(CInt(c))
69+
}
70+
var p = terminator.utf8Start
71+
while p.pointee != 0 {
72+
putchar(CInt(p.pointee))
73+
p += 1
74+
}
75+
}
76+
6677
func printCharacters(_ buf: UnsafeRawBufferPointer) {
6778
for c in buf {
6879
putchar(CInt(c))

stdlib/public/core/EmbeddedRuntime.swift

+12
Original file line numberDiff line numberDiff line change
@@ -515,17 +515,29 @@ public func swift_clearSensitive(buf: UnsafeMutableRawPointer, nbytes: Int) {
515515
}
516516

517517
@usableFromInline
518+
@inline(never)
518519
func _embeddedReportFatalError(prefix: StaticString, message: StaticString) {
519520
print(prefix, terminator: "")
520521
if message.utf8CodeUnitCount > 0 { print(": ", terminator: "") }
521522
print(message)
522523
}
523524

524525
@usableFromInline
526+
@inline(never)
525527
func _embeddedReportFatalErrorInFile(prefix: StaticString, message: StaticString, file: StaticString, line: UInt) {
526528
print(file, terminator: ":")
527529
print(line, terminator: ": ")
528530
print(prefix, terminator: "")
529531
if message.utf8CodeUnitCount > 0 { print(": ", terminator: "") }
530532
print(message)
531533
}
534+
535+
@usableFromInline
536+
@inline(never)
537+
func _embeddedReportFatalErrorInFile(prefix: StaticString, message: UnsafeBufferPointer<UInt8>, file: StaticString, line: UInt) {
538+
print(file, terminator: ":")
539+
print(line, terminator: ": ")
540+
print(prefix, terminator: "")
541+
if message.count > 0 { print(": ", terminator: "") }
542+
print(message)
543+
}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-clang -x c -c %S/Inputs/unbuffered-putchar.c -o %t/unbuffered-putchar.o
3+
4+
// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out
5+
// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s --check-prefix=CHECK-MESSAGE
6+
7+
// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out -O
8+
// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s --check-prefix=CHECK-NOMESSAGE
9+
10+
// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out -Osize
11+
// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s --check-prefix=CHECK-NOMESSAGE
12+
13+
// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out -O -assert-config Debug
14+
// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s --check-prefix=CHECK-MESSAGE
15+
16+
// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out -Osize -assert-config Debug
17+
// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s --check-prefix=CHECK-MESSAGE
18+
19+
// REQUIRES: swift_in_compiler
20+
// REQUIRES: executable_test
21+
// REQUIRES: optimized_stdlib
22+
// REQUIRES: OS=macosx || OS=linux-gnu
23+
// REQUIRES: swift_test_mode_optimize_none
24+
// REQUIRES: swift_feature_Embedded
25+
26+
func testWithInterpolation(i: Int) {
27+
fatalError("task failed successfully \(i)")
28+
// CHECK-MESSAGE: {{.*}}/traps-fatalerror-exec2.swift:[[@LINE-1]]: Fatal error: task failed successfully 42
29+
// CHECK-NOMESSAGE-NOT: Fatal error
30+
// CHECK-NOMESSAGE-NOT: task failed successfully 42
31+
}
32+
33+
testWithInterpolation(i: 42)

test/embedded/traps-fatalerror-ir.swift

+20
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,23 @@ public func test() {
2828
// CHECK-NOMESSAGE-NEXT: tail call void @llvm.trap()
2929
// CHECK-NOMESSAGE-NEXT: unreachable
3030
// CHECK-NOMESSAGE-NEXT: }
31+
32+
public func testWithInterpolation(i: Int) {
33+
fatalError("task failed successfully \(i)")
34+
}
35+
36+
// CHECK-MESSAGE: define {{.*}}void @"$s4main21testWithInterpolation1iySi_tF"(i64 %0){{.*}} {
37+
// CHECK-MESSAGE: entry:
38+
// CHECK-MESSAGE: task failed successfully
39+
// CHECK-MESSAGE: {{.*}}call {{.*}}void @"${{(ss17_assertionFailure__|ss31_embeddedReportFatalErrorInFile6prefix7message4file4lineys12StaticStringV_SRys5UInt8VGAGSutF)}}
40+
// CHECK-MESSAGE-SAME: Fatal error
41+
// CHECK-MESSAGE-SAME: traps-fatalerror-ir.swift
42+
// CHECK-MESSAGE: unreachable
43+
// CHECK-MESSAGE: }
44+
45+
// CHECK-NOMESSAGE: define {{.*}}void @"$s4main21testWithInterpolation1iySi_tF"(i64 %0){{.*}} {
46+
// CHECK-NOMESSAGE-NEXT: entry:
47+
// CHECK-NOMESSAGE-NEXT: tail call void asm sideeffect "", "n"(i32 0)
48+
// CHECK-NOMESSAGE-NEXT: tail call void @llvm.trap()
49+
// CHECK-NOMESSAGE-NEXT: unreachable
50+
// CHECK-NOMESSAGE-NEXT: }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -enable-experimental-feature Embedded -emit-ir -Osize -disable-llvm-merge-functions-pass | %FileCheck %s
3+
4+
// REQUIRES: swift_in_compiler
5+
// REQUIRES: optimized_stdlib
6+
// REQUIRES: OS=macosx || OS=linux-gnu
7+
// REQUIRES: swift_feature_Embedded
8+
9+
public func test1(i: Int) {
10+
fatalError("\(i) is not 42")
11+
}
12+
13+
public func test2(i: Int) {
14+
assert(i == 42, "\(i) is not 42")
15+
}
16+
17+
public func test3(i: Int) {
18+
precondition(i == 42, "\(i) is not 42")
19+
}
20+
21+
public func test4(i: Int) {
22+
assertionFailure("\(i) is not 42")
23+
}
24+
25+
public func test5(i: Int) {
26+
preconditionFailure("\(i) is not 42")
27+
}
28+
29+
// CHECK: define {{.*}}@"$s4main5test11iySi_tF"
30+
// CHECK-NEXT: entry:
31+
// CHECK-NEXT: tail call void asm sideeffect ""
32+
// CHECK-NEXT: tail call void @llvm.trap()
33+
// CHECK-NEXT: unreachable
34+
// CHECK-NEXT: }
35+
36+
// CHECK: define {{.*}}@"$s4main5test21iySi_tF"
37+
// CHECK-NEXT: entry:
38+
// CHECK-NEXT: ret void
39+
// CHECK-NEXT: }
40+
41+
// CHECK: define {{.*}}@"$s4main5test31iySi_tF"
42+
// CHECK-NEXT: entry:
43+
// CHECK-NEXT: %.not = icmp eq i64 %0, 42
44+
// CHECK-NEXT: br i1 %.not, label %1, label %2
45+
// CHECK-EMPTY:
46+
// CHECK-NEXT: 1:
47+
// CHECK-NEXT: ret void
48+
// CHECK-EMPTY:
49+
// CHECK-NEXT: 2:
50+
// CHECK-NEXT: tail call void asm sideeffect ""
51+
// CHECK-NEXT: tail call void @llvm.trap()
52+
// CHECK-NEXT: unreachable
53+
// CHECK-NEXT: }
54+
55+
// CHECK: define {{.*}}@"$s4main5test41iySi_tF"
56+
// CHECK-NEXT: entry:
57+
// CHECK-NEXT: ret void
58+
// CHECK-NEXT: }
59+
60+
// CHECK: define {{.*}}@"$s4main5test51iySi_tF"
61+
// CHECK-NEXT: entry:
62+
// CHECK-NEXT: tail call void asm sideeffect ""
63+
// CHECK-NEXT: tail call void @llvm.trap()
64+
// CHECK-NEXT: unreachable
65+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)