mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-19 07:06:07 +00:00

Now tests for metadata created by clang involve compiling code snippets placed into c/c++ source files and matching interesting patterns in the obtained textual representation of IR. Writting such tests is a painful process as metadata often form complex tree-like structures but textual representation of IR contains only a pile of metadata at the module end. This change implements IR matchers that may be used to match required patterns in the binary IR representation. In this case the metadata structure is not broken and creation of match patterns is easier. The change adds unit tests for TBAA metadata generation. Differential Revision: https://reviews.llvm.org/D41433 llvm-svn: 321360
1300 lines
29 KiB
C++
1300 lines
29 KiB
C++
//=== 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 <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);
|
|
}
|
|
}
|