Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,80 @@
//===- unittests/CodeGen/BufferSourceTest.cpp - MemoryBuffer source tests -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace clang;
namespace {
// Emitting constructors for global objects involves looking
// at the source file name. This makes sure that we don't crash
// if the source file is a memory buffer.
const char TestProgram[] =
"class EmitCXXGlobalInitFunc "
"{ "
"public: "
" EmitCXXGlobalInitFunc() {} "
"}; "
"EmitCXXGlobalInitFunc test; ";
TEST(BufferSourceTest, EmitCXXGlobalInitFunc) {
LLVMContext Context;
CompilerInstance compiler;
compiler.createDiagnostics();
compiler.getLangOpts().CPlusPlus = 1;
compiler.getLangOpts().CPlusPlus11 = 1;
compiler.getTargetOpts().Triple = llvm::Triple::normalize(
llvm::sys::getProcessTriple());
compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
compiler.getDiagnostics(),
std::make_shared<clang::TargetOptions>(
compiler.getTargetOpts())));
compiler.createFileManager();
compiler.createSourceManager(compiler.getFileManager());
compiler.createPreprocessor(clang::TU_Prefix);
compiler.createASTContext();
compiler.setASTConsumer(std::unique_ptr<ASTConsumer>(
CreateLLVMCodeGen(
compiler.getDiagnostics(),
"EmitCXXGlobalInitFuncTest",
compiler.getHeaderSearchOpts(),
compiler.getPreprocessorOpts(),
compiler.getCodeGenOpts(),
Context)));
compiler.createSema(clang::TU_Prefix, nullptr);
clang::SourceManager &sm = compiler.getSourceManager();
sm.setMainFileID(sm.createFileID(
llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User));
clang::ParseAST(compiler.getSema(), false, false);
}
} // end anonymous namespace

View File

@@ -0,0 +1,21 @@
set(LLVM_LINK_COMPONENTS
Core
Support
)
add_clang_unittest(ClangCodeGenTests
BufferSourceTest.cpp
CodeGenExternalTest.cpp
IncrementalProcessingTest.cpp
TBAAMetadataTest.cpp
)
target_link_libraries(ClangCodeGenTests
PRIVATE
clangAST
clangBasic
clangCodeGen
clangFrontend
clangLex
clangParse
)

View File

