//===--- 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/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/Assertions.h" #include "swift/Basic/QuotedString.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/SourceManager.h" #include "swift/Demangling/Demangle.h" #include "swift/SIL/ApplySite.h" #include "swift/SIL/CFG.h" #include "swift/SIL/InstructionUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILCoverageMap.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILMoveOnlyDeinit.h" #include "swift/SIL/SILPrintContext.h" #include "swift/SIL/SILVTable.h" #include "swift/SIL/SILVisitor.h" #include "swift/SIL/TerminatorUtils.h" #include "swift/Strings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.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/FileSystem.h" #include "llvm/Support/FormattedStream.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 SILPrintDebugInfoVerbose("sil-print-debuginfo-verbose", llvm::cl::init(false), llvm::cl::desc("Print verbose debug info output")); llvm::cl::opt SILPrintSourceInfo("sil-print-sourceinfo", llvm::cl::init(false), llvm::cl::desc("Include source annotation in SIL output")); llvm::cl::opt SILPrintTypes("sil-print-types", llvm::cl::init(false), llvm::cl::desc("always print type annotations for instruction operands in SIL output")); llvm::cl::opt SILPrintNoUses("sil-print-no-uses", llvm::cl::init(false), llvm::cl::desc("omit use comments 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; std::optional OwnershipKind; bool IsNoImplicitCopy = false; LifetimeAnnotation Lifetime = LifetimeAnnotation::None; bool IsCapture = false; bool IsReborrow = false; bool IsEscaping = false; bool needPrintType = false; SILValuePrinterInfo(ID ValueID) : ValueID(ValueID), Type(), OwnershipKind() {} SILValuePrinterInfo(ID ValueID, SILType Type, bool needPrintType) : ValueID(ValueID), Type(Type), OwnershipKind(), needPrintType(needPrintType) {} SILValuePrinterInfo(ID ValueID, SILType Type, ValueOwnershipKind OwnershipKind) : ValueID(ValueID), Type(Type), OwnershipKind(OwnershipKind) {} SILValuePrinterInfo(ID ValueID, SILType Type, ValueOwnershipKind OwnershipKind, bool IsNoImplicitCopy, LifetimeAnnotation Lifetime, bool IsCapture, bool IsReborrow, bool IsEscaping, bool needPrintType) : ValueID(ValueID), Type(Type), OwnershipKind(OwnershipKind), IsNoImplicitCopy(IsNoImplicitCopy), Lifetime(Lifetime), IsCapture(IsCapture), IsReborrow(IsReborrow), IsEscaping(IsEscaping), needPrintType(needPrintType){} SILValuePrinterInfo(ID ValueID, SILType Type, bool IsNoImplicitCopy, LifetimeAnnotation Lifetime, bool IsCapture, bool IsReborrow, bool IsEscaping, bool needPrintType) : ValueID(ValueID), Type(Type), OwnershipKind(), IsNoImplicitCopy(IsNoImplicitCopy), Lifetime(Lifetime), IsCapture(IsCapture), IsReborrow(IsReborrow), IsEscaping(IsEscaping), needPrintType(needPrintType) {} SILValuePrinterInfo(ID ValueID, SILType Type, ValueOwnershipKind OwnershipKind, bool IsReborrow, bool IsEscaping, bool needPrintType) : ValueID(ValueID), Type(Type), OwnershipKind(OwnershipKind), IsReborrow(IsReborrow), IsEscaping(IsEscaping), needPrintType(needPrintType) {} }; /// Return the fully qualified dotted path for DeclContext. static void printFullContext(const DeclContext *Context, raw_ostream &Buffer) { if (!Context) return; switch (Context->getContextKind()) { case swift::DeclContextKind::Package: return; 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::MacroDecl: // Ignore the macro, which won't have anything in it; just print the module. printFullContext(Context->getParent(), Buffer); return; case DeclContextKind::Initializer: // FIXME Buffer << ""; return; case DeclContextKind::AbstractClosureExpr: case DeclContextKind::SerializedAbstractClosure: // FIXME 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: case DeclContextKind::SerializedTopLevelCodeDecl: // 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 isKeyword = 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/AST/TokenKinds.def" .Default(false); bool shouldEscapeIdentifier = !Decl->getBaseName().isSpecial() && (isKeyword || Decl->getBaseName().mustAlwaysBeEscaped()); if (shouldEscapeIdentifier) { OS << '`'; } OS << Decl->getBaseName().userFacingName(); if (shouldEscapeIdentifier) { OS << '`'; } } } /// 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; switch (getLocKind()) { case LocKind::Closure: OS << ""; break; case LocKind::File: OS << ""; break; case LocKind::Decl: { if (kind != Kind::Func) { printValueDecl(getDecl(), OS); break; } auto *accessor = dyn_cast(getDecl()); if (!accessor) { printValueDecl(getDecl(), OS); isDot = false; break; } printValueDecl(accessor->getStorage(), OS); switch (accessor->getAccessorKind()) { case AccessorKind::WillSet: OS << "!willSet"; break; case AccessorKind::DidSet: OS << "!didSet"; break; case AccessorKind::Get: OS << "!getter"; break; case AccessorKind::DistributedGet: OS << "!_distributed_getter"; break; case AccessorKind::Set: OS << "!setter"; break; case AccessorKind::Address: OS << "!addressor"; break; case AccessorKind::MutableAddress: OS << "!mutableAddressor"; break; case AccessorKind::Read: OS << "!read"; break; case AccessorKind::Modify: OS << "!modify"; break; case AccessorKind::Init: OS << "!init"; break; case AccessorKind::Read2: OS << "!read2"; break; case AccessorKind::Modify2: OS << "!modify2"; break; } break; } } switch (kind) { case SILDeclRef::Kind::Func: case SILDeclRef::Kind::EntryPoint: case SILDeclRef::Kind::AsyncEntryPoint: 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::IsolatedDeallocator: OS << "!isolateddeallocator"; 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; case SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue: OS << "!projectedvalueinit"; break; } if (isForeign) OS << (isDot ? '.' : '!') << "foreign"; if (getDerivativeFunctionIdentifier()) { OS << ((isDot || isForeign) ? '.' : '!'); switch (getDerivativeFunctionIdentifier()->getKind()) { case AutoDiffDerivativeFunctionKind::JVP: OS << "jvp."; break; case AutoDiffDerivativeFunctionKind::VJP: OS << "vjp."; break; } OS << getDerivativeFunctionIdentifier()->getParameterIndices()->getString(); if (auto derivativeGenSig = getDerivativeFunctionIdentifier()->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 && Subs.empty()) return; auto PrintSubstitutions = [&](SubstitutionMap Subs) { OS << '<'; interleave(Subs.getReplacementTypes(), [&](Type type) { OS << type; }, [&] { OS << ", "; }); OS << '>'; OS << " conformances <"; interleave(Subs.getConformances(), [&](ProtocolConformanceRef conf) { conf.print(OS); }, [&] { 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 PrintOptions &PO) const { printSILTypeColorAndSigil(OS, *this); // Print other types as their Swift representation. // // NOTE: We always print the Raw AST type so we don't look through // move-onlyness. getRawASTType().print(OS, PO); } 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, const SILPrintContext *silPrintContext = nullptr) { function->printName(OS); OS << " : $"; auto *genEnv = function->getGenericEnvironment(); GenericSignature genSig; // If `genEnv` is defined, get sugared names of generic // parameter types for printing. if (genEnv) { genSig = genEnv->getGenericSignature(); 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->getGenericSignature()->getSugaredType(paramTy); // Opaque parameter types are printed as their canonical types and not // the unparseable "". if (sugaredTy->getOpaqueDecl()) continue; 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(silPrintContext); printOptions.GenericSig = genSig.getPointer(); 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 { // 1. Accumulate opcode-specific comments in this stream. // 2. Start emitting comments: lineComments.start() // 3. Emit each comment section: lineComments.delim() // 4. End emitting comments: LineComments::end() class LineComments : public raw_ostream { llvm::formatted_raw_ostream &os; // Opcode-specific comments to be printed at the end of the current line. std::string opcodeCommentString; llvm::raw_string_ostream opcodeCommentStream; bool emitting = false; bool printedSlashes = false; public: LineComments(llvm::formatted_raw_ostream &os) : os(os), opcodeCommentStream(opcodeCommentString) { SetUnbuffered(); // pass through to the underlying stream } // Call to start emitting line comments into the underlying stream. void start() { emitting = true; printedSlashes = false; if (opcodeCommentString.empty()) return; delim(); os << opcodeCommentString; opcodeCommentString.clear(); } // Call for each section of line void delim() { assert(emitting); if (printedSlashes) { os << "; "; } else { os.PadToColumn(50); os << "// "; printedSlashes = true; } } void end() { assert(emitting); emitting = false; printedSlashes = false; os << "\n"; } protected: void write_impl(const char *ptr, size_t size) override { if (emitting) os.write(ptr, size); else opcodeCommentStream.write(ptr, size); } uint64_t current_pos() const override { if (emitting) return os.tell() - os.GetNumBytesInBuffer(); return opcodeCommentString.size(); } }; } // namespace namespace swift { /// 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; LineComments lineComments; unsigned LastBufferID; llvm::DenseSet printedBlocks; // 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(int64_t) SIMPLE_PRINTER(StringRef) SIMPLE_PRINTER(Identifier) SIMPLE_PRINTER(ID) SIMPLE_PRINTER(QuotedString) SIMPLE_PRINTER(SILDeclRef) SIMPLE_PRINTER(APInt) SIMPLE_PRINTER(ValueOwnershipKind) SIMPLE_PRINTER(UUID) SIMPLE_PRINTER(GenericSignature) SIMPLE_PRINTER(ActorIsolation) #undef SIMPLE_PRINTER SILPrinter &operator<<(SILValuePrinterInfo i) { SILColor C(PrintState.OS, SC_Type); *this << i.ValueID; if (!i.Type) return *this; const char *separator = " : "; if (i.IsNoImplicitCopy) { *this << separator << "@noImplicitCopy"; separator = " "; } switch (i.Lifetime) { case LifetimeAnnotation::EagerMove: *this << separator << "@_eagerMove"; separator = " "; break; case LifetimeAnnotation::None: break; case LifetimeAnnotation::Lexical: *this << separator << "@_lexical"; separator = " "; break; } if (i.IsCapture) { *this << separator << "@closureCapture"; separator = " "; } if (i.IsReborrow) { *this << separator << "@reborrow"; separator = " "; } if (i.IsEscaping) { *this << separator << "@pointer_escape"; separator = " "; } if (!i.IsReborrow && i.OwnershipKind && *i.OwnershipKind != OwnershipKind::None) { *this << separator << "@" << i.OwnershipKind.value(); separator = " "; } if (i.needPrintType) { *this << separator << i.Type; } return *this; } bool needPrintTypeFor(SILValue V) { if (SILPrintTypes) return true; if (!V) return false; if (isa(V)) return true; // Make sure to print the type if the operand's definition was not printed so far return printedBlocks.count(V->getParentBlock()) == 0; } 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.getRawASTType().print(PrintState.OS, PrintState.ASTOptions); return *this; } public: SILPrinter( SILPrintContext &PrintCtx, llvm::DenseMap *AlternativeTypeNames = nullptr) : Ctx(PrintCtx), PrintState{{PrintCtx.OS()}, PrintOptions::printSIL(&PrintCtx)}, lineComments(PrintState.OS), LastBufferID(0) { PrintState.ASTOptions.AlternativeTypeNames = AlternativeTypeNames; PrintState.ASTOptions.PrintForSIL = true; } SILValuePrinterInfo getIDAndType(SILValue V) { return {Ctx.getID(V), V ? V->getType() : SILType(), needPrintTypeFor(V)}; } SILValuePrinterInfo getIDAndForcedPrintedType(SILValue V) { return {Ctx.getID(V), V ? V->getType() : SILType(), /*needPrintType=*/true}; } SILValuePrinterInfo getIDAndType(SILFunctionArgument *arg) { return {Ctx.getID(arg), arg->getType(), arg->isNoImplicitCopy(), arg->getLifetimeAnnotation(), arg->isClosureCapture(), arg->isReborrow(), arg->hasPointerEscape(), /*needPrintType=*/true}; } SILValuePrinterInfo getIDAndType(SILArgument *arg) { return {Ctx.getID(arg), arg->getType(), /*needPrintType=*/true}; } SILValuePrinterInfo getIDAndTypeAndOwnership(SILValue V) { return {Ctx.getID(V), V ? V->getType() : SILType(), V->getOwnershipKind()}; } SILValuePrinterInfo getIDAndTypeAndOwnership(SILFunctionArgument *arg) { return {Ctx.getID(arg), arg->getType(), arg->getOwnershipKind(), arg->isNoImplicitCopy(), arg->getLifetimeAnnotation(), arg->isClosureCapture(), arg->isReborrow(), arg->hasPointerEscape(), /*needPrintType=*/true}; } SILValuePrinterInfo getIDAndTypeAndOwnership(SILArgument *arg) { return {Ctx.getID(arg), arg->getType(), arg->getOwnershipKind(), arg->isReborrow(), arg->hasPointerEscape(), /*needPrintType=*/true}; } void markBlockAsPrinted(const SILBasicBlock *block) { printedBlocks.insert(block); } //===--------------------------------------------------------------------===// // 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 (SILPrintNoUses) return; if (BB->args_empty()) return; for (SILArgument *arg : BB->getArguments()) { StringRef name; if (arg->getDecl() && arg->getDecl()->hasName()) name = arg->getDecl()->getBaseName().userFacingName(); if (arg->use_empty() && name.empty()) continue; *this << "// " << Ctx.getID(arg); if (!name.empty()) { *this << " \"" << name << '\"'; } if (!arg->use_empty()) { PrintState.OS.PadToColumn(50); *this << "// user"; if (std::next(arg->use_begin()) != arg->use_end()) *this << 's'; *this << ": "; llvm::SmallVector UserIDs; for (auto *Op : arg->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()); } llvm::interleave( UserIDs.begin(), UserIDs.end(), [&](ID id) { *this << id; }, [&] { *this << ", "; }); } *this << '\n'; } } void printBlockArguments(const SILBasicBlock *BB) { if (BB->args_empty()) return; *this << '('; // If SIL ownership is enabled and the given function has not had ownership // stripped out, print out ownership of SILArguments. if (BB->getParent()->hasOwnership()) { if (BB->isEntry()) { auto Args = BB->getSILFunctionArguments(); *this << getIDAndTypeAndOwnership(Args[0]); for (unsigned i : range(1, Args.size())) { SILFunctionArgument *Arg = Args[i]; *this << ", " << getIDAndTypeAndOwnership(Arg); } *this << ')'; } else { ArrayRef Args = BB->getArguments(); *this << getIDAndTypeAndOwnership(Args[0]); for (SILArgument *Arg : Args.drop_front()) { *this << ", " << getIDAndTypeAndOwnership(Arg); } *this << ')'; } return; } if (BB->isEntry()) { auto Args = BB->getSILFunctionArguments(); *this << getIDAndType(Args[0]); for (unsigned i : range(1, Args.size())) { SILFunctionArgument *Arg = Args[i]; *this << ", " << getIDAndType(Arg); } *this << ')'; return; } ArrayRef Args = BB->getArguments(); *this << getIDAndType(Args[0]); for (SILArgument *Arg : Args.drop_front()) { *this << ", " << getIDAndType(Arg); } *this << ')'; } #ifndef NDEBUG void printID(const SILBasicBlock *BB, bool newline) { *this << Ctx.getID(BB); if (newline) { *this << "\n"; } } #endif void print(const SILBasicBlock *BB) { markBlockAsPrinted(BB); // Output uses for BB arguments. These are put into place as comments before // the block header. printBlockArgumentUses(BB); // If the basic block has a name available, print it as well auto debugName = BB->getDebugName(); if (debugName.has_value()) { *this << "// " << debugName.value() << '\n'; } // Then print the name of our block, the arguments, and the block colon. *this << Ctx.getID(BB); printBlockArguments(BB); *this << ":"; if (!BB->pred_empty() && !SILPrintNoUses) { 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; std::optional PrevLoc; for (const SILInstruction &I : *BB) { if (SILPrintSourceInfo) { auto CurSourceLoc = I.getLoc().getSourceLoc(); if (CurSourceLoc.isValid()) { if (!PrevLoc || SM.getLineAndColumnInBuffer(CurSourceLoc).first > SM.getLineAndColumnInBuffer(PrevLoc->getSourceLoc()).first) { auto Buffer = SM.findBufferContainingLoc(CurSourceLoc); auto Line = SM.getLineAndColumnInBuffer(CurSourceLoc).first; auto LineLength = SM.getLineLength(Buffer, Line); PrintState.OS << " // " << SM.extractText( {SM.getLocForLineCol(Buffer, Line, 0), LineLength.value_or(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.getSubstitutionMap().empty()) && AI.getCalleeFunction()) printGenericSpecializationInfo( PrintState.OS, "call-site", AI.getCalleeFunction()->getName(), AI.getSpecializationInfo(), AI.getSubstitutionMap()); } print(&I); } } //===--------------------------------------------------------------------===// // SILInstruction Printing Logic void printCastingIsolatedConformancesIfNeeded(CastingIsolatedConformances flag) { switch (flag) { case CastingIsolatedConformances::Allow: break; case CastingIsolatedConformances::Prohibit: *this << "[prohibit_isolated_conformances] "; break; } } void printTypeDependentOperands(const SILInstruction *I) { ArrayRef TypeDepOps = I->getTypeDependentOperands(); if (TypeDepOps.empty()) return; lineComments.delim(); *this << "type-defs: "; interleave(TypeDepOps, [&](const Operand &op) { *this << Ctx.getID(op.get()); }, [&] { *this << ", "; }); } /// 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. void printUsersOfValue(SILValue value) { lineComments.start(); printUserList({value}, value); lineComments.end(); } void printUsersOfInstruction(const SILInstruction *inst) { llvm::SmallVector values; llvm::copy(inst->getResults(), std::back_inserter(values)); printUserList(values, inst); printBranchTargets(inst); } void printUserList(ArrayRef values, SILNodePointer node) { if (SILPrintNoUses) return; // 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; } lineComments.delim(); if (values.empty()) { *this << "id: " << Ctx.getID(node); return; } 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()); } llvm::interleave( UserIDs.begin(), UserIDs.end(), [&](ID id) { *this << id; }, [&] { *this << ", "; }); } void printBranchTargets(const SILInstruction *inst) { if (auto condBr = dyn_cast(inst)) { if (condBr->getTrueBB()->getDebugName().has_value()) { *this << ", true->" << condBr->getTrueBB()->getDebugName().value(); } if (condBr->getFalseBB()->getDebugName().has_value()) { *this << ", false->" << condBr->getFalseBB()->getDebugName().value(); } } else if (auto br = dyn_cast(inst)) { if (br->getDestBB()->getDebugName().has_value()) { *this << ", dest->" << br->getDestBB()->getDebugName().value(); } } else if (auto termInst = dyn_cast(inst)) { // Otherwise, we just print the successors in order without pretty printing for (unsigned i = 0, numSuccessors = termInst->getSuccessors().size(); i != numSuccessors; ++i) { auto &successor = termInst->getSuccessors()[i]; if (successor.getBB()->getDebugName().has_value()) { *this << ", #" << i << "->" << successor.getBB()->getDebugName().value(); } } } } void printConformances(ArrayRef conformances) { // FIXME: conformances should always be printed and parsed! if (!Ctx.printVerbose()) { return; } for (ProtocolConformanceRef conformance : conformances) { conformance.dump(lineComments, /*indent*/ 0, /*details*/ false); } } void printDebugLocRef(SILLocation Loc, const SourceManager &SM, bool PrintComma = true) { auto DL = Loc.decodeForDebugging(SM); if (!DL.filename.empty()) { if (PrintComma) *this << ", "; *this << "loc "; if (Loc.isAutoGenerated()) *this << "* "; *this << QuotedString(DL.filename) << ':' << DL.line << ':' << (unsigned)DL.column; if (SILPrintDebugInfoVerbose) { if (Loc.isImplicit()) *this << " isImplicit: " << "true"; else *this << " isImplicit: " << "false"; if (Loc.isAutoGenerated()) *this << ", isAutoGenerated: " << "true"; else *this << ", isAutoGenerated: " << "false"; if (Loc.isHiddenFromDebugInfo()) *this << ", isHiddenFromDebugInfo: " << "true"; else *this << ", isHiddenFromDebugInfo: " << "false"; } } } 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) { lineComments.delim(); if (!L.isNull()) { // 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"; } 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->getReferencedFunction()->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->isDeleted() && 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. if (Ctx.printDebugInfo() && !I->isDeleted() && !I->isStaticInitializerInst()) { auto &SM = I->getModule().getASTContext().SourceMgr; printDebugLocRef(I->getLoc(), SM); printDebugScopeRef(I->getDebugScope(), SM); } lineComments.start(); printTypeDependentOperands(I); // Print users, or id for valueless instructions. printUsersOfInstruction(I); // Print SIL location. if (Ctx.printVerbose()) { printSILLocation(I->getLoc(), I->getModule(), I->getDebugScope()); } lineComments.end(); } 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; case SILNodeKind::PlaceholderValue: // This should really only happen during debugging. *this << "placeholder<" << cast(node)->getType() << ">\n"; return; case SILNodeKind::MultipleValueInstructionResult: 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. printUsersOfValue(arg); } 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 << '('; llvm::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. printUsersOfValue(result); } void printInContext(const SILNode *node) { auto sortByID = [&](SILNodePointer a, SILNodePointer 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 printDebugInfoExpression(const SILDebugInfoExpression &DIExpr) { assert(DIExpr && "DIExpression empty?"); *this << ", expr "; bool IsFirst = true; for (const auto &Operand : DIExpr.operands()) { if (IsFirst) IsFirst = false; else *this << ":"; // Print the operator SILDIExprOperator Op = Operand.getOperator(); assert(Op != SILDIExprOperator::INVALID && "Invalid SILDIExprOperator kind"); *this << SILDIExprInfo::get(Op)->OpText; // Print arguments for (const auto &Arg : Operand.args()) { *this << ":"; switch (Arg.getKind()) { case SILDIExprElement::OperatorKind: llvm_unreachable("Cannot use operator as argument"); break; case SILDIExprElement::DeclKind: { const Decl *D = Arg.getAsDecl(); // FIXME: Can we generalize this special handling for VarDecl // to other kinds of Decl? if (const auto *VD = dyn_cast(D)) { *this << "#"; printFullContext(VD->getDeclContext(), PrintState.OS); *this << VD->getName().get(); } else D->print(PrintState.OS, PrintState.ASTOptions); break; } case SILDIExprElement::ConstIntKind: { uint64_t V = *Arg.getAsConstInt(); if (Op == SILDIExprOperator::ConstSInt) *this << static_cast(V); else *this << V; break; } case SILDIExprElement::TypeKind: { const Type TypePtr = Arg.getAsType(); *this << "$"; TypePtr->print(PrintState.OS, PrintState.ASTOptions); } } } } } void printDebugVar(std::optional Var, const SourceManager *SM = nullptr) { if (!Var) return; if (!Var->Name.empty()) { if (Var->Constant) *this << ", let"; else *this << ", var"; if ((Var->Loc || Var->Scope) && SM && Ctx.printDebugInfo()) { *this << ", (name \"" << Var->Name << '"'; if (Var->Loc) printDebugLocRef(*Var->Loc, *SM); if (Var->Scope) printDebugScopeRef(Var->Scope, *SM); *this << ")"; } else *this << ", name \"" << Var->Name << '"'; if (Var->ArgNo) *this << ", argno " << Var->ArgNo; if (Var->Type) { *this << ", type "; Var->Type->print(PrintState.OS, PrintState.ASTOptions); } } // Although it's rare in real-world use cases, but during testing, // sometimes we want to print out di-expression, even the debug // variable name is empty. if (Var->DIExpr) printDebugInfoExpression(Var->DIExpr); } void visitAllocStackInst(AllocStackInst *AVI) { if (AVI->hasDynamicLifetime()) *this << "[dynamic_lifetime] "; if (AVI->isLexical()) *this << "[lexical] "; if (AVI->isFromVarDecl()) *this << "[var_decl] "; if (AVI->usesMoveableValueDebugInfo() && !AVI->getType().isMoveOnly()) *this << "[moveable_value_debuginfo] "; *this << AVI->getElementType(); printDebugVar(AVI->getVarInfo(false), &AVI->getModule().getASTContext().SourceMgr); } void visitAllocPackInst(AllocPackInst *API) { *this << API->getType().getObjectType(); } void visitAllocPackMetadataInst(AllocPackMetadataInst *APMI) { *this << APMI->getType().getObjectType(); } 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) { if (ARI->isBare()) *this << "[bare] "; printAllocRefInstBase(ARI); *this << ARI->getType(); } void visitAllocRefDynamicInst(AllocRefDynamicInst *ARDI) { printAllocRefInstBase(ARDI); *this << getIDAndType(ARDI->getMetatypeOperand()); *this << ", " << ARDI->getType(); } void visitAllocBoxInst(AllocBoxInst *ABI) { if (ABI->hasDynamicLifetime()) *this << "[dynamic_lifetime] "; if (ABI->emitReflectionMetadata()) { *this << "[reflection] "; } if (ABI->hasPointerEscape()) { *this << "[pointer_escape] "; } if (ABI->usesMoveableValueDebugInfo() && !ABI->getAddressType().isMoveOnly()) { *this << "[moveable_value_debuginfo] "; } *this << ABI->getType(); printDebugVar(ABI->getVarInfo(false), &ABI->getModule().getASTContext().SourceMgr); } 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 << '('; llvm::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] "; if (AI->isNonAsync()) *this << "[noasync] "; if (auto isolationCrossing = AI->getIsolationCrossing()) { auto callerIsolation = isolationCrossing->getCallerIsolation(); if (callerIsolation != ActorIsolation::Unspecified) { *this << "[callee_isolation="; callerIsolation.printForSIL(PrintState.OS); *this << "] "; } auto calleeIsolation = isolationCrossing->getCalleeIsolation(); if (calleeIsolation != ActorIsolation::Unspecified) { *this << "[caller_isolation="; calleeIsolation.printForSIL(PrintState.OS); *this << "] "; } } visitApplyInstBase(AI); } void visitBeginApplyInst(BeginApplyInst *AI) { if (AI->isNonThrowing()) *this << "[nothrow] "; visitApplyInstBase(AI); } void visitTryApplyInst(TryApplyInst *AI) { if (AI->isNonAsync()) *this << "[noasync] "; visitApplyInstBase(AI); *this << ", normal " << Ctx.getID(AI->getNormalBB()); *this << ", error " << Ctx.getID(AI->getErrorBB()); if (AI->getNormalBBCount()) *this << " !normal_count(" << AI->getNormalBBCount().getValue() << ")"; if (AI->getErrorBBCount()) *this << " !error_count(" << AI->getErrorBBCount().getValue() << ")"; } void visitPartialApplyInst(PartialApplyInst *CI) { auto fnType = CI->getFunctionType(); switch (fnType->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_Inout: case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_InoutAliasable: case ParameterConvention::Indirect_In_CXX: case ParameterConvention::Pack_Guaranteed: case ParameterConvention::Pack_Owned: case ParameterConvention::Pack_Inout: llvm_unreachable("unexpected callee convention!"); } switch (fnType->getIsolation().getKind()) { case SILFunctionTypeIsolation::Unknown: break; case SILFunctionTypeIsolation::Erased: *this << "[isolated_any] "; break; } 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()) << " as " << AI->getType(); } void visitFunctionRefInst(FunctionRefInst *FRI) { FRI->getReferencedFunction()->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 << "("; llvm::interleave(BI->getArguments(), [&](SILValue v) { *this << getIDAndType(v); }, [&]{ *this << ", "; }); *this << ") : "; *this << BI->getType(); } void visitMergeIsolationRegionInst(MergeIsolationRegionInst *mir) { llvm::interleave( mir->getArguments(), [&](SILValue v) { *this << getIDAndType(v); }, [&] { *this << ", "; }); } 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(); if (SILValue token = GAI->getDependencyToken()) { *this << " depends_on " << Ctx.getID(token); } } void visitGlobalValueInst(GlobalValueInst *GVI) { if (GVI->isBare()) *this << "[bare] "; GVI->getReferencedGlobal()->printName(PrintState.OS); *this << " : " << GVI->getType(); } void visitBaseAddrForOffsetInst(BaseAddrForOffsetInst *BAI) { *this << BAI->getType(); } void visitIntegerLiteralInst(IntegerLiteralInst *ILI) { const auto &lit = ILI->getValue(); *this << ILI->getType() << ", " << lit; } void visitFloatLiteralInst(FloatLiteralInst *FLI) { llvm::SmallString<12> hex; llvm::SmallString<12> decimal; FLI->getBits().toString(hex, 16, /*Signed*/ false); FLI->getValue().toString(decimal); *this << FLI->getType() << (llvm::Twine(", 0x") + hex + " // " + decimal).str(); } static StringRef getStringEncodingName(StringLiteralInst::Encoding kind) { switch (kind) { case StringLiteralInst::Encoding::Bytes: return "bytes "; case StringLiteralInst::Encoding::UTF8: return "utf8 "; case StringLiteralInst::Encoding::UTF8_OSLOG: return "oslog "; 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) { if (LBI->isUnchecked()) { *this << "[unchecked] "; } *this << getIDAndType(LBI->getOperand()); } void visitBeginBorrowInst(BeginBorrowInst *BBI) { if (BBI->isLexical()) { *this << "[lexical] "; } if (BBI->hasPointerEscape()) { *this << "[pointer_escape] "; } if (BBI->isFromVarDecl()) { *this << "[var_decl] "; } if (BBI->isFixed()) { *this << "[fixed] "; } *this << getIDAndType(BBI->getOperand()); } void visitBorrowedFromInst(BorrowedFromInst *bfi) { *this << getIDAndType(bfi->getBorrowedValue()); *this << " from ("; bool first = true; for (SILValue ev : bfi->getEnclosingValues()) { if (!first) { *this << ", "; } first = false; *this << getIDAndType(ev); } *this << ")"; } 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 printForwardingOwnershipKind(ForwardingInstruction *inst, SILValue op) { if (!op) return; if (inst->getForwardingOwnershipKind() != op->getOwnershipKind()) { *this << ", forwarding: @" << inst->getForwardingOwnershipKind(); } } 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 "; switch (AI->getMode()) { case AssignByWrapperInst::Unknown: break; case AssignByWrapperInst::Initialization: *this << "[init] "; break; case AssignByWrapperInst::Assign: *this << "[assign] "; break; case AssignByWrapperInst::AssignWrappedValue: *this << "[assign_wrapped_value] "; break; } *this << getIDAndType(AI->getDest()) << ", init " << getIDAndType(AI->getInitializer()) << ", set " << getIDAndType(AI->getSetter()); } void visitAssignOrInitInst(AssignOrInitInst *AI) { switch (AI->getMode()) { case AssignOrInitInst::Unknown: break; case AssignOrInitInst::Init: *this << "[init] "; break; case AssignOrInitInst::Set: *this << "[set] "; break; } // Print all of the properties that have been previously initialized. for (unsigned i = 0, n = AI->getNumInitializedProperties(); i != n; ++i) { if (AI->isPropertyAlreadyInitialized(i)) { *this << "[assign=" << i << "] "; } } *this << "#"; printFullContext(AI->getProperty()->getDeclContext(), PrintState.OS); *this << AI->getPropertyName(); *this << ", self " << getIDAndType(AI->getSelf()); *this << ", value " << getIDAndType(AI->getSrc()); *this << ", init " << getIDAndType(AI->getInitializer()) << ", set " << getIDAndType(AI->getSetter()); } void visitMarkUninitializedInst(MarkUninitializedInst *MU) { switch (MU->getMarkUninitializedKind()) { 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; case MarkUninitializedInst::Out: *this << "[out] "; break; } *this << getIDAndType(MU->getOperand()); printForwardingOwnershipKind(MU, MU->getOperand()); } void visitMarkFunctionEscapeInst(MarkFunctionEscapeInst *MFE) { llvm::interleave( MFE->getElements(), [&](SILValue Var) { *this << getIDAndType(Var); }, [&] { *this << ", "; }); } void visitDebugValueInst(DebugValueInst *DVI) { if (DVI->poisonRefs()) *this << "[poison] "; if (DVI->usesMoveableValueDebugInfo() && !DVI->getOperand()->getType().isMoveOnly()) *this << "[moveable_value_debuginfo] "; if (DVI->hasTrace()) *this << "[trace] "; *this << getIDAndType(DVI->getOperand()); printDebugVar(DVI->getVarInfo(false), &DVI->getModule().getASTContext().SourceMgr); } void visitDebugStepInst(DebugStepInst *dsi) { // nothing to print other than the instruction name } #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 << "[init] "; \ *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 << "[init] "; *this << getIDAndType(CI->getDest()); } void visitExplicitCopyAddrInst(ExplicitCopyAddrInst *CI) { if (CI->isTakeOfSrc()) *this << "[take] "; *this << Ctx.getID(CI->getSrc()) << " to "; if (CI->isInitializationOfDest()) *this << "[init] "; *this << getIDAndType(CI->getDest()); } void visitMarkUnresolvedMoveAddrInst(MarkUnresolvedMoveAddrInst *CI) { *this << Ctx.getID(CI->getSrc()) << " to "; *this << getIDAndType(CI->getDest()); } void visitBindMemoryInst(BindMemoryInst *BI) { *this << getIDAndType(BI->getBase()) << ", "; *this << getIDAndType(BI->getIndex()) << " to "; *this << BI->getBoundType(); } void visitRebindMemoryInst(RebindMemoryInst *BI) { *this << getIDAndType(BI->getBase()) << " to "; *this << getIDAndType(BI->getInToken()); } void visitUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *CI) { printCastingIsolatedConformancesIfNeeded(CI->getIsolatedConformances()); *this << getIDAndType(CI->getOperand()) << " to " << CI->getTargetFormalType(); printForwardingOwnershipKind(CI, CI->getOperand()); } void visitCheckedCastBranchInst(CheckedCastBranchInst *CI) { printCastingIsolatedConformancesIfNeeded(CI->getIsolatedConformances()); if (CI->isExact()) *this << "[exact] "; *this << CI->getSourceFormalType() << " in "; *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() << ")"; printForwardingOwnershipKind(CI, CI->getOperand()); } void visitUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *CI) { printCastingIsolatedConformancesIfNeeded(CI->getIsolatedConformances()); *this << CI->getSourceFormalType() << " in " << getIDAndType(CI->getSrc()) << " to " << CI->getTargetFormalType() << " in " << getIDAndType(CI->getDest()); } void visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *CI) { printCastingIsolatedConformancesIfNeeded(CI->getIsolatedConformances()); *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(ConversionOperation CI, SILValue operand) { *this << getIDAndType(operand) << " to " << CI->getType(); if (auto *ofci = dyn_cast(*CI)) { printForwardingOwnershipKind(ofci, ofci->getOperand(0)); } } 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(); printForwardingOwnershipKind(CI, CI->getOperand()); } void visitThunkInst(ThunkInst *ti) { switch (ti->getThunkKind()) { case ThunkInst::Kind::Invalid: llvm_unreachable("Cannot print invalid?!"); break; case ThunkInst::Kind::Identity: *this << "[identity] "; break; } *this << Ctx.getID(ti->getOperand()); printSubstitutions( ti->getSubstitutionMap(), ti->getOrigCalleeType()->getInvocationGenericSignature()); *this << "() : " << ti->getOperand()->getType(); } void visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *CI) { *this << (CI->isLifetimeGuaranteed() ? "" : "[not_guaranteed] ") << getIDAndType(CI->getOperand()) << " to " << CI->getType(); } void visitUpcastInst(UpcastInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitAddressToPointerInst(AddressToPointerInst *CI) { *this << (CI->needsStackProtection() ? "[stack_protection] " : ""); printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitPointerToAddressInst(PointerToAddressInst *CI) { *this << getIDAndType(CI->getOperand()) << " to "; if (CI->isStrict()) *this << "[strict] "; if (CI->isInvariant()) *this << "[invariant] "; if (CI->alignment()) *this << "[align=" << CI->alignment()->value() << "] "; *this << CI->getType(); } void visitUncheckedRefCastInst(UncheckedRefCastInst *CI) { printUncheckedConversionInst(ConversionOperation(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(ConversionOperation(CI), CI->getOperand()); } void visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitUncheckedValueCastInst(UncheckedValueCastInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitRefToRawPointerInst(RefToRawPointerInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitRawPointerToRefInst(RawPointerToRefInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } #define LOADABLE_REF_STORAGE(Name, ...) \ void visitRefTo##Name##Inst(RefTo##Name##Inst *CI) { \ printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); \ } \ void visit##Name##ToRefInst(Name##ToRefInst *CI) { \ printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); \ } #include "swift/AST/ReferenceStorage.def" void visitThinToThickFunctionInst(ThinToThickFunctionInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitThickToObjCMetatypeInst(ThickToObjCMetatypeInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitObjCToThickMetatypeInst(ObjCToThickMetatypeInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitObjCMetatypeToObjectInst(ObjCMetatypeToObjectInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitObjCExistentialMetatypeToObjectInst( ObjCExistentialMetatypeToObjectInst *CI) { printUncheckedConversionInst(ConversionOperation(CI), CI->getOperand()); } void visitObjCProtocolInst(ObjCProtocolInst *CI) { *this << "#" << CI->getProtocol()->getName() << " : " << CI->getType(); } void visitRefToBridgeObjectInst(RefToBridgeObjectInst *I) { *this << getIDAndType(I->getOperand(0)) << ", " << getIDAndType(I->getBitsOperand()); printForwardingOwnershipKind(I, I->getOperand(0)); } void visitBridgeObjectToRefInst(BridgeObjectToRefInst *I) { printUncheckedConversionInst(ConversionOperation(I), I->getOperand()); printForwardingOwnershipKind(I, I->getOperand()); } void visitBridgeObjectToWordInst(BridgeObjectToWordInst *I) { printUncheckedConversionInst(ConversionOperation(I), I->getOperand()); } void visitCopyValueInst(CopyValueInst *I) { *this << getIDAndType(I->getOperand()); } void visitExplicitCopyValueInst(ExplicitCopyValueInst *I) { *this << getIDAndType(I->getOperand()); } void visitMoveValueInst(MoveValueInst *I) { if (I->getAllowDiagnostics()) *this << "[allows_diagnostics] "; if (I->isLexical()) *this << "[lexical] "; if (I->hasPointerEscape()) *this << "[pointer_escape] "; if (I->isFromVarDecl()) *this << "[var_decl] "; *this << getIDAndType(I->getOperand()); } void visitDropDeinitInst(DropDeinitInst *I) { *this << getIDAndType(I->getOperand()); } void visitMarkUnresolvedNonCopyableValueInst( MarkUnresolvedNonCopyableValueInst *I) { using CheckKind = MarkUnresolvedNonCopyableValueInst::CheckKind; if (I->isStrict()) { *this << "[strict] "; } switch (I->getCheckKind()) { case CheckKind::Invalid: llvm_unreachable("Invalid?!"); case CheckKind::ConsumableAndAssignable: *this << "[consumable_and_assignable] "; break; case CheckKind::NoConsumeOrAssign: *this << "[no_consume_or_assign] "; break; case CheckKind::AssignableButNotConsumable: *this << "[assignable_but_not_consumable] "; break; case CheckKind::InitableButNotConsumable: *this << "[initable_but_not_consumable] "; break; } *this << getIDAndType(I->getOperand()); } void visitMarkUnresolvedReferenceBindingInst( MarkUnresolvedReferenceBindingInst *I) { using Kind = MarkUnresolvedReferenceBindingInst::Kind; switch (I->getKind()) { case Kind::Invalid: llvm_unreachable("Invalid?!"); case Kind::InOut: *this << "[inout] "; break; } *this << getIDAndType(I->getOperand()); } void visitCopyableToMoveOnlyWrapperValueInst( CopyableToMoveOnlyWrapperValueInst *I) { switch (I->getInitialKind()) { case CopyableToMoveOnlyWrapperValueInst::Owned: *this << "[owned] "; break; case CopyableToMoveOnlyWrapperValueInst::Guaranteed: *this << "[guaranteed] "; break; } *this << getIDAndType(I->getOperand()); } void visitMoveOnlyWrapperToCopyableValueInst( MoveOnlyWrapperToCopyableValueInst *I) { switch (I->getInitialKind()) { case MoveOnlyWrapperToCopyableValueInst::Owned: *this << "[owned] "; break; case MoveOnlyWrapperToCopyableValueInst::Guaranteed: *this << "[guaranteed] "; break; } *this << getIDAndType(I->getOperand()); } void visitUnownedCopyValueInst(UnownedCopyValueInst *I) { *this << getIDAndType(I->getOperand()); } void visitWeakCopyValueInst(WeakCopyValueInst *I) { *this << getIDAndType(I->getOperand()); } #define REF_STORAGE(Name, ...) \ void visitStrongCopy##Name##ValueInst(StrongCopy##Name##ValueInst *I) { \ *this << getIDAndType(I->getOperand()); \ } #include "swift/AST/ReferenceStorage.def" void visitDestroyValueInst(DestroyValueInst *I) { if (I->poisonRefs()) *this << "[poison] "; if (I->isDeadEnd()) *this << "[dead_end] "; *this << getIDAndType(I->getOperand()); } void visitStructInst(StructInst *SI) { *this << SI->getType() << " ("; llvm::interleave( SI->getElements(), [&](const SILValue &V) { *this << getIDAndType(V); }, [&] { *this << ", "; }); *this << ')'; } void visitObjectInst(ObjectInst *OI) { *this << OI->getType() << " ("; llvm::interleave( OI->getBaseElements(), [&](const SILValue &V) { *this << getIDAndType(V); }, [&] { *this << ", "; }); if (!OI->getTailElements().empty()) { *this << ", [tail_elems] "; llvm::interleave( OI->getTailElements(), [&](const SILValue &V) { *this << getIDAndType(V); }, [&] { *this << ", "; }); } *this << ')'; } void visitVectorInst(VectorInst *vi) { *this << "("; llvm::interleave( vi->getElements(), [&](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()) { SimpleType = false; break; } } // If the type is simple, just print the tuple elements. if (SimpleType) { *this << '('; llvm::interleave( TI->getElements(), [&](const SILValue &V) { *this << getIDAndType(V); }, [&] { *this << ", "; }); *this << ')'; } else { // Otherwise, print the type, then each value. *this << TI->getType() << " ("; llvm::interleave( TI->getElements(), [&](const SILValue &V) { *this << Ctx.getID(V); }, [&] { *this << ", "; }); *this << ')'; } } void visitTupleAddrConstructorInst(TupleAddrConstructorInst *TI) { // First print out our dest. if (TI->isInitializationOfDest()) { *this << "[init] "; } else { *this << "[assign] "; } *this << getIDAndType(TI->getDest()); *this << " with ("; llvm::interleave( TI->getElements(), [&](const SILValue &V) { *this << getIDAndType(V); }, [&] { *this << ", "; }); *this << ')'; } void visitEnumInst(EnumInst *UI) { *this << UI->getType() << ", " << SILDeclRef(UI->getElement(), SILDeclRef::Kind::EnumElement); if (UI->hasOperand()) { *this << ", " << getIDAndType(UI->getOperand()); printForwardingOwnershipKind(UI, 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); printForwardingOwnershipKind(UDAI, UDAI->getOperand()); } 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->getFieldIndex(); printForwardingOwnershipKind(EI, EI->getOperand()); } void visitTupleElementAddrInst(TupleElementAddrInst *EI) { *this << getIDAndType(EI->getOperand()) << ", " << EI->getFieldIndex(); } void visitStructExtractInst(StructExtractInst *EI) { *this << getIDAndType(EI->getOperand()) << ", #"; printFullContext(EI->getField()->getDeclContext(), PrintState.OS); *this << EI->getField()->getName().get(); printForwardingOwnershipKind(EI, EI->getOperand()); } void visitStructElementAddrInst(StructElementAddrInst *EI) { *this << getIDAndType(EI->getOperand()) << ", #"; printFullContext(EI->getField()->getDeclContext(), PrintState.OS); *this << EI->getField()->getName().get(); } void visitVectorBaseAddrInst(VectorBaseAddrInst *vbai) { *this << getIDAndType(vbai->getVector()); } void visitRefElementAddrInst(RefElementAddrInst *EI) { *this << (EI->isImmutable() ? "[immutable] " : "") << getIDAndType(EI->getOperand()) << ", #"; printFullContext(EI->getField()->getDeclContext(), PrintState.OS); *this << EI->getField()->getName().get(); } void visitRefTailAddrInst(RefTailAddrInst *RTAI) { *this << (RTAI->isImmutable() ? "[immutable] " : "") << getIDAndType(RTAI->getOperand()) << ", " << RTAI->getTailType(); } void visitDestructureStructInst(DestructureStructInst *DSI) { *this << getIDAndType(DSI->getOperand()); printForwardingOwnershipKind(DSI, DSI->getOperand()); } void visitDestructureTupleInst(DestructureTupleInst *DTI) { *this << getIDAndType(DTI->getOperand()); printForwardingOwnershipKind(DTI, 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(); auto lookupType = WMI->getLookupType(); *this << "$" << lookupType << ", " << WMI->getMember() << " : "; WMI->getMember().getDecl()->getInterfaceType().print( PrintState.OS, QualifiedSILTypeOptions); if ((getLocalArchetypeOf(lookupType) || lookupType->hasDynamicSelfType()) && !WMI->getTypeDependentOperands().empty()) { *this << ", "; *this << getIDAndForcedPrintedType(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(); printForwardingOwnershipKind(OI, OI->getOperand()); } 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(); printForwardingOwnershipKind(OI, OI->getOperand()); } void visitOpenExistentialValueInst(OpenExistentialValueInst *OI) { *this << getIDAndType(OI->getOperand()) << " to " << OI->getType(); printForwardingOwnershipKind(OI, OI->getOperand()); } 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 << getIDAndForcedPrintedType(AEI->getOperand()) << " : $" << AEI->getFormalConcreteType() << ", " << AEI->getType(); printConformances(AEI->getConformances()); printForwardingOwnershipKind(AEI, AEI->getOperand()); } 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 visitPackLengthInst(PackLengthInst *PLI) { *this << "$" << PLI->getPackType(); } void visitDynamicPackIndexInst(DynamicPackIndexInst *DPII) { *this << Ctx.getID(DPII->getOperand()) << " of $" << DPII->getIndexedPackType(); } void visitPackPackIndexInst(PackPackIndexInst *PPII) { *this << PPII->getComponentStartIndex() << ", " << Ctx.getID(PPII->getOperand()) << " of $" << PPII->getIndexedPackType(); } void visitScalarPackIndexInst(ScalarPackIndexInst *SPII) { *this << SPII->getComponentIndex() << " of $" << SPII->getIndexedPackType(); } void visitOpenPackElementInst(OpenPackElementInst *OPEI) { auto env = OPEI->getOpenedGenericEnvironment(); auto subs = env->getOuterSubstitutions(); *this << Ctx.getID(OPEI->getIndexOperand()) << " of "; PrintOptions Opts; Opts.PrintInverseRequirements = true; subs.getGenericSignature().print(PrintState.OS, Opts); *this << " at "; printSubstitutions(subs); // The shape class in the opened environment is a canonical interface // type, which won't resolve in the generic signature we just printed. // Map it back to the sugared generic parameter. auto sugaredShapeClass = subs.getGenericSignature()->getSugaredType( env->getOpenedElementShapeClass()); *this << ", shape $" << sugaredShapeClass << ", uuid \"" << env->getOpenedElementUUID() << "\""; } void visitPackElementGetInst(PackElementGetInst *I) { *this << Ctx.getID(I->getIndex()) << " of " << getIDAndType(I->getPack()) << " as " << I->getElementType(); } void visitPackElementSetInst(PackElementSetInst *I) { *this << getIDAndType(I->getValue()) << " into " << Ctx.getID(I->getIndex()) << " of " << getIDAndType(I->getPack()); } void visitTuplePackElementAddrInst(TuplePackElementAddrInst *I) { *this << Ctx.getID(I->getIndex()) << " of " << getIDAndType(I->getTuple()) << " as " << I->getElementType(); } void visitTuplePackExtractInst(TuplePackExtractInst *I) { *this << Ctx.getID(I->getIndex()) << " of " << getIDAndType(I->getTuple()) << " as " << I->getElementType(); } 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 visitTypeValueInst(TypeValueInst *tvi) { *this << tvi->getType() << " for " << tvi->getParamType(); } void visitEndLifetimeInst(EndLifetimeInst *ELI) { *this << getIDAndType(ELI->getOperand()); } void visitExtendLifetimeInst(ExtendLifetimeInst *ELLI) { *this << getIDAndType(ELLI->getOperand()); } void visitValueToBridgeObjectInst(ValueToBridgeObjectInst *VBOI) { *this << getIDAndType(VBOI->getOperand()); } void visitClassifyBridgeObjectInst(ClassifyBridgeObjectInst *CBOI) { *this << getIDAndType(CBOI->getOperand()); } template void visitMarkDependenceInstBase(MarkDependenceInstBase *MDI) { switch (MDI->dependenceKind()) { case MarkDependenceKind::Unresolved: *this << "[unresolved] "; break; case MarkDependenceKind::Escaping: break; case MarkDependenceKind::NonEscaping: *this << "[nonescaping] "; break; } *this << getIDAndType(MDI->getOperand(MarkDependenceInstBase::Dependent)) << " on " << getIDAndType(MDI->getBase()); } void visitMarkDependenceInst(MarkDependenceInst *MDI) { visitMarkDependenceInstBase(MDI); printForwardingOwnershipKind(MDI, MDI->getValue()); } void visitMarkDependenceAddrInst(MarkDependenceAddrInst *MDI) { visitMarkDependenceInstBase(MDI); } 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 visitBeginCOWMutationInst(BeginCOWMutationInst *BCMI) { if (BCMI->isNative()) *this << "[native] "; *this << getIDAndType(BCMI->getOperand()); } void visitEndCOWMutationInst(EndCOWMutationInst *ECMI) { if (ECMI->doKeepUnique()) *this << "[keep_unique] "; *this << getIDAndType(ECMI->getOperand()); } void visitEndCOWMutationAddrInst(EndCOWMutationAddrInst *ECMI) { *this << getIDAndType(ECMI->getOperand()); } void visitEndInitLetRefInst(EndInitLetRefInst *I) { *this << getIDAndType(I->getOperand()); } void visitBeginDeallocRefInst(BeginDeallocRefInst *I) { *this << getIDAndType(I->getReference()) << " of " << getIDAndType(I->getOperand(1)); } void visitDestroyNotEscapedClosureInst(DestroyNotEscapedClosureInst *CUI) { if (CUI->getVerificationType()) *this << "[objc] "; *this << getIDAndType(CUI->getOperand()); } void visitDeallocStackInst(DeallocStackInst *DI) { *this << getIDAndType(DI->getOperand()); } void visitDeallocPackInst(DeallocPackInst *DI) { *this << getIDAndType(DI->getOperand()); } void visitDeallocPackMetadataInst(DeallocPackMetadataInst *DPMI) { *this << getIDAndType(DPMI->getOperand()); } void visitDeallocStackRefInst(DeallocStackRefInst *ESRL) { *this << getIDAndType(ESRL->getOperand()); } void visitDeallocRefInst(DeallocRefInst *DI) { *this << getIDAndType(DI->getOperand()); } void visitDeallocPartialRefInst(DeallocPartialRefInst *DPI) { *this << getIDAndType(DPI->getInstance()); *this << ", "; *this << getIDAndType(DPI->getMetatype()); } void visitDeallocBoxInst(DeallocBoxInst *DI) { if (DI->isDeadEnd()) *this << "[dead_end] "; *this << getIDAndType(DI->getOperand()); } void visitDestroyAddrInst(DestroyAddrInst *DI) { *this << getIDAndType(DI->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 visitMoveOnlyWrapperToCopyableAddrInst( MoveOnlyWrapperToCopyableAddrInst *BAI) { *this << getIDAndType(BAI->getOperand()); } void visitMoveOnlyWrapperToCopyableBoxInst(MoveOnlyWrapperToCopyableBoxInst *BAI) { *this << getIDAndType(BAI->getOperand()); } void visitCopyableToMoveOnlyWrapperAddrInst( CopyableToMoveOnlyWrapperAddrInst *BAI) { *this << 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 visitIncrementProfilerCounterInst(IncrementProfilerCounterInst *IPCI) { *this << IPCI->getCounterIndex() << ", " << QuotedString(IPCI->getPGOFuncName()) << ", " << "num_counters " << IPCI->getNumCounters() << ", " << "hash " << IPCI->getPGOFuncHash(); } void visitIndexAddrInst(IndexAddrInst *IAI) { *this << (IAI->needsStackProtection() ? "[stack_protection] " : "") << 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 visitSpecifyTestInst(SpecifyTestInst *TSI) { *this << QuotedString(TSI->getArgumentsSpecification()); } void visitThrowInst(ThrowInst *TI) { *this << getIDAndType(TI->getOperand()); } void visitThrowAddrInst(ThrowAddrInst *TAI) { // no operands } void visitUnwindInst(UnwindInst *UI) { // no operands } void visitYieldInst(YieldInst *YI) { auto values = YI->getYieldedValues(); if (values.size() != 1) *this << '('; llvm::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 visitGetAsyncContinuationInst(GetAsyncContinuationInst *GI) { if (GI->throws()) *this << "[throws] "; *this << GI->getFormalResumeType(); } void visitIgnoredUseInst(IgnoredUseInst *i) { *this << getIDAndType(i->getOperand()); } void visitGetAsyncContinuationAddrInst(GetAsyncContinuationAddrInst *GI) { if (GI->throws()) *this << "[throws] "; *this << GI->getFormalResumeType() << ", " << getIDAndType(GI->getOperand()); } void visitAwaitAsyncContinuationInst(AwaitAsyncContinuationInst *AI) { *this << getIDAndType(AI->getOperand()) << ", resume " << Ctx.getID(AI->getResumeBB()); if (auto errorBB = AI->getErrorBB()) { *this << ", error " << Ctx.getID(errorBB); } } void visitHopToExecutorInst(HopToExecutorInst *HTEI) { if (HTEI->isMandatory()) *this << "[mandatory] "; *this << getIDAndType(HTEI->getTargetExecutor()); } void visitExtractExecutorInst(ExtractExecutorInst *AEI) { *this << getIDAndType(AEI->getExpectedExecutor()); } void visitFunctionExtractIsolationInst(FunctionExtractIsolationInst *I) { *this << getIDAndType(I->getFunction()); } 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(SwitchEnumTermInst switchEnum) { *this << getIDAndType(switchEnum.getOperand()); for (unsigned i = 0, e = switchEnum.getNumCases(); i < e; ++i) { EnumElementDecl *elt; SILBasicBlock *dest; std::tie(elt, dest) = switchEnum.getCase(i); *this << ", case " << SILDeclRef(elt, SILDeclRef::Kind::EnumElement) << ": " << Ctx.getID(dest); if (switchEnum.getCaseCount(i)) { *this << " !case_count(" << switchEnum.getCaseCount(i).getValue() << ")"; } } if (switchEnum.hasDefault()) { *this << ", default " << Ctx.getID(switchEnum.getDefaultBB()); if (switchEnum.getDefaultCount()) { *this << " !default_count(" << switchEnum.getDefaultCount().getValue() << ")"; } if (NullablePtr uniqueCase = switchEnum.getUniqueCaseForDefault()) { lineComments << SILDeclRef(uniqueCase.get(), SILDeclRef::Kind::EnumElement); } } } void visitSwitchEnumInst(SwitchEnumInst *switchEnum) { printSwitchEnumInst(switchEnum); printForwardingOwnershipKind(switchEnum, switchEnum->getOperand()); } void visitSwitchEnumAddrInst(SwitchEnumAddrInst *switchEnum) { printSwitchEnumInst(switchEnum); } void printSelectEnumInst(SelectEnumOperation SEO) { *this << getIDAndType(SEO.getEnumOperand()); for (unsigned i = 0, e = SEO.getNumCases(); i < e; ++i) { EnumElementDecl *elt; SILValue result; std::tie(elt, result) = SEO.getCase(i); *this << ", case " << SILDeclRef(elt, SILDeclRef::Kind::EnumElement) << ": " << Ctx.getID(result); } if (SEO.hasDefault()) *this << ", default " << Ctx.getID(SEO.getDefaultResult()); *this << " : " << SEO->getType(); } void visitSelectEnumInst(SelectEnumInst *SEI) { printSelectEnumInst(SEI); } void visitSelectEnumAddrInst(SelectEnumAddrInst *SEI) { printSelectEnumInst(SEI); } 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 << '('; llvm::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()) { PrintOptions Opts; Opts.PrintInverseRequirements = true; pattern->getGenericSignature()->print(PrintState.OS, Opts); *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->getPatternOperands().empty()) { *this << " ("; interleave(KPI->getPatternOperands(), [&](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: case KeyPathPatternComponent::Kind::Method: { *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.getComputedPropertyForGettable()->printName(PrintState.OS); *this << " : " << component.getComputedPropertyForGettable()->getLoweredType(); if (kind == KeyPathPatternComponent::Kind::SettableProperty) { *this << ", setter "; component.getComputedPropertyForSettable()->printName(PrintState.OS); *this << " : " << component.getComputedPropertyForSettable()->getLoweredType(); } if (!component.getArguments().empty()) { *this << ", indices "; printComponentIndices(component.getArguments()); *this << ", indices_equals "; component.getIndexEquals()->printName(PrintState.OS); *this << " : " << component.getIndexEquals()->getLoweredType(); *this << ", indices_hash "; component.getIndexHash()->printName(PrintState.OS); *this << " : " << component.getIndexHash()->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 << "[results"; for (auto i : dfi->getResultIndices()->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(); } printForwardingOwnershipKind(dfei, dfei->getOperand()); } void visitLinearFunctionExtractInst(LinearFunctionExtractInst *lfei) { *this << '['; switch (lfei->getExtractee()) { case LinearDifferentiableFunctionTypeComponent::Original: *this << "original"; break; case LinearDifferentiableFunctionTypeComponent::Transpose: *this << "transpose"; break; } *this << "] "; *this << getIDAndType(lfei->getOperand()); printForwardingOwnershipKind(lfei, lfei->getOperand()); } 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 << "] ["; switch (dwfi->getWitness()->getKind()) { case DifferentiabilityKind::Forward: *this << "forward"; break; case DifferentiabilityKind::Reverse: *this << "reverse"; break; case DifferentiabilityKind::Normal: *this << "normal"; break; case DifferentiabilityKind::Linear: *this << "linear"; break; case DifferentiabilityKind::NonDifferentiable: llvm_unreachable("Impossible case"); } *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(); subPrinter.PrintInverseRequirements = true; witnessGenSig->print(PrintState.OS, subPrinter); *this << " "; } printSILFunctionNameAndType(PrintState.OS, witness->getOriginalFunction()); if (dwfi->getHasExplicitFunctionType()) { *this << " as "; *this << dwfi->getType(); } } void visitHasSymbolInst(HasSymbolInst *hsi) { *this << "#"; printValueDecl(hsi->getDecl(), PrintState.OS); } }; } // namespace swift 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 SILInstruction::dump(bool DebugInfo) const { SILPrintContext Ctx(llvm::errs(), /*Verbose*/ false, /*SortedSIL*/ false, DebugInfo, /*PrintFullConvention*/ false); SILPrinter(Ctx).print(this); } void SingleValueInstruction::dump() const { SILInstruction::dump(); } void SILInstruction::print(raw_ostream &OS) const { SILPrintContext Ctx(OS); SILPrinter(Ctx).print(this); } void NonSingleValueInstruction::dump() const { SILNode::dump(); } /// Pretty-print the SILBasicBlock to errs. void SILBasicBlock::dump() const { print(llvm::errs()); } /// Pretty-print the SILBasicBlock to errs with Debug Info. void SILBasicBlock::dump(bool DebugInfo) const { SILPrintContext Ctx(llvm::errs(), /*Verbose*/ false, /*SortedSIL*/ false, DebugInfo, /*PrintFullConvention*/ false); SILPrinter(Ctx).print(this); } /// 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(SILPrintContext &Ctx) const { SILPrinter(Ctx).print(this); } void SILBasicBlock::dumpID(bool newline) const { #ifndef NDEBUG printID(llvm::errs(), newline); #else llvm::errs() << "NOASSERTS" << (newline ? "\n" : ""); #endif } void SILBasicBlock::printID(llvm::raw_ostream &OS, bool newline) const { #ifndef NDEBUG SILPrintContext Ctx(OS); printID(Ctx, newline); #else llvm::errs() << "NOASSERTS" << (newline ? "\n" : ""); #endif } void SILBasicBlock::printID(SILPrintContext &Ctx, bool newline) const { #ifndef NDEBUG SILPrinter(Ctx).printID(this, newline); #else llvm::errs() << "NOASSERTS" << (newline ? "\n" : ""); #endif } /// 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); } /// Pretty-print the SILFunction to errs. void SILFunction::dump(bool Verbose, bool DebugInfo) const { SILPrintContext Ctx(llvm::errs(), Verbose, /*SortedSIL*/ false, DebugInfo, /*PrintFullConvention*/ false); print(Ctx); } void SILFunction::dump(const char *FileName) const { std::error_code EC; llvm::raw_fd_ostream os(FileName, EC, llvm::sys::fs::OpenFlags::OF_None); print(os); } static StringRef getLinkageString(SILLinkage linkage) { switch (linkage) { case SILLinkage::Public: return "public "; case SILLinkage::PublicNonABI: return "non_abi "; case SILLinkage::Package: return "package "; case SILLinkage::PackageNonABI: return "package_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::PackageExternal: return "package_external "; case SILLinkage::HiddenExternal: return "hidden_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); } static void printSerializedKind(llvm::raw_ostream &OS, SerializedKind_t kind) { switch (kind) { case IsNotSerialized: break; case IsSerializedForPackage: OS << "[serialized_for_package] "; break; case IsSerialized: OS << "[serialized] "; break; } } static void printClangQualifiedNameCommentIfPresent(llvm::raw_ostream &OS, const clang::Decl *decl) { if (decl) { if (auto namedDecl = dyn_cast_or_null(decl)) { OS << "// clang name: "; namedDecl->printQualifiedName(OS); OS << "\n"; } } } /// 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()); if (PrintCtx.printDebugInfo()) { auto &SM = getModule().getASTContext().SourceMgr; SILPrinter P(PrintCtx); P.printDebugLocRef(getLocation(), SM); P.printDebugScopeRef(getDebugScope(), SM); } OS << '\n'; if (auto functionIsolation = getActorIsolation()) { OS << "// Isolation: "; functionIsolation->print(OS); OS << '\n'; } printClangQualifiedNameCommentIfPresent(OS, getClangDecl()); OS << "sil "; printLinkage(OS, getLinkage(), isDefinition()); if (isTransparent()) OS << "[transparent] "; printSerializedKind(OS, getSerializedKind()); switch (isThunk()) { case IsNotThunk: break; case IsBackDeployedThunk: OS << "[back_deployed_thunk] "; 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 (isDistributed()) { OS << "[distributed] "; } if (isRuntimeAccessible()) { OS << "[runtime_accessible] "; } if (forceEnableLexicalLifetimes()) { OS << "[lexical_lifetimes] "; } if (!useStackForPackMetadata()) { OS << "[no_onstack_pack_metadata] "; } if (hasUnsafeNonEscapableResult()) { OS << "[unsafe_nonescapable_result] "; } 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::GlobalInitOnceFunction: OS << "[global_init_once_fn] "; break; case SILFunction::Purpose::LazyPropertyGetter: OS << "[lazy_getter] "; break; } if (isAlwaysWeakImported()) OS << "[weak_imported] "; auto availability = getAvailabilityForLinkage(); if (!availability.isAlwaysAvailable()) { OS << "[available " << availability.getVersionString() << "] "; } 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; } PerformanceConstraints perf = getPerfConstraints(); switch (perf) { case PerformanceConstraints::None: break; case PerformanceConstraints::NoLocks: OS << "[no_locks] "; break; case PerformanceConstraints::NoAllocation: OS << "[no_allocation] "; break; case PerformanceConstraints::NoRuntime: OS << "[no_runtime] "; break; case PerformanceConstraints::NoExistentials: OS << "[no_existentials] "; break; case PerformanceConstraints::NoObjCBridging: OS << "[no_objc_bridging] "; break; } if (isPerformanceConstraint()) OS << "[perf_constraint] "; 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 (auto *usedFunc = getReferencedAdHocRequirementWitnessFunction()) { OS << "[ref_adhoc_requirement_witness \""; OS << usedFunc->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 << "] "; } if (markedAsUsed()) OS << "[used] "; if (!section().empty()) OS << "[section \"" << section() << "\"] "; // 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] "; if (needsStackProtection()) OS << "[stack_protection] "; llvm::DenseMap sugaredTypeNames; printSILFunctionNameAndType(OS, this, sugaredTypeNames, &PrintCtx); if (!isExternalDeclaration()) { if (auto eCount = getEntryCount()) { OS << " !function_entry_count(" << eCount.getValue() << ")"; } OS << " {\n"; writeEffects(OS); SILPrinter(PrintCtx, sugaredTypeNames.empty() ? nullptr : &sugaredTypeNames) .print(this); OS << "} // end sil function '" << getName() << '\''; } else if (hasArgumentEffects()) { OS << " {\n"; writeEffects(OS); 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'; printClangQualifiedNameCommentIfPresent(OS, getClangDecl()); OS << "sil_global "; // Passing true for 'isDefinition' lets print the (external) linkage if it's // not a definition. printLinkage(OS, getLinkage(), /*isDefinition*/ true); printSerializedKind(OS, getSerializedKind()); if (isLet()) OS << "[let] "; printName(OS); OS << " : " << LoweredType; if (!StaticInitializerBlock.empty()) { OS << " = {\n"; { SILPrintContext Ctx(OS); SILPrinter Printer(Ctx); Printer.markBlockAsPrinted(&StaticInitializerBlock); 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); } /// Pretty-print the SILModule to errs with DebugInfo. void SILModule::dump(bool Verbose, bool DebugInfo) const { SILPrintContext Ctx(llvm::errs(), Verbose, /*SortedSIL*/ false, DebugInfo, /*PrintFullConvention*/ false); 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::OF_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 auto &vt : VTables) vt->print(Ctx.OS(), Ctx.printVerbose()); return; } std::vector vtables; vtables.reserve(VTables.size()); for (const auto &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 printSILMoveOnlyDeinits( SILPrintContext &printCtx, const SILModule::SILMoveOnlyDeinitListType &deinitTables) { if (!printCtx.sortSIL()) { for (const auto &tbl : deinitTables) tbl->print(printCtx.OS(), printCtx.printVerbose()); return; } std::vector sortedTables; sortedTables.reserve(deinitTables.size()); for (const auto &tbl : deinitTables) sortedTables.push_back(tbl); std::sort( sortedTables.begin(), sortedTables.end(), [](const SILMoveOnlyDeinit *v1, const SILMoveOnlyDeinit *v2) -> bool { StringRef name1 = v1->getNominalDecl()->getName().str(); StringRef name2 = v2->getNominalDecl()->getName().str(); return name1.compare(name2) == -1; }); for (const auto *tbl : sortedTables) tbl->print(printCtx.OS(), printCtx.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 printSILDefaultOverrideTables( SILPrintContext &Ctx, const SILModule::DefaultOverrideTableListType &tables) { if (!Ctx.sortSIL()) { for (const auto &table : tables) table.print(Ctx.OS(), Ctx.printVerbose()); return; } std::vector sorted; sorted.reserve(tables.size()); for (const auto &table : tables) sorted.push_back(&table); std::sort(sorted.begin(), sorted.end(), [](const auto *left, const auto *right) -> bool { return left->getClass()->getName().compare( right->getClass()->getName()) == -1; }); for (const auto *table : sorted) table->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 printSILLinearMapTypes(SILPrintContext &Ctx, const ModuleDecl *M) { auto &OS = Ctx.OS(); PrintOptions Options = PrintOptions::printSIL(); Options.TypeDefinitions = true; Options.VarInitializers = true; Options.ExplodePatternBindingDecls = true; Options.SkipImplicit = false; Options.PrintGetSetOnRWProperties = true; Options.PrintInSILBody = false; SmallVector topLevelDecls; M->getTopLevelDecls(topLevelDecls); for (const Decl *D : topLevelDecls) { if (D->getDeclContext() == M) continue; if (!isa(D) && !isa(D)) continue; StringRef Name = cast(D)->getNameStr(); if (!Name.starts_with("_AD__")) continue; D->print(OS, Options); OS << "\n\n"; } } 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 FileIDMap = llvm::StringMap>; static void printFileIDMapEntry(SILPrintContext &Ctx, const FileIDMap::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 printFileIDMap(SILPrintContext &Ctx, const FileIDMap map) { if (map.empty()) return; Ctx.OS() << "\n\n// Mappings from '#fileID' 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) printFileIDMapEntry(Ctx, *map.find(key)); } else { for (const auto &entry : map) printFileIDMapEntry(Ctx, entry); } } void SILProperty::print(SILPrintContext &Ctx) const { auto &OS = Ctx.OS(); OS << "sil_property "; printSerializedKind(OS, getSerializedKind()); OS << '#'; printValueDecl(getDecl(), OS); if (auto sig = getDecl()->getInnermostDeclContext() ->getGenericSignatureOfContext()) { PrintOptions Options = PrintOptions::printSIL(&Ctx); Options.PrintInverseRequirements = true; 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()); printSILLinearMapTypes(PrintCtx, getSwiftModule()); printSILFunctions(PrintCtx, getFunctionList()); printSILVTables(PrintCtx, getVTables()); printSILWitnessTables(PrintCtx, getWitnessTableList()); printSILDefaultWitnessTables(PrintCtx, getDefaultWitnessTableList()); printSILDefaultOverrideTables(PrintCtx, getDefaultOverrideTableList()); printSILCoverageMaps(PrintCtx, getCoverageMaps()); printSILProperties(PrintCtx, getPropertyList()); printSILMoveOnlyDeinits(PrintCtx, getMoveOnlyDeinits()); printExternallyVisibleDecls(PrintCtx, externallyVisible.getArrayRef()); if (M) printFileIDMap( PrintCtx, M->computeFileIDMap(/*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(asSILNode()); } void SILVTableEntry::print(llvm::raw_ostream &OS) const { getMethod().print(OS); OS << ": "; PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); bool HasSingleImplementation = false; switch (getMethod().kind) { default: break; case SILDeclRef::Kind::IVarDestroyer: case SILDeclRef::Kind::Destroyer: case SILDeclRef::Kind::Deallocator: case SILDeclRef::Kind::IsolatedDeallocator: HasSingleImplementation = true; } // No need to emit the signature for methods that may have only // single implementation, e.g. for destructors. if (!HasSingleImplementation) { QualifiedSILTypeOptions.CurrentModule = getMethod().getDecl()->getDeclContext()->getParentModule(); getMethod().getDecl()->getInterfaceType().print( OS, QualifiedSILTypeOptions); OS << " : "; } OS << '@' << getImplementation()->getName(); switch (getKind()) { case SILVTable::Entry::Kind::Normal: break; case SILVTable::Entry::Kind::Inherited: OS << " [inherited]"; break; case SILVTable::Entry::Kind::Override: OS << " [override]"; break; } if (isNonOverridden()) { OS << " [nonoverridden]"; } OS << "\t// " << demangleSymbol(getImplementation()->getName()); } void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const { OS << "sil_vtable "; printSerializedKind(OS, getSerializedKind()); if (SILType classTy = getClassType()) { OS << classTy; } else { OS << getClass()->getName(); } OS << " {\n"; for (auto &entry : getEntries()) { OS << " "; entry.print(OS); OS << "\n"; } OS << "}\n\n"; } void SILVTable::dump() const { print(llvm::errs()); } void SILMoveOnlyDeinit::print(llvm::raw_ostream &OS, bool verbose) const { OS << "sil_moveonlydeinit "; printSerializedKind(OS, getSerializedKind()); OS << getNominalDecl()->getName() << " {\n"; OS << " @" << getImplementation()->getName(); OS << "\t// " << demangleSymbol(getImplementation()->getName()); OS << "\n"; OS << "}\n\n"; } void SILMoveOnlyDeinit::dump() const { print(llvm::errs(), false); } /// 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::AssociatedConformance: { // associated_conformance (AssociatedTypeName: Protocol): auto &assocProtoWitness = getAssociatedConformanceWitness(); if (assocProtoWitness.Witness.isInvalid()) return; out << "associated_conformance ("; (void) printAssociatedTypePath(out, assocProtoWitness.Requirement); auto conformance = assocProtoWitness.Witness; out << ": " << conformance.getProtocol()->getName() << "): "; if (conformance.isConcrete()) conformance.getConcrete()->printName(out, options); else { out << "dependent "; assocProtoWitness.Witness.getType()->print(out, options); } 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()); printSerializedKind(OS, getSerializedKind()); if (isSpecialized()) OS << "[specialized] "; getConformance()->printName(OS, Options); Options.GenericSig = getConformance()->getDeclContext()->getGenericSignatureOfContext() .getPointer(); 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): // if (conditionalConformance.isInvalid()) { OS << " conditional_conformance invalid"; continue; } OS << " conditional_conformance ("; conditionalConformance.getType().print(OS, Options); OS << ": " << conditionalConformance.getProtocol()->getName() << "): "; if (conditionalConformance.isConcrete()) conditionalConformance.getConcrete()->printName(OS, Options); else { ASSERT(conditionalConformance.isAbstract() && "Handle pack conformance here"); OS << "dependent "; conditionalConformance.getType()->print(OS, Options); } 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.GenericSig = Protocol->getGenericSignatureOfContext().getPointer(); for (auto &witness : getEntries()) { witness.print(OS, Verbose, options); } OS << "}\n\n"; } void SILDefaultWitnessTable::dump() const { print(llvm::errs()); } void SILDefaultOverrideTable::Entry::print(llvm::raw_ostream &out, bool verbose) const { PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); out << " "; // #replacement.declref : #original.declref : @function method.print(out); out << ": "; original.print(out); out << ": "; auto *decl = method.getDecl(); QualifiedSILTypeOptions.CurrentModule = decl->getDeclContext()->getParentModule(); decl->getInterfaceType().print(out, QualifiedSILTypeOptions); out << " : "; impl->printName(out); out << "\t// " << demangleSymbol(impl->getName()); out << '\n'; } void SILDefaultOverrideTable::Entry::dump() const { print(llvm::errs(), /*verbose=*/false); } void SILDefaultOverrideTable::print(llvm::raw_ostream &OS, bool Verbose) const { // sil_default_override_table [] PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); OS << "sil_default_override_table "; printLinkage(OS, getLinkage(), ForDefinition); OS << decl->getName() << " {\n"; PrintOptions options = PrintOptions::printSIL(); options.GenericSig = decl->getGenericSignatureOfContext().getPointer(); for (auto &entry : getEntries()) { entry.print(OS, Verbose); } OS << "}\n\n"; } void SILDefaultOverrideTable::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] "; // Kind OS << '['; switch (getKind()) { case DifferentiabilityKind::Forward: OS << "forward"; break; case DifferentiabilityKind::Reverse: OS << "reverse"; break; case DifferentiabilityKind::Normal: OS << "normal"; break; case DifferentiabilityKind::Linear: OS << "linear"; break; case DifferentiabilityKind::NonDifferentiable: llvm_unreachable("Impossible case"); } // [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(); subPrinter.PrintInverseRequirements = true; 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(getFilename()) << " " << 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 << " : "; switch (MR.RegionKind) { case MappedRegion::Kind::Code: printCounter(OS, MR.Counter); break; case MappedRegion::Kind::Skipped: OS << "skipped"; break; } 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::print(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->print(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->print(SM, OS, Indent + 2); OS.indent(Indent + 2); } OS << "}\n"; } void SILDebugScope::print(SILModule &Mod) const { // We just use the default indent and llvm::errs(). print(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 << ", "; if (!getSPIGroup().empty()) { OS << "spi: " << getSPIGroup() << ", "; OS << "spiModule: "; getSPIModule()->getReverseFullModuleName().printForward(OS); OS << ", "; } auto *genericEnv = getFunction()->getGenericEnvironment(); GenericSignature genericSig; if (genericEnv) genericSig = genericEnv->getGenericSignature(); auto requirements = getUnerasedSpecializedSignature().requirementsNotSatisfiedBy(genericSig); if (targetFunction) { OS << "target: \"" << targetFunction->getName() << "\", "; } if (!availability.isAlwaysAvailable()) { OS << "available: " << availability.getVersionString() << ", "; } if (!requirements.empty()) { OS << "where "; SILFunction *F = getFunction(); assert(F); interleave( requirements, [&](Requirement req) { if (!genericSig) { req.print(OS, SubPrinter); return; } // Use GenericEnvironment to produce user-friendly // names instead of something like t_0_0. auto FirstTy = genericSig->getSugaredType(req.getFirstType()); auto erasedParams = getTypeErasedParams(); bool erased = std::any_of(erasedParams.begin(), erasedParams.end(), [&](auto Ty) { return Ty->isEqual(FirstTy); }); if (erased) { OS << " @_noMetadata "; } if (req.getKind() != RequirementKind::Layout) { auto SecondTy = genericSig->getSugaredType(req.getSecondType()); Requirement ReqWithDecls(req.getKind(), FirstTy, SecondTy); ReqWithDecls.print(OS, SubPrinter); } else { Requirement ReqWithDecls(req.getKind(), FirstTy, req.getLayoutConstraint()); auto SubPrinterCopy = SubPrinter; SubPrinterCopy.PrintInternalLayoutName = erased; ReqWithDecls.print(OS, SubPrinterCopy); } }, [&] { OS << ", "; }); } } void KeyPathPatternComponent::print(SILPrintContext &ctxt) const { SILPrinter printer(ctxt); printer.printKeyPathPatternComponent(*this); } //===----------------------------------------------------------------------===// // SILPrintContext members //===----------------------------------------------------------------------===// SILPrintContext::SILPrintContext(llvm::raw_ostream &OS, bool Verbose, bool SortedSIL, bool PrintFullConvention) : OutStream(OS), Verbose(Verbose), SortedSIL(SortedSIL), DebugInfo(SILPrintDebugInfo), PrintFullConvention(PrintFullConvention) {} SILPrintContext::SILPrintContext(llvm::raw_ostream &OS, const SILOptions &Opts) : OutStream(OS), Verbose(Opts.EmitVerboseSIL), SortedSIL(Opts.EmitSortedSIL), DebugInfo(Opts.PrintDebugInfo || SILPrintDebugInfo), PrintFullConvention(Opts.PrintFullConvention) {} SILPrintContext::SILPrintContext(llvm::raw_ostream &OS, bool Verbose, bool SortedSIL, bool DebugInfo, bool PrintFullConvention) : OutStream(OS), Verbose(Verbose), SortedSIL(SortedSIL), DebugInfo(DebugInfo), PrintFullConvention(PrintFullConvention) {} 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(SILNodePointer node) { if (node == nullptr) return {ID::Null, ~0U}; if (isa(node.get())) return {ID::SILUndef, 0}; SILBasicBlock *BB = node->getParentBlock(); if (!BB) { return { ID::Null, 0 }; } 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.asSILNode()] = 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; } PrintOptions PrintOptions::printSIL(const SILPrintContext *ctx) { PrintOptions result; result.PrintLongAttrsOnSeparateLines = true; result.PrintStorageRepresentationAttrs = true; result.AbstractAccessors = false; result.PrintForSIL = true; result.PrintInSILBody = true; result.PreferTypeRepr = false; result.OpaqueReturnTypePrinting = OpaqueReturnTypePrintingMode::StableReference; if (ctx && ctx->printFullConvention()) result.PrintFunctionRepresentationAttrs = PrintOptions::FunctionRepresentationMode::Full; return result; }