Skip to content

Commit a6fb187

Browse files
committed
LoopInvariantCodeMotion: correctly create projections for owned values
Owned structs and tuples must be projected by `destructure_struct` and `destructure_tuple`, respectively. rdar://161467837
1 parent 7bbe5c6 commit a6fb187

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,20 +125,32 @@ extension Value {
125125
return true
126126
}
127127

128+
/// Project out a sub-field of this value according to `path`.
129+
/// If this is an "owned" value the result is an "owned" value which forwards the original value.
130+
/// This only works if _all_ non-trivial fields are projected. Otherwise some non-trivial results of
131+
/// `destructure_struct` or `destructure_tuple` will be leaked.
128132
func createProjection(path: SmallProjectionPath, builder: Builder) -> Value {
129133
let (kind, index, subPath) = path.pop()
134+
let result: Value
130135
switch kind {
131136
case .root:
132137
return self
133138
case .structField:
134-
let structExtract = builder.createStructExtract(struct: self, fieldIndex: index)
135-
return structExtract.createProjection(path: subPath, builder: builder)
139+
if ownership == .owned {
140+
result = builder.createDestructureStruct(struct: self).results[index]
141+
} else {
142+
result = builder.createStructExtract(struct: self, fieldIndex: index)
143+
}
136144
case .tupleField:
137-
let tupleExtract = builder.createTupleExtract(tuple: self, elementIndex: index)
138-
return tupleExtract.createProjection(path: subPath, builder: builder)
145+
if ownership == .owned {
146+
result = builder.createDestructureTuple(tuple: self).results[index]
147+
} else {
148+
result = builder.createTupleExtract(tuple: self, elementIndex: index)
149+
}
139150
default:
140151
fatalError("path is not materializable")
141152
}
153+
return result.createProjection(path: subPath, builder: builder)
142154
}
143155

144156
func createAddressProjection(path: SmallProjectionPath, builder: Builder) -> Value {

test/SILOptimizer/licm.sil

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,3 +2005,30 @@ bb3:
20052005
return %r
20062006
}
20072007

2008+
// CHECK-LABEL: sil [ossa] @projected_load_take :
2009+
// CHECK: bb1([[V:%.*]] : @owned $(S, Int)):
2010+
// CHECK-NEXT: ([[E:%.*]], {{%[0-9]+}}) = destructure_tuple [[V]]
2011+
// CHECK-NEXT: ({{%[0-9]+}}, [[S:%.*]]) = destructure_struct [[E]]
2012+
// CHECK-NEXT: = struct $S (%1 : $Int, [[S]] : $String)
2013+
// CHECK-LABEL: } // end sil function 'projected_load_take'
2014+
sil [ossa] @projected_load_take : $@convention(thin) (@inout (S, Int), Int) -> () {
2015+
bb0(%0 : $*(S, Int), %1 : $Int):
2016+
br bb1
2017+
2018+
bb1:
2019+
%2 = tuple_element_addr %0, 0
2020+
%3 = struct_element_addr %2, #S.s
2021+
%4 = load [take] %3
2022+
%5 = struct $S (%1, %4)
2023+
%6 = tuple (%5, %1)
2024+
store %6 to [init] %0
2025+
cond_br undef, bb2, bb3
2026+
2027+
bb2:
2028+
br bb1
2029+
2030+
bb3:
2031+
%r = tuple ()
2032+
return %r
2033+
}
2034+

0 commit comments

Comments
 (0)