Skip to content

Commit 4917510

Browse files
committed
TempLValue opt: don't insert destroy_addr too early due to ignoring deinit barriers
This can happen for inout arguments. It fixes a potential miscompile, e.g. observable by a weak reference being nil where it shouldn't. rdar://116335089
1 parent a8296e1 commit 4917510

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

lib/SILOptimizer/Transforms/TempLValueOpt.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "swift/SILOptimizer/PassManager/Transforms.h"
2020
#include "swift/SILOptimizer/Analysis/AliasAnalysis.h"
21+
#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h"
2122
#include "swift/SIL/NodeBits.h"
2223
#include "swift/SIL/SILFunction.h"
2324
#include "swift/SIL/SILBasicBlock.h"
@@ -176,6 +177,13 @@ void TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) {
176177
// but a block argument.
177178
SILInstruction *destRootInst = destRootAddr->getDefiningInstruction();
178179

180+
bool needDestroyEarly = false;
181+
BasicCalleeAnalysis *bca = nullptr;
182+
if (!copyInst->isInitializationOfDest()) {
183+
needDestroyEarly = true;
184+
bca = PM->getAnalysis<BasicCalleeAnalysis>();
185+
}
186+
179187
// Iterate over the liferange of the temporary and make some validity checks.
180188
AliasAnalysis *AA = nullptr;
181189
SILInstruction *beginOfLiferange = nullptr;
@@ -220,6 +228,9 @@ void TempLValueOptPass::tempLValueOpt(CopyAddrInst *copyInst) {
220228
// Needed to treat init_existential_addr as not-writing projection.
221229
projections.contains(inst) == 0)
222230
return;
231+
232+
if (needDestroyEarly && isDeinitBarrier(inst, bca))
233+
return;
223234
}
224235
}
225236
assert(endOfLiferangeReached);

test/SILOptimizer/templvalueopt_ossa.sil

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,35 @@ bb0(%0 : $*T):
300300
return %78 : $()
301301
}
302302

303+
sil @createAny : $@convention(thin) () -> @out Any
304+
sil @createAny_no_barrier : $@convention(thin) () -> @out Any {
305+
[global:]
306+
}
307+
308+
// CHECK-LABEL: sil [ossa] @test_deinit_barrier :
309+
// CHECK: copy_addr [take]
310+
// CHECK-LABEL: } // end sil function 'test_deinit_barrier'
311+
sil [ossa] @test_deinit_barrier : $@convention(thin) (@guaranteed Any, @inout Any) -> () {
312+
bb0(%0 : @guaranteed $Any, %1 : $*Any):
313+
%2 = alloc_stack $Any
314+
%4 = function_ref @createAny : $@convention(thin) () -> @out Any
315+
%5 = apply %4(%2) : $@convention(thin) () -> @out Any
316+
copy_addr [take] %2 to %1 : $*Any
317+
dealloc_stack %2 : $*Any
318+
%11 = tuple ()
319+
return %11 : $()
320+
}
321+
322+
// CHECK-LABEL: sil [ossa] @test_no_deinit_barrier :
323+
// CHECK-NOT: copy_addr
324+
// CHECK-LABEL: } // end sil function 'test_no_deinit_barrier'
325+
sil [ossa] @test_no_deinit_barrier : $@convention(thin) (@guaranteed Any, @inout Any) -> () {
326+
bb0(%0 : @guaranteed $Any, %1 : $*Any):
327+
%2 = alloc_stack $Any
328+
%4 = function_ref @createAny_no_barrier : $@convention(thin) () -> @out Any
329+
%5 = apply %4(%2) : $@convention(thin) () -> @out Any
330+
copy_addr [take] %2 to %1 : $*Any
331+
dealloc_stack %2 : $*Any
332+
%11 = tuple ()
333+
return %11 : $()
334+
}

0 commit comments

Comments
 (0)