| //=== unittests/CodeGen/TBAAMetadataTest.cpp - Checks metadata generation -===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "IRMatchers.h" |
| #include "clang/AST/ASTConsumer.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/Basic/SourceManager.h" |
| #include "clang/Basic/TargetInfo.h" |
| #include "clang/CodeGen/ModuleBuilder.h" |
| #include "clang/Frontend/CompilerInstance.h" |
| #include "clang/Parse/ParseAST.h" |
| #include "llvm/ADT/Triple.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/LLVMContext.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Support/Host.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "gtest/gtest.h" |
| #include <memory> |
| |
| 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<clang::TargetOptions>(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<clang::ASTConsumer>(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<typename T1, typename T2> |
| struct ABC { |
| T1 f1; |
| T2 f2; |
| }; |
| |
| void func(ABC<double, int> *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); |
| } |
| } |