Skip to content

Optimizer/IRGen: allow enums in static initializers of globals #66118

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 6 commits into from
May 26, 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
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ swift_compiler_sources(Optimizer
SimplifyDebugStep.swift
SimplifyDestructure.swift
SimplifyGlobalValue.swift
SimplifyInitEnumDataAddr.swift
SimplifyLoad.swift
SimplifyPartialApply.swift
SimplifyStrongRetainRelease.swift
SimplifyStructExtract.swift
SimplifyTupleExtract.swift
SimplifyUncheckedEnumData.swift)
SimplifyUncheckedEnumData.swift
SimplifyValueToBridgeObject.swift)
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===--- SimplifyInitEnumDataAddr.swift -----------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import SIL

extension InitEnumDataAddrInst : OnoneSimplifyable {
func simplify(_ context: SimplifyContext) {

// Optimize the sequence
// ```
// %1 = init_enum_data_addr %enum_addr, #someCaseWithPayload
// store %payload to %1
// inject_enum_addr %enum_addr, #someCaseWithPayload
// ```
// to
// ```
// %1 = enum $E, #someCaseWithPayload, %payload
// store %1 to %enum_addr
// ```
// This sequence of three instructions must appear in consecutive order.
// But usually this is the case, because it's generated this way by SILGen.
//
if let nextInst = self.next,
let store = nextInst as? StoreInst,
store.destination == self,
let singleUse = self.uses.singleUse,
singleUse.instruction == store,
let nextAfterStore = store.next,
let inject = nextAfterStore as? InjectEnumAddrInst,
inject.enum == self.enum,
inject.enum.type.isLoadable(in: parentFunction) {

assert(self.caseIndex == inject.caseIndex, "mismatching case indices when creating an enum")

let builder = Builder(before: store, context)
let enumInst = builder.createEnum(caseIndex: self.caseIndex, payload: store.source, enumType: self.enum.type.objectType)
let storeOwnership = StoreInst.Ownership(for: self.enum.type, in: parentFunction, initialize: true)
builder.createStore(source: enumInst, destination: self.enum, ownership: storeOwnership)
context.erase(instruction: store)
context.erase(instruction: inject)
context.erase(instruction: self)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===--- SimplifyValueToBridgeObject.swift --------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import SIL

extension ValueToBridgeObjectInst : OnoneSimplifyable {
func simplify(_ context: SimplifyContext) {

// Optimize the sequence
// ```
// %1 = value_to_bridge_object %0
// %2 = struct $SomeInt (%1)
// %3 = unchecked_trivial_bit_cast %2
// %4 = struct_extract %3, #valueFieldInInt
// %5 = value_to_bridge_object %4
// ```
// to
// ```
// %5 = value_to_bridge_object %0
// ```
// This sequence comes up in the code for constructing an empty string literal.
//
if let se = self.value as? StructExtractInst,
let utbc = se.struct as? UncheckedTrivialBitCastInst,
let vtbo = utbc.fromValue as? ValueToBridgeObjectInst {
self.operand.set(to: vtbo.value, context)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,7 @@ struct FunctionPassContext : MutatingContext {
var notifyInstructionChanged: (Instruction) -> () { return { inst in } }

func continueWithNextSubpassRun(for inst: Instruction? = nil) -> Bool {
let bridgedInst = OptionalBridgedInstruction(inst?.bridged.obj)
return _bridged.continueWithNextSubpassRun(bridgedInst)
return _bridged.continueWithNextSubpassRun(inst.bridged)
}

func createSimplifyContext(preserveDebugInfo: Bool, notifyInstructionChanged: @escaping (Instruction) -> ()) -> SimplifyContext {
Expand Down
15 changes: 12 additions & 3 deletions SwiftCompilerSources/Sources/SIL/Builder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public struct Builder {
return notifyNew(cast.getAs(UpcastInst.self))
}

public func createLoad(fromAddress: Value, ownership: LoadInst.LoadOwnership) -> LoadInst {
public func createLoad(fromAddress: Value, ownership: LoadInst.Ownership) -> LoadInst {
let load = bridged.createLoad(fromAddress.bridged, ownership.rawValue)
return notifyNew(load.getAs(LoadInst.self))
}
Expand Down Expand Up @@ -184,6 +184,12 @@ public struct Builder {
let ued = bridged.createUncheckedEnumData(enumVal.bridged, caseIndex, resultType.bridged)
return notifyNew(ued.getAs(UncheckedEnumDataInst.self))
}

public func createEnum(caseIndex: Int, payload: Value?, enumType: Type) -> EnumInst {
let enumInst = bridged.createEnum(caseIndex, payload.bridged, enumType.bridged)
return notifyNew(enumInst.getAs(EnumInst.self))
}

@discardableResult
public func createSwitchEnum(enum enumVal: Value,
cases: [(Int, BasicBlock)],
Expand Down Expand Up @@ -225,20 +231,23 @@ public struct Builder {
return notifyNew(bridged.createGlobalValue(global.bridged).getAs(GlobalValueInst.self))
}

@discardableResult
public func createStruct(type: Type, elements: [Value]) -> StructInst {
let structInst = elements.withBridgedValues { valuesRef in
return bridged.createStruct(type.bridged, valuesRef)
}
return notifyNew(structInst.getAs(StructInst.self))
}

@discardableResult
public func createTuple(type: Type, elements: [Value]) -> TupleInst {
let tuple = elements.withBridgedValues { valuesRef in
return bridged.createTuple(type.bridged, valuesRef)
}
return notifyNew(tuple.getAs(TupleInst.self))
}

@discardableResult
public func createStore(source: Value, destination: Value, ownership: StoreInst.Ownership) -> StoreInst {
let store = bridged.createStore(source.bridged, destination.bridged, ownership.rawValue)
return notifyNew(store.getAs(StoreInst.self))
}
}
1 change: 1 addition & 0 deletions SwiftCompilerSources/Sources/SIL/GlobalVariable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ extension Instruction {
return !fri.referencedFunction.isAsync
case is StructInst,
is TupleInst,
is EnumInst,
is IntegerLiteralInst,
is FloatLiteralInst,
is ObjectInst,
Expand Down
39 changes: 32 additions & 7 deletions SwiftCompilerSources/Sources/SIL/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ extension OptionalBridgedInstruction {
}
}

extension Optional where Wrapped == Instruction {
public var bridged: OptionalBridgedInstruction {
OptionalBridgedInstruction(self?.bridged.obj)
}
}

public class SingleValueInstruction : Instruction, Value {
final public var definingInstruction: Instruction? { self }

Expand Down Expand Up @@ -222,11 +228,23 @@ extension StoringInstruction {

final public class StoreInst : Instruction, StoringInstruction {
// must match with enum class StoreOwnershipQualifier
public enum StoreOwnership: Int {
public enum Ownership: Int {
case unqualified = 0, initialize = 1, assign = 2, trivial = 3

public init(for type: Type, in function: Function, initialize: Bool) {
if function.hasOwnership {
if type.isTrivial(in: function) {
self = .trivial
} else {
self = initialize ? .initialize : .assign
}
} else {
self = .unqualified
}
}
}
public var destinationOwnership: StoreOwnership {
StoreOwnership(rawValue: bridged.StoreInst_getStoreOwnership())!
public var destinationOwnership: Ownership {
Ownership(rawValue: bridged.StoreInst_getStoreOwnership())!
}
}

Expand Down Expand Up @@ -307,6 +325,7 @@ final public class DestroyAddrInst : Instruction, UnaryInstruction {
}

final public class InjectEnumAddrInst : Instruction, UnaryInstruction, EnumInstruction {
public var `enum`: Value { operand.value }
public var caseIndex: Int { bridged.InjectEnumAddrInst_caseIndex() }
}

Expand Down Expand Up @@ -351,11 +370,11 @@ final public class LoadInst : SingleValueInstruction, UnaryInstruction {
public var address: Value { operand.value }

// must match with enum class LoadOwnershipQualifier
public enum LoadOwnership: Int {
public enum Ownership: Int {
case unqualified = 0, take = 1, copy = 2, trivial = 3
}
public var ownership: LoadOwnership {
LoadOwnership(rawValue: bridged.LoadInst_getLoadOwnership())!
public var ownership: Ownership {
Ownership(rawValue: bridged.LoadInst_getLoadOwnership())!
}
}

Expand Down Expand Up @@ -388,6 +407,10 @@ final public class UncheckedAddrCastInst : SingleValueInstruction, UnaryInstruct
public var fromAddress: Value { operand.value }
}

final public class UncheckedTrivialBitCastInst : SingleValueInstruction, UnaryInstruction {
public var fromValue: Value { operand.value }
}

final public
class RawPointerToRefInst : SingleValueInstruction, UnaryInstruction {
public var pointer: Value { operand.value }
Expand Down Expand Up @@ -626,7 +649,9 @@ final public
class ObjCMetatypeToObjectInst : SingleValueInstruction, UnaryInstruction {}

final public
class ValueToBridgeObjectInst : SingleValueInstruction, UnaryInstruction {}
class ValueToBridgeObjectInst : SingleValueInstruction, UnaryInstruction {
public var value: Value { return operand.value }
}

final public
class MarkDependenceInst : SingleValueInstruction {
Expand Down
1 change: 1 addition & 0 deletions SwiftCompilerSources/Sources/SIL/Registration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public func registerSILClasses() {
register(UpcastInst.self)
register(UncheckedRefCastInst.self)
register(UncheckedAddrCastInst.self)
register(UncheckedTrivialBitCastInst.self)
register(MarkMustCheckInst.self)
register(ObjectInst.self)
register(RawPointerToRefInst.self)
Expand Down
4 changes: 4 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Type.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
return !bridged.isNonTrivialOrContainsRawPointer(function.bridged.getFunction())
}

public func isLoadable(in function: Function) -> Bool {
return bridged.isLoadable(function.bridged.getFunction())
}

public func isReferenceCounted(in function: Function) -> Bool {
return bridged.isReferenceCounted(function.bridged.getFunction())
}
Expand Down
6 changes: 6 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Value.swift
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,9 @@ final class PlaceholderValue : Value {
extension OptionalBridgedValue {
public var value: Value? { obj.getAs(AnyObject.self) as? Value }
}

extension Optional where Wrapped == Value {
public var bridged: OptionalBridgedValue {
OptionalBridgedValue(obj: self?.bridged.obj)
}
}
21 changes: 21 additions & 0 deletions include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ struct BridgedValue {

struct OptionalBridgedValue {
OptionalSwiftObject obj;

swift::SILValue getSILValue() const {
if (obj)
return static_cast<swift::ValueBase *>(obj);
return swift::SILValue();
}
};

inline swift::ValueOwnershipKind castToOwnership(BridgedValue::Ownership ownership) {
Expand Down Expand Up @@ -1173,6 +1179,14 @@ struct BridgedBuilder{
en->getType().getEnumElement(caseIdx), resultType)};
}

SWIFT_IMPORT_UNSAFE
BridgedInstruction createEnum(SwiftInt caseIdx, OptionalBridgedValue payload,
swift::SILType resultType) const {
swift::EnumElementDecl *caseDecl = resultType.getEnumElement(caseIdx);
swift::SILValue pl = payload.getSILValue();
return {builder().createEnum(regularLoc(), pl, caseDecl, resultType)};
}

SWIFT_IMPORT_UNSAFE
BridgedInstruction createBranch(BridgedBasicBlock destBlock, BridgedValueArray arguments) const {
llvm::SmallVector<swift::SILValue, 16> argValues;
Expand Down Expand Up @@ -1212,6 +1226,13 @@ struct BridgedBuilder{
llvm::SmallVector<swift::SILValue, 16> elementValues;
return {builder().createTuple(regularLoc(), type, elements.getValues(elementValues))};
}

SWIFT_IMPORT_UNSAFE
BridgedInstruction createStore(BridgedValue src, BridgedValue dst,
SwiftInt ownership) const {
return {builder().createStore(regularLoc(), src.getSILValue(), dst.getSILValue(),
(swift::StoreOwnershipQualifier)ownership)};
}
};

// AST bridging
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SIL/SILType.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ class SILType {
return !isAddressOnly(F);
}

bool isLoadable(const SILFunction *f) const { return isLoadable(*f); }

/// True if either:
/// 1) The type, or the referenced type of an address type, is loadable.
/// 2) The SIL Module conventions uses lowered addresses
Expand Down
Loading