view gen/optimizer.cpp @ 1318:bac742d3a72d

Make sure this testcase keeps crashing with -O3. Recent optimization improvements made LLVM realize the store-to-null was unavoidable, so it deleted all of main() and replaced it with 'unreachable'. Because the body of main() no longer even contained a return instruction, calling it caused random code to be ran instead. This happened to be the code that links in the ModuleInfo on my machine, which then returned "successfully".
author Frits van Bommel <fvbommel wxs.nl>
date Sat, 09 May 2009 00:55:47 +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;
}