Skip to content

Commit 88a4a97

Browse files
committed
Swift Optimizer: add simplification for load
Replace loads of global let variables with there static initializer values.
1 parent 6d6b94e commit 88a4a97

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ swift_compiler_sources(Optimizer
1616
SimplifyDebugStep.swift
1717
SimplifyDestructure.swift
1818
SimplifyGlobalValue.swift
19+
SimplifyLoad.swift
1920
SimplifyStrongRetainRelease.swift
2021
SimplifyStructExtract.swift
2122
SimplifyTupleExtract.swift
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===--- SimplifyLoad.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 LoadInst : OnoneSimplifyable {
16+
func simplify(_ context: SimplifyContext) {
17+
replaceLoadOfGlobalLet(context)
18+
}
19+
20+
private func replaceLoadOfGlobalLet(_ context: SimplifyContext) {
21+
guard let globalInitVal = getGlobalInitValue(address: address) else {
22+
return
23+
}
24+
let builder = Builder(before: self, context)
25+
guard let initVal = context.copyStaticInitializer(fromInitValue: globalInitVal, to: builder) else {
26+
return
27+
}
28+
uses.replaceAll(with: initVal, context)
29+
transitivelyErase(load: self, context)
30+
}
31+
}
32+
33+
/// Returns the init value of a global which is loaded from `address`.
34+
private func getGlobalInitValue(address: Value) -> Value? {
35+
switch address {
36+
case let gai as GlobalAddrInst:
37+
if gai.global.isLet {
38+
return gai.global.staticInitValue
39+
}
40+
case let pta as PointerToAddressInst:
41+
return globalLoadedViaAddressor(pointer: pta.pointer)?.staticInitValue
42+
case let sea as StructElementAddrInst:
43+
if let structVal = getGlobalInitValue(address: sea.struct) as? StructInst {
44+
return structVal.operands[sea.fieldIndex].value
45+
}
46+
case let tea as TupleElementAddrInst:
47+
if let tupleVal = getGlobalInitValue(address: tea.tuple) as? TupleInst {
48+
return tupleVal.operands[tea.fieldIndex].value
49+
}
50+
case let bai as BeginAccessInst:
51+
return getGlobalInitValue(address: bai.address)
52+
default:
53+
break
54+
}
55+
return nil
56+
}
57+
58+
private func globalLoadedViaAddressor(pointer: Value) -> GlobalVariable? {
59+
if let ai = pointer as? ApplyInst,
60+
let callee = ai.referencedFunction,
61+
let global = callee.globalOfGlobalInitFunction,
62+
global.isLet {
63+
return global
64+
}
65+
return nil
66+
}
67+
68+
private func transitivelyErase(load: LoadInst, _ context: SimplifyContext) {
69+
var inst: SingleValueInstruction = load
70+
while inst.uses.isEmpty {
71+
if inst.operands.count != 1 {
72+
context.erase(instruction: inst)
73+
return
74+
}
75+
let operandInst = inst.operands[0].value as! SingleValueInstruction
76+
context.erase(instruction: inst)
77+
inst = operandInst
78+
}
79+
}

test/SILOptimizer/simplify_load.sil

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=load | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ONONE
2+
3+
// REQUIRES: swift_in_compiler
4+
5+
import Swift
6+
import Builtin
7+
8+
struct Str {
9+
@_hasStorage let x: Int64
10+
@_hasStorage let y: (Int64, Int64)
11+
}
12+
13+
sil_global [let] @gstr : $Str = {
14+
%0 = integer_literal $Builtin.Int64, 10
15+
%1 = struct $Int64 (%0 : $Builtin.Int64)
16+
%2 = integer_literal $Builtin.Int64, 27
17+
%3 = struct $Int64 (%2 : $Builtin.Int64)
18+
%4 = tuple (%1 : $Int64, %3 : $Int64)
19+
%initval = struct $Str (%1 : $Int64, %4 : $(Int64, Int64))
20+
}
21+
22+
sil [global_init] @gstr_addressor : $@convention(thin) () -> Builtin.RawPointer {
23+
bb0:
24+
%0 = global_addr @gstr : $*Str
25+
%1 = address_to_pointer %0 : $*Str to $Builtin.RawPointer
26+
return %1 : $Builtin.RawPointer
27+
}
28+
29+
// CHECK-LABEL: sil @load_global_simple
30+
// CHECK-DAG: [[L27:%.*]] = integer_literal $Builtin.Int64, 27
31+
// CHECK-DAG: [[I27:%.*]] = struct $Int64 ([[L27]] : $Builtin.Int64)
32+
// CHECK-DAG: [[L10:%.*]] = integer_literal $Builtin.Int64, 10
33+
// CHECK-DAG: [[I10:%.*]] = struct $Int64 ([[L10]] : $Builtin.Int64)
34+
// CHECK-DAG: [[T:%.*]] = tuple ([[I10]] : $Int64, [[I27]] : $Int64)
35+
// CHECK: [[STR:%.*]] = struct $Str ([[I10]] : $Int64, [[T]] : $(Int64, Int64))
36+
// CHECK: return [[STR]]
37+
// CHECK: } // end sil function 'load_global_simple'
38+
sil @load_global_simple : $@convention(thin) () -> Str {
39+
bb0:
40+
%0 = global_addr @gstr : $*Str
41+
%1 = begin_access [read] [static] %0 : $*Str
42+
%2 = load %1 : $*Str
43+
end_access %1 : $*Str
44+
return %2 : $Str
45+
}
46+
47+
// CHECK-LABEL: sil @load_global_via_addressor
48+
// CHECK-NOT: apply
49+
// CHECK-DAG: [[L27:%.*]] = integer_literal $Builtin.Int64, 27
50+
// CHECK-DAG: [[I27:%.*]] = struct $Int64 ([[L27]] : $Builtin.Int64)
51+
// CHECK-DAG: [[L10:%.*]] = integer_literal $Builtin.Int64, 10
52+
// CHECK-DAG: [[I10:%.*]] = struct $Int64 ([[L10]] : $Builtin.Int64)
53+
// CHECK-DAG: [[T:%.*]] = tuple ([[I10]] : $Int64, [[I27]] : $Int64)
54+
// CHECK: [[STR:%.*]] = struct $Str ([[I10]] : $Int64, [[T]] : $(Int64, Int64))
55+
// CHECK: return [[STR]]
56+
// CHECK: } // end sil function 'load_global_via_addressor'
57+
sil @load_global_via_addressor : $@convention(thin) () -> Str {
58+
bb0:
59+
%0 = function_ref @gstr_addressor : $@convention(thin) () -> Builtin.RawPointer
60+
%1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer
61+
%2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Str
62+
%3 = load %2 : $*Str
63+
return %3 : $Str
64+
}
65+
66+
// CHECK-LABEL: sil @load_global_struct_element
67+
// CHECK-NOT: global_addr
68+
// CHECK-DAG: [[L10:%.*]] = integer_literal $Builtin.Int64, 10
69+
// CHECK-DAG: [[I10:%.*]] = struct $Int64 ([[L10]] : $Builtin.Int64)
70+
// CHECK: return [[I10]]
71+
// CHECK: } // end sil function 'load_global_struct_element'
72+
sil @load_global_struct_element : $@convention(thin) () -> Int64 {
73+
bb0:
74+
%0 = global_addr @gstr : $*Str
75+
%1 = struct_element_addr %0 : $*Str, #Str.x
76+
%2 = load %1 : $*Int64
77+
return %2 : $Int64
78+
}
79+
80+
// CHECK-LABEL: sil @load_global_struct_tuple
81+
// CHECK-NOT: global_addr
82+
// CHECK-DAG: [[L27:%.*]] = integer_literal $Builtin.Int64, 27
83+
// CHECK-DAG: [[I27:%.*]] = struct $Int64 ([[L27]] : $Builtin.Int64)
84+
// CHECK: return [[I27]]
85+
// CHECK: } // end sil function 'load_global_struct_tuple'
86+
sil @load_global_struct_tuple : $@convention(thin) () -> Int64 {
87+
bb0:
88+
%0 = global_addr @gstr : $*Str
89+
%1 = struct_element_addr %0 : $*Str, #Str.y
90+
%2 = tuple_element_addr %1 : $*(Int64, Int64), 1
91+
%3 = load %2 : $*Int64
92+
return %3 : $Int64
93+
}
94+

0 commit comments

Comments
 (0)