Skip to content

Add stronger SILVerifier support for formal access. #16880

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

Closed
wants to merge 5 commits into from
Closed
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
1 change: 1 addition & 0 deletions include/swift/Parse/ParseSILSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef SWIFT_PARSER_PARSESILSUPPORT_H
#define SWIFT_PARSER_PARSESILSUPPORT_H

#include "swift/Parse/Parser.h"
#include "llvm/Support/PrettyStackTrace.h"

namespace swift {
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/MemAccessUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ class AccessedStorage {
}
}

/// Return true if the storage is guaranteed local.
bool isLocal() const {
switch (getKind()) {
case Box:
Expand Down
37 changes: 36 additions & 1 deletion include/swift/SIL/SILGlobalVariable.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ class SILGlobalVariable
/// once (either in its declaration, or once later), making it immutable.
unsigned IsLet : 1;

/// The VarDecl associated with this SILGlobalVariable. For debugger purpose.
/// The VarDecl associated with this SILGlobalVariable. Must by nonnull for
/// language-level global variables.
VarDecl *VDecl;

/// Whether or not this is a declaration.
Expand Down Expand Up @@ -225,4 +226,38 @@ public ilist_default_traits<::swift::SILGlobalVariable> {

} // end llvm namespace

//===----------------------------------------------------------------------===//
// Utilities for verification and optimization.
//===----------------------------------------------------------------------===//

namespace swift {

/// Given an addressor, AddrF, return the global variable being addressed, or
/// return nullptr if the addressor isn't a recognized pattern.
SILGlobalVariable *getVariableOfGlobalInit(SILFunction *AddrF);

/// Return the callee of a once call.
SILFunction *getCalleeOfOnceCall(BuiltinInst *BI);

/// Helper for getVariableOfGlobalInit(), so GlobalOpts can deeply inspect and
/// rewrite the initialization pattern.
///
/// Given an addressor, AddrF, find the call to the global initializer if
/// present, otherwise return null. If an initializer is returned, then
/// `CallsToOnce` is initialized to the corresponding builtin "once" call.
SILFunction *findInitializer(SILModule *Module, SILFunction *AddrF,
BuiltinInst *&CallToOnce);

/// Helper for getVariableOfGlobalInit(), so GlobalOpts can deeply inspect and
/// rewrite the initialization pattern.
///
/// Given a global initializer, InitFunc, return the GlobalVariable that it
/// statically initializes or return nullptr if it isn't an obvious static
/// initializer. If a global variable is returned, InitVal is initialized to the
/// the instruction producing the global's initial value.
SILGlobalVariable *getVariableOfStaticInitializer(
SILFunction *InitFunc, SingleValueInstruction *&InitVal);

} // namespace swift

#endif
4 changes: 4 additions & 0 deletions include/swift/SIL/SILLinkage.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

namespace swift {

class ValueDecl;

/// Linkage for a SIL object. This concept combines the notions
/// of symbol linkage and visibility.
///
Expand Down Expand Up @@ -176,6 +178,8 @@ inline bool isPossiblyUsedExternally(SILLinkage linkage, bool wholeModule) {
return linkage <= SILLinkage::Hidden;
}

SILLinkage getDeclSILLinkage(const ValueDecl *decl);

inline bool hasPublicVisibility(SILLinkage linkage) {
switch (linkage) {
case SILLinkage::Public:
Expand Down
8 changes: 8 additions & 0 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,14 @@ class SILModule {
void setOptRecordStream(std::unique_ptr<llvm::yaml::Output> &&Stream,
std::unique_ptr<llvm::raw_ostream> &&RawStream);

// This is currently limited to VarDecl because the visibility of global
// variables and class properties is straighforward, while the visibility of
// class methods (ValueDecls) depends on the subclass scope. "Visiblity" has
// a different meaning when vtable layout is at stake.
bool isVisibleExternally(const VarDecl *decl) {
return isPossiblyUsedExternally(getDeclSILLinkage(decl), isWholeModule());
}

PropertyListType &getPropertyList() { return properties; }
const PropertyListType &getPropertyList() const { return properties; }

Expand Down
31 changes: 24 additions & 7 deletions lib/ParseSIL/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
#include "swift/AST/ProtocolConformance.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/Timer.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Parse/Lexer.h"
#include "swift/Parse/Parser.h"
#include "swift/Parse/ParseSILSupport.h"
#include "swift/Parse/Parser.h"
#include "swift/SIL/AbstractionPattern.h"
#include "swift/SIL/InstructionUtils.h"
#include "swift/SIL/SILArgument.h"
Expand All @@ -28,8 +29,8 @@
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SIL/TypeLowering.h"
#include "swift/Syntax/SyntaxKind.h"
#include "swift/Subsystems.h"
#include "swift/Syntax/SyntaxKind.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/SaveAndRestore.h"

Expand Down Expand Up @@ -5403,11 +5404,27 @@ bool SILParserTUState::parseSILGlobal(Parser &P) {
if (!GlobalLinkage.hasValue())
GlobalLinkage = SILLinkage::DefaultForDefinition;

// FIXME: check for existing global variable?
auto *GV = SILGlobalVariable::create(M, GlobalLinkage.getValue(),
isSerialized,
GlobalName.str(),GlobalType,
RegularLocation(NameLoc));
// Lookup the global variable declaration for this sil_global.
std::string GlobalDeclName = Demangle::demangleSymbolAsString(
GlobalName.str(), Demangle::DemangleOptions::SimplifiedUIDemangleOptions());
SmallVector<ValueDecl *, 4> CurModuleResults;
P.SF.getParentModule()->lookupValue(
{}, P.Context.getIdentifier(GlobalDeclName), NLKind::UnqualifiedLookup,
CurModuleResults);
// A variable declaration exists for all sil_global variables defined in
// Swift. If a Swift global is defined outside this module, it will be exposed
// via an addressor rather than as a sil_global. However, globals imported
// from clang *will* result in a sil_global *without* any corresponding
// variable declaration.
VarDecl *VD = nullptr;
if (!CurModuleResults.empty()) {
assert(CurModuleResults.size() == 1);
VD = cast<VarDecl>(CurModuleResults[0]);
assert(getDeclSILLinkage(VD) == GlobalLinkage);
}
auto *GV = SILGlobalVariable::create(
M, GlobalLinkage.getValue(), isSerialized, GlobalName.str(), GlobalType,
RegularLocation(NameLoc), VD);

GV->setLet(isLet);
// Parse static initializer if exists.
Expand Down
51 changes: 47 additions & 4 deletions lib/SIL/MemAccessUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define DEBUG_TYPE "sil-access-utils"

#include "swift/SIL/MemAccessUtils.h"
#include "swift/SIL/SILGlobalVariable.h"
#include "swift/SIL/SILUndef.h"

using namespace swift;
Expand All @@ -28,6 +29,14 @@ AccessedStorage::Kind AccessedStorage::classify(SILValue base) {
return Stack;
case ValueKind::GlobalAddrInst:
return Global;
case ValueKind::ApplyInst: {
FullApplySite apply(cast<ApplyInst>(base));
if (auto *funcRef = apply.getReferencedFunction()) {
if (getVariableOfGlobalInit(funcRef))
return Global;
}
return Unidentified;
}
case ValueKind::RefElementAddrInst:
return Class;
// A function argument is effectively a nested access, enforced
Expand Down Expand Up @@ -67,7 +76,19 @@ AccessedStorage::AccessedStorage(SILValue base, Kind kind) {
paramIndex = cast<SILFunctionArgument>(base)->getIndex();
break;
case Global:
global = cast<GlobalAddrInst>(base)->getReferencedGlobal();
if (auto *GAI = dyn_cast<GlobalAddrInst>(base))
global = GAI->getReferencedGlobal();
else {
FullApplySite apply(cast<ApplyInst>(base));
auto *funcRef = apply.getReferencedFunction();
assert(funcRef);
global = getVariableOfGlobalInit(funcRef);
assert(global);
// Require a decl for all formally accessed globals defined in this
// module. (Access of globals defined elsewhere has Unidentified storage).
// AccessEnforcementWMO requires this.
assert(global->getDecl());
}
break;
case Class: {
// Do a best-effort to find the identity of the object being projected
Expand Down Expand Up @@ -149,6 +170,17 @@ void AccessedStorage::print(raw_ostream &os) const {

void AccessedStorage::dump() const { print(llvm::dbgs()); }

// Return true if the given apply invokes a global addressor defined in another
// module.
static bool isExternalGlobalAddressor(ApplyInst *AI) {
FullApplySite apply(AI);
auto *funcRef = apply.getReferencedFunction();
if (!funcRef)
return false;

return funcRef->isGlobalInit() && funcRef->isExternalDeclaration();
}

// Given an address base is a block argument, verify that it is actually a box
// projected from a switch_enum. This is a valid pattern at any SIL stage
// resulting in a block-type phi. In later SIL stages, the optimizer may form
Expand Down Expand Up @@ -186,12 +218,16 @@ static bool isAddressForLocalInitOnly(SILValue sourceAddr) {
}
}

// AccessEnforcementWMO makes a strong assumption that all accesses are either
// identified or are *not* accessing a global variable or class property defined
// in this module. Consequently, we cannot simply bail out on
// PointerToAddressInst as an Unidentified access.
AccessedStorage swift::findAccessedStorage(SILValue sourceAddr) {
SILValue address = sourceAddr;
while (true) {
AccessedStorage::Kind kind = AccessedStorage::classify(address);
// First handle identified cases: these are always valid as the base of a
// formal access.
// First handle identified cases: these are always valid as the base of
// a formal access.
if (kind != AccessedStorage::Unidentified)
return AccessedStorage(address, kind);

Expand All @@ -202,10 +238,16 @@ AccessedStorage swift::findAccessedStorage(SILValue sourceAddr) {
return AccessedStorage(address, AccessedStorage::Unidentified);
return AccessedStorage();

case ValueKind::PointerToAddressInst:
case ValueKind::SILUndef:
return AccessedStorage(address, AccessedStorage::Unidentified);

case ValueKind::ApplyInst:
if (isExternalGlobalAddressor(cast<ApplyInst>(address)))
return AccessedStorage(address, AccessedStorage::Unidentified);

// Don't currently allow any other calls to return an accessed address.
return AccessedStorage();

// A block argument may be a box value projected out of
// switch_enum. Address-type block arguments are not allowed.
case ValueKind::SILPHIArgument:
Expand Down Expand Up @@ -233,6 +275,7 @@ AccessedStorage swift::findAccessedStorage(SILValue sourceAddr) {
// Look through address casts to find the source address.
case ValueKind::MarkUninitializedInst:
case ValueKind::OpenExistentialAddrInst:
case ValueKind::PointerToAddressInst:
case ValueKind::UncheckedAddrCastInst:
// Inductive cases that apply to any type.
case ValueKind::CopyValueInst:
Expand Down
Loading