| //===- llvm/unittest/Bitcode/BitReaderTest.cpp - Tests for BitReader ------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #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/LLVMContext.h" | |
| #include "llvm/IR/Module.h" | |
| #include "llvm/IR/Verifier.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/Error.h" | |
| #include "llvm/Support/MemoryBuffer.h" | |
| #include "llvm/Support/SourceMgr.h" | |
| #include "gtest/gtest.h" | |
| using namespace llvm; | |
| namespace { | |
| std::unique_ptr<Module> parseAssembly(LLVMContext &Context, | |
| const char *Assembly) { | |
| SMDiagnostic Error; | |
| std::unique_ptr<Module> M = parseAssemblyString(Assembly, Error, Context); | |
| std::string ErrMsg; | |
| raw_string_ostream OS(ErrMsg); | |
| Error.print("", OS); | |
| // A failure here means that the test itself is buggy. | |
| if (!M) | |
| report_fatal_error(OS.str().c_str()); | |
| return M; | |
| } | |
| static void writeModuleToBuffer(std::unique_ptr<Module> Mod, | |
| SmallVectorImpl<char> &Buffer) { | |
| raw_svector_ostream OS(Buffer); | |
| WriteBitcodeToFile(*Mod, OS); | |
| } | |
| static std::unique_ptr<Module> getLazyModuleFromAssembly(LLVMContext &Context, | |
| SmallString<1024> &Mem, | |
| const char *Assembly) { | |
| writeModuleToBuffer(parseAssembly(Context, Assembly), Mem); | |
| Expected<std::unique_ptr<Module>> ModuleOrErr = | |
| getLazyBitcodeModule(MemoryBufferRef(Mem.str(), "test"), Context); | |
| if (!ModuleOrErr) | |
| report_fatal_error("Could not parse bitcode module"); | |
| return std::move(ModuleOrErr.get()); | |
| } | |
| // Tests that lazy evaluation can parse functions out of order. | |
| TEST(BitReaderTest, MaterializeFunctionsOutOfOrder) { | |
| SmallString<1024> Mem; | |
| LLVMContext Context; | |
| std::unique_ptr<Module> M = getLazyModuleFromAssembly( | |
| Context, Mem, "define void @f() {\n" | |
| " unreachable\n" | |
| "}\n" | |
| "define void @g() {\n" | |
| " unreachable\n" | |
| "}\n" | |
| "define void @h() {\n" | |
| " unreachable\n" | |
| "}\n" | |
| "define void @j() {\n" | |
| " unreachable\n" | |
| "}\n"); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| Function *F = M->getFunction("f"); | |
| Function *G = M->getFunction("g"); | |
| Function *H = M->getFunction("h"); | |
| Function *J = M->getFunction("j"); | |
| // Initially all functions are not materialized (no basic blocks). | |
| EXPECT_TRUE(F->empty()); | |
| EXPECT_TRUE(G->empty()); | |
| EXPECT_TRUE(H->empty()); | |
| EXPECT_TRUE(J->empty()); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| // Materialize h. | |
| ASSERT_FALSE(H->materialize()); | |
| EXPECT_TRUE(F->empty()); | |
| EXPECT_TRUE(G->empty()); | |
| EXPECT_FALSE(H->empty()); | |
| EXPECT_TRUE(J->empty()); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| // Materialize g. | |
| ASSERT_FALSE(G->materialize()); | |
| EXPECT_TRUE(F->empty()); | |
| EXPECT_FALSE(G->empty()); | |
| EXPECT_FALSE(H->empty()); | |
| EXPECT_TRUE(J->empty()); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| // Materialize j. | |
| ASSERT_FALSE(J->materialize()); | |
| EXPECT_TRUE(F->empty()); | |
| EXPECT_FALSE(G->empty()); | |
| EXPECT_FALSE(H->empty()); | |
| EXPECT_FALSE(J->empty()); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| // Materialize f. | |
| ASSERT_FALSE(F->materialize()); | |
| EXPECT_FALSE(F->empty()); | |
| EXPECT_FALSE(G->empty()); | |
| EXPECT_FALSE(H->empty()); | |
| EXPECT_FALSE(J->empty()); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| } | |
| TEST(BitReaderTest, MaterializeFunctionsForBlockAddr) { // PR11677 | |
| SmallString<1024> Mem; | |
| LLVMContext Context; | |
| std::unique_ptr<Module> M = getLazyModuleFromAssembly( | |
| Context, Mem, "@table = constant i8* blockaddress(@func, %bb)\n" | |
| "define void @func() {\n" | |
| " unreachable\n" | |
| "bb:\n" | |
| " unreachable\n" | |
| "}\n"); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| EXPECT_FALSE(M->getFunction("func")->empty()); | |
| } | |
| TEST(BitReaderTest, MaterializeFunctionsForBlockAddrInFunctionBefore) { | |
| SmallString<1024> Mem; | |
| LLVMContext Context; | |
| std::unique_ptr<Module> M = getLazyModuleFromAssembly( | |
| Context, Mem, "define i8* @before() {\n" | |
| " ret i8* blockaddress(@func, %bb)\n" | |
| "}\n" | |
| "define void @other() {\n" | |
| " unreachable\n" | |
| "}\n" | |
| "define void @func() {\n" | |
| " unreachable\n" | |
| "bb:\n" | |
| " unreachable\n" | |
| "}\n"); | |
| EXPECT_TRUE(M->getFunction("before")->empty()); | |
| EXPECT_TRUE(M->getFunction("func")->empty()); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| // Materialize @before, pulling in @func. | |
| EXPECT_FALSE(M->getFunction("before")->materialize()); | |
| EXPECT_FALSE(M->getFunction("func")->empty()); | |
| EXPECT_TRUE(M->getFunction("other")->empty()); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| } | |
| TEST(BitReaderTest, MaterializeFunctionsForBlockAddrInFunctionAfter) { | |
| SmallString<1024> Mem; | |
| LLVMContext Context; | |
| std::unique_ptr<Module> M = getLazyModuleFromAssembly( | |
| Context, Mem, "define void @func() {\n" | |
| " unreachable\n" | |
| "bb:\n" | |
| " unreachable\n" | |
| "}\n" | |
| "define void @other() {\n" | |
| " unreachable\n" | |
| "}\n" | |
| "define i8* @after() {\n" | |
| " ret i8* blockaddress(@func, %bb)\n" | |
| "}\n"); | |
| EXPECT_TRUE(M->getFunction("after")->empty()); | |
| EXPECT_TRUE(M->getFunction("func")->empty()); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| // Materialize @after, pulling in @func. | |
| EXPECT_FALSE(M->getFunction("after")->materialize()); | |
| EXPECT_FALSE(M->getFunction("func")->empty()); | |
| EXPECT_TRUE(M->getFunction("other")->empty()); | |
| EXPECT_FALSE(verifyModule(*M, &dbgs())); | |
| } | |
| } // end namespace |