Chandler Carruth | 972cc0d | 2012-01-02 09:19:48 +0000 | [diff] [blame] | 1 | //===- llvm/unittest/Bitcode/BitReaderTest.cpp - Tests for BitReader ------===// |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
Rafael Espindola | cc625c9 | 2015-06-17 01:15:47 +0000 | [diff] [blame] | 10 | #include "llvm/ADT/STLExtras.h" |
Teresa Johnson | a547919 | 2016-11-11 05:34:58 +0000 | [diff] [blame] | 11 | #include "llvm/ADT/SmallString.h" |
Chandler Carruth | 1b27914 | 2015-01-14 11:23:27 +0000 | [diff] [blame] | 12 | #include "llvm/AsmParser/Parser.h" |
Teresa Johnson | a547919 | 2016-11-11 05:34:58 +0000 | [diff] [blame] | 13 | #include "llvm/Bitcode/BitcodeReader.h" |
| 14 | #include "llvm/Bitcode/BitcodeWriter.h" |
Chandler Carruth | 0b8c9a8 | 2013-01-02 11:36:10 +0000 | [diff] [blame] | 15 | #include "llvm/IR/LLVMContext.h" |
| 16 | #include "llvm/IR/Module.h" |
Chandler Carruth | 56e1394 | 2014-01-13 09:26:24 +0000 | [diff] [blame] | 17 | #include "llvm/IR/Verifier.h" |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 18 | #include "llvm/Support/Debug.h" |
Peter Collingbourne | 76c218e | 2016-11-09 17:49:19 +0000 | [diff] [blame] | 19 | #include "llvm/Support/Error.h" |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 20 | #include "llvm/Support/MemoryBuffer.h" |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 21 | #include "llvm/Support/SourceMgr.h" |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 22 | #include "gtest/gtest.h" |
| 23 | |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 24 | using namespace llvm; |
| 25 | |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 26 | namespace { |
| 27 | |
Mehdi Amini | 8be7707 | 2016-04-14 21:59:01 +0000 | [diff] [blame] | 28 | std::unique_ptr<Module> parseAssembly(LLVMContext &Context, |
| 29 | const char *Assembly) { |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 30 | SMDiagnostic Error; |
Mehdi Amini | 8be7707 | 2016-04-14 21:59:01 +0000 | [diff] [blame] | 31 | std::unique_ptr<Module> M = parseAssemblyString(Assembly, Error, Context); |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 32 | |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 33 | std::string ErrMsg; |
| 34 | raw_string_ostream OS(ErrMsg); |
| 35 | Error.print("", OS); |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 36 | |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 37 | // A failure here means that the test itself is buggy. |
Rafael Espindola | 9b29ff9 | 2014-08-19 16:58:54 +0000 | [diff] [blame] | 38 | if (!M) |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 39 | report_fatal_error(OS.str().c_str()); |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 40 | |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 41 | return M; |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 42 | } |
| 43 | |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 44 | static void writeModuleToBuffer(std::unique_ptr<Module> Mod, |
| 45 | SmallVectorImpl<char> &Buffer) { |
Daniel Dunbar | fdc8f78 | 2012-02-29 20:30:56 +0000 | [diff] [blame] | 46 | raw_svector_ostream OS(Buffer); |
Rafael Espindola | 06d6207 | 2018-02-14 19:11:32 +0000 | [diff] [blame] | 47 | WriteBitcodeToFile(*Mod, OS); |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 48 | } |
| 49 | |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 50 | static std::unique_ptr<Module> getLazyModuleFromAssembly(LLVMContext &Context, |
| 51 | SmallString<1024> &Mem, |
| 52 | const char *Assembly) { |
Mehdi Amini | 8be7707 | 2016-04-14 21:59:01 +0000 | [diff] [blame] | 53 | writeModuleToBuffer(parseAssembly(Context, Assembly), Mem); |
Peter Collingbourne | dead081 | 2016-11-13 07:00:17 +0000 | [diff] [blame] | 54 | Expected<std::unique_ptr<Module>> ModuleOrErr = |
Peter Collingbourne | 5498e18 | 2016-11-08 06:03:43 +0000 | [diff] [blame] | 55 | getLazyBitcodeModule(MemoryBufferRef(Mem.str(), "test"), Context); |
Peter Collingbourne | dead081 | 2016-11-13 07:00:17 +0000 | [diff] [blame] | 56 | if (!ModuleOrErr) |
| 57 | report_fatal_error("Could not parse bitcode module"); |
Rafael Espindola | 20a6785 | 2015-06-16 22:27:55 +0000 | [diff] [blame] | 58 | return std::move(ModuleOrErr.get()); |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 59 | } |
Chandler Carruth | 972cc0d | 2012-01-02 09:19:48 +0000 | [diff] [blame] | 60 | |
Derek Schuff | 683cf0f | 2015-05-06 16:52:35 +0000 | [diff] [blame] | 61 | // Tests that lazy evaluation can parse functions out of order. |
| 62 | TEST(BitReaderTest, MaterializeFunctionsOutOfOrder) { |
| 63 | SmallString<1024> Mem; |
| 64 | LLVMContext Context; |
| 65 | std::unique_ptr<Module> M = getLazyModuleFromAssembly( |
| 66 | Context, Mem, "define void @f() {\n" |
| 67 | " unreachable\n" |
| 68 | "}\n" |
| 69 | "define void @g() {\n" |
| 70 | " unreachable\n" |
| 71 | "}\n" |
| 72 | "define void @h() {\n" |
| 73 | " unreachable\n" |
| 74 | "}\n" |
| 75 | "define void @j() {\n" |
| 76 | " unreachable\n" |
| 77 | "}\n"); |
| 78 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
| 79 | |
| 80 | Function *F = M->getFunction("f"); |
| 81 | Function *G = M->getFunction("g"); |
| 82 | Function *H = M->getFunction("h"); |
| 83 | Function *J = M->getFunction("j"); |
| 84 | |
| 85 | // Initially all functions are not materialized (no basic blocks). |
| 86 | EXPECT_TRUE(F->empty()); |
| 87 | EXPECT_TRUE(G->empty()); |
| 88 | EXPECT_TRUE(H->empty()); |
| 89 | EXPECT_TRUE(J->empty()); |
| 90 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
| 91 | |
| 92 | // Materialize h. |
Peter Collingbourne | 76c218e | 2016-11-09 17:49:19 +0000 | [diff] [blame] | 93 | ASSERT_FALSE(H->materialize()); |
Derek Schuff | 683cf0f | 2015-05-06 16:52:35 +0000 | [diff] [blame] | 94 | EXPECT_TRUE(F->empty()); |
| 95 | EXPECT_TRUE(G->empty()); |
| 96 | EXPECT_FALSE(H->empty()); |
| 97 | EXPECT_TRUE(J->empty()); |
| 98 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
| 99 | |
| 100 | // Materialize g. |
Peter Collingbourne | 76c218e | 2016-11-09 17:49:19 +0000 | [diff] [blame] | 101 | ASSERT_FALSE(G->materialize()); |
Derek Schuff | 683cf0f | 2015-05-06 16:52:35 +0000 | [diff] [blame] | 102 | EXPECT_TRUE(F->empty()); |
| 103 | EXPECT_FALSE(G->empty()); |
| 104 | EXPECT_FALSE(H->empty()); |
| 105 | EXPECT_TRUE(J->empty()); |
| 106 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
| 107 | |
| 108 | // Materialize j. |
Peter Collingbourne | 76c218e | 2016-11-09 17:49:19 +0000 | [diff] [blame] | 109 | ASSERT_FALSE(J->materialize()); |
Derek Schuff | 683cf0f | 2015-05-06 16:52:35 +0000 | [diff] [blame] | 110 | EXPECT_TRUE(F->empty()); |
| 111 | EXPECT_FALSE(G->empty()); |
| 112 | EXPECT_FALSE(H->empty()); |
| 113 | EXPECT_FALSE(J->empty()); |
| 114 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
| 115 | |
| 116 | // Materialize f. |
Peter Collingbourne | 76c218e | 2016-11-09 17:49:19 +0000 | [diff] [blame] | 117 | ASSERT_FALSE(F->materialize()); |
Derek Schuff | 683cf0f | 2015-05-06 16:52:35 +0000 | [diff] [blame] | 118 | EXPECT_FALSE(F->empty()); |
| 119 | EXPECT_FALSE(G->empty()); |
| 120 | EXPECT_FALSE(H->empty()); |
| 121 | EXPECT_FALSE(J->empty()); |
| 122 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
| 123 | } |
| 124 | |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 125 | TEST(BitReaderTest, MaterializeFunctionsForBlockAddr) { // PR11677 |
| 126 | SmallString<1024> Mem; |
| 127 | |
| 128 | LLVMContext Context; |
| 129 | std::unique_ptr<Module> M = getLazyModuleFromAssembly( |
| 130 | Context, Mem, "@table = constant i8* blockaddress(@func, %bb)\n" |
| 131 | "define void @func() {\n" |
| 132 | " unreachable\n" |
| 133 | "bb:\n" |
| 134 | " unreachable\n" |
| 135 | "}\n"); |
| 136 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
Peter Collingbourne | e851658 | 2016-11-02 00:08:19 +0000 | [diff] [blame] | 137 | EXPECT_FALSE(M->getFunction("func")->empty()); |
Duncan P. N. Exon Smith | cf8b959 | 2014-08-01 21:11:34 +0000 | [diff] [blame] | 138 | } |
| 139 | |
| 140 | TEST(BitReaderTest, MaterializeFunctionsForBlockAddrInFunctionBefore) { |
| 141 | SmallString<1024> Mem; |
| 142 | |
| 143 | LLVMContext Context; |
| 144 | std::unique_ptr<Module> M = getLazyModuleFromAssembly( |
| 145 | Context, Mem, "define i8* @before() {\n" |
| 146 | " ret i8* blockaddress(@func, %bb)\n" |
| 147 | "}\n" |
| 148 | "define void @other() {\n" |
| 149 | " unreachable\n" |
| 150 | "}\n" |
| 151 | "define void @func() {\n" |
| 152 | " unreachable\n" |
| 153 | "bb:\n" |
| 154 | " unreachable\n" |
| 155 | "}\n"); |
| 156 | EXPECT_TRUE(M->getFunction("before")->empty()); |
| 157 | EXPECT_TRUE(M->getFunction("func")->empty()); |
| 158 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
| 159 | |
| 160 | // Materialize @before, pulling in @func. |
Rafael Espindola | c498284 | 2014-10-24 22:50:48 +0000 | [diff] [blame] | 161 | EXPECT_FALSE(M->getFunction("before")->materialize()); |
Duncan P. N. Exon Smith | cf8b959 | 2014-08-01 21:11:34 +0000 | [diff] [blame] | 162 | EXPECT_FALSE(M->getFunction("func")->empty()); |
| 163 | EXPECT_TRUE(M->getFunction("other")->empty()); |
| 164 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
Duncan P. N. Exon Smith | cf8b959 | 2014-08-01 21:11:34 +0000 | [diff] [blame] | 165 | } |
| 166 | |
| 167 | TEST(BitReaderTest, MaterializeFunctionsForBlockAddrInFunctionAfter) { |
| 168 | SmallString<1024> Mem; |
| 169 | |
| 170 | LLVMContext Context; |
| 171 | std::unique_ptr<Module> M = getLazyModuleFromAssembly( |
| 172 | Context, Mem, "define void @func() {\n" |
| 173 | " unreachable\n" |
| 174 | "bb:\n" |
| 175 | " unreachable\n" |
| 176 | "}\n" |
| 177 | "define void @other() {\n" |
| 178 | " unreachable\n" |
| 179 | "}\n" |
| 180 | "define i8* @after() {\n" |
| 181 | " ret i8* blockaddress(@func, %bb)\n" |
| 182 | "}\n"); |
| 183 | EXPECT_TRUE(M->getFunction("after")->empty()); |
| 184 | EXPECT_TRUE(M->getFunction("func")->empty()); |
| 185 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
| 186 | |
| 187 | // Materialize @after, pulling in @func. |
Rafael Espindola | c498284 | 2014-10-24 22:50:48 +0000 | [diff] [blame] | 188 | EXPECT_FALSE(M->getFunction("after")->materialize()); |
Duncan P. N. Exon Smith | cf8b959 | 2014-08-01 21:11:34 +0000 | [diff] [blame] | 189 | EXPECT_FALSE(M->getFunction("func")->empty()); |
| 190 | EXPECT_TRUE(M->getFunction("other")->empty()); |
| 191 | EXPECT_FALSE(verifyModule(*M, &dbgs())); |
Rafael Espindola | 47f79bb | 2012-01-02 07:49:53 +0000 | [diff] [blame] | 192 | } |
Duncan P. N. Exon Smith | 2e9b60a | 2014-08-01 21:01:04 +0000 | [diff] [blame] | 193 | |
| 194 | } // end namespace |