mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
SimplifyLoad: improve simplification of load of global variable
Inline the initialization code of a global initializer if the load is a global_addr with a builtin "once" dependency.
This commit is contained in:
@@ -98,7 +98,7 @@ extension LoadInst : OnoneSimplifyable, SILCombineSimplifyable {
|
||||
|
||||
/// The load of a global let variable is replaced by its static initializer value.
|
||||
private func replaceLoadOfGlobalLet(_ context: SimplifyContext) -> Bool {
|
||||
guard let globalInitVal = getGlobalInitValue(address: address) else {
|
||||
guard let globalInitVal = getGlobalInitValue(address: address, context) else {
|
||||
return false
|
||||
}
|
||||
if !globalInitVal.canBeCopied(into: parentFunction, context) {
|
||||
@@ -211,30 +211,51 @@ extension LoadInst : OnoneSimplifyable, SILCombineSimplifyable {
|
||||
}
|
||||
|
||||
/// Returns the init value of a global which is loaded from `address`.
|
||||
private func getGlobalInitValue(address: Value) -> Value? {
|
||||
private func getGlobalInitValue(address: Value, _ context: SimplifyContext) -> Value? {
|
||||
switch address {
|
||||
case let gai as GlobalAddrInst:
|
||||
if gai.global.isLet {
|
||||
return gai.global.staticInitValue
|
||||
if let staticInitValue = gai.global.staticInitValue {
|
||||
return staticInitValue
|
||||
}
|
||||
if let staticInitValue = getInitializerFromInitFunction(of: gai, context) {
|
||||
return staticInitValue
|
||||
}
|
||||
}
|
||||
case let pta as PointerToAddressInst:
|
||||
return globalLoadedViaAddressor(pointer: pta.pointer)?.staticInitValue
|
||||
case let sea as StructElementAddrInst:
|
||||
if let structVal = getGlobalInitValue(address: sea.struct) as? StructInst {
|
||||
if let structVal = getGlobalInitValue(address: sea.struct, context) as? StructInst {
|
||||
return structVal.operands[sea.fieldIndex].value
|
||||
}
|
||||
case let tea as TupleElementAddrInst:
|
||||
if let tupleVal = getGlobalInitValue(address: tea.tuple) as? TupleInst {
|
||||
if let tupleVal = getGlobalInitValue(address: tea.tuple, context) as? TupleInst {
|
||||
return tupleVal.operands[tea.fieldIndex].value
|
||||
}
|
||||
case let bai as BeginAccessInst:
|
||||
return getGlobalInitValue(address: bai.address)
|
||||
return getGlobalInitValue(address: bai.address, context)
|
||||
default:
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func getInitializerFromInitFunction(of globalAddr: GlobalAddrInst, _ context: SimplifyContext) -> Value? {
|
||||
guard let dependentOn = globalAddr.dependencyToken,
|
||||
let builtinOnce = dependentOn as? BuiltinInst,
|
||||
builtinOnce.id == .Once,
|
||||
let initFnRef = builtinOnce.operands[1].value as? FunctionRefInst else
|
||||
{
|
||||
return nil
|
||||
}
|
||||
let initFn = initFnRef.referencedFunction
|
||||
context.notifyDependency(onBodyOf: initFn)
|
||||
guard let (_, storeToGlobal) = getGlobalInitialization(of: initFn, allowGlobalValue: true) else {
|
||||
return nil
|
||||
}
|
||||
return storeToGlobal.source
|
||||
}
|
||||
|
||||
private func globalLoadedViaAddressor(pointer: Value) -> GlobalVariable? {
|
||||
if let ai = pointer as? ApplyInst,
|
||||
let callee = ai.referencedFunction,
|
||||
|
||||
@@ -23,6 +23,36 @@ sil_global [let] @gstr : $Str = {
|
||||
class B { }
|
||||
class E : B { }
|
||||
|
||||
sil_global hidden [let] @gb : $B
|
||||
sil_global hidden [let] @gb2 : $(B, Int64)
|
||||
|
||||
sil_global private @gb_obj : $B = {
|
||||
%initval = object $B ()
|
||||
}
|
||||
|
||||
sil [global_init_once_fn] @init_gb : $@convention(c) () -> () {
|
||||
bb0:
|
||||
alloc_global @gb
|
||||
%1 = global_addr @gb : $*B
|
||||
%2 = global_value @gb_obj : $B
|
||||
store %2 to %1 : $*B
|
||||
%6 = tuple ()
|
||||
return %6 : $()
|
||||
}
|
||||
|
||||
sil [global_init_once_fn] @init_gb2 : $@convention(c) () -> () {
|
||||
bb0:
|
||||
alloc_global @gb2
|
||||
%1 = global_addr @gb2 : $*(B, Int64)
|
||||
%2 = global_value @gb_obj : $B
|
||||
%3 = integer_literal $Builtin.Int64, 10
|
||||
%4 = struct $Int64 (%3 : $Builtin.Int64)
|
||||
%5 = tuple (%2 : $B, %4 : $Int64)
|
||||
store %5 to %1 : $*(B, Int64)
|
||||
%6 = tuple ()
|
||||
return %6 : $()
|
||||
}
|
||||
|
||||
sil [global_init] @gstr_addressor : $@convention(thin) () -> Builtin.RawPointer {
|
||||
bb0:
|
||||
%0 = global_addr @gstr : $*Str
|
||||
@@ -96,6 +126,64 @@ bb0:
|
||||
return %3 : $Int64
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil @load_global_object :
|
||||
// CHECK: %1 = global_value @gb_obj
|
||||
// CHECK-NEXT: return %1
|
||||
// CHECK: } // end sil function 'load_global_object'
|
||||
sil @load_global_object : $@convention(thin) (Builtin.RawPointer) -> @owned B {
|
||||
bb0(%0 : $Builtin.RawPointer):
|
||||
%1 = function_ref @init_gb : $@convention(c) () -> ()
|
||||
%2 = builtin "once"(%0 : $Builtin.RawPointer, %1 : $@convention(c) () -> ()) : $Builtin.SILToken
|
||||
%3 = global_addr @gb : $*B depends_on %2
|
||||
%4 = load %3 : $*B
|
||||
return %4 : $B
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil @load_global_object_keep_once :
|
||||
// CHECK: %2 = builtin "once"
|
||||
// CHECK: %3 = global_value @gb_obj
|
||||
// CHECK: fix_lifetime
|
||||
// CHECK: return %3
|
||||
// CHECK: } // end sil function 'load_global_object_keep_once'
|
||||
sil @load_global_object_keep_once : $@convention(thin) (Builtin.RawPointer) -> @owned B {
|
||||
bb0(%0 : $Builtin.RawPointer):
|
||||
%1 = function_ref @init_gb : $@convention(c) () -> ()
|
||||
%2 = builtin "once"(%0 : $Builtin.RawPointer, %1 : $@convention(c) () -> ()) : $Builtin.SILToken
|
||||
%3 = global_addr @gb : $*B depends_on %2
|
||||
%4 = load %3 : $*B
|
||||
%5 = global_addr @gb : $*B depends_on %2
|
||||
fix_lifetime %5 : $*B
|
||||
return %4 : $B
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil @load_global_object_from_tuple :
|
||||
// CHECK: %1 = global_value @gb_obj
|
||||
// CHECK-NEXT: return %1
|
||||
// CHECK: } // end sil function 'load_global_object_from_tuple'
|
||||
sil @load_global_object_from_tuple : $@convention(thin) (Builtin.RawPointer) -> @owned B {
|
||||
bb0(%0 : $Builtin.RawPointer):
|
||||
%1 = function_ref @init_gb2 : $@convention(c) () -> ()
|
||||
%2 = builtin "once"(%0 : $Builtin.RawPointer, %1 : $@convention(c) () -> ()) : $Builtin.SILToken
|
||||
%3 = global_addr @gb2 : $*(B, Int64) depends_on %2
|
||||
%4 = tuple_element_addr %3 : $*(B, Int64), 0
|
||||
%5 = load %4 : $*B
|
||||
return %5 : $B
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil @load_global_tuple :
|
||||
// CHECK: %1 = global_value @gb_obj
|
||||
// CHECK: [[T:%.*]] = tuple (%1 : $B, {{%.*}} : $Int64)
|
||||
// CHECK-NEXT: return [[T]]
|
||||
// CHECK: } // end sil function 'load_global_tuple'
|
||||
sil @load_global_tuple : $@convention(thin) (Builtin.RawPointer) -> @owned (B, Int64) {
|
||||
bb0(%0 : $Builtin.RawPointer):
|
||||
%1 = function_ref @init_gb2 : $@convention(c) () -> ()
|
||||
%2 = builtin "once"(%0 : $Builtin.RawPointer, %1 : $@convention(c) () -> ()) : $Builtin.SILToken
|
||||
%3 = global_addr @gb2 : $*(B, Int64) depends_on %2
|
||||
%4 = load %3 : $*(B, Int64)
|
||||
return %4 : $(B, Int64)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil @load_first_char_from_string_literal
|
||||
// CHECK: bb0:
|
||||
// CHECK-NEXT: %0 = integer_literal $Builtin.Int8, 97
|
||||
|
||||
Reference in New Issue
Block a user