423 lines · cpp
1//===- llvm/unittest/IR/VerifierTest.cpp - Verifier unit tests --*- C++ -*-===//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 "llvm/IR/Verifier.h"10#include "llvm/IR/Constants.h"11#include "llvm/IR/DIBuilder.h"12#include "llvm/IR/DebugInfoMetadata.h"13#include "llvm/IR/DerivedTypes.h"14#include "llvm/IR/Function.h"15#include "llvm/IR/GlobalAlias.h"16#include "llvm/IR/GlobalValue.h"17#include "llvm/IR/GlobalVariable.h"18#include "llvm/IR/IRBuilder.h"19#include "llvm/IR/Instructions.h"20#include "llvm/IR/LLVMContext.h"21#include "llvm/IR/Module.h"22#include "gtest/gtest.h"23 24namespace llvm {25namespace {26 27TEST(VerifierTest, Branch_i1) {28 LLVMContext C;29 Module M("M", C);30 FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);31 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);32 BasicBlock *Entry = BasicBlock::Create(C, "entry", F);33 BasicBlock *Exit = BasicBlock::Create(C, "exit", F);34 ReturnInst::Create(C, Exit);35 36 // To avoid triggering an assertion in BranchInst::Create, we first create37 // a branch with an 'i1' condition ...38 39 Constant *False = ConstantInt::getFalse(C);40 BranchInst *BI = BranchInst::Create(Exit, Exit, False, Entry);41 42 // ... then use setOperand to redirect it to a value of different type.43 44 Constant *Zero32 = ConstantInt::get(IntegerType::get(C, 32), 0);45 BI->setOperand(0, Zero32);46 47 EXPECT_TRUE(verifyFunction(*F));48}49 50TEST(VerifierTest, Freeze) {51 LLVMContext C;52 Module M("M", C);53 FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);54 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);55 BasicBlock *Entry = BasicBlock::Create(C, "entry", F);56 ReturnInst *RI = ReturnInst::Create(C, Entry);57 58 IntegerType *ITy = IntegerType::get(C, 32);59 ConstantInt *CI = ConstantInt::get(ITy, 0);60 61 // Valid type : freeze(<2 x i32>)62 Constant *CV = ConstantVector::getSplat(ElementCount::getFixed(2), CI);63 FreezeInst *FI_vec = new FreezeInst(CV);64 FI_vec->insertBefore(RI->getIterator());65 66 EXPECT_FALSE(verifyFunction(*F));67 68 FI_vec->eraseFromParent();69 70 // Valid type : freeze(float)71 Constant *CFP = ConstantFP::get(Type::getDoubleTy(C), 0.0);72 FreezeInst *FI_dbl = new FreezeInst(CFP);73 FI_dbl->insertBefore(RI->getIterator());74 75 EXPECT_FALSE(verifyFunction(*F));76 77 FI_dbl->eraseFromParent();78 79 // Valid type : freeze(i32*)80 PointerType *PT = PointerType::get(C, 0);81 ConstantPointerNull *CPN = ConstantPointerNull::get(PT);82 FreezeInst *FI_ptr = new FreezeInst(CPN);83 FI_ptr->insertBefore(RI->getIterator());84 85 EXPECT_FALSE(verifyFunction(*F));86 87 FI_ptr->eraseFromParent();88 89 // Valid type : freeze(int)90 FreezeInst *FI = new FreezeInst(CI);91 FI->insertBefore(RI->getIterator());92 93 EXPECT_FALSE(verifyFunction(*F));94 95 FI->eraseFromParent();96}97 98TEST(VerifierTest, InvalidRetAttribute) {99 LLVMContext C;100 Module M("M", C);101 FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false);102 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);103 AttributeList AS = F->getAttributes();104 F->setAttributes(AS.addRetAttribute(105 C, Attribute::getWithUWTableKind(C, UWTableKind::Default)));106 107 std::string Error;108 raw_string_ostream ErrorOS(Error);109 EXPECT_TRUE(verifyModule(M, &ErrorOS));110 EXPECT_TRUE(StringRef(Error).starts_with(111 "Attribute 'uwtable' does not apply to function return values"));112}113 114/// Test the verifier rejects invalid nofpclass values that the assembler may115/// also choose to reject.116TEST(VerifierTest, InvalidNoFPClassAttribute) {117 LLVMContext C;118 119 const unsigned InvalidMasks[] = {0, fcAllFlags + 1};120 121 for (unsigned InvalidMask : InvalidMasks) {122 Module M("M", C);123 FunctionType *FTy =124 FunctionType::get(Type::getFloatTy(C), /*isVarArg=*/false);125 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);126 AttributeList AS = F->getAttributes();127 128 // Don't use getWithNoFPClass to avoid using out of bounds enum values here.129 F->setAttributes(AS.addRetAttribute(130 C, Attribute::get(C, Attribute::NoFPClass, InvalidMask)));131 132 std::string Error;133 raw_string_ostream ErrorOS(Error);134 EXPECT_TRUE(verifyModule(M, &ErrorOS));135 136 StringRef ErrMsg(Error);137 138 if (InvalidMask == 0) {139 EXPECT_TRUE(ErrMsg.starts_with(140 "Attribute 'nofpclass' must have at least one test bit set"))141 << ErrMsg;142 } else {143 EXPECT_TRUE(ErrMsg.starts_with("Invalid value for 'nofpclass' test mask"))144 << ErrMsg;145 }146 }147}148 149TEST(VerifierTest, CrossModuleRef) {150 LLVMContext C;151 Module M1("M1", C);152 Module M2("M2", C);153 Module M3("M3", C);154 FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false);155 Function *F1 = Function::Create(FTy, Function::ExternalLinkage, "foo1", M1);156 Function *F2 = Function::Create(FTy, Function::ExternalLinkage, "foo2", M2);157 Function *F3 = Function::Create(FTy, Function::ExternalLinkage, "foo3", M3);158 159 BasicBlock *Entry1 = BasicBlock::Create(C, "entry", F1);160 BasicBlock *Entry3 = BasicBlock::Create(C, "entry", F3);161 162 // BAD: Referencing function in another module163 CallInst::Create(F2,"call",Entry1);164 165 // BAD: Referencing personality routine in another module166 F3->setPersonalityFn(F2);167 168 // Fill in the body169 Constant *ConstZero = ConstantInt::get(Type::getInt32Ty(C), 0);170 ReturnInst::Create(C, ConstZero, Entry1);171 ReturnInst::Create(C, ConstZero, Entry3);172 173 std::string Error;174 raw_string_ostream ErrorOS(Error);175 EXPECT_TRUE(verifyModule(M2, &ErrorOS));176 EXPECT_TRUE(Error == "Global is referenced in a different module!\n"177 "ptr @foo2\n"178 "; ModuleID = 'M2'\n"179 " %call = call i32 @foo2()\n"180 "ptr @foo1\n"181 "; ModuleID = 'M1'\n"182 "Global is used by function in a different module\n"183 "ptr @foo2\n"184 "; ModuleID = 'M2'\n"185 "ptr @foo3\n"186 "; ModuleID = 'M3'\n");187 188 Error.clear();189 EXPECT_TRUE(verifyModule(M1, &ErrorOS));190 EXPECT_TRUE(StringRef(Error) == "Referencing function in another module!\n"191 " %call = call i32 @foo2()\n"192 "; ModuleID = 'M1'\n"193 "ptr @foo2\n"194 "; ModuleID = 'M2'\n");195 196 Error.clear();197 EXPECT_TRUE(verifyModule(M3, &ErrorOS));198 EXPECT_TRUE(StringRef(Error).starts_with(199 "Referencing personality function in another module!"));200 201 // Erase bad methods to avoid triggering an assertion failure on destruction202 F1->eraseFromParent();203 F3->eraseFromParent();204}205 206TEST(VerifierTest, InvalidVariableLinkage) {207 LLVMContext C;208 Module M("M", C);209 new GlobalVariable(M, Type::getInt8Ty(C), false,210 GlobalValue::LinkOnceODRLinkage, nullptr, "Some Global");211 std::string Error;212 raw_string_ostream ErrorOS(Error);213 EXPECT_TRUE(verifyModule(M, &ErrorOS));214 EXPECT_TRUE(StringRef(Error).starts_with("Global is external, but doesn't "215 "have external or weak linkage!"));216}217 218TEST(VerifierTest, InvalidFunctionLinkage) {219 LLVMContext C;220 Module M("M", C);221 222 FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);223 Function::Create(FTy, GlobalValue::LinkOnceODRLinkage, "foo", &M);224 std::string Error;225 raw_string_ostream ErrorOS(Error);226 EXPECT_TRUE(verifyModule(M, &ErrorOS));227 EXPECT_TRUE(StringRef(Error).starts_with("Global is external, but doesn't "228 "have external or weak linkage!"));229}230 231TEST(VerifierTest, DetectInvalidDebugInfo) {232 {233 LLVMContext C;234 Module M("M", C);235 DIBuilder DIB(M);236 DIB.createCompileUnit(DISourceLanguageName(dwarf::DW_LANG_C89),237 DIB.createFile("broken.c", "/"), "unittest", false,238 "", 0);239 DIB.finalize();240 EXPECT_FALSE(verifyModule(M));241 242 // Now break it by inserting non-CU node to the list of CUs.243 auto *File = DIB.createFile("not-a-CU.f", ".");244 NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");245 NMD->addOperand(File);246 EXPECT_TRUE(verifyModule(M));247 }248 {249 LLVMContext C;250 Module M("M", C);251 DIBuilder DIB(M);252 auto *CU = DIB.createCompileUnit(DISourceLanguageName(dwarf::DW_LANG_C89),253 DIB.createFile("broken.c", "/"),254 "unittest", false, "", 0);255 new GlobalVariable(M, Type::getInt8Ty(C), false,256 GlobalValue::ExternalLinkage, nullptr, "g");257 258 auto *F = Function::Create(FunctionType::get(Type::getVoidTy(C), false),259 Function::ExternalLinkage, "f", M);260 IRBuilder<> Builder(BasicBlock::Create(C, "", F));261 Builder.CreateUnreachable();262 F->setSubprogram(DIB.createFunction(263 CU, "f", "f", DIB.createFile("broken.c", "/"), 1, nullptr, 1,264 DINode::FlagZero,265 DISubprogram::SPFlagLocalToUnit | DISubprogram::SPFlagDefinition));266 DIB.finalize();267 EXPECT_FALSE(verifyModule(M));268 269 // Now break it by not listing the CU at all.270 M.eraseNamedMetadata(M.getOrInsertNamedMetadata("llvm.dbg.cu"));271 EXPECT_TRUE(verifyModule(M));272 }273}274 275TEST(VerifierTest, MDNodeWrongContext) {276 LLVMContext C1, C2;277 auto *Node = MDNode::get(C1, {});278 279 Module M("M", C2);280 auto *NamedNode = M.getOrInsertNamedMetadata("test");281 NamedNode->addOperand(Node);282 283 std::string Error;284 raw_string_ostream ErrorOS(Error);285 EXPECT_TRUE(verifyModule(M, &ErrorOS));286 EXPECT_TRUE(StringRef(Error).starts_with(287 "MDNode context does not match Module context!"));288}289 290TEST(VerifierTest, AttributesWrongContext) {291 LLVMContext C1, C2;292 Module M1("M", C1);293 FunctionType *FTy1 =294 FunctionType::get(Type::getVoidTy(C1), /*isVarArg=*/false);295 Function *F1 = Function::Create(FTy1, Function::ExternalLinkage, "foo", M1);296 F1->setDoesNotReturn();297 298 Module M2("M", C2);299 FunctionType *FTy2 =300 FunctionType::get(Type::getVoidTy(C2), /*isVarArg=*/false);301 Function *F2 = Function::Create(FTy2, Function::ExternalLinkage, "foo", M2);302 F2->copyAttributesFrom(F1);303 304 EXPECT_TRUE(verifyFunction(*F2));305}306 307TEST(VerifierTest, SwitchInst) {308 LLVMContext C;309 Module M("M", C);310 IntegerType *Int32Ty = Type::getInt32Ty(C);311 FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), {Int32Ty, Int32Ty},312 /*isVarArg=*/false);313 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);314 BasicBlock *Entry = BasicBlock::Create(C, "entry", F);315 BasicBlock *Default = BasicBlock::Create(C, "default", F);316 BasicBlock *OnOne = BasicBlock::Create(C, "on_one", F);317 BasicBlock *OnTwo = BasicBlock::Create(C, "on_two", F);318 319 BasicBlock *Exit = BasicBlock::Create(C, "exit", F);320 321 BranchInst::Create(Exit, Default);322 BranchInst::Create(Exit, OnTwo);323 BranchInst::Create(Exit, OnOne);324 ReturnInst::Create(C, Exit);325 326 Value *Cond = F->getArg(0);327 SwitchInst *Switch = SwitchInst::Create(Cond, Default, 2, Entry);328 Switch->addCase(ConstantInt::get(Int32Ty, 1), OnOne);329 Switch->addCase(ConstantInt::get(Int32Ty, 2), OnTwo);330 331 EXPECT_FALSE(verifyFunction(*F));332 // set one case value to function argument.333 Switch->setOperand(2, F->getArg(1));334 EXPECT_TRUE(verifyFunction(*F));335}336 337TEST(VerifierTest, CrossFunctionRef) {338 LLVMContext C;339 Module M("M", C);340 FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);341 Function *F1 = Function::Create(FTy, Function::ExternalLinkage, "foo1", M);342 Function *F2 = Function::Create(FTy, Function::ExternalLinkage, "foo2", M);343 BasicBlock *Entry1 = BasicBlock::Create(C, "entry", F1);344 BasicBlock *Entry2 = BasicBlock::Create(C, "entry", F2);345 Type *I32 = Type::getInt32Ty(C);346 347 Value *Alloca = new AllocaInst(I32, 0, "alloca", Entry1);348 ReturnInst::Create(C, Entry1);349 350 Instruction *Store = new StoreInst(ConstantInt::get(I32, 0), Alloca, Entry2);351 ReturnInst::Create(C, Entry2);352 353 std::string Error;354 raw_string_ostream ErrorOS(Error);355 EXPECT_TRUE(verifyModule(M, &ErrorOS));356 EXPECT_TRUE(StringRef(Error).starts_with(357 "Referring to an instruction in another function!"));358 359 // Explicitly erase the store to avoid a use-after-free when the module is360 // destroyed.361 Store->eraseFromParent();362}363 364TEST(VerifierTest, AtomicRMW) {365 LLVMContext C;366 Module M("M", C);367 FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);368 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);369 BasicBlock *Entry = BasicBlock::Create(C, "entry", F);370 Value *Ptr = PoisonValue::get(PointerType::get(C, 0));371 372 Type *FPTy = Type::getFloatTy(C);373 Constant *CF = ConstantFP::getZero(FPTy);374 375 // Invalid scalable type : atomicrmw (<vscale x 2 x float>)376 Constant *CV = ConstantVector::getSplat(ElementCount::getScalable(2), CF);377 new AtomicRMWInst(AtomicRMWInst::FAdd, Ptr, CV, Align(8),378 AtomicOrdering::SequentiallyConsistent, SyncScope::System,379 Entry);380 ReturnInst::Create(C, Entry);381 382 std::string Error;383 raw_string_ostream ErrorOS(Error);384 EXPECT_TRUE(verifyFunction(*F, &ErrorOS));385 EXPECT_TRUE(StringRef(Error).starts_with(386 "atomicrmw fadd operand must have floating-point or "387 "fixed vector of floating-point type!"))388 << Error;389}390 391TEST(VerifierTest, GetElementPtrInst) {392 LLVMContext C;393 Module M("M", C);394 FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false);395 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);396 BasicBlock *Entry = BasicBlock::Create(C, "entry", F);397 ReturnInst *RI = ReturnInst::Create(C, Entry);398 399 FixedVectorType *V2P1Ty = FixedVectorType::get(PointerType::get(C, 1), 2);400 FixedVectorType *V2P2Ty = FixedVectorType::get(PointerType::get(C, 2), 2);401 402 Instruction *GEPVec = GetElementPtrInst::Create(403 Type::getInt8Ty(C), ConstantAggregateZero::get(V2P1Ty),404 {ConstantVector::getSplat(ElementCount::getFixed(2),405 ConstantInt::get(Type::getInt64Ty(C), 0))},406 Entry);407 408 GEPVec->insertBefore(RI->getIterator());409 410 // Break the address space of the source value411 GEPVec->getOperandUse(0).set(ConstantAggregateZero::get(V2P2Ty));412 413 std::string Error;414 raw_string_ostream ErrorOS(Error);415 EXPECT_TRUE(verifyFunction(*F, &ErrorOS));416 EXPECT_TRUE(417 StringRef(Error).starts_with("GEP address space doesn't match type"))418 << Error;419}420 421} // end anonymous namespace422} // end namespace llvm423