Skip to content

Commit ec71713

Browse files
committed
[ownership] Teach CanonicalizeInstruction how to eliminate trivial copies/borrows.
I am going to be using in inst-simplify/sil-combine/canonicalize instruction a RAUW everything against everything API (*). This creates some extra ARC traffic/borrows. It is going to be useful to have some simple peepholes that gets rid of some of the extraneous traffic. (*) Noting that we are not going to support replacing non-trivial OwnershipKind::None values with non-trivial OwnershipKind::* values. This is a corner case that only comes up with non-trivial enums that have a non-payloaded or trivial enum case. It is much more complex to implement that transform, but it is an edge case, so we are just not going to support those for now. ---- I also eliminated the dependence of SILGenCleanup on Swift/SwiftShims. This speeds up iterating on the test case with a debug compiler since we don't need those modules.
1 parent b13a8e9 commit ec71713

File tree

7 files changed

+134
-59
lines changed

7 files changed

+134
-59
lines changed

lib/SILOptimizer/Utils/CanonicalizeInstruction.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,65 @@ broadenSingleElementStores(StoreInst *storeInst,
383383
return killInstruction(storeInst, nextII, pass);
384384
}
385385

386+
//===----------------------------------------------------------------------===//
387+
// Simple ARC Peepholes
388+
//===----------------------------------------------------------------------===//
389+
390+
static SILBasicBlock::iterator
391+
eliminateSimpleCopies(CopyValueInst *cvi, CanonicalizeInstruction &pass) {
392+
auto next = std::next(cvi->getIterator());
393+
394+
// Eliminate copies that only have destroy_value uses.
395+
SmallVector<DestroyValueInst *, 8> destroys;
396+
for (auto *use : getNonDebugUses(cvi)) {
397+
if (auto *dvi = dyn_cast<DestroyValueInst>(use->getUser())) {
398+
destroys.push_back(dvi);
399+
continue;
400+
}
401+
return next;
402+
}
403+
404+
while (!destroys.empty()) {
405+
next = killInstruction(destroys.pop_back_val(), next, pass);
406+
}
407+
408+
next = killInstAndIncidentalUses(cvi, next, pass);
409+
return next;
410+
}
411+
412+
static SILBasicBlock::iterator
413+
eliminateSimpleBorrows(BeginBorrowInst *bbi, CanonicalizeInstruction &pass) {
414+
auto next = std::next(bbi->getIterator());
415+
416+
// We know that our borrow is completely within the lifetime of its base value
417+
// if the borrow is never reborrowed. We check for reborrows and do not
418+
// optimize such cases. Otherwise, we can eliminate our borrow and instead use
419+
// our operand.
420+
auto base = bbi->getOperand();
421+
auto baseOwnership = base.getOwnershipKind();
422+
SmallVector<EndBorrowInst *, 8> endBorrows;
423+
for (auto *use : getNonDebugUses(bbi)) {
424+
if (auto *ebi = dyn_cast<EndBorrowInst>(use->getUser())) {
425+
endBorrows.push_back(ebi);
426+
continue;
427+
}
428+
429+
// Otherwise, if we have a use that is non-lifetime ending and can accept
430+
// our base ownership, continue.
431+
if (!use->isLifetimeEnding() && use->canAcceptKind(baseOwnership))
432+
continue;
433+
434+
return next;
435+
}
436+
437+
while (!endBorrows.empty()) {
438+
next = killInstruction(endBorrows.pop_back_val(), next, pass);
439+
}
440+
bbi->replaceAllUsesWith(base);
441+
pass.notifyHasNewUsers(base);
442+
return killInstruction(bbi, next, pass);
443+
}
444+
386445
//===----------------------------------------------------------------------===//
387446
// Top-Level Entry Point
388447
//===----------------------------------------------------------------------===//
@@ -398,6 +457,12 @@ CanonicalizeInstruction::canonicalize(SILInstruction *inst) {
398457
if (auto *storeInst = dyn_cast<StoreInst>(inst))
399458
return broadenSingleElementStores(storeInst, *this);
400459

460+
if (auto *cvi = dyn_cast<CopyValueInst>(inst))
461+
return eliminateSimpleCopies(cvi, *this);
462+
463+
if (auto *bbi = dyn_cast<BeginBorrowInst>(inst))
464+
return eliminateSimpleBorrows(bbi, *this);
465+
401466
// Skip ahead.
402467
return std::next(inst->getIterator());
403468
}

