class LLVMContext;
class Module;
class MemoryBuffer;
-class Metadata;
class ModuleSummaryIndex;
-class Type;
-class Value;
// Callback to override the data layout string of an imported bitcode module.
// The first argument is the target triple, the second argument the data layout
// string from the input, or a default string. It will be used if the callback
// returns std::nullopt.
-typedef std::function<std::optional<std::string>(StringRef, StringRef)>
- DataLayoutCallbackFuncTy;
-
-typedef std::function<Type *(unsigned)> GetTypeByIDTy;
-
-typedef std::function<unsigned(unsigned, unsigned)> GetContainedTypeIDTy;
-
-typedef std::function<void(Value *, unsigned, GetTypeByIDTy,
- GetContainedTypeIDTy)>
- ValueTypeCallbackTy;
-
-typedef std::function<void(Metadata **, unsigned, GetTypeByIDTy,
- GetContainedTypeIDTy)>
- MDTypeCallbackTy;
-
-// These functions are for converting Expected/Error values to
-// ErrorOr/std::error_code for compatibility with legacy clients. FIXME:
-// Remove these functions once no longer needed by the C and libLTO APIs.
-
-std::error_code errorToErrorCodeAndEmitErrors(LLVMContext &Ctx, Error Err);
-
-template <typename T>
-ErrorOr<T> expectedToErrorOrAndEmitErrors(LLVMContext &Ctx, Expected<T> Val) {
- if (!Val)
- return errorToErrorCodeAndEmitErrors(Ctx, Val.takeError());
- return std::move(*Val);
-}
-
-struct ParserCallbacks {
- std::optional<DataLayoutCallbackFuncTy> DataLayout;
- /// The ValueType callback is called for every function definition or
- /// declaration and allows accessing the type information, also behind
- /// pointers. This can be useful, when the opaque pointer upgrade cleans all
- /// type information behind pointers.
- /// The second argument to ValueTypeCallback is the type ID of the
- /// function, the two passed functions can be used to extract type
- /// information.
- std::optional<ValueTypeCallbackTy> ValueType;
- /// The MDType callback is called for every value in metadata.
- std::optional<MDTypeCallbackTy> MDType;
-
- ParserCallbacks() = default;
- explicit ParserCallbacks(DataLayoutCallbackFuncTy DataLayout)
- : DataLayout(DataLayout) {}
-};
+typedef llvm::function_ref<std::optional<std::string>(StringRef, StringRef)>
+ DataLayoutCallbackTy;
+
+ // These functions are for converting Expected/Error values to
+ // ErrorOr/std::error_code for compatibility with legacy clients. FIXME:
+ // Remove these functions once no longer needed by the C and libLTO APIs.
+
+ std::error_code errorToErrorCodeAndEmitErrors(LLVMContext &Ctx, Error Err);
+
+ template <typename T>
+ ErrorOr<T> expectedToErrorOrAndEmitErrors(LLVMContext &Ctx, Expected<T> Val) {
+ if (!Val)
+ return errorToErrorCodeAndEmitErrors(Ctx, Val.takeError());
+ return std::move(*Val);
+ }
struct BitcodeFileContents;
Expected<std::unique_ptr<Module>>
getModuleImpl(LLVMContext &Context, bool MaterializeAll,
bool ShouldLazyLoadMetadata, bool IsImporting,
- ParserCallbacks Callbacks = {});
+ DataLayoutCallbackTy DataLayoutCallback);
public:
StringRef getBuffer() const {
/// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well.
/// If IsImporting is true, this module is being parsed for ThinLTO
/// importing into another module.
- Expected<std::unique_ptr<Module>>
- getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata,
- bool IsImporting, ParserCallbacks Callbacks = {});
+ Expected<std::unique_ptr<Module>> getLazyModule(
+ LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting,
+ DataLayoutCallbackTy DataLayoutCallback = [](StringRef, StringRef) {
+ return std::nullopt;
+ });
/// Read the entire bitcode module and return it.
- Expected<std::unique_ptr<Module>>
- parseModule(LLVMContext &Context, ParserCallbacks Callbacks = {});
+ Expected<std::unique_ptr<Module>> parseModule(
+ LLVMContext &Context,
+ DataLayoutCallbackTy DataLayoutCallback = [](StringRef, StringRef) {
+ return std::nullopt;
+ });
/// Returns information about the module to be used for LTO: whether to
/// compile with ThinLTO, and whether it has a summary.
/// deserialization of function bodies. If ShouldLazyLoadMetadata is true,
/// lazily load metadata as well. If IsImporting is true, this module is
/// being parsed for ThinLTO importing into another module.
- Expected<std::unique_ptr<Module>>
- getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context,
- bool ShouldLazyLoadMetadata = false,
- bool IsImporting = false,
- ParserCallbacks Callbacks = {});
+ Expected<std::unique_ptr<Module>> getLazyBitcodeModule(
+ MemoryBufferRef Buffer, LLVMContext &Context,
+ bool ShouldLazyLoadMetadata = false, bool IsImporting = false,
+ DataLayoutCallbackTy DataLayoutCallback = [](StringRef, StringRef) {
+ return std::nullopt;
+ });
/// Like getLazyBitcodeModule, except that the module takes ownership of
/// the memory buffer if successful. If successful, this moves Buffer. On
/// being parsed for ThinLTO importing into another module.
Expected<std::unique_ptr<Module>> getOwningLazyBitcodeModule(
std::unique_ptr<MemoryBuffer> &&Buffer, LLVMContext &Context,
- bool ShouldLazyLoadMetadata = false, bool IsImporting = false,
- ParserCallbacks Callbacks = {});
+ bool ShouldLazyLoadMetadata = false, bool IsImporting = false);
/// Read the header of the specified bitcode buffer and extract just the
/// triple information. If successful, this returns a string. On error, this
Expected<std::string> getBitcodeProducerString(MemoryBufferRef Buffer);
/// Read the specified bitcode file, returning the module.
- Expected<std::unique_ptr<Module>>
- parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context,
- ParserCallbacks Callbacks = {});
+ Expected<std::unique_ptr<Module>> parseBitcodeFile(
+ MemoryBufferRef Buffer, LLVMContext &Context,
+ DataLayoutCallbackTy DataLayoutCallback = [](StringRef, StringRef) {
+ return std::nullopt;
+ });
/// Returns LTO information for the specified bitcode file.
Expected<BitcodeLTOInfo> getBitcodeLTOInfo(MemoryBufferRef Buffer);
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Bitcode/BitcodeReader.h"
#include <memory>
#include <optional>
class SMDiagnostic;
class LLVMContext;
+typedef llvm::function_ref<std::optional<std::string>(StringRef, StringRef)>
+ DataLayoutCallbackTy;
+
/// If the given MemoryBuffer holds a bitcode image, return a Module
/// for it which does lazy deserialization of function bodies. Otherwise,
/// attempt to parse it as LLVM Assembly and return a fully populated
/// for it. Otherwise, attempt to parse it as LLVM Assembly and return
/// a Module for it.
/// \param DataLayoutCallback Override datalayout in the llvm assembly.
-std::unique_ptr<Module> parseIR(MemoryBufferRef Buffer, SMDiagnostic &Err,
- LLVMContext &Context,
- ParserCallbacks Callbacks = {});
+std::unique_ptr<Module> parseIR(
+ MemoryBufferRef Buffer, SMDiagnostic &Err, LLVMContext &Context,
+ DataLayoutCallbackTy DataLayoutCallback = [](StringRef, StringRef) {
+ return std::nullopt;
+ });
/// If the given file holds a bitcode image, return a Module for it.
/// Otherwise, attempt to parse it as LLVM Assembly and return a Module
/// for it.
/// \param DataLayoutCallback Override datalayout in the llvm assembly.
-std::unique_ptr<Module> parseIRFile(StringRef Filename, SMDiagnostic &Err,
- LLVMContext &Context,
- ParserCallbacks Callbacks = {});
+std::unique_ptr<Module> parseIRFile(
+ StringRef Filename, SMDiagnostic &Err, LLVMContext &Context,
+ DataLayoutCallbackTy DataLayoutCallback = [](StringRef, StringRef) {
+ return std::nullopt;
+ });
}
#endif
std::vector<std::string> BundleTags;
SmallVector<SyncScope::ID, 8> SSIDs;
- std::optional<ValueTypeCallbackTy> ValueTypeCallback;
-
public:
BitcodeReader(BitstreamCursor Stream, StringRef Strtab,
StringRef ProducerIdentification, LLVMContext &Context);
/// Main interface to parsing a bitcode buffer.
/// \returns true if an error occurred.
- Error parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata,
- bool IsImporting, ParserCallbacks Callbacks = {});
+ Error parseBitcodeInto(
+ Module *M, bool ShouldLazyLoadMetadata, bool IsImporting,
+ DataLayoutCallbackTy DataLayoutCallback);
static uint64_t decodeSignRotatedValue(uint64_t V);
unsigned getContainedTypeID(unsigned ID, unsigned Idx = 0);
unsigned getVirtualTypeID(Type *Ty, ArrayRef<unsigned> ContainedTypeIDs = {});
- void callValueTypeCallback(Value *F, unsigned TypeID);
Expected<Value *> materializeValue(unsigned ValID, BasicBlock *InsertBB);
Expected<Constant *> getValueForInitializer(unsigned ID);
/// a corresponding error code.
Error parseAlignmentValue(uint64_t Exponent, MaybeAlign &Alignment);
Error parseAttrKind(uint64_t Code, Attribute::AttrKind *Kind);
- Error parseModule(uint64_t ResumeBit, bool ShouldLazyLoadMetadata = false,
- ParserCallbacks Callbacks = {});
+ Error parseModule(
+ uint64_t ResumeBit, bool ShouldLazyLoadMetadata = false,
+ DataLayoutCallbackTy DataLayoutCallback = [](StringRef, StringRef) {
+ return std::nullopt;
+ });
Error parseComdatRecord(ArrayRef<uint64_t> Record);
Error parseGlobalVarRecord(ArrayRef<uint64_t> Record);
return Error::success();
}
-void BitcodeReader::callValueTypeCallback(Value *F, unsigned TypeID) {
- if (ValueTypeCallback) {
- (*ValueTypeCallback)(
- F, TypeID, [this](unsigned I) { return getTypeByID(I); },
- [this](unsigned I, unsigned J) { return getContainedTypeID(I, J); });
- }
-}
-
Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
// v1: [type, callingconv, isproto, linkage, paramattr, alignment, section,
// visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat,
uint64_t RawLinkage = Record[3];
Func->setLinkage(getDecodedLinkage(RawLinkage));
Func->setAttributes(getAttributes(Record[4]));
- callValueTypeCallback(Func, FTyID);
// Upgrade any old-style byval or sret without a type by propagating the
// argument's pointee type. There should be no opaque pointers where the byval
Error BitcodeReader::parseModule(uint64_t ResumeBit,
bool ShouldLazyLoadMetadata,
- ParserCallbacks Callbacks) {
- this->ValueTypeCallback = std::move(Callbacks.ValueType);
+ DataLayoutCallbackTy DataLayoutCallback) {
if (ResumeBit) {
if (Error JumpFailed = Stream.JumpToBit(ResumeBit))
return JumpFailed;
TentativeDataLayoutStr, TheModule->getTargetTriple());
// Apply override
- if (Callbacks.DataLayout) {
- if (auto LayoutOverride = (*Callbacks.DataLayout)(
- TheModule->getTargetTriple(), TentativeDataLayoutStr))
- TentativeDataLayoutStr = *LayoutOverride;
- }
+ if (auto LayoutOverride = DataLayoutCallback(TheModule->getTargetTriple(),
+ TentativeDataLayoutStr))
+ TentativeDataLayoutStr = *LayoutOverride;
// Now the layout string is finalized in TentativeDataLayoutStr. Parse it.
Expected<DataLayout> MaybeDL = DataLayout::parse(TentativeDataLayoutStr);
}
Record.clear();
}
- this->ValueTypeCallback = std::nullopt;
return Error::success();
}
Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata,
bool IsImporting,
- ParserCallbacks Callbacks) {
+ DataLayoutCallbackTy DataLayoutCallback) {
TheModule = M;
- MetadataLoaderCallbacks MDCallbacks;
- MDCallbacks.GetTypeByID = [&](unsigned ID) { return getTypeByID(ID); };
- MDCallbacks.GetContainedTypeID = [&](unsigned I, unsigned J) {
- return getContainedTypeID(I, J);
- };
- MDCallbacks.MDType = Callbacks.MDType;
- MDLoader = MetadataLoader(Stream, *M, ValueList, IsImporting, MDCallbacks);
- return parseModule(0, ShouldLazyLoadMetadata, Callbacks);
+ MDLoader = MetadataLoader(Stream, *M, ValueList, IsImporting,
+ [&](unsigned ID) { return getTypeByID(ID); });
+ return parseModule(0, ShouldLazyLoadMetadata, DataLayoutCallback);
}
Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) {
Expected<std::unique_ptr<Module>>
BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
bool ShouldLazyLoadMetadata, bool IsImporting,
- ParserCallbacks Callbacks) {
+ DataLayoutCallbackTy DataLayoutCallback) {
BitstreamCursor Stream(Buffer);
std::string ProducerIdentification;
// Delay parsing Metadata if ShouldLazyLoadMetadata is true.
if (Error Err = R->parseBitcodeInto(M.get(), ShouldLazyLoadMetadata,
- IsImporting, Callbacks))
+ IsImporting, DataLayoutCallback))
return std::move(Err);
if (MaterializeAll) {
Expected<std::unique_ptr<Module>>
BitcodeModule::getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata,
- bool IsImporting, ParserCallbacks Callbacks) {
+ bool IsImporting,
+ DataLayoutCallbackTy DataLayoutCallback) {
return getModuleImpl(Context, false, ShouldLazyLoadMetadata, IsImporting,
- Callbacks);
+ DataLayoutCallback);
}
// Parse the specified bitcode buffer and merge the index into CombinedIndex.
Expected<std::unique_ptr<Module>>
llvm::getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context,
bool ShouldLazyLoadMetadata, bool IsImporting,
- ParserCallbacks Callbacks) {
+ DataLayoutCallbackTy DataLayoutCallback) {
Expected<BitcodeModule> BM = getSingleModule(Buffer);
if (!BM)
return BM.takeError();
return BM->getLazyModule(Context, ShouldLazyLoadMetadata, IsImporting,
- Callbacks);
+ DataLayoutCallback);
}
Expected<std::unique_ptr<Module>> llvm::getOwningLazyBitcodeModule(
std::unique_ptr<MemoryBuffer> &&Buffer, LLVMContext &Context,
- bool ShouldLazyLoadMetadata, bool IsImporting, ParserCallbacks Callbacks) {
+ bool ShouldLazyLoadMetadata, bool IsImporting) {
auto MOrErr = getLazyBitcodeModule(*Buffer, Context, ShouldLazyLoadMetadata,
- IsImporting, Callbacks);
+ IsImporting);
if (MOrErr)
(*MOrErr)->setOwnedMemoryBuffer(std::move(Buffer));
return MOrErr;
}
Expected<std::unique_ptr<Module>>
-BitcodeModule::parseModule(LLVMContext &Context, ParserCallbacks Callbacks) {
- return getModuleImpl(Context, true, false, false, Callbacks);
+BitcodeModule::parseModule(LLVMContext &Context,
+ DataLayoutCallbackTy DataLayoutCallback) {
+ return getModuleImpl(Context, true, false, false, DataLayoutCallback);
// TODO: Restore the use-lists to the in-memory state when the bitcode was
// written. We must defer until the Module has been fully materialized.
}
Expected<std::unique_ptr<Module>>
llvm::parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context,
- ParserCallbacks Callbacks) {
+ DataLayoutCallbackTy DataLayoutCallback) {
Expected<BitcodeModule> BM = getSingleModule(Buffer);
if (!BM)
return BM.takeError();
- return BM->parseModule(Context, Callbacks);
+ return BM->parseModule(Context, DataLayoutCallback);
}
Expected<std::string> llvm::getBitcodeTargetTriple(MemoryBufferRef Buffer) {
BitstreamCursor &Stream;
LLVMContext &Context;
Module &TheModule;
- MetadataLoaderCallbacks Callbacks;
+ std::function<Type *(unsigned)> getTypeByID;
/// Cursor associated with the lazy-loading of Metadata. This is the easy way
/// to keep around the right "context" (Abbrev list) to be able to jump in
upgradeCUVariables();
}
- void callMDTypeCallback(Metadata **Val, unsigned TypeID);
-
public:
MetadataLoaderImpl(BitstreamCursor &Stream, Module &TheModule,
BitcodeReaderValueList &ValueList,
- MetadataLoaderCallbacks Callbacks, bool IsImporting)
+ std::function<Type *(unsigned)> getTypeByID,
+ bool IsImporting)
: MetadataList(TheModule.getContext(), Stream.SizeInBytes()),
ValueList(ValueList), Stream(Stream), Context(TheModule.getContext()),
- TheModule(TheModule), Callbacks(std::move(Callbacks)),
+ TheModule(TheModule), getTypeByID(std::move(getTypeByID)),
IsImporting(IsImporting) {}
Error parseMetadata(bool ModuleLevel);
}
}
-void MetadataLoader::MetadataLoaderImpl::callMDTypeCallback(Metadata **Val,
- unsigned TypeID) {
- if (Callbacks.MDType) {
- (*Callbacks.MDType)(Val, TypeID, Callbacks.GetTypeByID,
- Callbacks.GetContainedTypeID);
- }
-}
-
/// Parse a METADATA_BLOCK. If ModuleLevel is true then we are parsing
/// module level metadata.
Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
}
unsigned TyID = Record[0];
- Type *Ty = Callbacks.GetTypeByID(TyID);
+ Type *Ty = getTypeByID(TyID);
if (Ty->isMetadataTy() || Ty->isVoidTy()) {
dropRecord();
break;
SmallVector<Metadata *, 8> Elts;
for (unsigned i = 0; i != Size; i += 2) {
unsigned TyID = Record[i];
- Type *Ty = Callbacks.GetTypeByID(TyID);
+ Type *Ty = getTypeByID(TyID);
if (!Ty)
return error("Invalid record");
if (Ty->isMetadataTy())
/*ConstExprInsertBB*/ nullptr);
if (!V)
return error("Invalid value reference from old metadata");
- Metadata *MD = ValueAsMetadata::get(V);
+ auto *MD = ValueAsMetadata::get(V);
assert(isa<ConstantAsMetadata>(MD) &&
"Expected non-function-local metadata");
- callMDTypeCallback(&MD, TyID);
Elts.push_back(MD);
} else
Elts.push_back(nullptr);
return error("Invalid record");
unsigned TyID = Record[0];
- Type *Ty = Callbacks.GetTypeByID(TyID);
+ Type *Ty = getTypeByID(TyID);
if (Ty->isMetadataTy() || Ty->isVoidTy())
return error("Invalid record");
if (!V)
return error("Invalid value reference from metadata");
- Metadata *MD = ValueAsMetadata::get(V);
- callMDTypeCallback(&MD, TyID);
- MetadataList.assignValue(MD, NextMetadataNo);
+ MetadataList.assignValue(ValueAsMetadata::get(V), NextMetadataNo);
NextMetadataNo++;
break;
}
MetadataLoader::MetadataLoader(BitstreamCursor &Stream, Module &TheModule,
BitcodeReaderValueList &ValueList,
bool IsImporting,
- MetadataLoaderCallbacks Callbacks)
+ std::function<Type *(unsigned)> getTypeByID)
: Pimpl(std::make_unique<MetadataLoaderImpl>(
- Stream, TheModule, ValueList, std::move(Callbacks), IsImporting)) {}
+ Stream, TheModule, ValueList, std::move(getTypeByID), IsImporting)) {}
Error MetadataLoader::parseMetadata(bool ModuleLevel) {
return Pimpl->parseMetadata(ModuleLevel);
class Type;
template <typename T> class ArrayRef;
-typedef std::function<Type *(unsigned)> GetTypeByIDTy;
-
-typedef std::function<unsigned(unsigned, unsigned)> GetContainedTypeIDTy;
-
-typedef std::function<void(Metadata **, unsigned, GetTypeByIDTy,
- GetContainedTypeIDTy)>
- MDTypeCallbackTy;
-
-struct MetadataLoaderCallbacks {
- GetTypeByIDTy GetTypeByID;
- GetContainedTypeIDTy GetContainedTypeID;
- std::optional<MDTypeCallbackTy> MDType;
-};
-
/// Helper class that handles loading Metadatas and keeping them available.
class MetadataLoader {
class MetadataLoaderImpl;
~MetadataLoader();
MetadataLoader(BitstreamCursor &Stream, Module &TheModule,
BitcodeReaderValueList &ValueList, bool IsImporting,
- MetadataLoaderCallbacks Callbacks);
+ std::function<Type *(unsigned)> getTypeByID);
MetadataLoader &operator=(MetadataLoader &&);
MetadataLoader(MetadataLoader &&);
std::unique_ptr<Module> llvm::parseIR(MemoryBufferRef Buffer, SMDiagnostic &Err,
LLVMContext &Context,
- ParserCallbacks Callbacks) {
+ DataLayoutCallbackTy DataLayoutCallback) {
NamedRegionTimer T(TimeIRParsingName, TimeIRParsingDescription,
TimeIRParsingGroupName, TimeIRParsingGroupDescription,
TimePassesIsEnabled);
if (isBitcode((const unsigned char *)Buffer.getBufferStart(),
(const unsigned char *)Buffer.getBufferEnd())) {
Expected<std::unique_ptr<Module>> ModuleOrErr =
- parseBitcodeFile(Buffer, Context, Callbacks);
+ parseBitcodeFile(Buffer, Context, DataLayoutCallback);
if (Error E = ModuleOrErr.takeError()) {
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
Err = SMDiagnostic(Buffer.getBufferIdentifier(), SourceMgr::DK_Error,
return std::move(ModuleOrErr.get());
}
- return parseAssembly(Buffer, Err, Context, nullptr,
- Callbacks.DataLayout.value_or(
- [](StringRef, StringRef) { return std::nullopt; }));
+ return parseAssembly(Buffer, Err, Context, nullptr, DataLayoutCallback);
}
-std::unique_ptr<Module> llvm::parseIRFile(StringRef Filename, SMDiagnostic &Err,
- LLVMContext &Context,
- ParserCallbacks Callbacks) {
+std::unique_ptr<Module>
+llvm::parseIRFile(StringRef Filename, SMDiagnostic &Err, LLVMContext &Context,
+ DataLayoutCallbackTy DataLayoutCallback) {
ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
if (std::error_code EC = FileOrErr.getError()) {
return nullptr;
}
- return parseIR(FileOrErr.get()->getMemBufferRef(), Err, Context, Callbacks);
+ return parseIR(FileOrErr.get()->getMemBufferRef(), Err, Context,
+ DataLayoutCallback);
}
//===----------------------------------------------------------------------===//
if (MIR)
M = MIR->parseIRModule(SetDataLayout);
} else {
- M = parseIRFile(InputFilename, Err, Context,
- ParserCallbacks(SetDataLayout));
+ M = parseIRFile(InputFilename, Err, Context, SetDataLayout);
}
if (!M) {
Err.print(argv[0], WithColor::error(errs(), argv[0]));
InputFilename, Err, Context, nullptr, SetDataLayout)
.Mod;
else
- M = parseIRFile(InputFilename, Err, Context,
- ParserCallbacks(SetDataLayout));
+ M = parseIRFile(InputFilename, Err, Context, SetDataLayout);
if (!M) {
Err.print(argv[0], errs());
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
-#include "llvm/IR/Constants.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
EXPECT_FALSE(verifyModule(*M, &dbgs()));
}
-// Helper function to convert type metadata to a string for testing
-static std::string mdToString(Metadata *MD) {
- std::string S;
- if (auto *VMD = dyn_cast<ValueAsMetadata>(MD)) {
- if (VMD->getType()->isPointerTy()) {
- S += "ptr";
- return S;
- }
- }
-
- if (auto *TMD = dyn_cast<MDTuple>(MD)) {
- S += "!{";
- for (unsigned I = 0; I < TMD->getNumOperands(); I++) {
- if (I != 0)
- S += ", ";
- S += mdToString(TMD->getOperand(I).get());
- }
- S += "}";
- } else if (auto *SMD = dyn_cast<MDString>(MD)) {
- S += "!'";
- S += SMD->getString();
- S += "'";
- } else if (auto *I = mdconst::dyn_extract<ConstantInt>(MD)) {
- S += std::to_string(I->getZExtValue());
- } else if (auto *P = mdconst::dyn_extract<PoisonValue>(MD)) {
- auto *Ty = P->getType();
- if (Ty->isIntegerTy()) {
- S += "i";
- S += std::to_string(Ty->getIntegerBitWidth());
- } else if (Ty->isStructTy()) {
- S += "%";
- S += Ty->getStructName();
- } else {
- llvm_unreachable("unhandled poison metadata");
- }
- } else {
- llvm_unreachable("unhandled metadata");
- }
- return S;
-}
-
-// Recursively look into a (pointer) type and the the type.
-// For primitive types it's a poison value of the type, for a pointer it's a
-// metadata tuple with the addrspace and the referenced type. For a function,
-// it's a tuple where the first element is the string "function", the second
-// element is the return type or the string "void" and the following elements
-// are the argument types.
-static Metadata *getTypeMetadataEntry(unsigned TypeID, LLVMContext &Context,
- GetTypeByIDTy GetTypeByID,
- GetContainedTypeIDTy GetContainedTypeID) {
- Type *Ty = GetTypeByID(TypeID);
- if (auto *FTy = dyn_cast<FunctionType>(Ty)) {
- // Save the function signature as metadata
- SmallVector<Metadata *> SignatureMD;
- SignatureMD.push_back(MDString::get(Context, "function"));
- // Return type
- if (FTy->getReturnType()->isVoidTy())
- SignatureMD.push_back(MDString::get(Context, "void"));
- else
- SignatureMD.push_back(getTypeMetadataEntry(GetContainedTypeID(TypeID, 0),
- Context, GetTypeByID,
- GetContainedTypeID));
- // Arguments
- for (unsigned I = 0; I != FTy->getNumParams(); ++I)
- SignatureMD.push_back(
- getTypeMetadataEntry(GetContainedTypeID(TypeID, I + 1), Context,
- GetTypeByID, GetContainedTypeID));
-
- return MDTuple::get(Context, SignatureMD);
- }
-
- if (!Ty->isPointerTy())
- return ConstantAsMetadata::get(PoisonValue::get(Ty));
-
- // Return !{<addrspace>, <inner>} for pointer
- SmallVector<Metadata *, 2> MD;
- MD.push_back(ConstantAsMetadata::get(ConstantInt::get(
- Type::getInt32Ty(Context), Ty->getPointerAddressSpace())));
- MD.push_back(getTypeMetadataEntry(GetContainedTypeID(TypeID, 0), Context,
- GetTypeByID, GetContainedTypeID));
- return MDTuple::get(Context, MD);
-}
-
-// Test that when reading bitcode with typed pointers and upgrading them to
-// opaque pointers, the type information of function signatures can be extracted
-// and stored in metadata.
-TEST(BitReaderTest, AccessFunctionTypeInfo) {
- SmallString<1024> Mem;
- LLVMContext WriteContext;
- writeModuleToBuffer(
- parseAssembly(
- WriteContext,
- "define void @func() {\n"
- " unreachable\n"
- "}\n"
- "declare i32 @func_header()\n"
- "declare i8* @ret_ptr()\n"
- "declare i8* @ret_and_arg_ptr(i32 addrspace(8)*)\n"
- "declare i8 addrspace(1)* @double_ptr(i32* addrspace(2)*, i32***)\n"),
- Mem);
-
- LLVMContext Context;
- Context.setOpaquePointers(true);
-
- ParserCallbacks Callbacks;
- // Supply a callback that stores the signature of a function into metadata,
- // so that the types behind pointers can be accessed.
- // Each function gets a !types metadata, which is a tuple with one element
- // for a non-void return type and every argument. For primitive types it's
- // a poison value of the type, for a pointer it's a metadata tuple with
- // the addrspace and the referenced type.
- Callbacks.ValueType = [&](Value *V, unsigned TypeID,
- GetTypeByIDTy GetTypeByID,
- GetContainedTypeIDTy GetContainedTypeID) {
- if (auto *F = dyn_cast<Function>(V)) {
- auto *MD = getTypeMetadataEntry(TypeID, F->getContext(), GetTypeByID,
- GetContainedTypeID);
- F->setMetadata("types", cast<MDNode>(MD));
- }
- };
-
- Expected<std::unique_ptr<Module>> ModuleOrErr =
- parseBitcodeFile(MemoryBufferRef(Mem.str(), "test"), Context, Callbacks);
-
- if (!ModuleOrErr)
- report_fatal_error("Could not parse bitcode module");
- std::unique_ptr<Module> M = std::move(ModuleOrErr.get());
-
- EXPECT_EQ(mdToString(M->getFunction("func")->getMetadata("types")),
- "!{!'function', !'void'}");
- EXPECT_EQ(mdToString(M->getFunction("func_header")->getMetadata("types")),
- "!{!'function', i32}");
- EXPECT_EQ(mdToString(M->getFunction("ret_ptr")->getMetadata("types")),
- "!{!'function', !{0, i8}}");
- EXPECT_EQ(mdToString(M->getFunction("ret_and_arg_ptr")->getMetadata("types")),
- "!{!'function', !{0, i8}, !{8, i32}}");
- EXPECT_EQ(mdToString(M->getFunction("double_ptr")->getMetadata("types")),
- "!{!'function', !{1, i8}, !{2, !{0, i32}}, !{0, !{0, !{0, i32}}}}");
-}
-
-// Test that when reading bitcode with typed pointers and upgrading them to
-// opaque pointers, the type information of pointers in metadata can be
-// extracted and stored in metadata.
-TEST(BitReaderTest, AccessMetadataTypeInfo) {
- SmallString<1024> Mem;
- LLVMContext WriteContext;
- writeModuleToBuffer(
- parseAssembly(WriteContext,
- "%dx.types.f32 = type { float }\n"
- "declare void @main()\n"
- "!md = !{!0}\n"
- "!md2 = !{!1}\n"
- "!0 = !{i32 2, %dx.types.f32 addrspace(1)* undef, void ()* "
- "@main, void() addrspace(3)* null}\n"
- "!1 = !{i8*(i32* addrspace(2)*) addrspace(4)* undef, "
- "i32*** undef}\n"),
- Mem);
-
- LLVMContext Context;
- Context.setOpaquePointers(true);
-
- ParserCallbacks Callbacks;
- // Supply a callback that stores types from metadata,
- // so that the types behind pointers can be accessed.
- // Non-pointer entries are ignored. Values with a pointer type are
- // replaced by a metadata tuple with {original value, type md}. We cannot
- // save the metadata outside because after conversion to opaque pointers,
- // entries are not distinguishable anymore (e.g. i32* and i8* are both
- // upgraded to ptr).
- Callbacks.MDType = [&](Metadata **Val, unsigned TypeID,
- GetTypeByIDTy GetTypeByID,
- GetContainedTypeIDTy GetContainedTypeID) {
- auto *OrigVal = cast<ValueAsMetadata>(*Val);
- if (OrigVal->getType()->isPointerTy()) {
- // Ignore function references, their signature can be saved like
- // in the test above
- if (!isa<Function>(OrigVal->getValue())) {
- SmallVector<Metadata *> Tuple;
- Tuple.push_back(OrigVal);
- Tuple.push_back(getTypeMetadataEntry(GetContainedTypeID(TypeID, 0),
- OrigVal->getContext(), GetTypeByID,
- GetContainedTypeID));
- *Val = MDTuple::get(OrigVal->getContext(), Tuple);
- }
- }
- };
-
- Expected<std::unique_ptr<Module>> ModuleOrErr =
- parseBitcodeFile(MemoryBufferRef(Mem.str(), "test"), Context, Callbacks);
-
- if (!ModuleOrErr)
- report_fatal_error("Could not parse bitcode module");
- std::unique_ptr<Module> M = std::move(ModuleOrErr.get());
-
- EXPECT_EQ(
- mdToString(M->getNamedMetadata("md")->getOperand(0)),
- "!{2, !{ptr, %dx.types.f32}, ptr, !{ptr, !{!'function', !'void'}}}");
- EXPECT_EQ(mdToString(M->getNamedMetadata("md2")->getOperand(0)),
- "!{!{ptr, !{!'function', !{0, i8}, !{2, !{0, i32}}}}, !{ptr, !{0, "
- "!{0, i32}}}}");
-}
-
} // end namespace