Skip to content

Commit

Permalink
Merge pull request #20643 from lorentey/string-32-simple
Browse files Browse the repository at this point in the history
[stdlib] _StringObject: Use a full 8-bit discriminator on 32-bit platforms
  • Loading branch information
lorentey committed Nov 20, 2018
2 parents f6985b6 + ef76bcf commit 694b153
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 46 deletions.
49 changes: 12 additions & 37 deletions stdlib/public/core/StringObject.swift
Expand Up @@ -137,7 +137,7 @@ internal struct _StringObject {
internal var _variant: Variant

@usableFromInline
internal var _discriminator: Builtin.Int7
internal var _discriminator: Discriminator

@usableFromInline
internal var _flags: Flags
Expand All @@ -149,11 +149,9 @@ internal struct _StringObject {
discriminator: Discriminator,
flags: Flags
) {
_internalInvariant(variant.isImmortal == discriminator.isImmortal)
self._count = count
self._variant = variant
self._discriminator =
Builtin.truncOrBitCast_Int8_Int7(discriminator._value._value)
self._discriminator = discriminator
self._flags = flags
}

Expand Down Expand Up @@ -197,20 +195,11 @@ internal struct _StringObject {
}

extension _StringObject {
#if arch(i386) || arch(arm)
@inlinable @inline(__always)
internal func discriminator(isImmortal: Bool) -> Discriminator {
let lowBits = UInt8(Builtin.zextOrBitCast_Int7_Int8(_discriminator))
guard isImmortal else { return Discriminator(lowBits) }
return Discriminator(lowBits | 0x80)
}
#endif

@inlinable
internal var discriminator: Discriminator {
@inline(__always) get {
#if arch(i386) || arch(arm)
return self.discriminator(isImmortal: _variant.isImmortal)
return _discriminator
#else
let d = objectRawBits &>> Nibbles.discriminatorShift
return Discriminator(UInt8(truncatingIfNeeded: d))
Expand All @@ -233,7 +222,7 @@ extension _StringObject {
let count = UInt64(truncatingIfNeeded: UInt(bitPattern: _count))
let payload = UInt64(truncatingIfNeeded: undiscriminatedObjectRawBits)
let flags = UInt64(truncatingIfNeeded: _flags._value)
let discr = UInt64(truncatingIfNeeded: discriminator._value)
let discr = UInt64(truncatingIfNeeded: _discriminator._value)
if isSmall {
// Rearrange small strings in a different way, compacting bytes into a
// contiguous sequence. See comment on small string layout below.
Expand Down Expand Up @@ -636,9 +625,7 @@ extension _StringObject {
internal var isSmall: Bool {
@inline(__always) get {
#if arch(i386) || arch(arm)
// Note: This assumes that the `isSmall` predicate doesn't look at the
// immortal bit. We may or may not actually be immortal.
return discriminator(isImmortal: true).isSmall
return _discriminator.isSmall
#else
return (objectRawBits & 0x2000_0000_0000_0000) != 0
#endif
Expand All @@ -658,9 +645,7 @@ extension _StringObject {
internal var providesFastUTF8: Bool {
@inline(__always) get {
#if arch(i386) || arch(arm)
// Note: This assumes that the `providesFastUTF8` predicate doesn't look
// at the immortal bit. We may or may not actually be immortal.
return discriminator(isImmortal: false).providesFastUTF8
return _discriminator.providesFastUTF8
#else
return (objectRawBits & 0x1000_0000_0000_0000) == 0
#endif
Expand All @@ -677,7 +662,7 @@ extension _StringObject {
internal var hasNativeStorage: Bool {
@inline(__always) get {
#if arch(i386) || arch(arm)
return discriminator.hasNativeStorage
return _discriminator.hasNativeStorage
#else
return (objectRawBits & 0xF800_0000_0000_0000) == 0
#endif
Expand All @@ -688,7 +673,7 @@ extension _StringObject {
internal var hasSharedStorage: Bool {
@inline(__always) get {
#if arch(i386) || arch(arm)
return discriminator.hasSharedStorage
return _discriminator.hasSharedStorage
#else
return (objectRawBits & 0xF800_0000_0000_0000)
== Nibbles.largeSharedMortal()
Expand All @@ -705,9 +690,7 @@ extension _StringObject {
@inline(__always) get {
_internalInvariant(isLarge && providesFastUTF8)
#if arch(i386) || arch(arm)
// Note: This assumes that the `largeFastIsNative` predicate doesn't look
// at the immortal bit. We may or may not actually be immortal.
return discriminator(isImmortal: false).largeFastIsNative
return _discriminator.largeFastIsNative
#else
return (objectRawBits & 0x0800_0000_0000_0000) == 0
#endif
Expand All @@ -726,9 +709,7 @@ extension _StringObject {
@inline(__always) get {
_internalInvariant(isLarge)
#if arch(i386) || arch(arm)
// Note: This assumes that the `largeIsCocoa` predicate doesn't look at
// the immortal bit. We may or may not actually be immortal.
return discriminator(isImmortal: false).largeIsCocoa
return _discriminator.largeIsCocoa
#else
return (objectRawBits & 0x4000_0000_0000_0000) != 0
#endif
Expand Down Expand Up @@ -770,12 +751,7 @@ extension _StringObject {
@inline(__always)
get {
_internalInvariant(isSmall)
#if arch(i386) || arch(arm)
// Note: This assumes that `isSmall` implies that we're immortal.
return discriminator(isImmortal: true).smallCount
#else
return discriminator.smallCount
#endif
}
}

Expand All @@ -785,8 +761,7 @@ extension _StringObject {
get {
_internalInvariant(isSmall)
#if arch(i386) || arch(arm)
// Note: This assumes that `isSmall` implies that we're immortal.
return discriminator(isImmortal: true).smallIsASCII
return _discriminator.smallIsASCII
#else
return objectRawBits & 0x4000_0000_0000_0000 != 0
#endif
Expand Down Expand Up @@ -1320,7 +1295,7 @@ extension _StringObject {
<\(word0) \(word1)> \
count: \(String(_count, radix: 16)), \
variant: \(_variant), \
discriminator: \(discriminator), \
discriminator: \(_discriminator), \
flags: \(_flags))
""")
#else
Expand Down
19 changes: 11 additions & 8 deletions test/SILOptimizer/concat_string_literals.32.swift
Expand Up @@ -9,15 +9,15 @@

// NOTE: 25185.byteSwapped = 0x62 'a', 0x61 'b'
// CHECK-LABEL: test_ascii_scalar_scalar2
// CHECK: insertvalue { i32, i32, i32 } { i32 25185,
// CHECK: ret { i32, i32, i32 } { i32 25185, i32 0, i32 {{[0-9]+}} }
public func test_ascii_scalar_scalar2() -> String {
return "a" + "b"
}


// NOTE: 11125601.byteSwapped = 0x61 'a', 0xC3 0xA9 'é'
// CHECK-LABEL: test_scalar_otherscalar
// CHECK: insertvalue { i32, i32, i32 } { i32 11125601,
// CHECK: ret { i32, i32, i32 } { i32 11125601, i32 0, i32 {{[0-9]+}} }
public func test_scalar_otherscalar() -> String {
return "a" + "é"
}
Expand All @@ -26,44 +26,47 @@ public func test_scalar_otherscalar() -> String {
// NOTE: -8097488946593795999 = 0x8f9ff0b4959ff061
// NOTE: -1784680351 = 0x959ff061, -1885343564 = 0x8f9ff0b4
// CHECK-LABEL: test_scalar_char
// CHECK: insertvalue { i32, i32, i32 } { i32 -1784680351, i32 -1885343564,
// CHECK: ret { i32, i32, i32 } { i32 -1784680351, i32 -1885343564, i32 {{[0-9]+}} }
public func test_scalar_char() -> String {
return "a" + "🕴🏿"
}

// NOTE: 112585666577249.byteSwapped = 0x61 'a', 0xc3 0xa9 'é', 0x64 'd', 0x65 'e', 0x66 'f'
// NOTE: 112585666577249 = 1688847201 + (26213 << 32)
// CHECK-LABEL: test_strng_strng2
// CHECK: insertvalue { i32, i32, i32 } { i32 1688847201, i32 26213,
// CHECK: ret { i32, i32, i32 } { i32 1688847201, i32 26213, i32 {{[0-9]+}} }
public func test_strng_strng2() -> String {
return "" + "def"
}

// NOTE: 43 = code-unit length
// NOTE: 20 = native bias
// CHECK-LABEL: test_scalar_strng
// CHECK: insertvalue { i32, i32, i32 } { i32 43, i32 sub
// CHECK: ret { i32, i32, i32 } { i32 43, i32 sub (i32 {{.*}}, i32 20)
public func test_scalar_strng() -> String {
return "a" + "👨🏿‍💼+🧙🏿‍♂️=🕴🏿"
}

// NOTE: 7450828190687388257.byteSwapped = 0x61 'a', 0x62 'b', 0x63 'c', 0x64 'd', 0xC3 0xA8 'è', 0x66 'f', 0x67 'g', ...
// NOTE: 1684234849 = 0x64636261, 1734781123 = 0x6766a8c3
// CHECK-LABEL test_strng_concat_smol
// CHECK: insertvalue { i32, i32, i32 } { i32 1684234849, i32 1734781123,
// CHECK: ret { i32, i32, i32 } { i32 1684234849, i32 1734781123,
public func test_strng_concat_smol() -> String {
return "a" + "bc" + "dèf" + ""
}

// NOTE: 11 = code-unit length
// NOTE: 20 = native bias
// CHECK-LABEL test_strng_concat_not_quite_smol
// CHECK: insertvalue { i32, i32, i32 } { i32 11, i32 sub
// CHECK: ret { i32, i32, i32 } { i32 11, i32 sub (i32 {{.*}}, i32 20)
public func test_strng_concat_not_quite_smol() -> String {
return "a" + "bc" + "dèf" + "ghī"
}

// NOTE: 23 = code-unit length
// NOTE: 20 = native bias
// CHECK-LABEL test_strng_concat_large
// CHECK: insertvalue { i32, i32, i32 } { i32 23, i32 sub
// CHECK: ret { i32, i32, i32 } { i32 23, i32 sub (i32 {{.*}}, i32 20)
public func test_strng_concat_large() -> String {
return "a" + "bc" + "dèf" + "ghī" + "jklmn" + "o" + "𝛒qr"
}
2 changes: 1 addition & 1 deletion validation-test/Reflection/reflect_String.swift
Expand Up @@ -49,7 +49,7 @@ reflect(object: obj)
// CHECK-32-NEXT: (multi_payload_enum size=5 alignment=4 stride=8 num_extra_inhabitants=253 bitwise_takable=1
// (unstable implementation details omitted)
// CHECK-32: (field name=_discriminator offset=9
// CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=128 bitwise_takable=1
// CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1
// (unstable implementation details omitted)
// CHECK-32: (field name=_flags offset=10
// CHECK-32-NEXT: (struct size=2 alignment=2 stride=2 num_extra_inhabitants=0 bitwise_takable=1
Expand Down

0 comments on commit 694b153

Please sign in to comment.