Skip to content

IRGen: fix a problem with 24-bit enum payloads in statically initialized global variables #67534

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions lib/IRGen/EnumPayload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,22 @@ EnumPayload EnumPayload::fromExplosion(IRGenModule &IGM,

schema.forEachType(IGM, [&](llvm::Type *type) {
auto next = in.claimNext();
assert(next->getType() == type && "explosion doesn't match payload schema");
result.PayloadValues.push_back(next);
if (next->getType() == type) {
result.PayloadValues.push_back(next);
} else {
// The original value had an unaligned integer size and was replaced by
// byte values in `replaceUnalignedIntegerValues`.
// This is done for enums in statically initialized global variables.
unsigned bitSize = cast<llvm::IntegerType>(type)->getBitWidth();
assert(bitSize % 8 == 0);
assert(cast<llvm::ConstantInt>(next)->getBitWidth() == 8);
result.PayloadValues.push_back(next);
for (unsigned byte = 1; byte < bitSize / 8; ++byte) {
auto nextByte = in.claimNext();
assert(cast<llvm::ConstantInt>(nextByte)->getBitWidth() == 8);
result.PayloadValues.push_back(nextByte);
}
}
});

return result;
Expand Down
14 changes: 14 additions & 0 deletions test/SILOptimizer/static_enums.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ public let success: R = .success(27)
// CHECK-LABEL: sil_global hidden @$s4test10optSuccessAA1ROSgvp : $Optional<R> = {
var optSuccess: R? = success

public enum Color {
case black
case rgb(r: UInt8, g: UInt8, b: UInt8)
}

// CHECK-LABEL: sil_global hidden @$s4test8optBlackAA5ColorOSgvp : $Optional<Color> = {
var optBlack: Color? = Color.black
// CHECK-LABEL: sil_global hidden @$s4test9optSalmonAA5ColorOSgvp : $Optional<Color> = {
var optSalmon: Color? = Color.rgb(r: 0xfa, g: 0x80, b: 0x72)

// CHECK-LABEL: sil_global private @$s4test9createArrSaySiSgGyFTv_ : $_ContiguousArrayStorage<Optional<Int>> = {
@inline(never)
func createArr() -> [Int?] {
Expand Down Expand Up @@ -246,6 +256,10 @@ struct Main {
print("stringGen3: \(getStringGen(sg3))")
// CHECK-OUTPUT: optSuccess: Optional(test.R.success(27))
print("optSuccess:", optSuccess as Any)
// CHECK-OUTPUT: optBlack: Optional(test.Color.black)
print("optBlack:", optBlack as Any)
// CHECK-OUTPUT: optSalmon: Optional(test.Color.rgb(r: 250, g: 128, b: 114))
print("optSalmon:", optSalmon as Any)
}
}

Expand Down
44 changes: 43 additions & 1 deletion validation-test/SILOptimizer/static_enums_fuzzing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ var typeDefinitions: String {
case C
}

public enum E24 {
case A
case B(UInt8, UInt8, UInt8)
}

public func fn() {}

public typealias Func = () -> ()
Expand Down Expand Up @@ -322,6 +327,42 @@ struct MultiPayloadEnum : Value {
var containsEnum: Bool { true }
}

struct Size24Enum : Value {
let caseIdx: Int

init(generator: inout RandomGenerator, depth: Int) {
self.caseIdx = Int.random(in: 0..<2, using: &generator)
}

func getType() -> String {
"E24"
}

func getInitValue() -> String {
switch caseIdx {
case 0: return "E24.A"
case 1: return "E24.B(250, 128, 114)"
default: fatalError()
}
}

func getExpectedOutput(topLevel: Bool) -> String {
let prefix = topLevel ? "" : "\(getRuntimeTypeName(topLevel: topLevel))."
switch caseIdx {
case 0: return "\(prefix)A"
case 1: return "\(prefix)B(250, 128, 114)"
default: fatalError()
}
}

func getRuntimeTypeName(topLevel: Bool) -> String {
let prefix = topLevel ? "" : "test."
return "\(prefix)E24"
}

var containsEnum: Bool { true }
}

// Can't use the default random generator becaus we need deterministic results
struct RandomGenerator : RandomNumberGenerator {
var state: (UInt64, UInt64, UInt64, UInt64) = (15042304078070129153, 10706435816813474385, 14710304063852993123, 11070704559760783939)
Expand Down Expand Up @@ -360,7 +401,8 @@ struct RandomGenerator : RandomNumberGenerator {
SmallString.self,
LargeString.self,
Function.self,
Enum.self
Enum.self,
Size24Enum.self
]
private static let allValueTypes: [any Value.Type] = allTerminalTypes + [
OptionalValue.self,
Expand Down