63 changes: 45 additions & 18 deletions llvm/tools/llvm-dis/llvm-dis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "llvm/IR/Type.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DataStream.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/ManagedStatic.h"
Expand Down Expand Up @@ -59,6 +60,11 @@ static cl::opt<bool> PreserveAssemblyUseListOrder(
cl::desc("Preserve use-list order when writing LLVM assembly."),
cl::init(false), cl::Hidden);

static cl::opt<bool>
MaterializeMetadata("materialize-metadata",
cl::desc("Load module without materializing metadata, "
"then materialize only the metadata"));

namespace {

static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) {
Expand Down Expand Up @@ -132,6 +138,37 @@ static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) {
exit(1);
}

static Expected<std::unique_ptr<Module>> openInputFile(LLVMContext &Context) {
if (MaterializeMetadata) {
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
MemoryBuffer::getFileOrSTDIN(InputFilename);
if (!MBOrErr)
return errorCodeToError(MBOrErr.getError());
ErrorOr<std::unique_ptr<Module>> MOrErr =
getLazyBitcodeModule(std::move(*MBOrErr), Context,
/*ShouldLazyLoadMetadata=*/true);
if (!MOrErr)
return errorCodeToError(MOrErr.getError());
(*MOrErr)->materializeMetadata();
return std::move(*MOrErr);
} else {
std::string ErrorMessage;
std::unique_ptr<DataStreamer> Streamer =
getDataFileStreamer(InputFilename, &ErrorMessage);
if (!Streamer)
return make_error<StringError>(ErrorMessage, inconvertibleErrorCode());
std::string DisplayFilename;
if (InputFilename == "-")
DisplayFilename = "<stdin>";
else
DisplayFilename = InputFilename;
ErrorOr<std::unique_ptr<Module>> MOrErr =
getStreamedBitcodeModule(DisplayFilename, std::move(Streamer), Context);
(*MOrErr)->materializeAll();
return std::move(*MOrErr);
}
}

int main(int argc, char **argv) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal(argv[0]);
Expand All @@ -144,26 +181,16 @@ int main(int argc, char **argv) {

cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n");

std::string ErrorMessage;
std::unique_ptr<Module> M;

// Use the bitcode streaming interface
std::unique_ptr<DataStreamer> Streamer =
getDataFileStreamer(InputFilename, &ErrorMessage);
if (Streamer) {
std::string DisplayFilename;
if (InputFilename == "-")
DisplayFilename = "<stdin>";
else
DisplayFilename = InputFilename;
ErrorOr<std::unique_ptr<Module>> MOrErr =
getStreamedBitcodeModule(DisplayFilename, std::move(Streamer), Context);
M = std::move(*MOrErr);
M->materializeAll();
} else {
errs() << argv[0] << ": " << ErrorMessage << '\n';
Expected<std::unique_ptr<Module>> MOrErr = openInputFile(Context);
if (!MOrErr) {
handleAllErrors(MOrErr.takeError(), [&](ErrorInfoBase &EIB) {
errs() << argv[0] << ": ";
EIB.log(errs());
errs() << '\n';
});
return 1;
}
std::unique_ptr<Module> M = std::move(*MOrErr);

// Just use stdout. We won't actually print anything on it.
if (DontPrint)
Expand Down
20 changes: 10 additions & 10 deletions llvm/unittests/IR/MetadataTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2260,20 +2260,20 @@ TEST_F(FunctionAttachmentTest, getAll) {
TEST_F(FunctionAttachmentTest, Verifier) {
Function *F = getFunction("foo");
F->setMetadata("attach", getTuple());
F->setIsMaterializable(true);

// Confirm this has no body.
ASSERT_TRUE(F->empty());

// Functions without a body cannot have metadata attachments (they also can't
// be verified directly, so check that the module fails to verify).
EXPECT_TRUE(verifyModule(*F->getParent()));
// Confirm this is materializable.
ASSERT_TRUE(F->isMaterializable());

// Nor can materializable functions.
F->setIsMaterializable(true);
EXPECT_TRUE(verifyModule(*F->getParent()));
// Materializable functions cannot have metadata attachments.
EXPECT_TRUE(verifyFunction(*F));

// Functions with a body can.
// Function declarations can.
F->setIsMaterializable(false);
EXPECT_FALSE(verifyModule(*F->getParent()));
EXPECT_FALSE(verifyFunction(*F));

// So can definitions.
(void)new UnreachableInst(Context, BasicBlock::Create(Context, "bb", F));
EXPECT_FALSE(verifyModule(*F->getParent()));
EXPECT_FALSE(verifyFunction(*F));
Expand Down