view gen/optimizer.cpp @ 1351:8d501abecd24

Initial (but disabled) fix for ticket #294 , the actual part that fixes the bug is in a #if 0 block as I'm afraid it will cause regressions. I'm most likely not going to be around tonight, and maybe not tomorrow as well, so I'm pushing it in case someone wants to run some serious testing/investigate the problem noted in llvmhelpers.cpp : realignOffset .
author Tomas Lindquist Olsen <tomas.l.olsen gmail com>
date Thu, 14 May 2009 17:20:17 +0200
parents 79b201533cf8
children 42bd767ec5a4
line wrap: on
line source

#include "gen/optimizer.h"
#include "gen/cl_helpers.h"

#include "gen/passes/Passes.h"

#include "llvm/PassManager.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/PassNameParser.h"

#include "root.h"       // error()

using namespace llvm;

// Allow the user to specify specific optimizations to run.
static cl::list<const PassInfo*, bool, PassNameParser>
    passList(
        cl::desc("Running specific optimizations:"),
        cl::Hidden      // to clean up --help output
    );

static cl::opt<unsigned char> optimizeLevel(
    cl::desc("Setting the optimization level:"),
    cl::ZeroOrMore,
    cl::values(
        clEnumValN(2, "O",  "Equivalent to -O2"),
        clEnumValN(0, "O0", "No optimizations (default)"),
        clEnumValN(1, "O1", "Simple optimizations"),
        clEnumValN(2, "O2", "Good optimizations"),
        clEnumValN(3, "O3", "Aggressive optimizations"),
        clEnumValN(4, "O4", "Link-time optimization"), //  not implemented?
        clEnumValN(5, "O5", "Link-time optimization"), //  not implemented?
        clEnumValEnd),
    cl::init(0));

static cl::opt<bool>
verifyEach("verify-each",
    cl::desc("Run verifier after each optimization pass"),
    cl::Hidden,
    cl::ZeroOrMore);

static cl::opt<bool>
disableLangSpecificPasses("disable-d-passes",
    cl::desc("Disable D-specific passes in -O<N>"),
    cl::ZeroOrMore);

static cl::opt<bool>
disableSimplifyRuntimeCalls("disable-simplify-drtcalls",
    cl::desc("Disable simplification of runtime calls in -O<N>"),
    cl::ZeroOrMore);

#ifdef USE_METADATA
static cl::opt<bool>
disableGCToStack("disable-gc2stack",
    cl::desc("Disable promotion of GC allocations to stack memory in -O<N>"),
    cl::ZeroOrMore);

// Not recommended; metadata currently triggers an assert in the backend...
static cl::opt<bool>
disableStripMetaData("disable-strip-metadata",
    cl::desc("Disable default metadata stripping (not recommended)"),
    cl::ZeroOrMore);
#endif

static cl::opt<opts::BoolOrDefaultAdapter, false, opts::FlagParser>
enableInlining("inlining",
    cl::desc("(*) Enable function inlining in -O<N>"),
    cl::ZeroOrMore);

// Determine whether or not to run the inliner as part of the default list of
// optimization passes.
// If not explicitly specified, treat as false for -O0-2, and true for -O3.
bool doInline() {
    return enableInlining == cl::BOU_TRUE
        || (enableInlining == cl::BOU_UNSET && optimizeLevel >= 3);
}

// Some extra accessors for the linker: (llvm-ld version only, currently unused?)
int optLevel() {
    return optimizeLevel;
}

bool optimize() {
    return optimizeLevel || doInline() || !passList.empty();
}

static void addPass(PassManager& pm, Pass* pass) {
    pm.add(pass);
    
    if (verifyEach) pm.add(createVerifierPass());
}

