1//===- Parser.cpp - Main dispatch module for the Parser library -----------===//
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 library implements the functionality defined in llvm/AsmParser/Parser.h
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/AsmParser/Parser.h"
14#include "llvm/ADT/SmallVector.h"
15#include "llvm/AsmParser/LLParser.h"
16#include "llvm/IR/DebugInfoMetadata.h"
17#include "llvm/IR/Module.h"
18#include "llvm/IR/ModuleSummaryIndex.h"
19#include "llvm/Support/MemoryBuffer.h"
20#include "llvm/Support/SourceMgr.h"
21#include <algorithm>
22#include <system_error>
23
24using namespace llvm;
25
26static bool parseAssemblyInto(MemoryBufferRef F, Module *M,
27 ModuleSummaryIndex *Index, SMDiagnostic &Err,
28 SlotMapping *Slots, bool UpgradeDebugInfo,
29 DataLayoutCallbackTy DataLayoutCallback,
30 AsmParserContext *ParserContext = nullptr) {
31 SourceMgr SM;
32 std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Ref: F);
33 SM.AddNewSourceBuffer(F: std::move(Buf), IncludeLoc: SMLoc());
34
35 std::optional<LLVMContext> OptContext;
36 return LLParser(F.getBuffer(), SM, Err, M, Index,
37 M ? M->getContext() : OptContext.emplace(), Slots,
38 ParserContext)
39 .Run(UpgradeDebugInfo, DataLayoutCallback);
40}
41
42bool llvm::parseAssemblyInto(MemoryBufferRef F, Module *M,
43 ModuleSummaryIndex *Index, SMDiagnostic &Err,
44 SlotMapping *Slots,
45 DataLayoutCallbackTy DataLayoutCallback,
46 AsmParserContext *ParserContext) {
47 return ::parseAssemblyInto(F, M, Index, Err, Slots,
48 /*UpgradeDebugInfo*/ true, DataLayoutCallback,
49 ParserContext);
50}
51
52std::unique_ptr<Module>
53llvm::parseAssembly(MemoryBufferRef F, SMDiagnostic &Err, LLVMContext &Context,
54 SlotMapping *Slots, DataLayoutCallbackTy DataLayoutCallback,
55 AsmParserContext *ParserContext) {
56 std::unique_ptr<Module> M =
57 std::make_unique<Module>(args: F.getBufferIdentifier(), args&: Context);
58
59 if (parseAssemblyInto(F, M: M.get(), Index: nullptr, Err, Slots, DataLayoutCallback,
60 ParserContext))
61 return nullptr;
62
63 return M;
64}
65
66std::unique_ptr<Module> llvm::parseAssemblyFile(StringRef Filename,
67 SMDiagnostic &Err,
68 LLVMContext &Context,
69 SlotMapping *Slots) {
70 ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
71 MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
72 if (std::error_code EC = FileOrErr.getError()) {
73 Err = SMDiagnostic(Filename, SourceMgr::DK_Error,
74 "Could not open input file: " + EC.message());
75 return nullptr;
76 }
77
78 return parseAssembly(F: FileOrErr.get()->getMemBufferRef(), Err, Context, Slots);
79}
80
81static ParsedModuleAndIndex
82parseAssemblyWithIndex(MemoryBufferRef F, SMDiagnostic &Err,
83 LLVMContext &Context, SlotMapping *Slots,
84 bool UpgradeDebugInfo,
85 DataLayoutCallbackTy DataLayoutCallback) {
86 std::unique_ptr<Module> M =
87 std::make_unique<Module>(args: F.getBufferIdentifier(), args&: Context);
88 std::unique_ptr<ModuleSummaryIndex> Index =
89 std::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/args: true);
90
91 if (parseAssemblyInto(F, M: M.get(), Index: Index.get(), Err, Slots, UpgradeDebugInfo,
92 DataLayoutCallback))
93 return {.Mod: nullptr, .Index: nullptr};
94
95 return {.Mod: std::move(M), .Index: std::move(Index)};
96}
97
98ParsedModuleAndIndex llvm::parseAssemblyWithIndex(MemoryBufferRef F,
99 SMDiagnostic &Err,
100 LLVMContext &Context,
101 SlotMapping *Slots) {
102 return ::parseAssemblyWithIndex(
103 F, Err, Context, Slots,
104 /*UpgradeDebugInfo*/ true,
105 DataLayoutCallback: [](StringRef, StringRef) { return std::nullopt; });
106}
107
108static ParsedModuleAndIndex
109parseAssemblyFileWithIndex(StringRef Filename, SMDiagnostic &Err,
110 LLVMContext &Context, SlotMapping *Slots,
111 bool UpgradeDebugInfo,
112 DataLayoutCallbackTy DataLayoutCallback) {
113 ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
114 MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
115 if (std::error_code EC = FileOrErr.getError()) {
116 Err = SMDiagnostic(Filename, SourceMgr::DK_Error,
117 "Could not open input file: " + EC.message());
118 return {.Mod: nullptr, .Index: nullptr};
119 }
120
121 return parseAssemblyWithIndex(F: FileOrErr.get()->getMemBufferRef(), Err,
122 Context, Slots, UpgradeDebugInfo,
123 DataLayoutCallback);
124}
125
126ParsedModuleAndIndex
127llvm::parseAssemblyFileWithIndex(StringRef Filename, SMDiagnostic &Err,
128 LLVMContext &Context, SlotMapping *Slots,
129 DataLayoutCallbackTy DataLayoutCallback) {
130 return ::parseAssemblyFileWithIndex(Filename, Err, Context, Slots,
131 /*UpgradeDebugInfo*/ true,
132 DataLayoutCallback);
133}
134
135ParsedModuleAndIndex llvm::parseAssemblyFileWithIndexNoUpgradeDebugInfo(
136 StringRef Filename, SMDiagnostic &Err, LLVMContext &Context,
137 SlotMapping *Slots, DataLayoutCallbackTy DataLayoutCallback) {
138 return ::parseAssemblyFileWithIndex(Filename, Err, Context, Slots,
139 /*UpgradeDebugInfo*/ false,
140 DataLayoutCallback);
141}
142
143std::unique_ptr<Module>
144llvm::parseAssemblyString(StringRef AsmString, SMDiagnostic &Err,
145 LLVMContext &Context, SlotMapping *Slots,
146 AsmParserContext *ParserContext) {
147 MemoryBufferRef F(AsmString, "<string>");
148 return parseAssembly(
149 F, Err, Context, Slots, DataLayoutCallback: [](StringRef, StringRef) { return std::nullopt; },
150 ParserContext);
151}
152
153static bool parseSummaryIndexAssemblyInto(MemoryBufferRef F,
154 ModuleSummaryIndex &Index,
155 SMDiagnostic &Err) {
156 SourceMgr SM;
157 std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Ref: F);
158 SM.AddNewSourceBuffer(F: std::move(Buf), IncludeLoc: SMLoc());
159
160 // The parser holds a reference to a context that is unused when parsing the
161 // index, but we need to initialize it.
162 LLVMContext unusedContext;
163 return LLParser(F.getBuffer(), SM, Err, nullptr, &Index, unusedContext)
164 .Run(UpgradeDebugInfo: true, DataLayoutCallback: [](StringRef, StringRef) { return std::nullopt; });
165}
166
167std::unique_ptr<ModuleSummaryIndex>
168llvm::parseSummaryIndexAssembly(MemoryBufferRef F, SMDiagnostic &Err) {
169 std::unique_ptr<ModuleSummaryIndex> Index =
170 std::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/args: false);
171
172 if (parseSummaryIndexAssemblyInto(F, Index&: *Index, Err))
173 return nullptr;
174
175 return Index;
176}
177
178std::unique_ptr<ModuleSummaryIndex>
179llvm::parseSummaryIndexAssemblyFile(StringRef Filename, SMDiagnostic &Err) {
180 ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
181 MemoryBuffer::getFileOrSTDIN(Filename);
182 if (std::error_code EC = FileOrErr.getError()) {
183 Err = SMDiagnostic(Filename, SourceMgr::DK_Error,
184 "Could not open input file: " + EC.message());
185 return nullptr;
186 }
187
188 return parseSummaryIndexAssembly(F: FileOrErr.get()->getMemBufferRef(), Err);
189}
190
191std::unique_ptr<ModuleSummaryIndex>
192llvm::parseSummaryIndexAssemblyString(StringRef AsmString, SMDiagnostic &Err) {
193 MemoryBufferRef F(AsmString, "<string>");
194 return parseSummaryIndexAssembly(F, Err);
195}
196
197Constant *llvm::parseConstantValue(StringRef Asm, SMDiagnostic &Err,
198 const Module &M, const SlotMapping *Slots) {
199 SourceMgr SM;
200 std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(InputData: Asm);
201 SM.AddNewSourceBuffer(F: std::move(Buf), IncludeLoc: SMLoc());
202 Constant *C;
203 if (LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext())
204 .parseStandaloneConstantValue(C, Slots))
205 return nullptr;
206 return C;
207}
208
209Type *llvm::parseType(StringRef Asm, SMDiagnostic &Err, const Module &M,
210 const SlotMapping *Slots) {
211 unsigned Read;
212 Type *Ty = parseTypeAtBeginning(Asm, Read, Err, M, Slots);
213 if (!Ty)
214 return nullptr;
215 if (Read != Asm.size()) {
216 SourceMgr SM;
217 std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(InputData: Asm);
218 SM.AddNewSourceBuffer(F: std::move(Buf), IncludeLoc: SMLoc());
219 Err = SM.GetMessage(Loc: SMLoc::getFromPointer(Ptr: Asm.begin() + Read),
220 Kind: SourceMgr::DK_Error, Msg: "expected end of string");
221 return nullptr;
222 }
223 return Ty;
224}
225Type *llvm::parseTypeAtBeginning(StringRef Asm, unsigned &Read,
226 SMDiagnostic &Err, const Module &M,
227 const SlotMapping *Slots) {
228 SourceMgr SM;
229 std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(InputData: Asm);
230 SM.AddNewSourceBuffer(F: std::move(Buf), IncludeLoc: SMLoc());
231 Type *Ty;
232 if (LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext())
233 .parseTypeAtBeginning(Ty, Read, Slots))
234 return nullptr;
235 return Ty;
236}
237
238DIExpression *llvm::parseDIExpressionBodyAtBeginning(StringRef Asm,
239 unsigned &Read,
240 SMDiagnostic &Err,
241 const Module &M,
242 const SlotMapping *Slots) {
243 SourceMgr SM;
244 std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(InputData: Asm);
245 SM.AddNewSourceBuffer(F: std::move(Buf), IncludeLoc: SMLoc());
246 MDNode *MD;
247 if (LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext())
248 .parseDIExpressionBodyAtBeginning(Result&: MD, Read, Slots))
249 return nullptr;
250 return dyn_cast<DIExpression>(Val: MD);
251}
252
253bool llvm::parseMetadataDefinitions(ArrayRef<StringRef> Definitions,
254 SMDiagnostic &Err, const Module &M,
255 SlotMapping &Slots,
256 unsigned &ErrorDefinitionIndex) {
257 std::string Asm;
258 SmallVector<std::pair<size_t, size_t>> DefinitionRanges;
259 for (StringRef Definition : Definitions) {
260 size_t Start = Asm.size();
261 Asm.append(svt: Definition);
262 DefinitionRanges.emplace_back(Args&: Start, Args: Asm.size());
263 Asm.push_back(c: '\n');
264 }
265
266 SourceMgr SM;
267 std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(InputData: Asm);
268 SM.AddNewSourceBuffer(F: std::move(Buf), IncludeLoc: SMLoc());
269 SmallVector<SMLoc> DefinitionEnds;
270 for (auto [_, End] : DefinitionRanges)
271 DefinitionEnds.push_back(Elt: SMLoc::getFromPointer(Ptr: Asm.data() + End));
272 if (!LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext())
273 .parseMetadataDefinitions(Slots, DefinitionEnds))
274 return false;
275
276 const char *ErrorPtr = Err.getLoc().getPointer();
277 size_t ErrorOffset =
278 ErrorPtr ? std::min<size_t>(a: ErrorPtr - Asm.data(), b: Asm.size()) : 0;
279 ErrorDefinitionIndex = DefinitionRanges.size() - 1;
280 for (unsigned I = 0; I != DefinitionRanges.size(); ++I) {
281 if (ErrorOffset <= DefinitionRanges[I].second) {
282 ErrorDefinitionIndex = I;
283 break;
284 }
285 }
286
287 auto [Start, End] = DefinitionRanges[ErrorDefinitionIndex];
288 size_t DefinitionOffset = std::clamp(val: ErrorOffset, lo: Start, hi: End) - Start;
289 SourceMgr DefinitionSM;
290 std::unique_ptr<MemoryBuffer> DefinitionBuf = MemoryBuffer::getMemBuffer(
291 InputData: Definitions[ErrorDefinitionIndex], BufferName: "", /*RequiresNullTerminator=*/false);
292 StringRef Definition = DefinitionBuf->getBuffer();
293 DefinitionSM.AddNewSourceBuffer(F: std::move(DefinitionBuf), IncludeLoc: SMLoc());
294 Err = DefinitionSM.GetMessage(
295 Loc: SMLoc::getFromPointer(Ptr: Definition.data() + DefinitionOffset),
296 Kind: Err.getKind(), Msg: Err.getMessage());
297 return true;
298}
299