Skip to content

Commit d2b5bc3

Browse files
committed
[sil-optimizer] Add a small pass that runs after TransferNonSendable and eliminates tuple addr constructor.
This will limit the number of passes that need to be updated to handle tuple_addr_constructor.
1 parent 6a65c78 commit d2b5bc3

File tree

7 files changed

+246
-0
lines changed

7 files changed

+246
-0
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6396,6 +6396,8 @@ class TupleAddrConstructorInst final
63966396
return operand->getOperandNumber() + 1;
63976397
}
63986398

6399+
unsigned getNumElements() const { return getTupleType()->getNumElements(); }
6400+
63996401
TupleType *getTupleType() const {
64006402
return getDest().get()->getType().getRawASTType()->castTo<TupleType>();
64016403
}

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,8 @@ PASS(IRGenPrepare, "irgen-prepare",
369369
"Cleanup SIL in preparation for IRGen")
370370
PASS(TransferNonSendable, "transfer-non-sendable",
371371
"Checks calls that send non-sendable values between isolation domains")
372+
PASS(LowerTupleAddrConstructor, "lower-tuple-addr-constructor",
373+
"Lower tuple addr constructor to tuple_element_addr+copy_addr")
372374
PASS(SILGenCleanup, "silgen-cleanup",
373375
"Cleanup SIL in preparation for diagnostics")
374376
PASS(SILCombine, "sil-combine",

lib/SILOptimizer/Mandatory/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ target_sources(swiftSILOptimizer PRIVATE
4343
RawSILInstLowering.cpp
4444
ReferenceBindingTransform.cpp
4545
TransferNonSendable.cpp
46+
LowerTupleAddrConstructor.cpp
4647
SILGenCleanup.cpp
4748
YieldOnceCheck.cpp
4849
OSLogOptimization.cpp
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//===--- LowerTupleAddrConstructor.cpp ------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/SIL/SILBuilder.h"
14+
#include "swift/SIL/SILFunction.h"
15+
#include "swift/SILOptimizer/PassManager/Transforms.h"
16+
17+
using namespace swift;
18+
19+
//===----------------------------------------------------------------------===//
20+
// MARK: Top Level Entrypoint
21+
//===----------------------------------------------------------------------===//
22+
23+
namespace {
24+
25+
class LowerTupleAddrConstructorTransform : public SILFunctionTransform {
26+
void run() override {
27+
SILFunction *function = getFunction();
28+
29+
// Once we have finished, lower all tuple_addr_constructor that we see.
30+
bool deletedInst = false;
31+
for (auto &block : *function) {
32+
for (auto ii = block.begin(), ie = block.end(); ii != ie;) {
33+
auto *inst = dyn_cast<TupleAddrConstructorInst>(&*ii);
34+
++ii;
35+
36+
if (!inst)
37+
continue;
38+
39+
SILBuilderWithScope builder(inst);
40+
41+
unsigned count = 0;
42+
visitExplodedTupleValue(
43+
inst->getDestValue(),
44+
[&](SILValue value, std::optional<unsigned> index) -> SILValue {
45+
if (!index) {
46+
SILValue elt = inst->getElement(count);
47+
if (elt->getType().isAddress()) {
48+
builder.createCopyAddr(inst->getLoc(), elt, value, IsTake,
49+
inst->isInitializationOfDest());
50+
} else {
51+
builder.emitStoreValueOperation(
52+
inst->getLoc(), elt, value,
53+
bool(inst->isInitializationOfDest())
54+
? StoreOwnershipQualifier::Init
55+
: StoreOwnershipQualifier::Assign);
56+
}
57+
++count;
58+
return value;
59+
}
60+
auto *teai =
61+
builder.createTupleElementAddr(inst->getLoc(), value, *index);
62+
return teai;
63+
});
64+
inst->eraseFromParent();
65+
deletedInst = true;
66+
}
67+
}
68+
69+
if (deletedInst)
70+
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
71+
}
72+
};
73+
74+
} // end anonymous namespace
75+
76+
SILTransform *swift::createLowerTupleAddrConstructor() {
77+
return new LowerTupleAddrConstructorTransform();
78+
}

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/SIL/NodeDatastructures.h"
2222
#include "swift/SIL/OwnershipUtils.h"
2323
#include "swift/SIL/SILBasicBlock.h"
24+
#include "swift/SIL/SILBuilder.h"
2425
#include "swift/SIL/SILFunction.h"
2526
#include "swift/SIL/SILInstruction.h"
2627
#include "swift/SILOptimizer/PassManager/Transforms.h"

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ static void addMandatoryDiagnosticOptPipeline(SILPassPipelinePlan &P) {
134134

135135
P.addFlowIsolation();
136136
P.addTransferNonSendable();
137+
// Lower tuple addr constructor. Eventually this can be merged into later
138+
// passes. This ensures we do not need to update later passes for something
139+
// that is only needed by TransferNonSendable().
140+
P.addLowerTupleAddrConstructor();
137141

138142
// Automatic differentiation: canonicalize all differentiability witnesses
139143
// and `differentiable_function` instructions.
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// RUN: %target-sil-opt -lower-tuple-addr-constructor %s | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
import Swift
7+
8+
// CHECK-LABEL: sil [ossa] @tuple_addr_constructor_init : $@convention(thin) (@in Builtin.NativeObject) -> () {
9+
// CHECK: bb0([[LHS:%.*]] : $*
10+
// CHECK: [[RHS:%.*]] = alloc_stack $Builtin.NativeObject
11+
// CHECK: [[DEST:%.*]] = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
12+
// CHECK: [[LHS_ADDR:%.*]] = tuple_element_addr [[DEST]] : $*(Builtin.NativeObject, Builtin.NativeObject), 0
13+
// CHECK: copy_addr [take] [[LHS]] to [init] [[LHS_ADDR]]
14+
// CHECK: [[RHS_ADDR:%.*]] = tuple_element_addr [[DEST]] : $*(Builtin.NativeObject, Builtin.NativeObject), 1
15+
// CHECK: copy_addr [take] [[RHS]] to [init] [[RHS_ADDR]]
16+
// CHECK: } // end sil function 'tuple_addr_constructor_init'
17+
sil [ossa] @tuple_addr_constructor_init : $@convention(thin) (@in Builtin.NativeObject) -> () {
18+
bb0(%0 : $*Builtin.NativeObject):
19+
%1 = alloc_stack $Builtin.NativeObject
20+
copy_addr %0 to [init] %1 : $*Builtin.NativeObject
21+
%2 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
22+
tuple_addr_constructor [init] %2 : $*(Builtin.NativeObject, Builtin.NativeObject) with (%0 : $*Builtin.NativeObject, %1 : $*Builtin.NativeObject)
23+
destroy_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
24+
dealloc_stack %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
25+
dealloc_stack %1 : $*Builtin.NativeObject
26+
%9999 = tuple ()
27+
return %9999 : $()
28+
}
29+
30+
// CHECK-LABEL: sil [ossa] @tuple_addr_constructor_assign : $@convention(thin) (@in Builtin.NativeObject, @in (Builtin.NativeObject, Builtin.NativeObject)) -> () {
31+
// CHECK: bb0([[LHS:%.*]] : $*Builtin.NativeObject,
32+
// CHECK: [[RHS:%.*]] = alloc_stack $Builtin.NativeObject
33+
// CHECK: [[DEST:%.*]] = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
34+
// CHECK: [[LHS_ADDR:%.*]] = tuple_element_addr [[DEST]] : $*(Builtin.NativeObject, Builtin.NativeObject), 0
35+
// CHECK: copy_addr [take] [[LHS]] to [[LHS_ADDR]]
36+
// CHECK: [[RHS_ADDR:%.*]] = tuple_element_addr [[DEST]] : $*(Builtin.NativeObject, Builtin.NativeObject), 1
37+
// CHECK: copy_addr [take] [[RHS]] to [[RHS_ADDR]]
38+
// CHECK: } // end sil function 'tuple_addr_constructor_assign'
39+
sil [ossa] @tuple_addr_constructor_assign : $@convention(thin) (@in Builtin.NativeObject, @in (Builtin.NativeObject, Builtin.NativeObject)) -> () {
40+
bb0(%0 : $*Builtin.NativeObject, %0a : $*(Builtin.NativeObject, Builtin.NativeObject)):
41+
%1 = alloc_stack $Builtin.NativeObject
42+
copy_addr %0 to [init] %1 : $*Builtin.NativeObject
43+
%2 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
44+
copy_addr [take] %0a to [init] %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
45+
tuple_addr_constructor [assign] %2 : $*(Builtin.NativeObject, Builtin.NativeObject) with (%0 : $*Builtin.NativeObject, %1 : $*Builtin.NativeObject)
46+
destroy_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
47+
dealloc_stack %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
48+
dealloc_stack %1 : $*Builtin.NativeObject
49+
%9999 = tuple ()
50+
return %9999 : $()
51+
}
52+
53+
// CHECK-LABEL: sil [ossa] @tuple_addr_constructor_mixed_init : $@convention(thin) (@in Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
54+
// CHECK: bb0([[LHS:%.*]] : $*Builtin.NativeObject, [[RHS:%.*]] : @owned $Builtin.NativeObject):
55+
// CHECK: [[DEST:%.*]] = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
56+
// CHECK: [[LHS_ADDR:%.*]] = tuple_element_addr [[DEST]] : $*(Builtin.NativeObject, Builtin.NativeObject), 0
57+
// CHECK: copy_addr [take] [[LHS]] to [init] [[LHS_ADDR]]
58+
// CHECK: [[RHS_ADDR:%.*]] = tuple_element_addr [[DEST]] : $*(Builtin.NativeObject, Builtin.NativeObject), 1
59+
// CHECK: store [[RHS]] to [init] [[RHS_ADDR]]
60+
// CHECK: } // end sil function 'tuple_addr_constructor_mixed_init'
61+
sil [ossa] @tuple_addr_constructor_mixed_init : $@convention(thin) (@in Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
62+
bb0(%0 : $*Builtin.NativeObject, %1 : @owned $Builtin.NativeObject):
63+
%2 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
64+
tuple_addr_constructor [init] %2 : $*(Builtin.NativeObject, Builtin.NativeObject) with (%0 : $*Builtin.NativeObject, %1 : $Builtin.NativeObject)
65+
destroy_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
66+
dealloc_stack %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
67+
%9999 = tuple ()
68+
return %9999 : $()
69+
}
70+
71+
// CHECK-LABEL: sil [ossa] @tuple_addr_constructor_mixed_assign : $@convention(thin) (@in Builtin.NativeObject, @in (Builtin.NativeObject, Builtin.NativeObject), @owned Builtin.NativeObject) -> () {
72+
// CHECK: bb0([[LHS:%.*]] : $*Builtin.NativeObject, {{%.*}} : $*(Builtin.NativeObject, Builtin.NativeObject), [[RHS:%.*]] : @owned
73+
// CHECK: [[DEST:%.*]] = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
74+
// CHECK: [[LHS_ADDR:%.*]] = tuple_element_addr [[DEST]] : $*(Builtin.NativeObject, Builtin.NativeObject), 0
75+
// CHECK: copy_addr [take] [[LHS]] to [[LHS_ADDR]]
76+
// CHECK: [[RHS_ADDR:%.*]] = tuple_element_addr [[DEST]] : $*(Builtin.NativeObject, Builtin.NativeObject), 1
77+
// CHECK: store [[RHS]] to [assign] [[RHS_ADDR]]
78+
// CHECK: } // end sil function 'tuple_addr_constructor_mixed_assign'
79+
sil [ossa] @tuple_addr_constructor_mixed_assign : $@convention(thin) (@in Builtin.NativeObject, @in (Builtin.NativeObject, Builtin.NativeObject), @owned Builtin.NativeObject) -> () {
80+
bb0(%0 : $*Builtin.NativeObject, %0a : $*(Builtin.NativeObject, Builtin.NativeObject), %0b : @owned $Builtin.NativeObject):
81+
%2 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject)
82+
copy_addr [take] %0a to [init] %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
83+
tuple_addr_constructor [assign] %2 : $*(Builtin.NativeObject, Builtin.NativeObject) with (%0 : $*Builtin.NativeObject, %0b : $Builtin.NativeObject)
84+
destroy_addr %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
85+
dealloc_stack %2 : $*(Builtin.NativeObject, Builtin.NativeObject)
86+
%9999 = tuple ()
87+
return %9999 : $()
88+
}
89+
90+
// CHECK-LABEL: sil [ossa] @tuple_addr_constructor_unfriendly : $@convention(thin) (@in Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
91+
// CHECK: bb0([[LHS:%.*]] : $*Builtin.NativeObject, [[RHS:%.*]] : @owned
92+
// CHECK: [[DEST:%.*]] = alloc_stack $((), (Builtin.NativeObject, Builtin.NativeObject))
93+
// CHECK: [[LHS_ADDR:%.*]] = tuple_element_addr [[DEST]] : $*((), (Builtin.NativeObject, Builtin.NativeObject)), 0
94+
// CHECK: [[RHS_ADDR:%.*]] = tuple_element_addr [[DEST]] : $*((), (Builtin.NativeObject, Builtin.NativeObject)), 1
95+
// CHECK: [[RHS_ADDR_1:%.*]] = tuple_element_addr [[RHS_ADDR]] : $*(Builtin.NativeObject, Builtin.NativeObject), 0
96+
// CHECK: copy_addr [take] [[LHS]] to [init] [[RHS_ADDR_1]]
97+
// CHECK: [[RHS_ADDR_2:%.*]] = tuple_element_addr [[RHS_ADDR]] : $*(Builtin.NativeObject, Builtin.NativeObject), 1
98+
// CHECK: store [[RHS]] to [init] [[RHS_ADDR_2]]
99+
// CHECK: } // end sil function 'tuple_addr_constructor_unfriendly'
100+
sil [ossa] @tuple_addr_constructor_unfriendly : $@convention(thin) (@in Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
101+
bb0(%0 : $*Builtin.NativeObject, %0a : @owned $Builtin.NativeObject):
102+
%2 = alloc_stack $((), (Builtin.NativeObject, Builtin.NativeObject))
103+
tuple_addr_constructor [init] %2 : $*((), (Builtin.NativeObject, Builtin.NativeObject)) with (%0 : $*Builtin.NativeObject, %0a : $Builtin.NativeObject)
104+
destroy_addr %2 : $*((), (Builtin.NativeObject, Builtin.NativeObject))
105+
dealloc_stack %2 : $*((), (Builtin.NativeObject, Builtin.NativeObject))
106+
%9999 = tuple ()
107+
return %9999 : $()
108+
}
109+
110+
// CHECK-LABEL: sil [ossa] @tuple_addr_constructor_unfriendly_2 : $@convention(thin) (@in Builtin.NativeObject, @owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
111+
// CHECK: bb0([[ARG1:%.*]] : $*Builtin.NativeObject, [[ARG2:%.*]] : @owned $Builtin.NativeObject, [[ARG3:%.*]] : $*Builtin.NativeObject
112+
// CHECK: [[DEST:%.*]] = alloc_stack $((), (Builtin.NativeObject, Builtin.NativeObject), ((), (), Builtin.NativeObject))
113+
// CHECK: [[ADDR_1:%.*]] = tuple_element_addr [[DEST]] : $*((), (Builtin.NativeObject, Builtin.NativeObject), ((), (), Builtin.NativeObject))
114+
// CHECK: [[ADDR_2:%.*]] = tuple_element_addr [[DEST]] : $*((), (Builtin.NativeObject, Builtin.NativeObject), ((), (), Builtin.NativeObject))
115+
// CHECK: [[ADDR_2_1:%.*]] = tuple_element_addr [[ADDR_2]] : $*(Builtin.NativeObject, Builtin.NativeObject), 0
116+
// CHECK: copy_addr [take] [[ARG1]] to [init] [[ADDR_2_1]]
117+
// CHECK: [[ADDR_2_2:%.*]] = tuple_element_addr [[ADDR_2]] : $*(Builtin.NativeObject, Builtin.NativeObject), 1
118+
// CHECK: store [[ARG2]] to [init] [[ADDR_2_2]]
119+
// CHECK: [[ADDR_3:%.*]] = tuple_element_addr [[DEST]] : $*((), (Builtin.NativeObject, Builtin.NativeObject), ((), (), Builtin.NativeObject))
120+
// CHECK: [[ADDR_3_1:%.*]] = tuple_element_addr [[ADDR_3]] : $*((), (), Builtin.NativeObject), 0
121+
// CHECK: [[ADDR_3_2:%.*]] = tuple_element_addr [[ADDR_3]] : $*((), (), Builtin.NativeObject), 1
122+
// CHECK: [[ADDR_3_3:%.*]] = tuple_element_addr [[ADDR_3]] : $*((), (), Builtin.NativeObject), 2
123+
// CHECK: copy_addr [take] [[ARG3]] to [init] [[ADDR_3_3]]
124+
// CHECK: } // end sil function 'tuple_addr_constructor_unfriendly_2'
125+
sil [ossa] @tuple_addr_constructor_unfriendly_2 : $@convention(thin) (@in Builtin.NativeObject, @owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
126+
bb0(%0 : $*Builtin.NativeObject, %0a : @owned $Builtin.NativeObject, %0b : $*Builtin.NativeObject):
127+
%2 = alloc_stack $((), (Builtin.NativeObject, Builtin.NativeObject), ((), (), (Builtin.NativeObject)))
128+
tuple_addr_constructor [init] %2 : $*((), (Builtin.NativeObject, Builtin.NativeObject), ((), (), (Builtin.NativeObject))) with (%0 : $*Builtin.NativeObject, %0a : $Builtin.NativeObject, %0b : $*Builtin.NativeObject)
129+
destroy_addr %2 : $*((), (Builtin.NativeObject, Builtin.NativeObject), ((), (), (Builtin.NativeObject)))
130+
dealloc_stack %2 : $*((), (Builtin.NativeObject, Builtin.NativeObject), ((), (), (Builtin.NativeObject)))
131+
%9999 = tuple ()
132+
return %9999 : $()
133+
}
134+
135+
// CHECK-LABEL: sil [ossa] @tuple_addr_constructor_unfriendly_3 : $@convention(thin) (@in Builtin.NativeObject, @owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
136+
// CHECK: bb0([[ARG1:%.*]] : $*Builtin.NativeObject, [[ARG2:%.*]] : @owned $Builtin.NativeObject, [[ARG3:%.*]] : $*Builtin.NativeObject
137+
// CHECK: [[DEST:%.*]] = alloc_stack $((a: ()), (Builtin.NativeObject, Builtin.NativeObject), ((), (), b: Builtin.NativeObject))
138+
// CHECK: [[ADDR_1:%.*]] = tuple_element_addr [[DEST]] : $*((a: ()), (Builtin.NativeObject, Builtin.NativeObject), ((), (), b: Builtin.NativeObject))
139+
// CHECK: [[ADDR_2:%.*]] = tuple_element_addr [[DEST]] : $*((a: ()), (Builtin.NativeObject, Builtin.NativeObject), ((), (), b: Builtin.NativeObject))
140+
// CHECK: [[ADDR_2_1:%.*]] = tuple_element_addr [[ADDR_2]] : $*(Builtin.NativeObject, Builtin.NativeObject), 0
141+
// CHECK: copy_addr [take] [[ARG1]] to [init] [[ADDR_2_1]]
142+
// CHECK: [[ADDR_2_2:%.*]] = tuple_element_addr [[ADDR_2]] : $*(Builtin.NativeObject, Builtin.NativeObject), 1
143+
// CHECK: store [[ARG2]] to [init] [[ADDR_2_2]]
144+
// CHECK: [[ADDR_3:%.*]] = tuple_element_addr [[DEST]] : $*((a: ()), (Builtin.NativeObject, Builtin.NativeObject), ((), (), b: Builtin.NativeObject))
145+
// CHECK: [[ADDR_3_1:%.*]] = tuple_element_addr [[ADDR_3]] : $*((), (), b: Builtin.NativeObject), 0
146+
// CHECK: [[ADDR_3_2:%.*]] = tuple_element_addr [[ADDR_3]] : $*((), (), b: Builtin.NativeObject), 1
147+
// CHECK: [[ADDR_3_3:%.*]] = tuple_element_addr [[ADDR_3]] : $*((), (), b: Builtin.NativeObject), 2
148+
// CHECK: copy_addr [take] [[ARG3]] to [init] [[ADDR_3_3]]
149+
// CHECK: } // end sil function 'tuple_addr_constructor_unfriendly_3'
150+
sil [ossa] @tuple_addr_constructor_unfriendly_3 : $@convention(thin) (@in Builtin.NativeObject, @owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
151+
bb0(%0 : $*Builtin.NativeObject, %0a : @owned $Builtin.NativeObject, %0b : $*Builtin.NativeObject):
152+
%2 = alloc_stack $*((a: ()), (Builtin.NativeObject, Builtin.NativeObject), ((), (), b: (Builtin.NativeObject)))
153+
tuple_addr_constructor [init] %2 : $*((a: ()), (Builtin.NativeObject, Builtin.NativeObject), ((), (), b: (Builtin.NativeObject))) with (%0 : $*Builtin.NativeObject, %0a : $Builtin.NativeObject, %0b : $*Builtin.NativeObject)
154+
destroy_addr %2 : $*((a: ()), (Builtin.NativeObject, Builtin.NativeObject), ((), (), b: (Builtin.NativeObject)))
155+
dealloc_stack %2 : $*((a: ()), (Builtin.NativeObject, Builtin.NativeObject), ((), (), b: (Builtin.NativeObject)))
156+
%9999 = tuple ()
157+
return %9999 : $()
158+
}

0 commit comments

Comments
 (0)