Skip to content

Commit ecc7127

Browse files
authored
Merge pull request #36183 from atrick/fix-dce-fixlifetime
Disable fix_lifetime DCE.
2 parents 791853c + f470b29 commit ecc7127

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace {
4141

4242
// Without any complex analysis, does this instruction seem like
4343
// something that we need to keep?
44+
//
4445
// FIXME: Reconcile the similarities between this and
4546
// isInstructionTriviallyDead.
4647
static bool seemsUseful(SILInstruction *I) {
@@ -243,9 +244,17 @@ void DCE::markLive() {
243244
}
244245
break;
245246
}
247+
// The side-effects of fix_lifetime effect all references to the same
248+
// object. It must be preserved to keep alive any potentially aliasing
249+
// references. fix_lifetime can only be removed by proving that its
250+
// operand is both a unique and a dead reference, but this makes more
251+
// sense in DeadObjectElimination.
246252
case SILInstructionKind::FixLifetimeInst: {
253+
// If the operand is a trivial scalar value, then it has no aliases or
254+
// side-effects. Consider handling this as an instruction
255+
// canonicalization instead.
247256
SILValue Op = I.getOperand(0);
248-
if (!Op->getType().isAddress()) {
257+
if (!Op->getType().isAddress() && Op->getType().isTrivial(*F)) {
249258
addReverseDependency(Op, &I);
250259
} else {
251260
markInstructionLive(&I);

test/SILOptimizer/dead_code_elimination_ossa.sil

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ sil_stage canonical
55
import Builtin
66
import Swift
77

8+
public struct S {
9+
var o: AnyObject
10+
}
11+
sil @dummy : $@convention(thin) () -> ()
12+
813
// CHECK-LABEL: sil [ossa] @dead1 :
914
// CHECK: bb0
1015
// CHECK-NEXT: return %0
@@ -289,3 +294,69 @@ bb0(%0 : @owned $(String, (Int, Int, String))):
289294
return %1 : $String
290295
}
291296

297+
// Test fix_lifetime of a struct and tuple. It cannot be removed
298+
// without proving reference uniqueness first.
299+
// rdar://36038096 ([SR-6608] DeadCodeElimination removes fix_lifetime instructions.)
300+
//
301+
// CHECK-LABEL: @testFixLifetimeTuple : $@convention(thin) (@owned S, @owned AnyObject) -> () {
302+
// CHECK: bb0(%0 : $S, %1 : $AnyObject):
303+
// CHECK: [[TUPLE:%.*]] = tuple (%0 : $S, %1 : $AnyObject)
304+
// CHECK: apply
305+
// CHECK: fix_lifetime [[TUPLE]] : $(S, AnyObject)
306+
// CHECK: strong_release %1 : $AnyObject
307+
// CHECK: strong_release %{{.*}} : $AnyObject
308+
// CHECK-LABEL: } // end sil function 'testFixLifetimeTuple'
309+
sil @testFixLifetimeTuple : $@convention(thin) (@owned S, @owned AnyObject) -> () {
310+
bb0(%0 : $S, %1 : $AnyObject):
311+
%4 = struct_extract %0 : $S, #S.o
312+
%7 = tuple (%0 : $S, %1 : $AnyObject)
313+
%8 = function_ref @dummy : $@convention(thin) () -> ()
314+
%9 = apply %8() : $@convention(thin) () -> ()
315+
fix_lifetime %7 : $(S, AnyObject)
316+
strong_release %1 : $AnyObject
317+
strong_release %4 : $AnyObject
318+
%15 = tuple ()
319+
return %15 : $()
320+
}
321+
322+
// Test fix_lifetime of a load_borrow. It cannot be removed without
323+
// proving reference uniqueness first.
324+
// rdar://74759728 (The compiler/optimizer seems to be shortening the lifetime too early)
325+
//
326+
// Test case derived from $defer #1 <A><A1>() in _ArrayBuffer.withUnsafeBufferPointer<A>(_:)
327+
//
328+
// Original source that exposed the issue with -Ounchecked -sanitize=address:
329+
//
330+
// public func makeRawData(name: String) -> UnsafeMutableRawPointer {
331+
// var array: [UInt8] = []
332+
// array.append(contentsOf: name.utf8)
333+
// array.append(0)
334+
//
335+
// let rawData = array.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) -> UnsafeMutableRawPointer in
336+
// let rawData = malloc(Int(buffer.count))!
337+
// rawData.copyMemory(from: buffer.baseAddress!, byteCount: buffer.count)
338+
// return rawData
339+
// }
340+
// return rawData
341+
// }
342+
//
343+
// CHECK-LABEL: sil [ossa] @testDCEFixLifetime : $@convention(thin) (@guaranteed S) -> () {
344+
// %0 "self" // users: %3, %1
345+
// CHECK: bb0(%0 : @guaranteed $S):
346+
// CHECK: [[LD:%.*]] = load_borrow
347+
// CHECK: fix_lifetime [[LD]] : $S
348+
// CHECK: end_borrow [[LD]] : $S
349+
// CHECK-LABEL: } // end sil function 'testDCEFixLifetime'
350+
sil [ossa] @testDCEFixLifetime : $@convention(thin) (@guaranteed S) -> () {
351+
// %0 "self"
352+
bb0(%0 : @guaranteed $S):
353+
debug_value %0 : $S, let, name "self", argno 1
354+
%2 = alloc_stack $S
355+
%3 = store_borrow %0 to %2 : $*S
356+
%4 = load_borrow %2 : $*S
357+
fix_lifetime %4 : $S
358+
end_borrow %4 : $S
359+
dealloc_stack %2 : $*S
360+
%8 = tuple ()
361+
return %8 : $()
362+
}

0 commit comments

Comments
 (0)