Skip to content

Commit 8bb3e45

Browse files
committed
WalkUtils: more precise handling of existential projections and index_addr
1 parent 0d3fe63 commit 8bb3e45

File tree

4 files changed

+136
-24
lines changed

4 files changed

+136
-24
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeUtils.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -489,9 +489,6 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
489489
return walkDownUses(ofValue: svi, path: path.with(knownType: nil))
490490
case let atp as AddressToPointerInst:
491491
return walkDownUses(ofValue: atp, path: path.with(knownType: nil))
492-
case let ia as IndexAddrInst:
493-
assert(operand.index == 0)
494-
return walkDownUses(ofAddress: ia, path: path.with(knownType: nil))
495492
case is DeallocStackInst, is InjectEnumAddrInst, is FixLifetimeInst, is EndBorrowInst, is EndAccessInst,
496493
is DebugValueInst:
497494
return .continueWalk
@@ -741,7 +738,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
741738
} else {
742739
return isEscaping
743740
}
744-
case is PointerToAddressInst, is IndexAddrInst:
741+
case is PointerToAddressInst:
745742
return walkUp(value: (def as! SingleValueInstruction).operands[0].value, path: path.with(knownType: nil))
746743
case let rta as RefTailAddrInst:
747744
return walkUp(value: rta.instance, path: path.push(.tailElements, index: 0).with(knownType: nil))

SwiftCompilerSources/Sources/Optimizer/Utilities/WalkUtils.swift

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,15 @@ extension ValueDefUseWalker {
340340
} else {
341341
return unmatchedPath(value: operand, path: path)
342342
}
343-
case is InitExistentialRefInst, is OpenExistentialRefInst,
344-
is BeginBorrowInst, is CopyValueInst, is MoveValueInst,
343+
case let ier as InitExistentialRefInst:
344+
return walkDownUses(ofValue: ier, path: path.push(.existential, index: 0))
345+
case let oer as OpenExistentialRefInst:
346+
if let path = path.popIfMatches(.existential, index: 0) {
347+
return walkDownUses(ofValue: oer, path: path)
348+
} else {
349+
return unmatchedPath(value: operand, path: path)
350+
}
351+
case is BeginBorrowInst, is CopyValueInst, is MoveValueInst,
345352
is UpcastInst, is UncheckedRefCastInst, is EndCOWMutationInst,
346353
is RefToBridgeObjectInst, is BridgeObjectToRefInst, is MarkMustCheckInst:
347354
return walkDownUses(ofValue: (instruction as! SingleValueInstruction), path: path)
@@ -470,14 +477,23 @@ extension AddressDefUseWalker {
470477
} else {
471478
return unmatchedPath(address: operand, path: path)
472479
}
473-
case is InitExistentialAddrInst, is OpenExistentialAddrInst,
474-
is IndexAddrInst, is MarkMustCheckInst:
475-
// FIXME: for now `index_addr` is treated as a forwarding instruction since
476-
// SmallProjectionPath does not track indices.
477-
// This is ok since `index_addr` is eventually preceeded by a `tail_addr`
478-
// which has pushed a `"ct"` component on the path that matches any
479-
// `index_addr` address.
480-
return walkDownUses(ofAddress: instruction as! SingleValueInstruction, path: path)
480+
case is InitExistentialAddrInst, is OpenExistentialAddrInst:
481+
if let path = path.popIfMatches(.existential, index: 0) {
482+
return walkDownUses(ofAddress: instruction as! SingleValueInstruction, path: path)
483+
} else {
484+
return unmatchedPath(address: operand, path: path)
485+
}
486+
case let ia as IndexAddrInst:
487+
if let (pathIdx, subPath) = path.pop(kind: .indexedElement) {
488+
if let idx = ia.constantSmallIndex,
489+
idx == pathIdx {
490+
return walkDownUses(ofAddress: ia, path: subPath)
491+
}
492+
return walkDownUses(ofAddress: ia, path: subPath.push(.anyIndexedElement, index: 0))
493+
}
494+
return walkDownUses(ofAddress: ia, path: path)
495+
case let mmc as MarkMustCheckInst:
496+
return walkDownUses(ofAddress: mmc, path: path)
481497
case let ba as BeginAccessInst:
482498
// Don't treat `end_access` as leaf-use. Just ignore it.
483499
return walkDownNonEndAccessUses(of: ba, path: path)
@@ -630,8 +646,15 @@ extension ValueUseDefWalker {
630646
} else {
631647
return rootDef(value: mvr, path: path)
632648
}
633-
case is InitExistentialRefInst, is OpenExistentialRefInst,
634-
is BeginBorrowInst, is CopyValueInst, is MoveValueInst,
649+
case let ier as InitExistentialRefInst:
650+
if let path = path.popIfMatches(.existential, index: 0) {
651+
return walkUp(value: ier.instance, path: path)
652+
} else {
653+
return unmatchedPath(value: ier, path: path)
654+
}
655+
case let oer as OpenExistentialRefInst:
656+
return walkUp(value: oer.existential, path: path.push(.existential, index: 0))
657+
case is BeginBorrowInst, is CopyValueInst, is MoveValueInst,
635658
is UpcastInst, is UncheckedRefCastInst, is EndCOWMutationInst,
636659
is RefToBridgeObjectInst, is BridgeObjectToRefInst, is MarkMustCheckInst:
637660
return walkUp(value: (def as! Instruction).operands[0].value, path: path)
@@ -718,18 +741,34 @@ extension AddressUseDefWalker {
718741
case is InitEnumDataAddrInst, is UncheckedTakeEnumDataAddrInst:
719742
return walkUp(address: (def as! UnaryInstruction).operand.value,
720743
path: path.push(.enumCase, index: (def as! EnumInstruction).caseIndex))
721-
case is InitExistentialAddrInst, is OpenExistentialAddrInst, is BeginAccessInst, is IndexAddrInst,
722-
is MarkMustCheckInst:
723-
// FIXME: for now `index_addr` is treated as a forwarding instruction since
724-
// SmallProjectionPath does not track indices.
725-
// This is ok since `index_addr` is eventually preceeded by a `tail_addr`
726-
// which has pushed a `"ct"` component on the path that matches any
727-
// `index_addr` address.
744+
case is InitExistentialAddrInst, is OpenExistentialAddrInst:
745+
return walkUp(address: (def as! Instruction).operands[0].value, path: path.push(.existential, index: 0))
746+
case is BeginAccessInst, is MarkMustCheckInst:
728747
return walkUp(address: (def as! Instruction).operands[0].value, path: path)
748+
case let ia as IndexAddrInst:
749+
if let idx = ia.constantSmallIndex {
750+
return walkUp(address: ia.base, path: path.push(.indexedElement, index: idx))
751+
} else {
752+
return walkUp(address: ia.base, path: path.push(.anyIndexedElement, index: 0))
753+
}
729754
case let mdi as MarkDependenceInst:
730755
return walkUp(address: mdi.operands[0].value, path: path)
731756
default:
732757
return rootDef(address: def, path: path)
733758
}
734759
}
735760
}
761+
762+
private extension IndexAddrInst {
763+
var constantSmallIndex: Int? {
764+
guard let literal = index as? IntegerLiteralInst else {
765+
return nil
766+
}
767+
let index = literal.value
768+
if index.isIntN(16) {
769+
return Int(index.getSExtValue())
770+
}
771+
return nil
772+
}
773+
}
774+

