std::unique_ptr<proto::Bip44Address> Blockchain::LoadAddress( const Identifier& nymID, const Identifier& accountID, const std::uint32_t index, const BIP44Chain chain) const { LOCK_ACCOUNT() std::unique_ptr<proto::Bip44Address> output{}; const std::string sNymID = nymID.str(); const std::string sAccountID = accountID.str(); auto account = load_account(accountLock, sNymID, sAccountID); if (false == bool(account)) { otErr << OT_METHOD << __FUNCTION__ << ": Account does not exist." << std::endl; return output; } const auto allocatedIndex = chain ? account->internalindex() : account->externalindex(); if (index > allocatedIndex) { otErr << OT_METHOD << __FUNCTION__ << ": Address has not been allocated." << std::endl; return output; } auto& address = find_address(index, chain, *account); output.reset(new proto::Bip44Address(address)); return output; }
std::unique_ptr<proto::Bip44Address> Blockchain::AllocateAddress( const Identifier& nymID, const Identifier& accountID, const std::string& label, const BIP44Chain chain) const { LOCK_ACCOUNT() const std::string sNymID = nymID.str(); const std::string sAccountID = accountID.str(); std::unique_ptr<proto::Bip44Address> output{nullptr}; auto account = load_account(accountLock, sNymID, sAccountID); if (false == bool(account)) { otErr << OT_METHOD << __FUNCTION__ << ": Account does not exist." << std::endl; return output; } const auto& type = account->type(); const auto index = chain ? account->internalindex() : account->externalindex(); if (MAX_INDEX == index) { otErr << OT_METHOD << __FUNCTION__ << ": Account is full." << std::endl; return output; } auto& newAddress = add_address(index, *account, chain); newAddress.set_version(BLOCKCHAIN_VERSION); newAddress.set_index(index); newAddress.set_address(calculate_address(*account, chain, index)); OT_ASSERT(false == newAddress.address().empty()); otErr << OT_METHOD << __FUNCTION__ << ": Address " << newAddress.address() << " allocated." << std::endl; newAddress.set_label(label); const auto saved = api_.Storage().Store(sNymID, type, *account); if (false == saved) { otErr << OT_METHOD << __FUNCTION__ << ": Failed to save account." << std::endl; return output; } output.reset(new proto::Bip44Address(newAddress)); return output; }
static void addParameters(ArrayRef<Identifier> &ArgNames, const ParameterList *paramList, TextEntity &Ent, SourceManager &SM, unsigned BufferID) { for (auto ¶m : *paramList) { StringRef Arg; if (!ArgNames.empty()) { Identifier Id = ArgNames.front(); Arg = Id.empty() ? "_" : Id.str(); ArgNames = ArgNames.slice(1); } if (auto typeRepr = param->getTypeLoc().getTypeRepr()) { SourceRange TypeRange = param->getTypeLoc().getSourceRange(); if (auto InOutTyR = dyn_cast_or_null<InOutTypeRepr>(typeRepr)) TypeRange = InOutTyR->getBase()->getSourceRange(); if (TypeRange.isInvalid()) continue; unsigned StartOffs = SM.getLocOffsetInBuffer(TypeRange.Start, BufferID); unsigned EndOffs = SM.getLocOffsetInBuffer(Lexer::getLocForEndOfToken(SM, TypeRange.End), BufferID); TextRange TR{ StartOffs, EndOffs-StartOffs }; TextEntity Param(param, Arg, TR, StartOffs); Ent.SubEntities.push_back(std::move(Param)); } } }
bool Blockchain::StoreOutgoing( const Identifier& senderNymID, const Identifier& accountID, const Identifier& recipientContactID, const proto::BlockchainTransaction& transaction) const { LOCK_ACCOUNT() const std::string sNymID = senderNymID.str(); const std::string sAccountID = accountID.str(); auto account = load_account(accountLock, sNymID, sAccountID); if (false == bool(account)) { otErr << OT_METHOD << __FUNCTION__ << ": Account does not exist." << std::endl; return false; } const auto& txid = transaction.txid(); account->add_outgoing(txid); auto saved = api_.Storage().Store(sNymID, account->type(), *account); if (false == saved) { otErr << OT_METHOD << __FUNCTION__ << ": Failed to save account." << std::endl; return false; } saved = api_.Storage().Store(transaction); if (false == saved) { otErr << OT_METHOD << __FUNCTION__ << ": Failed to save transaction." << std::endl; return false; } if (recipientContactID.empty()) { return true; } return activity_.AddBlockchainTransaction( senderNymID, recipientContactID, StorageBox::OUTGOINGBLOCKCHAIN, transaction); }
int Identifier::compare(Identifier other) const { // Handle empty identifiers. if (empty() || other.empty()) { if (empty() != other.empty()) { return other.empty() ? -1 : 1; } return 0; } return str().compare(other.str()); }
std::set<OTIdentifier> Blockchain::AccountList( const Identifier& nymID, const proto::ContactItemType type) const { std::set<OTIdentifier> output; auto list = api_.Storage().BlockchainAccountList(nymID.str(), type); for (const auto& accountID : list) { // output.emplace(String(accountID.c_str())); output.emplace(Identifier::Factory(accountID)); } return output; }
static void addParameters(ArrayRef<Identifier> &ArgNames, const Pattern *Pat, TextEntity &Ent, SourceManager &SM, unsigned BufferID) { if (auto ParenPat = dyn_cast<ParenPattern>(Pat)) { addParameters(ArgNames, ParenPat->getSubPattern(), Ent, SM, BufferID); return; } if (auto Tuple = dyn_cast<TuplePattern>(Pat)) { for (const auto &Elt : Tuple->getElements()) addParameters(ArgNames, Elt.getPattern(), Ent, SM, BufferID); return; } StringRef Arg; if (!ArgNames.empty()) { Identifier Id = ArgNames.front(); Arg = Id.empty() ? "_" : Id.str(); ArgNames = ArgNames.slice(1); } if (auto Typed = dyn_cast<TypedPattern>(Pat)) { VarDecl *VD = nullptr; if (auto Named = dyn_cast<NamedPattern>(Typed->getSubPattern())) { VD = Named->getDecl(); } SourceRange TypeRange = Typed->getTypeLoc().getSourceRange(); if (auto InOutTyR = dyn_cast_or_null<InOutTypeRepr>(Typed->getTypeLoc().getTypeRepr())) { TypeRange = InOutTyR->getBase()->getSourceRange(); } if (TypeRange.isInvalid()) return; unsigned StartOffs = SM.getLocOffsetInBuffer(TypeRange.Start, BufferID); unsigned EndOffs = SM.getLocOffsetInBuffer(Lexer::getLocForEndOfToken(SM, TypeRange.End), BufferID); TextRange TR{ StartOffs, EndOffs-StartOffs }; TextEntity Param(VD, Arg, TR, StartOffs); Ent.SubEntities.push_back(std::move(Param)); } }
SILWitnessTable * SILWitnessTable::create(SILModule &M, SILLinkage Linkage, NormalProtocolConformance *Conformance) { assert(Conformance && "Cannot create a witness table for a null " "conformance."); // Create the mangled name of our witness table... Identifier Name = M.getASTContext().getIdentifier(mangleConstant(Conformance)); // Allocate the witness table and initialize it. void *buf = M.allocate(sizeof(SILWitnessTable), alignof(SILWitnessTable)); SILWitnessTable *wt = ::new (buf) SILWitnessTable(M, Linkage, Name.str(), Conformance); wt->addWitnessTable(); // Return the resulting witness table. return wt; }
bool Nym::AddContract( const Identifier& instrumentDefinitionID, const proto::ContactItemType currency, const bool primary, const bool active) { const std::string id(instrumentDefinitionID.str()); if (id.empty()) { return false; } eLock lock(shared_lock_); if (false == bool(contact_data_)) { init_claims(lock); } contact_data_.reset(new ContactData( contact_data_->AddContract(id, currency, primary, active))); OT_ASSERT(contact_data_); return set_contact_data(lock, contact_data_->Serialize()); }
std::string Nym::AddChildKeyCredential( const Identifier& masterID, const NymParameters& nymParameters) { eLock lock(shared_lock_); std::string output; std::string master = masterID.str(); auto it = m_mapCredentialSets.find(master); const bool noMaster = (it == m_mapCredentialSets.end()); if (noMaster) { otErr << __FUNCTION__ << ": master ID not found." << std::endl; return output; } if (it->second) { output = it->second->AddChildKeyCredential(nymParameters); } return output; }
OTIdentifier Blockchain::NewAccount( const Identifier& nymID, const BlockchainAccountType standard, const proto::ContactItemType type) const { LOCK_NYM() const std::string sNymID = nymID.str(); auto existing = api_.Storage().BlockchainAccountList(sNymID, type); if (0 < existing.size()) { otErr << OT_METHOD << __FUNCTION__ << ": Account already exists." << std::endl; return Identifier::Factory(*existing.begin()); } auto nym = api_.Wallet().Nym(nymID); if (false == bool(nym)) { otErr << OT_METHOD << __FUNCTION__ << ": Nym does not exist." << std::endl; return Identifier::Factory(); } proto::HDPath nymPath{}; if (false == nym->Path(nymPath)) { otErr << OT_METHOD << __FUNCTION__ << ": No nym path." << std::endl; return Identifier::Factory(); } if (0 == nymPath.root().size()) { otErr << OT_METHOD << __FUNCTION__ << ": Missing root." << std::endl; return Identifier::Factory(); } if (2 > nymPath.child().size()) { otErr << OT_METHOD << __FUNCTION__ << ": Invalid path." << std::endl; return Identifier::Factory(); } proto::HDPath accountPath{}; init_path( nymPath.root(), type, nymPath.child(1) | static_cast<std::uint32_t>(Bip32Child::HARDENED), standard, accountPath); const auto accountID = Identifier::Factory(type, accountPath); Lock accountLock(account_lock_[accountID]); proto::Bip44Account account{}; account.set_version(ACCOUNT_VERSION); account.set_id(accountID->str()); account.set_type(type); account.set_revision(0); *account.mutable_path() = accountPath; account.set_internalindex(0); account.set_externalindex(0); account.clear_internaladdress(); account.clear_externaladdress(); const bool saved = api_.Storage().Store(sNymID, type, account); if (saved) { return accountID; } otErr << OT_METHOD << __FUNCTION__ << ": Failed to save account." << std::endl; return Identifier::Factory(); }
/// Performs the compile requested by the user. /// \returns true on error static bool performCompile(CompilerInstance &Instance, CompilerInvocation &Invocation, ArrayRef<const char *> Args, int &ReturnValue) { FrontendOptions opts = Invocation.getFrontendOptions(); FrontendOptions::ActionType Action = opts.RequestedAction; IRGenOptions &IRGenOpts = Invocation.getIRGenOptions(); bool inputIsLLVMIr = Invocation.getInputKind() == InputFileKind::IFK_LLVM_IR; if (inputIsLLVMIr) { auto &LLVMContext = llvm::getGlobalContext(); // Load in bitcode file. assert(Invocation.getInputFilenames().size() == 1 && "We expect a single input for bitcode input!"); llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(Invocation.getInputFilenames()[0]); if (!FileBufOrErr) { Instance.getASTContext().Diags.diagnose(SourceLoc(), diag::error_open_input_file, Invocation.getInputFilenames()[0], FileBufOrErr.getError().message()); return true; } llvm::MemoryBuffer *MainFile = FileBufOrErr.get().get(); llvm::SMDiagnostic Err; std::unique_ptr<llvm::Module> Module = llvm::parseIR( MainFile->getMemBufferRef(), Err, LLVMContext); if (!Module) { // TODO: Translate from the diagnostic info to the SourceManager location // if available. Instance.getASTContext().Diags.diagnose(SourceLoc(), diag::error_parse_input_file, Invocation.getInputFilenames()[0], Err.getMessage()); return true; } // TODO: remove once the frontend understands what action it should perform IRGenOpts.OutputKind = getOutputKind(Action); return performLLVM(IRGenOpts, Instance.getASTContext(), Module.get()); } ReferencedNameTracker nameTracker; bool shouldTrackReferences = !opts.ReferenceDependenciesFilePath.empty(); if (shouldTrackReferences) Instance.setReferencedNameTracker(&nameTracker); if (Action == FrontendOptions::DumpParse || Action == FrontendOptions::DumpInterfaceHash) Instance.performParseOnly(); else Instance.performSema(); FrontendOptions::DebugCrashMode CrashMode = opts.CrashMode; if (CrashMode == FrontendOptions::DebugCrashMode::AssertAfterParse) debugFailWithAssertion(); else if (CrashMode == FrontendOptions::DebugCrashMode::CrashAfterParse) debugFailWithCrash(); ASTContext &Context = Instance.getASTContext(); if (Action == FrontendOptions::REPL) { runREPL(Instance, ProcessCmdLine(Args.begin(), Args.end()), Invocation.getParseStdlib()); return false; } SourceFile *PrimarySourceFile = Instance.getPrimarySourceFile(); // We've been told to dump the AST (either after parsing or type-checking, // which is already differentiated in CompilerInstance::performSema()), // so dump or print the main source file and return. if (Action == FrontendOptions::DumpParse || Action == FrontendOptions::DumpAST || Action == FrontendOptions::PrintAST || Action == FrontendOptions::DumpTypeRefinementContexts || Action == FrontendOptions::DumpInterfaceHash) { SourceFile *SF = PrimarySourceFile; if (!SF) { SourceFileKind Kind = Invocation.getSourceFileKind(); SF = &Instance.getMainModule()->getMainSourceFile(Kind); } if (Action == FrontendOptions::PrintAST) SF->print(llvm::outs(), PrintOptions::printEverything()); else if (Action == FrontendOptions::DumpTypeRefinementContexts) SF->getTypeRefinementContext()->dump(llvm::errs(), Context.SourceMgr); else if (Action == FrontendOptions::DumpInterfaceHash) SF->dumpInterfaceHash(llvm::errs()); else SF->dump(); return false; } // If we were asked to print Clang stats, do so. if (opts.PrintClangStats && Context.getClangModuleLoader()) Context.getClangModuleLoader()->printStatistics(); if (!opts.DependenciesFilePath.empty()) (void)emitMakeDependencies(Context.Diags, *Instance.getDependencyTracker(), opts); if (shouldTrackReferences) emitReferenceDependencies(Context.Diags, Instance.getPrimarySourceFile(), *Instance.getDependencyTracker(), opts); if (Context.hadError()) return true; // FIXME: This is still a lousy approximation of whether the module file will // be externally consumed. bool moduleIsPublic = !Instance.getMainModule()->hasEntryPoint() && opts.ImplicitObjCHeaderPath.empty() && !Context.LangOpts.EnableAppExtensionRestrictions; // We've just been told to perform a parse, so we can return now. if (Action == FrontendOptions::Parse) { if (!opts.ObjCHeaderOutputPath.empty()) return printAsObjC(opts.ObjCHeaderOutputPath, Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic); return false; } assert(Action >= FrontendOptions::EmitSILGen && "All actions not requiring SILGen must have been handled!"); std::unique_ptr<SILModule> SM = Instance.takeSILModule(); if (!SM) { if (opts.PrimaryInput.hasValue() && opts.PrimaryInput.getValue().isFilename()) { FileUnit *PrimaryFile = PrimarySourceFile; if (!PrimaryFile) { auto Index = opts.PrimaryInput.getValue().Index; PrimaryFile = Instance.getMainModule()->getFiles()[Index]; } SM = performSILGeneration(*PrimaryFile, Invocation.getSILOptions(), None, opts.SILSerializeAll); } else { SM = performSILGeneration(Instance.getMainModule(), Invocation.getSILOptions(), opts.SILSerializeAll, true); } } // We've been told to emit SIL after SILGen, so write it now. if (Action == FrontendOptions::EmitSILGen) { // If we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); return writeSIL(*SM, Instance.getMainModule(), opts.EmitVerboseSIL, opts.getSingleOutputFilename(), opts.EmitSortedSIL); } if (Action == FrontendOptions::EmitSIBGen) { // If we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance.getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.SerializeAllSIL = true; serializationOpts.IsSIB = true; serialize(DC, serializationOpts, SM.get()); } return false; } // Perform "stable" optimizations that are invariant across compiler versions. if (!Invocation.getDiagnosticOptions().SkipDiagnosticPasses && runSILDiagnosticPasses(*SM)) return true; // Now if we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); SM->verify(); // Perform SIL optimization passes if optimizations haven't been disabled. // These may change across compiler versions. if (IRGenOpts.Optimize) { StringRef CustomPipelinePath = Invocation.getSILOptions().ExternalPassPipelineFilename; if (!CustomPipelinePath.empty()) { runSILOptimizationPassesWithFileSpecification(*SM, CustomPipelinePath); } else { runSILOptimizationPasses(*SM); } } else { runSILPassesForOnone(*SM); } SM->verify(); // Gather instruction counts if we are asked to do so. if (SM->getOptions().PrintInstCounts) { performSILInstCount(&*SM); } // Get the main source file's private discriminator and attach it to // the compile unit's flags. if (PrimarySourceFile) { Identifier PD = PrimarySourceFile->getPrivateDiscriminator(); if (!PD.empty()) IRGenOpts.DWARFDebugFlags += (" -private-discriminator "+PD.str()).str(); } if (!opts.ObjCHeaderOutputPath.empty()) { (void)printAsObjC(opts.ObjCHeaderOutputPath, Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic); } if (Action == FrontendOptions::EmitSIB) { auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance.getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.SerializeAllSIL = true; serializationOpts.IsSIB = true; serialize(DC, serializationOpts, SM.get()); } return false; } if (!opts.ModuleOutputPath.empty() || !opts.ModuleDocOutputPath.empty()) { auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance.getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.DocOutputPath = opts.ModuleDocOutputPath.c_str(); serializationOpts.SerializeAllSIL = opts.SILSerializeAll; if (opts.SerializeBridgingHeader) serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath; serializationOpts.ModuleLinkName = opts.ModuleLinkName; serializationOpts.ExtraClangOptions = Invocation.getClangImporterOptions().ExtraArgs; if (!IRGenOpts.ForceLoadSymbolName.empty()) serializationOpts.AutolinkForceLoad = true; // Options contain information about the developer's computer, // so only serialize them if the module isn't going to be shipped to // the public. serializationOpts.SerializeOptionsForDebugging = !moduleIsPublic || opts.AlwaysSerializeDebuggingOptions; serialize(DC, serializationOpts, SM.get()); } if (Action == FrontendOptions::EmitModuleOnly) return false; } assert(Action >= FrontendOptions::EmitSIL && "All actions not requiring SILPasses must have been handled!"); // We've been told to write canonical SIL, so write it now. if (Action == FrontendOptions::EmitSIL) { return writeSIL(*SM, Instance.getMainModule(), opts.EmitVerboseSIL, opts.getSingleOutputFilename(), opts.EmitSortedSIL); } assert(Action >= FrontendOptions::Immediate && "All actions not requiring IRGen must have been handled!"); assert(Action != FrontendOptions::REPL && "REPL mode must be handled immediately after Instance.performSema()"); // Check if we had any errors; if we did, don't proceed to IRGen. if (Context.hadError()) return true; // Cleanup instructions/builtin calls not suitable for IRGen. performSILCleanup(SM.get()); // TODO: remove once the frontend understands what action it should perform IRGenOpts.OutputKind = getOutputKind(Action); if (Action == FrontendOptions::Immediate) { assert(!PrimarySourceFile && "-i doesn't work in -primary-file mode"); IRGenOpts.UseJIT = true; IRGenOpts.DebugInfoKind = IRGenDebugInfoKind::Normal; const ProcessCmdLine &CmdLine = ProcessCmdLine(opts.ImmediateArgv.begin(), opts.ImmediateArgv.end()); Instance.setSILModule(std::move(SM)); ReturnValue = RunImmediately(Instance, CmdLine, IRGenOpts, Invocation.getSILOptions()); return false; } // FIXME: We shouldn't need to use the global context here, but // something is persisting across calls to performIRGeneration. auto &LLVMContext = llvm::getGlobalContext(); if (PrimarySourceFile) { performIRGeneration(IRGenOpts, *PrimarySourceFile, SM.get(), opts.getSingleOutputFilename(), LLVMContext); } else { performIRGeneration(IRGenOpts, Instance.getMainModule(), SM.get(), opts.getSingleOutputFilename(), LLVMContext); } return false; }
/// Print an identifier value. static void printValue(llvm::raw_ostream &os, Identifier value) { os << value.str(); }
/// Performs the compile requested by the user. /// \param Instance Will be reset after performIRGeneration when the verifier /// mode is NoVerify and there were no errors. /// \returns true on error static bool performCompile(std::unique_ptr<CompilerInstance> &Instance, CompilerInvocation &Invocation, ArrayRef<const char *> Args, int &ReturnValue, FrontendObserver *observer) { FrontendOptions opts = Invocation.getFrontendOptions(); FrontendOptions::ActionType Action = opts.RequestedAction; IRGenOptions &IRGenOpts = Invocation.getIRGenOptions(); bool inputIsLLVMIr = Invocation.getInputKind() == InputFileKind::IFK_LLVM_IR; if (inputIsLLVMIr) { auto &LLVMContext = getGlobalLLVMContext(); // Load in bitcode file. assert(Invocation.getInputFilenames().size() == 1 && "We expect a single input for bitcode input!"); llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(Invocation.getInputFilenames()[0]); if (!FileBufOrErr) { Instance->getASTContext().Diags.diagnose(SourceLoc(), diag::error_open_input_file, Invocation.getInputFilenames()[0], FileBufOrErr.getError().message()); return true; } llvm::MemoryBuffer *MainFile = FileBufOrErr.get().get(); llvm::SMDiagnostic Err; std::unique_ptr<llvm::Module> Module = llvm::parseIR( MainFile->getMemBufferRef(), Err, LLVMContext); if (!Module) { // TODO: Translate from the diagnostic info to the SourceManager location // if available. Instance->getASTContext().Diags.diagnose(SourceLoc(), diag::error_parse_input_file, Invocation.getInputFilenames()[0], Err.getMessage()); return true; } // TODO: remove once the frontend understands what action it should perform IRGenOpts.OutputKind = getOutputKind(Action); return performLLVM(IRGenOpts, Instance->getASTContext(), Module.get()); } ReferencedNameTracker nameTracker; bool shouldTrackReferences = !opts.ReferenceDependenciesFilePath.empty(); if (shouldTrackReferences) Instance->setReferencedNameTracker(&nameTracker); if (Action == FrontendOptions::Parse || Action == FrontendOptions::DumpParse || Action == FrontendOptions::DumpInterfaceHash) Instance->performParseOnly(); else Instance->performSema(); if (Action == FrontendOptions::Parse) return Instance->getASTContext().hadError(); if (observer) { observer->performedSemanticAnalysis(*Instance); } FrontendOptions::DebugCrashMode CrashMode = opts.CrashMode; if (CrashMode == FrontendOptions::DebugCrashMode::AssertAfterParse) debugFailWithAssertion(); else if (CrashMode == FrontendOptions::DebugCrashMode::CrashAfterParse) debugFailWithCrash(); ASTContext &Context = Instance->getASTContext(); if (Action == FrontendOptions::REPL) { runREPL(*Instance, ProcessCmdLine(Args.begin(), Args.end()), Invocation.getParseStdlib()); return Context.hadError(); } SourceFile *PrimarySourceFile = Instance->getPrimarySourceFile(); // We've been told to dump the AST (either after parsing or type-checking, // which is already differentiated in CompilerInstance::performSema()), // so dump or print the main source file and return. if (Action == FrontendOptions::DumpParse || Action == FrontendOptions::DumpAST || Action == FrontendOptions::PrintAST || Action == FrontendOptions::DumpScopeMaps || Action == FrontendOptions::DumpTypeRefinementContexts || Action == FrontendOptions::DumpInterfaceHash) { SourceFile *SF = PrimarySourceFile; if (!SF) { SourceFileKind Kind = Invocation.getSourceFileKind(); SF = &Instance->getMainModule()->getMainSourceFile(Kind); } if (Action == FrontendOptions::PrintAST) SF->print(llvm::outs(), PrintOptions::printEverything()); else if (Action == FrontendOptions::DumpScopeMaps) { ASTScope &scope = SF->getScope(); if (opts.DumpScopeMapLocations.empty()) { scope.expandAll(); } else if (auto bufferID = SF->getBufferID()) { SourceManager &sourceMgr = Instance->getSourceMgr(); // Probe each of the locations, and dump what we find. for (auto lineColumn : opts.DumpScopeMapLocations) { SourceLoc loc = sourceMgr.getLocForLineCol(*bufferID, lineColumn.first, lineColumn.second); if (loc.isInvalid()) continue; llvm::errs() << "***Scope at " << lineColumn.first << ":" << lineColumn.second << "***\n"; auto locScope = scope.findInnermostEnclosingScope(loc); locScope->print(llvm::errs(), 0, false, false); // Dump the AST context, too. if (auto dc = locScope->getDeclContext()) { dc->printContext(llvm::errs()); } // Grab the local bindings introduced by this scope. auto localBindings = locScope->getLocalBindings(); if (!localBindings.empty()) { llvm::errs() << "Local bindings: "; interleave(localBindings.begin(), localBindings.end(), [&](ValueDecl *value) { llvm::errs() << value->getFullName(); }, [&]() { llvm::errs() << " "; }); llvm::errs() << "\n"; } } llvm::errs() << "***Complete scope map***\n"; } // Print the resulting map. scope.print(llvm::errs()); } else if (Action == FrontendOptions::DumpTypeRefinementContexts) SF->getTypeRefinementContext()->dump(llvm::errs(), Context.SourceMgr); else if (Action == FrontendOptions::DumpInterfaceHash) SF->dumpInterfaceHash(llvm::errs()); else SF->dump(); return Context.hadError(); } // If we were asked to print Clang stats, do so. if (opts.PrintClangStats && Context.getClangModuleLoader()) Context.getClangModuleLoader()->printStatistics(); if (!opts.DependenciesFilePath.empty()) (void)emitMakeDependencies(Context.Diags, *Instance->getDependencyTracker(), opts); if (shouldTrackReferences) emitReferenceDependencies(Context.Diags, Instance->getPrimarySourceFile(), *Instance->getDependencyTracker(), opts); if (Context.hadError()) return true; // FIXME: This is still a lousy approximation of whether the module file will // be externally consumed. bool moduleIsPublic = !Instance->getMainModule()->hasEntryPoint() && opts.ImplicitObjCHeaderPath.empty() && !Context.LangOpts.EnableAppExtensionRestrictions; // We've just been told to perform a typecheck, so we can return now. if (Action == FrontendOptions::Typecheck) { if (!opts.ObjCHeaderOutputPath.empty()) return printAsObjC(opts.ObjCHeaderOutputPath, Instance->getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic); return Context.hadError(); } assert(Action >= FrontendOptions::EmitSILGen && "All actions not requiring SILGen must have been handled!"); std::unique_ptr<SILModule> SM = Instance->takeSILModule(); if (!SM) { if (opts.PrimaryInput.hasValue() && opts.PrimaryInput.getValue().isFilename()) { FileUnit *PrimaryFile = PrimarySourceFile; if (!PrimaryFile) { auto Index = opts.PrimaryInput.getValue().Index; PrimaryFile = Instance->getMainModule()->getFiles()[Index]; } SM = performSILGeneration(*PrimaryFile, Invocation.getSILOptions(), None, opts.SILSerializeAll); } else { SM = performSILGeneration(Instance->getMainModule(), Invocation.getSILOptions(), opts.SILSerializeAll, true); } } if (observer) { observer->performedSILGeneration(*SM); } // We've been told to emit SIL after SILGen, so write it now. if (Action == FrontendOptions::EmitSILGen) { // If we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); return writeSIL(*SM, Instance->getMainModule(), opts.EmitVerboseSIL, opts.getSingleOutputFilename(), opts.EmitSortedSIL); } if (Action == FrontendOptions::EmitSIBGen) { // If we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance->getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.SerializeAllSIL = true; serializationOpts.IsSIB = true; serialize(DC, serializationOpts, SM.get()); } return Context.hadError(); } // Perform "stable" optimizations that are invariant across compiler versions. if (!Invocation.getDiagnosticOptions().SkipDiagnosticPasses) { if (runSILDiagnosticPasses(*SM)) return true; if (observer) { observer->performedSILDiagnostics(*SM); } } else { // Even if we are not supposed to run the diagnostic passes, we still need // to run the ownership evaluator. if (runSILOwnershipEliminatorPass(*SM)) return true; } // Now if we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); { SharedTimer timer("SIL verification (pre-optimization)"); SM->verify(); } // Perform SIL optimization passes if optimizations haven't been disabled. // These may change across compiler versions. { SharedTimer timer("SIL optimization"); if (Invocation.getSILOptions().Optimization > SILOptions::SILOptMode::None) { StringRef CustomPipelinePath = Invocation.getSILOptions().ExternalPassPipelineFilename; if (!CustomPipelinePath.empty()) { runSILOptimizationPassesWithFileSpecification(*SM, CustomPipelinePath); } else { runSILOptimizationPasses(*SM); } } else { runSILPassesForOnone(*SM); } } if (observer) { observer->performedSILOptimization(*SM); } { SharedTimer timer("SIL verification (post-optimization)"); SM->verify(); } // Gather instruction counts if we are asked to do so. if (SM->getOptions().PrintInstCounts) { performSILInstCount(&*SM); } // Get the main source file's private discriminator and attach it to // the compile unit's flags. if (PrimarySourceFile) { Identifier PD = PrimarySourceFile->getPrivateDiscriminator(); if (!PD.empty()) IRGenOpts.DWARFDebugFlags += (" -private-discriminator "+PD.str()).str(); } if (!opts.ObjCHeaderOutputPath.empty()) { (void)printAsObjC(opts.ObjCHeaderOutputPath, Instance->getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic); } if (Action == FrontendOptions::EmitSIB) { auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance->getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.SerializeAllSIL = true; serializationOpts.IsSIB = true; serialize(DC, serializationOpts, SM.get()); } return Context.hadError(); } if (!opts.ModuleOutputPath.empty() || !opts.ModuleDocOutputPath.empty()) { auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance->getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.DocOutputPath = opts.ModuleDocOutputPath.c_str(); serializationOpts.GroupInfoPath = opts.GroupInfoPath.c_str(); serializationOpts.SerializeAllSIL = opts.SILSerializeAll; if (opts.SerializeBridgingHeader) serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath; serializationOpts.ModuleLinkName = opts.ModuleLinkName; serializationOpts.ExtraClangOptions = Invocation.getClangImporterOptions().ExtraArgs; if (!IRGenOpts.ForceLoadSymbolName.empty()) serializationOpts.AutolinkForceLoad = true; // Options contain information about the developer's computer, // so only serialize them if the module isn't going to be shipped to // the public. serializationOpts.SerializeOptionsForDebugging = !moduleIsPublic || opts.AlwaysSerializeDebuggingOptions; serialize(DC, serializationOpts, SM.get()); } if (Action == FrontendOptions::EmitModuleOnly) return Context.hadError(); } assert(Action >= FrontendOptions::EmitSIL && "All actions not requiring SILPasses must have been handled!"); // We've been told to write canonical SIL, so write it now. if (Action == FrontendOptions::EmitSIL) { return writeSIL(*SM, Instance->getMainModule(), opts.EmitVerboseSIL, opts.getSingleOutputFilename(), opts.EmitSortedSIL); } assert(Action >= FrontendOptions::Immediate && "All actions not requiring IRGen must have been handled!"); assert(Action != FrontendOptions::REPL && "REPL mode must be handled immediately after Instance->performSema()"); // Check if we had any errors; if we did, don't proceed to IRGen. if (Context.hadError()) return true; // Cleanup instructions/builtin calls not suitable for IRGen. performSILCleanup(SM.get()); // TODO: remove once the frontend understands what action it should perform IRGenOpts.OutputKind = getOutputKind(Action); if (Action == FrontendOptions::Immediate) { assert(!PrimarySourceFile && "-i doesn't work in -primary-file mode"); IRGenOpts.UseJIT = true; IRGenOpts.DebugInfoKind = IRGenDebugInfoKind::Normal; const ProcessCmdLine &CmdLine = ProcessCmdLine(opts.ImmediateArgv.begin(), opts.ImmediateArgv.end()); Instance->setSILModule(std::move(SM)); if (observer) { observer->aboutToRunImmediately(*Instance); } ReturnValue = RunImmediately(*Instance, CmdLine, IRGenOpts, Invocation.getSILOptions()); return Context.hadError(); } // FIXME: We shouldn't need to use the global context here, but // something is persisting across calls to performIRGeneration. auto &LLVMContext = getGlobalLLVMContext(); std::unique_ptr<llvm::Module> IRModule; llvm::GlobalVariable *HashGlobal; if (PrimarySourceFile) { IRModule = performIRGeneration(IRGenOpts, *PrimarySourceFile, std::move(SM), opts.getSingleOutputFilename(), LLVMContext, 0, &HashGlobal); } else { IRModule = performIRGeneration(IRGenOpts, Instance->getMainModule(), std::move(SM), opts.getSingleOutputFilename(), LLVMContext, &HashGlobal); } // Just because we had an AST error it doesn't mean we can't performLLVM. bool HadError = Instance->getASTContext().hadError(); // If the AST Context has no errors but no IRModule is available, // parallelIRGen happened correctly, since parallel IRGen produces multiple // modules. if (!IRModule) { return HadError; } std::unique_ptr<llvm::TargetMachine> TargetMachine = createTargetMachine(IRGenOpts, Context); version::Version EffectiveLanguageVersion = Context.LangOpts.EffectiveLanguageVersion; DiagnosticEngine &Diags = Context.Diags; const DiagnosticOptions &DiagOpts = Invocation.getDiagnosticOptions(); // Delete the compiler instance now that we have an IRModule. if (DiagOpts.VerifyMode == DiagnosticOptions::NoVerify) { SM.reset(); Instance.reset(); } // Now that we have a single IR Module, hand it over to performLLVM. return performLLVM(IRGenOpts, &Diags, nullptr, HashGlobal, IRModule.get(), TargetMachine.get(), EffectiveLanguageVersion, opts.getSingleOutputFilename()) || HadError; }
void formatValue(std::ostream& out, const char* /*fmtBegin*/, const char* fmtEnd, int ntrunc, const Identifier& id) { out << id.str(); }
void swift::serialization::diagnoseSerializedASTLoadFailure( ASTContext &Ctx, SourceLoc diagLoc, const serialization::ValidationInfo &loadInfo, const serialization::ExtendedValidationInfo &extendedInfo, StringRef moduleBufferID, StringRef moduleDocBufferID, ModuleFile *loadedModuleFile, Identifier ModuleName) { auto diagnoseDifferentLanguageVersion = [&](StringRef shortVersion) -> bool { if (shortVersion.empty()) return false; SmallString<32> versionBuf; llvm::raw_svector_ostream versionString(versionBuf); versionString << Version::getCurrentLanguageVersion(); if (versionString.str() == shortVersion) return false; Ctx.Diags.diagnose( diagLoc, diag::serialization_module_language_version_mismatch, loadInfo.shortVersion, versionString.str(), moduleBufferID); return true; }; switch (loadInfo.status) { case serialization::Status::Valid: llvm_unreachable("At this point we know loading has failed"); case serialization::Status::FormatTooNew: if (diagnoseDifferentLanguageVersion(loadInfo.shortVersion)) break; Ctx.Diags.diagnose(diagLoc, diag::serialization_module_too_new, moduleBufferID); break; case serialization::Status::FormatTooOld: if (diagnoseDifferentLanguageVersion(loadInfo.shortVersion)) break; Ctx.Diags.diagnose(diagLoc, diag::serialization_module_too_old, ModuleName, moduleBufferID); break; case serialization::Status::Malformed: Ctx.Diags.diagnose(diagLoc, diag::serialization_malformed_module, moduleBufferID); break; case serialization::Status::MalformedDocumentation: assert(!moduleDocBufferID.empty()); Ctx.Diags.diagnose(diagLoc, diag::serialization_malformed_module, moduleDocBufferID); break; case serialization::Status::MissingDependency: { // Figure out /which/ dependencies are missing. // FIXME: Dependencies should be de-duplicated at serialization time, // not now. llvm::StringSet<> duplicates; llvm::SmallVector<ModuleFile::Dependency, 4> missing; std::copy_if( loadedModuleFile->getDependencies().begin(), loadedModuleFile->getDependencies().end(), std::back_inserter(missing), [&duplicates](const ModuleFile::Dependency &dependency) -> bool { if (dependency.isLoaded() || dependency.isHeader() || dependency.isImplementationOnly()) { return false; } return duplicates.insert(dependency.RawPath).second; }); // FIXME: only show module part of RawAccessPath assert(!missing.empty() && "unknown missing dependency?"); if (missing.size() == 1) { Ctx.Diags.diagnose(diagLoc, diag::serialization_missing_single_dependency, missing.front().getPrettyPrintedPath()); } else { llvm::SmallString<64> missingNames; missingNames += '\''; interleave(missing, [&](const ModuleFile::Dependency &next) { missingNames += next.getPrettyPrintedPath(); }, [&] { missingNames += "', '"; }); missingNames += '\''; Ctx.Diags.diagnose(diagLoc, diag::serialization_missing_dependencies, missingNames); } if (Ctx.SearchPathOpts.SDKPath.empty() && llvm::Triple(llvm::sys::getProcessTriple()).isMacOSX()) { Ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk); Ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk_xcrun); } break; } case serialization::Status::CircularDependency: { auto circularDependencyIter = llvm::find_if(loadedModuleFile->getDependencies(), [](const ModuleFile::Dependency &next) { return !next.Import.second->hasResolvedImports(); }); assert(circularDependencyIter != loadedModuleFile->getDependencies().end() && "circular dependency reported, but no module with unresolved " "imports found"); // FIXME: We should include the path of the circularity as well, but that's // hard because we're discovering this /while/ resolving imports, which // means the problematic modules haven't been recorded yet. Ctx.Diags.diagnose(diagLoc, diag::serialization_circular_dependency, circularDependencyIter->getPrettyPrintedPath(), ModuleName); break; } case serialization::Status::MissingShadowedModule: { Ctx.Diags.diagnose(diagLoc, diag::serialization_missing_shadowed_module, ModuleName); if (Ctx.SearchPathOpts.SDKPath.empty() && llvm::Triple(llvm::sys::getProcessTriple()).isMacOSX()) { Ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk); Ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk_xcrun); } break; } case serialization::Status::FailedToLoadBridgingHeader: // We already emitted a diagnostic about the bridging header. Just emit // a generic message here. Ctx.Diags.diagnose(diagLoc, diag::serialization_load_failed, ModuleName); break; case serialization::Status::NameMismatch: { // FIXME: This doesn't handle a non-debugger REPL, which should also treat // this as a non-fatal error. auto diagKind = diag::serialization_name_mismatch; if (Ctx.LangOpts.DebuggerSupport) diagKind = diag::serialization_name_mismatch_repl; Ctx.Diags.diagnose(diagLoc, diagKind, loadInfo.name, ModuleName.str()); break; } case serialization::Status::TargetIncompatible: { // FIXME: This doesn't handle a non-debugger REPL, which should also treat // this as a non-fatal error. auto diagKind = diag::serialization_target_incompatible; if (Ctx.LangOpts.DebuggerSupport) diagKind = diag::serialization_target_incompatible_repl; Ctx.Diags.diagnose(diagLoc, diagKind, ModuleName, loadInfo.targetTriple, moduleBufferID); break; } case serialization::Status::TargetTooNew: { llvm::Triple moduleTarget(llvm::Triple::normalize(loadInfo.targetTriple)); std::pair<StringRef, clang::VersionTuple> moduleOSInfo = getOSAndVersionForDiagnostics(moduleTarget); std::pair<StringRef, clang::VersionTuple> compilationOSInfo = getOSAndVersionForDiagnostics(Ctx.LangOpts.Target); // FIXME: This doesn't handle a non-debugger REPL, which should also treat // this as a non-fatal error. auto diagKind = diag::serialization_target_too_new; if (Ctx.LangOpts.DebuggerSupport) diagKind = diag::serialization_target_too_new_repl; Ctx.Diags.diagnose(diagLoc, diagKind, compilationOSInfo.first, compilationOSInfo.second, ModuleName, moduleOSInfo.second, moduleBufferID); break; } } }
bool Blockchain::AssignAddress( const Identifier& nymID, const Identifier& accountID, const std::uint32_t index, const Identifier& contactID, const BIP44Chain chain) const { LOCK_ACCOUNT() const std::string sNymID = nymID.str(); const std::string sAccountID = accountID.str(); const std::string sContactID = contactID.str(); auto account = load_account(accountLock, sNymID, sAccountID); if (false == bool(account)) { otErr << OT_METHOD << __FUNCTION__ << ": Account does not exist." << std::endl; return false; } const auto& type = account->type(); const auto allocatedIndex = chain ? account->internalindex() : account->externalindex(); if (index > allocatedIndex) { otErr << OT_METHOD << __FUNCTION__ << ": Address has not been allocated." << std::endl; return false; } auto& address = find_address(index, chain, *account); const auto& existing = address.contact(); if (false == existing.empty()) { move_transactions(nymID, address, existing, sContactID); } address.set_contact(sContactID); account->set_revision(account->revision() + 1); // check: does the activity thread exist between nym and contact? bool threadExists = false; const auto threadList = api_.Storage().ThreadList(sNymID, false); for (const auto it : threadList) { const auto& id = it.first; if (id == sContactID) { threadExists = true; } } if (threadExists) { // check: does every incoming transaction exist as an activity std::shared_ptr<proto::StorageThread> thread = activity_.Thread(nymID, contactID); OT_ASSERT(thread); for (const std::string& txID : address.incoming()) { bool exists = false; for (const auto activity : thread->item()) if (txID.compare(activity.id()) == 0) exists = true; // add: transaction to the thread if (!exists) { activity_.AddBlockchainTransaction( nymID, contactID, StorageBox::INCOMINGBLOCKCHAIN, *Transaction(txID)); } } } else { // create the thread and add the transactions for (const auto txID : address.incoming()) { activity_.AddBlockchainTransaction( nymID, contactID, StorageBox::INCOMINGBLOCKCHAIN, *Transaction(txID)); } } return api_.Storage().Store(sNymID, type, *account); }
void TypeChecker::checkForForbiddenPrefix(Identifier Ident) { if (!hasEnabledForbiddenTypecheckPrefix()) return; checkForForbiddenPrefix(Ident.empty() ? StringRef() : Ident.str()); }
bool Blockchain::StoreIncoming( const Identifier& nymID, const Identifier& accountID, const std::uint32_t index, const BIP44Chain chain, const proto::BlockchainTransaction& transaction) const { LOCK_ACCOUNT() const std::string sNymID = nymID.str(); const std::string sAccountID = accountID.str(); auto account = load_account(accountLock, sNymID, sAccountID); if (false == bool(account)) { otErr << OT_METHOD << __FUNCTION__ << ": Account does not exist." << std::endl; return false; } const auto allocatedIndex = chain ? account->internalindex() : account->externalindex(); if (index > allocatedIndex) { otErr << OT_METHOD << __FUNCTION__ << ": Address has not been allocated." << std::endl; return false; } auto& address = find_address(index, chain, *account); bool exists = false; for (const auto& txid : address.incoming()) { if (txid == transaction.txid()) { exists = true; break; } } if (false == exists) { address.add_incoming(transaction.txid()); } auto saved = api_.Storage().Store(sNymID, account->type(), *account); if (false == saved) { otErr << OT_METHOD << __FUNCTION__ << ": Failed to save account." << std::endl; return false; } saved = api_.Storage().Store(transaction); if (false == saved) { otErr << OT_METHOD << __FUNCTION__ << ": Failed to save transaction." << std::endl; return false; } if (address.contact().empty()) { return true; } const auto contactID = Identifier::Factory(address.contact()); return activity_.AddBlockchainTransaction( nymID, contactID, StorageBox::INCOMINGBLOCKCHAIN, transaction); }
bool Identifier::operator == (const Identifier& other) const { return (other.name == this->name) && (other.str() == this->str()); }
/// emitBuiltinCall - Emit a call to a builtin function. void irgen::emitBuiltinCall(IRGenFunction &IGF, Identifier FnId, SILType resultType, Explosion &args, Explosion &out, SubstitutionList substitutions) { // Decompose the function's name into a builtin name and type list. const BuiltinInfo &Builtin = IGF.getSILModule().getBuiltinInfo(FnId); if (Builtin.ID == BuiltinValueKind::UnsafeGuaranteedEnd) { // Just consume the incoming argument. assert(args.size() == 1 && "Expecting one incoming argument"); (void)args.claimAll(); return; } if (Builtin.ID == BuiltinValueKind::UnsafeGuaranteed) { // Just forward the incoming argument. assert(args.size() == 1 && "Expecting one incoming argument"); out = std::move(args); // This is a token. out.add(llvm::ConstantInt::get(IGF.IGM.Int8Ty, 0)); return; } if (Builtin.ID == BuiltinValueKind::OnFastPath) { // The onFastPath builtin has only an effect on SIL level, so we lower it // to a no-op. return; } // These builtins don't care about their argument: if (Builtin.ID == BuiltinValueKind::Sizeof) { (void)args.claimAll(); auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM, substitutions[0].getReplacement()); out.add(valueTy.second.getSize(IGF, valueTy.first)); return; } if (Builtin.ID == BuiltinValueKind::Strideof) { (void)args.claimAll(); auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM, substitutions[0].getReplacement()); out.add(valueTy.second.getStride(IGF, valueTy.first)); return; } if (Builtin.ID == BuiltinValueKind::Alignof) { (void)args.claimAll(); auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM, substitutions[0].getReplacement()); // The alignof value is one greater than the alignment mask. out.add(IGF.Builder.CreateAdd( valueTy.second.getAlignmentMask(IGF, valueTy.first), IGF.IGM.getSize(Size(1)))); return; } if (Builtin.ID == BuiltinValueKind::IsPOD) { (void)args.claimAll(); auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM, substitutions[0].getReplacement()); out.add(valueTy.second.getIsPOD(IGF, valueTy.first)); return; } // addressof expects an lvalue argument. if (Builtin.ID == BuiltinValueKind::AddressOf) { llvm::Value *address = args.claimNext(); llvm::Value *value = IGF.Builder.CreateBitCast(address, IGF.IGM.Int8PtrTy); out.add(value); return; } // Everything else cares about the (rvalue) argument. // If this is an LLVM IR intrinsic, lower it to an intrinsic call. const IntrinsicInfo &IInfo = IGF.getSILModule().getIntrinsicInfo(FnId); llvm::Intrinsic::ID IID = IInfo.ID; // Calls to the int_instrprof_increment intrinsic are emitted during SILGen. // At that stage, the function name GV used by the profiling pass is hidden. // Fix the intrinsic call here by pointing it to the correct GV. if (IID == llvm::Intrinsic::instrprof_increment) { // Extract the PGO function name. auto *NameGEP = cast<llvm::User>(args.claimNext()); auto *NameGV = dyn_cast<llvm::GlobalVariable>(NameGEP->stripPointerCasts()); if (NameGV) { auto *NameC = NameGV->getInitializer(); StringRef Name = cast<llvm::ConstantDataArray>(NameC)->getRawDataValues(); StringRef PGOFuncName = Name.rtrim(StringRef("\0", 1)); // Point the increment call to the right function name variable. std::string PGOFuncNameVar = llvm::getPGOFuncNameVarName( PGOFuncName, llvm::GlobalValue::LinkOnceAnyLinkage); auto *FuncNamePtr = IGF.IGM.Module.getNamedGlobal(PGOFuncNameVar); if (FuncNamePtr) { llvm::SmallVector<llvm::Value *, 2> Indices(2, NameGEP->getOperand(1)); NameGEP = llvm::ConstantExpr::getGetElementPtr( ((llvm::PointerType *)FuncNamePtr->getType())->getElementType(), FuncNamePtr, makeArrayRef(Indices)); } } // Replace the placeholder value with the new GEP. Explosion replacement; replacement.add(NameGEP); replacement.add(args.claimAll()); args = std::move(replacement); } if (IID != llvm::Intrinsic::not_intrinsic) { SmallVector<llvm::Type*, 4> ArgTys; for (auto T : IInfo.Types) ArgTys.push_back(IGF.IGM.getStorageTypeForLowered(T->getCanonicalType())); auto F = llvm::Intrinsic::getDeclaration(&IGF.IGM.Module, (llvm::Intrinsic::ID)IID, ArgTys); llvm::FunctionType *FT = F->getFunctionType(); SmallVector<llvm::Value*, 8> IRArgs; for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) IRArgs.push_back(args.claimNext()); llvm::Value *TheCall = IGF.Builder.CreateCall(F, IRArgs); if (!TheCall->getType()->isVoidTy()) extractScalarResults(IGF, TheCall->getType(), TheCall, out); return; } // TODO: A linear series of ifs is suboptimal. #define BUILTIN_SIL_OPERATION(id, name, overload) \ if (Builtin.ID == BuiltinValueKind::id) \ llvm_unreachable(name " builtin should be lowered away by SILGen!"); #define BUILTIN_CAST_OPERATION(id, name, attrs) \ if (Builtin.ID == BuiltinValueKind::id) \ return emitCastBuiltin(IGF, resultType, out, args, \ llvm::Instruction::id); #define BUILTIN_CAST_OR_BITCAST_OPERATION(id, name, attrs) \ if (Builtin.ID == BuiltinValueKind::id) \ return emitCastOrBitCastBuiltin(IGF, resultType, out, args, \ BuiltinValueKind::id); #define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) \ if (Builtin.ID == BuiltinValueKind::id) { \ llvm::Value *lhs = args.claimNext(); \ llvm::Value *rhs = args.claimNext(); \ llvm::Value *v = IGF.Builder.Create##id(lhs, rhs); \ return out.add(v); \ } #define BUILTIN_RUNTIME_CALL(id, name, attrs) \ if (Builtin.ID == BuiltinValueKind::id) { \ llvm::CallInst *call = IGF.Builder.CreateCall(IGF.IGM.get##id##Fn(), \ args.claimNext()); \ call->setCallingConv(IGF.IGM.DefaultCC); \ call->setDoesNotThrow(); \ return out.add(call); \ } #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, uncheckedID, attrs, overload) \ if (Builtin.ID == BuiltinValueKind::id) { \ SmallVector<llvm::Type*, 2> ArgTys; \ auto opType = Builtin.Types[0]->getCanonicalType(); \ ArgTys.push_back(IGF.IGM.getStorageTypeForLowered(opType)); \ auto F = llvm::Intrinsic::getDeclaration(&IGF.IGM.Module, \ getLLVMIntrinsicIDForBuiltinWithOverflow(Builtin.ID), ArgTys); \ SmallVector<llvm::Value*, 2> IRArgs; \ IRArgs.push_back(args.claimNext()); \ IRArgs.push_back(args.claimNext()); \ args.claimNext();\ llvm::Value *TheCall = IGF.Builder.CreateCall(F, IRArgs); \ extractScalarResults(IGF, TheCall->getType(), TheCall, out); \ return; \ } // FIXME: We could generate the code to dynamically report the overflow if the // third argument is true. Now, we just ignore it. #define BUILTIN_BINARY_PREDICATE(id, name, attrs, overload) \ if (Builtin.ID == BuiltinValueKind::id) \ return emitCompareBuiltin(IGF, out, args, llvm::CmpInst::id); #define BUILTIN_TYPE_TRAIT_OPERATION(id, name) \ if (Builtin.ID == BuiltinValueKind::id) \ return emitTypeTraitBuiltin(IGF, out, args, substitutions, &TypeBase::name); #define BUILTIN(ID, Name, Attrs) // Ignore the rest. #include "swift/AST/Builtins.def" if (Builtin.ID == BuiltinValueKind::FNeg) { llvm::Value *rhs = args.claimNext(); llvm::Value *lhs = llvm::ConstantFP::get(rhs->getType(), "-0.0"); llvm::Value *v = IGF.Builder.CreateFSub(lhs, rhs); return out.add(v); } if (Builtin.ID == BuiltinValueKind::AssumeNonNegative) { llvm::Value *v = args.claimNext(); // Set a value range on the load instruction, which must be the argument of // the builtin. if (isa<llvm::LoadInst>(v) || isa<llvm::CallInst>(v)) { // The load must be post-dominated by the builtin. Otherwise we would get // a wrong assumption in the else-branch in this example: // x = f() // if condition { // y = assumeNonNegative(x) // } else { // // x might be negative here! // } // For simplicity we just enforce that both the load and the builtin must // be in the same block. llvm::Instruction *I = static_cast<llvm::Instruction *>(v); if (I->getParent() == IGF.Builder.GetInsertBlock()) { llvm::LLVMContext &ctx = IGF.IGM.Module.getContext(); auto *intType = dyn_cast<llvm::IntegerType>(v->getType()); llvm::Metadata *rangeElems[] = { llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(intType, 0)), llvm::ConstantAsMetadata::get( llvm::ConstantInt::get(intType, APInt::getSignedMaxValue(intType->getBitWidth()))) }; llvm::MDNode *range = llvm::MDNode::get(ctx, rangeElems); I->setMetadata(llvm::LLVMContext::MD_range, range); } } // Don't generate any code for the builtin. return out.add(v); } if (Builtin.ID == BuiltinValueKind::AllocRaw) { auto size = args.claimNext(); auto align = args.claimNext(); // Translate the alignment to a mask. auto alignMask = IGF.Builder.CreateSub(align, IGF.IGM.getSize(Size(1))); auto alloc = IGF.emitAllocRawCall(size, alignMask, "builtin-allocRaw"); out.add(alloc); return; } if (Builtin.ID == BuiltinValueKind::DeallocRaw) { auto pointer = args.claimNext(); auto size = args.claimNext(); auto align = args.claimNext(); // Translate the alignment to a mask. auto alignMask = IGF.Builder.CreateSub(align, IGF.IGM.getSize(Size(1))); IGF.emitDeallocRawCall(pointer, size, alignMask); return; } if (Builtin.ID == BuiltinValueKind::Fence) { SmallVector<Type, 4> Types; StringRef BuiltinName = getBuiltinBaseName(IGF.IGM.Context, FnId.str(), Types); BuiltinName = BuiltinName.drop_front(strlen("fence_")); // Decode the ordering argument, which is required. auto underscore = BuiltinName.find('_'); auto ordering = decodeLLVMAtomicOrdering(BuiltinName.substr(0, underscore)); assert(ordering != llvm::AtomicOrdering::NotAtomic); BuiltinName = BuiltinName.substr(underscore); // Accept singlethread if present. bool isSingleThread = BuiltinName.startswith("_singlethread"); if (isSingleThread) BuiltinName = BuiltinName.drop_front(strlen("_singlethread")); assert(BuiltinName.empty() && "Mismatch with sema"); IGF.Builder.CreateFence(ordering, isSingleThread ? llvm::SyncScope::SingleThread : llvm::SyncScope::System); return; } if (Builtin.ID == BuiltinValueKind::CmpXChg) { SmallVector<Type, 4> Types; StringRef BuiltinName = getBuiltinBaseName(IGF.IGM.Context, FnId.str(), Types); BuiltinName = BuiltinName.drop_front(strlen("cmpxchg_")); // Decode the success- and failure-ordering arguments, which are required. SmallVector<StringRef, 4> Parts; BuiltinName.split(Parts, "_"); assert(Parts.size() >= 2 && "Mismatch with sema"); auto successOrdering = decodeLLVMAtomicOrdering(Parts[0]); auto failureOrdering = decodeLLVMAtomicOrdering(Parts[1]); assert(successOrdering != llvm::AtomicOrdering::NotAtomic); assert(failureOrdering != llvm::AtomicOrdering::NotAtomic); auto NextPart = Parts.begin() + 2; // Accept weak, volatile, and singlethread if present. bool isWeak = false, isVolatile = false, isSingleThread = false; if (NextPart != Parts.end() && *NextPart == "weak") { isWeak = true; NextPart++; } if (NextPart != Parts.end() && *NextPart == "volatile") { isVolatile = true; NextPart++; } if (NextPart != Parts.end() && *NextPart == "singlethread") { isSingleThread = true; NextPart++; } assert(NextPart == Parts.end() && "Mismatch with sema"); auto pointer = args.claimNext(); auto cmp = args.claimNext(); auto newval = args.claimNext(); llvm::Type *origTy = cmp->getType(); if (origTy->isPointerTy()) { cmp = IGF.Builder.CreatePtrToInt(cmp, IGF.IGM.IntPtrTy); newval = IGF.Builder.CreatePtrToInt(newval, IGF.IGM.IntPtrTy); } pointer = IGF.Builder.CreateBitCast(pointer, llvm::PointerType::getUnqual(cmp->getType())); llvm::Value *value = IGF.Builder.CreateAtomicCmpXchg( pointer, cmp, newval, successOrdering, failureOrdering, isSingleThread ? llvm::SyncScope::SingleThread : llvm::SyncScope::System); cast<llvm::AtomicCmpXchgInst>(value)->setVolatile(isVolatile); cast<llvm::AtomicCmpXchgInst>(value)->setWeak(isWeak); auto valueLoaded = IGF.Builder.CreateExtractValue(value, {0}); auto loadSuccessful = IGF.Builder.CreateExtractValue(value, {1}); if (origTy->isPointerTy()) valueLoaded = IGF.Builder.CreateIntToPtr(valueLoaded, origTy); out.add(valueLoaded); out.add(loadSuccessful); return; } if (Builtin.ID == BuiltinValueKind::AtomicRMW) { using namespace llvm; SmallVector<Type, 4> Types; StringRef BuiltinName = getBuiltinBaseName(IGF.IGM.Context, FnId.str(), Types); BuiltinName = BuiltinName.drop_front(strlen("atomicrmw_")); auto underscore = BuiltinName.find('_'); StringRef SubOp = BuiltinName.substr(0, underscore); AtomicRMWInst::BinOp SubOpcode = StringSwitch<AtomicRMWInst::BinOp>(SubOp) .Case("xchg", AtomicRMWInst::Xchg) .Case("add", AtomicRMWInst::Add) .Case("sub", AtomicRMWInst::Sub) .Case("and", AtomicRMWInst::And) .Case("nand", AtomicRMWInst::Nand) .Case("or", AtomicRMWInst::Or) .Case("xor", AtomicRMWInst::Xor) .Case("max", AtomicRMWInst::Max) .Case("min", AtomicRMWInst::Min) .Case("umax", AtomicRMWInst::UMax) .Case("umin", AtomicRMWInst::UMin); BuiltinName = BuiltinName.drop_front(underscore+1); // Decode the ordering argument, which is required. underscore = BuiltinName.find('_'); auto ordering = decodeLLVMAtomicOrdering(BuiltinName.substr(0, underscore)); assert(ordering != llvm::AtomicOrdering::NotAtomic); BuiltinName = BuiltinName.substr(underscore); // Accept volatile and singlethread if present. bool isVolatile = BuiltinName.startswith("_volatile"); if (isVolatile) BuiltinName = BuiltinName.drop_front(strlen("_volatile")); bool isSingleThread = BuiltinName.startswith("_singlethread"); if (isSingleThread) BuiltinName = BuiltinName.drop_front(strlen("_singlethread")); assert(BuiltinName.empty() && "Mismatch with sema"); auto pointer = args.claimNext(); auto val = args.claimNext(); // Handle atomic ops on pointers by casting to intptr_t. llvm::Type *origTy = val->getType(); if (origTy->isPointerTy()) val = IGF.Builder.CreatePtrToInt(val, IGF.IGM.IntPtrTy); pointer = IGF.Builder.CreateBitCast(pointer, llvm::PointerType::getUnqual(val->getType())); llvm::Value *value = IGF.Builder.CreateAtomicRMW( SubOpcode, pointer, val, ordering, isSingleThread ? llvm::SyncScope::SingleThread : llvm::SyncScope::System); cast<AtomicRMWInst>(value)->setVolatile(isVolatile); if (origTy->isPointerTy()) value = IGF.Builder.CreateIntToPtr(value, origTy); out.add(value); return; } if (Builtin.ID == BuiltinValueKind::AtomicLoad || Builtin.ID == BuiltinValueKind::AtomicStore) { using namespace llvm; SmallVector<Type, 4> Types; StringRef BuiltinName = getBuiltinBaseName(IGF.IGM.Context, FnId.str(), Types); auto underscore = BuiltinName.find('_'); BuiltinName = BuiltinName.substr(underscore+1); underscore = BuiltinName.find('_'); auto ordering = decodeLLVMAtomicOrdering(BuiltinName.substr(0, underscore)); assert(ordering != llvm::AtomicOrdering::NotAtomic); BuiltinName = BuiltinName.substr(underscore); // Accept volatile and singlethread if present. bool isVolatile = BuiltinName.startswith("_volatile"); if (isVolatile) BuiltinName = BuiltinName.drop_front(strlen("_volatile")); bool isSingleThread = BuiltinName.startswith("_singlethread"); if (isSingleThread) BuiltinName = BuiltinName.drop_front(strlen("_singlethread")); assert(BuiltinName.empty() && "Mismatch with sema"); auto pointer = args.claimNext(); auto &valueTI = IGF.getTypeInfoForUnlowered(Types[0]); auto schema = valueTI.getSchema(); assert(schema.size() == 1 && "not a scalar type?!"); auto origValueTy = schema[0].getScalarType(); // If the type is floating-point, then we need to bitcast to integer. auto valueTy = origValueTy; if (valueTy->isFloatingPointTy()) { valueTy = llvm::IntegerType::get(IGF.IGM.LLVMContext, valueTy->getPrimitiveSizeInBits()); } pointer = IGF.Builder.CreateBitCast(pointer, valueTy->getPointerTo()); if (Builtin.ID == BuiltinValueKind::AtomicLoad) { auto load = IGF.Builder.CreateLoad(pointer, valueTI.getBestKnownAlignment()); load->setAtomic(ordering, isSingleThread ? llvm::SyncScope::SingleThread : llvm::SyncScope::System); load->setVolatile(isVolatile); llvm::Value *value = load; if (valueTy != origValueTy) value = IGF.Builder.CreateBitCast(value, origValueTy); out.add(value); return; } else if (Builtin.ID == BuiltinValueKind::AtomicStore) { llvm::Value *value = args.claimNext(); if (valueTy != origValueTy) value = IGF.Builder.CreateBitCast(value, valueTy); auto store = IGF.Builder.CreateStore(value, pointer, valueTI.getBestKnownAlignment()); store->setAtomic(ordering, isSingleThread ? llvm::SyncScope::SingleThread : llvm::SyncScope::System); store->setVolatile(isVolatile); return; } else { llvm_unreachable("out of sync with outer conditional"); } } if (Builtin.ID == BuiltinValueKind::ExtractElement) { using namespace llvm; auto vector = args.claimNext(); auto index = args.claimNext(); out.add(IGF.Builder.CreateExtractElement(vector, index)); return; } if (Builtin.ID == BuiltinValueKind::InsertElement) { using namespace llvm; auto vector = args.claimNext(); auto newValue = args.claimNext(); auto index = args.claimNext(); out.add(IGF.Builder.CreateInsertElement(vector, newValue, index)); return; } if (Builtin.ID == BuiltinValueKind::SToSCheckedTrunc || Builtin.ID == BuiltinValueKind::UToUCheckedTrunc || Builtin.ID == BuiltinValueKind::SToUCheckedTrunc) { auto FromTy = IGF.IGM.getStorageTypeForLowered(Builtin.Types[0]->getCanonicalType()); auto ToTy = IGF.IGM.getStorageTypeForLowered(Builtin.Types[1]->getCanonicalType()); // Compute the result for SToSCheckedTrunc_IntFrom_IntTo(Arg): // Res = trunc_IntTo(Arg) // Ext = sext_IntFrom(Res) // OverflowFlag = (Arg == Ext) ? 0 : 1 // return (resultVal, OverflowFlag) // // Compute the result for UToUCheckedTrunc_IntFrom_IntTo(Arg) // and SToUCheckedTrunc_IntFrom_IntTo(Arg): // Res = trunc_IntTo(Arg) // Ext = zext_IntFrom(Res) // OverflowFlag = (Arg == Ext) ? 0 : 1 // return (Res, OverflowFlag) llvm::Value *Arg = args.claimNext(); llvm::Value *Res = IGF.Builder.CreateTrunc(Arg, ToTy); bool Signed = (Builtin.ID == BuiltinValueKind::SToSCheckedTrunc); llvm::Value *Ext = Signed ? IGF.Builder.CreateSExt(Res, FromTy) : IGF.Builder.CreateZExt(Res, FromTy); llvm::Value *OverflowCond = IGF.Builder.CreateICmpEQ(Arg, Ext); llvm::Value *OverflowFlag = IGF.Builder.CreateSelect(OverflowCond, llvm::ConstantInt::get(IGF.IGM.Int1Ty, 0), llvm::ConstantInt::get(IGF.IGM.Int1Ty, 1)); // Return the tuple - the result + the overflow flag. out.add(Res); return out.add(OverflowFlag); } if (Builtin.ID == BuiltinValueKind::UToSCheckedTrunc) { auto FromTy = IGF.IGM.getStorageTypeForLowered(Builtin.Types[0]->getCanonicalType()); auto ToTy = IGF.IGM.getStorageTypeForLowered(Builtin.Types[1]->getCanonicalType()); llvm::Type *ToMinusOneTy = llvm::Type::getIntNTy(ToTy->getContext(), ToTy->getIntegerBitWidth() - 1); // Compute the result for UToSCheckedTrunc_IntFrom_IntTo(Arg): // Res = trunc_IntTo(Arg) // Trunc = trunc_'IntTo-1bit'(Arg) // Ext = zext_IntFrom(Trunc) // OverflowFlag = (Arg == Ext) ? 0 : 1 // return (Res, OverflowFlag) llvm::Value *Arg = args.claimNext(); llvm::Value *Res = IGF.Builder.CreateTrunc(Arg, ToTy); llvm::Value *Trunc = IGF.Builder.CreateTrunc(Arg, ToMinusOneTy); llvm::Value *Ext = IGF.Builder.CreateZExt(Trunc, FromTy); llvm::Value *OverflowCond = IGF.Builder.CreateICmpEQ(Arg, Ext); llvm::Value *OverflowFlag = IGF.Builder.CreateSelect(OverflowCond, llvm::ConstantInt::get(IGF.IGM.Int1Ty, 0), llvm::ConstantInt::get(IGF.IGM.Int1Ty, 1)); // Return the tuple: (the result, the overflow flag). out.add(Res); return out.add(OverflowFlag); } if (Builtin.ID == BuiltinValueKind::SUCheckedConversion || Builtin.ID == BuiltinValueKind::USCheckedConversion) { auto Ty = IGF.IGM.getStorageTypeForLowered(Builtin.Types[0]->getCanonicalType()); // Report a sign error if the input parameter is a negative number, when // interpreted as signed. llvm::Value *Arg = args.claimNext(); llvm::Value *Zero = llvm::ConstantInt::get(Ty, 0); llvm::Value *OverflowFlag = IGF.Builder.CreateICmpSLT(Arg, Zero); // Return the tuple: (the result (same as input), the overflow flag). out.add(Arg); return out.add(OverflowFlag); } // We are currently emitting code for '_convertFromBuiltinIntegerLiteral', // which will call the builtin and pass it a non-compile-time-const parameter. if (Builtin.ID == BuiltinValueKind::IntToFPWithOverflow) { auto ToTy = IGF.IGM.getStorageTypeForLowered(Builtin.Types[1]->getCanonicalType()); llvm::Value *Arg = args.claimNext(); unsigned bitSize = Arg->getType()->getScalarSizeInBits(); if (bitSize > 64) { // TODO: the integer literal bit size is 2048, but we only have a 64-bit // conversion function available (on all platforms). Arg = IGF.Builder.CreateTrunc(Arg, IGF.IGM.Int64Ty); } else if (bitSize < 64) { // Just for completeness. IntToFPWithOverflow is currently only used to // convert 2048 bit integer literals. Arg = IGF.Builder.CreateSExt(Arg, IGF.IGM.Int64Ty); } llvm::Value *V = IGF.Builder.CreateSIToFP(Arg, ToTy); return out.add(V); } if (Builtin.ID == BuiltinValueKind::Once || Builtin.ID == BuiltinValueKind::OnceWithContext) { // The input type is statically (Builtin.RawPointer, @convention(thin) () -> ()). llvm::Value *PredPtr = args.claimNext(); // Cast the predicate to a OnceTy pointer. PredPtr = IGF.Builder.CreateBitCast(PredPtr, IGF.IGM.OnceTy->getPointerTo()); llvm::Value *FnCode = args.claimNext(); // Get the context if any. llvm::Value *Context; if (Builtin.ID == BuiltinValueKind::OnceWithContext) { Context = args.claimNext(); } else { Context = llvm::UndefValue::get(IGF.IGM.Int8PtrTy); } // If we know the platform runtime's "done" value, emit the check inline. llvm::BasicBlock *doneBB = nullptr; if (auto ExpectedPred = IGF.IGM.TargetInfo.OnceDonePredicateValue) { auto PredValue = IGF.Builder.CreateLoad(PredPtr, IGF.IGM.getPointerAlignment()); auto ExpectedPredValue = llvm::ConstantInt::getSigned(IGF.IGM.OnceTy, *ExpectedPred); auto PredIsDone = IGF.Builder.CreateICmpEQ(PredValue, ExpectedPredValue); auto notDoneBB = IGF.createBasicBlock("once_not_done"); doneBB = IGF.createBasicBlock("once_done"); IGF.Builder.CreateCondBr(PredIsDone, doneBB, notDoneBB); IGF.Builder.emitBlock(notDoneBB); } // Emit the runtime "once" call. auto call = IGF.Builder.CreateCall(IGF.IGM.getOnceFn(), {PredPtr, FnCode, Context}); call->setCallingConv(IGF.IGM.DefaultCC); // If we emitted the "done" check inline, join the branches. if (auto ExpectedPred = IGF.IGM.TargetInfo.OnceDonePredicateValue) { IGF.Builder.CreateBr(doneBB); IGF.Builder.emitBlock(doneBB); // We can assume the once predicate is in the "done" state now. auto PredValue = IGF.Builder.CreateLoad(PredPtr, IGF.IGM.getPointerAlignment()); auto ExpectedPredValue = llvm::ConstantInt::getSigned(IGF.IGM.OnceTy, *ExpectedPred); auto PredIsDone = IGF.Builder.CreateICmpEQ(PredValue, ExpectedPredValue); IGF.Builder.CreateAssumption(PredIsDone); } // No return value. return; } if (Builtin.ID == BuiltinValueKind::AssertConf) { // Replace the call to assert_configuration by the Debug configuration // value. // TODO: assert(IGF.IGM.getOptions().AssertConfig == // SILOptions::DisableReplacement); // Make sure this only happens in a mode where we build a library dylib. llvm::Value *DebugAssert = IGF.Builder.getInt32(SILOptions::Debug); out.add(DebugAssert); return; } if (Builtin.ID == BuiltinValueKind::DestroyArray) { // The input type is (T.Type, Builtin.RawPointer, Builtin.Word). /* metatype (which may be thin) */ if (args.size() == 3) args.claimNext(); llvm::Value *ptr = args.claimNext(); llvm::Value *count = args.claimNext(); auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM, substitutions[0].getReplacement()); ptr = IGF.Builder.CreateBitCast(ptr, valueTy.second.getStorageType()->getPointerTo()); Address array = valueTy.second.getAddressForPointer(ptr); valueTy.second.destroyArray(IGF, array, count, valueTy.first); return; } if (Builtin.ID == BuiltinValueKind::CopyArray || Builtin.ID == BuiltinValueKind::TakeArrayNoAlias || Builtin.ID == BuiltinValueKind::TakeArrayFrontToBack || Builtin.ID == BuiltinValueKind::TakeArrayBackToFront || Builtin.ID == BuiltinValueKind::AssignCopyArrayNoAlias || Builtin.ID == BuiltinValueKind::AssignCopyArrayFrontToBack || Builtin.ID == BuiltinValueKind::AssignCopyArrayBackToFront || Builtin.ID == BuiltinValueKind::AssignTakeArray) { // The input type is (T.Type, Builtin.RawPointer, Builtin.RawPointer, Builtin.Word). /* metatype (which may be thin) */ if (args.size() == 4) args.claimNext(); llvm::Value *dest = args.claimNext(); llvm::Value *src = args.claimNext(); llvm::Value *count = args.claimNext(); auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM, substitutions[0].getReplacement()); dest = IGF.Builder.CreateBitCast(dest, valueTy.second.getStorageType()->getPointerTo()); src = IGF.Builder.CreateBitCast(src, valueTy.second.getStorageType()->getPointerTo()); Address destArray = valueTy.second.getAddressForPointer(dest); Address srcArray = valueTy.second.getAddressForPointer(src); switch (Builtin.ID) { case BuiltinValueKind::CopyArray: valueTy.second.initializeArrayWithCopy(IGF, destArray, srcArray, count, valueTy.first); break; case BuiltinValueKind::TakeArrayNoAlias: valueTy.second.initializeArrayWithTakeNoAlias(IGF, destArray, srcArray, count, valueTy.first); break; case BuiltinValueKind::TakeArrayFrontToBack: valueTy.second.initializeArrayWithTakeFrontToBack(IGF, destArray, srcArray, count, valueTy.first); break; case BuiltinValueKind::TakeArrayBackToFront: valueTy.second.initializeArrayWithTakeBackToFront(IGF, destArray, srcArray, count, valueTy.first); break; case BuiltinValueKind::AssignCopyArrayNoAlias: valueTy.second.assignArrayWithCopyNoAlias(IGF, destArray, srcArray, count, valueTy.first); break; case BuiltinValueKind::AssignCopyArrayFrontToBack: valueTy.second.assignArrayWithCopyFrontToBack(IGF, destArray, srcArray, count, valueTy.first); break; case BuiltinValueKind::AssignCopyArrayBackToFront: valueTy.second.assignArrayWithCopyBackToFront(IGF, destArray, srcArray, count, valueTy.first); break; case BuiltinValueKind::AssignTakeArray: valueTy.second.assignArrayWithTake(IGF, destArray, srcArray, count, valueTy.first); break; default: llvm_unreachable("out of sync with if condition"); } return; } if (Builtin.ID == BuiltinValueKind::CondUnreachable) { // conditionallyUnreachable is a no-op by itself. Since it's noreturn, there // should be a true unreachable terminator right after. return; } if (Builtin.ID == BuiltinValueKind::ZeroInitializer) { // Build a zero initializer of the result type. auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM, substitutions[0].getReplacement()); auto schema = valueTy.second.getSchema(); for (auto &elt : schema) { out.add(llvm::Constant::getNullValue(elt.getScalarType())); } return; } if (Builtin.ID == BuiltinValueKind::GetObjCTypeEncoding) { (void)args.claimAll(); Type valueTy = substitutions[0].getReplacement(); // Get the type encoding for the associated clang type. auto clangTy = IGF.IGM.getClangType(valueTy->getCanonicalType()); std::string encoding; IGF.IGM.getClangASTContext().getObjCEncodingForType(clangTy, encoding); auto globalString = IGF.IGM.getAddrOfGlobalString(encoding); out.add(globalString); return; } if (Builtin.ID == BuiltinValueKind::TSanInoutAccess) { auto address = args.claimNext(); IGF.emitTSanInoutAccessCall(address); return; } if (Builtin.ID == BuiltinValueKind::Swift3ImplicitObjCEntrypoint) { llvm::Value *entrypointArgs[7]; auto argIter = IGF.CurFn->arg_begin(); // self entrypointArgs[0] = &*argIter++; if (entrypointArgs[0]->getType() != IGF.IGM.ObjCPtrTy) entrypointArgs[0] = IGF.Builder.CreateBitCast(entrypointArgs[0], IGF.IGM.ObjCPtrTy); // _cmd entrypointArgs[1] = &*argIter; if (entrypointArgs[1]->getType() != IGF.IGM.ObjCSELTy) entrypointArgs[1] = IGF.Builder.CreateBitCast(entrypointArgs[1], IGF.IGM.ObjCSELTy); // Filename pointer entrypointArgs[2] = args.claimNext(); // Filename length entrypointArgs[3] = args.claimNext(); // Line entrypointArgs[4] = args.claimNext(); // Column entrypointArgs[5] = args.claimNext(); // Create a flag variable so that this invocation logs only once. auto flagStorageTy = llvm::ArrayType::get(IGF.IGM.Int8Ty, IGF.IGM.getAtomicBoolSize().getValue()); auto flag = new llvm::GlobalVariable(IGF.IGM.Module, flagStorageTy, /*constant*/ false, llvm::GlobalValue::PrivateLinkage, llvm::ConstantAggregateZero::get(flagStorageTy)); flag->setAlignment(IGF.IGM.getAtomicBoolAlignment().getValue()); entrypointArgs[6] = llvm::ConstantExpr::getBitCast(flag, IGF.IGM.Int8PtrTy); IGF.Builder.CreateCall(IGF.IGM.getSwift3ImplicitObjCEntrypointFn(), entrypointArgs); return; } if (Builtin.ID == BuiltinValueKind::IsSameMetatype) { auto metatypeLHS = args.claimNext(); auto metatypeRHS = args.claimNext(); (void)args.claimAll(); llvm::Value *metatypeLHSCasted = IGF.Builder.CreateBitCast(metatypeLHS, IGF.IGM.Int8PtrTy); llvm::Value *metatypeRHSCasted = IGF.Builder.CreateBitCast(metatypeRHS, IGF.IGM.Int8PtrTy); out.add(IGF.Builder.CreateICmpEQ(metatypeLHSCasted, metatypeRHSCasted)); return; } llvm_unreachable("IRGen unimplemented for this builtin!"); }