437 lines · cpp
1//===- llvm/unittest/Bitcode/BitReaderTest.cpp - Tests for BitReader ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "BitReaderTestCode.h"10#include "llvm/ADT/STLExtras.h"11#include "llvm/ADT/SmallString.h"12#include "llvm/AsmParser/Parser.h"13#include "llvm/Bitcode/BitcodeReader.h"14#include "llvm/Bitcode/BitcodeWriter.h"15#include "llvm/IR/Constants.h"16#include "llvm/IR/InstrTypes.h"17#include "llvm/IR/LLVMContext.h"18#include "llvm/IR/Module.h"19#include "llvm/IR/Verifier.h"20#include "llvm/Support/Debug.h"21#include "llvm/Support/Error.h"22#include "llvm/Support/MemoryBuffer.h"23#include "llvm/Support/SourceMgr.h"24#include "gtest/gtest.h"25 26using namespace llvm;27 28namespace {29 30std::unique_ptr<Module> parseAssembly(LLVMContext &Context,31 const char *Assembly) {32 SMDiagnostic Error;33 std::unique_ptr<Module> M = parseAssemblyString(Assembly, Error, Context);34 35 std::string ErrMsg;36 raw_string_ostream OS(ErrMsg);37 Error.print("", OS);38 39 // A failure here means that the test itself is buggy.40 if (!M)41 report_fatal_error(ErrMsg.c_str());42 43 return M;44}45 46static void writeModuleToBuffer(std::unique_ptr<Module> Mod,47 SmallVectorImpl<char> &Buffer) {48 raw_svector_ostream OS(Buffer);49 WriteBitcodeToFile(*Mod, OS);50}51 52static std::unique_ptr<Module> getLazyModuleFromAssembly(LLVMContext &Context,53 SmallString<1024> &Mem,54 const char *Assembly) {55 writeModuleToBuffer(parseAssembly(Context, Assembly), Mem);56 Expected<std::unique_ptr<Module>> ModuleOrErr =57 getLazyBitcodeModule(MemoryBufferRef(Mem.str(), "test"), Context);58 if (!ModuleOrErr)59 report_fatal_error("Could not parse bitcode module");60 return std::move(ModuleOrErr.get());61}62 63// Tests that lazy evaluation can parse functions out of order.64TEST(BitReaderTest, MaterializeFunctionsOutOfOrder) {65 SmallString<1024> Mem;66 LLVMContext Context;67 std::unique_ptr<Module> M = getLazyModuleFromAssembly(68 Context, Mem, "define void @f() {\n"69 " unreachable\n"70 "}\n"71 "define void @g() {\n"72 " unreachable\n"73 "}\n"74 "define void @h() {\n"75 " unreachable\n"76 "}\n"77 "define void @j() {\n"78 " unreachable\n"79 "}\n");80 EXPECT_FALSE(verifyModule(*M, &dbgs()));81 82 Function *F = M->getFunction("f");83 Function *G = M->getFunction("g");84 Function *H = M->getFunction("h");85 Function *J = M->getFunction("j");86 87 // Initially all functions are not materialized (no basic blocks).88 EXPECT_TRUE(F->empty());89 EXPECT_TRUE(G->empty());90 EXPECT_TRUE(H->empty());91 EXPECT_TRUE(J->empty());92 EXPECT_FALSE(verifyModule(*M, &dbgs()));93 94 // Materialize h.95 ASSERT_FALSE(H->materialize());96 EXPECT_TRUE(F->empty());97 EXPECT_TRUE(G->empty());98 EXPECT_FALSE(H->empty());99 EXPECT_TRUE(J->empty());100 EXPECT_FALSE(verifyModule(*M, &dbgs()));101 102 // Materialize g.103 ASSERT_FALSE(G->materialize());104 EXPECT_TRUE(F->empty());105 EXPECT_FALSE(G->empty());106 EXPECT_FALSE(H->empty());107 EXPECT_TRUE(J->empty());108 EXPECT_FALSE(verifyModule(*M, &dbgs()));109 110 // Materialize j.111 ASSERT_FALSE(J->materialize());112 EXPECT_TRUE(F->empty());113 EXPECT_FALSE(G->empty());114 EXPECT_FALSE(H->empty());115 EXPECT_FALSE(J->empty());116 EXPECT_FALSE(verifyModule(*M, &dbgs()));117 118 // Materialize f.119 ASSERT_FALSE(F->materialize());120 EXPECT_FALSE(F->empty());121 EXPECT_FALSE(G->empty());122 EXPECT_FALSE(H->empty());123 EXPECT_FALSE(J->empty());124 EXPECT_FALSE(verifyModule(*M, &dbgs()));125}126 127TEST(BitReaderTest, MaterializeFunctionsStrictFP) {128 SmallString<1024> Mem;129 130 LLVMContext Context;131 std::unique_ptr<Module> M = getLazyModuleFromAssembly(132 Context, Mem, "define double @foo(double %a) {\n"133 " %result = call double @bar(double %a) strictfp\n"134 " ret double %result\n"135 "}\n"136 "declare double @bar(double)\n");137 Function *Foo = M->getFunction("foo");138 ASSERT_FALSE(Foo->materialize());139 EXPECT_FALSE(Foo->empty());140 141 for (auto &BB : *Foo) {142 auto It = BB.begin();143 while (It != BB.end()) {144 Instruction &I = *It;145 ++It;146 147 if (auto *Call = dyn_cast<CallBase>(&I)) {148 EXPECT_FALSE(Call->isStrictFP());149 EXPECT_TRUE(Call->isNoBuiltin());150 }151 }152 }153 154 EXPECT_FALSE(verifyModule(*M, &dbgs()));155}156 157TEST(BitReaderTest, MaterializeConstrainedFPStrictFP) {158 SmallString<1024> Mem;159 160 LLVMContext Context;161 std::unique_ptr<Module> M = getLazyModuleFromAssembly(162 Context, Mem,163 "define double @foo(double %a) strictfp {\n"164 " %result = call double @llvm.experimental.constrained.sqrt.f64(double "165 "%a, metadata !\"round.tonearest\", metadata !\"fpexcept.strict\") "166 "strictfp\n"167 " ret double %result\n"168 "}\n"169 "declare double @llvm.experimental.constrained.sqrt.f64(double, "170 "metadata, metadata)\n");171 Function *Foo = M->getFunction("foo");172 ASSERT_FALSE(Foo->materialize());173 EXPECT_FALSE(Foo->empty());174 175 for (auto &BB : *Foo) {176 auto It = BB.begin();177 while (It != BB.end()) {178 Instruction &I = *It;179 ++It;180 181 if (auto *Call = dyn_cast<CallBase>(&I)) {182 EXPECT_TRUE(Call->isStrictFP());183 EXPECT_FALSE(Call->isNoBuiltin());184 }185 }186 }187 188 EXPECT_FALSE(verifyModule(*M, &dbgs()));189}190 191TEST(BitReaderTest, MaterializeFunctionsForBlockAddr) { // PR11677192 SmallString<1024> Mem;193 194 LLVMContext Context;195 std::unique_ptr<Module> M = getLazyModuleFromAssembly(196 Context, Mem, "@table = constant i8* blockaddress(@func, %bb)\n"197 "define void @func() {\n"198 " unreachable\n"199 "bb:\n"200 " unreachable\n"201 "}\n");202 EXPECT_FALSE(verifyModule(*M, &dbgs()));203 EXPECT_FALSE(M->getFunction("func")->empty());204}205 206TEST(BitReaderTest, MaterializeFunctionsForBlockAddrInFunctionBefore) {207 SmallString<1024> Mem;208 209 LLVMContext Context;210 std::unique_ptr<Module> M = getLazyModuleFromAssembly(211 Context, Mem, "define i8* @before() {\n"212 " ret i8* blockaddress(@func, %bb)\n"213 "}\n"214 "define void @other() {\n"215 " unreachable\n"216 "}\n"217 "define void @func() {\n"218 " unreachable\n"219 "bb:\n"220 " unreachable\n"221 "}\n");222 EXPECT_TRUE(M->getFunction("before")->empty());223 EXPECT_TRUE(M->getFunction("func")->empty());224 EXPECT_FALSE(verifyModule(*M, &dbgs()));225 226 // Materialize @before, pulling in @func.227 EXPECT_FALSE(M->getFunction("before")->materialize());228 EXPECT_FALSE(M->getFunction("func")->empty());229 EXPECT_TRUE(M->getFunction("other")->empty());230 EXPECT_FALSE(verifyModule(*M, &dbgs()));231}232 233TEST(BitReaderTest, MaterializeFunctionsForBlockAddrInFunctionAfter) {234 SmallString<1024> Mem;235 236 LLVMContext Context;237 std::unique_ptr<Module> M = getLazyModuleFromAssembly(238 Context, Mem, "define void @func() {\n"239 " unreachable\n"240 "bb:\n"241 " unreachable\n"242 "}\n"243 "define void @other() {\n"244 " unreachable\n"245 "}\n"246 "define i8* @after() {\n"247 " ret i8* blockaddress(@func, %bb)\n"248 "}\n");249 EXPECT_TRUE(M->getFunction("after")->empty());250 EXPECT_TRUE(M->getFunction("func")->empty());251 EXPECT_FALSE(verifyModule(*M, &dbgs()));252 253 // Materialize @after, pulling in @func.254 EXPECT_FALSE(M->getFunction("after")->materialize());255 EXPECT_FALSE(M->getFunction("func")->empty());256 EXPECT_TRUE(M->getFunction("other")->empty());257 EXPECT_FALSE(verifyModule(*M, &dbgs()));258}259 260// Helper function to convert type metadata to a string for testing261static std::string mdToString(Metadata *MD) {262 std::string S;263 if (auto *VMD = dyn_cast<ValueAsMetadata>(MD)) {264 if (VMD->getType()->isPointerTy()) {265 S += "ptr";266 return S;267 }268 }269 270 if (auto *TMD = dyn_cast<MDTuple>(MD)) {271 S += "!{";272 for (unsigned I = 0; I < TMD->getNumOperands(); I++) {273 if (I != 0)274 S += ", ";275 S += mdToString(TMD->getOperand(I).get());276 }277 S += "}";278 } else if (auto *SMD = dyn_cast<MDString>(MD)) {279 S += "!'";280 S += SMD->getString();281 S += "'";282 } else if (auto *I = mdconst::dyn_extract<ConstantInt>(MD)) {283 S += std::to_string(I->getZExtValue());284 } else if (auto *P = mdconst::dyn_extract<PoisonValue>(MD)) {285 auto *Ty = P->getType();286 if (Ty->isIntegerTy()) {287 S += "i";288 S += std::to_string(Ty->getIntegerBitWidth());289 } else if (Ty->isStructTy()) {290 S += "%";291 S += Ty->getStructName();292 } else {293 llvm_unreachable("unhandled poison metadata");294 }295 } else {296 llvm_unreachable("unhandled metadata");297 }298 return S;299}300 301// Recursively look into a (pointer) type and the the type.302// For primitive types it's a poison value of the type, for a pointer it's a303// metadata tuple with the addrspace and the referenced type. For a function,304// it's a tuple where the first element is the string "function", the second305// element is the return type or the string "void" and the following elements306// are the argument types.307static Metadata *getTypeMetadataEntry(unsigned TypeID, LLVMContext &Context,308 GetTypeByIDTy GetTypeByID,309 GetContainedTypeIDTy GetContainedTypeID) {310 Type *Ty = GetTypeByID(TypeID);311 if (auto *FTy = dyn_cast<FunctionType>(Ty)) {312 // Save the function signature as metadata313 SmallVector<Metadata *> SignatureMD;314 SignatureMD.push_back(MDString::get(Context, "function"));315 // Return type316 if (FTy->getReturnType()->isVoidTy())317 SignatureMD.push_back(MDString::get(Context, "void"));318 else319 SignatureMD.push_back(getTypeMetadataEntry(GetContainedTypeID(TypeID, 0),320 Context, GetTypeByID,321 GetContainedTypeID));322 // Arguments323 for (unsigned I = 0; I != FTy->getNumParams(); ++I)324 SignatureMD.push_back(325 getTypeMetadataEntry(GetContainedTypeID(TypeID, I + 1), Context,326 GetTypeByID, GetContainedTypeID));327 328 return MDTuple::get(Context, SignatureMD);329 }330 331 if (!Ty->isPointerTy())332 return ConstantAsMetadata::get(PoisonValue::get(Ty));333 334 // Return !{<addrspace>, <inner>} for pointer335 SmallVector<Metadata *, 2> MD;336 MD.push_back(ConstantAsMetadata::get(ConstantInt::get(337 Type::getInt32Ty(Context), Ty->getPointerAddressSpace())));338 MD.push_back(getTypeMetadataEntry(GetContainedTypeID(TypeID, 0), Context,339 GetTypeByID, GetContainedTypeID));340 return MDTuple::get(Context, MD);341}342 343// Test that when reading bitcode with typed pointers and upgrading them to344// opaque pointers, the type information of function signatures can be extracted345// and stored in metadata.346TEST(BitReaderTest, AccessFunctionTypeInfo) {347 StringRef Bitcode(reinterpret_cast<const char *>(AccessFunctionTypeInfoBc),348 sizeof(AccessFunctionTypeInfoBc));349 350 LLVMContext Context;351 ParserCallbacks Callbacks;352 // Supply a callback that stores the signature of a function into metadata,353 // so that the types behind pointers can be accessed.354 // Each function gets a !types metadata, which is a tuple with one element355 // for a non-void return type and every argument. For primitive types it's356 // a poison value of the type, for a pointer it's a metadata tuple with357 // the addrspace and the referenced type.358 Callbacks.ValueType = [&](Value *V, unsigned TypeID,359 GetTypeByIDTy GetTypeByID,360 GetContainedTypeIDTy GetContainedTypeID) {361 if (auto *F = dyn_cast<Function>(V)) {362 auto *MD = getTypeMetadataEntry(TypeID, F->getContext(), GetTypeByID,363 GetContainedTypeID);364 F->setMetadata("types", cast<MDNode>(MD));365 }366 };367 368 Expected<std::unique_ptr<Module>> ModuleOrErr =369 parseBitcodeFile(MemoryBufferRef(Bitcode, "test"), Context, Callbacks);370 371 if (!ModuleOrErr)372 report_fatal_error("Could not parse bitcode module");373 std::unique_ptr<Module> M = std::move(ModuleOrErr.get());374 375 EXPECT_EQ(mdToString(M->getFunction("func")->getMetadata("types")),376 "!{!'function', !'void'}");377 EXPECT_EQ(mdToString(M->getFunction("func_header")->getMetadata("types")),378 "!{!'function', i32}");379 EXPECT_EQ(mdToString(M->getFunction("ret_ptr")->getMetadata("types")),380 "!{!'function', !{0, i8}}");381 EXPECT_EQ(mdToString(M->getFunction("ret_and_arg_ptr")->getMetadata("types")),382 "!{!'function', !{0, i8}, !{8, i32}}");383 EXPECT_EQ(mdToString(M->getFunction("double_ptr")->getMetadata("types")),384 "!{!'function', !{1, i8}, !{2, !{0, i32}}, !{0, !{0, !{0, i32}}}}");385}386 387// Test that when reading bitcode with typed pointers and upgrading them to388// opaque pointers, the type information of pointers in metadata can be389// extracted and stored in metadata.390TEST(BitReaderTest, AccessMetadataTypeInfo) {391 StringRef Bitcode(reinterpret_cast<const char *>(AccessMetadataTypeInfoBc),392 sizeof(AccessFunctionTypeInfoBc));393 394 LLVMContext Context;395 ParserCallbacks Callbacks;396 // Supply a callback that stores types from metadata,397 // so that the types behind pointers can be accessed.398 // Non-pointer entries are ignored. Values with a pointer type are399 // replaced by a metadata tuple with {original value, type md}. We cannot400 // save the metadata outside because after conversion to opaque pointers,401 // entries are not distinguishable anymore (e.g. i32* and i8* are both402 // upgraded to ptr).403 Callbacks.MDType = [&](Metadata **Val, unsigned TypeID,404 GetTypeByIDTy GetTypeByID,405 GetContainedTypeIDTy GetContainedTypeID) {406 auto *OrigVal = cast<ValueAsMetadata>(*Val);407 if (OrigVal->getType()->isPointerTy()) {408 // Ignore function references, their signature can be saved like409 // in the test above410 if (!isa<Function>(OrigVal->getValue())) {411 SmallVector<Metadata *> Tuple;412 Tuple.push_back(OrigVal);413 Tuple.push_back(getTypeMetadataEntry(GetContainedTypeID(TypeID, 0),414 OrigVal->getContext(), GetTypeByID,415 GetContainedTypeID));416 *Val = MDTuple::get(OrigVal->getContext(), Tuple);417 }418 }419 };420 421 Expected<std::unique_ptr<Module>> ModuleOrErr =422 parseBitcodeFile(MemoryBufferRef(Bitcode, "test"), Context, Callbacks);423 424 if (!ModuleOrErr)425 report_fatal_error("Could not parse bitcode module");426 std::unique_ptr<Module> M = std::move(ModuleOrErr.get());427 428 EXPECT_EQ(429 mdToString(M->getNamedMetadata("md")->getOperand(0)),430 "!{2, !{ptr, %dx.types.f32}, ptr, !{ptr, !{!'function', !'void'}}}");431 EXPECT_EQ(mdToString(M->getNamedMetadata("md2")->getOperand(0)),432 "!{!{ptr, !{!'function', !{0, i8}, !{2, !{0, i32}}}}, !{ptr, !{0, "433 "!{0, i32}}}}");434}435 436} // end namespace437