Skip to content

Commit 8677146

Browse files
committed
Swift Optimizer: move StoreInst.split into OpUtils.swift
To make it available in other optimizations as well. Also, a few problems: * Use destructre instructions when in OSSA * Don't split the store if it's nominal type has unreferenceable stoarge * rename it to `trySplit` because it's not guaranteed to work Also, add the counterpart for load instructions: `LoadInst.trySplit()`
1 parent ab2202c commit 8677146

File tree

2 files changed

+94
-22
lines changed

2 files changed

+94
-22
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/DeadStoreElimination.swift

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ private func tryEliminate(store: StoreInst, _ context: FunctionPassContext) {
8888
case .dead:
8989
// The new individual stores are inserted right after the current store and
9090
// will be optimized in the following loop iterations.
91-
store.split(context)
91+
store.trySplit(context)
9292
}
9393
}
9494
}
@@ -158,27 +158,6 @@ private extension StoreInst {
158158
}
159159
}
160160

161-
func split(_ context: FunctionPassContext) {
162-
let builder = Builder(after: self, context)
163-
let type = source.type
164-
if type.isStruct {
165-
for idx in 0..<type.getNominalFields(in: parentFunction).count {
166-
let srcField = builder.createStructExtract(struct: source, fieldIndex: idx)
167-
let destFieldAddr = builder.createStructElementAddr(structAddress: destination, fieldIndex: idx)
168-
builder.createStore(source: srcField, destination: destFieldAddr, ownership: storeOwnership)
169-
}
170-
} else if type.isTuple {
171-
for idx in 0..<type.tupleElements.count {
172-
let srcField = builder.createTupleExtract(tuple: source, elementIndex: idx)
173-
let destFieldAddr = builder.createTupleElementAddr(tupleAddress: destination, elementIndex: idx)
174-
builder.createStore(source: srcField, destination: destFieldAddr, ownership: storeOwnership)
175-
}
176-
} else {
177-
fatalError("a materializable projection path should only contain struct and tuple projections")
178-
}
179-
context.erase(instruction: self)
180-
}
181-
182161
var hasValidOwnershipForDeadStoreElimination: Bool {
183162
switch storeOwnership {
184163
case .unqualified, .trivial:

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,99 @@ extension Instruction {
146146
}
147147
}
148148

149+
extension StoreInst {
150+
func trySplit(_ context: FunctionPassContext) {
151+
let builder = Builder(after: self, context)
152+
let type = source.type
153+
if type.isStruct {
154+
if type.nominal.isStructWithUnreferenceableStorage {
155+
return
156+
}
157+
if parentFunction.hasOwnership && source.ownership != .none {
158+
let destructure = builder.createDestructureStruct(struct: source)
159+
for (fieldIdx, fieldValue) in destructure.results.enumerated() {
160+
let destFieldAddr = builder.createStructElementAddr(structAddress: destination, fieldIndex: fieldIdx)
161+
builder.createStore(source: fieldValue, destination: destFieldAddr, ownership: splitOwnership(for: fieldValue))
162+
}
163+
} else {
164+
for idx in 0..<type.getNominalFields(in: parentFunction).count {
165+
let srcField = builder.createStructExtract(struct: source, fieldIndex: idx)
166+
let fieldAddr = builder.createStructElementAddr(structAddress: destination, fieldIndex: idx)
167+
builder.createStore(source: srcField, destination: fieldAddr, ownership: splitOwnership(for: srcField))
168+
}
169+
}
170+
} else if type.isTuple {
171+
if parentFunction.hasOwnership && source.ownership != .none {
172+
let destructure = builder.createDestructureTuple(tuple: source)
173+
for (elementIdx, elementValue) in destructure.results.enumerated() {
174+
let elementAddr = builder.createTupleElementAddr(tupleAddress: destination, elementIndex: elementIdx)
175+
builder.createStore(source: elementValue, destination: elementAddr, ownership: splitOwnership(for: elementValue))
176+
}
177+
} else {
178+
for idx in 0..<type.tupleElements.count {
179+
let srcField = builder.createTupleExtract(tuple: source, elementIndex: idx)
180+
let destFieldAddr = builder.createTupleElementAddr(tupleAddress: destination, elementIndex: idx)
181+
builder.createStore(source: srcField, destination: destFieldAddr, ownership: splitOwnership(for: srcField))
182+
}
183+
}
184+
} else {
185+
return
186+
}
187+
context.erase(instruction: self)
188+
}
189+
190+
private func splitOwnership(for fieldValue: Value) -> StoreOwnership {
191+
switch self.storeOwnership {
192+
case .trivial, .unqualified:
193+
return self.storeOwnership
194+
case .assign, .initialize:
195+
return fieldValue.type.isTrivial(in: parentFunction) ? .trivial : self.storeOwnership
196+
}
197+
}
198+
}
199+
200+
extension LoadInst {
201+
func trySplit(_ context: FunctionPassContext) {
202+
var elements = [Value]()
203+
let builder = Builder(before: self, context)
204+
if type.isStruct {
205+
if type.nominal.isStructWithUnreferenceableStorage {
206+
return
207+
}
208+
for idx in 0..<type.getNominalFields(in: parentFunction).count {
209+
let fieldAddr = builder.createStructElementAddr(structAddress: address, fieldIndex: idx)
210+
let splitLoad = builder.createLoad(fromAddress: fieldAddr, ownership: self.splitOwnership(for: fieldAddr))
211+
elements.append(splitLoad)
212+
}
213+
let newStruct = builder.createStruct(type: self.type, elements: elements)
214+
self.uses.replaceAll(with: newStruct, context)
215+
} else if type.isTuple {
216+
var elements = [Value]()
217+
let builder = Builder(before: self, context)
218+
for idx in 0..<type.tupleElements.count {
219+
let fieldAddr = builder.createTupleElementAddr(tupleAddress: address, elementIndex: idx)
220+
let splitLoad = builder.createLoad(fromAddress: fieldAddr, ownership: self.splitOwnership(for: fieldAddr))
221+
elements.append(splitLoad)
222+
}
223+
let newTuple = builder.createTuple(type: self.type, elements: elements)
224+
self.uses.replaceAll(with: newTuple, context)
225+
} else {
226+
return
227+
}
228+
context.erase(instruction: self)
229+
}
230+
231+
private func splitOwnership(for fieldValue: Value) -> LoadOwnership {
232+
switch self.loadOwnership {
233+
case .trivial, .unqualified:
234+
return self.loadOwnership
235+
case .copy, .take:
236+
return fieldValue.type.isTrivial(in: parentFunction) ? .trivial : self.loadOwnership
237+
}
238+
}
239+
}
240+
241+
149242
extension UseList {
150243
var singleNonDebugUse: Operand? {
151244
var singleUse: Operand?

0 commit comments

Comments
 (0)