| //===- Parser.cpp - Main dispatch module for the Parser library -----------===// | |
| // | |
| // 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 library implements the functionality defined in llvm/AsmParser/Parser.h | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/AsmParser/Parser.h" | |
| #include "llvm/ADT/SmallVector.h" | |
| #include "llvm/AsmParser/LLParser.h" | |
| #include "llvm/IR/DebugInfoMetadata.h" | |
| #include "llvm/IR/Module.h" | |
| #include "llvm/IR/ModuleSummaryIndex.h" | |
| #include "llvm/Support/MemoryBuffer.h" | |
| #include "llvm/Support/SourceMgr.h" | |
| #include <algorithm> | |
| #include <system_error> | |
| using namespace llvm; | |
| static bool parseAssemblyInto(MemoryBufferRef F, Module *M, | |
| ModuleSummaryIndex *Index, SMDiagnostic &Err, | |
| SlotMapping *Slots, bool UpgradeDebugInfo, | |
| DataLayoutCallbackTy DataLayoutCallback, | |
| AsmParserContext *ParserContext = nullptr) { | |
| SourceMgr SM; | |
| std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(F); | |
| SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); | |
| std::optional<LLVMContext> OptContext; | |
| return LLParser(F.getBuffer(), SM, Err, M, Index, | |
| M ? M->getContext() : OptContext.emplace(), Slots, | |
| ParserContext) | |
| .Run(UpgradeDebugInfo, DataLayoutCallback); | |
| } | |
| bool llvm::parseAssemblyInto(MemoryBufferRef F, Module *M, | |
| ModuleSummaryIndex *Index, SMDiagnostic &Err, | |
| SlotMapping *Slots, | |
| DataLayoutCallbackTy DataLayoutCallback, | |
| AsmParserContext *ParserContext) { | |
| return ::parseAssemblyInto(F, M, Index, Err, Slots, | |
| /*UpgradeDebugInfo*/ true, DataLayoutCallback, | |
| ParserContext); | |
| } | |
| std::unique_ptr<Module> | |
| llvm::parseAssembly(MemoryBufferRef F, SMDiagnostic &Err, LLVMContext &Context, | |
| SlotMapping *Slots, DataLayoutCallbackTy DataLayoutCallback, | |
| AsmParserContext *ParserContext) { | |
| std::unique_ptr<Module> M = | |
| std::make_unique<Module>(F.getBufferIdentifier(), Context); | |
| if (parseAssemblyInto(F, M.get(), nullptr, Err, Slots, DataLayoutCallback, | |
| ParserContext)) | |
| return nullptr; | |
| return M; | |
| } | |
| std::unique_ptr<Module> llvm::parseAssemblyFile(StringRef Filename, | |
| SMDiagnostic &Err, | |
| LLVMContext &Context, | |
| SlotMapping *Slots) { | |
| ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = | |
| MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true); | |
| if (std::error_code EC = FileOrErr.getError()) { | |
| Err = SMDiagnostic(Filename, SourceMgr::DK_Error, | |
| "Could not open input file: " + EC.message()); | |
| return nullptr; | |
| } | |
| return parseAssembly(FileOrErr.get()->getMemBufferRef(), Err, Context, Slots); | |
| } | |
| static ParsedModuleAndIndex | |
| parseAssemblyWithIndex(MemoryBufferRef F, SMDiagnostic &Err, | |
| LLVMContext &Context, SlotMapping *Slots, | |
| bool UpgradeDebugInfo, | |
| DataLayoutCallbackTy DataLayoutCallback) { | |
| std::unique_ptr<Module> M = | |
| std::make_unique<Module>(F.getBufferIdentifier(), Context); | |
| std::unique_ptr<ModuleSummaryIndex> Index = | |
| std::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/true); | |
| if (parseAssemblyInto(F, M.get(), Index.get(), Err, Slots, UpgradeDebugInfo, | |
| DataLayoutCallback)) | |
| return {nullptr, nullptr}; | |
| return {std::move(M), std::move(Index)}; | |
| } | |
| ParsedModuleAndIndex llvm::parseAssemblyWithIndex(MemoryBufferRef F, | |
| SMDiagnostic &Err, | |
| LLVMContext &Context, | |
| SlotMapping *Slots) { | |
| return ::parseAssemblyWithIndex( | |
| F, Err, Context, Slots, | |
| /*UpgradeDebugInfo*/ true, | |
| [](StringRef, StringRef) { return std::nullopt; }); | |
| } | |
| static ParsedModuleAndIndex | |
| parseAssemblyFileWithIndex(StringRef Filename, SMDiagnostic &Err, | |
| LLVMContext &Context, SlotMapping *Slots, | |
| bool UpgradeDebugInfo, | |
| DataLayoutCallbackTy DataLayoutCallback) { | |
| ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = | |
| MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true); | |
| if (std::error_code EC = FileOrErr.getError()) { | |
| Err = SMDiagnostic(Filename, SourceMgr::DK_Error, | |
| "Could not open input file: " + EC.message()); | |
| return {nullptr, nullptr}; | |
| } | |
| return parseAssemblyWithIndex(FileOrErr.get()->getMemBufferRef(), Err, | |
| Context, Slots, UpgradeDebugInfo, | |
| DataLayoutCallback); | |
| } | |
| ParsedModuleAndIndex | |
| llvm::parseAssemblyFileWithIndex(StringRef Filename, SMDiagnostic &Err, | |
| LLVMContext &Context, SlotMapping *Slots, | |
| DataLayoutCallbackTy DataLayoutCallback) { | |
| return ::parseAssemblyFileWithIndex(Filename, Err, Context, Slots, | |
| /*UpgradeDebugInfo*/ true, | |
| DataLayoutCallback); | |
| } | |
| ParsedModuleAndIndex llvm::parseAssemblyFileWithIndexNoUpgradeDebugInfo( | |
| StringRef Filename, SMDiagnostic &Err, LLVMContext &Context, | |
| SlotMapping *Slots, DataLayoutCallbackTy DataLayoutCallback) { | |
| return ::parseAssemblyFileWithIndex(Filename, Err, Context, Slots, | |
| /*UpgradeDebugInfo*/ false, | |
| DataLayoutCallback); | |
| } | |
| std::unique_ptr<Module> | |
| llvm::parseAssemblyString(StringRef AsmString, SMDiagnostic &Err, | |
| LLVMContext &Context, SlotMapping *Slots, | |
| AsmParserContext *ParserContext) { | |
| MemoryBufferRef F(AsmString, "<string>"); | |
| return parseAssembly( | |
| F, Err, Context, Slots, [](StringRef, StringRef) { return std::nullopt; }, | |
| ParserContext); | |
| } | |
| static bool parseSummaryIndexAssemblyInto(MemoryBufferRef F, | |
| ModuleSummaryIndex &Index, | |
| SMDiagnostic &Err) { | |
| SourceMgr SM; | |
| std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(F); | |
| SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); | |
| // The parser holds a reference to a context that is unused when parsing the | |
| // index, but we need to initialize it. | |
| LLVMContext unusedContext; | |
| return LLParser(F.getBuffer(), SM, Err, nullptr, &Index, unusedContext) | |
| .Run(true, [](StringRef, StringRef) { return std::nullopt; }); | |
| } | |
| std::unique_ptr<ModuleSummaryIndex> | |
| llvm::parseSummaryIndexAssembly(MemoryBufferRef F, SMDiagnostic &Err) { | |
| std::unique_ptr<ModuleSummaryIndex> Index = | |
| std::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/false); | |
| if (parseSummaryIndexAssemblyInto(F, *Index, Err)) | |
| return nullptr; | |
| return Index; | |
| } | |
| std::unique_ptr<ModuleSummaryIndex> | |
| llvm::parseSummaryIndexAssemblyFile(StringRef Filename, SMDiagnostic &Err) { | |
| ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = | |
| MemoryBuffer::getFileOrSTDIN(Filename); | |
| if (std::error_code EC = FileOrErr.getError()) { | |
| Err = SMDiagnostic(Filename, SourceMgr::DK_Error, | |
| "Could not open input file: " + EC.message()); | |
| return nullptr; | |
| } | |
| return parseSummaryIndexAssembly(FileOrErr.get()->getMemBufferRef(), Err); | |
| } | |
| std::unique_ptr<ModuleSummaryIndex> | |
| llvm::parseSummaryIndexAssemblyString(StringRef AsmString, SMDiagnostic &Err) { | |
| MemoryBufferRef F(AsmString, "<string>"); | |
| return parseSummaryIndexAssembly(F, Err); | |
| } | |
| Constant *llvm::parseConstantValue(StringRef Asm, SMDiagnostic &Err, | |
| const Module &M, const SlotMapping *Slots) { | |
| SourceMgr SM; | |
| std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Asm); | |
| SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); | |
| Constant *C; | |
| if (LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext()) | |
| .parseStandaloneConstantValue(C, Slots)) | |
| return nullptr; | |
| return C; | |
| } | |
| Type *llvm::parseType(StringRef Asm, SMDiagnostic &Err, const Module &M, | |
| const SlotMapping *Slots) { | |
| unsigned Read; | |
| Type *Ty = parseTypeAtBeginning(Asm, Read, Err, M, Slots); | |
| if (!Ty) | |
| return nullptr; | |
| if (Read != Asm.size()) { | |
| SourceMgr SM; | |
| std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Asm); | |
| SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); | |
| Err = SM.GetMessage(SMLoc::getFromPointer(Asm.begin() + Read), | |
| SourceMgr::DK_Error, "expected end of string"); | |
| return nullptr; | |
| } | |
| return Ty; | |
| } | |
| Type *llvm::parseTypeAtBeginning(StringRef Asm, unsigned &Read, | |
| SMDiagnostic &Err, const Module &M, | |
| const SlotMapping *Slots) { | |
| SourceMgr SM; | |
| std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Asm); | |
| SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); | |
| Type *Ty; | |
| if (LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext()) | |
| .parseTypeAtBeginning(Ty, Read, Slots)) | |
| return nullptr; | |
| return Ty; | |
| } | |
| DIExpression *llvm::parseDIExpressionBodyAtBeginning(StringRef Asm, | |
| unsigned &Read, | |
| SMDiagnostic &Err, | |
| const Module &M, | |
| const SlotMapping *Slots) { | |
| SourceMgr SM; | |
| std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Asm); | |
| SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); | |
| MDNode *MD; | |
| if (LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext()) | |
| .parseDIExpressionBodyAtBeginning(MD, Read, Slots)) | |
| return nullptr; | |
| return dyn_cast<DIExpression>(MD); | |
| } | |
| bool llvm::parseMetadataDefinitions(ArrayRef<StringRef> Definitions, | |
| SMDiagnostic &Err, const Module &M, | |
| SlotMapping &Slots, | |
| unsigned &ErrorDefinitionIndex) { | |
| std::string Asm; | |
| SmallVector<std::pair<size_t, size_t>> DefinitionRanges; | |
| for (StringRef Definition : Definitions) { | |
| size_t Start = Asm.size(); | |
| Asm.append(Definition); | |
| DefinitionRanges.emplace_back(Start, Asm.size()); | |
| Asm.push_back('\n'); | |
| } | |
| SourceMgr SM; | |
| std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Asm); | |
| SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); | |
| SmallVector<SMLoc> DefinitionEnds; | |
| for (auto [_, End] : DefinitionRanges) | |
| DefinitionEnds.push_back(SMLoc::getFromPointer(Asm.data() + End)); | |
| if (!LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext()) | |
| .parseMetadataDefinitions(Slots, DefinitionEnds)) | |
| return false; | |
| const char *ErrorPtr = Err.getLoc().getPointer(); | |
| size_t ErrorOffset = | |
| ErrorPtr ? std::min<size_t>(ErrorPtr - Asm.data(), Asm.size()) : 0; | |
| ErrorDefinitionIndex = DefinitionRanges.size() - 1; | |
| for (unsigned I = 0; I != DefinitionRanges.size(); ++I) { | |
| if (ErrorOffset <= DefinitionRanges[I].second) { | |
| ErrorDefinitionIndex = I; | |
| break; | |
| } | |
| } | |
| auto [Start, End] = DefinitionRanges[ErrorDefinitionIndex]; | |
| size_t DefinitionOffset = std::clamp(ErrorOffset, Start, End) - Start; | |
| SourceMgr DefinitionSM; | |
| std::unique_ptr<MemoryBuffer> DefinitionBuf = MemoryBuffer::getMemBuffer( | |
| Definitions[ErrorDefinitionIndex], "", /*RequiresNullTerminator=*/false); | |
| StringRef Definition = DefinitionBuf->getBuffer(); | |
| DefinitionSM.AddNewSourceBuffer(std::move(DefinitionBuf), SMLoc()); | |
| Err = DefinitionSM.GetMessage( | |
| SMLoc::getFromPointer(Definition.data() + DefinitionOffset), | |
| Err.getKind(), Err.getMessage()); | |
| return true; | |
| } |