@@ -0,0 +1,302 @@
//===- unittests/CodeGen/CodeGenExternalTest.cpp - test external CodeGen -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CodeGenABITypes.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace clang;
namespace {
// Mocks up a language using Clang code generation as a library and
// tests some basic functionality there.
// - CodeGen->GetAddrOfGlobal
// - CodeGen::convertTypeForMemory
// - CodeGen::getLLVMFieldNumber
static const bool DebugThisTest = false;
// forward declarations
struct MyASTConsumer;
static void test_codegen_fns(MyASTConsumer *my);
static bool test_codegen_fns_ran;
// This forwards the calls to the Clang CodeGenerator
// so that we can test CodeGen functions while it is open.
// It accumulates toplevel decls in HandleTopLevelDecl and
// calls test_codegen_fns() in HandleTranslationUnit
// before forwarding that function to the CodeGenerator.
struct MyASTConsumer : public ASTConsumer {
std::unique_ptr<CodeGenerator> Builder;
std::vector<Decl*> toplevel_decls;
MyASTConsumer(std::unique_ptr<CodeGenerator> Builder_in)
: ASTConsumer(), Builder(std::move(Builder_in))
{
}
~MyASTConsumer() { }
void Initialize(ASTContext &Context) override;
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override;
bool HandleTopLevelDecl(DeclGroupRef D) override;
void HandleInlineFunctionDefinition(FunctionDecl *D) override;
void HandleInterestingDecl(DeclGroupRef D) override;
void HandleTranslationUnit(ASTContext &Ctx) override;
void HandleTagDeclDefinition(TagDecl *D) override;
void HandleTagDeclRequiredDefinition(const TagDecl *D) override;
void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override;
void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override;
void HandleImplicitImportDecl(ImportDecl *D) override;
void CompleteTentativeDefinition(VarDecl *D) override;
void AssignInheritanceModel(CXXRecordDecl *RD) override;
void HandleVTable(CXXRecordDecl *RD) override;
ASTMutationListener *GetASTMutationListener() override;
ASTDeserializationListener *GetASTDeserializationListener() override;
void PrintStats() override;
bool shouldSkipFunctionBody(Decl *D) override;
};
void MyASTConsumer::Initialize(ASTContext &Context) {
Builder->Initialize(Context);
}
bool MyASTConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
toplevel_decls.push_back(*I);
}
return Builder->HandleTopLevelDecl(DG);
}
void MyASTConsumer::HandleInlineFunctionDefinition(FunctionDecl *D) {
Builder->HandleInlineFunctionDefinition(D);
}
void MyASTConsumer::HandleInterestingDecl(DeclGroupRef D) {
Builder->HandleInterestingDecl(D);
}
void MyASTConsumer::HandleTranslationUnit(ASTContext &Context) {
test_codegen_fns(this);
// HandleTranslationUnit can close the module
Builder->HandleTranslationUnit(Context);
}
void MyASTConsumer::HandleTagDeclDefinition(TagDecl *D) {
Builder->HandleTagDeclDefinition(D);
}
void MyASTConsumer::HandleTagDeclRequiredDefinition(const TagDecl *D) {
Builder->HandleTagDeclRequiredDefinition(D);
}
void MyASTConsumer::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
Builder->HandleCXXImplicitFunctionInstantiation(D);
}
void MyASTConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
Builder->HandleTopLevelDeclInObjCContainer(D);
}
void MyASTConsumer::HandleImplicitImportDecl(ImportDecl *D) {
Builder->HandleImplicitImportDecl(D);
}
void MyASTConsumer::CompleteTentativeDefinition(VarDecl *D) {
Builder->CompleteTentativeDefinition(D);
}
void MyASTConsumer::AssignInheritanceModel(CXXRecordDecl *RD) {
Builder->AssignInheritanceModel(RD);
}
void MyASTConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
Builder->HandleCXXStaticMemberVarInstantiation(VD);
}
void MyASTConsumer::HandleVTable(CXXRecordDecl *RD) {
Builder->HandleVTable(RD);
}
ASTMutationListener *MyASTConsumer::GetASTMutationListener() {
return Builder->GetASTMutationListener();
}
ASTDeserializationListener *MyASTConsumer::GetASTDeserializationListener() {
return Builder->GetASTDeserializationListener();
}
void MyASTConsumer::PrintStats() {
Builder->PrintStats();
}
bool MyASTConsumer::shouldSkipFunctionBody(Decl *D) {
return Builder->shouldSkipFunctionBody(D);
}
const char TestProgram[] =
"struct mytest_struct { char x; short y; char p; long z; };\n"
"int mytest_fn(int x) { return x; }\n";
// This function has the real test code here
static void test_codegen_fns(MyASTConsumer *my) {
bool mytest_fn_ok = false;
bool mytest_struct_ok = false;
CodeGen::CodeGenModule &CGM = my->Builder->CGM();
for (auto decl : my->toplevel_decls ) {
if (FunctionDecl *fd = dyn_cast<FunctionDecl>(decl)) {
if (fd->getName() == "mytest_fn") {
Constant *c = my->Builder->GetAddrOfGlobal(GlobalDecl(fd), false);
// Verify that we got a function.
ASSERT_TRUE(c != NULL);
if (DebugThisTest) {
c->print(dbgs(), true);
dbgs() << "\n";
}
mytest_fn_ok = true;
}
} else if(clang::RecordDecl *rd = dyn_cast<RecordDecl>(decl)) {
if (rd->getName() == "mytest_struct") {
RecordDecl *def = rd->getDefinition();
ASSERT_TRUE(def != NULL);
const clang::Type *clangTy = rd->getCanonicalDecl()->getTypeForDecl();
ASSERT_TRUE(clangTy != NULL);
QualType qType = clangTy->getCanonicalTypeInternal();
// Check convertTypeForMemory
llvm::Type *llvmTy = CodeGen::convertTypeForMemory(CGM, qType);
ASSERT_TRUE(llvmTy != NULL);
if (DebugThisTest) {
llvmTy->print(dbgs(), true);
dbgs() << "\n";
}
llvm::CompositeType* structTy = dyn_cast<CompositeType>(llvmTy);
ASSERT_TRUE(structTy != NULL);
// Check getLLVMFieldNumber
FieldDecl *xField = NULL;
FieldDecl *yField = NULL;
FieldDecl *zField = NULL;
for (auto field : rd->fields()) {
if (field->getName() == "x") xField = field;
if (field->getName() == "y") yField = field;
if (field->getName() == "z") zField = field;
}
ASSERT_TRUE(xField != NULL);
ASSERT_TRUE(yField != NULL);
ASSERT_TRUE(zField != NULL);
unsigned x = CodeGen::getLLVMFieldNumber(CGM, rd, xField);
unsigned y = CodeGen::getLLVMFieldNumber(CGM, rd, yField);
unsigned z = CodeGen::getLLVMFieldNumber(CGM, rd, zField);
ASSERT_NE(x, y);
ASSERT_NE(y, z);
llvm::Type* xTy = structTy->getTypeAtIndex(x);
llvm::Type* yTy = structTy->getTypeAtIndex(y);
llvm::Type* zTy = structTy->getTypeAtIndex(z);
ASSERT_TRUE(xTy != NULL);
ASSERT_TRUE(yTy != NULL);
ASSERT_TRUE(zTy != NULL);
if (DebugThisTest) {
xTy->print(dbgs(), true);
dbgs() << "\n";
yTy->print(dbgs(), true);
dbgs() << "\n";
zTy->print(dbgs(), true);
dbgs() << "\n";
}
ASSERT_GE(xTy->getPrimitiveSizeInBits(), 1u);
ASSERT_GE(yTy->getPrimitiveSizeInBits(), 16u); // short is at least 16b
ASSERT_GE(zTy->getPrimitiveSizeInBits(), 32u); // long is at least 32b
mytest_struct_ok = true;
}
}
}
ASSERT_TRUE(mytest_fn_ok);
ASSERT_TRUE(mytest_struct_ok);
test_codegen_fns_ran = true;
}
TEST(CodeGenExternalTest, CodeGenExternalTest) {
LLVMContext Context;
CompilerInstance compiler;
compiler.createDiagnostics();
compiler.getLangOpts().CPlusPlus = 1;
compiler.getLangOpts().CPlusPlus11 = 1;
compiler.getTargetOpts().Triple = llvm::Triple::normalize(
llvm::sys::getProcessTriple());
compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
compiler.getDiagnostics(),
std::make_shared<clang::TargetOptions>(
compiler.getTargetOpts())));
compiler.createFileManager();
compiler.createSourceManager(compiler.getFileManager());
compiler.createPreprocessor(clang::TU_Prefix);
compiler.createASTContext();
compiler.setASTConsumer(std::unique_ptr<ASTConsumer>(
new MyASTConsumer(std::unique_ptr<CodeGenerator>(
CreateLLVMCodeGen(compiler.getDiagnostics(),
"MemoryTypesTest",
compiler.getHeaderSearchOpts(),
compiler.getPreprocessorOpts(),
compiler.getCodeGenOpts(),
Context)))));
compiler.createSema(clang::TU_Prefix, nullptr);
clang::SourceManager &sm = compiler.getSourceManager();
sm.setMainFileID(sm.createFileID(
llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User));
clang::ParseAST(compiler.getSema(), false, false);
ASSERT_TRUE(test_codegen_fns_ran);
}
} // end anonymous namespace

