Skip to content

Commit fc6302e

Browse files
committed
LoopInvariantCodeMotion: correctly handle load [copy]
When moving loads and stores out of a loop, a `load [copy]` must be replaced by a `copy_value`.
1 parent a6fb187 commit fc6302e

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LoopInvariantCodeMotion.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,13 @@ private extension MovableInstructions {
798798
let rootVal = currentVal ?? ssaUpdater.getValue(inMiddleOf: block)
799799

800800
if loadInst.operand.value.accessPath == accessPath {
801-
loadInst.replace(with: rootVal, context)
801+
if loadInst.loadOwnership == .copy {
802+
let builder = Builder(before: loadInst, context)
803+
let copy = builder.createCopyValue(operand: rootVal)
804+
loadInst.replace(with: copy, context)
805+
} else {
806+
loadInst.replace(with: rootVal, context)
807+
}
802808
changed = true
803809
continue
804810
}
@@ -808,7 +814,11 @@ private extension MovableInstructions {
808814
}
809815

810816
let builder = Builder(before: loadInst, context)
811-
let projection = rootVal.createProjection(path: projectionPath, builder: builder)
817+
let projection = if loadInst.loadOwnership == .copy {
818+
rootVal.createProjectionAndCopy(path: projectionPath, builder: builder)
819+
} else {
820+
rootVal.createProjection(path: projectionPath, builder: builder)
821+
}
812822
loadInst.replace(with: projection, context)
813823

814824
changed = true

test/SILOptimizer/licm.sil

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,3 +2032,59 @@ bb3:
20322032
return %r
20332033
}
20342034

2035+
// CHECK-LABEL: sil [ossa] @load_copy_followed_by_take :
2036+
// CHECK: bb1([[V:%.*]] : @owned $S):
2037+
// CHECK-NEXT: [[C:%.*]] = copy_value [[V]]
2038+
// CHECK-NEXT: destroy_value [[C]]
2039+
// CHECK-NEXT: = move_value [[V]]
2040+
// CHECK-LABEL: } // end sil function 'load_copy_followed_by_take'
2041+
sil [ossa] @load_copy_followed_by_take : $@convention(thin) (@inout S) -> () {
2042+
bb0(%0 : $*S):
2043+
br bb1
2044+
2045+
bb1:
2046+
%4 = load [copy] %0
2047+
destroy_value %4
2048+
%6 = load [take] %0
2049+
%7 = move_value %6
2050+
store %7 to [init] %0
2051+
cond_br undef, bb2, bb3
2052+
2053+
bb2:
2054+
br bb1
2055+
2056+
bb3:
2057+
%r = tuple ()
2058+
return %r
2059+
}
2060+
2061+
// CHECK-LABEL: sil [ossa] @projected_load_copy_followed_by_take :
2062+
// CHECK: bb1([[V:%.*]] : @owned $S):
2063+
// CHECK-NEXT: [[B:%.*]] = begin_borrow [[V]]
2064+
// CHECK-NEXT: [[SE:%.*]] = struct_extract [[B]]
2065+
// CHECK-NEXT: [[C:%.*]] = copy_value [[SE]]
2066+
// CHECK-NEXT: end_borrow [[B]]
2067+
// CHECK-NEXT: destroy_value [[C]]
2068+
// CHECK-NEXT: ({{%[0-9]+}}, [[S:%.*]]) = destructure_struct [[V]]
2069+
// CHECK-NEXT: = struct $S (%1 : $Int, [[S]] : $String)
2070+
// CHECK-LABEL: } // end sil function 'projected_load_copy_followed_by_take'
2071+
sil [ossa] @projected_load_copy_followed_by_take : $@convention(thin) (@inout S, Int) -> () {
2072+
bb0(%0 : $*S, %1 : $Int):
2073+
br bb1
2074+
2075+
bb1:
2076+
%43 = struct_element_addr %0, #S.s
2077+
%4 = load [copy] %43
2078+
destroy_value %4
2079+
%48 = load [take] %43
2080+
%49 = struct $S (%1, %48)
2081+
store %49 to [init] %0
2082+
cond_br undef, bb2, bb3
2083+
2084+
bb2:
2085+
br bb1
2086+
2087+
bb3:
2088+
%r = tuple ()
2089+
return %r
2090+
}

0 commit comments

Comments
 (0)