SILGen: use vector_base_addr in InlineArray literals

This commit is contained in:
Erik Eckstein
2025-05-12 12:15:56 +02:00
parent bc4310b0eb
commit d28384dbd7
5 changed files with 74 additions and 41 deletions

View File

@@ -175,7 +175,7 @@ private func lowerInlineArray(array: InlineArray, _ context: FunctionPassContext
///
private func getInlineArrayInfo(of allocStack: AllocStackInst) -> InlineArray? {
var arrayLoad: LoadInst? = nil
var elementStorage: UncheckedAddrCastInst? = nil
var elementStorage: VectorBaseAddrInst? = nil
for use in allocStack.uses {
switch use.instruction {
@@ -188,11 +188,11 @@ private func getInlineArrayInfo(of allocStack: AllocStackInst) -> InlineArray? {
arrayLoad = load
case is DeallocStackInst:
break
case let addrCastToElement as UncheckedAddrCastInst:
case let baseAddr as VectorBaseAddrInst:
if elementStorage != nil {
return nil
}
elementStorage = addrCastToElement
elementStorage = baseAddr
default:
return nil
}

View File

@@ -4992,7 +4992,7 @@ static RValue emitInlineArrayLiteral(SILGenFunction &SGF, CollectionExpr *E,
SGFContext C) {
ArgumentScope scope(SGF, E);
auto iaTy = E->getType()->castTo<BoundGenericType>();
auto iaTy = E->getType()->castTo<BoundGenericStructType>();
auto loweredIAType = SGF.getLoweredType(iaTy);
// If this is an empty InlineArray literal and it's loadable, then create an
@@ -5007,9 +5007,19 @@ static RValue emitInlineArrayLiteral(SILGenFunction &SGF, CollectionExpr *E,
auto elementType = iaTy->getGenericArgs()[1]->getCanonicalType();
auto &eltTL = SGF.getTypeLowering(AbstractionPattern::getOpaque(), elementType);
auto *arrayDecl = cast<StructDecl>(iaTy->getDecl());
VarDecl *storageProperty = nullptr;
for (VarDecl *property : arrayDecl->getStoredProperties()) {
if ((property->getTypeInContext()->is<BuiltinFixedArrayType>())) {
storageProperty = property;
break;
}
}
SILValue alloc = SGF.emitTemporaryAllocation(E, loweredIAType);
SILValue addr = SGF.B.createUncheckedAddrCast(E, alloc,
eltTL.getLoweredType().getAddressType());
SILValue storage = SGF.B.createStructElementAddr(E, alloc, storageProperty);
SILValue addr = SGF.B.createVectorBaseAddr(E, storage);
// Cleanups for any elements that have been initialized so far.
SmallVector<CleanupHandle, 8> cleanups;

View File

@@ -37,7 +37,8 @@ func emptyNoncopyable() -> InlineArray<0, Atomic<Int>> {
// CHECK-LABEL: sil{{.*}} @$s19inlinearray_literal7trivials11InlineArrayVy$3_SiGyF : $@convention(thin) () -> InlineArray<4, Int> {
// CHECK: [[SLAB_ALLOC:%.*]] = alloc_stack $InlineArray<4, Int>
// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*Int
// CHECK-NEXT: [[SE:%.*]] = struct_element_addr [[SLAB_ALLOC]], #InlineArray._storage
// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = vector_base_addr [[SE]]
// CHECK-NEXT: [[ELT_0_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 1
// CHECK: [[ELT_0:%.*]] = apply {{%.*}}([[ELT_0_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
// CHECK-NEXT: store [[ELT_0]] to [trivial] [[ELEMENT_PTR]]
@@ -66,7 +67,8 @@ func trivial() -> InlineArray<4, Int> {
// CHECK-LABEL: sil{{.*}} @$s19inlinearray_literal10nontrivials11InlineArrayVy$1_SSGyF : $@convention(thin) () -> @owned InlineArray<2, String> {
// CHECK: [[SLAB_ALLOC:%.*]] = alloc_stack $InlineArray<2, String>
// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*String
// CHECK-NEXT: [[SE:%.*]] = struct_element_addr [[SLAB_ALLOC]], #InlineArray._storage
// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = vector_base_addr [[SE]]
// CHECK-NEXT: [[ELT_0_LITERAL:%.*]] = string_literal utf8 "hello"
// CHECK: [[ELT_0:%.*]] = apply {{%.*}}([[ELT_0_LITERAL]], {{.*}}) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
// CHECK-NEXT: store [[ELT_0]] to [init] [[ELEMENT_PTR]]
@@ -86,7 +88,8 @@ func nontrivial() -> InlineArray<2, String> {
// CHECK-LABEL: sil{{.*}} @$s19inlinearray_literal11noncopyables11InlineArrayVy$1_15Synchronization6AtomicVySiGGyF : $@convention(thin) () -> @out InlineArray<2, Atomic<Int>> {
// CHECK: bb0([[SLAB_RETURN:%.*]] : $*InlineArray<2, Atomic<Int>>):
// CHECK-NEXT: [[SLAB_ALLOC:%.*]] = alloc_stack $InlineArray<2, Atomic<Int>>
// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*Atomic<Int>
// CHECK-NEXT: [[SE:%.*]] = struct_element_addr [[SLAB_ALLOC]], #InlineArray._storage
// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = vector_base_addr [[SE]]
// CHECK: [[ATOMIC_INIT:%.*]] = function_ref @$s15Synchronization6AtomicVyACyxGxcfC
// CHECK-NEXT: [[ELT_0:%.*]] = apply [[ATOMIC_INIT]]<Int>([[ELEMENT_PTR]], {{.*}}) : $@convention(method) <τ_0_0 where τ_0_0 : AtomicRepresentable> (@in τ_0_0, @thin Atomic<τ_0_0>.Type) -> @out Atomic<τ_0_0>
// CHECK: [[ELT_1_OFFSET:%.*]] = integer_literal $Builtin.Word, 1
@@ -109,10 +112,11 @@ func noncopyable() -> InlineArray<2, Atomic<Int>> {
// CHECK-LABEL: sil{{.*}} @$s19inlinearray_literal7closures11InlineArrayVy$0_S2icGyF : $@convention(thin) () -> @owned InlineArray<1, (Int) -> Int> {
// CHECK: [[IA_ALLOC:%.*]] = alloc_stack $InlineArray<1, (Int) -> Int>
// CHECK-NEXT: [[ADDR_CAST:%.*]] = unchecked_addr_cast [[IA_ALLOC]] to $*@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Int, Int>
// CHECK-NEXT: [[SE:%.*]] = struct_element_addr [[IA_ALLOC]], #InlineArray._storage
// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = vector_base_addr [[SE]]
// CHECK: [[FN_REF:%.*]] = function_ref
// CHECK-NEXT: [[THIN_TO_THICK_FN:%.*]] = thin_to_thick_function [[FN_REF]] to $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Int, Int>
// CHECK-NEXT: store [[THIN_TO_THICK_FN]] to [init] [[ADDR_CAST]]
// CHECK-NEXT: store [[THIN_TO_THICK_FN]] to [init] [[ELEMENT_PTR]]
// CHECK-NEXT: [[IA:%.*]] = load [take] [[IA_ALLOC]]
// CHECK-NEXT: dealloc_stack [[IA_ALLOC]]
// CHECK-NEXT: return [[IA]]

View File

@@ -107,7 +107,8 @@ sil_global [let] @g9 : $TwoFields
// CHECK-NEXT: %3 = struct $Int32 (%2)
// CHECK-NEXT: %4 = integer_literal $Builtin.Int32, 3
// CHECK-NEXT: %5 = struct $Int32 (%4)
// CHECK-NEXT: %initval = vector (%1, %3, %5)
// CHECK-NEXT: %6 = vector (%1, %3, %5)
// CHECK-NEXT: %initval = struct $InlineArray<3, Int32> (%6)
// CHECK-NEXT: }
sil_global [let] @inline_array1 : $InlineArray<3, Int32>
@@ -127,7 +128,8 @@ sil_global [let] @inline_array1 : $InlineArray<3, Int32>
// CHECK-NEXT: %12 = integer_literal $Builtin.Int32, 60
// CHECK-NEXT: %13 = struct $Int32 (%12)
// CHECK-NEXT: %14 = tuple (%11, %13)
// CHECK-NEXT: %initval = vector (%4, %9, %14)
// CHECK-NEXT: %15 = vector (%4, %9, %14)
// CHECK-NEXT: %initval = struct $InlineArray<3, (Int32, Int32)> (%15)
// CHECK-NEXT: }
sil_global [let] @inline_array2 : $InlineArray<3, (Int32, Int32)>
@@ -357,8 +359,8 @@ sil [global_init_once_fn] [ossa] @globalinit_inline_array : $@convention(c) (Bui
bb0(%0 : $Builtin.RawPointer):
alloc_global @inline_array1
%2 = global_addr @inline_array1 : $*InlineArray<3, Int32>
%3 = alloc_stack $InlineArray<3, Int32>
%4 = unchecked_addr_cast %3 to $*Int32
%3 = alloc_stack $Builtin.FixedArray<3, Int32>
%4 = vector_base_addr %3
%5 = integer_literal $Builtin.Int32, 1
%6 = struct $Int32 (%5)
store %6 to [trivial] %4
@@ -373,8 +375,9 @@ bb0(%0 : $Builtin.RawPointer):
%16 = struct $Int32 (%15)
store %16 to [trivial] %14
%18 = load [trivial] %3
%19 = struct $InlineArray<3, Int32> (%18)
dealloc_stack %3
store %18 to [trivial] %2
store %19 to [trivial] %2
%21 = tuple ()
return %21
}
@@ -388,8 +391,8 @@ sil [global_init_once_fn] [ossa] @globalinit_inline_array_of_tuples : $@conventi
bb0(%0 : $Builtin.RawPointer):
alloc_global @inline_array2
%2 = global_addr @inline_array2 : $*InlineArray<3, (Int32, Int32)>
%3 = alloc_stack $InlineArray<3, (Int32, Int32)>
%4 = unchecked_addr_cast %3 to $*(Int32, Int32)
%3 = alloc_stack $Builtin.FixedArray<3, (Int32, Int32)>
%4 = vector_base_addr %3
%5 = tuple_element_addr %4, 0
%6 = tuple_element_addr %4, 1
%7 = integer_literal $Builtin.Int32, 10
@@ -419,8 +422,9 @@ bb0(%0 : $Builtin.RawPointer):
%31 = struct $Int32 (%30)
store %31 to [trivial] %26
%33 = load [trivial] %3
%34 = struct $InlineArray<3, (Int32, Int32)> (%33)
dealloc_stack %3
store %33 to [trivial] %2
store %34 to [trivial] %2
%36 = tuple ()
return %36
}
@@ -434,8 +438,8 @@ sil [global_init_once_fn] [ossa] @no_globalinit_double_store: $@convention(c) (B
bb0(%0 : $Builtin.RawPointer):
alloc_global @inline_array3
%2 = global_addr @inline_array3 : $*InlineArray<2, Int32>
%3 = alloc_stack $InlineArray<2, Int32>
%4 = unchecked_addr_cast %3 to $*Int32
%3 = alloc_stack $Builtin.FixedArray<2, Int32>
%4 = vector_base_addr %3
%5 = integer_literal $Builtin.Int32, 1
%6 = struct $Int32 (%5)
store %6 to [trivial] %4
@@ -446,8 +450,9 @@ bb0(%0 : $Builtin.RawPointer):
store %11 to [trivial] %9
store %6 to [trivial] %9
%18 = load [trivial] %3
%19 = struct $InlineArray<2, Int32> (%18)
dealloc_stack %3
store %18 to [trivial] %2
store %19 to [trivial] %2
%21 = tuple ()
return %21
}
@@ -461,8 +466,8 @@ sil [global_init_once_fn] [ossa] @no_globalinit_extra_load: $@convention(c) (Bui
bb0(%0 : $Builtin.RawPointer):
alloc_global @inline_array4
%2 = global_addr @inline_array4 : $*InlineArray<2, Int32>
%3 = alloc_stack $InlineArray<2, Int32>
%4 = unchecked_addr_cast %3 to $*Int32
%3 = alloc_stack $Builtin.FixedArray<2, Int32>
%4 = vector_base_addr %3
%5 = integer_literal $Builtin.Int32, 1
%6 = struct $Int32 (%5)
store %6 to [trivial] %4
@@ -471,8 +476,9 @@ bb0(%0 : $Builtin.RawPointer):
%10 = load [trivial] %4
store %10 to [trivial] %9
%18 = load [trivial] %3
%19 = struct $InlineArray<2, Int32> (%18)
dealloc_stack %3
store %18 to [trivial] %2
store %19 to [trivial] %2
%21 = tuple ()
return %21
}
@@ -486,8 +492,8 @@ sil [global_init_once_fn] [ossa] @no_globalinit_no_load: $@convention(c) (Builti
bb0(%0 : $Builtin.RawPointer):
alloc_global @gint
%2 = global_addr @gint : $*Int32
%3 = alloc_stack $InlineArray<2, Int32>
%4 = unchecked_addr_cast %3 to $*Int32
%3 = alloc_stack $Builtin.FixedArray<2, Int32>
%4 = vector_base_addr %3
%5 = integer_literal $Builtin.Int32, 1
%6 = struct $Int32 (%5)
store %6 to [trivial] %4
@@ -511,11 +517,12 @@ sil [global_init_once_fn] [ossa] @no_globalinit_empty_inline_array : $@conventio
bb0(%0 : $Builtin.RawPointer):
alloc_global @empty_inline_array
%2 = global_addr @empty_inline_array : $*InlineArray<0, Int32>
%3 = alloc_stack $InlineArray<0, Int32>
%4 = unchecked_addr_cast %3 to $*Int32
%3 = alloc_stack $Builtin.FixedArray<0, Int32>
%4 = vector_base_addr %3
%18 = load [trivial] %3
%19 = struct $InlineArray<0, Int32> (%18)
dealloc_stack %3
store %18 to [trivial] %2
store %19 to [trivial] %2
%21 = tuple ()
return %21
}
@@ -529,15 +536,16 @@ sil [global_init_once_fn] [ossa] @no_globalinit_inline_array_empty_elements : $@
bb0(%0 : $Builtin.RawPointer):
alloc_global @inline_array_empty_elements
%2 = global_addr @inline_array_empty_elements : $*InlineArray<3, ()>
%3 = alloc_stack $InlineArray<3, ()>
%4 = unchecked_addr_cast %3 to $*()
%3 = alloc_stack $Builtin.FixedArray<3, ()>
%4 = vector_base_addr %3
%13 = integer_literal $Builtin.Word, 2
%14 = index_addr %4, %13
%15 = tuple ()
store %15 to [trivial] %14
%18 = load [trivial] %3
%19 = struct $InlineArray<3, ()> (%18)
dealloc_stack %3
store %18 to [trivial] %2
store %19 to [trivial] %2
%21 = tuple ()
return %21
}

View File

@@ -25,18 +25,21 @@ struct IntByteAndByte {
struct S {
// CHECK-LABEL: sil_global hidden [let] @$s4test1SV6simples11InlineArrayVy$2_SiGvpZ : $InlineArray<3, Int> = {
// CHECK: %initval = vector
// CHECK: [[V:%.*]] = vector
// CHECK: %initval = struct $InlineArray<3, Int> ([[V]])
// CHECK: }
static let simple: InlineArray = [1, 2, 3]
// CHECK-LABEL: sil_global hidden [let] @$s4test1SV12optionalIntss11InlineArrayVy$2_SiSgGvpZ : $InlineArray<3, Optional<Int>> = {
// CHECK: %initval = vector
// CHECK: [[V:%.*]] = vector
// CHECK: %initval = struct $InlineArray<3, Optional<Int>> ([[V]])
// CHECK: }
static let optionalInts: InlineArray<_, Int?> = [10, 20, 30]
// CHECK-LABEL: sil_global hidden [let] @$s4test1SV13optionalArrays06InlineC0Vy$2_SiGSgvpZ : $Optional<InlineArray<3, Int>> = {
// CHECK: [[V:%.*]] = vector
// CHECK: %initval = enum $Optional<InlineArray<3, Int>>, #Optional.some!enumelt, [[V]]
// CHECK: [[A:%.*]] = struct $InlineArray<3, Int> ([[V]])
// CHECK: %initval = enum $Optional<InlineArray<3, Int>>, #Optional.some!enumelt, [[A]]
// CHECK: }
static let optionalArray: InlineArray? = [1, 2, 3]
@@ -44,13 +47,15 @@ struct S {
// CHECK: [[S0:%.*]] = struct $IntByte
// CHECK: [[S1:%.*]] = struct $IntByte
// CHECK: [[S2:%.*]] = struct $IntByte
// CHECK: %initval = vector ([[S0]], [[S1]], [[S2]])
// CHECK: [[V:%.*]] = vector ([[S0]], [[S1]], [[S2]])
// CHECK: %initval = struct $InlineArray<3, IntByte> ([[V]])
// CHECK: }
static let intBytePairs: InlineArray<_, IntByte> = [IntByte(i: 1, b: 2), IntByte(i: 3, b: 4), IntByte(i: 5, b: 6)]
// CHECK-LABEL: sil_global hidden [let] @$s4test1SV26optionalInlineArrayOfPairss0cD0Vy$2_AA7IntByteVGSgvpZ : $Optional<InlineArray<3, IntByte>> = {
// CHECK: [[V:%.*]] = vector
// CHECK: %initval = enum $Optional<InlineArray<3, IntByte>>, #Optional.some!enumelt, [[V]]
// CHECK: [[A:%.*]] = struct $InlineArray<3, IntByte> ([[V]])
// CHECK: %initval = enum $Optional<InlineArray<3, IntByte>>, #Optional.some!enumelt, [[A]]
// CHECK: }
static let optionalInlineArrayOfPairs: InlineArray<_, IntByte>? = [IntByte(i: 11, b: 12), IntByte(i: 13, b: 14), IntByte(i: 15, b: 16)]
@@ -58,21 +63,27 @@ struct S {
// CHECK: [[T0:%.*]] = tuple
// CHECK: [[T1:%.*]] = tuple
// CHECK: [[T2:%.*]] = tuple
// CHECK: %initval = vector ([[T0]], [[T1]], [[T2]])
// CHECK: [[V:%.*]] = vector ([[T0]], [[T1]], [[T2]])
// CHECK: %initval = struct $InlineArray<3, (Int, Int)> ([[V]])
// CHECK: }
static let tuples: InlineArray = [(10, 20), (30, 40), (50, 60)]
// CHECK-LABEL: sil_global hidden [let] @$s4test1SV6nesteds11InlineArrayVy$2_AFy$1_SiGGvpZ : $InlineArray<3, InlineArray<2, Int>> = {
// CHECK: [[V0:%.*]] = vector
// CHECK: [[A0:%.*]] = struct $InlineArray<2, Int> ([[V0]])
// CHECK: [[V1:%.*]] = vector
// CHECK: [[A1:%.*]] = struct $InlineArray<2, Int> ([[V1]])
// CHECK: [[V2:%.*]] = vector
// CHECK: %initval = vector ([[V0]], [[V1]], [[V2]])
// CHECK: [[A2:%.*]] = struct $InlineArray<2, Int> ([[V2]])
// CHECK: [[V:%.*]] = vector ([[A0]], [[A1]], [[A2]])
// CHECK: %initval = struct $InlineArray<3, InlineArray<2, Int>> ([[V]])
// CHECK: }
static let nested: InlineArray<3, InlineArray<2, Int>> = [[100, 200], [300, 400], [500, 600]]
// CHECK-LABEL: sil_global hidden [let] @$s4test1SV010intByteAndC0AA03IntcdC0VvpZ : $IntByteAndByte = {
// CHECK: [[V:%.*]] = vector
// CHECK: %initval = struct $IntByteAndByte ([[V]],
// CHECK: [[A:%.*]] = struct $InlineArray<3, IntByte> ([[V]])
// CHECK: %initval = struct $IntByteAndByte ([[A]],
// CHECK: }
static let intByteAndByte = IntByteAndByte(a: [IntByte(i: 1, b: 2), IntByte(i: 3, b: 4), IntByte(i: 5, b: 6)], x: 27)
}