test/AutoDiff/SILOptimizer/activity_analysis.swift

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -347,31 +347,29 @@ func testArrayUninitializedIntrinsicNested(_ x: Float, _ y: Float) -> [Float] {
347347
// CHECK: [VARIED] %11 = integer_literal $Builtin.Word, 1
348348
// CHECK: [ACTIVE] %12 = index_addr %9 : $*Float, %11 : $Builtin.Word
349349
// CHECK: [NONE] // function_ref _finalizeUninitializedArray<A>(_:)
350-
// CHECK: [ACTIVE] %15 = apply %14<Float>(%7) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0>
350+
// CHECK: [ACTIVE] [[ARRAY:%.*]] = apply %14<Float>(%7) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0>
351351
// CHECK: [USEFUL] %17 = integer_literal $Builtin.Word, 2
352352
// CHECK: [NONE] // function_ref _allocateUninitializedArray<A>(_:)
353353
// CHECK: [ACTIVE] %19 = apply %18<Float>(%17) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer)
354354
// CHECK: [ACTIVE] (**%20**, %21) = destructure_tuple %19 : $(Array<Float>, Builtin.RawPointer)
355355
// CHECK: [VARIED] (%20, **%21**) = destructure_tuple %19 : $(Array<Float>, Builtin.RawPointer)
356356
// CHECK: [ACTIVE] %22 = pointer_to_address %21 : $Builtin.RawPointer to [strict] $*Float
357-
// CHECK: [ACTIVE] %23 = begin_borrow %15 : $Array<Float>
358-
// CHECK: [USEFUL] %24 = integer_literal $Builtin.IntLiteral, 0
359-
// CHECK: [USEFUL] %25 = metatype $@thin Int.Type
357+
// CHECK: [USEFUL] %23 = integer_literal $Builtin.IntLiteral, 0
358+
// CHECK: [USEFUL] %24 = metatype $@thin Int.Type
360359
// CHECK: [NONE] // function_ref Int.init(_builtinIntegerLiteral:)
361-
// CHECK: [USEFUL] %27 = apply %26(%24, %25) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
360+
// CHECK: [USEFUL] %26 = apply %25(%23, %24) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
362361
// CHECK: [NONE] // function_ref Array.subscript.getter
363-
// CHECK: [NONE] %29 = apply %28<Float>(%22, %27, %23) : $@convention(method) <τ_0_0> (Int, @guaranteed Array<τ_0_0>) -> @out τ_0_0
364-
// CHECK: [VARIED] %30 = integer_literal $Builtin.Word, 1
365-
// CHECK: [ACTIVE] %31 = index_addr %22 : $*Float, %30 : $Builtin.Word
366-
// CHECK: [ACTIVE] %32 = begin_borrow %15 : $Array<Float>
367-
// CHECK: [USEFUL] %33 = integer_literal $Builtin.IntLiteral, 1
368-
// CHECK: [USEFUL] %34 = metatype $@thin Int.Type
362+
// CHECK: [NONE] %28 = apply %27<Float>(%22, %26, %15) : $@convention(method) <τ_0_0> (Int, @guaranteed Array<τ_0_0>) -> @out τ_0_0
363+
// CHECK: [VARIED] %29 = integer_literal $Builtin.Word, 1
364+
// CHECK: [ACTIVE] %30 = index_addr %22 : $*Float, %29 : $Builtin.Word
365+
// CHECK: [USEFUL] %31 = integer_literal $Builtin.IntLiteral, 1
366+
// CHECK: [USEFUL] %32 = metatype $@thin Int.Type
369367
// CHECK: [NONE] // function_ref Int.init(_builtinIntegerLiteral:)
370-
// CHECK: [USEFUL] %36 = apply %35(%33, %34) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
368+
// CHECK: [USEFUL] %34 = apply %33(%31, %32) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
371369
// CHECK: [NONE] // function_ref Array.subscript.getter
372-
// CHECK: [NONE] %38 = apply %37<Float>(%31, %36, %32) : $@convention(method) <τ_0_0> (Int, @guaranteed Array<τ_0_0>) -> @out τ_0_0
370+
// CHECK: [NONE] %36 = apply %35<Float>(%30, %34, %15) : $@convention(method) <τ_0_0> (Int, @guaranteed Array<τ_0_0>) -> @out τ_0_0
373371
// CHECK: [NONE] // function_ref _finalizeUninitializedArray<A>(_:)
374-
// CHECK: [ACTIVE] %40 = apply %39<Float>(%20) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0>
372+
// CHECK: [ACTIVE] %38 = apply %37<Float>(%20) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0>
375373

376374
// TF-978: Test array literal initialized with `apply` indirect results.
377375
struct Wrapper<T: Differentiable>: Differentiable {
@@ -733,16 +731,13 @@ func testClassModifyAccessor(_ c: inout C) {
733731
// CHECK: [VARIED] %4 = load [copy] %3 : $*C
734732
// CHECK: [ACTIVE] %6 = begin_access [read] [static] %0 : $*C
735733
// CHECK: [VARIED] %7 = load [copy] %6 : $*C
736-
// CHECK: [VARIED] %9 = begin_borrow %7 : $C
737-
// CHECK: [VARIED] %10 = class_method %9 : $C, #C.float!getter : (C) -> () -> Float, $@convention(method) (@guaranteed C) -> Float
738-
// CHECK: [VARIED] %11 = apply %10(%9) : $@convention(method) (@guaranteed C) -> Float
739-
// CHECK: [VARIED] %14 = begin_borrow %4 : $C
740-
// CHECK: [VARIED] %15 = class_method %14 : $C, #C.float!modify : (C) -> () -> (), $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
741-
// CHECK: [VARIED] (**%16**, %17) = begin_apply %15(%14) : $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
742-
// CHECK: [VARIED] (%16, **%17**) = begin_apply %15(%14) : $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
734+
// CHECK: [VARIED] %9 = class_method %7 : $C, #C.float!getter : (C) -> () -> Float, $@convention(method) (@guaranteed C) -> Float
735+
// CHECK: [VARIED] %10 = apply %9(%7) : $@convention(method) (@guaranteed C) -> Float
736+
// CHECK: [VARIED] %12 = class_method %4 : $C, #C.float!modify : (C) -> () -> (), $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
737+
// CHECK: [VARIED] (**%13**, %14) = begin_apply %12(%4) : $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
738+
// CHECK: [VARIED] (%13, **%14**) = begin_apply %12(%4) : $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
743739
// CHECK: [NONE] // function_ref static Float.*= infix(_:_:)
744-
// CHECK: [NONE] %19 = apply %18(%16, %11, %2) : $@convention(method) (@inout Float, Float, @thin Float.Type) -> ()
745-
// CHECK: [NONE] %23 = tuple ()
740+
// CHECK: [NONE] %16 = apply %15(%13, %10, %2) : $@convention(method) (@inout Float, Float, @thin Float.Type) -> ()
746741

747742
//===----------------------------------------------------------------------===//
748743
// Enum differentiation

test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ func modify(_ s: Struct, _ x: Float) -> Float {
714714
func tupleArrayLiteralInitialization(_ x: Float, _ y: Float) -> Float {
715715
// `Array<(Float, Float)>` does not conform to `Differentiable`.
716716
let array = [(x * y, x * y)]
717-
// expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{10-10=withoutDerivative(at: }} {{15-15=)}}
717+
// expected-note @-1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{15-15=withoutDerivative(at: }} {{31-31=)}}
718718
return array[0].0
719719
}
720720

test/IRGen/alloc_box.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -primary-file %s -emit-ir -o - | %FileCheck %s
1+
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass=SILGenCleanup -primary-file %s -emit-ir -o - | %FileCheck %s
22

33
func f() -> Bool? { return nil }
44

test/SILOptimizer/capturepromotion-wrong-lexicalscope.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
// CHECK: destroy_value %7 : ${ var Int }, loc {{.*}}:33:11, scope 3
2020
// CHECK: %13 = partial_apply [callee_guaranteed] %10(%11) : $@convention(thin) (Int) -> Int, loc {{.*}}:33:11, scope 3
2121
// CHECK: debug_value %13 : $@callee_guaranteed () -> Int, let, name "f", loc {{.*}}:33:7, scope 3
22-
// CHECK: %15 = begin_borrow %13 : $@callee_guaranteed () -> Int, loc {{.*}}:34:10, scope 3
23-
// CHECK: %16 = copy_value %15 : $@callee_guaranteed () -> Int, loc {{.*}}:34:10, scope 3
24-
// CHECK: end_borrow %15 : $@callee_guaranteed () -> Int
22+
// There used to be a begin_borrow here. We leave an emptyline here to preserve line numbers.
23+
// CHECK: %15 = copy_value %13 : $@callee_guaranteed () -> Int, loc {{.*}}:34:10, scope 3
24+
// There used to be an end_borrow here. We leave an emptyline here to preserve line numbers.
2525
// CHECK: destroy_value %13 : $@callee_guaranteed () -> Int, loc {{.*}}:35:1, scope 3
2626
// CHECK: destroy_value %0 : ${ var Int }, loc {{.*}}:35:1, scope 3
27-
// CHECK: return %16 : $@callee_guaranteed () -> Int, loc {{.*}}:34:3, scope 3
27+
// CHECK: return %15 : $@callee_guaranteed () -> Int, loc {{.*}}:34:3, scope 3
2828
// CHECK: }
2929

3030

test/SILOptimizer/constantprop-wrongscope.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// instructions surrounding it.
1414

1515
// CHECK: destroy_addr %7 : $*Any, loc {{.*}}:22:19, scope 2
16-
// CHECK: dealloc_stack %13 : $*Optional<Any>, loc {{.*}}:22:23, scope 2
16+
// CHECK: dealloc_stack %12 : $*Optional<Any>, loc {{.*}}:22:23, scope 2
1717
// CHECK: dealloc_stack %7 : $*Any, loc {{.*}}:22:23, scope 2
1818
// CHECK: dealloc_stack %6 : $*A, loc {{.*}}:22:7, scope 2
1919

test/SILOptimizer/silgen_cleanup.sil

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,27 @@ import Builtin
44

55
sil_stage raw
66

7-
import Swift
8-
import SwiftShims
7+
class Klass {}
8+
class SubKlass : Klass {}
9+
10+
sil @use_klass_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
11+
sil @use_klass_owned : $@convention(thin) (@owned Klass) -> ()
12+
sil @use_klass_unowned : $@convention(thin) (Klass) -> ()
13+
14+
enum FakeOptional<T> {
15+
case none
16+
case some(T)
17+
}
18+
19+
sil @use_fakeoptional_klass_guaranteed : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
20+
21+
struct Int {
22+
var _value : Builtin.Int32
23+
}
24+
25+
struct UInt8 {
26+
var _value : Builtin.Int8
27+
}
928

1029
// CHECK-LABEL: sil [ossa] @struct_extract_load_to_load_struct_element_addr
1130
// CHECK: bb0([[IN:%[0-9]+]] : $*UInt8):
@@ -91,30 +110,26 @@ bb0(%0 : $*(Builtin.Int8, Builtin.Int8)):
91110

92111
struct X1 {
93112
@_hasStorage @_hasInitialValue let a: Int { get }
94-
@_hasStorage @_hasInitialValue var obj1: AnyObject { get set }
95-
@_hasStorage @_hasInitialValue var obj2: AnyObject { get set }
96-
init(a: Int, obj1: AnyObject, obj2: AnyObject)
113+
@_hasStorage @_hasInitialValue var obj1: Builtin.NativeObject { get set }
114+
@_hasStorage @_hasInitialValue var obj2: Builtin.NativeObject { get set }
115+
init(a: Int, obj1: Builtin.NativeObject, obj2: Builtin.NativeObject)
97116
}
98117

99-
// CHECK-LABEL: sil private [ossa] @testLoadNontrivial : $@convention(thin) (@inout_aliasable X1) -> (Int, @owned AnyObject, @owned AnyObject) {
118+
// CHECK-LABEL: sil private [ossa] @testLoadNontrivial : $@convention(thin) (@inout_aliasable X1) -> (Int, @owned Builtin.NativeObject, @owned Builtin.NativeObject) {
100119
// CHECK-LABEL: bb0(%0 : $*X1):
101120
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] %0 : $*X1
102121
// CHECK: [[AA:%.*]] = struct_element_addr [[ACCESS]] : $*X1, #X1.a
103122
// CHECK: load [trivial] [[AA]] : $*Int
104123
// CHECK: [[OA1:%.*]] = struct_element_addr [[ACCESS]] : $*X1, #X1.obj1
105-
// CHECK: [[OV1:%.*]] = load [copy] [[OA1]] : $*AnyObject
124+
// CHECK: [[OV1:%.*]] = load [copy] [[OA1]] : $*Builtin.NativeObject
106125
// CHECK: [[OA2:%.*]] = struct_element_addr [[ACCESS]] : $*X1, #X1.obj2
107-
// CHECK: [[OV2:%.*]] = load [copy] [[OA2]] : $*AnyObject
126+
// CHECK: [[OV2:%.*]] = load [copy] [[OA2]] : $*Builtin.NativeObject
108127
// CHECK: end_access [[ACCESS]] : $*X1
109-
// CHECK: [[B1:%.*]] = begin_borrow [[OV1]] : $AnyObject
110-
// CHECK: copy_value [[B1]] : $AnyObject
111-
// CHECK: end_borrow [[B1]] : $AnyObject
112-
// CHECK: [[B2:%.*]] = begin_borrow [[OV2]] : $AnyObject
113-
// CHECK: copy_value [[B2]] : $AnyObject
114-
// CHECK: end_borrow [[B2]] : $AnyObject
128+
// CHECK: copy_value [[OV1]] : $Builtin.NativeObject
129+
// CHECK: copy_value [[OV2]] : $Builtin.NativeObject
115130
// CHECK: return
116131
// CHECK-LABEL: } // end sil function 'testLoadNontrivial'
117-
sil private [ossa] @testLoadNontrivial : $@convention(thin) (@inout_aliasable X1) -> (Int, @owned AnyObject, @owned AnyObject) {
132+
sil private [ossa] @testLoadNontrivial : $@convention(thin) (@inout_aliasable X1) -> (Int, @owned Builtin.NativeObject, @owned Builtin.NativeObject) {
118133
bb0(%0 : $*X1):
119134
%access = begin_access [read] [unknown] %0 : $*X1
120135
%load = load [copy] %access : $*X1
@@ -126,44 +141,44 @@ bb0(%0 : $*X1):
126141

127142
%borrow1 = begin_borrow %load : $X1
128143
%o1 = struct_extract %borrow1 : $X1, #X1.obj1
129-
%copy1 = copy_value %o1 : $AnyObject
144+
%copy1 = copy_value %o1 : $Builtin.NativeObject
130145
end_borrow %borrow1 : $X1
131146

132147
%borrow2 = begin_borrow %load : $X1
133148
%o2 = struct_extract %borrow2 : $X1, #X1.obj2
134-
%copy2 = copy_value %o2 : $AnyObject
149+
%copy2 = copy_value %o2 : $Builtin.NativeObject
135150
end_borrow %borrow2 : $X1
136151

137152
destroy_value %load : $X1
138153

139-
%result = tuple (%a : $Int, %copy1 : $AnyObject, %copy2 : $AnyObject)
140-
return %result : $(Int, AnyObject, AnyObject)
154+
%result = tuple (%a : $Int, %copy1 : $Builtin.NativeObject, %copy2 : $Builtin.NativeObject)
155+
return %result : $(Int, Builtin.NativeObject, Builtin.NativeObject)
141156
}
142157

143158
struct X2 {
144-
@_hasStorage @_hasInitialValue var obj: AnyObject { get set }
159+
@_hasStorage @_hasInitialValue var obj: Builtin.NativeObject { get set }
145160
}
146161

147162
struct X3 {
148163
@_hasStorage @_hasInitialValue var x2: X2 { get set }
149164
}
150165

151-
// CHECK-LABEL: sil private [ossa] @testStoreNontrivial : $@convention(thin) (@inout X3, @guaranteed AnyObject) -> () {
152-
// CHECK-LABEL: bb0(%0 : $*X3, %1 : @guaranteed $AnyObject):
153-
// CHECK: [[CP:%.*]] = copy_value %1 : $AnyObject
166+
// CHECK-LABEL: sil private [ossa] @testStoreNontrivial : $@convention(thin) (@inout X3, @guaranteed Builtin.NativeObject) -> () {
167+
// CHECK: bb0(%0 : $*X3, %1 : @guaranteed $Builtin.NativeObject):
168+
// CHECK: [[CP:%.*]] = copy_value %1 : $Builtin.NativeObject
154169
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] %0 : $*X3
155-
// CHECK: [[X2:%.*]] = struct $X2 ([[CP]] : $AnyObject)
170+
// CHECK: [[X2:%.*]] = struct $X2 ([[CP]] : $Builtin.NativeObject)
156171
// CHECK: [[X3:%.*]] = struct $X3 ([[X2]] : $X2)
157172
// CHECK: store [[X3]] to [assign] [[ACCESS]] : $*X3
158173
// CHECK: end_access [[ACCESS]] : $*X3
159-
// CHECK-LABEL: } // end sil function 'testStoreNontrivial'
160-
sil private [ossa] @testStoreNontrivial : $@convention(thin) (@inout X3, @guaranteed AnyObject) -> () {
161-
bb0(%0 : $*X3, %1 : @guaranteed $AnyObject):
162-
%4 = copy_value %1 : $AnyObject
174+
// CHECK: } // end sil function 'testStoreNontrivial'
175+
sil private [ossa] @testStoreNontrivial : $@convention(thin) (@inout X3, @guaranteed Builtin.NativeObject) -> () {
176+
bb0(%0 : $*X3, %1 : @guaranteed $Builtin.NativeObject):
177+
%4 = copy_value %1 : $Builtin.NativeObject
163178
%5 = begin_access [modify] [unknown] %0 : $*X3
164179
%6 = struct_element_addr %5 : $*X3, #X3.x2
165180
%7 = struct_element_addr %6 : $*X2, #X2.obj
166-
store %4 to [assign] %7 : $*AnyObject
181+
store %4 to [assign] %7 : $*Builtin.NativeObject
167182
end_access %5 : $*X3
168183
%12 = tuple ()
169184
return %12 : $()

0 commit comments

Comments
 (0)