//===--- SILGlobalVariable.cpp - Defines SILGlobalVariable structure ------===// // // 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/SIL/SILFunction.h" #include "swift/SIL/SILGlobalVariable.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILLinkage.h" #include "swift/SIL/SILModule.h" using namespace swift; SILGlobalVariable *SILGlobalVariable::create(SILModule &M, SILLinkage linkage, IsSerialized_t isSerialized, StringRef name, SILType loweredType, Optional loc, VarDecl *Decl) { // Get a StringMapEntry for the variable. As a sop to error cases, // allow the name to have an empty string. llvm::StringMapEntry *entry = nullptr; if (!name.empty()) { entry = &*M.GlobalVariableMap.insert(std::make_pair(name, nullptr)).first; assert(!entry->getValue() && "global variable already exists"); name = entry->getKey(); } auto var = new (M) SILGlobalVariable(M, linkage, isSerialized, name, loweredType, loc, Decl); if (entry) entry->setValue(var); return var; } SILGlobalVariable::SILGlobalVariable(SILModule &Module, SILLinkage Linkage, IsSerialized_t isSerialized, StringRef Name, SILType LoweredType, Optional Loc, VarDecl *Decl) : Module(Module), Name(Name), LoweredType(LoweredType), Location(Loc), Linkage(unsigned(Linkage)), VDecl(Decl) { setSerialized(isSerialized); IsDeclaration = isAvailableExternally(Linkage); setLet(Decl ? Decl->isLet() : false); Module.silGlobals.push_back(this); } SILGlobalVariable::~SILGlobalVariable() { getModule().GlobalVariableMap.erase(Name); } /// Get this global variable's fragile attribute. IsSerialized_t SILGlobalVariable::isSerialized() const { return Serialized ? IsSerialized : IsNotSerialized; } void SILGlobalVariable::setSerialized(IsSerialized_t isSerialized) { assert(isSerialized != IsSerializable); Serialized = isSerialized ? 1 : 0; } /// Return the value that is written into the global variable. SILInstruction *SILGlobalVariable::getStaticInitializerValue() { if (StaticInitializerBlock.empty()) return nullptr; return &StaticInitializerBlock.back(); } BuiltinInst *SILGlobalVariable::getOffsetSubtract(const TupleExtractInst *TE, SILModule &M) { // Match the pattern: // tuple_extract(usub_with_overflow(x, integer_literal, integer_literal 0), 0) if (TE->getFieldNo() != 0) return nullptr; auto *BI = dyn_cast(TE->getOperand()); if (!BI) return nullptr; if (M.getBuiltinInfo(BI->getName()).ID != BuiltinValueKind::USubOver) return nullptr; if (!isa(BI->getArguments()[1])) return nullptr; auto *overflowFlag = dyn_cast(BI->getArguments()[2]); if (!overflowFlag || !overflowFlag->getValue().isNullValue()) return nullptr; return BI; } bool SILGlobalVariable::isValidStaticInitializerInst(const SILInstruction *I, SILModule &M) { switch (I->getKind()) { case SILInstructionKind::BuiltinInst: { auto *bi = cast(I); switch (M.getBuiltinInfo(bi->getName()).ID) { case BuiltinValueKind::PtrToInt: if (isa(bi->getArguments()[0])) return true; break; case BuiltinValueKind::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. if (isa(bi->getArguments()[1])) return true; break; case BuiltinValueKind::ZExtOrBitCast: return true; case BuiltinValueKind::USubOver: { // Handle StringObjectOr(tuple_extract(usub_with_overflow(x, offset)), bits) // This pattern appears in UTF8 String literal construction. auto *TE = bi->getSingleUserOfType(); return TE && getOffsetSubtract(TE, M); } default: break; } return false; } case SILInstructionKind::TupleExtractInst: { // Handle StringObjectOr(tuple_extract(usub_with_overflow(x, offset)), bits) // This pattern appears in UTF8 String literal construction. auto *TE = cast(I); if (!getOffsetSubtract(TE, M)) return false; auto *BI = TE->getSingleUserOfType(); return BI && M.getBuiltinInfo(BI->getName()).ID == BuiltinValueKind::StringObjectOr; } case SILInstructionKind::StringLiteralInst: switch (cast(I)->getEncoding()) { case StringLiteralInst::Encoding::Bytes: case StringLiteralInst::Encoding::UTF8: case StringLiteralInst::Encoding::UTF16: return true; case StringLiteralInst::Encoding::ObjCSelector: // Objective-C selector string literals cannot be used in static // initializers. return false; } return false; case SILInstructionKind::StructInst: case SILInstructionKind::TupleInst: case SILInstructionKind::IntegerLiteralInst: case SILInstructionKind::FloatLiteralInst: case SILInstructionKind::ObjectInst: case SILInstructionKind::ValueToBridgeObjectInst: return true; default: return false; } } /// Return whether this variable corresponds to a Clang node. bool SILGlobalVariable::hasClangNode() const { return (VDecl ? VDecl->hasClangNode() : false); } /// Return the Clang node associated with this variable if it has one. ClangNode SILGlobalVariable::getClangNode() const { return (VDecl ? VDecl->getClangNode() : ClangNode()); } const clang::Decl *SILGlobalVariable::getClangDecl() const { return (VDecl ? VDecl->getClangDecl() : nullptr); } //===----------------------------------------------------------------------===// // Utilities for verification and optimization. //===----------------------------------------------------------------------===// static SILGlobalVariable *getStaticallyInitializedVariable(SILFunction *AddrF) { if (AddrF->isExternalDeclaration()) return nullptr; auto *RetInst = cast(AddrF->findReturnBB()->getTerminator()); auto *API = dyn_cast(RetInst->getOperand()); if (!API) return nullptr; auto *GAI = dyn_cast(API->getOperand()); if (!GAI) return nullptr; return GAI->getReferencedGlobal(); } SILGlobalVariable *swift::getVariableOfGlobalInit(SILFunction *AddrF) { if (!AddrF->isGlobalInit()) return nullptr; if (auto *SILG = getStaticallyInitializedVariable(AddrF)) return SILG; // If the addressor contains a single "once" call, it calls globalinit_func, // and the globalinit_func is called by "once" from a single location, // continue; otherwise bail. BuiltinInst *CallToOnce; auto *InitF = findInitializer(&AddrF->getModule(), AddrF, CallToOnce); if (!InitF || !InitF->getName().startswith("globalinit_")) return nullptr; // If the globalinit_func is trivial, continue; otherwise bail. SingleValueInstruction *dummyInitVal; auto *SILG = getVariableOfStaticInitializer(InitF, dummyInitVal); return SILG; } SILFunction *swift::getCalleeOfOnceCall(BuiltinInst *BI) { assert(BI->getNumOperands() == 2 && "once call should have 2 operands."); auto Callee = BI->getOperand(1); assert(Callee->getType().castTo()->getRepresentation() == SILFunctionTypeRepresentation::CFunctionPointer && "Expected C function representation!"); if (auto *FR = dyn_cast(Callee)) return FR->getReferencedFunction(); return nullptr; } // Find the globalinit_func by analyzing the body of the addressor. SILFunction *swift::findInitializer(SILModule *Module, SILFunction *AddrF, BuiltinInst *&CallToOnce) { // We only handle a single SILBasicBlock for now. if (AddrF->size() != 1) return nullptr; CallToOnce = nullptr; SILBasicBlock *BB = &AddrF->front(); for (auto &I : *BB) { // Find the builtin "once" call. if (auto *BI = dyn_cast(&I)) { const BuiltinInfo &Builtin = BI->getModule().getBuiltinInfo(BI->getName()); if (Builtin.ID != BuiltinValueKind::Once) continue; // Bail if we have multiple "once" calls in the addressor. if (CallToOnce) return nullptr; CallToOnce = BI; } } if (!CallToOnce) return nullptr; return getCalleeOfOnceCall(CallToOnce); } SILGlobalVariable * swift::getVariableOfStaticInitializer(SILFunction *InitFunc, SingleValueInstruction *&InitVal) { InitVal = nullptr; SILGlobalVariable *GVar = nullptr; // We only handle a single SILBasicBlock for now. if (InitFunc->size() != 1) return nullptr; SILBasicBlock *BB = &InitFunc->front(); GlobalAddrInst *SGA = nullptr; bool HasStore = false; for (auto &I : *BB) { // Make sure we have a single GlobalAddrInst and a single StoreInst. // And the StoreInst writes to the GlobalAddrInst. if (isa(&I) || isa(&I) || isa(&I)) { continue; } else if (auto *sga = dyn_cast(&I)) { if (SGA) return nullptr; SGA = sga; GVar = SGA->getReferencedGlobal(); } else if (auto *SI = dyn_cast(&I)) { if (HasStore || SI->getDest() != SGA) return nullptr; HasStore = true; SILValue value = SI->getSrc(); // We only handle StructInst and TupleInst being stored to a // global variable for now. if (!isa(value) && !isa(value)) return nullptr; InitVal = cast(value); } else if (!SILGlobalVariable::isValidStaticInitializerInst(&I, I.getModule())) { return nullptr; } } if (!InitVal) return nullptr; return GVar; }