diff --git a/lib/SIL/SILValue.cpp b/lib/SIL/SILValue.cpp index 60523507c8fa8..22954df5b4b9b 100644 --- a/lib/SIL/SILValue.cpp +++ b/lib/SIL/SILValue.cpp @@ -205,6 +205,7 @@ void Operand::hoistAddressProjections(SILInstruction *InsertBefore, DominanceInfo *DomTree) { SILValue V = get(); SILInstruction *Prev = nullptr; + auto *InsertPt = InsertBefore; while (true) { SILValue Incoming = stripSinglePredecessorArgs(V); @@ -214,11 +215,13 @@ void Operand::hoistAddressProjections(SILInstruction *InsertBefore, // If we are the operand itself set the operand to the incoming // arugment. set(Incoming); + V = Incoming; } else { // Otherwise, set the previous projections operand to the incoming // argument. assert(Prev && "Must have seen a projection"); Prev->setOperand(0, Incoming); + V = Incoming; } } @@ -234,7 +237,8 @@ void Operand::hoistAddressProjections(SILInstruction *InsertBefore, // Move the current projection and memorize it for the next iteration. Prev = Inst; - Inst->moveBefore(InsertBefore); + Inst->moveBefore(InsertPt); + InsertPt = Inst; V = Inst->getOperand(0); continue; } diff --git a/test/SILPasses/cowarray_opt.sil b/test/SILPasses/cowarray_opt.sil index 98fc2a470da22..0c0589e1250c9 100644 --- a/test/SILPasses/cowarray_opt.sil +++ b/test/SILPasses/cowarray_opt.sil @@ -27,6 +27,14 @@ class MyArrayContainer { deinit } +struct Container { + var array: MyArray +} + +struct ContainerContainer { + var container: Container +} + sil [_semantics "array.make_mutable"] @array_make_mutable : $@convention(method) (@inout MyArray) -> () sil [_semantics "array.get_count"] @guaranteed_array_get_count : $@convention(method) (@guaranteed MyArray) -> Int sil [_semantics "array.get_capacity"] @guaranteed_array_get_capacity : $@convention(method) (@guaranteed MyArray) -> Int @@ -1013,3 +1021,84 @@ bb6(%23 : $Builtin.Int64): %73 = apply %72() : $@convention(thin) () -> () cond_br undef, bb5, bb6(%26 : $Builtin.Int64) } + +// CHECK-LABEL: sil @hoist_projections +// CHECK: bb0([[CONTAINER:%[0-9]+]] +// CHECK: [[CONTAINER2:%.*]] = struct_element_addr [[CONTAINER]] : $*ContainerContainer +// CHECK: [[ARRAY:%.*]] = struct_element_addr [[CONTAINER2]] : $*Container, +// CHECK: [[FUN:%[0-9]+]] = function_ref @array_make_mutable +// CHECK: apply [[FUN]]([[ARRAY]] +// CHECK: bb1 +// CHECK-NOT: array_make_mutable +// CHECK-NOT: apply [[FUN]] +sil @hoist_projections : $@convention(thin) (@inout ContainerContainer, @inout Builtin.Int1) -> () { +bb0(%0 : $*ContainerContainer, %1 : $*Builtin.Int1): + br bb1 + +bb1: + %2 = struct_element_addr %0 : $*ContainerContainer, #ContainerContainer.container + br bb3(%2 : $*Container) + +bb3(%3: $*Container): + %4 = struct_element_addr %3 : $*Container, #Container.array + %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () + %6 = apply %5(%4) : $@convention(method) (@inout MyArray) -> () + cond_br undef, bb1, bb2 + +bb2: + %7 = tuple() + return %7 : $() +} + +// CHECK-LABEL: sil @hoist_projections2 +// CHECK: bb0([[CONTAINER:%[0-9]+]] +// CHECK: [[CONTAINER2:%.*]] = struct_element_addr [[CONTAINER]] : $*ContainerContainer +// CHECK: [[ARRAY:%.*]] = struct_element_addr [[CONTAINER2]] : $*Container, +// CHECK: [[FUN:%[0-9]+]] = function_ref @array_make_mutable +// CHECK: apply [[FUN]]([[ARRAY]] +// CHECK: bb1 +// CHECK-NOT: array_make_mutable +// CHECK-NOT: apply [[FUN]] +sil @hoist_projections2 : $@convention(thin) (@inout ContainerContainer, @inout Builtin.Int1) -> () { +bb0(%0 : $*ContainerContainer, %1 : $*Builtin.Int1): + br bb1 + +bb1: + %2 = struct_element_addr %0 : $*ContainerContainer, #ContainerContainer.container + %3 = struct_element_addr %2 : $*Container, #Container.array + br bb3(%3 : $*MyArray) + +bb3(%4 : $*MyArray): + %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () + %6 = apply %5(%4) : $@convention(method) (@inout MyArray) -> () + cond_br undef, bb1, bb2 + +bb2: + %7 = tuple() + return %7 : $() +} + +// CHECK-LABEL: sil @hoist_projections3 +// CHECK: bb0([[CONTAINER:%[0-9]+]] +// CHECK: [[CONTAINER2:%.*]] = struct_element_addr [[CONTAINER]] : $*ContainerContainer +// CHECK: [[ARRAY:%.*]] = struct_element_addr [[CONTAINER2]] : $*Container, +// CHECK: [[FUN:%[0-9]+]] = function_ref @array_make_mutable +// CHECK: apply [[FUN]]([[ARRAY]] +// CHECK: bb1 +// CHECK-NOT: array_make_mutable +// CHECK-NOT: apply [[FUN]] +sil @hoist_projections3 : $@convention(thin) (@inout ContainerContainer, @inout Builtin.Int1) -> () { +bb0(%0 : $*ContainerContainer, %1 : $*Builtin.Int1): + br bb1 + +bb1: + %2 = struct_element_addr %0 : $*ContainerContainer, #ContainerContainer.container + %3 = struct_element_addr %2 : $*Container, #Container.array + %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () + %6 = apply %5(%3) : $@convention(method) (@inout MyArray) -> () + cond_br undef, bb1, bb2 + +bb2: + %7 = tuple() + return %7 : $() +}