mirror of
https://github.com/apple/swift.git
synced 2026-03-04 18:24:35 +01:00
Optimizes String operations with constant operands.
Specifically:
* Replaces x.append(y) with x = y if x is empty.
* Removes x.append("")
* Replaces x.append(y) with x = x + y if x and y are constant strings.
* Replaces _typeName(T.self) with a constant string if T is statically known.
With this optimization it's possible to constant fold string interpolations, like "the \(Int.self) type" -> "the Int type"
This new pass runs on high-level SIL, where semantic calls are still in place.
rdar://problem/65642843
179 lines
8.8 KiB
Plaintext
179 lines
8.8 KiB
Plaintext
// RUN: %target-sil-opt %s -string-optimization -sil-combine | %FileCheck %s
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
import SwiftShims
|
|
|
|
sil [readonly] [_semantics "string.makeUTF8"] @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
|
|
sil [readonly] [_semantics "string.init_empty"] @empty_string : $@convention(method) (@thin String.Type) -> @owned String
|
|
sil [_semantics "string.init_empty"] @empty_string_with_capacity : $@convention(method) (Int, @thin String.Type) -> @owned String
|
|
sil [_semantics "string.append"] @string_append : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
|
|
// CHECK-LABEL: sil @append_to_empty_string
|
|
// CHECK: [[S:%[0-9]+]] = alloc_stack $String
|
|
// CHECK: [[F:%[0-9]+]] = function_ref @empty_string
|
|
// CHECK: [[A:%[0-9]+]] = apply [[F]]
|
|
// CHECK-NEXT: store [[A]] to [[S]]
|
|
// CHECK-NEXT: retain_value %0
|
|
// CHECK-NEXT: destroy_addr [[S]]
|
|
// CHECK-NEXT: store %0 to [[S]]
|
|
// CHECK-NEXT: [[L:%[0-9]+]] = load [[S]]
|
|
// CHECK: return [[L]]
|
|
// CHECK: } // end sil function 'append_to_empty_string'
|
|
sil @append_to_empty_string : $@convention(thin) (@guaranteed String) -> @owned String {
|
|
bb0(%0 : $String):
|
|
%2 = alloc_stack $String
|
|
%5 = metatype $@thin String.Type
|
|
%6 = function_ref @empty_string : $@convention(method) (@thin String.Type) -> @owned String
|
|
%7 = apply %6(%5) : $@convention(method) (@thin String.Type) -> @owned String
|
|
store %7 to %2 : $*String
|
|
%14 = function_ref @string_append : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
%15 = apply %14(%0, %2) : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
%28 = load %2 : $*String
|
|
dealloc_stack %2 : $*String
|
|
return %28 : $String
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @ossa_append_to_empty_string
|
|
// CHECK: [[S:%[0-9]+]] = alloc_stack $String
|
|
// CHECK: [[F:%[0-9]+]] = function_ref @empty_string
|
|
// CHECK: [[A:%[0-9]+]] = apply [[F]]
|
|
// CHECK-NEXT: store [[A]] to [init] [[S]]
|
|
// CHECK-NEXT: [[COPY:%[0-9]+]] = copy_value %0
|
|
// CHECK-NEXT: store [[COPY]] to [assign] [[S]]
|
|
// CHECK-NEXT: [[L:%[0-9]+]] = load [take] [[S]]
|
|
// CHECK: return [[L]]
|
|
// CHECK: } // end sil function 'ossa_append_to_empty_string'
|
|
sil [ossa] @ossa_append_to_empty_string : $@convention(thin) (@guaranteed String) -> @owned String {
|
|
bb0(%0 : @guaranteed $String):
|
|
%2 = alloc_stack $String
|
|
%5 = metatype $@thin String.Type
|
|
%6 = function_ref @empty_string : $@convention(method) (@thin String.Type) -> @owned String
|
|
%7 = apply %6(%5) : $@convention(method) (@thin String.Type) -> @owned String
|
|
store %7 to [init] %2 : $*String
|
|
%14 = function_ref @string_append : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
%15 = apply %14(%0, %2) : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
%28 = load [take] %2 : $*String
|
|
dealloc_stack %2 : $*String
|
|
return %28 : $String
|
|
}
|
|
|
|
// CHECK-LABEL: sil @append_empty_string
|
|
// CHECK: [[S:%[0-9]+]] = alloc_stack $String
|
|
// CHECK-NEXT: store %0 to [[S]]
|
|
// CHECK-NEXT: [[L:%[0-9]+]] = load [[S]]
|
|
// CHECK: return [[L]]
|
|
// CHECK: } // end sil function 'append_empty_string'
|
|
sil @append_empty_string : $@convention(thin) (@owned String) -> @owned String {
|
|
bb0(%0 : $String):
|
|
%2 = alloc_stack $String
|
|
store %0 to %2 : $*String
|
|
%5 = metatype $@thin String.Type
|
|
%6 = function_ref @empty_string : $@convention(method) (@thin String.Type) -> @owned String
|
|
%7 = apply %6(%5) : $@convention(method) (@thin String.Type) -> @owned String
|
|
%14 = function_ref @string_append : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
%15 = apply %14(%7, %2) : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
release_value %7 : $String
|
|
%28 = load %2 : $*String
|
|
dealloc_stack %2 : $*String
|
|
return %28 : $String
|
|
}
|
|
|
|
// CHECK-LABEL: sil @concat_constant_strings
|
|
// CHECK: [[S:%[0-9]+]] = alloc_stack $String
|
|
// CHECK: [[STR:%[0-9]+]] = string_literal utf8 "a🙂"
|
|
// CHECK: [[LENGTH:%[0-9]+]] = integer_literal $Builtin.Word, 5
|
|
// CHECK: [[ASCII:%[0-9]+]] = integer_literal $Builtin.Int1, 0
|
|
// CHECK: [[MT:%[0-9]+]] = metatype $@thin String.Type
|
|
// CHECK: [[F:%[0-9]+]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
|
|
// CHECK: [[A:%[0-9]+]] = apply [[F]]([[STR]], [[LENGTH]], [[ASCII]], [[MT]])
|
|
// CHECK-NEXT: destroy_addr [[S]]
|
|
// CHECK-NEXT: store [[A]] to [[S]]
|
|
// CHECK-NEXT: [[L:%[0-9]+]] = load [[S]]
|
|
// CHECK: return [[L]]
|
|
// CHECK: } // end sil function 'concat_constant_strings'
|
|
sil @concat_constant_strings : $@convention(thin) (@guaranteed String) -> @owned String {
|
|
bb0(%0 : $String):
|
|
%2 = alloc_stack $String
|
|
%3 = string_literal utf8 "a"
|
|
%4 = integer_literal $Builtin.Word, 1
|
|
%5 = integer_literal $Builtin.Int1, -1
|
|
%6 = metatype $@thin String.Type
|
|
%7 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
|
|
%8 = apply %7(%3, %4, %5, %6) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
|
|
%9 = string_literal utf8 "🙂"
|
|
%10 = integer_literal $Builtin.Word, 4
|
|
%11 = apply %7(%9, %10, %5, %6) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
|
|
store %8 to %2 : $*String
|
|
%14 = function_ref @string_append : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
%15 = apply %14(%11, %2) : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
release_value %11 : $String
|
|
%28 = load %2 : $*String
|
|
dealloc_stack %2 : $*String
|
|
return %28 : $String
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_concat_non_const_strings
|
|
// CHECK: [[S:%[0-9]+]] = alloc_stack $String
|
|
// CHECK-DAG: [[APPEND:%[0-9]+]] = function_ref @string_append
|
|
// CHECK-DAG: store %0 to [[S]]
|
|
// CHECK: [[A_STR:%[0-9]+]] = apply {{.*}} : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
|
|
// CHECK: apply [[APPEND]]([[A_STR]], [[S]])
|
|
// CHECK: [[L:%[0-9]+]] = load [[S]]
|
|
// CHECK: return [[L]]
|
|
// CHECK: } // end sil function 'dont_concat_non_const_strings'
|
|
sil @dont_concat_non_const_strings : $@convention(thin) (@guaranteed String) -> @owned String {
|
|
bb0(%0 : $String):
|
|
%2 = alloc_stack $String
|
|
|
|
%5 = metatype $@thin String.Type
|
|
%6 = function_ref @empty_string : $@convention(method) (@thin String.Type) -> @owned String
|
|
%7 = apply %6(%5) : $@convention(method) (@thin String.Type) -> @owned String
|
|
store %7 to %2 : $*String
|
|
|
|
%10 = function_ref @string_append : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
%11 = apply %10(%0, %2) : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
|
|
%12 = string_literal utf8 "a"
|
|
%13 = integer_literal $Builtin.Word, 1
|
|
%14 = integer_literal $Builtin.Int1, -1
|
|
%15 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
|
|
%16 = apply %15(%12, %13, %14, %5) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
|
|
|
|
%17 = apply %10(%16, %2) : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
release_value %16 : $String
|
|
|
|
%28 = load %2 : $*String
|
|
dealloc_stack %2 : $*String
|
|
return %28 : $String
|
|
}
|
|
|
|
sil @unknown_modify : $@convention(thin) (@inout String) -> ()
|
|
|
|
// CHECK-LABEL: sil @dont_optimize_modified_string
|
|
// CHECK: [[INIT:%[0-9]+]] = function_ref @empty_string
|
|
// CHECK: apply [[INIT]]
|
|
// CHECK: [[UNKNOWN:%[0-9]+]] = function_ref @unknown_modify
|
|
// CHECK: apply [[UNKNOWN]]
|
|
// CHECK: [[APPEND:%[0-9]+]] = function_ref @string_append
|
|
// CHECK: apply [[APPEND]]
|
|
// CHECK: } // end sil function 'dont_optimize_modified_string'
|
|
sil @dont_optimize_modified_string : $@convention(thin) (@guaranteed String) -> @owned String {
|
|
bb0(%0 : $String):
|
|
%2 = alloc_stack $String
|
|
%5 = metatype $@thin String.Type
|
|
%6 = function_ref @empty_string : $@convention(method) (@thin String.Type) -> @owned String
|
|
%7 = apply %6(%5) : $@convention(method) (@thin String.Type) -> @owned String
|
|
store %7 to %2 : $*String
|
|
%8 = function_ref @unknown_modify : $@convention(thin) (@inout String) -> ()
|
|
%9 = apply %8(%2) : $@convention(thin) (@inout String) -> ()
|
|
%14 = function_ref @string_append : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
%15 = apply %14(%0, %2) : $@convention(method) (@guaranteed String, @inout String) -> ()
|
|
%28 = load %2 : $*String
|
|
dealloc_stack %2 : $*String
|
|
return %28 : $String
|
|
}
|
|
|