2013-11-09 13:26:54 +01:00
|
|
|
//===- llvm/unittest/IR/LegacyPassManager.cpp - Legacy PassManager tests --===//
|
2009-06-29 20:49:09 +02:00
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// 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
|
2009-06-29 20:49:09 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2013-11-09 13:26:54 +01:00
|
|
|
//
|
|
|
|
// This unit test exercises the legacy pass manager infrastructure. We use the
|
2015-02-13 11:01:29 +01:00
|
|
|
// old names as well to ensure that the source-level compatibility is preserved
|
|
|
|
// where possible.
|
2013-11-09 13:26:54 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-06-29 20:49:09 +02:00
|
|
|
|
2015-02-13 11:01:29 +01:00
|
|
|
#include "llvm/IR/LegacyPassManager.h"
|
2013-01-07 16:26:48 +01:00
|
|
|
#include "llvm/Analysis/CallGraphSCCPass.h"
|
2009-06-29 20:49:09 +02:00
|
|
|
#include "llvm/Analysis/LoopInfo.h"
|
|
|
|
#include "llvm/Analysis/LoopPass.h"
|
2020-07-27 15:02:06 +02:00
|
|
|
#include "llvm/AsmParser/Parser.h"
|
|
|
|
#include "llvm/IR/AbstractCallSite.h"
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
|
|
#include "llvm/IR/CallingConv.h"
|
|
|
|
#include "llvm/IR/DataLayout.h"
|
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/GlobalVariable.h"
|
|
|
|
#include "llvm/IR/Instructions.h"
|
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
2018-04-05 12:29:37 +02:00
|
|
|
#include "llvm/IR/OptBisect.h"
|
2019-11-14 03:19:54 +01:00
|
|
|
#include "llvm/InitializePasses.h"
|
2009-06-29 20:49:09 +02:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2020-07-27 15:02:06 +02:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2009-06-29 20:49:09 +02:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2019-11-29 20:11:24 +01:00
|
|
|
#include "llvm/Transforms/Utils/CallGraphUpdater.h"
|
2009-06-29 20:49:09 +02:00
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
2010-10-19 19:21:58 +02:00
|
|
|
using namespace llvm;
|
|
|
|
|
2009-06-29 20:49:09 +02:00
|
|
|
namespace llvm {
|
2010-10-19 19:21:58 +02:00
|
|
|
void initializeModuleNDMPass(PassRegistry&);
|
|
|
|
void initializeFPassPass(PassRegistry&);
|
|
|
|
void initializeCGPassPass(PassRegistry&);
|
|
|
|
void initializeLPassPass(PassRegistry&);
|
2011-03-31 11:58:51 +02:00
|
|
|
|
2009-06-29 20:49:09 +02:00
|
|
|
namespace {
|
|
|
|
// ND = no deps
|
|
|
|
// NM = no modifications
|
|
|
|
struct ModuleNDNM: public ModulePass {
|
|
|
|
public:
|
|
|
|
static char run;
|
|
|
|
static char ID;
|
2010-10-19 19:21:58 +02:00
|
|
|
ModuleNDNM() : ModulePass(ID) { }
|
2014-09-10 17:50:08 +02:00
|
|
|
bool runOnModule(Module &M) override {
|
2009-06-29 20:49:09 +02:00
|
|
|
run++;
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-10 17:50:08 +02:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
2009-06-29 20:49:09 +02:00
|
|
|
AU.setPreservesAll();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
char ModuleNDNM::ID=0;
|
|
|
|
char ModuleNDNM::run=0;
|
|
|
|
|
|
|
|
struct ModuleNDM : public ModulePass {
|
|
|
|
public:
|
|
|
|
static char run;
|
|
|
|
static char ID;
|
2010-08-06 20:33:48 +02:00
|
|
|
ModuleNDM() : ModulePass(ID) {}
|
2014-09-10 17:50:08 +02:00
|
|
|
bool runOnModule(Module &M) override {
|
2009-06-29 20:49:09 +02:00
|
|
|
run++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
char ModuleNDM::ID=0;
|
|
|
|
char ModuleNDM::run=0;
|
|
|
|
|
|
|
|
struct ModuleNDM2 : public ModulePass {
|
|
|
|
public:
|
|
|
|
static char run;
|
|
|
|
static char ID;
|
2010-08-06 20:33:48 +02:00
|
|
|
ModuleNDM2() : ModulePass(ID) {}
|
2014-09-10 17:50:08 +02:00
|
|
|
bool runOnModule(Module &M) override {
|
2009-06-29 20:49:09 +02:00
|
|
|
run++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
char ModuleNDM2::ID=0;
|
|
|
|
char ModuleNDM2::run=0;
|
|
|
|
|
|
|
|
struct ModuleDNM : public ModulePass {
|
|
|
|
public:
|
|
|
|
static char run;
|
|
|
|
static char ID;
|
2010-10-19 19:21:58 +02:00
|
|
|
ModuleDNM() : ModulePass(ID) {
|
|
|
|
initializeModuleNDMPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
2014-09-10 17:50:08 +02:00
|
|
|
bool runOnModule(Module &M) override {
|
2009-06-29 20:49:09 +02:00
|
|
|
run++;
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-10 17:50:08 +02:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
2009-06-29 20:49:09 +02:00
|
|
|
AU.addRequired<ModuleNDM>();
|
|
|
|
AU.setPreservesAll();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
char ModuleDNM::ID=0;
|
|
|
|
char ModuleDNM::run=0;
|
|
|
|
|
|
|
|
template<typename P>
|
|
|
|
struct PassTestBase : public P {
|
|
|
|
protected:
|
|
|
|
static int runc;
|
|
|
|
static bool initialized;
|
|
|
|
static bool finalized;
|
|
|
|
int allocated;
|
|
|
|
void run() {
|
2010-07-13 19:28:05 +02:00
|
|
|
EXPECT_TRUE(initialized);
|
|
|
|
EXPECT_FALSE(finalized);
|
2009-06-29 20:49:09 +02:00
|
|
|
EXPECT_EQ(0, allocated);
|
|
|
|
allocated++;
|
|
|
|
runc++;
|
|
|
|
}
|
|
|
|
public:
|
|
|
|
static char ID;
|
|
|
|
static void finishedOK(int run) {
|
|
|
|
EXPECT_GT(runc, 0);
|
2010-07-13 19:28:05 +02:00
|
|
|
EXPECT_TRUE(initialized);
|
|
|
|
EXPECT_TRUE(finalized);
|
2009-06-29 20:49:09 +02:00
|
|
|
EXPECT_EQ(run, runc);
|
|
|
|
}
|
2010-08-06 20:33:48 +02:00
|
|
|
PassTestBase() : P(ID), allocated(0) {
|
2009-06-29 20:49:09 +02:00
|
|
|
initialized = false;
|
|
|
|
finalized = false;
|
|
|
|
runc = 0;
|
|
|
|
}
|
|
|
|
|
2014-09-10 17:50:08 +02:00
|
|
|
void releaseMemory() override {
|
2009-06-29 20:49:09 +02:00
|
|
|
EXPECT_GT(runc, 0);
|
|
|
|
EXPECT_GT(allocated, 0);
|
|
|
|
allocated--;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
template<typename P> char PassTestBase<P>::ID;
|
|
|
|
template<typename P> int PassTestBase<P>::runc;
|
|
|
|
template<typename P> bool PassTestBase<P>::initialized;
|
|
|
|
template<typename P> bool PassTestBase<P>::finalized;
|
|
|
|
|
|
|
|
template<typename T, typename P>
|
|
|
|
struct PassTest : public PassTestBase<P> {
|
|
|
|
public:
|
2012-12-04 08:25:24 +01:00
|
|
|
#ifndef _MSC_VER // MSVC complains that Pass is not base class.
|
2012-12-04 06:41:27 +01:00
|
|
|
using llvm::Pass::doInitialization;
|
|
|
|
using llvm::Pass::doFinalization;
|
2012-12-04 08:25:24 +01:00
|
|
|
#endif
|
2014-09-10 17:50:08 +02:00
|
|
|
bool doInitialization(T &t) override {
|
2010-07-13 19:28:05 +02:00
|
|
|
EXPECT_FALSE(PassTestBase<P>::initialized);
|
2009-06-29 20:49:09 +02:00
|
|
|
PassTestBase<P>::initialized = true;
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-10 17:50:08 +02:00
|
|
|
bool doFinalization(T &t) override {
|
2010-07-13 19:28:05 +02:00
|
|
|
EXPECT_FALSE(PassTestBase<P>::finalized);
|
2009-06-29 20:49:09 +02:00
|
|
|
PassTestBase<P>::finalized = true;
|
|
|
|
EXPECT_EQ(0, PassTestBase<P>::allocated);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct CGPass : public PassTest<CallGraph, CallGraphSCCPass> {
|
|
|
|
public:
|
2010-10-19 19:21:58 +02:00
|
|
|
CGPass() {
|
|
|
|
initializeCGPassPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
2014-09-10 17:50:08 +02:00
|
|
|
bool runOnSCC(CallGraphSCC &SCMM) override {
|
2009-06-29 20:49:09 +02:00
|
|
|
run();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct FPass : public PassTest<Module, FunctionPass> {
|
|
|
|
public:
|
2014-09-10 17:50:08 +02:00
|
|
|
bool runOnFunction(Function &F) override {
|
2009-06-29 20:49:09 +02:00
|
|
|
// FIXME: PR4112
|
2012-10-08 18:39:34 +02:00
|
|
|
// EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>());
|
2009-06-29 20:49:09 +02:00
|
|
|
run();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct LPass : public PassTestBase<LoopPass> {
|
|
|
|
private:
|
|
|
|
static int initcount;
|
|
|
|
static int fincount;
|
|
|
|
public:
|
|
|
|
LPass() {
|
2010-10-19 19:21:58 +02:00
|
|
|
initializeLPassPass(*PassRegistry::getPassRegistry());
|
2009-06-29 20:49:09 +02:00
|
|
|
initcount = 0; fincount=0;
|
2010-07-13 19:28:05 +02:00
|
|
|
EXPECT_FALSE(initialized);
|
2009-06-29 20:49:09 +02:00
|
|
|
}
|
|
|
|
static void finishedOK(int run, int finalized) {
|
|
|
|
PassTestBase<LoopPass>::finishedOK(run);
|
|
|
|
EXPECT_EQ(run, initcount);
|
|
|
|
EXPECT_EQ(finalized, fincount);
|
|
|
|
}
|
2012-12-04 06:41:27 +01:00
|
|
|
using llvm::Pass::doInitialization;
|
|
|
|
using llvm::Pass::doFinalization;
|
2014-09-10 17:50:08 +02:00
|
|
|
bool doInitialization(Loop* L, LPPassManager &LPM) override {
|
2009-06-29 20:49:09 +02:00
|
|
|
initialized = true;
|
|
|
|
initcount++;
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-10 17:50:08 +02:00
|
|
|
bool runOnLoop(Loop *L, LPPassManager &LPM) override {
|
2009-06-29 20:49:09 +02:00
|
|
|
run();
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-10 17:50:08 +02:00
|
|
|
bool doFinalization() override {
|
2009-06-29 20:49:09 +02:00
|
|
|
fincount++;
|
|
|
|
finalized = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
int LPass::initcount=0;
|
|
|
|
int LPass::fincount=0;
|
|
|
|
|
|
|
|
struct OnTheFlyTest: public ModulePass {
|
|
|
|
public:
|
|
|
|
static char ID;
|
2010-10-19 19:21:58 +02:00
|
|
|
OnTheFlyTest() : ModulePass(ID) {
|
|
|
|
initializeFPassPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
2014-09-10 17:50:08 +02:00
|
|
|
bool runOnModule(Module &M) override {
|
2009-06-29 20:49:09 +02:00
|
|
|
for (Module::iterator I=M.begin(),E=M.end(); I != E; ++I) {
|
|
|
|
Function &F = *I;
|
|
|
|
{
|
|
|
|
SCOPED_TRACE("Running on the fly function pass");
|
|
|
|
getAnalysis<FPass>(F);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-10 17:50:08 +02:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
2009-06-29 20:49:09 +02:00
|
|
|
AU.addRequired<FPass>();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
char OnTheFlyTest::ID=0;
|
|
|
|
|
|
|
|
TEST(PassManager, RunOnce) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext Context;
|
|
|
|
Module M("test-once", Context);
|
2009-06-29 20:49:09 +02:00
|
|
|
struct ModuleNDNM *mNDNM = new ModuleNDNM();
|
|
|
|
struct ModuleDNM *mDNM = new ModuleDNM();
|
|
|
|
struct ModuleNDM *mNDM = new ModuleNDM();
|
|
|
|
struct ModuleNDM2 *mNDM2 = new ModuleNDM2();
|
|
|
|
|
|
|
|
mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0;
|
|
|
|
|
2015-02-13 11:01:29 +01:00
|
|
|
legacy::PassManager Passes;
|
2009-06-29 20:49:09 +02:00
|
|
|
Passes.add(mNDM2);
|
|
|
|
Passes.add(mNDM);
|
|
|
|
Passes.add(mNDNM);
|
|
|
|
Passes.add(mDNM);
|
|
|
|
|
|
|
|
Passes.run(M);
|
|
|
|
// each pass must be run exactly once, since nothing invalidates them
|
|
|
|
EXPECT_EQ(1, mNDM->run);
|
|
|
|
EXPECT_EQ(1, mNDNM->run);
|
|
|
|
EXPECT_EQ(1, mDNM->run);
|
|
|
|
EXPECT_EQ(1, mNDM2->run);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PassManager, ReRun) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext Context;
|
|
|
|
Module M("test-rerun", Context);
|
2009-06-29 20:49:09 +02:00
|
|
|
struct ModuleNDNM *mNDNM = new ModuleNDNM();
|
|
|
|
struct ModuleDNM *mDNM = new ModuleDNM();
|
|
|
|
struct ModuleNDM *mNDM = new ModuleNDM();
|
|
|
|
struct ModuleNDM2 *mNDM2 = new ModuleNDM2();
|
|
|
|
|
|
|
|
mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0;
|
|
|
|
|
2015-02-13 11:01:29 +01:00
|
|
|
legacy::PassManager Passes;
|
2009-06-29 20:49:09 +02:00
|
|
|
Passes.add(mNDM);
|
|
|
|
Passes.add(mNDNM);
|
|
|
|
Passes.add(mNDM2);// invalidates mNDM needed by mDNM
|
|
|
|
Passes.add(mDNM);
|
|
|
|
|
|
|
|
Passes.run(M);
|
|
|
|
// Some passes must be rerun because a pass that modified the
|
2012-06-02 12:20:22 +02:00
|
|
|
// module/function was run in between
|
2009-06-29 20:49:09 +02:00
|
|
|
EXPECT_EQ(2, mNDM->run);
|
|
|
|
EXPECT_EQ(1, mNDNM->run);
|
|
|
|
EXPECT_EQ(1, mNDM2->run);
|
|
|
|
EXPECT_EQ(1, mDNM->run);
|
|
|
|
}
|
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
Module *makeLLVMModule(LLVMContext &Context);
|
2009-06-29 20:49:09 +02:00
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void MemoryTestHelper(int run) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext Context;
|
|
|
|
std::unique_ptr<Module> M(makeLLVMModule(Context));
|
2009-06-29 20:49:09 +02:00
|
|
|
T *P = new T();
|
2015-02-13 11:01:29 +01:00
|
|
|
legacy::PassManager Passes;
|
2009-06-29 20:49:09 +02:00
|
|
|
Passes.add(P);
|
|
|
|
Passes.run(*M);
|
|
|
|
T::finishedOK(run);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void MemoryTestHelper(int run, int N) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext Context;
|
|
|
|
Module *M = makeLLVMModule(Context);
|
2009-06-29 20:49:09 +02:00
|
|
|
T *P = new T();
|
2015-02-13 11:01:29 +01:00
|
|
|
legacy::PassManager Passes;
|
2009-06-29 20:49:09 +02:00
|
|
|
Passes.add(P);
|
|
|
|
Passes.run(*M);
|
|
|
|
T::finishedOK(run, N);
|
|
|
|
delete M;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PassManager, Memory) {
|
|
|
|
// SCC#1: test1->test2->test3->test1
|
|
|
|
// SCC#2: test4
|
|
|
|
// SCC#3: indirect call node
|
|
|
|
{
|
|
|
|
SCOPED_TRACE("Callgraph pass");
|
|
|
|
MemoryTestHelper<CGPass>(3);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
SCOPED_TRACE("Function pass");
|
|
|
|
MemoryTestHelper<FPass>(4);// 4 functions
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
SCOPED_TRACE("Loop pass");
|
|
|
|
MemoryTestHelper<LPass>(2, 1); //2 loops, 1 function
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PassManager, MemoryOnTheFly) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext Context;
|
|
|
|
Module *M = makeLLVMModule(Context);
|
2009-06-29 20:49:09 +02:00
|
|
|
{
|
|
|
|
SCOPED_TRACE("Running OnTheFlyTest");
|
|
|
|
struct OnTheFlyTest *O = new OnTheFlyTest();
|
2015-02-13 11:01:29 +01:00
|
|
|
legacy::PassManager Passes;
|
2009-06-29 20:49:09 +02:00
|
|
|
Passes.add(O);
|
|
|
|
Passes.run(*M);
|
|
|
|
|
|
|
|
FPass::finishedOK(4);
|
|
|
|
}
|
|
|
|
delete M;
|
|
|
|
}
|
|
|
|
|
2018-04-05 12:29:37 +02:00
|
|
|
// Skips or runs optional passes.
|
|
|
|
struct CustomOptPassGate : public OptPassGate {
|
|
|
|
bool Skip;
|
|
|
|
CustomOptPassGate(bool Skip) : Skip(Skip) { }
|
2020-07-17 05:36:46 +02:00
|
|
|
bool shouldRunPass(const Pass *P, StringRef IRDescription) override {
|
2019-02-28 05:00:55 +01:00
|
|
|
if (P->getPassKind() == PT_Module)
|
|
|
|
return !Skip;
|
|
|
|
return OptPassGate::shouldRunPass(P, IRDescription);
|
|
|
|
}
|
2020-07-17 05:36:46 +02:00
|
|
|
bool isEnabled() const override { return true; }
|
2018-04-05 12:29:37 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// Optional module pass.
|
|
|
|
struct ModuleOpt: public ModulePass {
|
|
|
|
char run = 0;
|
|
|
|
static char ID;
|
|
|
|
ModuleOpt() : ModulePass(ID) { }
|
|
|
|
bool runOnModule(Module &M) override {
|
|
|
|
if (!skipModule(M))
|
|
|
|
run++;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
char ModuleOpt::ID=0;
|
|
|
|
|
|
|
|
TEST(PassManager, CustomOptPassGate) {
|
|
|
|
LLVMContext Context0;
|
|
|
|
LLVMContext Context1;
|
|
|
|
LLVMContext Context2;
|
|
|
|
CustomOptPassGate SkipOptionalPasses(true);
|
|
|
|
CustomOptPassGate RunOptionalPasses(false);
|
|
|
|
|
|
|
|
Module M0("custom-opt-bisect", Context0);
|
|
|
|
Module M1("custom-opt-bisect", Context1);
|
|
|
|
Module M2("custom-opt-bisect2", Context2);
|
|
|
|
struct ModuleOpt *mOpt0 = new ModuleOpt();
|
|
|
|
struct ModuleOpt *mOpt1 = new ModuleOpt();
|
|
|
|
struct ModuleOpt *mOpt2 = new ModuleOpt();
|
|
|
|
|
|
|
|
mOpt0->run = mOpt1->run = mOpt2->run = 0;
|
|
|
|
|
|
|
|
legacy::PassManager Passes0;
|
|
|
|
legacy::PassManager Passes1;
|
|
|
|
legacy::PassManager Passes2;
|
|
|
|
|
|
|
|
Passes0.add(mOpt0);
|
|
|
|
Passes1.add(mOpt1);
|
|
|
|
Passes2.add(mOpt2);
|
|
|
|
|
|
|
|
Context1.setOptPassGate(SkipOptionalPasses);
|
|
|
|
Context2.setOptPassGate(RunOptionalPasses);
|
|
|
|
|
|
|
|
Passes0.run(M0);
|
|
|
|
Passes1.run(M1);
|
|
|
|
Passes2.run(M2);
|
|
|
|
|
|
|
|
// By default optional passes are run.
|
|
|
|
EXPECT_EQ(1, mOpt0->run);
|
|
|
|
|
|
|
|
// The first context skips optional passes.
|
|
|
|
EXPECT_EQ(0, mOpt1->run);
|
|
|
|
|
|
|
|
// The second context runs optional passes.
|
|
|
|
EXPECT_EQ(1, mOpt2->run);
|
|
|
|
}
|
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
Module *makeLLVMModule(LLVMContext &Context) {
|
2009-06-29 20:49:09 +02:00
|
|
|
// Module Construction
|
2016-04-14 23:59:01 +02:00
|
|
|
Module *mod = new Module("test-mem", Context);
|
2009-06-29 20:49:09 +02:00
|
|
|
mod->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
|
|
|
|
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
|
2013-12-13 19:56:34 +01:00
|
|
|
"a:0:64-s:64:64-f80:128:128");
|
2009-06-29 20:49:09 +02:00
|
|
|
mod->setTargetTriple("x86_64-unknown-linux-gnu");
|
|
|
|
|
|
|
|
// Type Definitions
|
2011-07-12 16:06:48 +02:00
|
|
|
std::vector<Type*>FuncTy_0_args;
|
2016-04-14 23:59:01 +02:00
|
|
|
FunctionType *FuncTy_0 = FunctionType::get(
|
|
|
|
/*Result=*/IntegerType::get(Context, 32),
|
|
|
|
/*Params=*/FuncTy_0_args,
|
|
|
|
/*isVarArg=*/false);
|
2009-06-29 20:49:09 +02:00
|
|
|
|
2011-07-12 16:06:48 +02:00
|
|
|
std::vector<Type*>FuncTy_2_args;
|
2016-04-14 23:59:01 +02:00
|
|
|
FuncTy_2_args.push_back(IntegerType::get(Context, 1));
|
|
|
|
FunctionType *FuncTy_2 = FunctionType::get(
|
|
|
|
/*Result=*/Type::getVoidTy(Context),
|
|
|
|
/*Params=*/FuncTy_2_args,
|
|
|
|
/*isVarArg=*/false);
|
2009-06-29 20:49:09 +02:00
|
|
|
|
|
|
|
// Function Declarations
|
|
|
|
|
|
|
|
Function* func_test1 = Function::Create(
|
|
|
|
/*Type=*/FuncTy_0,
|
|
|
|
/*Linkage=*/GlobalValue::ExternalLinkage,
|
|
|
|
/*Name=*/"test1", mod);
|
|
|
|
func_test1->setCallingConv(CallingConv::C);
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
AttributeList func_test1_PAL;
|
2009-06-29 20:49:09 +02:00
|
|
|
func_test1->setAttributes(func_test1_PAL);
|
|
|
|
|
|
|
|
Function* func_test2 = Function::Create(
|
|
|
|
/*Type=*/FuncTy_0,
|
|
|
|
/*Linkage=*/GlobalValue::ExternalLinkage,
|
|
|
|
/*Name=*/"test2", mod);
|
|
|
|
func_test2->setCallingConv(CallingConv::C);
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
AttributeList func_test2_PAL;
|
2009-06-29 20:49:09 +02:00
|
|
|
func_test2->setAttributes(func_test2_PAL);
|
|
|
|
|
|
|
|
Function* func_test3 = Function::Create(
|
|
|
|
/*Type=*/FuncTy_0,
|
[CallGraphUpdater] Update the ExternalCallingNode for node replacements
Summary:
While it is uncommon that the ExternalCallingNode needs to be updated,
it can happen. It is uncommon because most functions listed as callees
have external linkage, modifying them is usually not allowed. That said,
there are also internal functions that have, or better had, their
"address taken" at construction time. We conservatively assume various
uses cause the address "to be taken". Furthermore, the user might have
become dead at some point. As a consequence, transformations, e.g., the
Attributor, might be able to replace a function that is listed
as callee of the ExternalCallingNode.
Since there is no function corresponding to the ExternalCallingNode, we
did just remove the node from the callee list if we replaced it (so
far). Now it would be preferable to replace it if needed and remove it
otherwise. However, removing the node has implications on the CGSCC
iteration. Locally, that caused some other nodes to be never visited
but it is for sure possible other (bad) side effects can occur. As it
seems conservatively safe to keep the new node in the callee list we
will do that for now.
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77854
2020-04-09 22:21:24 +02:00
|
|
|
/*Linkage=*/GlobalValue::InternalLinkage,
|
2009-06-29 20:49:09 +02:00
|
|
|
/*Name=*/"test3", mod);
|
|
|
|
func_test3->setCallingConv(CallingConv::C);
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
AttributeList func_test3_PAL;
|
2009-06-29 20:49:09 +02:00
|
|
|
func_test3->setAttributes(func_test3_PAL);
|
|
|
|
|
|
|
|
Function* func_test4 = Function::Create(
|
|
|
|
/*Type=*/FuncTy_2,
|
|
|
|
/*Linkage=*/GlobalValue::ExternalLinkage,
|
|
|
|
/*Name=*/"test4", mod);
|
|
|
|
func_test4->setCallingConv(CallingConv::C);
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
AttributeList func_test4_PAL;
|
2009-06-29 20:49:09 +02:00
|
|
|
func_test4->setAttributes(func_test4_PAL);
|
|
|
|
|
|
|
|
// Global Variable Declarations
|
|
|
|
|
|
|
|
|
|
|
|
// Constant Definitions
|
|
|
|
|
|
|
|
// Global Variable Definitions
|
|
|
|
|
|
|
|
// Function Definitions
|
|
|
|
|
|
|
|
// Function: test1 (func_test1)
|
|
|
|
{
|
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
BasicBlock *label_entry =
|
|
|
|
BasicBlock::Create(Context, "entry", func_test1, nullptr);
|
2009-06-29 20:49:09 +02:00
|
|
|
|
|
|
|
// Block entry (label_entry)
|
|
|
|
CallInst* int32_3 = CallInst::Create(func_test2, "", label_entry);
|
|
|
|
int32_3->setCallingConv(CallingConv::C);
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
int32_3->setTailCall(false);
|
|
|
|
AttributeList int32_3_PAL;
|
2009-06-29 20:49:09 +02:00
|
|
|
int32_3->setAttributes(int32_3_PAL);
|
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
ReturnInst::Create(Context, int32_3, label_entry);
|
2009-06-29 20:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Function: test2 (func_test2)
|
|
|
|
{
|
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
BasicBlock *label_entry_5 =
|
|
|
|
BasicBlock::Create(Context, "entry", func_test2, nullptr);
|
2009-06-29 20:49:09 +02:00
|
|
|
|
|
|
|
// Block entry (label_entry_5)
|
|
|
|
CallInst* int32_6 = CallInst::Create(func_test3, "", label_entry_5);
|
|
|
|
int32_6->setCallingConv(CallingConv::C);
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
int32_6->setTailCall(false);
|
|
|
|
AttributeList int32_6_PAL;
|
2009-06-29 20:49:09 +02:00
|
|
|
int32_6->setAttributes(int32_6_PAL);
|
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
ReturnInst::Create(Context, int32_6, label_entry_5);
|
2009-06-29 20:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Function: test3 (func_test3)
|
|
|
|
{
|
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
BasicBlock *label_entry_8 =
|
|
|
|
BasicBlock::Create(Context, "entry", func_test3, nullptr);
|
2009-06-29 20:49:09 +02:00
|
|
|
|
|
|
|
// Block entry (label_entry_8)
|
|
|
|
CallInst* int32_9 = CallInst::Create(func_test1, "", label_entry_8);
|
|
|
|
int32_9->setCallingConv(CallingConv::C);
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-21 17:57:19 +01:00
|
|
|
int32_9->setTailCall(false);
|
|
|
|
AttributeList int32_9_PAL;
|
2009-06-29 20:49:09 +02:00
|
|
|
int32_9->setAttributes(int32_9_PAL);
|
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
ReturnInst::Create(Context, int32_9, label_entry_8);
|
2009-06-29 20:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Function: test4 (func_test4)
|
|
|
|
{
|
|
|
|
Function::arg_iterator args = func_test4->arg_begin();
|
2015-10-20 20:30:20 +02:00
|
|
|
Value *int1_f = &*args++;
|
2009-06-29 20:49:09 +02:00
|
|
|
int1_f->setName("f");
|
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
BasicBlock *label_entry_11 =
|
|
|
|
BasicBlock::Create(Context, "entry", func_test4, nullptr);
|
|
|
|
BasicBlock *label_bb =
|
|
|
|
BasicBlock::Create(Context, "bb", func_test4, nullptr);
|
|
|
|
BasicBlock *label_bb1 =
|
|
|
|
BasicBlock::Create(Context, "bb1", func_test4, nullptr);
|
|
|
|
BasicBlock *label_return =
|
|
|
|
BasicBlock::Create(Context, "return", func_test4, nullptr);
|
2009-06-29 20:49:09 +02:00
|
|
|
|
|
|
|
// Block entry (label_entry_11)
|
[CallGraphUpdater] Update the ExternalCallingNode for node replacements
Summary:
While it is uncommon that the ExternalCallingNode needs to be updated,
it can happen. It is uncommon because most functions listed as callees
have external linkage, modifying them is usually not allowed. That said,
there are also internal functions that have, or better had, their
"address taken" at construction time. We conservatively assume various
uses cause the address "to be taken". Furthermore, the user might have
become dead at some point. As a consequence, transformations, e.g., the
Attributor, might be able to replace a function that is listed
as callee of the ExternalCallingNode.
Since there is no function corresponding to the ExternalCallingNode, we
did just remove the node from the callee list if we replaced it (so
far). Now it would be preferable to replace it if needed and remove it
otherwise. However, removing the node has implications on the CGSCC
iteration. Locally, that caused some other nodes to be never visited
but it is for sure possible other (bad) side effects can occur. As it
seems conservatively safe to keep the new node in the callee list we
will do that for now.
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77854
2020-04-09 22:21:24 +02:00
|
|
|
auto *AI = new AllocaInst(func_test3->getType(), 0, "func3ptr",
|
|
|
|
label_entry_11);
|
|
|
|
new StoreInst(func_test3, AI, label_entry_11);
|
2009-06-29 20:49:09 +02:00
|
|
|
BranchInst::Create(label_bb, label_entry_11);
|
|
|
|
|
|
|
|
// Block bb (label_bb)
|
|
|
|
BranchInst::Create(label_bb, label_bb1, int1_f, label_bb);
|
|
|
|
|
|
|
|
// Block bb1 (label_bb1)
|
|
|
|
BranchInst::Create(label_bb1, label_return, int1_f, label_bb1);
|
|
|
|
|
|
|
|
// Block return (label_return)
|
2016-04-14 23:59:01 +02:00
|
|
|
ReturnInst::Create(Context, label_return);
|
2009-06-29 20:49:09 +02:00
|
|
|
}
|
|
|
|
return mod;
|
|
|
|
}
|
|
|
|
|
2020-04-12 18:52:06 +02:00
|
|
|
/// Split a simple function which contains only a call and a return into two
|
|
|
|
/// such that the first calls the second and the second whoever was called
|
|
|
|
/// initially.
|
|
|
|
Function *splitSimpleFunction(Function &F) {
|
|
|
|
LLVMContext &Context = F.getContext();
|
|
|
|
Function *SF = Function::Create(F.getFunctionType(), F.getLinkage(),
|
|
|
|
F.getName() + "b", F.getParent());
|
|
|
|
F.setName(F.getName() + "a");
|
|
|
|
BasicBlock *Entry = BasicBlock::Create(Context, "entry", SF, nullptr);
|
|
|
|
CallInst &CI = cast<CallInst>(F.getEntryBlock().front());
|
|
|
|
CI.clone()->insertBefore(ReturnInst::Create(Context, Entry));
|
|
|
|
CI.setCalledFunction(SF);
|
|
|
|
return SF;
|
|
|
|
}
|
|
|
|
|
2019-11-29 20:11:24 +01:00
|
|
|
struct CGModifierPass : public CGPass {
|
|
|
|
unsigned NumSCCs = 0;
|
|
|
|
unsigned NumFns = 0;
|
[CallGraphUpdater] Remove nodes from their SCC (old PM)
Summary:
We can and should remove deleted nodes from their respective SCCs. We
did not do this before and this was a potential problem even though I
couldn't locally trigger an issue. Since the `DeleteNode` would assert
if the node was not in the SCC, we know we only remove nodes from their
SCC and only once (when run on all the Attributor tests).
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77855
2020-04-09 22:43:31 +02:00
|
|
|
unsigned NumFnDecls = 0;
|
|
|
|
unsigned SetupWorked = 0;
|
[CallGraphUpdater] Update the ExternalCallingNode for node replacements
Summary:
While it is uncommon that the ExternalCallingNode needs to be updated,
it can happen. It is uncommon because most functions listed as callees
have external linkage, modifying them is usually not allowed. That said,
there are also internal functions that have, or better had, their
"address taken" at construction time. We conservatively assume various
uses cause the address "to be taken". Furthermore, the user might have
become dead at some point. As a consequence, transformations, e.g., the
Attributor, might be able to replace a function that is listed
as callee of the ExternalCallingNode.
Since there is no function corresponding to the ExternalCallingNode, we
did just remove the node from the callee list if we replaced it (so
far). Now it would be preferable to replace it if needed and remove it
otherwise. However, removing the node has implications on the CGSCC
iteration. Locally, that caused some other nodes to be never visited
but it is for sure possible other (bad) side effects can occur. As it
seems conservatively safe to keep the new node in the callee list we
will do that for now.
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77854
2020-04-09 22:21:24 +02:00
|
|
|
unsigned NumExtCalledBefore = 0;
|
|
|
|
unsigned NumExtCalledAfter = 0;
|
2019-11-29 20:11:24 +01:00
|
|
|
|
|
|
|
CallGraphUpdater CGU;
|
|
|
|
|
|
|
|
bool runOnSCC(CallGraphSCC &SCMM) override {
|
|
|
|
++NumSCCs;
|
[CallGraphUpdater] Remove nodes from their SCC (old PM)
Summary:
We can and should remove deleted nodes from their respective SCCs. We
did not do this before and this was a potential problem even though I
couldn't locally trigger an issue. Since the `DeleteNode` would assert
if the node was not in the SCC, we know we only remove nodes from their
SCC and only once (when run on all the Attributor tests).
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77855
2020-04-09 22:43:31 +02:00
|
|
|
for (CallGraphNode *N : SCMM) {
|
|
|
|
if (N->getFunction()){
|
2019-11-29 20:11:24 +01:00
|
|
|
++NumFns;
|
[CallGraphUpdater] Remove nodes from their SCC (old PM)
Summary:
We can and should remove deleted nodes from their respective SCCs. We
did not do this before and this was a potential problem even though I
couldn't locally trigger an issue. Since the `DeleteNode` would assert
if the node was not in the SCC, we know we only remove nodes from their
SCC and only once (when run on all the Attributor tests).
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77855
2020-04-09 22:43:31 +02:00
|
|
|
NumFnDecls += N->getFunction()->isDeclaration();
|
|
|
|
}
|
|
|
|
}
|
2019-11-29 20:11:24 +01:00
|
|
|
CGPass::run();
|
|
|
|
|
[CallGraphUpdater] Update the ExternalCallingNode for node replacements
Summary:
While it is uncommon that the ExternalCallingNode needs to be updated,
it can happen. It is uncommon because most functions listed as callees
have external linkage, modifying them is usually not allowed. That said,
there are also internal functions that have, or better had, their
"address taken" at construction time. We conservatively assume various
uses cause the address "to be taken". Furthermore, the user might have
become dead at some point. As a consequence, transformations, e.g., the
Attributor, might be able to replace a function that is listed
as callee of the ExternalCallingNode.
Since there is no function corresponding to the ExternalCallingNode, we
did just remove the node from the callee list if we replaced it (so
far). Now it would be preferable to replace it if needed and remove it
otherwise. However, removing the node has implications on the CGSCC
iteration. Locally, that caused some other nodes to be never visited
but it is for sure possible other (bad) side effects can occur. As it
seems conservatively safe to keep the new node in the callee list we
will do that for now.
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77854
2020-04-09 22:21:24 +02:00
|
|
|
CallGraph &CG = const_cast<CallGraph &>(SCMM.getCallGraph());
|
|
|
|
CallGraphNode *ExtCallingNode = CG.getExternalCallingNode();
|
|
|
|
NumExtCalledBefore = ExtCallingNode->size();
|
|
|
|
|
2019-11-29 20:11:24 +01:00
|
|
|
if (SCMM.size() <= 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
CallGraphNode *N = *(SCMM.begin());
|
|
|
|
Function *F = N->getFunction();
|
|
|
|
Module *M = F->getParent();
|
|
|
|
Function *Test1F = M->getFunction("test1");
|
2020-04-12 18:52:06 +02:00
|
|
|
Function *Test2aF = M->getFunction("test2a");
|
|
|
|
Function *Test2bF = M->getFunction("test2b");
|
2019-11-29 20:11:24 +01:00
|
|
|
Function *Test3F = M->getFunction("test3");
|
[CallGraphUpdater] Update the ExternalCallingNode for node replacements
Summary:
While it is uncommon that the ExternalCallingNode needs to be updated,
it can happen. It is uncommon because most functions listed as callees
have external linkage, modifying them is usually not allowed. That said,
there are also internal functions that have, or better had, their
"address taken" at construction time. We conservatively assume various
uses cause the address "to be taken". Furthermore, the user might have
become dead at some point. As a consequence, transformations, e.g., the
Attributor, might be able to replace a function that is listed
as callee of the ExternalCallingNode.
Since there is no function corresponding to the ExternalCallingNode, we
did just remove the node from the callee list if we replaced it (so
far). Now it would be preferable to replace it if needed and remove it
otherwise. However, removing the node has implications on the CGSCC
iteration. Locally, that caused some other nodes to be never visited
but it is for sure possible other (bad) side effects can occur. As it
seems conservatively safe to keep the new node in the callee list we
will do that for now.
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77854
2020-04-09 22:21:24 +02:00
|
|
|
|
2019-11-29 20:11:24 +01:00
|
|
|
auto InSCC = [&](Function *Fn) {
|
|
|
|
return llvm::any_of(SCMM, [Fn](CallGraphNode *CGN) {
|
|
|
|
return CGN->getFunction() == Fn;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-04-12 18:52:06 +02:00
|
|
|
if (!Test1F || !Test2aF || !Test2bF || !Test3F || !InSCC(Test1F) ||
|
|
|
|
!InSCC(Test2aF) || !InSCC(Test2bF) || !InSCC(Test3F))
|
[CallGraphUpdater] Remove nodes from their SCC (old PM)
Summary:
We can and should remove deleted nodes from their respective SCCs. We
did not do this before and this was a potential problem even though I
couldn't locally trigger an issue. Since the `DeleteNode` would assert
if the node was not in the SCC, we know we only remove nodes from their
SCC and only once (when run on all the Attributor tests).
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77855
2020-04-09 22:43:31 +02:00
|
|
|
return false;
|
2019-11-29 20:11:24 +01:00
|
|
|
|
|
|
|
CallInst *CI = dyn_cast<CallInst>(&Test1F->getEntryBlock().front());
|
2020-04-12 18:52:06 +02:00
|
|
|
if (!CI || CI->getCalledFunction() != Test2aF)
|
[CallGraphUpdater] Remove nodes from their SCC (old PM)
Summary:
We can and should remove deleted nodes from their respective SCCs. We
did not do this before and this was a potential problem even though I
couldn't locally trigger an issue. Since the `DeleteNode` would assert
if the node was not in the SCC, we know we only remove nodes from their
SCC and only once (when run on all the Attributor tests).
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77855
2020-04-09 22:43:31 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
SetupWorked += 1;
|
2019-11-29 20:11:24 +01:00
|
|
|
|
[CallGraphUpdater] Update the ExternalCallingNode for node replacements
Summary:
While it is uncommon that the ExternalCallingNode needs to be updated,
it can happen. It is uncommon because most functions listed as callees
have external linkage, modifying them is usually not allowed. That said,
there are also internal functions that have, or better had, their
"address taken" at construction time. We conservatively assume various
uses cause the address "to be taken". Furthermore, the user might have
become dead at some point. As a consequence, transformations, e.g., the
Attributor, might be able to replace a function that is listed
as callee of the ExternalCallingNode.
Since there is no function corresponding to the ExternalCallingNode, we
did just remove the node from the callee list if we replaced it (so
far). Now it would be preferable to replace it if needed and remove it
otherwise. However, removing the node has implications on the CGSCC
iteration. Locally, that caused some other nodes to be never visited
but it is for sure possible other (bad) side effects can occur. As it
seems conservatively safe to keep the new node in the callee list we
will do that for now.
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77854
2020-04-09 22:21:24 +02:00
|
|
|
// Create a replica of test3 and just move the blocks there.
|
|
|
|
Function *Test3FRepl = Function::Create(
|
|
|
|
/*Type=*/Test3F->getFunctionType(),
|
|
|
|
/*Linkage=*/GlobalValue::InternalLinkage,
|
|
|
|
/*Name=*/"test3repl", Test3F->getParent());
|
|
|
|
while (!Test3F->empty()) {
|
|
|
|
BasicBlock &BB = Test3F->front();
|
|
|
|
BB.removeFromParent();
|
|
|
|
BB.insertInto(Test3FRepl);
|
|
|
|
}
|
|
|
|
|
|
|
|
CGU.initialize(CG, SCMM);
|
2019-11-29 20:11:24 +01:00
|
|
|
|
[CallGraphUpdater] Update the ExternalCallingNode for node replacements
Summary:
While it is uncommon that the ExternalCallingNode needs to be updated,
it can happen. It is uncommon because most functions listed as callees
have external linkage, modifying them is usually not allowed. That said,
there are also internal functions that have, or better had, their
"address taken" at construction time. We conservatively assume various
uses cause the address "to be taken". Furthermore, the user might have
become dead at some point. As a consequence, transformations, e.g., the
Attributor, might be able to replace a function that is listed
as callee of the ExternalCallingNode.
Since there is no function corresponding to the ExternalCallingNode, we
did just remove the node from the callee list if we replaced it (so
far). Now it would be preferable to replace it if needed and remove it
otherwise. However, removing the node has implications on the CGSCC
iteration. Locally, that caused some other nodes to be never visited
but it is for sure possible other (bad) side effects can occur. As it
seems conservatively safe to keep the new node in the callee list we
will do that for now.
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77854
2020-04-09 22:21:24 +02:00
|
|
|
// Replace test3 with the replica. This is legal as it is actually
|
|
|
|
// internal and the "capturing use" is not really capturing anything.
|
|
|
|
CGU.replaceFunctionWith(*Test3F, *Test3FRepl);
|
|
|
|
Test3F->replaceAllUsesWith(Test3FRepl);
|
|
|
|
|
|
|
|
// Rewrite the call in test1 to point to the replica of 3 not test2.
|
|
|
|
CI->setCalledFunction(Test3FRepl);
|
|
|
|
|
|
|
|
// Delete test2a and test2b and reanalyze 1 as we changed calls inside.
|
2020-04-12 18:52:06 +02:00
|
|
|
CGU.removeFunction(*Test2aF);
|
|
|
|
CGU.removeFunction(*Test2bF);
|
2019-11-29 20:11:24 +01:00
|
|
|
CGU.reanalyzeFunction(*Test1F);
|
[CallGraphUpdater] Update the ExternalCallingNode for node replacements
Summary:
While it is uncommon that the ExternalCallingNode needs to be updated,
it can happen. It is uncommon because most functions listed as callees
have external linkage, modifying them is usually not allowed. That said,
there are also internal functions that have, or better had, their
"address taken" at construction time. We conservatively assume various
uses cause the address "to be taken". Furthermore, the user might have
become dead at some point. As a consequence, transformations, e.g., the
Attributor, might be able to replace a function that is listed
as callee of the ExternalCallingNode.
Since there is no function corresponding to the ExternalCallingNode, we
did just remove the node from the callee list if we replaced it (so
far). Now it would be preferable to replace it if needed and remove it
otherwise. However, removing the node has implications on the CGSCC
iteration. Locally, that caused some other nodes to be never visited
but it is for sure possible other (bad) side effects can occur. As it
seems conservatively safe to keep the new node in the callee list we
will do that for now.
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77854
2020-04-09 22:21:24 +02:00
|
|
|
|
2019-11-29 20:11:24 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[CallGraphUpdater] Update the ExternalCallingNode for node replacements
Summary:
While it is uncommon that the ExternalCallingNode needs to be updated,
it can happen. It is uncommon because most functions listed as callees
have external linkage, modifying them is usually not allowed. That said,
there are also internal functions that have, or better had, their
"address taken" at construction time. We conservatively assume various
uses cause the address "to be taken". Furthermore, the user might have
become dead at some point. As a consequence, transformations, e.g., the
Attributor, might be able to replace a function that is listed
as callee of the ExternalCallingNode.
Since there is no function corresponding to the ExternalCallingNode, we
did just remove the node from the callee list if we replaced it (so
far). Now it would be preferable to replace it if needed and remove it
otherwise. However, removing the node has implications on the CGSCC
iteration. Locally, that caused some other nodes to be never visited
but it is for sure possible other (bad) side effects can occur. As it
seems conservatively safe to keep the new node in the callee list we
will do that for now.
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77854
2020-04-09 22:21:24 +02:00
|
|
|
bool doFinalization(CallGraph &CG) override {
|
|
|
|
CGU.finalize();
|
|
|
|
// We removed test2 and replaced the internal test3.
|
|
|
|
NumExtCalledAfter = CG.getExternalCallingNode()->size();
|
|
|
|
return true;
|
|
|
|
}
|
2019-11-29 20:11:24 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
TEST(PassManager, CallGraphUpdater0) {
|
2020-04-12 18:52:06 +02:00
|
|
|
// SCC#1: test1->test2a->test2b->test3->test1
|
2019-11-29 20:11:24 +01:00
|
|
|
// SCC#2: test4
|
[CallGraphUpdater] Remove nodes from their SCC (old PM)
Summary:
We can and should remove deleted nodes from their respective SCCs. We
did not do this before and this was a potential problem even though I
couldn't locally trigger an issue. Since the `DeleteNode` would assert
if the node was not in the SCC, we know we only remove nodes from their
SCC and only once (when run on all the Attributor tests).
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77855
2020-04-09 22:43:31 +02:00
|
|
|
// SCC#3: test3 (the empty function declaration as we replaced it with
|
|
|
|
// test3repl when we visited SCC#1)
|
|
|
|
// SCC#4: test2a->test2b (the empty function declarations as we deleted
|
|
|
|
// these functions when we visited SCC#1)
|
|
|
|
// SCC#5: indirect call node
|
2019-11-29 20:11:24 +01:00
|
|
|
|
|
|
|
LLVMContext Context;
|
|
|
|
std::unique_ptr<Module> M(makeLLVMModule(Context));
|
|
|
|
ASSERT_EQ(M->getFunctionList().size(), 4U);
|
2020-04-12 18:52:06 +02:00
|
|
|
Function *F = M->getFunction("test2");
|
|
|
|
Function *SF = splitSimpleFunction(*F);
|
2020-05-28 12:40:17 +02:00
|
|
|
CallInst::Create(F, "", &*SF->getEntryBlock().getFirstInsertionPt());
|
2020-04-12 18:52:06 +02:00
|
|
|
ASSERT_EQ(M->getFunctionList().size(), 5U);
|
2019-11-29 20:11:24 +01:00
|
|
|
CGModifierPass *P = new CGModifierPass();
|
|
|
|
legacy::PassManager Passes;
|
|
|
|
Passes.add(P);
|
|
|
|
Passes.run(*M);
|
[CallGraphUpdater] Remove nodes from their SCC (old PM)
Summary:
We can and should remove deleted nodes from their respective SCCs. We
did not do this before and this was a potential problem even though I
couldn't locally trigger an issue. Since the `DeleteNode` would assert
if the node was not in the SCC, we know we only remove nodes from their
SCC and only once (when run on all the Attributor tests).
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77855
2020-04-09 22:43:31 +02:00
|
|
|
ASSERT_EQ(P->SetupWorked, 1U);
|
2020-05-05 03:58:59 +02:00
|
|
|
ASSERT_EQ(P->NumSCCs, 4U);
|
|
|
|
ASSERT_EQ(P->NumFns, 6U);
|
|
|
|
ASSERT_EQ(P->NumFnDecls, 1U);
|
2019-11-29 20:11:24 +01:00
|
|
|
ASSERT_EQ(M->getFunctionList().size(), 3U);
|
[CallGraphUpdater] Update the ExternalCallingNode for node replacements
Summary:
While it is uncommon that the ExternalCallingNode needs to be updated,
it can happen. It is uncommon because most functions listed as callees
have external linkage, modifying them is usually not allowed. That said,
there are also internal functions that have, or better had, their
"address taken" at construction time. We conservatively assume various
uses cause the address "to be taken". Furthermore, the user might have
become dead at some point. As a consequence, transformations, e.g., the
Attributor, might be able to replace a function that is listed
as callee of the ExternalCallingNode.
Since there is no function corresponding to the ExternalCallingNode, we
did just remove the node from the callee list if we replaced it (so
far). Now it would be preferable to replace it if needed and remove it
otherwise. However, removing the node has implications on the CGSCC
iteration. Locally, that caused some other nodes to be never visited
but it is for sure possible other (bad) side effects can occur. As it
seems conservatively safe to keep the new node in the callee list we
will do that for now.
Reviewers: lebedev.ri, hfinkel, fhahn, probinson, wristow, loladiro, sstefan1, uenoku
Subscribers: hiraditya, bollu, uenoku, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77854
2020-04-09 22:21:24 +02:00
|
|
|
ASSERT_EQ(P->NumExtCalledBefore, /* test1, 2a, 2b, 3, 4 */ 5U);
|
|
|
|
ASSERT_EQ(P->NumExtCalledAfter, /* test1, 3repl, 4 */ 3U);
|
2019-11-29 20:11:24 +01:00
|
|
|
}
|
2020-07-27 15:02:06 +02:00
|
|
|
|
|
|
|
// Test for call graph SCC pass that replaces all callback call instructions
|
|
|
|
// with clones and updates CallGraph by calling CallGraph::replaceCallEdge()
|
|
|
|
// method. Test is expected to complete successfully after running pass on
|
|
|
|
// all SCCs in the test module.
|
|
|
|
struct CallbackCallsModifierPass : public CGPass {
|
|
|
|
bool runOnSCC(CallGraphSCC &SCC) override {
|
|
|
|
CGPass::run();
|
|
|
|
|
|
|
|
CallGraph &CG = const_cast<CallGraph &>(SCC.getCallGraph());
|
|
|
|
|
|
|
|
bool Changed = false;
|
|
|
|
for (CallGraphNode *CGN : SCC) {
|
|
|
|
Function *F = CGN->getFunction();
|
|
|
|
if (!F || F->isDeclaration())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SmallVector<CallBase *, 4u> Calls;
|
|
|
|
for (Use &U : F->uses()) {
|
|
|
|
AbstractCallSite ACS(&U);
|
|
|
|
if (!ACS || !ACS.isCallbackCall() || !ACS.isCallee(&U))
|
|
|
|
continue;
|
|
|
|
Calls.push_back(cast<CallBase>(ACS.getInstruction()));
|
|
|
|
}
|
|
|
|
if (Calls.empty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (CallBase *OldCB : Calls) {
|
|
|
|
CallGraphNode *CallerCGN = CG[OldCB->getParent()->getParent()];
|
|
|
|
assert(any_of(*CallerCGN,
|
|
|
|
[CGN](const CallGraphNode::CallRecord &CallRecord) {
|
|
|
|
return CallRecord.second == CGN;
|
|
|
|
}) &&
|
|
|
|
"function is not a callee");
|
|
|
|
|
|
|
|
CallBase *NewCB = cast<CallBase>(OldCB->clone());
|
|
|
|
|
|
|
|
NewCB->insertBefore(OldCB);
|
|
|
|
NewCB->takeName(OldCB);
|
|
|
|
|
|
|
|
CallerCGN->replaceCallEdge(*OldCB, *NewCB, CG[F]);
|
|
|
|
|
|
|
|
OldCB->replaceAllUsesWith(NewCB);
|
|
|
|
OldCB->eraseFromParent();
|
|
|
|
}
|
|
|
|
Changed = true;
|
|
|
|
}
|
|
|
|
return Changed;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST(PassManager, CallbackCallsModifier0) {
|
|
|
|
LLVMContext Context;
|
|
|
|
|
|
|
|
const char *IR = "define void @foo() {\n"
|
|
|
|
" call void @broker(void (i8*)* @callback0, i8* null)\n"
|
|
|
|
" call void @broker(void (i8*)* @callback1, i8* null)\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n"
|
|
|
|
"\n"
|
|
|
|
"declare !callback !0 void @broker(void (i8*)*, i8*)\n"
|
|
|
|
"\n"
|
|
|
|
"define internal void @callback0(i8* %arg) {\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n"
|
|
|
|
"\n"
|
|
|
|
"define internal void @callback1(i8* %arg) {\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n"
|
|
|
|
"\n"
|
|
|
|
"!0 = !{!1}\n"
|
|
|
|
"!1 = !{i64 0, i64 1, i1 false}";
|
|
|
|
|
|
|
|
SMDiagnostic Err;
|
|
|
|
std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Context);
|
|
|
|
if (!M)
|
|
|
|
Err.print("LegacyPassManagerTest", errs());
|
|
|
|
|
|
|
|
CallbackCallsModifierPass *P = new CallbackCallsModifierPass();
|
|
|
|
legacy::PassManager Passes;
|
|
|
|
Passes.add(P);
|
|
|
|
Passes.run(*M);
|
|
|
|
}
|
2009-06-29 20:49:09 +02:00
|
|
|
}
|
|
|
|
}
|
2010-10-19 19:21:58 +02:00
|
|
|
|
|
|
|
INITIALIZE_PASS(ModuleNDM, "mndm", "mndm", false, false)
|
|
|
|
INITIALIZE_PASS_BEGIN(CGPass, "cgp","cgp", false, false)
|
2013-11-26 05:19:30 +01:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
|
2010-10-19 19:21:58 +02:00
|
|
|
INITIALIZE_PASS_END(CGPass, "cgp","cgp", false, false)
|
|
|
|
INITIALIZE_PASS(FPass, "fp","fp", false, false)
|
|
|
|
INITIALIZE_PASS_BEGIN(LPass, "lp","lp", false, false)
|
2015-01-17 15:16:18 +01:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
|
2010-10-19 19:21:58 +02:00
|
|
|
INITIALIZE_PASS_END(LPass, "lp","lp", false, false)
|