Skip to content

Commit b3cd553

Browse files
authored
Merge pull request #67534 from eeckstein/fix-24-bit-enums
IRGen: fix a problem with 24-bit enum payloads in statically initialized global variables
2 parents 2fa808c + a3822cd commit b3cd553

File tree

3 files changed

+73
-3
lines changed

3 files changed

+73
-3
lines changed

lib/IRGen/EnumPayload.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,22 @@ EnumPayload EnumPayload::fromExplosion(IRGenModule &IGM,
163163

164164
schema.forEachType(IGM, [&](llvm::Type *type) {
165165
auto next = in.claimNext();
166-
assert(next->getType() == type && "explosion doesn't match payload schema");
167-
result.PayloadValues.push_back(next);
166+
if (next->getType() == type) {
167+
result.PayloadValues.push_back(next);
168+
} else {
169+
// The original value had an unaligned integer size and was replaced by
170+
// byte values in `replaceUnalignedIntegerValues`.
171+
// This is done for enums in statically initialized global variables.
172+
unsigned bitSize = cast<llvm::IntegerType>(type)->getBitWidth();
173+
assert(bitSize % 8 == 0);
174+
assert(cast<llvm::ConstantInt>(next)->getBitWidth() == 8);
175+
result.PayloadValues.push_back(next);
176+
for (unsigned byte = 1; byte < bitSize / 8; ++byte) {
177+
auto nextByte = in.claimNext();
178+
assert(cast<llvm::ConstantInt>(nextByte)->getBitWidth() == 8);
179+
result.PayloadValues.push_back(nextByte);
180+
}
181+
}
168182
});
169183

170184
return result;

test/SILOptimizer/static_enums.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,16 @@ public let success: R = .success(27)
171171
// CHECK-LABEL: sil_global hidden @$s4test10optSuccessAA1ROSgvp : $Optional<R> = {
172172
var optSuccess: R? = success
173173

174+
public enum Color {
175+
case black
176+
case rgb(r: UInt8, g: UInt8, b: UInt8)
177+
}
178+
179+
// CHECK-LABEL: sil_global hidden @$s4test8optBlackAA5ColorOSgvp : $Optional<Color> = {
180+
var optBlack: Color? = Color.black
181+
// CHECK-LABEL: sil_global hidden @$s4test9optSalmonAA5ColorOSgvp : $Optional<Color> = {
182+
var optSalmon: Color? = Color.rgb(r: 0xfa, g: 0x80, b: 0x72)
183+
174184
// CHECK-LABEL: sil_global private @$s4test9createArrSaySiSgGyFTv_ : $_ContiguousArrayStorage<Optional<Int>> = {
175185
@inline(never)
176186
func createArr() -> [Int?] {
@@ -246,6 +256,10 @@ struct Main {
246256
print("stringGen3: \(getStringGen(sg3))")
247257
// CHECK-OUTPUT: optSuccess: Optional(test.R.success(27))
248258
print("optSuccess:", optSuccess as Any)
259+
// CHECK-OUTPUT: optBlack: Optional(test.Color.black)
260+
print("optBlack:", optBlack as Any)
261+
// CHECK-OUTPUT: optSalmon: Optional(test.Color.rgb(r: 250, g: 128, b: 114))
262+
print("optSalmon:", optSalmon as Any)
249263
}
250264
}
251265

validation-test/SILOptimizer/static_enums_fuzzing.swift

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ var typeDefinitions: String {
7979
case C
8080
}
8181
82+
public enum E24 {
83+
case A
84+
case B(UInt8, UInt8, UInt8)
85+
}
86+
8287
public func fn() {}
8388
8489
public typealias Func = () -> ()
@@ -322,6 +327,42 @@ struct MultiPayloadEnum : Value {
322327
var containsEnum: Bool { true }
323328
}
324329

330+
struct Size24Enum : Value {
331+
let caseIdx: Int
332+
333+
init(generator: inout RandomGenerator, depth: Int) {
334+
self.caseIdx = Int.random(in: 0..<2, using: &generator)
335+
}
336+
337+
func getType() -> String {
338+
"E24"
339+
}
340+
341+
func getInitValue() -> String {
342+
switch caseIdx {
343+
case 0: return "E24.A"
344+
case 1: return "E24.B(250, 128, 114)"
345+
default: fatalError()
346+
}
347+
}
348+
349+
func getExpectedOutput(topLevel: Bool) -> String {
350+
let prefix = topLevel ? "" : "\(getRuntimeTypeName(topLevel: topLevel))."
351+
switch caseIdx {
352+
case 0: return "\(prefix)A"
353+
case 1: return "\(prefix)B(250, 128, 114)"
354+
default: fatalError()
355+
}
356+
}
357+
358+
func getRuntimeTypeName(topLevel: Bool) -> String {
359+
let prefix = topLevel ? "" : "test."
360+
return "\(prefix)E24"
361+
}
362+
363+
var containsEnum: Bool { true }
364+
}
365+
325366
// Can't use the default random generator becaus we need deterministic results
326367
struct RandomGenerator : RandomNumberGenerator {
327368
var state: (UInt64, UInt64, UInt64, UInt64) = (15042304078070129153, 10706435816813474385, 14710304063852993123, 11070704559760783939)
@@ -360,7 +401,8 @@ struct RandomGenerator : RandomNumberGenerator {
360401
SmallString.self,
361402
LargeString.self,
362403
Function.self,
363-
Enum.self
404+
Enum.self,
405+
Size24Enum.self
364406
]
365407
private static let allValueTypes: [any Value.Type] = allTerminalTypes + [
366408
OptionalValue.self,

0 commit comments

Comments
 (0)