|  | //=== 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 "TestCompiler.h" | 
|  | #include "clang/AST/ASTConsumer.h" | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/Basic/SourceManager.h" | 
|  | #include "clang/Basic/TargetInfo.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/Support/MemoryBuffer.h" | 
|  | #include "gtest/gtest.h" | 
|  | #include <memory> | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct TBAATestCompiler : public TestCompiler { | 
|  | TBAATestCompiler(clang::LangOptions LO, clang::CodeGenOptions CGO) | 
|  | : TestCompiler(LO, CGO) {} | 
|  | static clang::CodeGenOptions getCommonCodeGenOpts() { | 
|  | clang::CodeGenOptions CGOpts; | 
|  | CGOpts.StructPathTBAA = 1; | 
|  | CGOpts.OptimizationLevel = 1; | 
|  | return CGOpts; | 
|  | } | 
|  | }; | 
|  |  | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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(PointerType::getUnqual(Compiler.Context)), | 
|  | MMTuple( | 
|  | MMTuple( | 
|  | MMString("any pointer"), | 
|  | OmnipotentCharC, | 
|  | MConstInt(0)), | 
|  | MSameAs(0), | 
|  | MConstInt(0)))); | 
|  | ASSERT_TRUE(I); | 
|  |  | 
|  | I = matchNext(I, | 
|  | MInstruction(Instruction::Store, | 
|  | MValType(PointerType::getUnqual(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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.C11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.C11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.C11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.C11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.CPlusPlus = 1; | 
|  | LO.CPlusPlus11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.CPlusPlus = 1; | 
|  | LO.CPlusPlus11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.CPlusPlus = 1; | 
|  | LO.CPlusPlus11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.CPlusPlus = 1; | 
|  | LO.CPlusPlus11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.CPlusPlus = 1; | 
|  | LO.CPlusPlus11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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"), ClassBase, MConstInt(0), | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.CPlusPlus = 1; | 
|  | LO.CPlusPlus11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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"), ClassBase, MConstInt(0), | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.CPlusPlus = 1; | 
|  | LO.CPlusPlus11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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; | 
|  | } | 
|  | )**"; | 
|  |  | 
|  | clang::LangOptions LO; | 
|  | LO.CPlusPlus = 1; | 
|  | LO.CPlusPlus11 = 1; | 
|  | TBAATestCompiler Compiler(LO, TBAATestCompiler::getCommonCodeGenOpts()); | 
|  | 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); | 
|  | } | 
|  | } |