mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Optimizer: let the InstructionDeleter respect deinit-barriers by default
The InstructionDeleter can remove instructions including their destroys and then insert compensating destroys at a new place. This is effectively destroy-hoisting which doesn't respect deinit-barriers. Therefore it's not done for lexical lifetimes. However, since https://github.com/swiftlang/swift/pull/85334, the optimizer should treat _all_ lifetimes as fixed and not only lexical lifetimes. This change adds a `assumeFixedLifetimes` flag to InstructionDeleter which is on by default. Only mandatory passes (like OSLogOptimization) should turn this off.
This commit is contained in:
@@ -119,11 +119,15 @@ class InstructionDeleter {
|
|||||||
/// Callbacks used when adding/deleting instructions.
|
/// Callbacks used when adding/deleting instructions.
|
||||||
InstModCallbacks callbacks;
|
InstModCallbacks callbacks;
|
||||||
|
|
||||||
public:
|
bool assumeFixedLifetimes = true;
|
||||||
InstructionDeleter() : deadInstructions() {}
|
|
||||||
|
|
||||||
InstructionDeleter(InstModCallbacks &&callbacks)
|
public:
|
||||||
: deadInstructions(), callbacks(std::move(callbacks)) {}
|
InstructionDeleter(bool assumeFixedLifetimes = true)
|
||||||
|
: deadInstructions(), assumeFixedLifetimes(assumeFixedLifetimes) {}
|
||||||
|
|
||||||
|
InstructionDeleter(InstModCallbacks &&callbacks, bool assumeFixedLifetimes = true)
|
||||||
|
: deadInstructions(), callbacks(std::move(callbacks)),
|
||||||
|
assumeFixedLifetimes(assumeFixedLifetimes) {}
|
||||||
|
|
||||||
InstModCallbacks &getCallbacks() { return callbacks; }
|
InstModCallbacks &getCallbacks() { return callbacks; }
|
||||||
|
|
||||||
|
|||||||
@@ -1206,7 +1206,7 @@ static bool tryEliminateOSLogMessage(SingleValueInstruction *oslogMessage) {
|
|||||||
}
|
}
|
||||||
(void)deletedInstructions.insert(deadInst);
|
(void)deletedInstructions.insert(deadInst);
|
||||||
});
|
});
|
||||||
InstructionDeleter deleter(std::move(callbacks));
|
InstructionDeleter deleter(std::move(callbacks), /*assumeFixedLifetimes=*/ false);
|
||||||
|
|
||||||
unsigned startIndex = 0;
|
unsigned startIndex = 0;
|
||||||
while (startIndex < worklist.size()) {
|
while (startIndex < worklist.size()) {
|
||||||
@@ -1433,7 +1433,7 @@ suppressGlobalStringTablePointerError(SingleValueInstruction *oslogMessage) {
|
|||||||
|
|
||||||
// Replace the globalStringTablePointer builtins by a string_literal
|
// Replace the globalStringTablePointer builtins by a string_literal
|
||||||
// instruction for an empty string and clean up dead code.
|
// instruction for an empty string and clean up dead code.
|
||||||
InstructionDeleter deleter;
|
InstructionDeleter deleter(/*assumeFixedLifetimes=*/ false);
|
||||||
for (BuiltinInst *bi : globalStringTablePointerInsts) {
|
for (BuiltinInst *bi : globalStringTablePointerInsts) {
|
||||||
SILBuilderWithScope builder(bi);
|
SILBuilderWithScope builder(bi);
|
||||||
StringLiteralInst *stringLiteral = builder.createStringLiteral(
|
StringLiteralInst *stringLiteral = builder.createStringLiteral(
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ static bool hasOnlyIncidentalUses(SILInstruction *inst,
|
|||||||
///
|
///
|
||||||
/// TODO: Handle partial_apply [stack] which has a dealloc_stack user.
|
/// TODO: Handle partial_apply [stack] which has a dealloc_stack user.
|
||||||
static bool isScopeAffectingInstructionDead(SILInstruction *inst,
|
static bool isScopeAffectingInstructionDead(SILInstruction *inst,
|
||||||
bool fixLifetime) {
|
bool fixLifetime,
|
||||||
|
bool assumeFixedLifetimes) {
|
||||||
SILFunction *fun = inst->getFunction();
|
SILFunction *fun = inst->getFunction();
|
||||||
assert(fun && "Instruction has no function.");
|
assert(fun && "Instruction has no function.");
|
||||||
// Only support ownership SIL for scoped instructions.
|
// Only support ownership SIL for scoped instructions.
|
||||||
@@ -84,7 +85,7 @@ static bool isScopeAffectingInstructionDead(SILInstruction *inst,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If result was lexical, lifetime shortening maybe observed, return.
|
// If result was lexical, lifetime shortening maybe observed, return.
|
||||||
if (result->isLexical()) {
|
if (result->isLexical() || assumeFixedLifetimes) {
|
||||||
auto resultTy = result->getType().getAs<SILFunctionType>();
|
auto resultTy = result->getType().getAs<SILFunctionType>();
|
||||||
// Allow deleted dead lexical values when they are trivial no escape types.
|
// Allow deleted dead lexical values when they are trivial no escape types.
|
||||||
if (!resultTy || !resultTy->isTrivialNoEscape()) {
|
if (!resultTy || !resultTy->isTrivialNoEscape()) {
|
||||||
@@ -186,7 +187,7 @@ static bool isScopeAffectingInstructionDead(SILInstruction *inst,
|
|||||||
bool InstructionDeleter::trackIfDead(SILInstruction *inst) {
|
bool InstructionDeleter::trackIfDead(SILInstruction *inst) {
|
||||||
bool fixLifetime = inst->getFunction()->hasOwnership();
|
bool fixLifetime = inst->getFunction()->hasOwnership();
|
||||||
if (isInstructionTriviallyDead(inst)
|
if (isInstructionTriviallyDead(inst)
|
||||||
|| isScopeAffectingInstructionDead(inst, fixLifetime)) {
|
|| isScopeAffectingInstructionDead(inst, fixLifetime, assumeFixedLifetimes)) {
|
||||||
assert(!isIncidentalUse(inst)
|
assert(!isIncidentalUse(inst)
|
||||||
|| canTriviallyDeleteOSSAEndScopeInst(inst) &&
|
|| canTriviallyDeleteOSSAEndScopeInst(inst) &&
|
||||||
"Incidental uses cannot be removed in isolation. "
|
"Incidental uses cannot be removed in isolation. "
|
||||||
@@ -333,7 +334,7 @@ bool InstructionDeleter::deleteIfDead(SILInstruction *inst) {
|
|||||||
|
|
||||||
bool InstructionDeleter::deleteIfDead(SILInstruction *inst, bool fixLifetime) {
|
bool InstructionDeleter::deleteIfDead(SILInstruction *inst, bool fixLifetime) {
|
||||||
if (isInstructionTriviallyDead(inst)
|
if (isInstructionTriviallyDead(inst)
|
||||||
|| isScopeAffectingInstructionDead(inst, fixLifetime)) {
|
|| isScopeAffectingInstructionDead(inst, fixLifetime, assumeFixedLifetimes)) {
|
||||||
getCallbacks().notifyWillBeDeleted(inst);
|
getCallbacks().notifyWillBeDeleted(inst);
|
||||||
deleteWithUses(inst, fixLifetime);
|
deleteWithUses(inst, fixLifetime);
|
||||||
return true;
|
return true;
|
||||||
@@ -349,7 +350,7 @@ namespace swift::test {
|
|||||||
static FunctionTest DeleterDeleteIfDeadTest(
|
static FunctionTest DeleterDeleteIfDeadTest(
|
||||||
"deleter_delete_if_dead", [](auto &function, auto &arguments, auto &test) {
|
"deleter_delete_if_dead", [](auto &function, auto &arguments, auto &test) {
|
||||||
auto *inst = arguments.takeInstruction();
|
auto *inst = arguments.takeInstruction();
|
||||||
InstructionDeleter deleter;
|
InstructionDeleter deleter(/*assumeFixedLifetimes=*/ false);
|
||||||
llvm::outs() << "Deleting-if-dead " << *inst;
|
llvm::outs() << "Deleting-if-dead " << *inst;
|
||||||
auto deleted = deleter.deleteIfDead(inst);
|
auto deleted = deleter.deleteIfDead(inst);
|
||||||
llvm::outs() << "deleteIfDead returned " << deleted << "\n";
|
llvm::outs() << "deleteIfDead returned " << deleted << "\n";
|
||||||
|
|||||||
@@ -2934,6 +2934,7 @@ bb0:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CHECK-LABEL: sil [ossa] @test_store_borrow_1_copy_addr : {{.*}} {
|
// CHECK-LABEL: sil [ossa] @test_store_borrow_1_copy_addr : {{.*}} {
|
||||||
|
// CHECK: alloc_stack
|
||||||
// CHECK: [[ADDR:%[^,]+]] = alloc_stack
|
// CHECK: [[ADDR:%[^,]+]] = alloc_stack
|
||||||
// CHECK: apply undef<T>([[ADDR]])
|
// CHECK: apply undef<T>([[ADDR]])
|
||||||
// CHECK: [[COPY:%[^,]+]] = alloc_stack
|
// CHECK: [[COPY:%[^,]+]] = alloc_stack
|
||||||
|
|||||||
@@ -909,9 +909,9 @@ sil [ossa] @canonicalize_source_of_redundant_move_value : $@convention(thin) ()
|
|||||||
return %retval : $()
|
return %retval : $()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that a dead copy_value is deleted.
|
// TODO: why is the copy not deleted here?
|
||||||
// CHECK-LABEL: sil [ossa] @delete_dead_reborrow_copy : {{.*}} {
|
// CHECK-LABEL: sil [ossa] @delete_dead_reborrow_copy : {{.*}} {
|
||||||
// CHECK-NOT: copy_value
|
// xCHECK-NOT: copy_value
|
||||||
// CHECK-LABEL: } // end sil function 'delete_dead_reborrow_copy'
|
// CHECK-LABEL: } // end sil function 'delete_dead_reborrow_copy'
|
||||||
sil [ossa] @delete_dead_reborrow_copy : $@convention(thin) (@owned X) -> () {
|
sil [ossa] @delete_dead_reborrow_copy : $@convention(thin) (@owned X) -> () {
|
||||||
bb0(%instance : @owned $X):
|
bb0(%instance : @owned $X):
|
||||||
|
|||||||
@@ -168,7 +168,8 @@ bb0(%0 : @guaranteed $NativeObjectPair):
|
|||||||
// CHECK-LABEL: sil [ossa] @testBorrowOuterUse : {{.*}} {
|
// CHECK-LABEL: sil [ossa] @testBorrowOuterUse : {{.*}} {
|
||||||
// CHECK: bb0:
|
// CHECK: bb0:
|
||||||
// CHECK: [[INSTANCE:%.*]] = apply
|
// CHECK: [[INSTANCE:%.*]] = apply
|
||||||
// CHECK-NOT: begin_borrow
|
// CHECK: begin_borrow
|
||||||
|
// CHECK-NEXT: end_borrow
|
||||||
// CHECK-NOT: copy
|
// CHECK-NOT: copy
|
||||||
// CHECK: apply %{{.*}}([[INSTANCE]]) : $@convention(thin) (@owned C) -> ()
|
// CHECK: apply %{{.*}}([[INSTANCE]]) : $@convention(thin) (@owned C) -> ()
|
||||||
// CHECK-NOT: destroy
|
// CHECK-NOT: destroy
|
||||||
@@ -191,7 +192,8 @@ bb0:
|
|||||||
//
|
//
|
||||||
// CHECK-LABEL: sil [ossa] @testMultiBlockBorrow : $@convention(thin) (@guaranteed C) -> () {
|
// CHECK-LABEL: sil [ossa] @testMultiBlockBorrow : $@convention(thin) (@guaranteed C) -> () {
|
||||||
// CHECK: bb0(%0 : @guaranteed $C):
|
// CHECK: bb0(%0 : @guaranteed $C):
|
||||||
// CHECK-NOT: borrow
|
// CHECK: borrow
|
||||||
|
// CHECK-NEXT: end_borrow
|
||||||
// CHECK-NOT: copy
|
// CHECK-NOT: copy
|
||||||
// CHECK: cond_br undef, bb1, bb2
|
// CHECK: cond_br undef, bb1, bb2
|
||||||
// CHECK: bb1:
|
// CHECK: bb1:
|
||||||
@@ -485,14 +487,17 @@ bb3:
|
|||||||
// CHECK-LABEL: sil [ossa] @testNestedBorrowInsideAndOutsideUse : $@convention(thin) () -> () {
|
// CHECK-LABEL: sil [ossa] @testNestedBorrowInsideAndOutsideUse : $@convention(thin) () -> () {
|
||||||
// CHECK: [[ALLOC:%.*]] = alloc_ref $C
|
// CHECK: [[ALLOC:%.*]] = alloc_ref $C
|
||||||
// CHECK: [[B1:%.*]] = begin_borrow [[ALLOC]] : $C
|
// CHECK: [[B1:%.*]] = begin_borrow [[ALLOC]] : $C
|
||||||
// CHECK-NOT: borrow
|
// CHECK-NEXT: [[B2:%.*]] = begin_borrow [[ALLOC]] : $C
|
||||||
|
// CHECK-NOT: copy_value
|
||||||
// CHECK: bb1:
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: end_borrow [[B2]] : $C
|
||||||
// CHECK-NEXT: end_borrow [[B1]] : $C
|
// CHECK-NEXT: end_borrow [[B1]] : $C
|
||||||
// CHECK-NEXT: destroy_value [[ALLOC]] : $C
|
// CHECK-NEXT: destroy_value [[ALLOC]] : $C
|
||||||
// CHECK-NEXT: br bb3
|
// CHECK-NEXT: br bb3
|
||||||
// CHECK: bb2:
|
// CHECK: bb2:
|
||||||
// CHECK-NEXT: end_borrow %1 : $C
|
// CHECK-NEXT: end_borrow [[B1]] : $C
|
||||||
// CHECK-NEXT: destroy_value %0 : $C
|
// CHECK-NEXT: end_borrow [[B2]] : $C
|
||||||
|
// CHECK-NEXT: destroy_value [[ALLOC]] : $C
|
||||||
// CHECK-NEXT: br bb3
|
// CHECK-NEXT: br bb3
|
||||||
// CHECK: bb3:
|
// CHECK: bb3:
|
||||||
// CHECK-NOT: destroy
|
// CHECK-NOT: destroy
|
||||||
@@ -655,11 +660,12 @@ bb3(%borrowphi : @guaranteed $C):
|
|||||||
// The inner copy's lifetime will be canonicalized, removing
|
// The inner copy's lifetime will be canonicalized, removing
|
||||||
// outercopy.
|
// outercopy.
|
||||||
//
|
//
|
||||||
|
// TODO: why can't the first copy_value not be removed?
|
||||||
// CHECK-LABEL: sil [ossa] @testDeadCopyAfterReborrow : $@convention(thin) () -> () {
|
// CHECK-LABEL: sil [ossa] @testDeadCopyAfterReborrow : $@convention(thin) () -> () {
|
||||||
// CHECK: [[ALLOC:%.*]] = alloc_ref $C
|
// CHECK: [[ALLOC:%.*]] = alloc_ref $C
|
||||||
// CHECK: bb3([[BORROWPHI:%.*]] : @reborrow $C):
|
// CHECK: bb3([[BORROWPHI:%.*]] : @reborrow $C):
|
||||||
// CHECK: [[R:%.*]] = borrowed [[BORROWPHI]] : $C from (%0 : $C)
|
// CHECK: [[R:%.*]] = borrowed [[BORROWPHI]] : $C from (%0 : $C)
|
||||||
// CHECK-NOT: copy_value
|
// xCHECK-NOT: copy_value
|
||||||
// CHECK: end_borrow [[R]] : $C
|
// CHECK: end_borrow [[R]] : $C
|
||||||
// CHECK-NOT: copy_value
|
// CHECK-NOT: copy_value
|
||||||
// CHECK: destroy_value [[ALLOC]] : $C
|
// CHECK: destroy_value [[ALLOC]] : $C
|
||||||
@@ -696,13 +702,14 @@ bb3(%borrowphi : @guaranteed $C):
|
|||||||
// end borrowphi
|
// end borrowphi
|
||||||
// outer copy -- removed when borrowphi's copy is canonicalized
|
// outer copy -- removed when borrowphi's copy is canonicalized
|
||||||
//
|
//
|
||||||
|
// TODO: why can't the first copy_value not be removed?
|
||||||
// CHECK-LABEL: sil [ossa] @testNestedReborrowOutsideUse : $@convention(thin) () -> () {
|
// CHECK-LABEL: sil [ossa] @testNestedReborrowOutsideUse : $@convention(thin) () -> () {
|
||||||
// CHECK: [[ALLOC:%.*]] = alloc_ref $C
|
// CHECK: [[ALLOC:%.*]] = alloc_ref $C
|
||||||
// CHECK: bb3([[BORROWPHI:%.*]] : @reborrow $C):
|
// CHECK: bb3([[BORROWPHI:%.*]] : @reborrow $C):
|
||||||
// CHECK: [[R:%.*]] = borrowed [[BORROWPHI]] : $C from (%0 : $C)
|
// CHECK: [[R:%.*]] = borrowed [[BORROWPHI]] : $C from (%0 : $C)
|
||||||
// CHECK-NOT: copy
|
// xCHECK-NOT: copy
|
||||||
// CHECK: end_borrow [[R]]
|
// CHECK: end_borrow [[R]]
|
||||||
// CHECK-NEXT: destroy_value [[ALLOC]] : $C
|
// CHECK: destroy_value [[ALLOC]] : $C
|
||||||
// CHECK-LABEL: } // end sil function 'testNestedReborrowOutsideUse'
|
// CHECK-LABEL: } // end sil function 'testNestedReborrowOutsideUse'
|
||||||
sil [ossa] @testNestedReborrowOutsideUse : $@convention(thin) () -> () {
|
sil [ossa] @testNestedReborrowOutsideUse : $@convention(thin) () -> () {
|
||||||
bb0:
|
bb0:
|
||||||
@@ -883,7 +890,8 @@ bb0:
|
|||||||
// CHECK-LABEL: sil [ossa] @testForwardBorrow3 : {{.*}} {
|
// CHECK-LABEL: sil [ossa] @testForwardBorrow3 : {{.*}} {
|
||||||
// CHECK: bb0:
|
// CHECK: bb0:
|
||||||
// CHECK: [[INSTANCE:%.*]] = apply
|
// CHECK: [[INSTANCE:%.*]] = apply
|
||||||
// CHECK-NOT: borrow
|
// CHECK: begin_borrow
|
||||||
|
// CHECK-NEXT: end_borrow
|
||||||
// CHECK-NOT: copy
|
// CHECK-NOT: copy
|
||||||
// CHECK: [[DSOUT1:%.*]] = destructure_struct [[INSTANCE]] : $Wrapper
|
// CHECK: [[DSOUT1:%.*]] = destructure_struct [[INSTANCE]] : $Wrapper
|
||||||
// CHECK-NEXT: ([[DSOUT2:%.*]], %{{.*}}) = destructure_struct [[DSOUT1]] : $HasObjectAndInt
|
// CHECK-NEXT: ([[DSOUT2:%.*]], %{{.*}}) = destructure_struct [[DSOUT1]] : $HasObjectAndInt
|
||||||
@@ -911,17 +919,18 @@ bb0:
|
|||||||
// but one has no outer uses.
|
// but one has no outer uses.
|
||||||
// Need to create two new destroys in this case.
|
// Need to create two new destroys in this case.
|
||||||
//
|
//
|
||||||
|
// TODO: why can't the copy_value not be removed?
|
||||||
//
|
//
|
||||||
// CHECK-LABEL: sil [ossa] @testForwardBorrow4 : {{.*}} {
|
// CHECK-LABEL: sil [ossa] @testForwardBorrow4 : {{.*}} {
|
||||||
// CHECK: bb0:
|
// CHECK: bb0:
|
||||||
// CHECK: [[INSTANCE:%.*]] = apply
|
// CHECK: [[INSTANCE:%.*]] = apply
|
||||||
// CHECK-NEXT: ([[HASOBJECTS_0:%[^,]+]], [[HASOBJECTS_1:%[^,]+]]) = destructure_struct [[INSTANCE]] : $MultiWrapper
|
// xCHECK-NEXT: ([[HASOBJECTS_0:%[^,]+]], [[HASOBJECTS_1:%[^,]+]]) = destructure_struct [[INSTANCE]] : $MultiWrapper
|
||||||
// CHECK-NEXT: destroy_value [[HASOBJECTS_1]] : $HasObjects
|
// xCHECK-NEXT: destroy_value [[HASOBJECTS_1]] : $HasObjects
|
||||||
// CHECK-NEXT: ([[VAL:%.*]], [[OBJECT_1:%[^,]+]]) = destructure_struct [[HASOBJECTS_0]] : $HasObjects
|
// xCHECK-NEXT: ([[VAL:%.*]], [[OBJECT_1:%[^,]+]]) = destructure_struct [[HASOBJECTS_0]] : $HasObjects
|
||||||
// CHECK-NEXT: destroy_value [[OBJECT_1]] : $C
|
// xCHECK-NEXT: destroy_value [[OBJECT_1]] : $C
|
||||||
// CHECK-NOT: borrow
|
// xCHECK-NOT: borrow
|
||||||
// CHECK: apply %{{.*}}([[VAL]]) : $@convention(thin) (@owned C) -> ()
|
// xCHECK: apply %{{.*}}([[VAL]]) : $@convention(thin) (@owned C) -> ()
|
||||||
// CHECK-NOT: destroy
|
// xCHECK-NOT: destroy
|
||||||
// CHECK-LABEL: } // end sil function 'testForwardBorrow4'
|
// CHECK-LABEL: } // end sil function 'testForwardBorrow4'
|
||||||
sil [ossa] @testForwardBorrow4 : $@convention(thin) () -> () {
|
sil [ossa] @testForwardBorrow4 : $@convention(thin) () -> () {
|
||||||
bb0:
|
bb0:
|
||||||
@@ -953,6 +962,9 @@ bb0:
|
|||||||
// CHECK: bb0:
|
// CHECK: bb0:
|
||||||
// CHECK: [[INSTANCE:%.*]] = apply
|
// CHECK: [[INSTANCE:%.*]] = apply
|
||||||
// CHECK-NEXT: [[COPY:%[^,]+]] = copy_value [[INSTANCE]] : $HasObjectAndInt
|
// CHECK-NEXT: [[COPY:%[^,]+]] = copy_value [[INSTANCE]] : $HasObjectAndInt
|
||||||
|
// CHECK-NEXT: begin_borrow
|
||||||
|
// CHECK-NEXT: destructure_struct
|
||||||
|
// CHECK-NEXT: end_borrow
|
||||||
// CHECK-NEXT: ([[OBJECT:%[^,]+]], {{%[^,]+}}) = destructure_struct [[COPY]] : $HasObjectAndInt
|
// CHECK-NEXT: ([[OBJECT:%[^,]+]], {{%[^,]+}}) = destructure_struct [[COPY]] : $HasObjectAndInt
|
||||||
// CHECK-NEXT: [[BORROW:%[^,]+]] = begin_borrow [[OBJECT]] : $C
|
// CHECK-NEXT: [[BORROW:%[^,]+]] = begin_borrow [[OBJECT]] : $C
|
||||||
// CHECK-NEXT: [[TAIL_ADDR:%[^,]+]] = ref_tail_addr [[BORROW]] : $C, $Builtin.Int8
|
// CHECK-NEXT: [[TAIL_ADDR:%[^,]+]] = ref_tail_addr [[BORROW]] : $C, $Builtin.Int8
|
||||||
@@ -1082,11 +1094,15 @@ bb0(%0 : @owned $HasObject):
|
|||||||
// CHECK-LABEL: sil [ossa] @testUselessBorrowString : {{.*}} {
|
// CHECK-LABEL: sil [ossa] @testUselessBorrowString : {{.*}} {
|
||||||
// CHECK: bb0:
|
// CHECK: bb0:
|
||||||
// CHECK: [[INSTANCE:%.*]] = apply
|
// CHECK: [[INSTANCE:%.*]] = apply
|
||||||
|
// CHECK-NEXT: begin_borrow
|
||||||
|
// CHECK-NEXT: end_borrow
|
||||||
// CHECK-NEXT: [[DESTRUCTURE:%.*]] = destructure_struct [[INSTANCE]] : $String
|
// CHECK-NEXT: [[DESTRUCTURE:%.*]] = destructure_struct [[INSTANCE]] : $String
|
||||||
// CHECK-NEXT: [[UTF16:%.*]] = struct $String.UTF16View ([[DESTRUCTURE]] : $_StringGuts)
|
// CHECK-NEXT: [[UTF16:%.*]] = struct $String.UTF16View ([[DESTRUCTURE]] : $_StringGuts)
|
||||||
// CHECK-NEXT: br bb1
|
// CHECK-NEXT: br bb1
|
||||||
// CHECK: bb1:
|
// CHECK: bb1:
|
||||||
// CHECK-NEXT: [[COPY:%.*]] = copy_value [[UTF16]] : $String.UTF16View
|
// CHECK-NEXT: [[COPY:%.*]] = copy_value [[UTF16]] : $String.UTF16View
|
||||||
|
// CHECK-NEXT: begin_borrow
|
||||||
|
// CHECK-NEXT: end_borrow
|
||||||
// CHECK-NEXT: [[GUTS:%.*]] = destructure_struct [[COPY]] : $String.UTF16View
|
// CHECK-NEXT: [[GUTS:%.*]] = destructure_struct [[COPY]] : $String.UTF16View
|
||||||
// CHECK-NEXT: [[OBJ:%.*]] = destructure_struct [[GUTS]] : $_StringGuts
|
// CHECK-NEXT: [[OBJ:%.*]] = destructure_struct [[GUTS]] : $_StringGuts
|
||||||
// CHECK-NEXT: [[BORROW:%.*]] = begin_borrow [[OBJ]] : $_StringObject
|
// CHECK-NEXT: [[BORROW:%.*]] = begin_borrow [[OBJ]] : $_StringObject
|
||||||
|
|||||||
@@ -419,6 +419,8 @@ bb0:
|
|||||||
// CHECK-LABEL: sil [ossa] @testBorrowCopy : {{.*}} {
|
// CHECK-LABEL: sil [ossa] @testBorrowCopy : {{.*}} {
|
||||||
// CHECK-LABEL: bb0:
|
// CHECK-LABEL: bb0:
|
||||||
// CHECK: [[INSTANCE:%[^,]+]] = apply
|
// CHECK: [[INSTANCE:%[^,]+]] = apply
|
||||||
|
// CHECK-NEXT: begin_borrow
|
||||||
|
// CHECK-NEXT: end_borrow
|
||||||
// CHECK-NEXT: destroy_value [[INSTANCE]] : $T
|
// CHECK-NEXT: destroy_value [[INSTANCE]] : $T
|
||||||
// CHECK-NEXT: tuple ()
|
// CHECK-NEXT: tuple ()
|
||||||
// CHECK-NEXT: return
|
// CHECK-NEXT: return
|
||||||
|
|||||||
@@ -1411,34 +1411,3 @@ bb5(%16 : @reborrow $FakeOptional<Klass>, %17 : @reborrow $FakeOptional<Klass>):
|
|||||||
return %23
|
return %23
|
||||||
}
|
}
|
||||||
|
|
||||||
struct String {
|
|
||||||
var guts: Builtin.AnyObject
|
|
||||||
}
|
|
||||||
|
|
||||||
sil [_semantics "string.makeUTF8"] [ossa] @makeString : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> @owned String
|
|
||||||
|
|
||||||
// CHECK-LABEL: sil [ossa] @uncompletedDeadStrings
|
|
||||||
// CHECK-NOT: apply
|
|
||||||
// CHECK-LABEL: } // end sil function 'uncompletedDeadStrings'
|
|
||||||
sil [ossa] @uncompletedDeadStrings : $@convention(thin) () -> () {
|
|
||||||
%first_ptr = string_literal utf8 "first"
|
|
||||||
%first_len = integer_literal $Builtin.Word, 5
|
|
||||||
%makeString = function_ref @makeString : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> @owned String
|
|
||||||
%first = apply %makeString(%first_ptr, %first_len) : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> @owned String
|
|
||||||
cond_br undef, nope, yep
|
|
||||||
|
|
||||||
nope:
|
|
||||||
destroy_value %first
|
|
||||||
%second_ptr = string_literal utf8 "second"
|
|
||||||
%second_len = integer_literal $Builtin.Word, 6
|
|
||||||
%second = apply %makeString(%second_ptr, %second_len) : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> @owned String
|
|
||||||
br this(%second)
|
|
||||||
|
|
||||||
yep:
|
|
||||||
br this(%first)
|
|
||||||
|
|
||||||
this(%string : @owned $String):
|
|
||||||
destroy_value %string
|
|
||||||
%retval = tuple ()
|
|
||||||
return %retval
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -445,12 +445,8 @@ bb0(%0 : @owned $MO):
|
|||||||
return %63 : $()
|
return %63 : $()
|
||||||
}
|
}
|
||||||
|
|
||||||
// The InstructionDeleter will delete the `load [take]` and insert a
|
|
||||||
// `destroy_addr`. Observe the creation of the new destroy_addr instruction
|
|
||||||
// that occurs when deleting the `load [take]` and mark it live. Prevents a
|
|
||||||
// leak.
|
|
||||||
// CHECK-LABEL: sil [ossa] @keep_new_destroy_addr : {{.*}} {
|
// CHECK-LABEL: sil [ossa] @keep_new_destroy_addr : {{.*}} {
|
||||||
// CHECK: destroy_addr
|
// CHECK: load [take]
|
||||||
// CHECK-LABEL: } // end sil function 'keep_new_destroy_addr'
|
// CHECK-LABEL: } // end sil function 'keep_new_destroy_addr'
|
||||||
sil [ossa] @keep_new_destroy_addr : $@convention(thin) () -> () {
|
sil [ossa] @keep_new_destroy_addr : $@convention(thin) () -> () {
|
||||||
bb0:
|
bb0:
|
||||||
|
|||||||
@@ -34,7 +34,9 @@ bb0(%0 : @owned $FileDescriptor):
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CHECK-LABEL: sil hidden [ossa] @fd_deinit2 :
|
// CHECK-LABEL: sil hidden [ossa] @fd_deinit2 :
|
||||||
// CHECK: end_lifetime
|
// CHECK: %1 = drop_deinit
|
||||||
|
// CHECK-NEXT: %2 = destructure_struct %1
|
||||||
|
// CHECK-NEXT: debug_value
|
||||||
// CHECK-LABEL: } // end sil function 'fd_deinit2'
|
// CHECK-LABEL: } // end sil function 'fd_deinit2'
|
||||||
sil hidden [ossa] @fd_deinit2 : $@convention(method) (@owned FileDescriptor) -> () {
|
sil hidden [ossa] @fd_deinit2 : $@convention(method) (@owned FileDescriptor) -> () {
|
||||||
bb0(%0 : @owned $FileDescriptor):
|
bb0(%0 : @owned $FileDescriptor):
|
||||||
|
|||||||
@@ -165,7 +165,8 @@ bb0(%0 : @owned $Builtin.NativeObject, %1 : $*Builtin.NativeObject):
|
|||||||
// CHECK: bb0([[ARG0:%.*]] : @owned $Builtin.NativeObject, [[ARG1:%.*]] : $*Builtin.NativeObject):
|
// CHECK: bb0([[ARG0:%.*]] : @owned $Builtin.NativeObject, [[ARG1:%.*]] : $*Builtin.NativeObject):
|
||||||
// CHECK-NOT: alloc_stack
|
// CHECK-NOT: alloc_stack
|
||||||
// CHECK: destroy_value [[ARG0]]
|
// CHECK: destroy_value [[ARG0]]
|
||||||
// CHECK: destroy_addr [[ARG1]]
|
// CHECK: [[L:%.*]] = load [take] [[ARG1]]
|
||||||
|
// CHECK: destroy_value [[L]]
|
||||||
// CHECK: } // end sil function 'simple_init_take'
|
// CHECK: } // end sil function 'simple_init_take'
|
||||||
sil [ossa] @simple_init_take : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
|
sil [ossa] @simple_init_take : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
|
||||||
bb0(%0 : @owned $Builtin.NativeObject, %1 : $*Builtin.NativeObject):
|
bb0(%0 : @owned $Builtin.NativeObject, %1 : $*Builtin.NativeObject):
|
||||||
|
|||||||
@@ -283,9 +283,9 @@ bb0(%0 : $*X3, %1 : @guaranteed $Builtin.NativeObject):
|
|||||||
//
|
//
|
||||||
// CHECK-LABEL: sil [ossa] @testDestructureTupleNoCrash : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.NativeObject)) -> () {
|
// CHECK-LABEL: sil [ossa] @testDestructureTupleNoCrash : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.NativeObject)) -> () {
|
||||||
// CHECKOPT: bb0(
|
// CHECKOPT: bb0(
|
||||||
// CHECKOPT-NEXT: destroy_value
|
// CHECKOPT-NEXT: (%1, %2) = destructure_tuple
|
||||||
// CHECKOPT-NEXT: tuple
|
// CHECKOPT: destroy_value %2
|
||||||
// CHECKOPT-NEXT: return
|
// CHECKOPT-NEXT: destroy_value %1
|
||||||
// CHECK: } // end sil function 'testDestructureTupleNoCrash'
|
// CHECK: } // end sil function 'testDestructureTupleNoCrash'
|
||||||
sil [ossa] @testDestructureTupleNoCrash : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.NativeObject)) -> () {
|
sil [ossa] @testDestructureTupleNoCrash : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.NativeObject)) -> () {
|
||||||
bb0(%0 : @owned $(Builtin.NativeObject, Builtin.NativeObject)):
|
bb0(%0 : @owned $(Builtin.NativeObject, Builtin.NativeObject)):
|
||||||
|
|||||||
Reference in New Issue
Block a user