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 | |