mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Before this change, if a global variable is required to be statically initialized (e.g. due to @_section attribute), we don't allow its type to be a struct, only a scalar type works. This change improves on that by teaching MandatoryPerformanceOptimizations pass to inline struct initializer calls into initializer of globals, as long as they are simple enough so that we can be sure that we don't trigger recursive/infinite inlining.
291 lines
10 KiB
C++
291 lines
10 KiB
C++
//===--- SILBridgingUtils.cpp - Utilities for swift bridging --------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Basic/BridgingUtils.h"
|
|
#include "swift/AST/Attr.h"
|
|
#include "swift/AST/SemanticAttrs.h"
|
|
#include "swift/SIL/SILNode.h"
|
|
#include "swift/SIL/ApplySite.h"
|
|
#include "swift/SIL/SILBridging.h"
|
|
#include "swift/SIL/SILGlobalVariable.h"
|
|
#include "swift/SIL/SILBuilder.h"
|
|
#include "swift/SIL/MemAccessUtils.h"
|
|
#include <string>
|
|
|
|
using namespace swift;
|
|
|
|
namespace {
|
|
|
|
bool nodeMetatypesInitialized = false;
|
|
|
|
// Filled in by class registration in initializeSwiftModules().
|
|
SwiftMetatype nodeMetatypes[(unsigned)SILNodeKind::Last_SILNode + 1];
|
|
|
|
}
|
|
|
|
// Does return null if initializeSwiftModules() is never called.
|
|
SwiftMetatype SILNode::getSILNodeMetatype(SILNodeKind kind) {
|
|
SwiftMetatype metatype = nodeMetatypes[(unsigned)kind];
|
|
assert((!nodeMetatypesInitialized || metatype) &&
|
|
"no metatype for bridged SIL node");
|
|
return metatype;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Class registration
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
static llvm::StringMap<SILNodeKind> valueNamesToKind;
|
|
static llvm::SmallPtrSet<SwiftMetatype, 4> unimplementedTypes;
|
|
|
|
// Utility to fill in a metatype of an "unimplemented" class for a whole range
|
|
// of class types.
|
|
static void setUnimplementedRange(SwiftMetatype metatype,
|
|
SILNodeKind from, SILNodeKind to) {
|
|
unimplementedTypes.insert(metatype);
|
|
for (unsigned kind = (unsigned)from; kind <= (unsigned)to; ++kind) {
|
|
assert((!nodeMetatypes[kind] || unimplementedTypes.count(metatype)) &&
|
|
"unimplemented nodes must be registered first");
|
|
nodeMetatypes[kind] = metatype;
|
|
}
|
|
}
|
|
|
|
/// Registers the metatype of a swift SIL class.
|
|
/// Called by initializeSwiftModules().
|
|
void registerBridgedClass(StringRef className, SwiftMetatype metatype) {
|
|
nodeMetatypesInitialized = true;
|
|
|
|
// Handle the important non Node classes.
|
|
if (className == "BasicBlock")
|
|
return SILBasicBlock::registerBridgedMetatype(metatype);
|
|
if (className == "GlobalVariable")
|
|
return SILGlobalVariable::registerBridgedMetatype(metatype);
|
|
if (className == "BlockArgument") {
|
|
nodeMetatypes[(unsigned)SILNodeKind::SILPhiArgument] = metatype;
|
|
return;
|
|
}
|
|
if (className == "FunctionArgument") {
|
|
nodeMetatypes[(unsigned)SILNodeKind::SILFunctionArgument] = metatype;
|
|
return;
|
|
}
|
|
|
|
// Pre-populate the "unimplemented" ranges of metatypes.
|
|
// If a specific class is not implemented in Swift yet, it bridges to an
|
|
// "unimplemented" class. This ensures that optimizations handle _all_ kind of
|
|
// instructions gracefully, without the need to define the not-yet-used
|
|
// classes in Swift.
|
|
#define VALUE_RANGE(ID) SILNodeKind::First_##ID, SILNodeKind::Last_##ID
|
|
if (className == "UnimplementedRefCountingInst")
|
|
return setUnimplementedRange(metatype, VALUE_RANGE(RefCountingInst));
|
|
if (className == "UnimplementedSingleValueInst")
|
|
return setUnimplementedRange(metatype, VALUE_RANGE(SingleValueInstruction));
|
|
if (className == "UnimplementedInstruction")
|
|
return setUnimplementedRange(metatype, VALUE_RANGE(SILInstruction));
|
|
#undef VALUE_RANGE
|
|
|
|
if (valueNamesToKind.empty()) {
|
|
#define VALUE(ID, PARENT) \
|
|
valueNamesToKind[#ID] = SILNodeKind::ID;
|
|
#define NON_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
|
|
VALUE(ID, NAME)
|
|
#define ARGUMENT(ID, PARENT) \
|
|
VALUE(ID, NAME)
|
|
#define SINGLE_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
|
|
VALUE(ID, NAME)
|
|
#define MULTIPLE_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
|
|
VALUE(ID, NAME)
|
|
#include "swift/SIL/SILNodes.def"
|
|
}
|
|
|
|
std::string prefixedName;
|
|
auto iter = valueNamesToKind.find(className);
|
|
if (iter == valueNamesToKind.end()) {
|
|
// Try again with a "SIL" prefix. For example Argument -> SILArgument.
|
|
prefixedName = std::string("SIL") + std::string(className);
|
|
iter = valueNamesToKind.find(prefixedName);
|
|
if (iter == valueNamesToKind.end()) {
|
|
llvm::errs() << "Unknown bridged node class " << className << '\n';
|
|
abort();
|
|
}
|
|
className = prefixedName;
|
|
}
|
|
SILNodeKind kind = iter->second;
|
|
SwiftMetatype existingTy = nodeMetatypes[(unsigned)kind];
|
|
if (existingTy && !unimplementedTypes.count(existingTy)) {
|
|
llvm::errs() << "Double registration of class " << className << '\n';
|
|
abort();
|
|
}
|
|
nodeMetatypes[(unsigned)kind] = metatype;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILFunction
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::string BridgedFunction::getDebugDescription() const {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
getFunction()->print(os);
|
|
str.pop_back(); // Remove trailing newline.
|
|
return str;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILBasicBlock
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::string BridgedBasicBlock::getDebugDescription() const {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
getBlock()->print(os);
|
|
str.pop_back(); // Remove trailing newline.
|
|
return str;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILValue
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::string BridgedValue::getDebugDescription() const {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
getSILValue()->print(os);
|
|
str.pop_back(); // Remove trailing newline.
|
|
return str;
|
|
}
|
|
|
|
BridgedValue::Kind BridgedValue::getKind() const {
|
|
SILValue v = getSILValue();
|
|
if (isa<SingleValueInstruction>(v)) {
|
|
return BridgedValue::Kind::SingleValueInstruction;
|
|
} else if (isa<SILArgument>(v)) {
|
|
return BridgedValue::Kind::Argument;
|
|
} else if (isa<MultipleValueInstructionResult>(v)) {
|
|
return BridgedValue::Kind::MultipleValueInstructionResult;
|
|
} else if (isa<SILUndef>(v)) {
|
|
return BridgedValue::Kind::Undef;
|
|
}
|
|
llvm_unreachable("unknown SILValue");
|
|
}
|
|
|
|
ArrayRef<SILValue> BridgedValueArray::getValues(SmallVectorImpl<SILValue> &storage) {
|
|
for (unsigned idx = 0; idx < count; ++idx) {
|
|
storage.push_back(base[idx].value.getSILValue());
|
|
}
|
|
return storage;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILGlobalVariable
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::string BridgedGlobalVar::getDebugDescription() const {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
getGlobal()->print(os);
|
|
str.pop_back(); // Remove trailing newline.
|
|
return str;
|
|
}
|
|
|
|
bool BridgedGlobalVar::canBeInitializedStatically() const {
|
|
SILGlobalVariable *global = getGlobal();
|
|
auto expansion = ResilienceExpansion::Maximal;
|
|
if (hasPublicVisibility(global->getLinkage()))
|
|
expansion = ResilienceExpansion::Minimal;
|
|
|
|
auto &tl = global->getModule().Types.getTypeLowering(
|
|
global->getLoweredType(),
|
|
TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(expansion));
|
|
return tl.isLoadable();
|
|
}
|
|
|
|
bool BridgedGlobalVar::mustBeInitializedStatically() const {
|
|
SILGlobalVariable *global = getGlobal();
|
|
return global->mustBeInitializedStatically();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILVTable
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::string BridgedVTable::getDebugDescription() const {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
vTable->print(os);
|
|
str.pop_back(); // Remove trailing newline.
|
|
return str;
|
|
}
|
|
|
|
std::string BridgedVTableEntry::getDebugDescription() const {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
entry->print(os);
|
|
str.pop_back(); // Remove trailing newline.
|
|
return str;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILVWitnessTable, SILDefaultWitnessTable
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::string BridgedWitnessTableEntry::getDebugDescription() const {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
entry->print(os, /*verbose=*/ false, PrintOptions::printSIL());
|
|
str.pop_back(); // Remove trailing newline.
|
|
return str;
|
|
}
|
|
|
|
std::string BridgedWitnessTable::getDebugDescription() const {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
table->print(os);
|
|
str.pop_back(); // Remove trailing newline.
|
|
return str;
|
|
}
|
|
|
|
std::string BridgedDefaultWitnessTable::getDebugDescription() const {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
table->print(os);
|
|
str.pop_back(); // Remove trailing newline.
|
|
return str;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILInstruction
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::string BridgedInstruction::getDebugDescription() const {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
getInst()->print(os);
|
|
str.pop_back(); // Remove trailing newline.
|
|
return str;
|
|
}
|
|
|
|
bool BridgedInstruction::mayAccessPointer() const {
|
|
return ::mayAccessPointer(getInst());
|
|
}
|
|
|
|
bool BridgedInstruction::mayLoadWeakOrUnowned() const {
|
|
return ::mayLoadWeakOrUnowned(getInst());
|
|
}
|
|
|
|
bool BridgedInstruction::maySynchronizeNotConsideringSideEffects() const {
|
|
return ::maySynchronizeNotConsideringSideEffects(getInst());
|
|
}
|
|
|
|
bool BridgedInstruction::mayBeDeinitBarrierNotConsideringSideEffects() const {
|
|
return ::mayBeDeinitBarrierNotConsideringSideEffects(getInst());
|
|
}
|