test/SILOptimizer/addr_escape_info.sil

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ class XandIntClass {
3131
@_hasStorage var i: Int
3232
}
3333

34+
protocol P {}
35+
36+
extension Int : P {}
37+
3438
sil @no_arguments : $@convention(thin) () -> ()
3539
sil @indirect_argument : $@convention(thin) (@in Int) -> ()
3640
sil @indirect_struct_argument : $@convention(thin) (@in Str) -> ()
@@ -633,3 +637,75 @@ bb0:
633637
return %9 : $Int64
634638
}
635639

640+
// CHECK-LABEL: Address escape information for test_index_addr:
641+
// CHECK: pair 0 - 1
642+
// CHECK-NEXT: %2 = ref_tail_addr %1 : $X, $Int
643+
// CHECK-NEXT: %5 = index_addr %2 : $*Int, %0 : $Builtin.Word
644+
// CHECK-NEXT: may alias
645+
// CHECK: pair 0 - 2
646+
// CHECK-NEXT: %2 = ref_tail_addr %1 : $X, $Int
647+
// CHECK-NEXT: %6 = index_addr %2 : $*Int, %3 : $Builtin.Word
648+
// CHECK-NEXT: may alias
649+
// CHECK: pair 0 - 3
650+
// CHECK-NEXT: %2 = ref_tail_addr %1 : $X, $Int
651+
// CHECK-NEXT: %7 = index_addr %2 : $*Int, %4 : $Builtin.Word
652+
// CHECK-NEXT: may alias
653+
// CHECK: pair 0 - 4
654+
// CHECK-NEXT: %2 = ref_tail_addr %1 : $X, $Int
655+
// CHECK-NEXT: %8 = index_addr %7 : $*Int, %4 : $Builtin.Word
656+
// CHECK-NEXT: may alias
657+
// CHECK: pair 1 - 2
658+
// CHECK-NEXT: %5 = index_addr %2 : $*Int, %0 : $Builtin.Word
659+
// CHECK-NEXT: %6 = index_addr %2 : $*Int, %3 : $Builtin.Word
660+
// CHECK-NEXT: may alias
661+
// CHECK: pair 1 - 3
662+
// CHECK-NEXT: %5 = index_addr %2 : $*Int, %0 : $Builtin.Word
663+
// CHECK-NEXT: %7 = index_addr %2 : $*Int, %4 : $Builtin.Word
664+
// CHECK-NEXT: may alias
665+
// CHECK: pair 1 - 4
666+
// CHECK-NEXT: %5 = index_addr %2 : $*Int, %0 : $Builtin.Word
667+
// CHECK-NEXT: %8 = index_addr %7 : $*Int, %4 : $Builtin.Word
668+
// CHECK-NEXT: may alias
669+
// CHECK: pair 2 - 4
670+
// CHECK-NEXT: %6 = index_addr %2 : $*Int, %3 : $Builtin.Word
671+
// CHECK-NEXT: %8 = index_addr %7 : $*Int, %4 : $Builtin.Word
672+
// CHECK-NEXT: may alias
673+
// CHECK: End function test_index_addr
674+
sil @test_index_addr : $@convention(thin) (Builtin.Word) -> () {
675+
bb0(%0 : $Builtin.Word):
676+
%1 = alloc_ref $X
677+
%2 = ref_tail_addr %1 : $X, $Int
678+
%3 = integer_literal $Builtin.Word, 2
679+
%4 = integer_literal $Builtin.Word, 1
680+
%5 = index_addr %2 : $*Int, %0 : $Builtin.Word
681+
%6 = index_addr %2 : $*Int, %3 : $Builtin.Word
682+
%7 = index_addr %2 : $*Int, %4 : $Builtin.Word
683+
%8 = index_addr %7 : $*Int, %4 : $Builtin.Word
684+
fix_lifetime %2 : $*Int
685+
fix_lifetime %5 : $*Int
686+
fix_lifetime %6 : $*Int
687+
fix_lifetime %7 : $*Int
688+
fix_lifetime %8 : $*Int
689+
%r = tuple ()
690+
return %r : $()
691+
}
692+
693+
// CHECK-LABEL: Address escape information for test_existentials:
694+
// CHECK: pair 0 - 1
695+
// CHECK-NEXT: %2 = init_existential_addr %1 : $*any P, $Int
696+
// CHECK-NEXT: %4 = open_existential_addr immutable_access %1 : $*any P to $*@opened("D2149896-0C4D-11EE-92B7-0EA13E3AABB3", any P) Self
697+
// CHECK-NEXT: may alias
698+
// CHECK: End function test_existentials
699+
sil @test_existentials : $@convention(thin) (Int) -> () {
700+
bb0(%0 : $Int):
701+
%1 = alloc_stack $P
702+
%2 = init_existential_addr %1 : $*P, $Int
703+
store %0 to %2 : $*Int
704+
%4 = open_existential_addr immutable_access %1 : $*any P to $*@opened("D2149896-0C4D-11EE-92B7-0EA13E3AABB3", any P) Self
705+
fix_lifetime %2 : $*Int
706+
fix_lifetime %4 : $*@opened("D2149896-0C4D-11EE-92B7-0EA13E3AABB3", any P) Self
707+
dealloc_stack %1 : $*P
708+
%r = tuple ()
709+
return %r : $()
710+
}
711+

test/SILOptimizer/escape_info.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ bb0:
615615

616616

617617
// CHECK-LABEL: Escape information for test_cast_and_existentials_walk_down:
618-
// CHECK: return[]: %0 = alloc_ref $Derived
618+
// CHECK: return[x]: %0 = alloc_ref $Derived
619619
// CHECK: - : %1 = alloc_ref $Derived
620620
// CHECK: End function test_cast_and_existentials_walk_down
621621
sil @test_cast_and_existentials_walk_down : $@convention(thin) () -> ClassP {

0 commit comments

Comments
 (0)