SILGen: improve code generation for array literals

It used to be done with a library intrinsic which returns the array and an element address pointer.
A `mark_dependence` was used to "connect" the two results.
But this resulted in completely wrong OSSA after inlining.
It just didn't get caught be the verifier because the SIL was obfuscated by address-pointer conversions.

Now we don't use the second result (= the element address) of the intrinsic but generate a correct borrow scope from the first (= array) result. Within that borrow scope we project out the element address with a `ref_tail_addr` instruction.

This relies on knowledge of the internal Array data structures. However those data structures are baked into the ABI since a long time and will not change.
This commit is contained in:
Erik Eckstein
2025-10-10 10:00:19 +02:00
parent 1803d3ec46
commit 3309809429
14 changed files with 115 additions and 68 deletions

View File

@@ -7058,7 +7058,7 @@ RValue SILGenFunction::emitLiteral(LiteralExpr *literal, SGFContext C) {
/// Allocate an uninitialized array of a given size, returning the array
/// and a pointer to its uninitialized contents, which must be initialized
/// before the array is valid.
std::pair<ManagedValue, SILValue>
ManagedValue
SILGenFunction::emitUninitializedArrayAllocation(Type ArrayTy,
SILValue Length,
SILLocation Loc) {
@@ -7075,11 +7075,13 @@ SILGenFunction::emitUninitializedArrayAllocation(Type ArrayTy,
SmallVector<ManagedValue, 2> resultElts;
std::move(result).getAll(resultElts);
// Add a mark_dependence between the interior pointer and the array value
auto dependentValue = B.createMarkDependence(Loc, resultElts[1].getValue(),
resultElts[0].getValue(),
MarkDependenceKind::Escaping);
return {resultElts[0], dependentValue};
// The second result, which is the base element address, is not used. We extract
// it from the array (= the first result) directly to create a correct borrow scope.
// TODO: Consider adding a new intrinsic which only returns the array.
// Although the current intrinsic is inlined and the code for returning the
// second result is optimized away. So it doesn't make a performance difference.
return resultElts[0];
}
/// Deallocate an uninitialized array.

View File

@@ -2664,6 +2664,29 @@ RValue RValueEmitter::visitUnreachableExpr(UnreachableExpr *E, SGFContext C) {
return RValue(SGF, E, ManagedValue::forRValueWithoutOwnership(undef));
}
static SILValue getArrayBuffer(SILValue array, SILGenFunction &SGF, SILLocation loc) {
SILValue v = array;
SILType storageType;
while (auto *sd = v->getType().getStructOrBoundGenericStruct()) {
ASSERT(sd->getStoredProperties().size() == 1 &&
"Array or its internal structs should have exactly one stored property");
auto *se = SGF.getBuilder().createStructExtract(loc, v, v->getType().getFieldDecl(0));
if (se->getType() == SILType::getBridgeObjectType(SGF.getASTContext())) {
auto bridgeObjTy = cast<BoundGenericStructType>(v->getType().getASTType());
CanType ct = CanType(bridgeObjTy->getGenericArgs()[0]);
storageType = SILType::getPrimitiveObjectType(ct);
}
v = se;
}
if (storageType) {
v = SGF.getBuilder().createUncheckedRefCast(loc, v, storageType);
}
ASSERT(v->getType().isReferenceCounted(&SGF.F) &&
"expected a reference-counted buffer in the Array data type");
return v;
}
VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
CanType baseTy, CanType arrayTy,
unsigned numElements) {
@@ -2675,12 +2698,7 @@ VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
SILValue numEltsVal = SGF.B.createIntegerLiteral(loc,
SILType::getBuiltinWordType(SGF.getASTContext()),
numElements);
// The first result is the array value.
ManagedValue array;
// The second result is a RawPointer to the base address of the array.
SILValue basePtr;
std::tie(array, basePtr)
= SGF.emitUninitializedArrayAllocation(arrayTy, numEltsVal, loc);
ManagedValue array = SGF.emitUninitializedArrayAllocation(arrayTy, numEltsVal, loc);
// Temporarily deactivate the main array cleanup.
if (array.hasCleanup())
@@ -2690,13 +2708,15 @@ VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
auto abortCleanup =
SGF.enterDeallocateUninitializedArrayCleanup(array.getValue());
// Turn the pointer into an address.
basePtr = SGF.B.createPointerToAddress(
loc, basePtr, baseTL.getLoweredType().getAddressType(),
/*isStrict*/ true,
/*isInvariant*/ false);
auto borrowedArray = array.borrow(SGF, loc);
auto borrowCleanup = SGF.Cleanups.getTopCleanup();
return VarargsInfo(array, abortCleanup, basePtr, baseTL, baseAbstraction);
SILValue buffer = getArrayBuffer(borrowedArray.getValue(), SGF, loc);
SILType elementAddrTy = baseTL.getLoweredType().getAddressType();
SILValue baseAddr = SGF.getBuilder().createRefTailAddr(loc, buffer, elementAddrTy);
return VarargsInfo(array, borrowCleanup, abortCleanup, baseAddr, baseTL, baseAbstraction);
}
ManagedValue Lowering::emitEndVarargs(SILGenFunction &SGF, SILLocation loc,
@@ -2710,6 +2730,8 @@ ManagedValue Lowering::emitEndVarargs(SILGenFunction &SGF, SILLocation loc,
if (array.hasCleanup())
SGF.Cleanups.setCleanupState(array.getCleanup(), CleanupState::Active);
SGF.Cleanups.popAndEmitCleanup(varargs.getBorrowCleanup(), CleanupLocation(loc), NotForUnwind);
// Array literals only need to be finalized, if the array is really allocated.
// In case of zero elements, no allocation is done, but the empty-array
// singleton is used. "Finalization" means to emit an end_cow_mutation

View File

@@ -1899,11 +1899,10 @@ public:
ManagedValue emitUndef(Type type);
ManagedValue emitUndef(SILType type);
RValue emitUndefRValue(SILLocation loc, Type type);
std::pair<ManagedValue, SILValue>
emitUninitializedArrayAllocation(Type ArrayTy,
SILValue Length,
SILLocation Loc);
ManagedValue emitUninitializedArrayAllocation(Type ArrayTy,
SILValue Length,
SILLocation Loc);
CleanupHandle enterDeallocateUninitializedArrayCleanup(SILValue array);
void emitUninitializedArrayDeallocation(SILLocation loc, SILValue array);

View File

@@ -31,15 +31,16 @@ class TypeLowering;
/// Information about a varargs emission.
class VarargsInfo {
ManagedValue Array;
CleanupHandle borrowCleanup;
CleanupHandle AbortCleanup;
SILValue BaseAddress;
AbstractionPattern BasePattern;
const TypeLowering &BaseTL;
public:
VarargsInfo(ManagedValue array, CleanupHandle abortCleanup,
VarargsInfo(ManagedValue array, CleanupHandle borrowCleanup, CleanupHandle abortCleanup,
SILValue baseAddress, const TypeLowering &baseTL,
AbstractionPattern basePattern)
: Array(array), AbortCleanup(abortCleanup),
: Array(array), borrowCleanup(borrowCleanup), AbortCleanup(abortCleanup),
BaseAddress(baseAddress), BasePattern(basePattern), BaseTL(baseTL) {}
/// Return the array value. emitEndVarargs() is really the only
@@ -47,6 +48,9 @@ public:
ManagedValue getArray() const {
return Array;
}
CleanupHandle getBorrowCleanup() const { return borrowCleanup; }
CleanupHandle getAbortCleanup() const { return AbortCleanup; }
/// An address of the lowered type.

View File

@@ -15,7 +15,8 @@ import Foundation
func returnUnmanagedCFArray() throws -> Unmanaged<CFArray> {
// CHECK: %[[T0:.+]] = call swiftcc { ptr, ptr } @"$ss27_allocateUninitializedArrayySayxG_BptBwlF"(i{{32|64}} 1, ptr @"$sSiN")
// CHECK-NEXT: %[[T1:.+]] = extractvalue { ptr, ptr } %[[T0]], 0
// CHECK-NEXT: %[[T2:.+]] = extractvalue { ptr, ptr } %[[T0]], 1
// CHECK-NEXT: = extractvalue { ptr, ptr } %[[T0]], 1
// CHECK-NEXT: %[[T2:.+]] = getelementptr inbounds i8, ptr %[[T1]]
// CHECK-NEXT: %._value = getelementptr inbounds{{.*}} %TSi, ptr %[[T2]], i32 0, i32 0
// CHECK: %[[T7:.+]] = call swiftcc ptr @"$ss27_finalizeUninitializedArrayySayxGABnlF"(ptr %[[T1]], ptr @"$sSiN")
// CHECK: %[[T4:.+]] = call swiftcc ptr @"$sSa10FoundationE19_bridgeToObjectiveCSo7NSArrayCyF"(ptr %[[T7]], ptr @"$sSiN")

View File

@@ -74,6 +74,6 @@ public func getArrayOfLocalCount() -> [NS.LocalCount] {
// CHECK-NEXT: %0 = call swiftcc %swift.metadata_response @"$sSo2NSO10LocalCountVMa"(i{{.*}} 0)
// CHECK-NEXT: %1 = extractvalue %swift.metadata_response %0, 0
// CHECK-NEXT: %2 = call swiftcc { ptr, ptr } @"$ss27_allocateUninitializedArrayySayxG_BptBwlF"(i{{.*}} 1, ptr %1)
// CHECK: %5 = call ptr @{{_ZN2NS10LocalCount6createEv|"\?create\@LocalCount\@NS\@\@SAPEAU12\@XZ"}}()
// CHECK-NEXT: call void @{{_Z8LCRetainPN2NS10LocalCountE|"\?LCRetain\@\@YAXPEAULocalCount\@NS\@\@\@Z"}}(ptr %5)
// CHECK: %6 = call ptr @{{_ZN2NS10LocalCount6createEv|"\?create\@LocalCount\@NS\@\@SAPEAU12\@XZ"}}()
// CHECK-NEXT: call void @{{_Z8LCRetainPN2NS10LocalCountE|"\?LCRetain\@\@YAXPEAULocalCount\@NS\@\@\@Z"}}(ptr %6)
// CHECK: }

View File

@@ -6,15 +6,19 @@ struct UnicodeScalar {}
enum Never {}
class ArrayBufer {}
// Minimal implementation to support varargs.
struct Array<T> { }
struct Array<T> {
let buffer: ArrayBufer
}
func _allocateUninitializedArray<T>(_: Builtin.Word)
-> (Array<T>, Builtin.RawPointer) {
Builtin.int_trap()
}
func _finalizeUninitializedArray<T>(_ a: Array<T>) -> Array<T> {
func _finalizeUninitializedArray<T>(_ a: __owned Array<T>) -> Array<T> {
return a
}
@@ -63,7 +67,7 @@ arg_default_tuple(x:i, y:f)
func variadic_arg_1(_ x: Int...) {}
// CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_1{{[_0-9a-zA-Z]*}}F
// CHECK: bb0([[X:%[0-9]+]] : $Array<Int>):
// CHECK: bb0([[X:%[0-9]+]] : @guaranteed $Array<Int>):
variadic_arg_1()
variadic_arg_1(i)
@@ -72,7 +76,7 @@ variadic_arg_1(i, i, i)
func variadic_arg_2(_ x: Int, _ y: Float...) {}
// CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_2{{[_0-9a-zA-Z]*}}F
// CHECK: bb0([[X:%[0-9]+]] : $Int, [[Y:%[0-9]+]] : $Array<Float>):
// CHECK: bb0([[X:%[0-9]+]] : $Int, [[Y:%[0-9]+]] : @guaranteed $Array<Float>):
variadic_arg_2(i)
variadic_arg_2(i, f)
@@ -80,15 +84,15 @@ variadic_arg_2(i, f, f, f)
func variadic_arg_3(_ y: Float..., x: Int) {}
// CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_3{{[_0-9a-zA-Z]*}}F
// CHECK: bb0([[Y:%[0-9]+]] : $Array<Float>, [[X:%[0-9]+]] : $Int):
// CHECK: bb0([[Y:%[0-9]+]] : @guaranteed $Array<Float>, [[X:%[0-9]+]] : $Int):
func variadic_arg_4(_ y: Float..., x: Int...) {}
// CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_4{{[_0-9a-zA-Z]*}}F
// CHECK: bb0([[Y:%[0-9]+]] : $Array<Float>, [[X:%[0-9]+]] : $Array<Int>):
// CHECK: bb0([[Y:%[0-9]+]] : @guaranteed $Array<Float>, [[X:%[0-9]+]] : @guaranteed $Array<Int>):
func variadic_arg_5(a: Int, b: Float..., c: Int, d: Int...) {}
// CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_5{{[_0-9a-zA-Z]*}}F
// CHECK: bb0([[A:%[0-9]+]] : $Int, [[B:%[0-9]+]] : $Array<Float>, [[C:%[0-9]+]] : $Int, [[D:%[0-9]+]] : $Array<Int>):
// CHECK: bb0([[A:%[0-9]+]] : $Int, [[B:%[0-9]+]] : @guaranteed $Array<Float>, [[C:%[0-9]+]] : $Int, [[D:%[0-9]+]] : @guaranteed $Array<Int>):
variadic_arg_3(x: i)
variadic_arg_3(f, x: i)

View File

@@ -5,13 +5,13 @@
// <rdar://problem/16039286>
// CHECK-LABEL: sil hidden [ossa] @$s25array_literal_abstraction0A9_of_funcsSayyycGyF
// CHECK: pointer_to_address {{.*}} $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>
// CHECK: ref_tail_addr %{{[0-9]+}}, $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>
func array_of_funcs() -> [(() -> ())] {
return [{}, {}]
}
// CHECK-LABEL: sil hidden [ossa] @$s25array_literal_abstraction13dict_of_funcsSDySiyycGyF
// CHECK: pointer_to_address {{.*}} $*(Int, @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>)
// CHECK: ref_tail_addr %{{[0-9]+}}, $(Int, @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>)
func dict_of_funcs() -> Dictionary<Int, () -> ()> {
return [0: {}, 1: {}]
}
@@ -19,7 +19,7 @@ func dict_of_funcs() -> Dictionary<Int, () -> ()> {
func vararg_funcs(_ fs: (() -> ())...) {}
// CHECK-LABEL: sil hidden [ossa] @$s25array_literal_abstraction17call_vararg_funcsyyF
// CHECK: pointer_to_address {{.*}} $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>
// CHECK: ref_tail_addr %{{[0-9]+}}, $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>
func call_vararg_funcs() {
vararg_funcs({}, {})
}

View File

@@ -615,8 +615,9 @@ func test_variadic(_ cat: Cat) throws {
// CHECK: [[T0:%.*]] = function_ref @$ss27_allocateUninitializedArray{{.*}}F
// CHECK: [[T1:%.*]] = apply [[T0]]<Cat>([[N]])
// CHECK: ([[ARRAY:%.*]], [[T2:%.*]]) = destructure_tuple [[T1]]
// CHECK: [[MDI:%.*]] = mark_dependence [[T2]] : $Builtin.RawPointer on [[ARRAY]]
// CHECK: [[ELT0:%.*]] = pointer_to_address [[MDI]] : $Builtin.RawPointer to [strict] $*Cat
// CHECK: [[BB:%.*]] = begin_borrow [[ARRAY]]
// CHECK: struct_extract [[BB]]
// CHECK: [[ELT0:%.*]] = ref_tail_addr
// Element 0.
// CHECK: [[T0:%.*]] = function_ref @$s6errors10make_a_catAA3CatCyKF : $@convention(thin) () -> (@owned Cat, @error any Error)
// CHECK: try_apply [[T0]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[NORM_0:bb[0-9]+]], error [[ERR_0:bb[0-9]+]]
@@ -654,7 +655,7 @@ func test_variadic(_ cat: Cat) throws {
// CHECK-NEXT: return
// Failure from element 0.
// CHECK: [[ERR_0]]([[ERROR:%.*]] : @owned $any Error):
// CHECK-NOT: end_borrow
// CHECK: end_borrow [[BB]]
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[T0:%.*]] = function_ref @$ss29_deallocateUninitializedArray{{.*}}F
// CHECK-NEXT: apply [[T0]]<Cat>([[ARRAY]])
@@ -663,6 +664,7 @@ func test_variadic(_ cat: Cat) throws {
// CHECK: [[ERR_2]]([[ERROR:%.*]] : @owned $any Error):
// CHECK-NEXT: destroy_addr [[ELT1]]
// CHECK-NEXT: destroy_addr [[ELT0]]
// CHECK: end_borrow [[BB]]
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[T0:%.*]] = function_ref @$ss29_deallocateUninitializedArray{{.*}}F
// CHECK-NEXT: apply [[T0]]<Cat>([[ARRAY]])
@@ -672,6 +674,7 @@ func test_variadic(_ cat: Cat) throws {
// CHECK-NEXT: destroy_addr [[ELT2]]
// CHECK-NEXT: destroy_addr [[ELT1]]
// CHECK-NEXT: destroy_addr [[ELT0]]
// CHECK-NEXT: end_borrow [[BB]]
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[T0:%.*]] = function_ref @$ss29_deallocateUninitializedArray{{.*}}F
// CHECK-NEXT: apply [[T0]]<Cat>([[ARRAY]])

View File

@@ -52,8 +52,9 @@ class TakesArrayLiteral<Element> : ExpressibleByArrayLiteral {
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<Int>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[MDI:%.*]] = mark_dependence [[ADDRESS]]
// CHECK: [[POINTER:%.*]] = pointer_to_address [[MDI]]
// CHECK: [[BB:%.*]] = begin_borrow [[ARR]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[POINTER:%.*]] = ref_tail_addr
// CHECK: store [[TMP:%.*]] to [trivial] [[POINTER]]
// CHECK: [[IDX1:%.*]] = integer_literal $Builtin.Word, 1
// CHECK: [[POINTER1:%.*]] = index_addr [[POINTER]] : $*Int, [[IDX1]] : $Builtin.Word
@@ -77,8 +78,9 @@ class Klass {}
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<Klass>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[MDI:%.*]] = mark_dependence [[ADDRESS]]
// CHECK: [[POINTER:%.*]] = pointer_to_address [[MDI]]
// CHECK: [[BB:%.*]] = begin_borrow [[ARR]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[POINTER:%.*]] = ref_tail_addr
// CHECK: [[KLASS_METATYPE:%.*]] = metatype $@thick Klass.Type
// CHECK: [[CTOR:%.*]] = function_ref @$s8literals5KlassCACycfC : $@convention(method) (@thick Klass.Type) -> @owned Klass
// CHECK: [[TMP:%.*]] = apply [[CTOR]]([[KLASS_METATYPE]]) : $@convention(method) (@thick Klass.Type) -> @owned Klass
@@ -102,8 +104,9 @@ struct Foo<T> {
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<Foo<T>>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[MDI:%.*]] = mark_dependence [[ADDRESS]]
// CHECK: [[POINTER:%.*]] = pointer_to_address [[MDI]]
// CHECK: [[BB:%.*]] = begin_borrow [[ARR]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[POINTER:%.*]] = ref_tail_addr
// CHECK: copy_addr %0 to [init] [[POINTER]] : $*Foo<T>
// CHECK: [[FIN_FN:%.*]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF
// CHECK: [[FIN_ARR:%.*]] = apply [[FIN_FN]]<Foo<T>>([[ARR]])
@@ -120,8 +123,9 @@ func returnsAddressOnlyElementArray<T>(t: Foo<T>) -> TakesArrayLiteral<Foo<T>> {
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<Foo<T>>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[MDI:%.*]] = mark_dependence [[ADDRESS]]
// CHECK: [[POINTER:%.*]] = pointer_to_address [[MDI]]
// CHECK: [[BB:%.*]] = begin_borrow [[ARR]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[POINTER:%.*]] = ref_tail_addr
// CHECK: copy_addr %0 to [init] [[POINTER]] : $*Foo<T>
// CHECK: [[FIN_FN:%.*]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF
// CHECK: [[FIN_ARR:%.*]] = apply [[FIN_FN]]<Foo<T>>([[ARR]])
@@ -140,8 +144,9 @@ extension Foo {
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<Foo<T>>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[MDI:%.*]] = mark_dependence [[ADDRESS]]
// CHECK: [[POINTER:%.*]] = pointer_to_address [[MDI]]
// CHECK: [[BB:%.*]] = begin_borrow [[ARR]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[POINTER:%.*]] = ref_tail_addr
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] %0 : $*Foo<T>
// CHECK: copy_addr [[ACCESS]] to [init] [[POINTER]] : $*Foo<T>
// CHECK: end_access [[ACCESS]] : $*Foo<T>
@@ -166,8 +171,9 @@ struct Foo2 {
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<Foo2>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[MDI:%.*]] = mark_dependence [[ADDRESS]]
// CHECK: [[POINTER:%.*]] = pointer_to_address [[MDI]]
// CHECK: [[BB:%.*]] = begin_borrow [[ARR]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[POINTER:%.*]] = ref_tail_addr
// CHECK: [[METATYPE_FOO2:%.*]] = metatype $@thin Foo2.Type
// CHECK: [[METATYPE_KLASS:%.*]] = metatype $@thick Klass.Type
// CHECK: [[CTOR:%.*]] = function_ref @$s8literals5KlassCACycfC : $@convention(method) (@thick Klass.Type) -> @owned Klass
@@ -191,8 +197,9 @@ func returnsNonTrivialStruct() -> TakesArrayLiteral<Foo2> {
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<NestedLValuePath>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[MDI:%.*]] = mark_dependence [[ADDRESS]]
// CHECK: [[POINTER:%.*]] = pointer_to_address [[MDI]]
// CHECK: [[BB:%.*]] = begin_borrow [[ARR]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[POINTER:%.*]] = ref_tail_addr
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] %0 : $*NestedLValuePath
// CHECK: [[OTHER_FN:%.*]] = function_ref @$s8literals16NestedLValuePathV21otherMutatingFunctionACyF : $@convention(method) (@inout NestedLValuePath) -> @owned NestedLValuePath
@@ -230,8 +237,9 @@ protocol WrapsSelfInArray {}
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<any WrapsSelfInArray>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[MDI:%.*]] = mark_dependence [[ADDRESS]]
// CHECK: [[POINTER:%.*]] = pointer_to_address [[MDI]]
// CHECK: [[BB:%.*]] = begin_borrow [[ARR]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[POINTER:%.*]] = ref_tail_addr
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] %0 : $*Self
// CHECK: [[EXISTENTIAL:%.*]] = init_existential_addr [[POINTER]] : $*any WrapsSelfInArray, $Self
// CHECK: copy_addr [[ACCESS]] to [init] [[EXISTENTIAL]] : $*Self
@@ -260,8 +268,9 @@ func makeBasic<T : FooProtocol>() -> T { return T() }
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<T>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[MDI:%.*]] = mark_dependence [[ADDRESS]]
// CHECK: [[POINTER:%.*]] = pointer_to_address [[MDI]]
// CHECK: [[BB:%.*]] = begin_borrow [[ARR]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[POINTER:%.*]] = ref_tail_addr
// CHECK: [[FN:%.*]] = function_ref @$s8literals9makeBasicxyAA11FooProtocolRzlF : $@convention(thin)
// CHECK: [[TMP:%.*]] = apply [[FN]]<T>([[POINTER]])
// CHECK: [[IDX:%.*]] = integer_literal $Builtin.Word, 1
@@ -295,8 +304,9 @@ class TakesDictionaryLiteral<Key, Value> : ExpressibleByDictionaryLiteral {
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer)
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<(Int, Int)>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[MDI:%.*]] = mark_dependence [[ADDRESS]]
// CHECK: [[TUPLE_ADDR:%.*]] = pointer_to_address [[MDI]] : $Builtin.RawPointer to [strict] $*(Int, Int)
// CHECK: [[BB:%.*]] = begin_borrow [[ARR]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[TUPLE_ADDR:%.*]] = ref_tail_addr
// CHECK: [[KEY_ADDR:%.*]] = tuple_element_addr [[TUPLE_ADDR]] : $*(Int, Int), 0
// CHECK: [[VALUE_ADDR:%.*]] = tuple_element_addr [[TUPLE_ADDR]] : $*(Int, Int), 1
// CHECK: store [[TMP]] to [trivial] [[KEY_ADDR]] : $*Int

View File

@@ -22,8 +22,9 @@ func setChildren(p: Parent, c: Child) {
// CHECK: [[FN:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer)
// CHECK: [[ARRAY_AND_BUFFER:%.*]] = apply [[FN]]<Child>([[LENGTH]]) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer)
// CHECK: ([[ARRAY:%.*]], [[BUFFER_PTR:%.*]]) = destructure_tuple [[ARRAY_AND_BUFFER]] : $(Array<Child>, Builtin.RawPointer)
// CHECK: [[MDI:%.*]] = mark_dependence [[BUFFER_PTR]] : $Builtin.RawPointer on [[ARRAY]]
// CHECK: [[BUFFER:%.*]] = pointer_to_address [[MDI]] : $Builtin.RawPointer to [strict] $*Child
// CHECK: [[BB:%.*]] = begin_borrow [[ARRAY]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[BUFFER:%.*]] = ref_tail_addr
// CHECK: [[CHILD:%.*]] = copy_value %1 : $Child
// CHECK: store [[CHILD]] to [init] [[BUFFER]] : $*Child
// CHECK: [[FIN_FN:%.*]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF

View File

@@ -539,10 +539,10 @@ public func objectFieldToPointer(rc: RefObj) {
// CHECK: [[ARRAY_REF:%.*]] = begin_access [modify] [unknown] %0 : $*Array<Int>
// CHECK: [[CONVERT_ARRAY_TO_POINTER:%.*]] = function_ref @$ss37_convertMutableArrayToPointerArgumentyyXlSg_q_tSayxGzs01_E0R_r0_lF
// CHECK: apply [[CONVERT_ARRAY_TO_POINTER]]<Int, UnsafeMutableRawPointer>({{.*}}, [[ARRAY_REF]])
// CHECK: [[V_REF:%.*]] = begin_access [modify] [unknown] %28 : $*Double
// CHECK: [[V_REF:%.*]] = begin_access [modify] [unknown] %{{[0-9]+}} : $*Double
// CHECK: [[DOUBLE_AS_PTR:%.*]] = address_to_pointer [stack_protection] [[V_REF]] : $*Double to $Builtin.RawPointer
// CHECK: [[INOUT_TO_PTR:%.*]] = function_ref @$ss30_convertInOutToPointerArgumentyxBps01_E0RzlF
// CHECK: apply [[INOUT_TO_PTR]]<UnsafeMutableRawPointer>(%39, [[DOUBLE_AS_PTR]])
// CHECK: apply [[INOUT_TO_PTR]]<UnsafeMutableRawPointer>(%{{[0-9]+}}, [[DOUBLE_AS_PTR]])
// CHECK: } // end sil function '$s18pointer_conversion21testVariadicParameter1aySaySiGz_tF'
public func testVariadicParameter(a: inout [Int]) {
func test(_ : UnsafeMutableRawPointer?...) {}

View File

@@ -55,8 +55,9 @@ tupleWithDefaults(x: (x,x))
// CHECK: [[ALLOC_ARRAY:%.*]] = apply {{.*}} -> (@owned Array<τ_0_0>, Builtin.RawPointer)
// CHECK: ([[ARRAY:%.*]], [[MEMORY:%.*]]) = destructure_tuple [[ALLOC_ARRAY]]
// CHECK: [[MDI:%.*]] = mark_dependence [[MEMORY]]
// CHECK: [[ADDR:%.*]] = pointer_to_address [[MDI]]
// CHECK: [[BB:%.*]] = begin_borrow [[ARRAY]]
// CHECK: = struct_extract [[BB]]
// CHECK: [[ADDR:%.*]] = ref_tail_addr
// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[X_ADDR]] : $*Int
// CHECK: copy_addr [[READ]] to [init] [[ADDR]]
// CHECK: [[FIN_FN:%.*]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF

View File

@@ -7,7 +7,7 @@
// CHECK: alloc_stack $any R, loc {{.*}}, scope [[SCOPE:[0-9]+]]
// CHECK-NEXT: init_existential_addr {{.*}} : $*any R, $Float, loc {{.*}}, scope [[SCOPE]]
// CHECK-NEXT: copy_addr [take] %9 to [init] {{.*}} : $*Float, loc {{.*}}, scope [[SCOPE]]
// CHECK-NEXT: copy_addr [take] %{{[0-9]+}} to [init] {{.*}} : $*Float, loc {{.*}}, scope [[SCOPE]]
protocol R {}
extension Float: R {}