// this function inserts some or all of the std-compile-opts passes depending on the
// optimization level given.
static void addPassesForOptLevel(PassManager& pm) {
    // -O1
    if (optimizeLevel >= 1)
    {
        //addPass(pm, createStripDeadPrototypesPass());
        addPass(pm, createGlobalDCEPass());
        addPass(pm, createRaiseAllocationsPass());
        addPass(pm, createCFGSimplificationPass());
        if (optimizeLevel == 1)
            addPass(pm, createPromoteMemoryToRegisterPass());
        else
            addPass(pm, createScalarReplAggregatesPass());
        addPass(pm, createGlobalOptimizerPass());
        addPass(pm, createGlobalDCEPass());
    }

    // -O2
    if (optimizeLevel >= 2)
    {
        addPass(pm, createIPConstantPropagationPass());
        addPass(pm, createDeadArgEliminationPass());
        addPass(pm, createInstructionCombiningPass());
        addPass(pm, createCFGSimplificationPass());
        addPass(pm, createPruneEHPass());

#ifdef USE_METADATA
        if (!disableLangSpecificPasses && !disableGCToStack)
            addPass(pm, createGarbageCollect2Stack());
#endif
    }

    // -inline
    if (doInline()) {
        addPass(pm, createFunctionInliningPass());

        if (optimizeLevel >= 2) {
            // Run some optimizations to clean up after inlining.
            addPass(pm, createScalarReplAggregatesPass());
            addPass(pm, createInstructionCombiningPass());

#ifdef USE_METADATA
            if (!disableLangSpecificPasses && !disableGCToStack)
                addPass(pm, createGarbageCollect2Stack());
#endif

            // Inline again, to catch things like foreach delegates
            // passed to inlined opApply's where the function wasn't
            // known during the first inliner pass.
            addPass(pm, createFunctionInliningPass());

            // Run clean-up again.
            addPass(pm, createScalarReplAggregatesPass());
            addPass(pm, createInstructionCombiningPass());

#ifdef USE_METADATA
            if (!disableLangSpecificPasses && !disableGCToStack)
                addPass(pm, createGarbageCollect2Stack());
#endif
        }
    }

    if (optimizeLevel >= 2 && !disableLangSpecificPasses) {
        if (!disableSimplifyRuntimeCalls)
            addPass(pm, createSimplifyDRuntimeCalls());

#ifdef USE_METADATA
        if (!disableGCToStack) {
            // Run some clean-up after the last GC to stack promotion pass.
            addPass(pm, createScalarReplAggregatesPass());
            addPass(pm, createInstructionCombiningPass());
            addPass(pm, createCFGSimplificationPass());
        }
#endif
    }

    // -O3
    if (optimizeLevel >= 3)
    {
        addPass(pm, createArgumentPromotionPass());
        addPass(pm, createTailDuplicationPass());
        addPass(pm, createInstructionCombiningPass());
        addPass(pm, createCFGSimplificationPass());
        addPass(pm, createScalarReplAggregatesPass());
        addPass(pm, createInstructionCombiningPass());
        addPass(pm, createCondPropagationPass());

        addPass(pm, createTailCallEliminationPass());
        addPass(pm, createCFGSimplificationPass());
        addPass(pm, createReassociatePass());
        addPass(pm, createLoopRotatePass());
        addPass(pm, createLICMPass());
        addPass(pm, createLoopUnswitchPass());
        addPass(pm, createInstructionCombiningPass());
        addPass(pm, createIndVarSimplifyPass());
        addPass(pm, createLoopUnrollPass());
        addPass(pm, createInstructionCombiningPass());
        addPass(pm, createGVNPass());
        addPass(pm, createSCCPPass());

        addPass(pm, createInstructionCombiningPass());
        addPass(pm, createCondPropagationPass());

        addPass(pm, createDeadStoreEliminationPass());
        addPass(pm, createAggressiveDCEPass());
        addPass(pm, createCFGSimplificationPass());
        addPass(pm, createSimplifyLibCallsPass());
        addPass(pm, createDeadTypeEliminationPass());
        addPass(pm, createConstantMergePass());
    }

    // level -O4 and -O5 are linktime optimizations
}

//////////////////////////////////////////////////////////////////////////////////////////
// This function runs optimization passes based on command line arguments.
// Returns true if any optimization passes were invoked.
bool ldc_optimize_module(llvm::Module* m)
{
    if (!optimize()) {
#ifdef USE_METADATA
        if (!disableStripMetaData) {
            // This one always needs to run if metadata is generated, because
            // the code generator will assert if it's not used.
            ModulePass* stripMD = createStripMetaData();
            stripMD->runOnModule(*m);
            delete stripMD;
        }
#endif
        return false;
    }

    PassManager pm;
    
    if (verifyEach) pm.add(createVerifierPass());
    
    addPass(pm, new TargetData(m));

    bool optimize = optimizeLevel != 0 || doInline();

    unsigned optPos = optimizeLevel != 0
                    ? optimizeLevel.getPosition()
                    : enableInlining.getPosition();

    for (size_t i = 0; i < passList.size(); i++) {
        // insert -O<N> / -enable-inlining in right position
        if (optimize && optPos < passList.getPosition(i)) {
            addPassesForOptLevel(pm);
            optimize = false;
        }

        const PassInfo* pass = passList[i];
        if (PassInfo::NormalCtor_t ctor = pass->getNormalCtor()) {
            addPass(pm, ctor());
        } else {
            const char* arg = pass->getPassArgument(); // may return null
            if (arg)
                error("Can't create pass '-%s' (%s)", arg, pass->getPassName());
            else
                error("Can't create pass (%s)", pass->getPassName());
            assert(0);  // Should be unreachable; root.h:error() calls exit()
        }
    }
    // insert -O<N> / -enable-inlining if specified at the end,
    if (optimize)
        addPassesForOptLevel(pm);

#ifdef USE_METADATA
    if (!disableStripMetaData) {
        // This one is purposely not disabled by disableLangSpecificPasses
        // because the code generator will assert if it's not used.
        addPass(pm, createStripMetaData());
    }
#endif

    pm.run(*m);
    return true;
}