Skip to content

Commit 5c0ae94

Browse files
committed
Optimizer: add simplification for the value_to_bridge_object instruction
This comes up in the code for constructing an empty string literal. With this optimization it's possible to statically initialize empty string global variables.
1 parent 4720673 commit 5c0ae94

File tree

6 files changed

+111
-2
lines changed

6 files changed

+111
-2
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ swift_compiler_sources(Optimizer
2121
SimplifyStrongRetainRelease.swift
2222
SimplifyStructExtract.swift
2323
SimplifyTupleExtract.swift
24-
SimplifyUncheckedEnumData.swift)
24+
SimplifyUncheckedEnumData.swift
25+
SimplifyValueToBridgeObject.swift)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===--- SimplifyValueToBridgeObject.swift --------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SIL
14+
15+
extension ValueToBridgeObjectInst : OnoneSimplifyable {
16+
func simplify(_ context: SimplifyContext) {
17+
18+
// Optimize the sequence
19+
// ```
20+
// %1 = value_to_bridge_object %0
21+
// %2 = struct $SomeInt (%1)
22+
// %3 = unchecked_trivial_bit_cast %2
23+
// %4 = struct_extract %3, #valueFieldInInt
24+
// %5 = value_to_bridge_object %4
25+
// ```
26+
// to
27+
// ```
28+
// %5 = value_to_bridge_object %0
29+
// ```
30+
// This sequence comes up in the code for constructing an empty string literal.
31+
//
32+
if let se = self.value as? StructExtractInst,
33+
let utbc = se.struct as? UncheckedTrivialBitCastInst,
34+
let vtbo = utbc.fromValue as? ValueToBridgeObjectInst {
35+
self.operand.set(to: vtbo.value, context)
36+
}
37+
}
38+
}

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ final public class UncheckedAddrCastInst : SingleValueInstruction, UnaryInstruct
388388
public var fromAddress: Value { operand.value }
389389
}
390390

