| 1 | //===-- LLVMContext.cpp - Implement LLVMContext ---------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file implements LLVMContext, as a wrapper around the opaque |
| 10 | // class LLVMContextImpl. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "llvm/IR/LLVMContext.h" |
| 15 | #include "LLVMContextImpl.h" |
| 16 | #include "llvm/ADT/SmallVector.h" |
| 17 | #include "llvm/ADT/StringMap.h" |
| 18 | #include "llvm/ADT/StringRef.h" |
| 19 | #include "llvm/ADT/Twine.h" |
| 20 | #include "llvm/IR/DiagnosticInfo.h" |
| 21 | #include "llvm/IR/DiagnosticPrinter.h" |
| 22 | #include "llvm/IR/LLVMRemarkStreamer.h" |
| 23 | #include "llvm/Remarks/RemarkStreamer.h" |
| 24 | #include "llvm/Support/Casting.h" |
| 25 | #include "llvm/Support/ErrorHandling.h" |
| 26 | #include "llvm/Support/raw_ostream.h" |
| 27 | #include <cassert> |
| 28 | #include <cstdlib> |
| 29 | #include <string> |
| 30 | #include <utility> |
| 31 | |
| 32 | using namespace llvm; |
| 33 | |
| 34 | static StringRef knownBundleName(unsigned BundleTagID) { |
| 35 | switch (BundleTagID) { |
| 36 | case LLVMContext::OB_deopt: |
| 37 | return "deopt" ; |
| 38 | case LLVMContext::OB_funclet: |
| 39 | return "funclet" ; |
| 40 | case LLVMContext::OB_gc_transition: |
| 41 | return "gc-transition" ; |
| 42 | case LLVMContext::OB_cfguardtarget: |
| 43 | return "cfguardtarget" ; |
| 44 | case LLVMContext::OB_preallocated: |
| 45 | return "preallocated" ; |
| 46 | case LLVMContext::OB_gc_live: |
| 47 | return "gc-live" ; |
| 48 | case LLVMContext::OB_clang_arc_attachedcall: |
| 49 | return "clang.arc.attachedcall" ; |
| 50 | case LLVMContext::OB_ptrauth: |
| 51 | return "ptrauth" ; |
| 52 | case LLVMContext::OB_kcfi: |
| 53 | return "kcfi" ; |
| 54 | case LLVMContext::OB_convergencectrl: |
| 55 | return "convergencectrl" ; |
| 56 | default: |
| 57 | llvm_unreachable("unknown bundle id" ); |
| 58 | } |
| 59 | |
| 60 | llvm_unreachable("covered switch" ); |
| 61 | } |
| 62 | |
| 63 | LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) { |
| 64 | // Create the fixed metadata kinds. This is done in the same order as the |
| 65 | // MD_* enum values so that they correspond. |
| 66 | std::pair<unsigned, StringRef> MDKinds[] = { |
| 67 | #define LLVM_FIXED_MD_KIND(EnumID, Name, Value) {EnumID, Name}, |
| 68 | #include "llvm/IR/FixedMetadataKinds.def" |
| 69 | #undef LLVM_FIXED_MD_KIND |
| 70 | }; |
| 71 | |
| 72 | for (auto &MDKind : MDKinds) { |
| 73 | unsigned ID = getMDKindID(Name: MDKind.second); |
| 74 | assert(ID == MDKind.first && "metadata kind id drifted" ); |
| 75 | (void)ID; |
| 76 | } |
| 77 | |
| 78 | for (unsigned BundleTagID = LLVMContext::OB_deopt; |
| 79 | BundleTagID <= LLVMContext::OB_convergencectrl; ++BundleTagID) { |
| 80 | [[maybe_unused]] const auto *Entry = |
| 81 | pImpl->getOrInsertBundleTag(Tag: knownBundleName(BundleTagID)); |
| 82 | assert(Entry->second == BundleTagID && "operand bundle id drifted!" ); |
| 83 | } |
| 84 | |
| 85 | SyncScope::ID SingleThreadSSID = |
| 86 | pImpl->getOrInsertSyncScopeID(SSN: "singlethread" ); |
| 87 | assert(SingleThreadSSID == SyncScope::SingleThread && |
| 88 | "singlethread synchronization scope ID drifted!" ); |
| 89 | (void)SingleThreadSSID; |
| 90 | |
| 91 | SyncScope::ID SystemSSID = |
| 92 | pImpl->getOrInsertSyncScopeID(SSN: "" ); |
| 93 | assert(SystemSSID == SyncScope::System && |
| 94 | "system synchronization scope ID drifted!" ); |
| 95 | (void)SystemSSID; |
| 96 | } |
| 97 | |
| 98 | LLVMContext::~LLVMContext() { delete pImpl; } |
| 99 | |
| 100 | void LLVMContext::addModule(Module *M) { |
| 101 | pImpl->OwnedModules.insert(Ptr: M); |
| 102 | } |
| 103 | |
| 104 | void LLVMContext::removeModule(Module *M) { |
| 105 | pImpl->OwnedModules.erase(Ptr: M); |
| 106 | pImpl->MachineFunctionNums.erase(Val: M); |
| 107 | } |
| 108 | |
| 109 | unsigned LLVMContext::generateMachineFunctionNum(Function &F) { |
| 110 | Module *M = F.getParent(); |
| 111 | assert(pImpl->OwnedModules.contains(M) && "Unexpected module!" ); |
| 112 | return pImpl->MachineFunctionNums[M]++; |
| 113 | } |
| 114 | |
| 115 | //===----------------------------------------------------------------------===// |
| 116 | // Recoverable Backend Errors |
| 117 | //===----------------------------------------------------------------------===// |
| 118 | |
| 119 | void LLVMContext::setDiagnosticHandlerCallBack( |
| 120 | DiagnosticHandler::DiagnosticHandlerTy DiagnosticHandler, |
| 121 | void *DiagnosticContext, bool RespectFilters) { |
| 122 | pImpl->DiagHandler->DiagHandlerCallback = DiagnosticHandler; |
| 123 | pImpl->DiagHandler->DiagnosticContext = DiagnosticContext; |
| 124 | pImpl->RespectDiagnosticFilters = RespectFilters; |
| 125 | } |
| 126 | |
| 127 | void LLVMContext::setDiagnosticHandler(std::unique_ptr<DiagnosticHandler> &&DH, |
| 128 | bool RespectFilters) { |
| 129 | pImpl->DiagHandler = std::move(DH); |
| 130 | pImpl->RespectDiagnosticFilters = RespectFilters; |
| 131 | } |
| 132 | |
| 133 | void LLVMContext::setDiagnosticsHotnessRequested(bool Requested) { |
| 134 | pImpl->DiagnosticsHotnessRequested = Requested; |
| 135 | } |
| 136 | bool LLVMContext::getDiagnosticsHotnessRequested() const { |
| 137 | return pImpl->DiagnosticsHotnessRequested; |
| 138 | } |
| 139 | |
| 140 | void LLVMContext::setDiagnosticsHotnessThreshold(std::optional<uint64_t> Threshold) { |
| 141 | pImpl->DiagnosticsHotnessThreshold = Threshold; |
| 142 | } |
| 143 | void LLVMContext::setMisExpectWarningRequested(bool Requested) { |
| 144 | pImpl->MisExpectWarningRequested = Requested; |
| 145 | } |
| 146 | bool LLVMContext::getMisExpectWarningRequested() const { |
| 147 | return pImpl->MisExpectWarningRequested; |
| 148 | } |
| 149 | uint64_t LLVMContext::getDiagnosticsHotnessThreshold() const { |
| 150 | return pImpl->DiagnosticsHotnessThreshold.value_or(UINT64_MAX); |
| 151 | } |
| 152 | void LLVMContext::setDiagnosticsMisExpectTolerance( |
| 153 | std::optional<uint32_t> Tolerance) { |
| 154 | pImpl->DiagnosticsMisExpectTolerance = Tolerance; |
| 155 | } |
| 156 | uint32_t LLVMContext::getDiagnosticsMisExpectTolerance() const { |
| 157 | return pImpl->DiagnosticsMisExpectTolerance.value_or(u: 0); |
| 158 | } |
| 159 | |
| 160 | bool LLVMContext::isDiagnosticsHotnessThresholdSetFromPSI() const { |
| 161 | return !pImpl->DiagnosticsHotnessThreshold.has_value(); |
| 162 | } |
| 163 | |
| 164 | remarks::RemarkStreamer *LLVMContext::getMainRemarkStreamer() { |
| 165 | return pImpl->MainRemarkStreamer.get(); |
| 166 | } |
| 167 | const remarks::RemarkStreamer *LLVMContext::getMainRemarkStreamer() const { |
| 168 | return const_cast<LLVMContext *>(this)->getMainRemarkStreamer(); |
| 169 | } |
| 170 | void LLVMContext::setMainRemarkStreamer( |
| 171 | std::unique_ptr<remarks::RemarkStreamer> ) { |
| 172 | pImpl->MainRemarkStreamer = std::move(RemarkStreamer); |
| 173 | } |
| 174 | |
| 175 | LLVMRemarkStreamer *LLVMContext::() { |
| 176 | return pImpl->LLVMRS.get(); |
| 177 | } |
| 178 | const LLVMRemarkStreamer *LLVMContext::() const { |
| 179 | return const_cast<LLVMContext *>(this)->getLLVMRemarkStreamer(); |
| 180 | } |
| 181 | void LLVMContext::( |
| 182 | std::unique_ptr<LLVMRemarkStreamer> ) { |
| 183 | pImpl->LLVMRS = std::move(RemarkStreamer); |
| 184 | } |
| 185 | |
| 186 | DiagnosticHandler::DiagnosticHandlerTy |
| 187 | LLVMContext::getDiagnosticHandlerCallBack() const { |
| 188 | return pImpl->DiagHandler->DiagHandlerCallback; |
| 189 | } |
| 190 | |
| 191 | void *LLVMContext::getDiagnosticContext() const { |
| 192 | return pImpl->DiagHandler->DiagnosticContext; |
| 193 | } |
| 194 | |
| 195 | void LLVMContext::setYieldCallback(YieldCallbackTy Callback, void *OpaqueHandle) |
| 196 | { |
| 197 | pImpl->YieldCallback = Callback; |
| 198 | pImpl->YieldOpaqueHandle = OpaqueHandle; |
| 199 | } |
| 200 | |
| 201 | void LLVMContext::yield() { |
| 202 | if (pImpl->YieldCallback) |
| 203 | pImpl->YieldCallback(this, pImpl->YieldOpaqueHandle); |
| 204 | } |
| 205 | |
| 206 | void LLVMContext::emitError(const Twine &ErrorStr) { |
| 207 | diagnose(DI: DiagnosticInfoGeneric(ErrorStr)); |
| 208 | } |
| 209 | |
| 210 | void LLVMContext::emitError(const Instruction *I, const Twine &ErrorStr) { |
| 211 | assert(I && "Invalid instruction" ); |
| 212 | diagnose(DI: DiagnosticInfoGeneric(I, ErrorStr)); |
| 213 | } |
| 214 | |
| 215 | static bool isDiagnosticEnabled(const DiagnosticInfo &DI) { |
| 216 | // Optimization remarks are selective. They need to check whether the regexp |
| 217 | // pattern, passed via one of the -pass-remarks* flags, matches the name of |
| 218 | // the pass that is emitting the diagnostic. If there is no match, ignore the |
| 219 | // diagnostic and return. |
| 220 | // |
| 221 | // Also noisy remarks are only enabled if we have hotness information to sort |
| 222 | // them. |
| 223 | if (auto * = dyn_cast<DiagnosticInfoOptimizationBase>(Val: &DI)) |
| 224 | return Remark->isEnabled() && |
| 225 | (!Remark->isVerbose() || Remark->getHotness()); |
| 226 | |
| 227 | return true; |
| 228 | } |
| 229 | |
| 230 | const char * |
| 231 | LLVMContext::getDiagnosticMessagePrefix(DiagnosticSeverity Severity) { |
| 232 | switch (Severity) { |
| 233 | case DS_Error: |
| 234 | return "error" ; |
| 235 | case DS_Warning: |
| 236 | return "warning" ; |
| 237 | case DS_Remark: |
| 238 | return "remark" ; |
| 239 | case DS_Note: |
| 240 | return "note" ; |
| 241 | } |
| 242 | llvm_unreachable("Unknown DiagnosticSeverity" ); |
| 243 | } |
| 244 | |
| 245 | void LLVMContext::diagnose(const DiagnosticInfo &DI) { |
| 246 | if (auto *OptDiagBase = dyn_cast<DiagnosticInfoOptimizationBase>(Val: &DI)) |
| 247 | if (LLVMRemarkStreamer *RS = getLLVMRemarkStreamer()) |
| 248 | RS->emit(Diag: *OptDiagBase); |
| 249 | |
| 250 | // If there is a report handler, use it. |
| 251 | if (pImpl->DiagHandler) { |
| 252 | if (DI.getSeverity() == DS_Error) |
| 253 | pImpl->DiagHandler->HasErrors = true; |
| 254 | if ((!pImpl->RespectDiagnosticFilters || isDiagnosticEnabled(DI)) && |
| 255 | pImpl->DiagHandler->handleDiagnostics(DI)) |
| 256 | return; |
| 257 | } |
| 258 | |
| 259 | if (!isDiagnosticEnabled(DI)) |
| 260 | return; |
| 261 | |
| 262 | // Otherwise, print the message with a prefix based on the severity. |
| 263 | DiagnosticPrinterRawOStream DP(errs()); |
| 264 | errs() << getDiagnosticMessagePrefix(Severity: DI.getSeverity()) << ": " ; |
| 265 | DI.print(DP); |
| 266 | errs() << "\n" ; |
| 267 | if (DI.getSeverity() == DS_Error) |
| 268 | exit(status: 1); |
| 269 | } |
| 270 | |
| 271 | //===----------------------------------------------------------------------===// |
| 272 | // Metadata Kind Uniquing |
| 273 | //===----------------------------------------------------------------------===// |
| 274 | |
| 275 | /// Return a unique non-zero ID for the specified metadata kind. |
| 276 | unsigned LLVMContext::getMDKindID(StringRef Name) const { |
| 277 | // If this is new, assign it its ID. |
| 278 | return pImpl->CustomMDKindNames.insert( |
| 279 | KV: std::make_pair( |
| 280 | x&: Name, y: pImpl->CustomMDKindNames.size())) |
| 281 | .first->second; |
| 282 | } |
| 283 | |
| 284 | /// getHandlerNames - Populate client-supplied smallvector using custom |
| 285 | /// metadata name and ID. |
| 286 | void LLVMContext::getMDKindNames(SmallVectorImpl<StringRef> &Names) const { |
| 287 | Names.resize(N: pImpl->CustomMDKindNames.size()); |
| 288 | for (StringMap<unsigned>::const_iterator I = pImpl->CustomMDKindNames.begin(), |
| 289 | E = pImpl->CustomMDKindNames.end(); I != E; ++I) |
| 290 | Names[I->second] = I->first(); |
| 291 | } |
| 292 | |
| 293 | void LLVMContext::getOperandBundleTags(SmallVectorImpl<StringRef> &Tags) const { |
| 294 | pImpl->getOperandBundleTags(Tags); |
| 295 | } |
| 296 | |
| 297 | StringMapEntry<uint32_t> * |
| 298 | LLVMContext::getOrInsertBundleTag(StringRef TagName) const { |
| 299 | return pImpl->getOrInsertBundleTag(Tag: TagName); |
| 300 | } |
| 301 | |
| 302 | uint32_t LLVMContext::getOperandBundleTagID(StringRef Tag) const { |
| 303 | return pImpl->getOperandBundleTagID(Tag); |
| 304 | } |
| 305 | |
| 306 | SyncScope::ID LLVMContext::getOrInsertSyncScopeID(StringRef SSN) { |
| 307 | return pImpl->getOrInsertSyncScopeID(SSN); |
| 308 | } |
| 309 | |
| 310 | void LLVMContext::getSyncScopeNames(SmallVectorImpl<StringRef> &SSNs) const { |
| 311 | pImpl->getSyncScopeNames(SSNs); |
| 312 | } |
| 313 | |
| 314 | std::optional<StringRef> LLVMContext::getSyncScopeName(SyncScope::ID Id) const { |
| 315 | return pImpl->getSyncScopeName(Id); |
| 316 | } |
| 317 | |
| 318 | void LLVMContext::setGC(const Function &Fn, std::string GCName) { |
| 319 | pImpl->GCNames[&Fn] = std::move(GCName); |
| 320 | } |
| 321 | |
| 322 | const std::string &LLVMContext::getGC(const Function &Fn) { |
| 323 | return pImpl->GCNames[&Fn]; |
| 324 | } |
| 325 | |
| 326 | void LLVMContext::deleteGC(const Function &Fn) { |
| 327 | pImpl->GCNames.erase(Val: &Fn); |
| 328 | } |
| 329 | |
| 330 | bool LLVMContext::shouldDiscardValueNames() const { |
| 331 | return pImpl->DiscardValueNames; |
| 332 | } |
| 333 | |
| 334 | bool LLVMContext::isODRUniquingDebugTypes() const { return !!pImpl->DITypeMap; } |
| 335 | |
| 336 | void LLVMContext::enableDebugTypeODRUniquing() { |
| 337 | if (pImpl->DITypeMap) |
| 338 | return; |
| 339 | |
| 340 | pImpl->DITypeMap.emplace(); |
| 341 | } |
| 342 | |
| 343 | void LLVMContext::disableDebugTypeODRUniquing() { pImpl->DITypeMap.reset(); } |
| 344 | |
| 345 | void LLVMContext::setDiscardValueNames(bool Discard) { |
| 346 | pImpl->DiscardValueNames = Discard; |
| 347 | } |
| 348 | |
| 349 | OptPassGate &LLVMContext::getOptPassGate() const { |
| 350 | return pImpl->getOptPassGate(); |
| 351 | } |
| 352 | |
| 353 | void LLVMContext::setOptPassGate(OptPassGate& OPG) { |
| 354 | pImpl->setOptPassGate(OPG); |
| 355 | } |
| 356 | |
| 357 | const DiagnosticHandler *LLVMContext::getDiagHandlerPtr() const { |
| 358 | return pImpl->DiagHandler.get(); |
| 359 | } |
| 360 | |
| 361 | std::unique_ptr<DiagnosticHandler> LLVMContext::getDiagnosticHandler() { |
| 362 | return std::move(pImpl->DiagHandler); |
| 363 | } |
| 364 | |
| 365 | StringRef LLVMContext::getDefaultTargetCPU() { |
| 366 | return pImpl->DefaultTargetCPU; |
| 367 | } |
| 368 | |
| 369 | void LLVMContext::setDefaultTargetCPU(StringRef CPU) { |
| 370 | pImpl->DefaultTargetCPU = CPU; |
| 371 | } |
| 372 | |
| 373 | StringRef LLVMContext::getDefaultTargetFeatures() { |
| 374 | return pImpl->DefaultTargetFeatures; |
| 375 | } |
| 376 | |
| 377 | void LLVMContext::setDefaultTargetFeatures(StringRef Features) { |
| 378 | pImpl->DefaultTargetFeatures = Features; |
| 379 | } |
| 380 | |
| 381 | void LLVMContext::updateDILocationAtomGroupWaterline(uint64_t V) { |
| 382 | pImpl->NextAtomGroup = std::max(a: pImpl->NextAtomGroup, b: V); |
| 383 | } |
| 384 | |
| 385 | uint64_t LLVMContext::incNextDILocationAtomGroup() { |
| 386 | return pImpl->NextAtomGroup++; |
| 387 | } |
| 388 | |