View File

@@ -0,0 +1,453 @@
//=== unittests/CodeGen/IRMatchers.h - Match on the LLVM IR -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file provides a simple mechanism for performing search operations over
/// IR including metadata and types. It allows writing complex search patterns
/// using understandable syntax. For instance, the code:
///
/// \code
/// const BasicBlock *BB = ...
/// const Instruction *I = match(BB,
/// MInstruction(Instruction::Store,
/// MConstInt(4, 8),
/// MMTuple(
/// MMTuple(
/// MMString("omnipotent char"),
/// MMTuple(
/// MMString("Simple C/C++ TBAA")),
/// MConstInt(0, 64)),
/// MSameAs(0),
/// MConstInt(0))));
/// \endcode
///
/// searches the basic block BB for the 'store' instruction, first argument of
/// which is 'i8 4', and the attached metadata has an item described by the
/// given tree.
//===----------------------------------------------------------------------===//
#ifndef CLANG_UNITTESTS_CODEGEN_IRMATCHERS_H
#define CLANG_UNITTESTS_CODEGEN_IRMATCHERS_H
#include "llvm/ADT/PointerUnion.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Value.h"
namespace llvm {
/// Keeps information about pending match queries.
///
/// This class stores state of all unfinished match actions. It allows to
/// use queries like "this operand is the same as n-th operand", which are
/// hard to implement otherwise.
///
class MatcherContext {
public:
/// Describes pending match query.
///
/// The query is represented by the current entity being investigated (type,
/// value or metadata). If the entity is a member of a list (like arguments),
/// the query also keeps the entity number in that list.
///
class Query {
PointerUnion3<const Value *, const Metadata *, const Type *> Entity;
unsigned OperandNo;
public:
Query(const Value *V, unsigned N) : Entity(V), OperandNo(N) {}
Query(const Metadata *M, unsigned N) : Entity(M), OperandNo(N) {}
Query(const Type *T, unsigned N) : Entity(T), OperandNo(N) {}
template<typename T>
const T *get() const {
return Entity.dyn_cast<const T *>();
}
unsigned getOperandNo() const { return OperandNo; }
};
template<typename T>
void push(const T *V, unsigned N = ~0) {
MatchStack.push_back(Query(V, N));
}
void pop() { MatchStack.pop_back(); }
template<typename T>
const T *top() const { return MatchStack.back().get<T>(); }
size_t size() const { return MatchStack.size(); }
unsigned getOperandNo() const { return MatchStack.back().getOperandNo(); }
/// Returns match query at the given offset from the top of queries.
///
/// Offset 0 corresponds to the topmost query.
///
const Query &getQuery(unsigned Offset) const {
assert(MatchStack.size() > Offset);
return MatchStack[MatchStack.size() - 1 - Offset];
}
private:
SmallVector<Query, 8> MatchStack;
};
/// Base of all matcher classes.
///
class Matcher {
public:
virtual ~Matcher() {}
/// Returns true if the entity on the top of the specified context satisfies
/// the matcher condition.
///
virtual bool match(MatcherContext &MC) = 0;
};
/// Base class of matchers that test particular entity.
///
template<typename T>
class EntityMatcher : public Matcher {
public:
bool match(MatcherContext &MC) override {
if (auto V = MC.top<T>())
return matchEntity(*V, MC);
return false;
}
virtual bool matchEntity(const T &M, MatcherContext &C) = 0;
};
/// Matcher that matches any entity of the specified kind.
///
template<typename T>
class AnyMatcher : public EntityMatcher<T> {
public:
bool matchEntity(const T &M, MatcherContext &C) override { return true; }
};
/// Matcher that tests if the current entity satisfies the specified
/// condition.
///
template<typename T>
class CondMatcher : public EntityMatcher<T> {
std::function<bool(const T &)> Condition;
public:
CondMatcher(std::function<bool(const T &)> C) : Condition(C) {}
bool matchEntity(const T &V, MatcherContext &C) override {
return Condition(V);
}
};
/// Matcher that save pointer to the entity that satisfies condition of the
// specified matcher.
///
template<typename T>
class SavingMatcher : public EntityMatcher<T> {
const T *&Var;
std::shared_ptr<Matcher> Next;
public:
SavingMatcher(const T *&V, std::shared_ptr<Matcher> N) : Var(V), Next(N) {}
bool matchEntity(const T &V, MatcherContext &C) override {
bool Result = Next->match(C);
if (Result)
Var = &V;
return Result;
}
};
/// Matcher that checks that the entity is identical to another entity in the
/// same container.
///
class SameAsMatcher : public Matcher {
unsigned OpNo;
public:
SameAsMatcher(unsigned N) : OpNo(N) {}
bool match(MatcherContext &C) override {
if (C.getOperandNo() != ~0U) {
// Handle all known containers here.
const MatcherContext::Query &StackRec = C.getQuery(1);
if (const Metadata *MR = StackRec.get<Metadata>()) {
if (const auto *MT = dyn_cast<MDTuple>(MR)) {
if (OpNo < MT->getNumOperands())
return C.top<Metadata>() == MT->getOperand(OpNo).get();
return false;
}
llvm_unreachable("Unknown metadata container");
}
if (const Value *VR = StackRec.get<Value>()) {
if (const auto *Insn = dyn_cast<Instruction>(VR)) {
if (OpNo < Insn->getNumOperands())
return C.top<Value>() == Insn->getOperand(OpNo);
return false;
}
llvm_unreachable("Unknown value container");
}
llvm_unreachable("Unknown type container");
}
return false;
}
};
/// Matcher that tests if the entity is a constant integer.
///
class ConstantIntMatcher : public Matcher {
uint64_t IntValue;
unsigned Width;
public:
ConstantIntMatcher(uint64_t V, unsigned W = 0) : IntValue(V), Width(W) {}
bool match(MatcherContext &Ctx) override {
if (const Value *V = Ctx.top<Value>()) {
if (const auto *CI = dyn_cast<ConstantInt>(V))
return (Width == 0 || CI->getBitWidth() == Width) &&
CI->getLimitedValue() == IntValue;
}
if (const Metadata *M = Ctx.top<Metadata>()) {
if (const auto *MT = dyn_cast<ValueAsMetadata>(M))
if (const auto *C = dyn_cast<ConstantInt>(MT->getValue()))
return (Width == 0 || C->getBitWidth() == Width) &&
C->getLimitedValue() == IntValue;
}
return false;
}
};
/// Value matcher tuned to test instructions.
///
class InstructionMatcher : public EntityMatcher<Value> {
SmallVector<std::shared_ptr<Matcher>, 8> OperandMatchers;
std::shared_ptr<EntityMatcher<Metadata>> MetaMatcher = nullptr;
unsigned Code;
public:
InstructionMatcher(unsigned C) : Code(C) {}
void push(std::shared_ptr<EntityMatcher<Metadata>> M) {
assert(!MetaMatcher && "Only one metadata matcher may be specified");
MetaMatcher = M;
}
void push(std::shared_ptr<Matcher> V) { OperandMatchers.push_back(V); }
template<typename... Args>
void push(std::shared_ptr<Matcher> V, Args... A) {
push(V);
push(A...);
}
virtual bool matchInstruction(const Instruction &I) {
return I.getOpcode() == Code;
}
bool matchEntity(const Value &V, MatcherContext &C) override {
if (const auto *I = dyn_cast<Instruction>(&V)) {
if (!matchInstruction(*I))
return false;
if (OperandMatchers.size() > I->getNumOperands())
return false;
for (unsigned N = 0, E = OperandMatchers.size(); N != E; ++N) {
C.push(I->getOperand(N), N);
if (!OperandMatchers[N]->match(C)) {
C.pop();
return false;
}
C.pop();
}
if (MetaMatcher) {
SmallVector<std::pair<unsigned, MDNode *>, 8> MDs;
I->getAllMetadata(MDs);
bool Found = false;
for (auto Item : MDs) {
C.push(Item.second);
if (MetaMatcher->match(C)) {
Found = true;
C.pop();
break;
}
C.pop();
}
return Found;
}
return true;
}
return false;
}
};
/// Matcher that tests type of the current value using the specified
/// type matcher.
///
class ValueTypeMatcher : public EntityMatcher<Value> {
std::shared_ptr<EntityMatcher<Type>> TyM;
public:
ValueTypeMatcher(std::shared_ptr<EntityMatcher<Type>> T) : TyM(T) {}
ValueTypeMatcher(const Type *T)
: TyM(new CondMatcher<Type>([T](const Type &Ty) -> bool {
return &Ty == T;
})) {}
bool matchEntity(const Value &V, MatcherContext &Ctx) override {
Type *Ty = V.getType();
Ctx.push(Ty);
bool Res = TyM->match(Ctx);
Ctx.pop();
return Res;
}
};
/// Matcher that matches string metadata.
///
class NameMetaMatcher : public EntityMatcher<Metadata> {
StringRef Name;
public:
NameMetaMatcher(StringRef N) : Name(N) {}
bool matchEntity(const Metadata &M, MatcherContext &C) override {
if (auto *MDS = dyn_cast<MDString>(&M))
return MDS->getString().equals(Name);
return false;
}
};
/// Matcher that matches metadata tuples.
///
class MTupleMatcher : public EntityMatcher<Metadata> {
SmallVector<std::shared_ptr<Matcher>, 4> Operands;
public:
void push(std::shared_ptr<Matcher> M) { Operands.push_back(M); }
template<typename... Args>
void push(std::shared_ptr<Matcher> M, Args... A) {
push(M);
push(A...);
}
bool matchEntity(const Metadata &M, MatcherContext &C) override {
if (const auto *MT = dyn_cast<MDTuple>(&M)) {
if (MT->getNumOperands() != Operands.size())
return false;
for (unsigned I = 0, E = MT->getNumOperands(); I != E; ++I) {
const MDOperand &Op = MT->getOperand(I);
C.push(Op.get(), I);
if (!Operands[I]->match(C)) {
C.pop();
return false;
}
C.pop();
}
return true;
}
return false;
}
};
// Helper function used to construct matchers.
std::shared_ptr<Matcher> MSameAs(unsigned N) {
return std::shared_ptr<Matcher>(new SameAsMatcher(N));
}
template<typename... T>
std::shared_ptr<InstructionMatcher> MInstruction(unsigned C, T... Args) {
auto Result = new InstructionMatcher(C);
Result->push(Args...);
return std::shared_ptr<InstructionMatcher>(Result);
}
std::shared_ptr<Matcher> MConstInt(uint64_t V, unsigned W = 0) {
return std::shared_ptr<Matcher>(new ConstantIntMatcher(V, W));
}
std::shared_ptr<EntityMatcher<Value>>
MValType(std::shared_ptr<EntityMatcher<Type>> T) {
return std::shared_ptr<EntityMatcher<Value>>(new ValueTypeMatcher(T));
}
std::shared_ptr<EntityMatcher<Value>> MValType(const Type *T) {
return std::shared_ptr<EntityMatcher<Value>>(new ValueTypeMatcher(T));
}
std::shared_ptr<EntityMatcher<Type>>
MType(std::function<bool(const Type &)> C) {
return std::shared_ptr<EntityMatcher<Type>>(new CondMatcher<Type>(C));
}
std::shared_ptr<EntityMatcher<Metadata>> MMAny() {
return std::shared_ptr<EntityMatcher<Metadata>>(new AnyMatcher<Metadata>);
}
std::shared_ptr<EntityMatcher<Metadata>>
MMSave(const Metadata *&V, std::shared_ptr<EntityMatcher<Metadata>> M) {
return std::shared_ptr<EntityMatcher<Metadata>>(
new SavingMatcher<Metadata>(V, M));
}
std::shared_ptr<EntityMatcher<Metadata>>
MMString(const char *Name) {
return std::shared_ptr<EntityMatcher<Metadata>>(new NameMetaMatcher(Name));
}
template<typename... T>
std::shared_ptr<EntityMatcher<Metadata>> MMTuple(T... Args) {
auto Res = new MTupleMatcher();
Res->push(Args...);
return std::shared_ptr<EntityMatcher<Metadata>>(Res);
}
/// Looks for the instruction that satisfies condition of the specified
/// matcher inside the given basic block.
/// \returns Pointer to the found instruction or nullptr if such instruction
/// was not found.
///
const Instruction *match(const BasicBlock *BB, std::shared_ptr<Matcher> M) {
MatcherContext MC;
for (const auto &I : *BB) {
MC.push(&I);
if (M->match(MC))
return &I;
MC.pop();
}
assert(MC.size() == 0);
return nullptr;
}
/// Looks for the instruction that satisfies condition of the specified
/// matcher starting from the specified instruction inside the same basic block.
///
/// The given instruction is not checked.
///
const Instruction *matchNext(const Instruction *I, std::shared_ptr<Matcher> M) {
if (!I)
return nullptr;
MatcherContext MC;
const BasicBlock *BB = I->getParent();
if (!BB)
return nullptr;
for (auto P = ++BasicBlock::const_iterator(I), E = BB->end(); P != E; ++P) {
MC.push(&*P);
if (M->match(MC))
return &*P;
MC.pop();
}
assert(MC.size() == 0);
return nullptr;
}
}
#endif

