351 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			351 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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/Metadata.h"
 | |
| #include "llvm/IR/Module.h"
 | |
| #include "llvm/IR/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[] = {
 | |
|     {MD_dbg, "dbg"},
 | |
|     {MD_tbaa, "tbaa"},
 | |
|     {MD_prof, "prof"},
 | |
|     {MD_fpmath, "fpmath"},
 | |
|     {MD_range, "range"},
 | |
|     {MD_tbaa_struct, "tbaa.struct"},
 | |
|     {MD_invariant_load, "invariant.load"},
 | |
|     {MD_alias_scope, "alias.scope"},
 | |
|     {MD_noalias, "noalias"},
 | |
|     {MD_nontemporal, "nontemporal"},
 | |
|     {MD_mem_parallel_loop_access, "llvm.mem.parallel_loop_access"},
 | |
|     {MD_nonnull, "nonnull"},
 | |
|     {MD_dereferenceable, "dereferenceable"},
 | |
|     {MD_dereferenceable_or_null, "dereferenceable_or_null"},
 | |
|     {MD_make_implicit, "make.implicit"},
 | |
|     {MD_unpredictable, "unpredictable"},
 | |
|     {MD_invariant_group, "invariant.group"},
 | |
|     {MD_align, "align"},
 | |
|     {MD_loop, "llvm.loop"},
 | |
|     {MD_type, "type"},
 | |
|     {MD_section_prefix, "section_prefix"},
 | |
|     {MD_absolute_symbol, "absolute_symbol"},
 | |
|     {MD_associated, "associated"},
 | |
|     {MD_callees, "callees"},
 | |
|     {MD_irr_loop, "irr_loop"},
 | |
|     {MD_access_group, "llvm.access.group"},
 | |
|     {MD_callback, "callback"},
 | |
|   };
 | |
| 
 | |
|   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;
 | |
| 
 | |
|   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::
 | |
| setInlineAsmDiagnosticHandler(InlineAsmDiagHandlerTy DiagHandler,
 | |
|                               void *DiagContext) {
 | |
|   pImpl->InlineAsmDiagHandler = DiagHandler;
 | |
|   pImpl->InlineAsmDiagContext = DiagContext;
 | |
| }
 | |
| 
 | |
| /// getInlineAsmDiagnosticHandler - Return the diagnostic handler set by
 | |
| /// setInlineAsmDiagnosticHandler.
 | |
| LLVMContext::InlineAsmDiagHandlerTy
 | |
| LLVMContext::getInlineAsmDiagnosticHandler() const {
 | |
|   return pImpl->InlineAsmDiagHandler;
 | |
| }
 | |
| 
 | |
| /// getInlineAsmDiagnosticContext - Return the diagnostic context set by
 | |
| /// setInlineAsmDiagnosticHandler.
 | |
| void *LLVMContext::getInlineAsmDiagnosticContext() const {
 | |
|   return pImpl->InlineAsmDiagContext;
 | |
| }
 | |
| 
 | |
| 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(uint64_t Threshold) {
 | |
|   pImpl->DiagnosticsHotnessThreshold = Threshold;
 | |
| }
 | |
| uint64_t LLVMContext::getDiagnosticsHotnessThreshold() const {
 | |
|   return pImpl->DiagnosticsHotnessThreshold;
 | |
| }
 | |
| 
 | |
| RemarkStreamer *LLVMContext::getRemarkStreamer() {
 | |
|   return pImpl->RemarkDiagStreamer.get();
 | |
| }
 | |
| const RemarkStreamer *LLVMContext::getRemarkStreamer() const {
 | |
|   return const_cast<LLVMContext *>(this)->getRemarkStreamer();
 | |
| }
 | |
| void LLVMContext::setRemarkStreamer(
 | |
|     std::unique_ptr<RemarkStreamer> RemarkStreamer) {
 | |
|   pImpl->RemarkDiagStreamer = 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 (RemarkStreamer *RS = getRemarkStreamer())
 | |
|       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(unsigned 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);
 | |
| }
 | |
| 
 | |
| 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);
 | |
| }
 |