| //===-- LLVMContext.cpp - Implement LLVMContext ---------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements LLVMContext, as a wrapper around the opaque |
| // class LLVMContextImpl. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/IR/LLVMContext.h" |
| #include "LLVMContextImpl.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/IR/DiagnosticInfo.h" |
| #include "llvm/IR/DiagnosticPrinter.h" |
| #include "llvm/IR/LLVMRemarkStreamer.h" |
| #include "llvm/IR/Metadata.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Remarks/RemarkStreamer.h" |
| #include "llvm/Support/Casting.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <cassert> |
| #include <cstdlib> |
| #include <string> |
| #include <utility> |
| |
| using namespace llvm; |
| |
| LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) { |
| // Create the fixed metadata kinds. This is done in the same order as the |
| // MD_* enum values so that they correspond. |
| std::pair<unsigned, StringRef> MDKinds[] = { |
| #define LLVM_FIXED_MD_KIND(EnumID, Name, Value) {EnumID, Name}, |
| #include "llvm/IR/FixedMetadataKinds.def" |
| #undef LLVM_FIXED_MD_KIND |
| }; |
| |
| for (auto &MDKind : MDKinds) { |
| unsigned ID = getMDKindID(MDKind.second); |
| assert(ID == MDKind.first && "metadata kind id drifted"); |
| (void)ID; |
| } |
| |
| auto *DeoptEntry = pImpl->getOrInsertBundleTag("deopt"); |
| assert(DeoptEntry->second == LLVMContext::OB_deopt && |
| "deopt operand bundle id drifted!"); |
| (void)DeoptEntry; |
| |
| auto *FuncletEntry = pImpl->getOrInsertBundleTag("funclet"); |
| assert(FuncletEntry->second == LLVMContext::OB_funclet && |
| "funclet operand bundle id drifted!"); |
| (void)FuncletEntry; |
| |
| auto *GCTransitionEntry = pImpl->getOrInsertBundleTag("gc-transition"); |
| assert(GCTransitionEntry->second == LLVMContext::OB_gc_transition && |
| "gc-transition operand bundle id drifted!"); |
| (void)GCTransitionEntry; |
| |
| auto *CFGuardTargetEntry = pImpl->getOrInsertBundleTag("cfguardtarget"); |
| assert(CFGuardTargetEntry->second == LLVMContext::OB_cfguardtarget && |
| "cfguardtarget operand bundle id drifted!"); |
| (void)CFGuardTargetEntry; |
| |
| auto *PreallocatedEntry = pImpl->getOrInsertBundleTag("preallocated"); |
| assert(PreallocatedEntry->second == LLVMContext::OB_preallocated && |
| "preallocated operand bundle id drifted!"); |
| (void)PreallocatedEntry; |
| |
| auto *GCLiveEntry = pImpl->getOrInsertBundleTag("gc-live"); |
| assert(GCLiveEntry->second == LLVMContext::OB_gc_live && |
| "gc-transition operand bundle id drifted!"); |
| (void)GCLiveEntry; |
| |
| auto *ClangAttachedCall = |
| pImpl->getOrInsertBundleTag("clang.arc.attachedcall"); |
| assert(ClangAttachedCall->second == LLVMContext::OB_clang_arc_attachedcall && |
| "clang.arc.attachedcall operand bundle id drifted!"); |
| (void)ClangAttachedCall; |
| |
| SyncScope::ID SingleThreadSSID = |
| pImpl->getOrInsertSyncScopeID("singlethread"); |
| assert(SingleThreadSSID == SyncScope::SingleThread && |
| "singlethread synchronization scope ID drifted!"); |
| (void)SingleThreadSSID; |
| |
| SyncScope::ID SystemSSID = |
| pImpl->getOrInsertSyncScopeID(""); |
| assert(SystemSSID == SyncScope::System && |
| "system synchronization scope ID drifted!"); |
| (void)SystemSSID; |
| } |
| |
| LLVMContext::~LLVMContext() { delete pImpl; } |
| |
| void LLVMContext::addModule(Module *M) { |
| pImpl->OwnedModules.insert(M); |
| } |
| |
| void LLVMContext::removeModule(Module *M) { |
| pImpl->OwnedModules.erase(M); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Recoverable Backend Errors |
| //===----------------------------------------------------------------------===// |
| |
| void LLVMContext::setDiagnosticHandlerCallBack( |
| DiagnosticHandler::DiagnosticHandlerTy DiagnosticHandler, |
| void *DiagnosticContext, bool RespectFilters) { |
| pImpl->DiagHandler->DiagHandlerCallback = DiagnosticHandler; |
| pImpl->DiagHandler->DiagnosticContext = DiagnosticContext; |
| pImpl->RespectDiagnosticFilters = RespectFilters; |
| } |
| |
| void LLVMContext::setDiagnosticHandler(std::unique_ptr<DiagnosticHandler> &&DH, |
| bool RespectFilters) { |
| pImpl->DiagHandler = std::move(DH); |
| pImpl->RespectDiagnosticFilters = RespectFilters; |
| } |
| |
| void LLVMContext::setDiagnosticsHotnessRequested(bool Requested) { |
| pImpl->DiagnosticsHotnessRequested = Requested; |
| } |
| bool LLVMContext::getDiagnosticsHotnessRequested() const { |
| return pImpl->DiagnosticsHotnessRequested; |
| } |
| |
| void LLVMContext::setDiagnosticsHotnessThreshold(Optional<uint64_t> Threshold) { |
| pImpl->DiagnosticsHotnessThreshold = Threshold; |
| } |
| |
| uint64_t LLVMContext::getDiagnosticsHotnessThreshold() const { |
| return pImpl->DiagnosticsHotnessThreshold.getValueOr(UINT64_MAX); |
| } |
| |
| bool LLVMContext::isDiagnosticsHotnessThresholdSetFromPSI() const { |
| return !pImpl->DiagnosticsHotnessThreshold.hasValue(); |
| } |
| |
| remarks::RemarkStreamer *LLVMContext::getMainRemarkStreamer() { |
| return pImpl->MainRemarkStreamer.get(); |
| } |
| const remarks::RemarkStreamer *LLVMContext::getMainRemarkStreamer() const { |
| return const_cast<LLVMContext *>(this)->getMainRemarkStreamer(); |
| } |
| void LLVMContext::setMainRemarkStreamer( |
| std::unique_ptr<remarks::RemarkStreamer> RemarkStreamer) { |
| pImpl->MainRemarkStreamer = std::move(RemarkStreamer); |
| } |
| |
| LLVMRemarkStreamer *LLVMContext::getLLVMRemarkStreamer() { |
| return pImpl->LLVMRS.get(); |
| } |
| const LLVMRemarkStreamer *LLVMContext::getLLVMRemarkStreamer() const { |
| return const_cast<LLVMContext *>(this)->getLLVMRemarkStreamer(); |
| } |
| void LLVMContext::setLLVMRemarkStreamer( |
| std::unique_ptr<LLVMRemarkStreamer> RemarkStreamer) { |
| pImpl->LLVMRS = std::move(RemarkStreamer); |
| } |
| |
| DiagnosticHandler::DiagnosticHandlerTy |
| LLVMContext::getDiagnosticHandlerCallBack() const { |
| return pImpl->DiagHandler->DiagHandlerCallback; |
| } |
| |
| void *LLVMContext::getDiagnosticContext() const { |
| return pImpl->DiagHandler->DiagnosticContext; |
| } |
| |
| void LLVMContext::setYieldCallback(YieldCallbackTy Callback, void *OpaqueHandle) |
| { |
| pImpl->YieldCallback = Callback; |
| pImpl->YieldOpaqueHandle = OpaqueHandle; |
| } |
| |
| void LLVMContext::yield() { |
| if (pImpl->YieldCallback) |
| pImpl->YieldCallback(this, pImpl->YieldOpaqueHandle); |
| } |
| |
| void LLVMContext::emitError(const Twine &ErrorStr) { |
| diagnose(DiagnosticInfoInlineAsm(ErrorStr)); |
| } |
| |
| void LLVMContext::emitError(const Instruction *I, const Twine &ErrorStr) { |
| assert (I && "Invalid instruction"); |
| diagnose(DiagnosticInfoInlineAsm(*I, ErrorStr)); |
| } |
| |
| static bool isDiagnosticEnabled(const DiagnosticInfo &DI) { |
| // Optimization remarks are selective. They need to check whether the regexp |
| // pattern, passed via one of the -pass-remarks* flags, matches the name of |
| // the pass that is emitting the diagnostic. If there is no match, ignore the |
| // diagnostic and return. |
| // |
| // Also noisy remarks are only enabled if we have hotness information to sort |
| // them. |
| if (auto *Remark = dyn_cast<DiagnosticInfoOptimizationBase>(&DI)) |
| return Remark->isEnabled() && |
| (!Remark->isVerbose() || Remark->getHotness()); |
| |
| return true; |
| } |
| |
| const char * |
| LLVMContext::getDiagnosticMessagePrefix(DiagnosticSeverity Severity) { |
| switch (Severity) { |
| case DS_Error: |
| return "error"; |
| case DS_Warning: |
| return "warning"; |
| case DS_Remark: |
| return "remark"; |
| case DS_Note: |
| return "note"; |
| } |
| llvm_unreachable("Unknown DiagnosticSeverity"); |
| } |
| |
| void LLVMContext::diagnose(const DiagnosticInfo &DI) { |
| if (auto *OptDiagBase = dyn_cast<DiagnosticInfoOptimizationBase>(&DI)) |
| if (LLVMRemarkStreamer *RS = getLLVMRemarkStreamer()) |
| RS->emit(*OptDiagBase); |
| |
| // If there is a report handler, use it. |
| if (pImpl->DiagHandler && |
| (!pImpl->RespectDiagnosticFilters || isDiagnosticEnabled(DI)) && |
| pImpl->DiagHandler->handleDiagnostics(DI)) |
| return; |
| |
| if (!isDiagnosticEnabled(DI)) |
| return; |
| |
| // Otherwise, print the message with a prefix based on the severity. |
| DiagnosticPrinterRawOStream DP(errs()); |
| errs() << getDiagnosticMessagePrefix(DI.getSeverity()) << ": "; |
| DI.print(DP); |
| errs() << "\n"; |
| if (DI.getSeverity() == DS_Error) |
| exit(1); |
| } |
| |
| void LLVMContext::emitError(uint64_t LocCookie, const Twine &ErrorStr) { |
| diagnose(DiagnosticInfoInlineAsm(LocCookie, ErrorStr)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Metadata Kind Uniquing |
| //===----------------------------------------------------------------------===// |
| |
| /// Return a unique non-zero ID for the specified metadata kind. |
| unsigned LLVMContext::getMDKindID(StringRef Name) const { |
| // If this is new, assign it its ID. |
| return pImpl->CustomMDKindNames.insert( |
| std::make_pair( |
| Name, pImpl->CustomMDKindNames.size())) |
| .first->second; |
| } |
| |
| /// getHandlerNames - Populate client-supplied smallvector using custom |
| /// metadata name and ID. |
| void LLVMContext::getMDKindNames(SmallVectorImpl<StringRef> &Names) const { |
| Names.resize(pImpl->CustomMDKindNames.size()); |
| for (StringMap<unsigned>::const_iterator I = pImpl->CustomMDKindNames.begin(), |
| E = pImpl->CustomMDKindNames.end(); I != E; ++I) |
| Names[I->second] = I->first(); |
| } |
| |
| void LLVMContext::getOperandBundleTags(SmallVectorImpl<StringRef> &Tags) const { |
| pImpl->getOperandBundleTags(Tags); |
| } |
| |
| StringMapEntry<uint32_t> * |
| LLVMContext::getOrInsertBundleTag(StringRef TagName) const { |
| return pImpl->getOrInsertBundleTag(TagName); |
| } |
| |
| uint32_t LLVMContext::getOperandBundleTagID(StringRef Tag) const { |
| return pImpl->getOperandBundleTagID(Tag); |
| } |
| |
| SyncScope::ID LLVMContext::getOrInsertSyncScopeID(StringRef SSN) { |
| return pImpl->getOrInsertSyncScopeID(SSN); |
| } |
| |
| void LLVMContext::getSyncScopeNames(SmallVectorImpl<StringRef> &SSNs) const { |
| pImpl->getSyncScopeNames(SSNs); |
| } |
| |
| void LLVMContext::setGC(const Function &Fn, std::string GCName) { |
| auto It = pImpl->GCNames.find(&Fn); |
| |
| if (It == pImpl->GCNames.end()) { |
| pImpl->GCNames.insert(std::make_pair(&Fn, std::move(GCName))); |
| return; |
| } |
| It->second = std::move(GCName); |
| } |
| |
| const std::string &LLVMContext::getGC(const Function &Fn) { |
| return pImpl->GCNames[&Fn]; |
| } |
| |
| void LLVMContext::deleteGC(const Function &Fn) { |
| pImpl->GCNames.erase(&Fn); |
| } |
| |
| bool LLVMContext::shouldDiscardValueNames() const { |
| return pImpl->DiscardValueNames; |
| } |
| |
| bool LLVMContext::isODRUniquingDebugTypes() const { return !!pImpl->DITypeMap; } |
| |
| void LLVMContext::enableDebugTypeODRUniquing() { |
| if (pImpl->DITypeMap) |
| return; |
| |
| pImpl->DITypeMap.emplace(); |
| } |
| |
| void LLVMContext::disableDebugTypeODRUniquing() { pImpl->DITypeMap.reset(); } |
| |
| void LLVMContext::setDiscardValueNames(bool Discard) { |
| pImpl->DiscardValueNames = Discard; |
| } |
| |
| OptPassGate &LLVMContext::getOptPassGate() const { |
| return pImpl->getOptPassGate(); |
| } |
| |
| void LLVMContext::setOptPassGate(OptPassGate& OPG) { |
| pImpl->setOptPassGate(OPG); |
| } |
| |
| const DiagnosticHandler *LLVMContext::getDiagHandlerPtr() const { |
| return pImpl->DiagHandler.get(); |
| } |
| |
| std::unique_ptr<DiagnosticHandler> LLVMContext::getDiagnosticHandler() { |
| return std::move(pImpl->DiagHandler); |
| } |
| |
| void LLVMContext::enableOpaquePointers() const { |
| assert(pImpl->PointerTypes.empty() && pImpl->ASPointerTypes.empty() && |
| "Must be called before creating any pointer types"); |
| pImpl->setOpaquePointers(true); |
| } |
| |
| bool LLVMContext::supportsTypedPointers() const { |
| return !pImpl->getOpaquePointers(); |
| } |