From 1a10f857826515433aca6993abf1347b4cc00c79 Mon Sep 17 00:00:00 2001 From: Dario Rexin Date: Tue, 26 Aug 2025 13:12:38 -0700 Subject: [PATCH] [IRGen] Fix computation of spare bits for fixed arrays rdar://159143492 Previously all bits after the spare bits of the first element were marked as spare bits. This caused enum tags to be stored in bits used by the payload. --- lib/IRGen/GenArray.cpp | 10 ++++- test/IRGen/inline_array_enum_tags.swift | 44 +++++++++++++++++++ test/Interpreter/inline_array_enum_tags.swift | 35 +++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 test/IRGen/inline_array_enum_tags.swift create mode 100644 test/Interpreter/inline_array_enum_tags.swift diff --git a/lib/IRGen/GenArray.cpp b/lib/IRGen/GenArray.cpp index c96ea16bf7845..b95766f74e5e7 100644 --- a/lib/IRGen/GenArray.cpp +++ b/lib/IRGen/GenArray.cpp @@ -248,9 +248,15 @@ class FixedArrayTypeInfoBase : public ArrayTypeInfoBase { // Take spare bits from the first element only. SpareBitVector result = elementTI.getSpareBits(); + // We can use the padding to the next element as spare bits too. - result.appendSetBits(getArraySize(arraySize, elementTI).getValueInBits() - - result.size()); + auto padding = elementTI.getFixedStride() - elementTI.getFixedSize(); + result.appendSetBits(padding.getValueInBits()); + + // spare bits of any other elements should not be considered + result.appendClearBits( + getArraySize(arraySize - 1, elementTI).getValueInBits()); + return result; } diff --git a/test/IRGen/inline_array_enum_tags.swift b/test/IRGen/inline_array_enum_tags.swift new file mode 100644 index 0000000000000..31c314ab1aa13 --- /dev/null +++ b/test/IRGen/inline_array_enum_tags.swift @@ -0,0 +1,44 @@ +// RUN: %target-swift-frontend -disable-availability-checking -O -emit-ir %s | %FileCheck %s + +// UNSUPPORTED: PTRSIZE=32 + +public struct Foo { + let x: UInt64 + let y: InlineArray<2, UInt64> +} + +public struct Bar { + let x: UInt64 + let y: [UInt64] +} + +// CHECK: define {{.*}} i32 @"$s22inline_array_enum_tags3BazOwug"(ptr noalias nocapture readonly %value, ptr nocapture readnone %Baz) +// CHECK: [[TAG_ADDR:%.*]] = getelementptr inbounds i8, ptr %value, i64 24 +// CHECK: [[TAG_VAL:%.*]] = load i1, ptr [[TAG_ADDR]], align 8 +// CHECK: [[TAG_EXT:%.*]] = zext i1 [[TAG_VAL]] to i32 +// CHECK: ret i32 [[TAG_EXT]] +// CHECK: } +public enum Baz { + case foo(Foo) + case bar(Bar) +} + +public struct Padded { + let x: UInt64 + let y: InlineArray<2, (UInt16, UInt8)> +} + + +// CHECK: define {{.*}} i32 @"$s22inline_array_enum_tags17WithPaddedPayloadOwug"(ptr noalias nocapture readonly %value, ptr nocapture readnone %WithPaddedPayload) +// CHECK: entry: +// CHECK: [[ADDR:%.*]] = getelementptr inbounds i8, ptr %value, i64 8 +// CHECK: [[VAL:%.*]] = load i64, ptr [[ADDR]], align 8 +// CHECK: [[MASKED:%.*]] = and i64 [[VAL]], 2147483648 +// CHECK: [[TAG:%.*]] = icmp ne i64 [[MASKED]], 0 +// CHECK: [[EXTENDED:%.*]] = zext i1 [[TAG]] to i32 +// CHECK: ret i32 [[EXTENDED]] +// CHECK: } +public enum WithPaddedPayload { + case a(Padded) + case b(Padded) +} diff --git a/test/Interpreter/inline_array_enum_tags.swift b/test/Interpreter/inline_array_enum_tags.swift new file mode 100644 index 0000000000000..32fc9493663c0 --- /dev/null +++ b/test/Interpreter/inline_array_enum_tags.swift @@ -0,0 +1,35 @@ +// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking) | %FileCheck %s +// RUN: %target-run-simple-swift(-O -Xfrontend -disable-availability-checking) | %FileCheck %s + +// REQUIRES: executable_test + +// UNSUPPORTED: back_deployment_runtime || use_os_stdlib + +struct Foo { + let x: UInt64 + let y: InlineArray<2, UInt64> +} + +struct Bar { + let x: UInt64 + let y: [UInt64] +} + +enum Baz { + case foo(Foo) + case bar(Bar) +} + +@inline(never) +func createEnum() -> Baz { + return .foo(Foo(x: 0, y: [0, 0xff00000000000000])) +} + + +let x = createEnum() + +// CHECK: 0 - 18374686479671623680 +switch x { + case .bar: fatalError("Expected .foo") + case .foo(let x): print("\(x.y[0]) - \(x.y[1])") +}