//=== unittests/CodeGen/TBAAMetadataTest.cpp - Checks metadata generation -===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "IRMatchers.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Parse/ParseAST.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Module.h" #include "llvm/Support/MemoryBuffer.h" #include "gtest/gtest.h" #include using namespace llvm; namespace { struct TestCompiler { LLVMContext Context; clang::CompilerInstance compiler; clang::CodeGenerator *CG = nullptr; llvm::Module *M = nullptr; unsigned PtrSize = 0; void init(const char *TestProgram) { compiler.createDiagnostics(); compiler.getCodeGenOpts().StructPathTBAA = 1; compiler.getCodeGenOpts().OptimizationLevel = 1; std::string TrStr = llvm::Triple::normalize(llvm::sys::getProcessTriple()); llvm::Triple Tr(TrStr); Tr.setOS(Triple::Linux); Tr.setVendor(Triple::VendorType::UnknownVendor); Tr.setEnvironment(Triple::EnvironmentType::UnknownEnvironment); compiler.getTargetOpts().Triple = Tr.getTriple(); compiler.setTarget(clang::TargetInfo::CreateTargetInfo( compiler.getDiagnostics(), std::make_shared(compiler.getTargetOpts()))); const clang::TargetInfo &TInfo = compiler.getTarget(); PtrSize = TInfo.getPointerWidth(0) / 8; compiler.createFileManager(); compiler.createSourceManager(compiler.getFileManager()); compiler.createPreprocessor(clang::TU_Prefix); compiler.createASTContext(); CG = CreateLLVMCodeGen( compiler.getDiagnostics(), "main-module", compiler.getHeaderSearchOpts(), compiler.getPreprocessorOpts(), compiler.getCodeGenOpts(), Context); compiler.setASTConsumer(std::unique_ptr(CG)); compiler.createSema(clang::TU_Prefix, nullptr); clang::SourceManager &sm = compiler.getSourceManager(); sm.setMainFileID(sm.createFileID( llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User)); } const BasicBlock *compile() { clang::ParseAST(compiler.getSema(), false, false); M = CG->GetModule(); // Do not expect more than one function definition. auto FuncPtr = M->begin(); for (; FuncPtr != M->end(); ++FuncPtr) if (!FuncPtr->isDeclaration()) break; assert(FuncPtr != M->end()); const llvm::Function &Func = *FuncPtr; ++FuncPtr; for (; FuncPtr != M->end(); ++FuncPtr) if (!FuncPtr->isDeclaration()) break; assert(FuncPtr == M->end()); // The function must consist of single basic block. auto BBPtr = Func.begin(); assert(Func.begin() != Func.end()); const BasicBlock &BB = *BBPtr; ++BBPtr; assert(BBPtr == Func.end()); return &BB; } }; auto OmnipotentCharC = MMTuple( MMString("omnipotent char"), MMTuple( MMString("Simple C/C++ TBAA")), MConstInt(0, 64) ); auto OmnipotentCharCXX = MMTuple( MMString("omnipotent char"), MMTuple( MMString("Simple C++ TBAA")), MConstInt(0, 64) ); TEST(TBAAMetadataTest, BasicTypes) { const char TestProgram[] = R"**( void func(char *CP, short *SP, int *IP, long long *LP, void **VPP, int **IPP) { *CP = 4; *SP = 11; *IP = 601; *LP = 604; *VPP = CP; *IPP = IP; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().C11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(4, 8), MMTuple( OmnipotentCharC, MSameAs(0), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(11, 16), MMTuple( MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MSameAs(0), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(601, 32), MMTuple( MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MSameAs(0), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(604, 64), MMTuple( MMTuple( MMString("long long"), OmnipotentCharC, MConstInt(0)), MSameAs(0), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MValType(Type::getInt8PtrTy(Compiler.Context)), MMTuple( MMTuple( MMString("any pointer"), OmnipotentCharC, MConstInt(0)), MSameAs(0), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MValType(Type::getInt32PtrTy(Compiler.Context)), MMTuple( MMTuple( MMString("any pointer"), OmnipotentCharC, MConstInt(0)), MSameAs(0), MConstInt(0)))); ASSERT_TRUE(I); } TEST(TBAAMetadataTest, CFields) { const char TestProgram[] = R"**( struct ABC { short f16; int f32; long long f64; unsigned short f16_2; unsigned f32_2; unsigned long long f64_2; }; void func(struct ABC *A) { A->f32 = 4; A->f16 = 11; A->f64 = 601; A->f16_2 = 22; A->f32_2 = 77; A->f64_2 = 604; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().C11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto StructABC = MMTuple( MMString("ABC"), MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(0), MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(4), MMTuple( MMString("long long"), OmnipotentCharC, MConstInt(0)), MConstInt(8), MSameAs(1), MConstInt(16), MSameAs(3), MConstInt(20), MSameAs(5), MConstInt(24)); const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(4, 32), MMTuple( StructABC, MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(11, 16), MMTuple( StructABC, MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(601, 64), MMTuple( StructABC, MMTuple( MMString("long long"), OmnipotentCharC, MConstInt(0)), MConstInt(8)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(22, 16), MMTuple( StructABC, MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(16)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(77, 32), MMTuple( StructABC, MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(20)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(604, 64), MMTuple( StructABC, MMTuple( MMString("long long"), OmnipotentCharC, MConstInt(0)), MConstInt(24)))); ASSERT_TRUE(I); } TEST(TBAAMetadataTest, CTypedefFields) { const char TestProgram[] = R"**( typedef struct { short f16; int f32; } ABC; typedef struct { short value_f16; int value_f32; } CDE; void func(ABC *A, CDE *B) { A->f32 = 4; A->f16 = 11; B->value_f32 = 44; B->value_f16 = 111; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().C11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto NamelessStruct = MMTuple( MMString(""), MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(0), MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(4)); const Metadata *MetaABC = nullptr; const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(4, 32), MMTuple( MMSave(MetaABC, NamelessStruct), MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(11, 16), MMTuple( NamelessStruct, MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); const Metadata *MetaCDE = nullptr; I = matchNext(I, MInstruction(Instruction::Store, MConstInt(44, 32), MMTuple( MMSave(MetaCDE, NamelessStruct), MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(111, 16), MMTuple( NamelessStruct, MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); // FIXME: Nameless structures used in definitions of 'ABC' and 'CDE' are // different structures and must be described by different descriptors. //ASSERT_TRUE(MetaABC != MetaCDE); } TEST(TBAAMetadataTest, CTypedefFields2) { const char TestProgram[] = R"**( typedef struct { short f16; int f32; } ABC; typedef struct { short f16; int f32; } CDE; void func(ABC *A, CDE *B) { A->f32 = 4; A->f16 = 11; B->f32 = 44; B->f16 = 111; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().C11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto NamelessStruct = MMTuple( MMString(""), MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(0), MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(4)); const Metadata *MetaABC = nullptr; const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(4, 32), MMTuple( MMSave(MetaABC, NamelessStruct), MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(11, 16), MMTuple( NamelessStruct, MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); const Metadata *MetaCDE = nullptr; I = matchNext(I, MInstruction(Instruction::Store, MConstInt(44, 32), MMTuple( MMSave(MetaCDE, NamelessStruct), MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(111, 16), MMTuple( NamelessStruct, MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); // FIXME: Nameless structures used in definitions of 'ABC' and 'CDE' are // different structures, although they have the same field sequence. They must // be described by different descriptors. //ASSERT_TRUE(MetaABC != MetaCDE); } TEST(TBAAMetadataTest, CTypedefFields3) { const char TestProgram[] = R"**( typedef struct { short f16; int f32; } ABC; typedef struct { int f32; short f16; } CDE; void func(ABC *A, CDE *B) { A->f32 = 4; A->f16 = 11; B->f32 = 44; B->f16 = 111; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().C11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto NamelessStruct1 = MMTuple( MMString(""), MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(0), MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(4)); auto NamelessStruct2 = MMTuple( MMString(""), MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(0), MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(4)); const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(4, 32), MMTuple( NamelessStruct1, MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(11, 16), MMTuple( NamelessStruct1, MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(44, 32), MMTuple( NamelessStruct2, MMTuple( MMString("int"), OmnipotentCharC, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(111, 16), MMTuple( NamelessStruct2, MMTuple( MMString("short"), OmnipotentCharC, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); } TEST(TBAAMetadataTest, CXXFields) { const char TestProgram[] = R"**( struct ABC { short f16; int f32; long long f64; unsigned short f16_2; unsigned f32_2; unsigned long long f64_2; }; void func(struct ABC *A) { A->f32 = 4; A->f16 = 11; A->f64 = 601; A->f16_2 = 22; A->f32_2 = 77; A->f64_2 = 604; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().CPlusPlus = 1; Compiler.compiler.getLangOpts().CPlusPlus11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto StructABC = MMTuple( MMString("_ZTS3ABC"), MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0), MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(4), MMTuple( MMString("long long"), OmnipotentCharCXX, MConstInt(0)), MConstInt(8), MSameAs(1), MConstInt(16), MSameAs(3), MConstInt(20), MSameAs(5), MConstInt(24)); const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(4, 32), MMTuple( StructABC, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(11, 16), MMTuple( StructABC, MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(601, 64), MMTuple( StructABC, MMTuple( MMString("long long"), OmnipotentCharCXX, MConstInt(0)), MConstInt(8)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(22, 16), MMTuple( StructABC, MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(16)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(77, 32), MMTuple( StructABC, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(20)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(604, 64), MMTuple( StructABC, MMTuple( MMString("long long"), OmnipotentCharCXX, MConstInt(0)), MConstInt(24)))); ASSERT_TRUE(I); } TEST(TBAAMetadataTest, CXXTypedefFields) { const char TestProgram[] = R"**( typedef struct { short f16; int f32; } ABC; typedef struct { short value_f16; int value_f32; } CDE; void func(ABC *A, CDE *B) { A->f32 = 4; A->f16 = 11; B->value_f32 = 44; B->value_f16 = 111; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().CPlusPlus = 1; Compiler.compiler.getLangOpts().CPlusPlus11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto StructABC = MMTuple( MMString("_ZTS3ABC"), MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0), MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(4)); auto StructCDE = MMTuple( MMString("_ZTS3CDE"), MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0), MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(4)); const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(4, 32), MMTuple( StructABC, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(11, 16), MMTuple( StructABC, MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(44, 32), MMTuple( StructCDE, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(111, 16), MMTuple( StructCDE, MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); } TEST(TBAAMetadataTest, StructureFields) { const char TestProgram[] = R"**( struct Inner { int f32; }; struct Outer { short f16; Inner b1; Inner b2; }; void func(Outer *S) { S->f16 = 14; S->b1.f32 = 35; S->b2.f32 = 77; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().CPlusPlus = 1; Compiler.compiler.getLangOpts().CPlusPlus11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto StructInner = MMTuple( MMString("_ZTS5Inner"), MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)); auto StructOuter = MMTuple( MMString("_ZTS5Outer"), MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0), StructInner, MConstInt(4), MSameAs(3), MConstInt(8)); const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(14, 16), MMTuple( StructOuter, MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(35, 32), MMTuple( StructOuter, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(77, 32), MMTuple( StructOuter, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(8)))); ASSERT_TRUE(I); } TEST(TBAAMetadataTest, ArrayFields) { const char TestProgram[] = R"**( struct Inner { int f32; }; struct Outer { short f16; Inner b1[2]; }; void func(Outer *S) { S->f16 = 14; S->b1[0].f32 = 35; S->b1[1].f32 = 77; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().CPlusPlus = 1; Compiler.compiler.getLangOpts().CPlusPlus11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto StructInner = MMTuple( MMString("_ZTS5Inner"), MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)); auto StructOuter = MMTuple( MMString("_ZTS5Outer"), MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0), OmnipotentCharCXX, // FIXME: Info about array field is lost. MConstInt(4)); const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(14, 16), MMTuple( StructOuter, MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(35, 32), MMTuple( StructInner, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(77, 32), MMTuple( StructInner, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); } TEST(TBAAMetadataTest, BaseClass) { const char TestProgram[] = R"**( struct Base { int f32; }; struct Derived : public Base { short f16; }; void func(Base *B, Derived *D) { B->f32 = 14; D->f16 = 35; D->f32 = 77; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().CPlusPlus = 1; Compiler.compiler.getLangOpts().CPlusPlus11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto ClassBase = MMTuple( MMString("_ZTS4Base"), MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)); auto ClassDerived = MMTuple( MMString("_ZTS7Derived"), MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(4)); const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(14, 32), MMTuple( ClassBase, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(35, 16), MMTuple( ClassDerived, MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(77, 32), MMTuple( ClassBase, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); } TEST(TBAAMetadataTest, PolymorphicClass) { const char TestProgram[] = R"**( struct Base { virtual void m1(int *) = 0; int f32; }; struct Derived : public Base { virtual void m1(int *) override; short f16; }; void func(Base *B, Derived *D) { B->f32 = 14; D->f16 = 35; D->f32 = 77; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().CPlusPlus = 1; Compiler.compiler.getLangOpts().CPlusPlus11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto ClassBase = MMTuple( MMString("_ZTS4Base"), MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(Compiler.PtrSize)); auto ClassDerived = MMTuple( MMString("_ZTS7Derived"), MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(Compiler.PtrSize + 4)); const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(14, 32), MMTuple( ClassBase, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(Compiler.PtrSize)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(35, 16), MMTuple( ClassDerived, MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(Compiler.PtrSize + 4)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(77, 32), MMTuple( ClassBase, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(Compiler.PtrSize)))); ASSERT_TRUE(I); } TEST(TBAAMetadataTest, VirtualBase) { const char TestProgram[] = R"**( struct Base { int f32; }; struct Derived : public virtual Base { short f16; }; void func(Base *B, Derived *D) { B->f32 = 14; D->f16 = 35; D->f32 = 77; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().CPlusPlus = 1; Compiler.compiler.getLangOpts().CPlusPlus11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto ClassBase = MMTuple( MMString("_ZTS4Base"), MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)); auto ClassDerived = MMTuple( MMString("_ZTS7Derived"), MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(Compiler.PtrSize)); const Instruction *I = match(BB, MInstruction(Instruction::Store, MConstInt(14, 32), MMTuple( ClassBase, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(35, 16), MMTuple( ClassDerived, MMTuple( MMString("short"), OmnipotentCharCXX, MConstInt(0)), MConstInt(Compiler.PtrSize)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Load, MMTuple( MMTuple( MMString("vtable pointer"), MMTuple( MMString("Simple C++ TBAA")), MConstInt(0)), MSameAs(0), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(77, 32), MMTuple( ClassBase, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); } TEST(TBAAMetadataTest, TemplSpec) { const char TestProgram[] = R"**( template struct ABC { T1 f1; T2 f2; }; void func(ABC *p) { p->f1 = 12.1; p->f2 = 44; } )**"; TestCompiler Compiler; Compiler.compiler.getLangOpts().CPlusPlus = 1; Compiler.compiler.getLangOpts().CPlusPlus11 = 1; Compiler.init(TestProgram); const BasicBlock *BB = Compiler.compile(); auto SpecABC = MMTuple( MMString("_ZTS3ABCIdiE"), MMTuple( MMString("double"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0), MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(8)); const Instruction *I = match(BB, MInstruction(Instruction::Store, MValType(MType([](const Type &T)->bool { return T.isDoubleTy(); })), MMTuple( SpecABC, MMTuple( MMString("double"), OmnipotentCharCXX, MConstInt(0)), MConstInt(0)))); ASSERT_TRUE(I); I = matchNext(I, MInstruction(Instruction::Store, MConstInt(44, 32), MMTuple( SpecABC, MMTuple( MMString("int"), OmnipotentCharCXX, MConstInt(0)), MConstInt(8)))); ASSERT_TRUE(I); } }