//===--- SILPrinter.cpp - Pretty-printing of SIL Code ---------------------===// // // 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 // //===----------------------------------------------------------------------===// /// /// \file /// /// This file defines the logic to pretty-print SIL, Instructions, etc. /// //===----------------------------------------------------------------------===// #include "swift/Strings.h" #include "swift/Demangling/Demangle.h" #include "swift/Basic/QuotedString.h" #include "swift/SIL/SILPrintContext.h" #include "swift/SIL/ApplySite.h" #include "swift/SIL/CFG.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILCoverageMap.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILVisitor.h" #include "swift/SIL/SILVTable.h" #include "swift/AST/Decl.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Module.h" #include "swift/AST/PrintOptions.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/Types.h" #include "swift/Basic/STLExtras.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/FileSystem.h" #include using namespace swift; using ID = SILPrintContext::ID; llvm::cl::opt SILPrintNoColor("sil-print-no-color", llvm::cl::init(""), llvm::cl::desc("Don't use color when printing SIL")); llvm::cl::opt SILFullDemangle("sil-full-demangle", llvm::cl::init(false), llvm::cl::desc("Fully demangle symbol names in SIL output")); llvm::cl::opt SILPrintDebugInfo("sil-print-debuginfo", llvm::cl::init(false), llvm::cl::desc("Include debug info in SIL output")); llvm::cl::opt SILPrintSourceInfo("sil-print-sourceinfo", llvm::cl::init(false), llvm::cl::desc("Include source annotation in SIL output")); llvm::cl::opt SILPrintGenericSpecializationInfo( "sil-print-generic-specialization-info", llvm::cl::init(false), llvm::cl::desc("Include generic specialization" "information info in SIL output")); static std::string demangleSymbol(StringRef Name) { if (SILFullDemangle) return Demangle::demangleSymbolAsString(Name); return Demangle::demangleSymbolAsString(Name, Demangle::DemangleOptions::SimplifiedUIDemangleOptions()); } enum SILColorKind { SC_Type, }; namespace { /// RAII based coloring of SIL output. class SILColor { raw_ostream &OS; enum raw_ostream::Colors Color; public: #define DEF_COL(NAME, RAW) case NAME: Color = raw_ostream::RAW; break; explicit SILColor(raw_ostream &OS, SILColorKind K) : OS(OS) { if (!OS.has_colors() || SILPrintNoColor) return; switch (K) { DEF_COL(SC_Type, YELLOW) } OS.resetColor(); OS.changeColor(Color); } explicit SILColor(raw_ostream &OS, ID::ID_Kind K) : OS(OS) { if (!OS.has_colors() || SILPrintNoColor) return; switch (K) { DEF_COL(ID::SILUndef, RED) DEF_COL(ID::SILBasicBlock, GREEN) DEF_COL(ID::SSAValue, MAGENTA) DEF_COL(ID::Null, YELLOW) } OS.resetColor(); OS.changeColor(Color); } ~SILColor() { if (!OS.has_colors() || SILPrintNoColor) return; // FIXME: instead of resetColor(), we can look into // capturing the current active color and restoring it. OS.resetColor(); } #undef DEF_COL }; } // end anonymous namespace void SILPrintContext::ID::print(raw_ostream &OS) { SILColor C(OS, Kind); switch (Kind) { case ID::SILUndef: OS << "undef"; return; case ID::SILBasicBlock: OS << "bb"; break; case ID::SSAValue: OS << '%'; break; case ID::Null: OS << "<>"; return; } OS << Number; } namespace swift { raw_ostream &operator<<(raw_ostream &OS, SILPrintContext::ID i) { i.print(OS); return OS; } } // namespace swift /// IDAndType - Used when a client wants to print something like "%0 : $Int". struct SILValuePrinterInfo { ID ValueID; SILType Type; Optional OwnershipKind; SILValuePrinterInfo(ID ValueID) : ValueID(ValueID), Type(), OwnershipKind() {} SILValuePrinterInfo(ID ValueID, SILType Type) : ValueID(ValueID), Type(Type), OwnershipKind() {} SILValuePrinterInfo(ID ValueID, SILType Type, ValueOwnershipKind OwnershipKind) : ValueID(ValueID), Type(Type), OwnershipKind(OwnershipKind) {} }; /// Return the fully qualified dotted path for DeclContext. static void printFullContext(const DeclContext *Context, raw_ostream &Buffer) { if (!Context) return; switch (Context->getContextKind()) { case DeclContextKind::Module: if (Context == cast(Context)->getASTContext().TheBuiltinModule) Buffer << cast(Context)->getName() << "."; return; case DeclContextKind::FileUnit: // Ignore the file; just print the module. printFullContext(Context->getParent(), Buffer); return; case DeclContextKind::Initializer: // FIXME Buffer << ""; return; case DeclContextKind::AbstractClosureExpr: // FIXME Buffer << ""; return; case DeclContextKind::SerializedLocal: Buffer << ""; return; case DeclContextKind::GenericTypeDecl: { auto *generic = cast(Context); printFullContext(generic->getDeclContext(), Buffer); Buffer << generic->getName() << "."; return; } case DeclContextKind::ExtensionDecl: { const NominalTypeDecl *ExtNominal = cast(Context)->getExtendedNominal(); printFullContext(ExtNominal->getDeclContext(), Buffer); Buffer << ExtNominal->getName() << "."; return; } case DeclContextKind::TopLevelCodeDecl: // FIXME Buffer << ""; return; case DeclContextKind::AbstractFunctionDecl: // FIXME Buffer << ""; return; case DeclContextKind::SubscriptDecl: // FIXME Buffer << ""; return; case DeclContextKind::EnumElementDecl: // FIXME Buffer << ""; return; } llvm_unreachable("bad decl context"); } static void printValueDecl(ValueDecl *Decl, raw_ostream &OS) { printFullContext(Decl->getDeclContext(), OS); if (!Decl->hasName()) { OS << "anonname=" << (const void*)Decl; } else if (Decl->isOperator()) { OS << '"' << Decl->getBaseName() << '"'; } else { bool shouldEscape = !Decl->getBaseName().isSpecial() && llvm::StringSwitch(Decl->getBaseName().userFacingName()) // FIXME: Represent "init" by a special name and remove this case .Case("init", false) #define KEYWORD(kw) \ .Case(#kw, true) #include "swift/Syntax/TokenKinds.def" .Default(false); if (shouldEscape) { OS << '`' << Decl->getBaseName().userFacingName() << '`'; } else { OS << Decl->getBaseName().userFacingName(); } } } /// SILDeclRef uses sigil "#" and prints the fully qualified dotted path. void SILDeclRef::print(raw_ostream &OS) const { OS << "#"; if (isNull()) { OS << ""; return; } bool isDot = true; if (!hasDecl()) { OS << ""; } else if (kind == SILDeclRef::Kind::Func) { auto *FD = cast(getDecl()); auto accessor = dyn_cast(FD); if (!accessor) { printValueDecl(FD, OS); isDot = false; } else { switch (accessor->getAccessorKind()) { case AccessorKind::WillSet: printValueDecl(accessor->getStorage(), OS); OS << "!willSet"; break; case AccessorKind::DidSet: printValueDecl(accessor->getStorage(), OS); OS << "!didSet"; break; case AccessorKind::Get: printValueDecl(accessor->getStorage(), OS); OS << "!getter"; break; case AccessorKind::Set: printValueDecl(accessor->getStorage(), OS); OS << "!setter"; break; case AccessorKind::Address: printValueDecl(accessor->getStorage(), OS); OS << "!addressor"; break; case AccessorKind::MutableAddress: printValueDecl(accessor->getStorage(), OS); OS << "!mutableAddressor"; break; case AccessorKind::Read: printValueDecl(accessor->getStorage(), OS); OS << "!read"; break; case AccessorKind::Modify: printValueDecl(accessor->getStorage(), OS); OS << "!modify"; break; } } } else { printValueDecl(getDecl(), OS); } switch (kind) { case SILDeclRef::Kind::Func: break; case SILDeclRef::Kind::Allocator: OS << "!allocator"; break; case SILDeclRef::Kind::Initializer: OS << "!initializer"; break; case SILDeclRef::Kind::EnumElement: OS << "!enumelt"; break; case SILDeclRef::Kind::Destroyer: OS << "!destroyer"; break; case SILDeclRef::Kind::Deallocator: OS << "!deallocator"; break; case SILDeclRef::Kind::IVarInitializer: OS << "!ivarinitializer"; break; case SILDeclRef::Kind::IVarDestroyer: OS << "!ivardestroyer"; break; case SILDeclRef::Kind::GlobalAccessor: OS << "!globalaccessor"; break; case SILDeclRef::Kind::DefaultArgGenerator: OS << "!defaultarg" << "." << defaultArgIndex; break; case SILDeclRef::Kind::StoredPropertyInitializer: OS << "!propertyinit"; break; case SILDeclRef::Kind::PropertyWrapperBackingInitializer: OS << "!backinginit"; break; } if (isForeign) OS << (isDot ? '.' : '!') << "foreign"; if (derivativeFunctionIdentifier) { OS << ((isDot || isForeign) ? '.' : '!'); switch (derivativeFunctionIdentifier->getKind()) { case AutoDiffDerivativeFunctionKind::JVP: OS << "jvp."; break; case AutoDiffDerivativeFunctionKind::VJP: OS << "vjp."; break; } OS << derivativeFunctionIdentifier->getParameterIndices()->getString(); if (auto derivativeGenSig = derivativeFunctionIdentifier->getDerivativeGenericSignature()) { OS << "." << derivativeGenSig; } } } void SILDeclRef::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } /// Pretty-print the generic specialization information. static void printGenericSpecializationInfo( raw_ostream &OS, StringRef Kind, StringRef Name, const GenericSpecializationInformation *SpecializationInfo, SubstitutionMap Subs = { }) { if (!SpecializationInfo) return; auto PrintSubstitutions = [&](SubstitutionMap Subs) { OS << '<'; interleave(Subs.getReplacementTypes(), [&](Type type) { OS << type; }, [&] { OS << ", "; }); OS << '>'; }; OS << "// Generic specialization information for " << Kind << " " << Name; if (!Subs.empty()) { OS << " "; PrintSubstitutions(Subs); } OS << ":\n"; while (SpecializationInfo) { OS << "// Caller: " << SpecializationInfo->getCaller()->getName() << '\n'; OS << "// Parent: " << SpecializationInfo->getParent()->getName() << '\n'; OS << "// Substitutions: "; PrintSubstitutions(SpecializationInfo->getSubstitutions()); OS << '\n'; OS << "//\n"; if (!SpecializationInfo->getCaller()->isSpecialization()) return; SpecializationInfo = SpecializationInfo->getCaller()->getSpecializationInfo(); } } static void print(raw_ostream &OS, SILValueCategory category) { switch (category) { case SILValueCategory::Object: return; case SILValueCategory::Address: OS << '*'; return; } llvm_unreachable("bad value category!"); } static StringRef getCastConsumptionKindName(CastConsumptionKind kind) { switch (kind) { case CastConsumptionKind::TakeAlways: return "take_always"; case CastConsumptionKind::TakeOnSuccess: return "take_on_success"; case CastConsumptionKind::CopyOnSuccess: return "copy_on_success"; case CastConsumptionKind::BorrowAlways: return "borrow_always"; } llvm_unreachable("bad cast consumption kind"); } static void printSILTypeColorAndSigil(raw_ostream &OS, SILType t) { SILColor C(OS, SC_Type); OS << '$'; // Potentially add a leading sigil for the value category. ::print(OS, t.getCategory()); } void SILType::print(raw_ostream &OS) const { printSILTypeColorAndSigil(OS, *this); // Print other types as their Swift representation. PrintOptions SubPrinter = PrintOptions::printSIL(); getASTType().print(OS, SubPrinter); } void SILType::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } /// Prints the name and type of the given SIL function with the given /// `PrintOptions`. Computes mapping for sugared type names and stores the /// result in `sugaredTypeNames`. static void printSILFunctionNameAndType( llvm::raw_ostream &OS, const SILFunction *function, llvm::DenseMap &sugaredTypeNames) { function->printName(OS); OS << " : $"; auto genSig = function->getLoweredFunctionType()->getInvocationGenericSignature(); auto *genEnv = function->getGenericEnvironment(); // If `genSig` and `genEnv` are both defined, get sugared names of generic // parameter types for printing. if (genSig && genEnv) { llvm::DenseSet usedNames; llvm::SmallString<16> disambiguatedNameBuf; unsigned disambiguatedNameCounter = 1; for (auto *paramTy : genSig->getGenericParams()) { // Get a uniqued sugared name for the generic parameter type. auto sugaredTy = genEnv->getSugaredType(paramTy); Identifier name = sugaredTy->getName(); while (!usedNames.insert(name).second) { disambiguatedNameBuf.clear(); { llvm::raw_svector_ostream names(disambiguatedNameBuf); names << sugaredTy->getName() << disambiguatedNameCounter++; } name = function->getASTContext().getIdentifier(disambiguatedNameBuf); } // If the uniqued sugared name is equal to the sugared name, continue. if (name == sugaredTy->getName()) continue; // Otherwise, add sugared name mapping for the type (and its archetype, if // defined). sugaredTypeNames[paramTy->getCanonicalType()] = name; if (auto *archetypeTy = genEnv->mapTypeIntoContext(paramTy)->getAs()) sugaredTypeNames[archetypeTy->getCanonicalType()] = name; } } auto printOptions = PrintOptions::printSIL(); printOptions.GenericEnv = genEnv; printOptions.AlternativeTypeNames = sugaredTypeNames.empty() ? nullptr : &sugaredTypeNames; function->getLoweredFunctionType()->print(OS, printOptions); } /// Prints the name and type of the given SIL function. static void printSILFunctionNameAndType(llvm::raw_ostream &OS, const SILFunction *function) { llvm::DenseMap sugaredTypeNames; printSILFunctionNameAndType(OS, function, sugaredTypeNames); } namespace { class SILPrinter; /// SILPrinter class - This holds the internal implementation details of /// printing SIL structures. class SILPrinter : public SILInstructionVisitor { SILPrintContext &Ctx; struct { llvm::formatted_raw_ostream OS; PrintOptions ASTOptions; } PrintState; unsigned LastBufferID; // Printers for the underlying stream. #define SIMPLE_PRINTER(TYPE) \ SILPrinter &operator<<(TYPE value) { \ PrintState.OS << value; \ return *this; \ } SIMPLE_PRINTER(char) SIMPLE_PRINTER(unsigned) SIMPLE_PRINTER(uint64_t) SIMPLE_PRINTER(StringRef) SIMPLE_PRINTER(Identifier) SIMPLE_PRINTER(ID) SIMPLE_PRINTER(QuotedString) SIMPLE_PRINTER(SILDeclRef) SIMPLE_PRINTER(APInt) SIMPLE_PRINTER(ValueOwnershipKind) #undef SIMPLE_PRINTER SILPrinter &operator<<(SILValuePrinterInfo i) { SILColor C(PrintState.OS, SC_Type); *this << i.ValueID; if (!i.Type) return *this; *this << " : "; if (i.OwnershipKind && *i.OwnershipKind != ValueOwnershipKind::None) { *this << "@" << i.OwnershipKind.getValue() << " "; } return *this << i.Type; } SILPrinter &operator<<(Type t) { // Print the type using our print options. t.print(PrintState.OS, PrintState.ASTOptions); return *this; } SILPrinter &operator<<(SILType t) { printSILTypeColorAndSigil(PrintState.OS, t); t.getASTType().print(PrintState.OS, PrintState.ASTOptions); return *this; } public: SILPrinter( SILPrintContext &PrintCtx, llvm::DenseMap *AlternativeTypeNames = nullptr) : Ctx(PrintCtx), PrintState{{PrintCtx.OS()}, PrintOptions::printSIL()}, LastBufferID(0) { PrintState.ASTOptions.AlternativeTypeNames = AlternativeTypeNames; PrintState.ASTOptions.PrintForSIL = true; } SILValuePrinterInfo getIDAndType(SILValue V) { return {Ctx.getID(V), V ? V->getType() : SILType()}; } SILValuePrinterInfo getIDAndTypeAndOwnership(SILValue V) { return {Ctx.getID(V), V ? V->getType() : SILType(), V.getOwnershipKind()}; } //===--------------------------------------------------------------------===// // Big entrypoints. void print(const SILFunction *F) { // If we are asked to emit sorted SIL, print out our BBs in RPOT order. if (Ctx.sortSIL()) { std::vector RPOT; auto *UnsafeF = const_cast(F); std::copy(po_begin(UnsafeF), po_end(UnsafeF), std::back_inserter(RPOT)); std::reverse(RPOT.begin(), RPOT.end()); Ctx.initBlockIDs(RPOT); interleave(RPOT, [&](SILBasicBlock *B) { print(B); }, [&] { *this << '\n'; }); return; } interleave(*F, [&](const SILBasicBlock &B) { print(&B); }, [&] { *this << '\n'; }); } void printBlockArgumentUses(const SILBasicBlock *BB) { if (BB->args_empty()) return; for (SILValue V : BB->getArguments()) { if (V->use_empty()) continue; *this << "// " << Ctx.getID(V); PrintState.OS.PadToColumn(50); *this << "// user"; if (std::next(V->use_begin()) != V->use_end()) *this << 's'; *this << ": "; llvm::SmallVector UserIDs; for (auto *Op : V->getUses()) UserIDs.push_back(Ctx.getID(Op->getUser())); // Display the user ids sorted to give a stable use order in the // printer's output if we are asked to do so. This makes diffing large // sections of SIL significantly easier at the expense of not showing // the _TRUE_ order of the users in the use list. if (Ctx.sortSIL()) { std::sort(UserIDs.begin(), UserIDs.end()); } interleave(UserIDs.begin(), UserIDs.end(), [&] (ID id) { *this << id; }, [&] { *this << ", "; }); *this << '\n'; } } void printBlockArguments(const SILBasicBlock *BB) { if (BB->args_empty()) return; *this << '('; ArrayRef Args = BB->getArguments(); // If SIL ownership is enabled and the given function has not had ownership // stripped out, print out ownership of SILArguments. if (BB->getParent()->hasOwnership()) { *this << getIDAndTypeAndOwnership(Args[0]); for (SILArgument *Arg : Args.drop_front()) { *this << ", " << getIDAndTypeAndOwnership(Arg); } *this << ')'; return; } // Otherwise, fall back to the old behavior *this << getIDAndType(Args[0]); for (SILArgument *Arg : Args.drop_front()) { *this << ", " << getIDAndType(Arg); } *this << ')'; } void print(const SILBasicBlock *BB) { // Output uses for BB arguments. These are put into place as comments before // the block header. printBlockArgumentUses(BB); // Then print the name of our block, the arguments, and the block colon. *this << Ctx.getID(BB); printBlockArguments(BB); *this << ":"; if (!BB->pred_empty()) { PrintState.OS.PadToColumn(50); *this << "// Preds:"; llvm::SmallVector PredIDs; for (auto *BBI : BB->getPredecessorBlocks()) PredIDs.push_back(Ctx.getID(BBI)); // Display the pred ids sorted to give a stable use order in the printer's // output if we are asked to do so. This makes diffing large sections of // SIL significantly easier at the expense of not showing the _TRUE_ order // of the users in the use list. if (Ctx.sortSIL()) { std::sort(PredIDs.begin(), PredIDs.end()); } for (auto Id : PredIDs) *this << ' ' << Id; } *this << '\n'; const auto &SM = BB->getModule().getASTContext().SourceMgr; Optional PrevLoc; for (const SILInstruction &I : *BB) { if (SILPrintSourceInfo) { auto CurSourceLoc = I.getLoc().getSourceLoc(); if (CurSourceLoc.isValid()) { if (!PrevLoc || SM.getLineNumber(CurSourceLoc) > SM.getLineNumber(PrevLoc->getSourceLoc())) { auto Buffer = SM.findBufferContainingLoc(CurSourceLoc); auto Line = SM.getLineNumber(CurSourceLoc); auto LineLength = SM.getLineLength(Buffer, Line); PrintState.OS << " // " << SM.extractText({SM.getLocForLineCol(Buffer, Line, 0), LineLength.getValueOr(0)}) << "\tSourceLoc: " << SM.getDisplayNameForLoc(CurSourceLoc) << ":" << Line << "\n"; PrevLoc = I.getLoc(); } } } Ctx.printInstructionCallBack(&I); if (SILPrintGenericSpecializationInfo) { if (auto AI = ApplySite::isa(const_cast(&I))) if (AI.getSpecializationInfo() && AI.getCalleeFunction()) printGenericSpecializationInfo( PrintState.OS, "call-site", AI.getCalleeFunction()->getName(), AI.getSpecializationInfo(), AI.getSubstitutionMap()); } print(&I); } } //===--------------------------------------------------------------------===// // SILInstruction Printing Logic bool printTypeDependentOperands(const SILInstruction *I) { ArrayRef TypeDepOps = I->getTypeDependentOperands(); if (TypeDepOps.empty()) return false; PrintState.OS.PadToColumn(50); *this << "// type-defs: "; interleave(TypeDepOps, [&](const Operand &op) { *this << Ctx.getID(op.get()); }, [&] { *this << ", "; }); return true; } /// Print out the users of the SILValue \p V. Return true if we printed out /// either an id or a use list. Return false otherwise. bool printUsersOfSILNode(const SILNode *node, bool printedSlashes) { llvm::SmallVector values; if (auto *value = dyn_cast(node)) { values.push_back(value); } else if (auto *inst = dyn_cast(node)) { assert(!isa(inst) && "SingleValueInstruction was " "handled by the previous " "value base check."); llvm::copy(inst->getResults(), std::back_inserter(values)); } // If the set of values is empty, we need to print the ID of // the instruction. Otherwise, if none of the values has a use, // we don't need to do anything. if (!values.empty()) { bool hasUse = false; for (auto value : values) { if (!value->use_empty()) hasUse = true; } if (!hasUse) return printedSlashes; } if (printedSlashes) { *this << "; "; } else { PrintState.OS.PadToColumn(50); *this << "// "; } if (values.empty()) { *this << "id: " << Ctx.getID(node); return true; } llvm::SmallVector UserIDs; for (auto value : values) for (auto *Op : value->getUses()) UserIDs.push_back(Ctx.getID(Op->getUser())); *this << "user"; if (UserIDs.size() != 1) *this << 's'; *this << ": "; // If we are asked to, display the user ids sorted to give a stable use // order in the printer's output. This makes diffing large sections of SIL // significantly easier. if (Ctx.sortSIL()) { std::sort(UserIDs.begin(), UserIDs.end()); } interleave(UserIDs.begin(), UserIDs.end(), [&](ID id) { *this << id; }, [&] { *this << ", "; }); return true; } void printConformances(ArrayRef conformances) { // FIXME: conformances should always be printed and parsed! if (!Ctx.printVerbose()) { return; } *this << " // "; for (ProtocolConformanceRef conformance : conformances) conformance.dump(PrintState.OS, /*indent*/ 0, /*details*/ false); } void printDebugLocRef(SILLocation Loc, const SourceManager &SM, bool PrintComma = true) { auto DL = Loc.decodeDebugLoc(SM); if (!DL.Filename.empty()) { if (PrintComma) *this << ", "; *this << "loc " << QuotedString(DL.Filename) << ':' << DL.Line << ':' << DL.Column; } } void printDebugScope(const SILDebugScope *DS, const SourceManager &SM) { if (!DS) return; if (!Ctx.hasScopeID(DS)) { printDebugScope(DS->Parent.dyn_cast(), SM); printDebugScope(DS->InlinedCallSite, SM); unsigned ID = Ctx.assignScopeID(DS); *this << "sil_scope " << ID << " { "; printDebugLocRef(DS->Loc, SM, false); *this << " parent "; if (auto *F = DS->Parent.dyn_cast()) *this << "@" << F->getName() << " : $" << F->getLoweredFunctionType(); else { auto *PS = DS->Parent.get(); *this << Ctx.getScopeID(PS); } if (auto *CS = DS->InlinedCallSite) *this << " inlined_at " << Ctx.getScopeID(CS); *this << " }\n"; } } void printDebugScopeRef(const SILDebugScope *DS, const SourceManager &SM, bool PrintComma = true) { if (DS) { if (PrintComma) *this << ", "; *this << "scope " << Ctx.getScopeID(DS); } } void printSILLocation(SILLocation L, SILModule &M, const SILDebugScope *DS, bool printedSlashes) { if (!L.isNull()) { if (!printedSlashes) { PrintState.OS.PadToColumn(50); *this << "//"; } *this << " "; // To minimize output, only print the line and column number for // everything but the first instruction. L.getSourceLoc().printLineAndColumn(PrintState.OS, M.getASTContext().SourceMgr); // Print the type of location. switch (L.getKind()) { case SILLocation::RegularKind: break; case SILLocation::ReturnKind: *this << ":return"; break; case SILLocation::ImplicitReturnKind: *this << ":imp_return"; break; case SILLocation::InlinedKind: *this << ":inlined"; break; case SILLocation::MandatoryInlinedKind: *this << ":minlined"; break; case SILLocation::CleanupKind: *this << ":cleanup"; break; case SILLocation::ArtificialUnreachableKind: *this << ":art_unreach"; break; } if (L.isSILFile()) *this << ":sil"; if (L.isAutoGenerated()) *this << ":auto_gen"; if (L.isInPrologue()) *this << ":in_prologue"; } if (L.isNull()) { if (!printedSlashes) { PrintState.OS.PadToColumn(50); *this << "//"; } if (L.isInTopLevel()) *this << " top_level"; else if (L.isAutoGenerated()) *this << " auto_gen"; else *this << " no_loc"; if (L.isInPrologue()) *this << ":in_prologue"; } if (!DS) return; // Print inlined-at location, if any. const SILDebugScope *CS = DS; while ((CS = CS->InlinedCallSite)) { *this << ": "; if (auto *InlinedF = CS->getInlinedFunction()) *this << demangleSymbol(InlinedF->getName()); else *this << '?'; *this << " perf_inlined_at "; auto CallSite = CS->Loc; if (!CallSite.isNull() && CallSite.isASTNode()) CallSite.getSourceLoc().print( PrintState.OS, M.getASTContext().SourceMgr, LastBufferID); else *this << "?"; } } void printInstOpCode(const SILInstruction *I) { *this << getSILInstructionName(I->getKind()) << " "; } void print(const SILInstruction *I) { if (auto *FRI = dyn_cast(I)) *this << " // function_ref " << demangleSymbol(FRI->getInitiallyReferencedFunction()->getName()) << "\n"; else if (auto *FRI = dyn_cast(I)) *this << " // dynamic_function_ref " << demangleSymbol(FRI->getInitiallyReferencedFunction()->getName()) << "\n"; else if (auto *FRI = dyn_cast(I)) *this << " // prev_dynamic_function_ref " << demangleSymbol(FRI->getInitiallyReferencedFunction()->getName()) << "\n"; *this << " "; // Print results. auto results = I->getResults(); if (results.size() == 1 && I->isStaticInitializerInst() && I == &I->getParent()->back()) { *this << "%initval = "; } else if (results.size() == 1) { ID Name = Ctx.getID(results[0]); *this << Name << " = "; } else if (results.size() > 1) { *this << '('; bool first = true; for (auto result : results) { if (first) { first = false; } else { *this << ", "; } ID Name = Ctx.getID(result); *this << Name; } *this << ") = "; } // Print the opcode. printInstOpCode(I); // Use the visitor to print the rest of the instruction. visit(const_cast(I)); // Maybe print debugging information. bool printedSlashes = false; if (Ctx.printDebugInfo() && !I->isStaticInitializerInst()) { auto &SM = I->getModule().getASTContext().SourceMgr; printDebugLocRef(I->getLoc(), SM); printDebugScopeRef(I->getDebugScope(), SM); } printedSlashes = printTypeDependentOperands(I); // Print users, or id for valueless instructions. printedSlashes = printUsersOfSILNode(I, printedSlashes); // Print SIL location. if (Ctx.printVerbose()) { printSILLocation(I->getLoc(), I->getModule(), I->getDebugScope(), printedSlashes); } *this << '\n'; } void print(const SILNode *node) { switch (node->getKind()) { #define INST(ID, PARENT) \ case SILNodeKind::ID: #include "swift/SIL/SILNodes.def" print(cast(node)); return; #define ARGUMENT(ID, PARENT) \ case SILNodeKind::ID: #include "swift/SIL/SILNodes.def" printSILArgument(cast(node)); return; case SILNodeKind::SILUndef: printSILUndef(cast(node)); return; #define MULTIPLE_VALUE_INST_RESULT(ID, PARENT) \ case SILNodeKind::ID: #include "swift/SIL/SILNodes.def" printSILMultipleValueInstructionResult( cast(node)); return; } llvm_unreachable("bad kind"); } void printSILArgument(const SILArgument *arg) { // This should really only happen during debugging. *this << Ctx.getID(arg) << " = argument of " << Ctx.getID(arg->getParent()) << " : " << arg->getType(); // Print users. (void) printUsersOfSILNode(arg, false); *this << '\n'; } void printSILUndef(const SILUndef *undef) { // This should really only happen during debugging. *this << "undef<" << undef->getType() << ">\n"; } void printSILMultipleValueInstructionResult( const MultipleValueInstructionResult *result) { // This should really only happen during debugging. if (result->getParent()->getNumResults() == 1) { *this << "**" << Ctx.getID(result) << "** = "; } else { *this << '('; interleave(result->getParent()->getResults(), [&](SILValue value) { if (value == SILValue(result)) { *this << "**" << Ctx.getID(result) << "**"; return; } *this << Ctx.getID(value); }, [&] { *this << ", "; }); *this << ')'; } *this << " = "; printInstOpCode(result->getParent()); auto *nonConstParent = const_cast(result->getParent()); visit(static_cast(nonConstParent)); // Print users. (void)printUsersOfSILNode(result, false); *this << '\n'; } void printInContext(const SILNode *node) { auto sortByID = [&](const SILNode *a, const SILNode *b) { return Ctx.getID(a).Number < Ctx.getID(b).Number; }; if (auto *I = dyn_cast(node)) { auto operands = map>(I->getAllOperands(), [](Operand const &o) { return o.get(); }); std::sort(operands.begin(), operands.end(), sortByID); for (auto &operand : operands) { *this << " "; print(operand); } } *this << "-> "; print(node); if (auto V = dyn_cast(node)) { auto users = map>(V->getUses(), [](Operand *o) { return o->getUser(); }); std::sort(users.begin(), users.end(), sortByID); for (auto &user : users) { *this << " "; print(user); } } } void printDebugVar(Optional Var) { if (!Var || Var->Name.empty()) return; if (Var->Constant) *this << ", let"; else *this << ", var"; *this << ", name \"" << Var->Name << '"'; if (Var->ArgNo) *this << ", argno " << Var->ArgNo; } void visitAllocStackInst(AllocStackInst *AVI) { if (AVI->hasDynamicLifetime()) *this << "[dynamic_lifetime] "; *this << AVI->getElementType(); printDebugVar(AVI->getVarInfo()); } void printAllocRefInstBase(AllocRefInstBase *ARI) { if (ARI->isObjC()) *this << "[objc] "; if (ARI->canAllocOnStack()) *this << "[stack] "; auto Types = ARI->getTailAllocatedTypes(); auto Counts = ARI->getTailAllocatedCounts(); for (unsigned Idx = 0, NumTypes = Types.size(); Idx < NumTypes; ++Idx) { *this << "[tail_elems " << Types[Idx] << " * " << getIDAndType(Counts[Idx].get()) << "] "; } } void visitAllocRefInst(AllocRefInst *ARI) { printAllocRefInstBase(ARI); *this << ARI->getType(); } void visitAllocRefDynamicInst(AllocRefDynamicInst *ARDI) { printAllocRefInstBase(ARDI); *this << getIDAndType(ARDI->getMetatypeOperand()); *this << ", " << ARDI->getType(); } void visitAllocValueBufferInst(AllocValueBufferInst *AVBI) { *this << AVBI->getValueType() << " in " << getIDAndType(AVBI->getOperand()); } void visitAllocBoxInst(AllocBoxInst *ABI) { if (ABI->hasDynamicLifetime()) *this << "[dynamic_lifetime] "; *this << ABI->getType(); printDebugVar(ABI->getVarInfo()); } void printSubstitutions(SubstitutionMap Subs, GenericSignature Sig = GenericSignature()) { if (!Subs.hasAnySubstitutableParams()) return; // FIXME: This is a hack to cope with cases where the substitution map uses // a generic signature that's close-to-but-not-the-same-as expected. auto genericSig = Sig ? Sig : Subs.getGenericSignature(); *this << '<'; bool first = true; for (auto gp : genericSig->getGenericParams()) { if (first) first = false; else *this << ", "; *this << Type(gp).subst(Subs); } *this << '>'; } template void visitApplyInstBase(Inst *AI) { *this << Ctx.getID(AI->getCallee()); printSubstitutions(AI->getSubstitutionMap(), AI->getOrigCalleeType()->getInvocationGenericSignature()); *this << '('; interleave(AI->getArguments(), [&](const SILValue &arg) { *this << Ctx.getID(arg); }, [&] { *this << ", "; }); *this << ") : "; if (auto callee = AI->getCallee()) *this << callee->getType(); else *this << "<>"; } void visitApplyInst(ApplyInst *AI) { if (AI->isNonThrowing()) *this << "[nothrow] "; visitApplyInstBase(AI); } void visitBeginApplyInst(BeginApplyInst *AI) { if (AI->isNonThrowing()) *this << "[nothrow] "; visitApplyInstBase(AI); } void visitTryApplyInst(TryApplyInst *AI) { visitApplyInstBase(AI); *this << ", normal " << Ctx.getID(AI->getNormalBB()); *this << ", error " << Ctx.getID(AI->getErrorBB()); } void visitPartialApplyInst(PartialApplyInst *CI) { switch (CI->getFunctionType()->getCalleeConvention()) { case ParameterConvention::Direct_Owned: // Default; do nothing. break; case ParameterConvention::Direct_Guaranteed: *this << "[callee_guaranteed] "; break; // Should not apply to callees. case ParameterConvention::Direct_Unowned: case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Constant: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_InoutAliasable: llvm_unreachable("unexpected callee convention!"); } if (CI->isOnStack()) *this << "[on_stack] "; visitApplyInstBase(CI); } void visitAbortApplyInst(AbortApplyInst *AI) { *this << Ctx.getID(AI->getOperand()); } void visitEndApplyInst(EndApplyInst *AI) { *this << Ctx.getID(AI->getOperand()); } void visitFunctionRefInst(FunctionRefInst *FRI) { FRI->getInitiallyReferencedFunction()->printName(PrintState.OS); *this << " : " << FRI->getType(); } void visitDynamicFunctionRefInst(DynamicFunctionRefInst *FRI) { FRI->getInitiallyReferencedFunction()->printName(PrintState.OS); *this << " : " << FRI->getType(); } void visitPreviousDynamicFunctionRefInst(PreviousDynamicFunctionRefInst *FRI) { FRI->getInitiallyReferencedFunction()->printName(PrintState.OS); *this << " : " << FRI->getType(); } void visitBuiltinInst(BuiltinInst *BI) { *this << QuotedString(BI->getName().str()); printSubstitutions(BI->getSubstitutions()); *this << "("; interleave(BI->getArguments(), [&](SILValue v) { *this << getIDAndType(v); }, [&]{ *this << ", "; }); *this << ") : "; *this << BI->getType(); } void visitAllocGlobalInst(AllocGlobalInst *AGI) { if (AGI->getReferencedGlobal()) { AGI->getReferencedGlobal()->printName(PrintState.OS); } else { *this << "<>"; } } void visitGlobalAddrInst(GlobalAddrInst *GAI) { if (GAI->getReferencedGlobal()) { GAI->getReferencedGlobal()->printName(PrintState.OS); } else { *this << "<>"; } *this << " : " << GAI->getType(); } void visitGlobalValueInst(GlobalValueInst *GVI) { GVI->getReferencedGlobal()->printName(PrintState.OS); *this << " : " << GVI->getType(); } void visitIntegerLiteralInst(IntegerLiteralInst *ILI) { const auto &lit = ILI->getValue(); *this << ILI->getType() << ", " << lit; } void visitFloatLiteralInst(FloatLiteralInst *FLI) { *this << FLI->getType() << ", 0x"; APInt bits = FLI->getBits(); *this << bits.toString(16, /*Signed*/ false); llvm::SmallString<12> decimal; FLI->getValue().toString(decimal); *this << " // " << decimal; } static StringRef getStringEncodingName(StringLiteralInst::Encoding kind) { switch (kind) { case StringLiteralInst::Encoding::Bytes: return "bytes "; case StringLiteralInst::Encoding::UTF8: return "utf8 "; case StringLiteralInst::Encoding::UTF16: return "utf16 "; case StringLiteralInst::Encoding::ObjCSelector: return "objc_selector "; } llvm_unreachable("bad string literal encoding"); } void visitStringLiteralInst(StringLiteralInst *SLI) { *this << getStringEncodingName(SLI->getEncoding()); if (SLI->getEncoding() != StringLiteralInst::Encoding::Bytes) { // FIXME: this isn't correct: this doesn't properly handle translating // UTF16 into UTF8, and the SIL parser always parses as UTF8. *this << QuotedString(SLI->getValue()); return; } // "Bytes" are always output in a hexadecimal form. *this << '"' << llvm::toHex(SLI->getValue()) << '"'; } void printLoadOwnershipQualifier(LoadOwnershipQualifier Qualifier) { switch (Qualifier) { case LoadOwnershipQualifier::Unqualified: return; case LoadOwnershipQualifier::Take: *this << "[take] "; return; case LoadOwnershipQualifier::Copy: *this << "[copy] "; return; case LoadOwnershipQualifier::Trivial: *this << "[trivial] "; return; } } void visitLoadInst(LoadInst *LI) { printLoadOwnershipQualifier(LI->getOwnershipQualifier()); *this << getIDAndType(LI->getOperand()); } void visitLoadBorrowInst(LoadBorrowInst *LBI) { *this << getIDAndType(LBI->getOperand()); } void visitBeginBorrowInst(BeginBorrowInst *LBI) { *this << getIDAndType(LBI->getOperand()); } void printStoreOwnershipQualifier(StoreOwnershipQualifier Qualifier) { switch (Qualifier) { case StoreOwnershipQualifier::Unqualified: return; case StoreOwnershipQualifier::Init: *this << "[init] "; return; case StoreOwnershipQualifier::Assign: *this << "[assign] "; return; case StoreOwnershipQualifier::Trivial: *this << "[trivial] "; return; } } void printAssignOwnershipQualifier(AssignOwnershipQualifier Qualifier) { switch (Qualifier) { case AssignOwnershipQualifier::Unknown: return; case AssignOwnershipQualifier::Init: *this << "[init] "; return; case AssignOwnershipQualifier::Reassign: *this << "[reassign] "; return; case AssignOwnershipQualifier::Reinit: *this << "[reinit] "; return; } } void visitStoreInst(StoreInst *SI) { *this << Ctx.getID(SI->getSrc()) << " to "; printStoreOwnershipQualifier(SI->getOwnershipQualifier()); *this << getIDAndType(SI->getDest()); } void visitStoreBorrowInst(StoreBorrowInst *SI) { *this << Ctx.getID(SI->getSrc()) << " to "; *this << getIDAndType(SI->getDest()); } void visitEndBorrowInst(EndBorrowInst *EBI) { *this << getIDAndType(EBI->getOperand()); } void visitAssignInst(AssignInst *AI) { *this << Ctx.getID(AI->getSrc()) << " to "; printAssignOwnershipQualifier(AI->getOwnershipQualifier()); *this << getIDAndType(AI->getDest()); } void visitAssignByWrapperInst(AssignByWrapperInst *AI) { *this << getIDAndType(AI->getSrc()) << " to "; printAssignOwnershipQualifier(AI->getOwnershipQualifier()); *this << getIDAndType(AI->getDest()) << ", init " << getIDAndType(AI->getInitializer()) << ", set " << getIDAndType(AI->getSetter()); } void visitMarkUninitializedInst(MarkUninitializedInst *MU) { switch (MU->getKind()) { case MarkUninitializedInst::Var: *this << "[var] "; break; case MarkUninitializedInst::RootSelf: *this << "[rootself] "; break; case MarkUninitializedInst::CrossModuleRootSelf: *this << "[crossmodulerootself] "; break; case MarkUninitializedInst::DerivedSelf: *this << "[derivedself] "; break; case MarkUninitializedInst::DerivedSelfOnly: *this << "[derivedselfonly] "; break; case MarkUninitializedInst::DelegatingSelf: *this << "[delegatingself] ";break; case MarkUninitializedInst::DelegatingSelfAllocated: *this << "[delegatingselfallocated] "; break; } *this << getIDAndType(MU->getOperand()); } void visitMarkFunctionEscapeInst(MarkFunctionEscapeInst *MFE) { interleave(MFE->getElements(), [&](SILValue Var) { *this << getIDAndType(Var); }, [&] { *this << ", "; }); } void visitDebugValueInst(DebugValueInst *DVI) { *this << getIDAndType(DVI->getOperand()); printDebugVar(DVI->getVarInfo()); } void visitDebugValueAddrInst(DebugValueAddrInst *DVAI) { *this << getIDAndType(DVAI->getOperand()); printDebugVar(DVAI->getVarInfo()); } #define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ void visitLoad##Name##Inst(Load##Name##Inst *LI) { \ if (LI->isTake()) \ *this << "[take] "; \ *this << getIDAndType(LI->getOperand()); \ } \ void visitStore##Name##Inst(Store##Name##Inst *SI) { \ *this << Ctx.getID(SI->getSrc()) << " to "; \ if (SI->isInitializationOfDest()) \ *this << "[initialization] "; \ *this << getIDAndType(SI->getDest()); \ } #include "swift/AST/ReferenceStorage.def" void visitCopyAddrInst(CopyAddrInst *CI) { if (CI->isTakeOfSrc()) *this << "[take] "; *this << Ctx.getID(CI->getSrc()) << " to "; if (CI->isInitializationOfDest()) *this << "[initialization] "; *this << getIDAndType(CI->getDest()); } void visitBindMemoryInst(BindMemoryInst *BI) { *this << getIDAndType(BI->getBase()) << ", "; *this << getIDAndType(BI->getIndex()) << " to "; *this << BI->getBoundType(); } void visitUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *CI) { *this << getIDAndType(CI->getOperand()) << " to " << CI->getTargetFormalType(); } void visitCheckedCastBranchInst(CheckedCastBranchInst *CI) { if (CI->isExact()) *this << "[exact] "; *this << getIDAndType(CI->getOperand()) << " to " << CI->getTargetFormalType() << ", " << Ctx.getID(CI->getSuccessBB()) << ", " << Ctx.getID(CI->getFailureBB()); if (CI->getTrueBBCount()) *this << " !true_count(" << CI->getTrueBBCount().getValue() << ")"; if (CI->getFalseBBCount()) *this << " !false_count(" << CI->getFalseBBCount().getValue() << ")"; } void visitCheckedCastValueBranchInst(CheckedCastValueBranchInst *CI) { *this << CI->getSourceFormalType() << " in " << getIDAndType(CI->getOperand()) << " to " << CI->getTargetFormalType() << ", " << Ctx.getID(CI->getSuccessBB()) << ", " << Ctx.getID(CI->getFailureBB()); } void visitUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *CI) { *this << CI->getSourceFormalType() << " in " << getIDAndType(CI->getSrc()) << " to " << CI->getTargetFormalType() << " in " << getIDAndType(CI->getDest()); } void visitUnconditionalCheckedCastValueInst( UnconditionalCheckedCastValueInst *CI) { *this << CI->getSourceFormalType() << " in " << getIDAndType(CI->getOperand()) << " to " << CI->getTargetFormalType(); } void visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *CI) { *this << getCastConsumptionKindName(CI->getConsumptionKind()) << ' ' << CI->getSourceFormalType() << " in " << getIDAndType(CI->getSrc()) << " to " << CI->getTargetFormalType() << " in " << getIDAndType(CI->getDest()) << ", " << Ctx.getID(CI->getSuccessBB()) << ", " << Ctx.getID(CI->getFailureBB()); if (CI->getTrueBBCount()) *this << " !true_count(" << CI->getTrueBBCount().getValue() << ")"; if (CI->getFalseBBCount()) *this << " !false_count(" << CI->getFalseBBCount().getValue() << ")"; } void printUncheckedConversionInst(ConversionInst *CI, SILValue operand) { *this << getIDAndType(operand) << " to " << CI->getType(); } void visitUncheckedOwnershipConversionInst( UncheckedOwnershipConversionInst *UOCI) { *this << getIDAndType(UOCI->getOperand()) << ", " << "@" << UOCI->getOperand().getOwnershipKind() << " to " << "@" << UOCI->getConversionOwnershipKind(); } void visitConvertFunctionInst(ConvertFunctionInst *CI) { *this << getIDAndType(CI->getOperand()) << " to "; if (CI->withoutActuallyEscaping()) *this << "[without_actually_escaping] "; *this << CI->getType(); } void visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *CI) { *this << (CI->isLifetimeGuaranteed() ? "" : "[not_guaranteed] ") << getIDAndType(CI->getOperand()) << " to " << CI->getType(); } void visitThinFunctionToPointerInst(ThinFunctionToPointerInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitPointerToThinFunctionInst(PointerToThinFunctionInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitUpcastInst(UpcastInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitAddressToPointerInst(AddressToPointerInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitPointerToAddressInst(PointerToAddressInst *CI) { *this << getIDAndType(CI->getOperand()) << " to "; if (CI->isStrict()) *this << "[strict] "; if (CI->isInvariant()) *this << "[invariant] "; *this << CI->getType(); } void visitUncheckedRefCastInst(UncheckedRefCastInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitUncheckedRefCastAddrInst(UncheckedRefCastAddrInst *CI) { *this << ' ' << CI->getSourceFormalType() << " in " << getIDAndType(CI->getSrc()) << " to " << CI->getTargetFormalType() << " in " << getIDAndType(CI->getDest()); } void visitUncheckedAddrCastInst(UncheckedAddrCastInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitRefToRawPointerInst(RefToRawPointerInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitRawPointerToRefInst(RawPointerToRefInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } #define LOADABLE_REF_STORAGE(Name, ...) \ void visitRefTo##Name##Inst(RefTo##Name##Inst *CI) { \ printUncheckedConversionInst(CI, CI->getOperand()); \ } \ void visit##Name##ToRefInst(Name##ToRefInst *CI) { \ printUncheckedConversionInst(CI, CI->getOperand()); \ } #include "swift/AST/ReferenceStorage.def" void visitThinToThickFunctionInst(ThinToThickFunctionInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitThickToObjCMetatypeInst(ThickToObjCMetatypeInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitObjCToThickMetatypeInst(ObjCToThickMetatypeInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitObjCMetatypeToObjectInst(ObjCMetatypeToObjectInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitObjCExistentialMetatypeToObjectInst( ObjCExistentialMetatypeToObjectInst *CI) { printUncheckedConversionInst(CI, CI->getOperand()); } void visitObjCProtocolInst(ObjCProtocolInst *CI) { *this << "#" << CI->getProtocol()->getName() << " : " << CI->getType(); } void visitRefToBridgeObjectInst(RefToBridgeObjectInst *I) { *this << getIDAndType(I->getConverted()) << ", " << getIDAndType(I->getBitsOperand()); } void visitBridgeObjectToRefInst(BridgeObjectToRefInst *I) { printUncheckedConversionInst(I, I->getOperand()); } void visitBridgeObjectToWordInst(BridgeObjectToWordInst *I) { printUncheckedConversionInst(I, I->getOperand()); } void visitCopyValueInst(CopyValueInst *I) { *this << getIDAndType(I->getOperand()); } #define UNCHECKED_REF_STORAGE(Name, ...) \ void visitStrongCopy##Name##ValueInst(StrongCopy##Name##ValueInst *I) { \ *this << getIDAndType(I->getOperand()); \ } #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ void visitStrongCopy##Name##ValueInst(StrongCopy##Name##ValueInst *I) { \ *this << getIDAndType(I->getOperand()); \ } #include "swift/AST/ReferenceStorage.def" void visitDestroyValueInst(DestroyValueInst *I) { *this << getIDAndType(I->getOperand()); } void visitStructInst(StructInst *SI) { *this << SI->getType() << " ("; interleave(SI->getElements(), [&](const SILValue &V) { *this << getIDAndType(V); }, [&] { *this << ", "; }); *this << ')'; } void visitObjectInst(ObjectInst *OI) { *this << OI->getType() << " ("; interleave(OI->getBaseElements(), [&](const SILValue &V) { *this << getIDAndType(V); }, [&] { *this << ", "; }); if (!OI->getTailElements().empty()) { *this << ", [tail_elems] "; interleave(OI->getTailElements(), [&](const SILValue &V) { *this << getIDAndType(V); }, [&] { *this << ", "; }); } *this << ')'; } void visitTupleInst(TupleInst *TI) { // Check to see if the type of the tuple can be inferred accurately from the // elements. bool SimpleType = true; for (auto &Elt : TI->getType().castTo()->getElements()) { if (Elt.hasName() || Elt.isVararg()) { SimpleType = false; break; } } // If the type is simple, just print the tuple elements. if (SimpleType) { *this << '('; interleave(TI->getElements(), [&](const SILValue &V){ *this << getIDAndType(V); }, [&] { *this << ", "; }); *this << ')'; } else { // Otherwise, print the type, then each value. *this << TI->getType() << " ("; interleave(TI->getElements(), [&](const SILValue &V) { *this << Ctx.getID(V); }, [&] { *this << ", "; }); *this << ')'; } } void visitEnumInst(EnumInst *UI) { *this << UI->getType() << ", " << SILDeclRef(UI->getElement(), SILDeclRef::Kind::EnumElement); if (UI->hasOperand()) { *this << ", " << getIDAndType(UI->getOperand()); } } void visitInitEnumDataAddrInst(InitEnumDataAddrInst *UDAI) { *this << getIDAndType(UDAI->getOperand()) << ", " << SILDeclRef(UDAI->getElement(), SILDeclRef::Kind::EnumElement); } void visitUncheckedEnumDataInst(UncheckedEnumDataInst *UDAI) { *this << getIDAndType(UDAI->getOperand()) << ", " << SILDeclRef(UDAI->getElement(), SILDeclRef::Kind::EnumElement); } void visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *UDAI) { *this << getIDAndType(UDAI->getOperand()) << ", " << SILDeclRef(UDAI->getElement(), SILDeclRef::Kind::EnumElement); } void visitInjectEnumAddrInst(InjectEnumAddrInst *IUAI) { *this << getIDAndType(IUAI->getOperand()) << ", " << SILDeclRef(IUAI->getElement(), SILDeclRef::Kind::EnumElement); } void visitTupleExtractInst(TupleExtractInst *EI) { *this << getIDAndType(EI->getOperand()) << ", " << EI->getFieldNo(); } void visitTupleElementAddrInst(TupleElementAddrInst *EI) { *this << getIDAndType(EI->getOperand()) << ", " << EI->getFieldNo(); } void visitStructExtractInst(StructExtractInst *EI) { *this << getIDAndType(EI->getOperand()) << ", #"; printFullContext(EI->getField()->getDeclContext(), PrintState.OS); *this << EI->getField()->getName().get(); } void visitStructElementAddrInst(StructElementAddrInst *EI) { *this << getIDAndType(EI->getOperand()) << ", #"; printFullContext(EI->getField()->getDeclContext(), PrintState.OS); *this << EI->getField()->getName().get(); } void visitRefElementAddrInst(RefElementAddrInst *EI) { *this << getIDAndType(EI->getOperand()) << ", #"; printFullContext(EI->getField()->getDeclContext(), PrintState.OS); *this << EI->getField()->getName().get(); } void visitRefTailAddrInst(RefTailAddrInst *RTAI) { *this << getIDAndType(RTAI->getOperand()) << ", " << RTAI->getTailType(); } void visitDestructureStructInst(DestructureStructInst *DSI) { *this << getIDAndType(DSI->getOperand()); } void visitDestructureTupleInst(DestructureTupleInst *DTI) { *this << getIDAndType(DTI->getOperand()); } void printMethodInst(MethodInst *I, SILValue Operand) { *this << getIDAndType(Operand) << ", " << I->getMember(); } void visitClassMethodInst(ClassMethodInst *AMI) { printMethodInst(AMI, AMI->getOperand()); *this << " : " << AMI->getMember().getDecl()->getInterfaceType(); *this << ", "; *this << AMI->getType(); } void visitSuperMethodInst(SuperMethodInst *AMI) { printMethodInst(AMI, AMI->getOperand()); *this << " : " << AMI->getMember().getDecl()->getInterfaceType(); *this << ", "; *this << AMI->getType(); } void visitObjCMethodInst(ObjCMethodInst *AMI) { printMethodInst(AMI, AMI->getOperand()); *this << " : " << AMI->getMember().getDecl()->getInterfaceType(); *this << ", "; *this << AMI->getType(); } void visitObjCSuperMethodInst(ObjCSuperMethodInst *AMI) { printMethodInst(AMI, AMI->getOperand()); *this << " : " << AMI->getMember().getDecl()->getInterfaceType(); *this << ", "; *this << AMI->getType(); } void visitWitnessMethodInst(WitnessMethodInst *WMI) { PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); QualifiedSILTypeOptions.CurrentModule = WMI->getModule().getSwiftModule(); *this << "$" << WMI->getLookupType() << ", " << WMI->getMember() << " : "; WMI->getMember().getDecl()->getInterfaceType().print( PrintState.OS, QualifiedSILTypeOptions); if (!WMI->getTypeDependentOperands().empty()) { *this << ", "; *this << getIDAndType(WMI->getTypeDependentOperands()[0].get()); } *this << " : " << WMI->getType(); printConformances({WMI->getConformance()}); } void visitOpenExistentialAddrInst(OpenExistentialAddrInst *OI) { if (OI->getAccessKind() == OpenedExistentialAccess::Immutable) *this << "immutable_access "; else *this << "mutable_access "; *this << getIDAndType(OI->getOperand()) << " to " << OI->getType(); } void visitOpenExistentialRefInst(OpenExistentialRefInst *OI) { *this << getIDAndType(OI->getOperand()) << " to " << OI->getType(); } void visitOpenExistentialMetatypeInst(OpenExistentialMetatypeInst *OI) { *this << getIDAndType(OI->getOperand()) << " to " << OI->getType(); } void visitOpenExistentialBoxInst(OpenExistentialBoxInst *OI) { *this << getIDAndType(OI->getOperand()) << " to " << OI->getType(); } void visitOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *OI) { *this << getIDAndType(OI->getOperand()) << " to " << OI->getType(); } void visitOpenExistentialValueInst(OpenExistentialValueInst *OI) { *this << getIDAndType(OI->getOperand()) << " to " << OI->getType(); } void visitInitExistentialAddrInst(InitExistentialAddrInst *AEI) { *this << getIDAndType(AEI->getOperand()) << ", $" << AEI->getFormalConcreteType(); printConformances(AEI->getConformances()); } void visitInitExistentialValueInst(InitExistentialValueInst *AEI) { *this << getIDAndType(AEI->getOperand()) << ", $" << AEI->getFormalConcreteType() << ", " << AEI->getType(); printConformances(AEI->getConformances()); } void visitInitExistentialRefInst(InitExistentialRefInst *AEI) { *this << getIDAndType(AEI->getOperand()) << " : $" << AEI->getFormalConcreteType() << ", " << AEI->getType(); printConformances(AEI->getConformances()); } void visitInitExistentialMetatypeInst(InitExistentialMetatypeInst *EMI) { *this << getIDAndType(EMI->getOperand()) << ", " << EMI->getType(); printConformances(EMI->getConformances()); } void visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) { *this << AEBI->getExistentialType() << ", $" << AEBI->getFormalConcreteType(); printConformances(AEBI->getConformances()); } void visitDeinitExistentialAddrInst(DeinitExistentialAddrInst *DEI) { *this << getIDAndType(DEI->getOperand()); } void visitDeinitExistentialValueInst(DeinitExistentialValueInst *DEI) { *this << getIDAndType(DEI->getOperand()); } void visitDeallocExistentialBoxInst(DeallocExistentialBoxInst *DEI) { *this << getIDAndType(DEI->getOperand()) << ", $" << DEI->getConcreteType(); } void visitProjectBlockStorageInst(ProjectBlockStorageInst *PBSI) { *this << getIDAndType(PBSI->getOperand()); } void visitInitBlockStorageHeaderInst(InitBlockStorageHeaderInst *IBSHI) { *this << getIDAndType(IBSHI->getBlockStorage()) << ", invoke " << Ctx.getID(IBSHI->getInvokeFunction()); printSubstitutions(IBSHI->getSubstitutions()); *this << " : " << IBSHI->getInvokeFunction()->getType() << ", type " << IBSHI->getType(); } void visitValueMetatypeInst(ValueMetatypeInst *MI) { *this << MI->getType() << ", " << getIDAndType(MI->getOperand()); } void visitExistentialMetatypeInst(ExistentialMetatypeInst *MI) { *this << MI->getType() << ", " << getIDAndType(MI->getOperand()); } void visitMetatypeInst(MetatypeInst *MI) { *this << MI->getType(); } void visitFixLifetimeInst(FixLifetimeInst *RI) { *this << getIDAndType(RI->getOperand()); } void visitEndLifetimeInst(EndLifetimeInst *ELI) { *this << getIDAndType(ELI->getOperand()); } void visitValueToBridgeObjectInst(ValueToBridgeObjectInst *VBOI) { *this << getIDAndType(VBOI->getOperand()); } void visitClassifyBridgeObjectInst(ClassifyBridgeObjectInst *CBOI) { *this << getIDAndType(CBOI->getOperand()); } void visitMarkDependenceInst(MarkDependenceInst *MDI) { *this << getIDAndType(MDI->getValue()) << " on " << getIDAndType(MDI->getBase()); } void visitCopyBlockInst(CopyBlockInst *RI) { *this << getIDAndType(RI->getOperand()); } void visitCopyBlockWithoutEscapingInst(CopyBlockWithoutEscapingInst *RI) { *this << getIDAndType(RI->getBlock()) << " withoutEscaping " << getIDAndType(RI->getClosure()); } void visitRefCountingInst(RefCountingInst *I) { if (I->isNonAtomic()) *this << "[nonatomic] "; *this << getIDAndType(I->getOperand(0)); } void visitIsUniqueInst(IsUniqueInst *CUI) { *this << getIDAndType(CUI->getOperand()); } void visitIsEscapingClosureInst(IsEscapingClosureInst *CUI) { if (CUI->getVerificationType()) *this << "[objc] "; *this << getIDAndType(CUI->getOperand()); } void visitDeallocStackInst(DeallocStackInst *DI) { *this << getIDAndType(DI->getOperand()); } void visitDeallocRefInst(DeallocRefInst *DI) { if (DI->canAllocOnStack()) *this << "[stack] "; *this << getIDAndType(DI->getOperand()); } void visitDeallocPartialRefInst(DeallocPartialRefInst *DPI) { *this << getIDAndType(DPI->getInstance()); *this << ", "; *this << getIDAndType(DPI->getMetatype()); } void visitDeallocValueBufferInst(DeallocValueBufferInst *DVBI) { *this << DVBI->getValueType() << " in " << getIDAndType(DVBI->getOperand()); } void visitDeallocBoxInst(DeallocBoxInst *DI) { *this << getIDAndType(DI->getOperand()); } void visitDestroyAddrInst(DestroyAddrInst *DI) { *this << getIDAndType(DI->getOperand()); } void visitProjectValueBufferInst(ProjectValueBufferInst *PVBI) { *this << PVBI->getValueType() << " in " << getIDAndType(PVBI->getOperand()); } void visitProjectBoxInst(ProjectBoxInst *PBI) { *this << getIDAndType(PBI->getOperand()) << ", " << PBI->getFieldIndex(); } void visitProjectExistentialBoxInst(ProjectExistentialBoxInst *PEBI) { *this << PEBI->getType().getObjectType() << " in " << getIDAndType(PEBI->getOperand()); } void visitBeginAccessInst(BeginAccessInst *BAI) { *this << '[' << getSILAccessKindName(BAI->getAccessKind()) << "] [" << getSILAccessEnforcementName(BAI->getEnforcement()) << "] " << (BAI->hasNoNestedConflict() ? "[no_nested_conflict] " : "") << (BAI->isFromBuiltin() ? "[builtin] " : "") << getIDAndType(BAI->getOperand()); } void visitEndAccessInst(EndAccessInst *EAI) { *this << (EAI->isAborting() ? "[abort] " : "") << getIDAndType(EAI->getOperand()); } void visitBeginUnpairedAccessInst(BeginUnpairedAccessInst *BAI) { *this << '[' << getSILAccessKindName(BAI->getAccessKind()) << "] [" << getSILAccessEnforcementName(BAI->getEnforcement()) << "] " << (BAI->hasNoNestedConflict() ? "[no_nested_conflict] " : "") << (BAI->isFromBuiltin() ? "[builtin] " : "") << getIDAndType(BAI->getSource()) << ", " << getIDAndType(BAI->getBuffer()); } void visitEndUnpairedAccessInst(EndUnpairedAccessInst *EAI) { *this << (EAI->isAborting() ? "[abort] " : "") << '[' << getSILAccessEnforcementName(EAI->getEnforcement()) << "] " << (EAI->isFromBuiltin() ? "[builtin] " : "") << getIDAndType(EAI->getOperand()); } void visitCondFailInst(CondFailInst *FI) { *this << getIDAndType(FI->getOperand()) << ", " << QuotedString(FI->getMessage()); } void visitIndexAddrInst(IndexAddrInst *IAI) { *this << getIDAndType(IAI->getBase()) << ", " << getIDAndType(IAI->getIndex()); } void visitTailAddrInst(TailAddrInst *TAI) { *this << getIDAndType(TAI->getBase()) << ", " << getIDAndType(TAI->getIndex()) << ", " << TAI->getTailType(); } void visitIndexRawPointerInst(IndexRawPointerInst *IAI) { *this << getIDAndType(IAI->getBase()) << ", " << getIDAndType(IAI->getIndex()); } void visitUnreachableInst(UnreachableInst *UI) {} void visitReturnInst(ReturnInst *RI) { *this << getIDAndType(RI->getOperand()); } void visitThrowInst(ThrowInst *TI) { *this << getIDAndType(TI->getOperand()); } void visitUnwindInst(UnwindInst *UI) { // no operands } void visitYieldInst(YieldInst *YI) { auto values = YI->getYieldedValues(); if (values.size() != 1) *this << '('; interleave(values, [&](SILValue value) { *this << getIDAndType(value); }, [&] { *this << ", "; }); if (values.size() != 1) *this << ')'; *this << ", resume " << Ctx.getID(YI->getResumeBB()) << ", unwind " << Ctx.getID(YI->getUnwindBB()); } void visitSwitchValueInst(SwitchValueInst *SII) { *this << getIDAndType(SII->getOperand()); for (unsigned i = 0, e = SII->getNumCases(); i < e; ++i) { SILValue value; SILBasicBlock *dest; std::tie(value, dest) = SII->getCase(i); *this << ", case " << Ctx.getID(value) << ": " << Ctx.getID(dest); } if (SII->hasDefault()) *this << ", default " << Ctx.getID(SII->getDefaultBB()); } void printSwitchEnumInst(SwitchEnumInstBase *SOI) { *this << getIDAndType(SOI->getOperand()); for (unsigned i = 0, e = SOI->getNumCases(); i < e; ++i) { EnumElementDecl *elt; SILBasicBlock *dest; std::tie(elt, dest) = SOI->getCase(i); *this << ", case " << SILDeclRef(elt, SILDeclRef::Kind::EnumElement) << ": " << Ctx.getID(dest); if (SOI->getCaseCount(i)) { *this << " !case_count(" << SOI->getCaseCount(i).getValue() << ")"; } } if (SOI->hasDefault()) { *this << ", default " << Ctx.getID(SOI->getDefaultBB()); if (SOI->getDefaultCount()) { *this << " !default_count(" << SOI->getDefaultCount().getValue() << ")"; } } } void visitSwitchEnumInst(SwitchEnumInst *SOI) { printSwitchEnumInst(SOI); } void visitSwitchEnumAddrInst(SwitchEnumAddrInst *SOI) { printSwitchEnumInst(SOI); } void printSelectEnumInst(SelectEnumInstBase *SEI) { *this << getIDAndType(SEI->getEnumOperand()); for (unsigned i = 0, e = SEI->getNumCases(); i < e; ++i) { EnumElementDecl *elt; SILValue result; std::tie(elt, result) = SEI->getCase(i); *this << ", case " << SILDeclRef(elt, SILDeclRef::Kind::EnumElement) << ": " << Ctx.getID(result); } if (SEI->hasDefault()) *this << ", default " << Ctx.getID(SEI->getDefaultResult()); *this << " : " << SEI->getType(); } void visitSelectEnumInst(SelectEnumInst *SEI) { printSelectEnumInst(SEI); } void visitSelectEnumAddrInst(SelectEnumAddrInst *SEI) { printSelectEnumInst(SEI); } void visitSelectValueInst(SelectValueInst *SVI) { *this << getIDAndType(SVI->getOperand()); for (unsigned i = 0, e = SVI->getNumCases(); i < e; ++i) { SILValue casevalue; SILValue result; std::tie(casevalue, result) = SVI->getCase(i); *this << ", case " << Ctx.getID(casevalue) << ": " << Ctx.getID(result); } if (SVI->hasDefault()) *this << ", default " << Ctx.getID(SVI->getDefaultResult()); *this << " : " << SVI->getType(); } void visitDynamicMethodBranchInst(DynamicMethodBranchInst *DMBI) { *this << getIDAndType(DMBI->getOperand()) << ", " << DMBI->getMember() << ", " << Ctx.getID(DMBI->getHasMethodBB()) << ", " << Ctx.getID(DMBI->getNoMethodBB()); } void printBranchArgs(OperandValueArrayRef args) { if (args.empty()) return; *this << '('; interleave(args, [&](SILValue v) { *this << getIDAndType(v); }, [&] { *this << ", "; }); *this << ')'; } void visitBranchInst(BranchInst *UBI) { *this << Ctx.getID(UBI->getDestBB()); printBranchArgs(UBI->getArgs()); } void visitCondBranchInst(CondBranchInst *CBI) { *this << Ctx.getID(CBI->getCondition()) << ", " << Ctx.getID(CBI->getTrueBB()); printBranchArgs(CBI->getTrueArgs()); *this << ", " << Ctx.getID(CBI->getFalseBB()); printBranchArgs(CBI->getFalseArgs()); if (CBI->getTrueBBCount()) *this << " !true_count(" << CBI->getTrueBBCount().getValue() << ")"; if (CBI->getFalseBBCount()) *this << " !false_count(" << CBI->getFalseBBCount().getValue() << ")"; } void visitKeyPathInst(KeyPathInst *KPI) { *this << KPI->getType() << ", "; auto pattern = KPI->getPattern(); if (pattern->getGenericSignature()) { pattern->getGenericSignature()->print(PrintState.OS); *this << ' '; } *this << "("; if (!pattern->getObjCString().empty()) *this << "objc \"" << pattern->getObjCString() << "\"; "; *this << "root $" << KPI->getPattern()->getRootType(); for (auto &component : pattern->getComponents()) { *this << "; "; printKeyPathPatternComponent(component); } *this << ')'; if (!KPI->getSubstitutions().empty()) { *this << ' '; printSubstitutions(KPI->getSubstitutions()); } if (!KPI->getAllOperands().empty()) { *this << " ("; interleave(KPI->getAllOperands(), [&](const Operand &operand) { *this << Ctx.getID(operand.get()); }, [&]{ *this << ", "; }); *this << ")"; } } void printKeyPathPatternComponent(const KeyPathPatternComponent &component) { auto printComponentIndices = [&](ArrayRef indices) { *this << '['; interleave(indices, [&](const KeyPathPatternComponent::Index &i) { *this << "%$" << i.Operand << " : $" << i.FormalType << " : " << i.LoweredType; }, [&]{ *this << ", "; }); *this << ']'; }; switch (auto kind = component.getKind()) { case KeyPathPatternComponent::Kind::StoredProperty: { auto prop = component.getStoredPropertyDecl(); *this << "stored_property #"; printValueDecl(prop, PrintState.OS); *this << " : $" << component.getComponentType(); break; } case KeyPathPatternComponent::Kind::GettableProperty: case KeyPathPatternComponent::Kind::SettableProperty: { *this << (kind == KeyPathPatternComponent::Kind::GettableProperty ? "gettable_property $" : "settable_property $") << component.getComponentType() << ", " << " id "; auto id = component.getComputedPropertyId(); switch (id.getKind()) { case KeyPathPatternComponent::ComputedPropertyId::DeclRef: { auto declRef = id.getDeclRef(); *this << declRef << " : " << declRef.getDecl()->getInterfaceType(); break; } case KeyPathPatternComponent::ComputedPropertyId::Function: { id.getFunction()->printName(PrintState.OS); *this << " : " << id.getFunction()->getLoweredType(); break; } case KeyPathPatternComponent::ComputedPropertyId::Property: { *this << "##"; printValueDecl(id.getProperty(), PrintState.OS); break; } } *this << ", getter "; component.getComputedPropertyGetter()->printName(PrintState.OS); *this << " : " << component.getComputedPropertyGetter()->getLoweredType(); if (kind == KeyPathPatternComponent::Kind::SettableProperty) { *this << ", setter "; component.getComputedPropertySetter()->printName(PrintState.OS); *this << " : " << component.getComputedPropertySetter()->getLoweredType(); } if (!component.getSubscriptIndices().empty()) { *this << ", indices "; printComponentIndices(component.getSubscriptIndices()); *this << ", indices_equals "; component.getSubscriptIndexEquals()->printName(PrintState.OS); *this << " : " << component.getSubscriptIndexEquals()->getLoweredType(); *this << ", indices_hash "; component.getSubscriptIndexHash()->printName(PrintState.OS); *this << " : " << component.getSubscriptIndexHash()->getLoweredType(); } if (auto external = component.getExternalDecl()) { *this << ", external #"; printValueDecl(external, PrintState.OS); auto subs = component.getExternalSubstitutions(); if (!subs.empty()) { printSubstitutions(subs); } } break; } case KeyPathPatternComponent::Kind::OptionalWrap: case KeyPathPatternComponent::Kind::OptionalChain: case KeyPathPatternComponent::Kind::OptionalForce: { switch (kind) { case KeyPathPatternComponent::Kind::OptionalWrap: *this << "optional_wrap : $"; break; case KeyPathPatternComponent::Kind::OptionalChain: *this << "optional_chain : $"; break; case KeyPathPatternComponent::Kind::OptionalForce: *this << "optional_force : $"; break; default: llvm_unreachable("out of sync"); } *this << component.getComponentType(); break; } case KeyPathPatternComponent::Kind::TupleElement: { *this << "tuple_element #" << component.getTupleIndex(); *this << " : $" << component.getComponentType(); break; } } } void visitDifferentiableFunctionInst(DifferentiableFunctionInst *dfi) { *this << "[parameters"; for (auto i : dfi->getParameterIndices()->getIndices()) *this << ' ' << i; *this << "] "; *this << getIDAndType(dfi->getOriginalFunction()); if (dfi->hasDerivativeFunctions()) { *this << " with_derivative "; *this << '{' << getIDAndType(dfi->getJVPFunction()) << ", " << getIDAndType(dfi->getVJPFunction()) << '}'; } } void visitLinearFunctionInst(LinearFunctionInst *lfi) { *this << "[parameters"; for (auto i : lfi->getParameterIndices()->getIndices()) *this << ' ' << i; *this << "] "; *this << getIDAndType(lfi->getOriginalFunction()); if (lfi->hasTransposeFunction()) { *this << " with_transpose "; *this << getIDAndType(lfi->getTransposeFunction()); } } void visitDifferentiableFunctionExtractInst( DifferentiableFunctionExtractInst *dfei) { *this << '['; switch (dfei->getExtractee()) { case NormalDifferentiableFunctionTypeComponent::Original: *this << "original"; break; case NormalDifferentiableFunctionTypeComponent::JVP: *this << "jvp"; break; case NormalDifferentiableFunctionTypeComponent::VJP: *this << "vjp"; break; } *this << "] "; *this << getIDAndType(dfei->getOperand()); if (dfei->hasExplicitExtracteeType()) { *this << " as "; *this << dfei->getType(); } } void visitLinearFunctionExtractInst(LinearFunctionExtractInst *lfei) { *this << '['; switch (lfei->getExtractee()) { case LinearDifferentiableFunctionTypeComponent::Original: *this << "original"; break; case LinearDifferentiableFunctionTypeComponent::Transpose: *this << "transpose"; break; } *this << "] "; *this << getIDAndType(lfei->getFunctionOperand()); } void visitDifferentiabilityWitnessFunctionInst( DifferentiabilityWitnessFunctionInst *dwfi) { auto *witness = dwfi->getWitness(); *this << '['; switch (dwfi->getWitnessKind()) { case DifferentiabilityWitnessFunctionKind::JVP: *this << "jvp"; break; case DifferentiabilityWitnessFunctionKind::VJP: *this << "vjp"; break; case DifferentiabilityWitnessFunctionKind::Transpose: *this << "transpose"; break; } *this << "] [parameters"; for (auto i : witness->getParameterIndices()->getIndices()) *this << ' ' << i; *this << "] [results"; for (auto i : witness->getResultIndices()->getIndices()) *this << ' ' << i; *this << "] "; if (auto witnessGenSig = witness->getDerivativeGenericSignature()) { auto subPrinter = PrintOptions::printSIL(); witnessGenSig->print(PrintState.OS, subPrinter); *this << " "; } printSILFunctionNameAndType(PrintState.OS, witness->getOriginalFunction()); if (dwfi->getHasExplicitFunctionType()) { *this << " as "; *this << dwfi->getType(); } } }; } // end anonymous namespace static void printBlockID(raw_ostream &OS, SILBasicBlock *bb) { SILPrintContext Ctx(OS); OS << Ctx.getID(bb); } void SILBasicBlock::printAsOperand(raw_ostream &OS, bool PrintType) { printBlockID(OS, this); } //===----------------------------------------------------------------------===// // Printing for SILInstruction, SILBasicBlock, SILFunction, and SILModule //===----------------------------------------------------------------------===// void SILNode::dump() const { print(llvm::errs()); } void SILNode::print(raw_ostream &OS) const { SILPrintContext Ctx(OS); SILPrinter(Ctx).print(this); } void SILInstruction::dump() const { print(llvm::errs()); } void SingleValueInstruction::dump() const { SILInstruction::dump(); } void SILInstruction::print(raw_ostream &OS) const { SILPrintContext Ctx(OS); SILPrinter(Ctx).print(this); } /// Pretty-print the SILBasicBlock to errs. void SILBasicBlock::dump() const { print(llvm::errs()); } /// Pretty-print the SILBasicBlock to the designated stream. void SILBasicBlock::print(raw_ostream &OS) const { SILPrintContext Ctx(OS); // Print the debug scope (and compute if we didn't do it already). auto &SM = this->getParent()->getModule().getASTContext().SourceMgr; for (auto &I : *this) { SILPrinter P(Ctx); P.printDebugScope(I.getDebugScope(), SM); } SILPrinter(Ctx).print(this); } void SILBasicBlock::print(raw_ostream &OS, SILPrintContext &Ctx) const { SILPrinter(Ctx).print(this); } /// Pretty-print the SILFunction to errs. void SILFunction::dump(bool Verbose) const { SILPrintContext Ctx(llvm::errs(), Verbose); print(Ctx); } // This is out of line so the debugger can find it. void SILFunction::dump() const { dump(false); } void SILFunction::dump(const char *FileName) const { std::error_code EC; llvm::raw_fd_ostream os(FileName, EC, llvm::sys::fs::OpenFlags::F_None); print(os); } static StringRef getLinkageString(SILLinkage linkage) { switch (linkage) { case SILLinkage::Public: return "public "; case SILLinkage::PublicNonABI: return "non_abi "; case SILLinkage::Hidden: return "hidden "; case SILLinkage::Shared: return "shared "; case SILLinkage::Private: return "private "; case SILLinkage::PublicExternal: return "public_external "; case SILLinkage::HiddenExternal: return "hidden_external "; case SILLinkage::SharedExternal: return "shared_external "; case SILLinkage::PrivateExternal: return "private_external "; } llvm_unreachable("bad linkage"); } static void printLinkage(llvm::raw_ostream &OS, SILLinkage linkage, bool isDefinition) { if ((isDefinition && linkage == SILLinkage::DefaultForDefinition) || (!isDefinition && linkage == SILLinkage::DefaultForDeclaration)) return; OS << getLinkageString(linkage); } /// Pretty-print the SILFunction to the designated stream. void SILFunction::print(SILPrintContext &PrintCtx) const { llvm::raw_ostream &OS = PrintCtx.OS(); if (PrintCtx.printDebugInfo()) { auto &SM = getModule().getASTContext().SourceMgr; for (auto &BB : *this) for (auto &I : BB) { SILPrinter P(PrintCtx); P.printDebugScope(I.getDebugScope(), SM); } OS << "\n"; } if (SILPrintGenericSpecializationInfo) { if (isSpecialization()) { printGenericSpecializationInfo(OS, "function", getName(), getSpecializationInfo()); } } OS << "// " << demangleSymbol(getName()) << '\n'; OS << "sil "; printLinkage(OS, getLinkage(), isDefinition()); if (isTransparent()) OS << "[transparent] "; switch (isSerialized()) { case IsNotSerialized: break; case IsSerializable: OS << "[serializable] "; break; case IsSerialized: OS << "[serialized] "; break; } switch (isThunk()) { case IsNotThunk: break; case IsThunk: OS << "[thunk] "; break; case IsSignatureOptimizedThunk: OS << "[signature_optimized_thunk] "; break; case IsReabstractionThunk: OS << "[reabstraction_thunk] "; break; } if (isDynamicallyReplaceable()) { OS << "[dynamically_replacable] "; } if (isExactSelfClass()) { OS << "[exact_self_class] "; } if (isWithoutActuallyEscapingThunk()) OS << "[without_actually_escaping] "; switch (getSpecialPurpose()) { case SILFunction::Purpose::None: break; case SILFunction::Purpose::GlobalInit: OS << "[global_init] "; break; case SILFunction::Purpose::LazyPropertyGetter: OS << "[lazy_getter] "; break; } if (isAlwaysWeakImported()) OS << "[weak_imported] "; auto availability = getAvailabilityForLinkage(); if (!availability.isAlwaysAvailable()) { auto version = availability.getOSVersion().getLowerEndpoint(); OS << "[available " << version.getAsString() << "] "; } switch (getInlineStrategy()) { case NoInline: OS << "[noinline] "; break; case AlwaysInline: OS << "[always_inline] "; break; case InlineDefault: break; } switch (getOptimizationMode()) { case OptimizationMode::NoOptimization: OS << "[Onone] "; break; case OptimizationMode::ForSpeed: OS << "[Ospeed] "; break; case OptimizationMode::ForSize: OS << "[Osize] "; break; default: break; } if (getEffectsKind() == EffectsKind::ReadOnly) OS << "[readonly] "; else if (getEffectsKind() == EffectsKind::ReadNone) OS << "[readnone] "; else if (getEffectsKind() == EffectsKind::ReadWrite) OS << "[readwrite] "; else if (getEffectsKind() == EffectsKind::ReleaseNone) OS << "[releasenone] "; if (auto *replacedFun = getDynamicallyReplacedFunction()) { OS << "[dynamic_replacement_for \""; OS << replacedFun->getName(); OS << "\"] "; } if (hasObjCReplacement()) { OS << "[objc_replacement_for \""; OS << getObjCReplacement().str(); OS << "\"] "; } for (auto &Attr : getSemanticsAttrs()) OS << "[_semantics \"" << Attr << "\"] "; for (auto *Attr : getSpecializeAttrs()) { OS << "[_specialize "; Attr->print(OS); OS << "] "; } // TODO: Handle clang node owners which don't have a name. if (hasClangNode() && getClangNodeOwner()->hasName()) { OS << "[clang "; printValueDecl(getClangNodeOwner(), OS); OS << "] "; } // Handle functions that are deserialized from canonical SIL. Normally, we // should emit SIL with the correct SIL stage, so preserving this attribute // won't be necessary. But consider serializing raw SIL (either textual SIL or // SIB) after importing canonical SIL from another module. If the imported // functions are reserialized (e.g. shared linkage), then we must preserve // this attribute. if (WasDeserializedCanonical && getModule().getStage() == SILStage::Raw) OS << "[canonical] "; // If this function is not an external declaration /and/ is in ownership ssa // form, print [ossa]. if (!isExternalDeclaration() && hasOwnership()) OS << "[ossa] "; llvm::DenseMap sugaredTypeNames; printSILFunctionNameAndType(OS, this, sugaredTypeNames); if (!isExternalDeclaration()) { if (auto eCount = getEntryCount()) { OS << " !function_entry_count(" << eCount.getValue() << ")"; } OS << " {\n"; SILPrinter(PrintCtx, sugaredTypeNames.empty() ? nullptr : &sugaredTypeNames) .print(this); OS << "} // end sil function '" << getName() << '\''; } OS << "\n\n"; } /// Pretty-print the SILFunction's name using SIL syntax, /// '@function_mangled_name'. void SILFunction::printName(raw_ostream &OS) const { OS << "@" << Name; } /// Pretty-print a global variable to the designated stream. void SILGlobalVariable::print(llvm::raw_ostream &OS, bool Verbose) const { OS << "// " << demangleSymbol(getName()) << '\n'; OS << "sil_global "; printLinkage(OS, getLinkage(), isDefinition()); if (isSerialized()) OS << "[serialized] "; if (isLet()) OS << "[let] "; printName(OS); OS << " : " << LoweredType; if (!StaticInitializerBlock.empty()) { OS << " = {\n"; { SILPrintContext Ctx(OS); SILPrinter Printer(Ctx); for (const SILInstruction &I : StaticInitializerBlock) { Printer.print(&I); } } OS << "}\n"; } OS << "\n\n"; } void SILGlobalVariable::dump(bool Verbose) const { print(llvm::errs(), Verbose); } void SILGlobalVariable::dump() const { dump(false); } void SILGlobalVariable::printName(raw_ostream &OS) const { OS << "@" << Name; } /// Pretty-print the SILModule to errs. void SILModule::dump(bool Verbose) const { SILPrintContext Ctx(llvm::errs(), Verbose); print(Ctx); } void SILModule::dump(const char *FileName, bool Verbose, bool PrintASTDecls) const { std::error_code EC; llvm::raw_fd_ostream os(FileName, EC, llvm::sys::fs::OpenFlags::F_None); SILPrintContext Ctx(os, Verbose); print(Ctx, getSwiftModule(), PrintASTDecls); } static void printSILGlobals(SILPrintContext &Ctx, const SILModule::GlobalListType &Globals) { if (!Ctx.sortSIL()) { for (const SILGlobalVariable &g : Globals) g.print(Ctx.OS(), Ctx.printVerbose()); return; } std::vector globals; globals.reserve(Globals.size()); for (const SILGlobalVariable &g : Globals) globals.push_back(&g); std::sort(globals.begin(), globals.end(), [] (const SILGlobalVariable *g1, const SILGlobalVariable *g2) -> bool { return g1->getName().compare(g2->getName()) == -1; } ); for (const SILGlobalVariable *g : globals) g->print(Ctx.OS(), Ctx.printVerbose()); } static void printSILFunctions(SILPrintContext &Ctx, const SILModule::FunctionListType &Functions) { if (!Ctx.sortSIL()) { for (const SILFunction &f : Functions) f.print(Ctx); return; } std::vector functions; functions.reserve(Functions.size()); for (const SILFunction &f : Functions) functions.push_back(&f); std::sort(functions.begin(), functions.end(), [] (const SILFunction *f1, const SILFunction *f2) -> bool { return f1->getName().compare(f2->getName()) == -1; } ); for (const SILFunction *f : functions) f->print(Ctx); } static void printSILVTables(SILPrintContext &Ctx, const SILModule::VTableListType &VTables) { if (!Ctx.sortSIL()) { for (const SILVTable &vt : VTables) vt.print(Ctx.OS(), Ctx.printVerbose()); return; } std::vector vtables; vtables.reserve(VTables.size()); for (const SILVTable &vt : VTables) vtables.push_back(&vt); std::sort(vtables.begin(), vtables.end(), [] (const SILVTable *v1, const SILVTable *v2) -> bool { StringRef Name1 = v1->getClass()->getName().str(); StringRef Name2 = v2->getClass()->getName().str(); return Name1.compare(Name2) == -1; } ); for (const SILVTable *vt : vtables) vt->print(Ctx.OS(), Ctx.printVerbose()); } static void printSILWitnessTables(SILPrintContext &Ctx, const SILModule::WitnessTableListType &WTables) { if (!Ctx.sortSIL()) { for (const SILWitnessTable &wt : WTables) wt.print(Ctx.OS(), Ctx.printVerbose()); return; } std::vector witnesstables; witnesstables.reserve(WTables.size()); for (const SILWitnessTable &wt : WTables) witnesstables.push_back(&wt); std::sort(witnesstables.begin(), witnesstables.end(), [] (const SILWitnessTable *w1, const SILWitnessTable *w2) -> bool { return w1->getName().compare(w2->getName()) == -1; } ); for (const SILWitnessTable *wt : witnesstables) wt->print(Ctx.OS(), Ctx.printVerbose()); } static void printSILDefaultWitnessTables(SILPrintContext &Ctx, const SILModule::DefaultWitnessTableListType &WTables) { if (!Ctx.sortSIL()) { for (const SILDefaultWitnessTable &wt : WTables) wt.print(Ctx.OS(), Ctx.printVerbose()); return; } std::vector witnesstables; witnesstables.reserve(WTables.size()); for (const SILDefaultWitnessTable &wt : WTables) witnesstables.push_back(&wt); std::sort(witnesstables.begin(), witnesstables.end(), [] (const SILDefaultWitnessTable *w1, const SILDefaultWitnessTable *w2) -> bool { return w1->getProtocol()->getName() .compare(w2->getProtocol()->getName()) == -1; } ); for (const SILDefaultWitnessTable *wt : witnesstables) wt->print(Ctx.OS(), Ctx.printVerbose()); } static void printSILDifferentiabilityWitnesses( SILPrintContext &Ctx, const SILModule::DifferentiabilityWitnessListType &diffWitnesses) { if (!Ctx.sortSIL()) { for (auto &dw : diffWitnesses) dw.print(Ctx.OS(), Ctx.printVerbose()); return; } std::vector sortedDiffWitnesses; sortedDiffWitnesses.reserve(diffWitnesses.size()); for (auto &dw : diffWitnesses) sortedDiffWitnesses.push_back(&dw); std::sort(sortedDiffWitnesses.begin(), sortedDiffWitnesses.end(), [](const SILDifferentiabilityWitness *dw1, const SILDifferentiabilityWitness *dw2) -> bool { // TODO(TF-893): Sort based on more criteria for deterministic // ordering. return dw1->getOriginalFunction()->getName().compare( dw2->getOriginalFunction()->getName()) == -1; }); for (auto *dw : sortedDiffWitnesses) dw->print(Ctx.OS(), Ctx.printVerbose()); } static void printSILCoverageMaps(SILPrintContext &Ctx, const SILModule::CoverageMapCollectionType &CoverageMaps) { if (!Ctx.sortSIL()) { for (const auto &M : CoverageMaps) M.second->print(Ctx); return; } std::vector Maps; Maps.reserve(CoverageMaps.size()); for (const auto &M : CoverageMaps) Maps.push_back(M.second); std::sort(Maps.begin(), Maps.end(), [](const SILCoverageMap *LHS, const SILCoverageMap *RHS) -> bool { return LHS->getName().compare(RHS->getName()) == -1; }); for (const SILCoverageMap *M : Maps) M->print(Ctx); } using MagicFileStringMap = llvm::StringMap>; static void printMagicFileStringMapEntry(SILPrintContext &Ctx, const MagicFileStringMap::MapEntryTy &entry) { auto &OS = Ctx.OS(); OS << "// '" << std::get<0>(entry.second) << "' => '" << entry.first() << "'"; if (!std::get<1>(entry.second)) OS << " (alternate)"; OS << "\n"; } static void printMagicFileStringMap(SILPrintContext &Ctx, const MagicFileStringMap map) { if (map.empty()) return; Ctx.OS() << "\n\n// Mappings from '#file' to '#filePath':\n"; if (Ctx.sortSIL()) { llvm::SmallVector keys; llvm::copy(map.keys(), std::back_inserter(keys)); llvm::sort(keys, [&](StringRef leftKey, StringRef rightKey) -> bool { const auto &leftValue = map.find(leftKey)->second; const auto &rightValue = map.find(rightKey)->second; // Lexicographically earlier #file strings sort earlier. if (std::get<0>(leftValue) != std::get<0>(rightValue)) return std::get<0>(leftValue) < std::get<0>(rightValue); // Conflict winners sort before losers. if (std::get<1>(leftValue) != std::get<1>(rightValue)) return std::get<1>(leftValue); // Finally, lexicographically earlier #filePath strings sort earlier. return leftKey < rightKey; }); for (auto key : keys) printMagicFileStringMapEntry(Ctx, *map.find(key)); } else { for (const auto &entry : map) printMagicFileStringMapEntry(Ctx, entry); } } void SILProperty::print(SILPrintContext &Ctx) const { PrintOptions Options = PrintOptions::printSIL(); auto &OS = Ctx.OS(); OS << "sil_property "; if (isSerialized()) OS << "[serialized] "; OS << '#'; printValueDecl(getDecl(), OS); if (auto sig = getDecl()->getInnermostDeclContext() ->getGenericSignatureOfContext()) { sig.getCanonicalSignature()->print(OS, Options); } OS << " ("; if (auto component = getComponent()) SILPrinter(Ctx).printKeyPathPatternComponent(*component); OS << ")\n"; } void SILProperty::dump() const { SILPrintContext context(llvm::errs()); print(context); } static void printSILProperties(SILPrintContext &Ctx, const SILModule::PropertyListType &Properties) { for (const SILProperty &P : Properties) { P.print(Ctx); } } static void printExternallyVisibleDecls(SILPrintContext &Ctx, ArrayRef decls) { if (decls.empty()) return; Ctx.OS() << "/* externally visible decls: \n"; for (ValueDecl *decl : decls) { printValueDecl(decl, Ctx.OS()); Ctx.OS() << '\n'; } Ctx.OS() << "*/\n"; } /// Pretty-print the SILModule to the designated stream. void SILModule::print(SILPrintContext &PrintCtx, ModuleDecl *M, bool PrintASTDecls) const { llvm::raw_ostream &OS = PrintCtx.OS(); OS << "sil_stage "; switch (Stage) { case SILStage::Raw: OS << "raw"; break; case SILStage::Canonical: OS << "canonical"; break; case SILStage::Lowered: OS << "lowered"; break; } OS << "\n\nimport " << BUILTIN_NAME << "\nimport " << STDLIB_NAME << "\nimport " << SWIFT_SHIMS_NAME << "\n\n"; // Print the declarations and types from the associated context (origin module or // current file). if (M && PrintASTDecls) { PrintOptions Options = PrintOptions::printSIL(); Options.TypeDefinitions = true; Options.VarInitializers = true; // FIXME: ExplodePatternBindingDecls is incompatible with VarInitializers! Options.ExplodePatternBindingDecls = true; Options.SkipImplicit = false; Options.PrintGetSetOnRWProperties = true; Options.PrintInSILBody = false; bool WholeModuleMode = (M == AssociatedDeclContext); SmallVector topLevelDecls; M->getTopLevelDecls(topLevelDecls); for (const Decl *D : topLevelDecls) { if (!WholeModuleMode && !(D->getDeclContext() == AssociatedDeclContext)) continue; if ((isa(D) || isa(D) || isa(D) || isa(D)) && !D->isImplicit()) { if (isa(D)) continue; // skip to visit ASTPrinter to avoid sil-opt prints duplicated import declarations if (auto importDecl = dyn_cast(D)) { StringRef importName = importDecl->getModule()->getName().str(); if (importName == BUILTIN_NAME || importName == STDLIB_NAME || importName == SWIFT_SHIMS_NAME) continue; } D->print(OS, Options); OS << "\n\n"; } } } printSILGlobals(PrintCtx, getSILGlobalList()); printSILDifferentiabilityWitnesses(PrintCtx, getDifferentiabilityWitnessList()); printSILFunctions(PrintCtx, getFunctionList()); printSILVTables(PrintCtx, getVTableList()); printSILWitnessTables(PrintCtx, getWitnessTableList()); printSILDefaultWitnessTables(PrintCtx, getDefaultWitnessTableList()); printSILCoverageMaps(PrintCtx, getCoverageMaps()); printSILProperties(PrintCtx, getPropertyList()); printExternallyVisibleDecls(PrintCtx, externallyVisible.getArrayRef()); if (M) printMagicFileStringMap( PrintCtx, M->computeMagicFileStringMap(/*shouldDiagnose=*/false)); OS << "\n\n"; } void SILNode::dumpInContext() const { printInContext(llvm::errs()); } void SILNode::printInContext(llvm::raw_ostream &OS) const { SILPrintContext Ctx(OS); SILPrinter(Ctx).printInContext(this); } void SILInstruction::dumpInContext() const { printInContext(llvm::errs()); } void SILInstruction::printInContext(llvm::raw_ostream &OS) const { SILPrintContext Ctx(OS); SILPrinter(Ctx).printInContext(this); } void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const { OS << "sil_vtable "; if (isSerialized()) OS << "[serialized] "; OS << getClass()->getName() << " {\n"; PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); for (auto &entry : getEntries()) { OS << " "; entry.Method.print(OS); OS << ": "; bool HasSingleImplementation = false; switch (entry.Method.kind) { default: break; case SILDeclRef::Kind::IVarDestroyer: case SILDeclRef::Kind::Destroyer: case SILDeclRef::Kind::Deallocator: HasSingleImplementation = true; } // No need to emit the signature for methods that may have only // single implementation, e.g. for destructors. if (!HasSingleImplementation) { QualifiedSILTypeOptions.CurrentModule = entry.Method.getDecl()->getDeclContext()->getParentModule(); entry.Method.getDecl()->getInterfaceType().print(OS, QualifiedSILTypeOptions); OS << " : "; } OS << '@' << entry.Implementation->getName(); switch (entry.TheKind) { case SILVTable::Entry::Kind::Normal: break; case SILVTable::Entry::Kind::Inherited: OS << " [inherited]"; break; case SILVTable::Entry::Kind::Override: OS << " [override]"; break; } OS << "\t// " << demangleSymbol(entry.Implementation->getName()); OS << "\n"; } OS << "}\n\n"; } void SILVTable::dump() const { print(llvm::errs()); } /// Returns true if anything was printed. static bool printAssociatedTypePath(llvm::raw_ostream &OS, CanType path) { if (auto memberType = dyn_cast(path)) { if (printAssociatedTypePath(OS, memberType.getBase())) OS << '.'; OS << memberType->getName().str(); return true; } else { assert(isa(path)); return false; } } void SILWitnessTable::Entry::print(llvm::raw_ostream &out, bool verbose, const PrintOptions &options) const { PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); out << " "; switch (getKind()) { case WitnessKind::Invalid: out << "no_default"; break; case WitnessKind::Method: { // method #declref: @function auto &methodWitness = getMethodWitness(); out << "method "; methodWitness.Requirement.print(out); out << ": "; QualifiedSILTypeOptions.CurrentModule = methodWitness.Requirement.getDecl() ->getDeclContext() ->getParentModule(); methodWitness.Requirement.getDecl()->getInterfaceType().print( out, QualifiedSILTypeOptions); out << " : "; if (methodWitness.Witness) { methodWitness.Witness->printName(out); out << "\t// " << demangleSymbol(methodWitness.Witness->getName()); } else { out << "nil"; } break; } case WitnessKind::AssociatedType: { // associated_type AssociatedTypeName: ConformingType auto &assocWitness = getAssociatedTypeWitness(); out << "associated_type "; out << assocWitness.Requirement->getName() << ": "; assocWitness.Witness->print(out, options); break; } case WitnessKind::AssociatedTypeProtocol: { // associated_type_protocol (AssociatedTypeName: Protocol): auto &assocProtoWitness = getAssociatedTypeProtocolWitness(); out << "associated_type_protocol ("; (void) printAssociatedTypePath(out, assocProtoWitness.Requirement); out << ": " << assocProtoWitness.Protocol->getName() << "): "; if (assocProtoWitness.Witness.isConcrete()) assocProtoWitness.Witness.getConcrete()->printName(out, options); else out << "dependent"; break; } case WitnessKind::BaseProtocol: { // base_protocol Protocol: auto &baseProtoWitness = getBaseProtocolWitness(); out << "base_protocol " << baseProtoWitness.Requirement->getName() << ": "; baseProtoWitness.Witness->printName(out, options); break; } } out << '\n'; } void SILWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const { PrintOptions Options = PrintOptions::printSIL(); PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); OS << "sil_witness_table "; printLinkage(OS, getLinkage(), /*isDefinition*/ isDefinition()); if (isSerialized()) OS << "[serialized] "; getConformance()->printName(OS, Options); Options.GenericEnv = getConformance()->getDeclContext()->getGenericEnvironmentOfContext(); if (isDeclaration()) { OS << "\n\n"; return; } OS << " {\n"; for (auto &witness : getEntries()) { witness.print(OS, Verbose, Options); } for (auto conditionalConformance : getConditionalConformances()) { // conditional_conformance (TypeName: Protocol): // OS << " conditional_conformance ("; conditionalConformance.Requirement.print(OS, Options); OS << ": " << conditionalConformance.Conformance.getRequirement()->getName() << "): "; if (conditionalConformance.Conformance.isConcrete()) conditionalConformance.Conformance.getConcrete()->printName(OS, Options); else OS << "dependent"; OS << '\n'; } OS << "}\n\n"; } void SILWitnessTable::dump() const { print(llvm::errs()); } void SILDefaultWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const { // sil_default_witness_table [] PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); OS << "sil_default_witness_table "; printLinkage(OS, getLinkage(), ForDefinition); OS << getProtocol()->getName() << " {\n"; PrintOptions options = PrintOptions::printSIL(); options.GenericEnv = Protocol->getGenericEnvironmentOfContext(); for (auto &witness : getEntries()) { witness.print(OS, Verbose, options); } OS << "}\n\n"; } void SILDefaultWitnessTable::dump() const { print(llvm::errs()); } void SILDifferentiabilityWitness::print(llvm::raw_ostream &OS, bool verbose) const { OS << "// differentiability witness for " << demangleSymbol(getOriginalFunction()->getName()) << '\n'; PrintOptions qualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); // sil_differentiability_witness (linkage)? OS << "sil_differentiability_witness "; printLinkage(OS, getLinkage(), /*isDefinition*/ isDefinition()); // ([serialized])? if (isSerialized()) OS << "[serialized] "; // [parameters ...] OS << "[parameters "; interleave( getParameterIndices()->getIndices(), [&](unsigned index) { OS << index; }, [&] { OS << ' '; }); // [results ...] OS << "] [results "; interleave( getResultIndices()->getIndices(), [&](unsigned index) { OS << index; }, [&] { OS << ' '; }); OS << "] "; // (<...>)? if (auto derivativeGenSig = getDerivativeGenericSignature()) { auto subPrinter = PrintOptions::printSIL(); derivativeGenSig->print(OS, subPrinter); OS << " "; } // @original-function-name : $original-sil-type printSILFunctionNameAndType(OS, getOriginalFunction()); if (isDeclaration()) { OS << "\n\n"; return; } // { // jvp: @jvp-function-name : $jvp-sil-type // vjp: @vjp-function-name : $vjp-sil-type // } OS << " {\n"; if (auto *jvp = getJVP()) { OS << " jvp: "; printSILFunctionNameAndType(OS, jvp); OS << '\n'; } if (auto *vjp = getVJP()) { OS << " vjp: "; printSILFunctionNameAndType(OS, vjp); OS << '\n'; } OS << "}\n\n"; } void SILDifferentiabilityWitness::dump() const { print(llvm::errs()); } void SILCoverageMap::print(SILPrintContext &PrintCtx) const { llvm::raw_ostream &OS = PrintCtx.OS(); OS << "sil_coverage_map " << QuotedString(getFile()) << " " << QuotedString(getName()) << " " << QuotedString(getPGOFuncName()) << " " << getHash() << " {\t// " << demangleSymbol(getName()) << "\n"; if (PrintCtx.sortSIL()) std::sort(MappedRegions.begin(), MappedRegions.end(), [](const MappedRegion &LHS, const MappedRegion &RHS) { return std::tie(LHS.StartLine, LHS.StartCol, LHS.EndLine, LHS.EndCol) < std::tie(RHS.StartLine, RHS.StartCol, RHS.EndLine, RHS.EndCol); }); for (auto &MR : getMappedRegions()) { OS << " " << MR.StartLine << ":" << MR.StartCol << " -> " << MR.EndLine << ":" << MR.EndCol << " : "; printCounter(OS, MR.Counter); OS << "\n"; } OS << "}\n\n"; } void SILCoverageMap::dump() const { print(llvm::errs()); } #ifndef NDEBUG // Disable the "for use only in debugger" warning. #if SWIFT_COMPILER_IS_MSVC #pragma warning(push) #pragma warning(disable : 4996) #endif void SILDebugScope::dump(SourceManager &SM, llvm::raw_ostream &OS, unsigned Indent) const { OS << "{\n"; OS.indent(Indent); if (Loc.isASTNode()) Loc.getSourceLoc().print(OS, SM); OS << "\n"; OS.indent(Indent + 2); OS << " parent: "; if (auto *P = Parent.dyn_cast()) { P->dump(SM, OS, Indent + 2); OS.indent(Indent + 2); } else if (auto *F = Parent.dyn_cast()) OS << "@" << F->getName(); else OS << "nullptr"; OS << "\n"; OS.indent(Indent + 2); if (auto *CS = InlinedCallSite) { OS << "inlinedCallSite: "; CS->dump(SM, OS, Indent + 2); OS.indent(Indent + 2); } OS << "}\n"; } void SILDebugScope::dump(SILModule &Mod) const { // We just use the default indent and llvm::errs(). dump(Mod.getASTContext().SourceMgr); } #if SWIFT_COMPILER_IS_MSVC #pragma warning(pop) #endif #endif void SILSpecializeAttr::print(llvm::raw_ostream &OS) const { SILPrintContext Ctx(OS); // Print other types as their Swift representation. PrintOptions SubPrinter = PrintOptions::printSIL(); auto exported = isExported() ? "true" : "false"; auto kind = isPartialSpecialization() ? "partial" : "full"; OS << "exported: " << exported << ", "; OS << "kind: " << kind << ", "; ArrayRef requirements; SmallVector requirementsScratch; if (auto specializedSig = getSpecializedSignature()) { if (auto env = getFunction()->getGenericEnvironment()) { requirementsScratch = specializedSig->requirementsNotSatisfiedBy( env->getGenericSignature()); requirements = requirementsScratch; } else { requirements = specializedSig->getRequirements(); } } if (!requirements.empty()) { OS << "where "; SILFunction *F = getFunction(); assert(F); auto GenericEnv = F->getGenericEnvironment(); interleave(requirements, [&](Requirement req) { if (!GenericEnv) { req.print(OS, SubPrinter); return; } // Use GenericEnvironment to produce user-friendly // names instead of something like t_0_0. auto FirstTy = GenericEnv->getSugaredType(req.getFirstType()); if (req.getKind() != RequirementKind::Layout) { auto SecondTy = GenericEnv->getSugaredType(req.getSecondType()); Requirement ReqWithDecls(req.getKind(), FirstTy, SecondTy); ReqWithDecls.print(OS, SubPrinter); } else { Requirement ReqWithDecls(req.getKind(), FirstTy, req.getLayoutConstraint()); ReqWithDecls.print(OS, SubPrinter); } }, [&] { OS << ", "; }); } } //===----------------------------------------------------------------------===// // SILPrintContext members //===----------------------------------------------------------------------===// SILPrintContext::SILPrintContext(llvm::raw_ostream &OS, bool Verbose, bool SortedSIL) : OutStream(OS), Verbose(Verbose), SortedSIL(SortedSIL), DebugInfo(SILPrintDebugInfo) { } SILPrintContext::SILPrintContext(llvm::raw_ostream &OS, const SILOptions &Opts) : OutStream(OS), Verbose(Opts.EmitVerboseSIL), SortedSIL(Opts.EmitSortedSIL), DebugInfo(SILPrintDebugInfo) {} SILPrintContext::SILPrintContext(llvm::raw_ostream &OS, bool Verbose, bool SortedSIL, bool DebugInfo) : OutStream(OS), Verbose(Verbose), SortedSIL(SortedSIL), DebugInfo(DebugInfo) { } void SILPrintContext::setContext(const void *FunctionOrBlock) { if (FunctionOrBlock != ContextFunctionOrBlock) { BlocksToIDMap.clear(); ValueToIDMap.clear(); ContextFunctionOrBlock = FunctionOrBlock; } } SILPrintContext::~SILPrintContext() { } void SILPrintContext::printInstructionCallBack(const SILInstruction *I) { } void SILPrintContext::initBlockIDs(ArrayRef Blocks) { if (Blocks.empty()) return; setContext(Blocks[0]->getParent()); // Initialize IDs so our IDs are in RPOT as well. This is a hack. for (unsigned Index : indices(Blocks)) BlocksToIDMap[Blocks[Index]] = Index; } ID SILPrintContext::getID(const SILBasicBlock *Block) { setContext(Block->getParent()); // Lazily initialize the Blocks-to-IDs mapping. // If we are asked to emit sorted SIL, print out our BBs in RPOT order. if (BlocksToIDMap.empty()) { if (sortSIL()) { std::vector RPOT; auto *UnsafeF = const_cast(Block->getParent()); std::copy(po_begin(UnsafeF), po_end(UnsafeF), std::back_inserter(RPOT)); std::reverse(RPOT.begin(), RPOT.end()); // Initialize IDs so our IDs are in RPOT as well. This is a hack. for (unsigned Index : indices(RPOT)) BlocksToIDMap[RPOT[Index]] = Index; } else { unsigned idx = 0; for (const SILBasicBlock &B : *Block->getParent()) BlocksToIDMap[&B] = idx++; } } ID R = {ID::SILBasicBlock, BlocksToIDMap[Block]}; return R; } ID SILPrintContext::getID(const SILNode *node) { if (node == nullptr) return {ID::Null, ~0U}; if (isa(node)) return {ID::SILUndef, 0}; SILBasicBlock *BB = node->getParentBlock(); if (SILFunction *F = BB->getParent()) { setContext(F); // Lazily initialize the instruction -> ID mapping. if (ValueToIDMap.empty()) F->numberValues(ValueToIDMap); ID R = {ID::SSAValue, ValueToIDMap[node]}; return R; } setContext(BB); // Check if we have initialized our ValueToIDMap yet. If we have, just use // that. if (!ValueToIDMap.empty()) { ID R = {ID::SSAValue, ValueToIDMap[node]}; return R; } // Otherwise, initialize the instruction -> ID mapping cache. unsigned idx = 0; for (auto &I : *BB) { // Give the instruction itself the next ID. ValueToIDMap[&I] = idx; // If there are no results, make sure we don't reuse that ID. auto results = I.getResults(); if (results.empty()) { idx++; continue; } // Otherwise, assign all of the results an index. Note that // we'll assign the same ID to both the instruction and the // first result. for (auto result : results) { ValueToIDMap[result] = idx++; } } ID R = {ID::SSAValue, ValueToIDMap[node]}; return R; }