Files
swift-mirror/SwiftCompilerSources/Sources/SIL/GlobalVariable.swift
Erik Eckstein 2dbd6cc56b SwiftCompilerSources: rework bridging
Introduce two modes of bridging:
* inline mode: this is basically how it worked so far. Using full C++ interop which allows bridging functions to be inlined.
* pure mode: bridging functions are not inlined but compiled in a cpp file. This allows to reduce the C++ interop requirements to a minimum. No std/llvm/swift headers are imported.

This change requires a major refactoring of bridging sources. The implementation of bridging functions go to two separate files: SILBridgingImpl.h and OptimizerBridgingImpl.h.
Depending on the mode, those files are either included in the corresponding header files (inline mode), or included in the c++ file (pure mode).

The mode can be selected with the BRIDGING_MODE cmake variable. By default it is set to the inline mode (= existing behavior). The pure mode is only selected in certain configurations to work around C++ interop issues:
* In debug builds, to workaround a problem with LLDB's `po` command (rdar://115770255).
* On windows to workaround a build problem.
2023-10-09 09:52:52 +02:00

192 lines
6.1 KiB
Swift

//===--- GlobalVariable.swift - Defines the GlobalVariable class ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 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 Basic
import SILBridging
final public class GlobalVariable : CustomStringConvertible, HasShortDescription, Hashable {
public var name: StringRef {
return StringRef(bridged: bridged.getName())
}
public var description: String {
return String(taking: bridged.getDebugDescription())
}
public var shortDescription: String { name.string }
public var isLet: Bool { bridged.isLet() }
/// True, if the linkage of the global variable indicates that it is visible outside the current
/// compilation unit and therefore not all of its uses are known.
///
/// For example, `public` linkage.
public var isPossiblyUsedExternally: Bool {
return bridged.isPossiblyUsedExternally()
}
/// True, if the linkage of the global indicates that it has a definition outside the
/// current compilation unit.
///
/// For example, `public_external` linkage.
public var isAvailableExternally: Bool {
return bridged.isAvailableExternally()
}
public var staticInitializerInstructions: InstructionList? {
if let firstStaticInitInst = bridged.getFirstStaticInitInst().instruction {
return InstructionList(first: firstStaticInitInst)
}
return nil
}
public var staticInitValue: SingleValueInstruction? {
if let staticInitInsts = staticInitializerInstructions {
return staticInitInsts.reversed().first! as? SingleValueInstruction
}
return nil
}
/// True if the global's linkage and resilience expansion allow the global
/// to be initialized statically.
public var canBeInitializedStatically: Bool {
return bridged.canBeInitializedStatically()
}
public var mustBeInitializedStatically: Bool {
return bridged.mustBeInitializedStatically()
}
public static func ==(lhs: GlobalVariable, rhs: GlobalVariable) -> Bool {
lhs === rhs
}
public func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(self))
}
public var bridged: BridgedGlobalVar { BridgedGlobalVar(SwiftObject(self)) }
}
extension Instruction {
public var isValidInStaticInitializerOfGlobal: Bool {
// Rule out SILUndef and SILArgument.
if operands.contains(where: { $0.value.definingInstruction == nil }) {
return false
}
switch self {
case let bi as BuiltinInst:
switch bi.id {
case .ZeroInitializer:
let type = bi.type.isBuiltinVector ? bi.type.builtinVectorElementType : bi.type
return type.isBuiltinInteger || type.isBuiltinFloat
case .PtrToInt:
return bi.operands[0].value is StringLiteralInst
case .IntToPtr:
return bi.operands[0].value is IntegerLiteralInst
case .StringObjectOr:
// The first operand can be a string literal (i.e. a pointer), but the
// second operand must be a constant. This enables creating a
// a pointer+offset relocation.
// Note that StringObjectOr requires the or'd bits in the first
// operand to be 0, so the operation is equivalent to an addition.
return bi.operands[1].value is IntegerLiteralInst
case .ZExtOrBitCast:
return true;
case .USubOver:
// Handle StringObjectOr(tuple_extract(usub_with_overflow(x, offset)), bits)
// This pattern appears in UTF8 String literal construction.
if let tei = bi.uses.getSingleUser(ofType: TupleExtractInst.self),
tei.isResultOfOffsetSubtract {
return true
}
return false
case .OnFastPath:
return true
default:
return false
}
case let tei as TupleExtractInst:
// Handle StringObjectOr(tuple_extract(usub_with_overflow(x, offset)), bits)
// This pattern appears in UTF8 String literal construction.
if tei.isResultOfOffsetSubtract,
let bi = tei.uses.getSingleUser(ofType: BuiltinInst.self),
bi.id == .StringObjectOr {
return true
}
return false
case let sli as StringLiteralInst:
switch sli.encoding {
case .Bytes, .UTF8:
return true
case .ObjCSelector:
// Objective-C selector string literals cannot be used in static
// initializers.
return false
}
case let fri as FunctionRefInst:
// TODO: support async function pointers in static globals.
return !fri.referencedFunction.isAsync
case is StructInst,
is TupleInst,
is EnumInst,
is IntegerLiteralInst,
is FloatLiteralInst,
is ObjectInst,
is ValueToBridgeObjectInst,
is ConvertFunctionInst,
is ThinToThickFunctionInst,
is AddressToPointerInst,
is GlobalAddrInst:
return true
default:
return false
}
}
}
// Match the pattern:
// tuple_extract(usub_with_overflow(x, integer_literal, integer_literal 0), 0)
private extension TupleExtractInst {
var isResultOfOffsetSubtract: Bool {
if fieldIndex == 0,
let bi = tuple as? BuiltinInst,
bi.id == .USubOver,
bi.operands[1].value is IntegerLiteralInst,
let overflowLiteral = bi.operands[2].value as? IntegerLiteralInst,
let overflowValue = overflowLiteral.value,
overflowValue == 0
{
return true
}
return false
}
}
// Bridging utilities
extension BridgedGlobalVar {
public var globalVar: GlobalVariable { obj.getAs(GlobalVariable.self) }
public var optional: OptionalBridgedGlobalVar {
OptionalBridgedGlobalVar(obj: self.obj)
}
}
extension OptionalBridgedGlobalVar {
public var globalVar: GlobalVariable? { obj.getAs(GlobalVariable.self) }
public static var none: OptionalBridgedGlobalVar {
OptionalBridgedGlobalVar(obj: nil)
}
}