391+
final public class UncheckedTrivialBitCastInst : SingleValueInstruction, UnaryInstruction {
392+
public var fromValue: Value { operand.value }
393+
}
394+
391395
final public
392396
class RawPointerToRefInst : SingleValueInstruction, UnaryInstruction {
393397
public var pointer: Value { operand.value }
@@ -626,7 +630,9 @@ final public
626630
class ObjCMetatypeToObjectInst : SingleValueInstruction, UnaryInstruction {}
627631

628632
final public
629-
class ValueToBridgeObjectInst : SingleValueInstruction, UnaryInstruction {}
633+
class ValueToBridgeObjectInst : SingleValueInstruction, UnaryInstruction {
634+
public var value: Value { return operand.value }
635+
}
630636

631637
final public
632638
class MarkDependenceInst : SingleValueInstruction {

SwiftCompilerSources/Sources/SIL/Registration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public func registerSILClasses() {
7777
register(UpcastInst.self)
7878
register(UncheckedRefCastInst.self)
7979
register(UncheckedAddrCastInst.self)
80+
register(UncheckedTrivialBitCastInst.self)
8081
register(MarkMustCheckInst.self)
8182
register(ObjectInst.self)
8283
register(RawPointerToRefInst.self)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=value_to_bridge_object | %FileCheck %s
2+
3+
// REQUIRES: swift_in_compiler
4+
5+
import Swift
6+
import Builtin
7+
8+
// CHECK-LABEL: sil @empty_string_literal_sequence
9+
// CHECK: %1 = value_to_bridge_object %0
10+
// CHECK: return %1
11+
// CHECK: } // end sil function 'empty_string_literal_sequence'
12+
sil @empty_string_literal_sequence : $@convention(thin) (Builtin.Int64) -> Builtin.BridgeObject {
13+
bb0(%0 : $Builtin.Int64):
14+
%1 = value_to_bridge_object %0 : $Builtin.Int64
15+
%2 = unchecked_trivial_bit_cast %1 : $Builtin.BridgeObject to $UInt64
16+
%3 = struct_extract %2 : $UInt64, #UInt64._value
17+
%4 = value_to_bridge_object %3 : $Builtin.Int64
18+
return %4 : $Builtin.BridgeObject
19+
}
20+
21+
// CHECK-LABEL: sil [ossa] @keep_both_vtbo_instructions
22+
// CHECK: %1 = value_to_bridge_object %0
23+
// CHECK: %2 = value_to_bridge_object %0
24+
// CHECK: %3 = tuple (%1 : $Builtin.BridgeObject, %2 : $Builtin.BridgeObject)
25+
// CHECK: return %3
26+
// CHECK: } // end sil function 'keep_both_vtbo_instructions'
27+
sil [ossa] @keep_both_vtbo_instructions : $@convention(thin) (Builtin.Int64) -> (Builtin.BridgeObject, Builtin.BridgeObject) {
28+
bb0(%0 : $Builtin.Int64):
29+
%1 = value_to_bridge_object %0 : $Builtin.Int64
30+
%2 = unchecked_trivial_bit_cast %1 : $Builtin.BridgeObject to $UInt64
31+
%3 = struct_extract %2 : $UInt64, #UInt64._value
32+
%4 = value_to_bridge_object %3 : $Builtin.Int64
33+
%5 = tuple (%1 : $Builtin.BridgeObject, %4 : $Builtin.BridgeObject)
34+
return %5 : $(Builtin.BridgeObject, Builtin.BridgeObject)
35+
}
36+

test/SILOptimizer/static_strings.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ public struct S {
1919
public static let largestr = "abc123asd3sdj3basfasdf"
2020
// CHECK: {{^@"}}[[UNICODE:.*unicodestr.*pZ]]" ={{.*}} global {{.*}} inttoptr {{.*}} add
2121
public static let unicodestr = "❄️gastroperiodyni"
22+
// CHECK: {{^@"}}[[EMPTY:.*emptystr.*pZ]]" ={{.*}} global {{.*}} inttoptr
23+
public static let emptystr = ""
2224
}
2325

2426
// unsafeMutableAddressor for S.smallstr
@@ -57,6 +59,18 @@ public struct S {
5759
// CHECK-NEXT: ret {{.*}}
5860
// CHECK-NEXT: }
5961

62+
// unsafeMutableAddressor for S.emptystr
63+
// CHECK: define {{.*emptystr.*}}u"
64+
// CHECK-NEXT: entry:
65+
// CHECK-NEXT: ret {{.*}} @"[[EMPTY]]"
66+
// CHECK-NEXT: }
67+
68+
// getter for S.emptystr
69+
// CHECK: define {{.*emptystr.*}}gZ"
70+
// CHECK-NEXT: entry:
71+
// CHECK-NEXT: ret {{.*}}
72+
// CHECK-NEXT: }
73+
6074
// CHECK-LABEL: define {{.*}}get_smallstr
6175
// CHECK: entry:
6276
// CHECK-NEXT: ret {{.*}}
@@ -84,25 +98,38 @@ public func get_unicodestr() -> String {
8498
return S.unicodestr
8599
}
86100

101+
// CHECK-LABEL: define {{.*}}get_emptystr
102+
// CHECK: entry:
103+
// CHECK-NEXT: ret {{.*}}
104+
// CHECK-NEXT: }
105+
@inline(never)
106+
public func get_emptystr() -> String {
107+
return S.emptystr
108+
}
109+
87110
// Also check if the generated code is correct.
88111

89112
// CHECK-OUTPUT: abc123a
90113
// CHECK-OUTPUT: abc123asd3sdj3basfasdf
91114
// CHECK-OUTPUT: ❄️gastroperiodyni
115+
// CHECK-OUTPUT: <>
92116
print(get_smallstr())
93117
print(get_largestr())
94118
print(get_unicodestr())
119+
print("<\(get_emptystr())>")
95120

96121
// Really load the globals from their addresses.
97122
@_optimize(none)
98123
func print_strings_from_addressors() {
99124
print(S.smallstr)
100125
print(S.largestr)
101126
print(S.unicodestr)
127+
print("<\(S.emptystr)>")
102128
}
103129

104130
// CHECK-OUTPUT: abc123a
105131
// CHECK-OUTPUT: abc123asd3sdj3basfasdf
106132
// CHECK-OUTPUT: ❄️gastroperiodyni
133+
// CHECK-OUTPUT: <>
107134
print_strings_from_addressors()
108135

0 commit comments

Comments
 (0)