View File

@@ -0,0 +1,174 @@
//=== unittests/CodeGen/IncrementalProcessingTest.cpp - IncrementalCodeGen ===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/Triple.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;
using namespace clang;
namespace {
// Incremental processing produces several modules, all using the same "main
// file". Make sure CodeGen can cope with that, e.g. for static initializers.
const char TestProgram1[] =
"extern \"C\" int funcForProg1() { return 17; }\n"
"struct EmitCXXGlobalInitFunc1 {\n"
" EmitCXXGlobalInitFunc1() {}\n"
"} test1;";
const char TestProgram2[] =
"extern \"C\" int funcForProg2() { return 42; }\n"
"struct EmitCXXGlobalInitFunc2 {\n"
" EmitCXXGlobalInitFunc2() {}\n"
"} test2;";
/// An incremental version of ParseAST().
static std::unique_ptr<llvm::Module>
IncrementalParseAST(CompilerInstance& CI, Parser& P,
CodeGenerator& CG, const char* code) {
static int counter = 0;
struct IncreaseCounterOnRet {
~IncreaseCounterOnRet() {
++counter;
}
} ICOR;
Sema& S = CI.getSema();
clang::SourceManager &SM = S.getSourceManager();
if (!code) {
// Main file
SM.setMainFileID(SM.createFileID(
llvm::MemoryBuffer::getMemBuffer(" "), clang::SrcMgr::C_User));
S.getPreprocessor().EnterMainSourceFile();
P.Initialize();
} else {
FileID FID = SM.createFileID(
llvm::MemoryBuffer::getMemBuffer(code), clang::SrcMgr::C_User);
SourceLocation MainStartLoc = SM.getLocForStartOfFile(SM.getMainFileID());
SourceLocation InclLoc = MainStartLoc.getLocWithOffset(counter);
S.getPreprocessor().EnterSourceFile(FID, 0, InclLoc);
}
ExternalASTSource *External = S.getASTContext().getExternalSource();
if (External)
External->StartTranslationUnit(&CG);
Parser::DeclGroupPtrTy ADecl;
for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
AtEOF = P.ParseTopLevelDecl(ADecl)) {
// If we got a null return and something *was* parsed, ignore it. This
// is due to a top-level semicolon, an action override, or a parse error
// skipping something.
if (ADecl && !CG.HandleTopLevelDecl(ADecl.get()))
return nullptr;
}
// Process any TopLevelDecls generated by #pragma weak.
for (Decl *D : S.WeakTopLevelDecls())
CG.HandleTopLevelDecl(DeclGroupRef(D));
CG.HandleTranslationUnit(S.getASTContext());
std::unique_ptr<llvm::Module> M(CG.ReleaseModule());
// Switch to next module.
CG.StartModule("incremental-module-" + std::to_string(counter),
M->getContext());
return M;
}
const Function* getGlobalInit(llvm::Module& M) {
for (const auto& Func: M)
if (Func.hasName() && Func.getName().startswith("_GLOBAL__sub_I_"))
return &Func;
return nullptr;
}
TEST(IncrementalProcessing, EmitCXXGlobalInitFunc) {
LLVMContext Context;
CompilerInstance compiler;
compiler.createDiagnostics();
compiler.getLangOpts().CPlusPlus = 1;
compiler.getLangOpts().CPlusPlus11 = 1;
compiler.getTargetOpts().Triple = llvm::Triple::normalize(
llvm::sys::getProcessTriple());
compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
compiler.getDiagnostics(),
std::make_shared<clang::TargetOptions>(
compiler.getTargetOpts())));
compiler.createFileManager();
compiler.createSourceManager(compiler.getFileManager());
compiler.createPreprocessor(clang::TU_Prefix);
compiler.getPreprocessor().enableIncrementalProcessing();
compiler.createASTContext();
CodeGenerator* CG =
CreateLLVMCodeGen(
compiler.getDiagnostics(),
"main-module",
compiler.getHeaderSearchOpts(),
compiler.getPreprocessorOpts(),
compiler.getCodeGenOpts(),
Context);
compiler.setASTConsumer(std::unique_ptr<ASTConsumer>(CG));
compiler.createSema(clang::TU_Prefix, nullptr);
Sema& S = compiler.getSema();
std::unique_ptr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
/*SkipFunctionBodies*/ false));
Parser &P = *ParseOP.get();
std::array<std::unique_ptr<llvm::Module>, 3> M;
M[0] = IncrementalParseAST(compiler, P, *CG, nullptr);
ASSERT_TRUE(M[0]);
M[1] = IncrementalParseAST(compiler, P, *CG, TestProgram1);
ASSERT_TRUE(M[1]);
ASSERT_TRUE(M[1]->getFunction("funcForProg1"));
M[2] = IncrementalParseAST(compiler, P, *CG, TestProgram2);
ASSERT_TRUE(M[2]);
ASSERT_TRUE(M[2]->getFunction("funcForProg2"));
// First code should not end up in second module:
ASSERT_FALSE(M[2]->getFunction("funcForProg1"));
// Make sure global inits exist and are unique:
const Function* GlobalInit1 = getGlobalInit(*M[1]);
ASSERT_TRUE(GlobalInit1);
const Function* GlobalInit2 = getGlobalInit(*M[2]);
ASSERT_TRUE(GlobalInit2);
ASSERT_FALSE(GlobalInit1->getName() == GlobalInit2->getName());
}
} // end anonymous namespace

File diff suppressed because it is too large Load Diff