Esempio n. 1
0
int main(int argc, char *argv[])
{
    cl::SetVersionPrinter(&versionPrinter);
    cl::ParseCommandLineOptions(argc, argv, "llvm2kittel\n");

    if (boundedIntegers && divisionConstraintType == Exact) {
        std::cerr << "Cannot use \"-division-constraint=exact\" in combination with \"-bounded-integers\"" << std::endl;
        return 333;
    }
    if (!boundedIntegers && unsignedEncoding) {
        std::cerr << "Cannot use \"-unsigned-encoding\" without \"-bounded-integers\"" << std::endl;
        return 333;
    }
    if (!boundedIntegers && bitwiseConditions) {
        std::cerr << "Cannot use \"-bitwise-conditions\" without \"-bounded-integers\"" << std::endl;
        return 333;
    }
    if (numInlines != 0 && eagerInline) {
        std::cerr << "Cannot use \"-inline\" in combination with \"-eager-inline\"" << std::endl;
        return 333;
    }

#if LLVM_VERSION < VERSION(3, 5)
    llvm::OwningPtr<llvm::MemoryBuffer> owningBuffer;
    llvm::MemoryBuffer::getFileOrSTDIN(filename, owningBuffer);
    llvm::MemoryBuffer *buffer = owningBuffer.get();
#else
    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> owningBuffer = llvm::MemoryBuffer::getFileOrSTDIN(filename);
    llvm::MemoryBuffer *buffer = NULL;
    if (!owningBuffer.getError()) {
        buffer = owningBuffer->get();
    }
#endif

    if (buffer == NULL) {
        std::cerr << "LLVM bitcode file \"" << filename << "\" does not exist or cannot be read." << std::endl;
        return 1;
    }

    llvm::LLVMContext context;
    std::string errMsg;
#if LLVM_VERSION < VERSION(3, 5)
    llvm::Module *module = llvm::ParseBitcodeFile(buffer, context, &errMsg);
#elif LLVM_VERSION == VERSION(3, 5)
    llvm::Module *module = NULL;
    llvm::ErrorOr<llvm::Module*> moduleOrError = llvm::parseBitcodeFile(buffer, context);
    std::error_code ec = moduleOrError.getError();
    if (ec) {
        errMsg = ec.message();
    } else {
        module = moduleOrError.get();
    }
#elif LLVM_VERSION == VERSION(3, 6)
    llvm::Module *module = NULL;
    llvm::ErrorOr<llvm::Module*> moduleOrError = llvm::parseBitcodeFile(buffer->getMemBufferRef(), context);
    std::error_code ec = moduleOrError.getError();
    if (ec) {
        errMsg = ec.message();
    } else {
        module = moduleOrError.get();
    }
#else
    llvm::Module *module = NULL;
    llvm::ErrorOr<std::unique_ptr<llvm::Module>> moduleOrError = llvm::parseBitcodeFile(buffer->getMemBufferRef(), context);
    std::error_code ec = moduleOrError.getError();
    if (ec) {
        errMsg = ec.message();
    } else {
        module = moduleOrError->get();
    }
#endif

    // check if the file is a proper bitcode file and contains a module
    if (module == NULL) {
        std::cerr << "LLVM bitcode file doesn't contain a valid module." << std::endl;
        return 2;
    }

    llvm::Function *function = NULL;
    llvm::Function *firstFunction = NULL;
    unsigned int numFunctions = 0;
    std::list<std::string> functionNames;

    for (llvm::Module::iterator i = module->begin(), e = module->end(); i != e; ++i) {
        if (i->getName() == functionname) {
            function = &*i;
            break;
        } else if (functionname.empty() && i->getName() == "main") {
            function = &*i;
            break;
        } else if (!i->isDeclaration()) {
            ++numFunctions;
            functionNames.push_back(i->getName());
            if (firstFunction == NULL) {
                firstFunction = &*i;
            }
        }
    }

    if (function == NULL) {
        if (numFunctions == 0) {
            std::cerr << "Module does not contain any function." << std::endl;
            return 3;
        }
        if (functionname.empty()) {
            if (numFunctions == 1) {
                function = firstFunction;
            } else {
                std::cerr << "LLVM module contains more than one function:" << std::endl;
                for (std::list<std::string>::iterator i = functionNames.begin(), e = functionNames.end(); i != e; ++i) {
                    std::cerr << "    " << *i << std::endl;
                }
                std::cerr << "Please specify which function should be used." << std::endl;
                return 4;
            }
        } else  {
            std::cerr << "Specified function not found." << std::endl;
            std::cerr << "Candidates are:" << std::endl;
            for (std::list<std::string>::iterator i = functionNames.begin(), e = functionNames.end(); i != e; ++i) {
                std::cerr << "    " << *i << std::endl;
            }
            return 5;
        }
    }

    // check for cyclic call hierarchies
    HierarchyBuilder checkHierarchy;
    checkHierarchy.computeHierarchy(module);
    if (eagerInline && checkHierarchy.isCyclic()) {
        std::cerr << "Cannot use \"-eager-inline\" with a cyclic call hierarchy!" << std::endl;
        return 7;
    }

    // transform!
    NondefFactory ndf(module);
    transformModule(module, function, ndf);

    // name them!
    InstNamer namer;
    namer.visit(module);

    // check them!
    const llvm::Type *boolType = llvm::Type::getInt1Ty(context);
    const llvm::Type *floatType = llvm::Type::getFloatTy(context);
    const llvm::Type *doubleType = llvm::Type::getDoubleTy(context);
    InstChecker checker(boolType, floatType, doubleType);
    checker.visit(module);

    // print it!
    if (debug) {
#if LLVM_VERSION < VERSION(3, 5)
        llvm::PassManager printPass;
        printPass.add(llvm::createPrintModulePass(&llvm::outs()));
        printPass.run(*module);
#else
        llvm::outs() << *module << '\n';
#endif
    }
    if (dumpLL) {
        std::string outFile = filename.substr(0, filename.length() - 3) + ".ll";
#if LLVM_VERSION < VERSION(3, 5)
        std::string errorInfo;
        llvm::raw_fd_ostream stream(outFile.data(), errorInfo);
        if (errorInfo.empty()) {
            llvm::PassManager dumpPass;
            dumpPass.add(llvm::createPrintModulePass(&stream));
            dumpPass.run(*module);
            stream.close();
        }
#elif LLVM_VERSION == VERSION(3, 5)
        std::string errorInfo;
        llvm::raw_fd_ostream stream(outFile.data(), errorInfo, llvm::sys::fs::F_Text);
        if (errorInfo.empty()) {
            stream << *module << '\n';
            stream.close();
        }
#else
        std::error_code errorCode;
        llvm::raw_fd_ostream stream(outFile.data(), errorCode, llvm::sys::fs::F_Text);
        if (!errorCode) {
            stream << *module << '\n';
            stream.close();
        }
#endif
    }

    // check for junk
    std::list<llvm::Instruction*> unsuitable = checker.getUnsuitableInsts();
    if (!unsuitable.empty()) {
        std::cerr << "Unsuitable instructions detected:" << std::endl;
        for (std::list<llvm::Instruction*>::iterator i = unsuitable.begin(), e = unsuitable.end(); i != e; ++i) {
            (*i)->dump();
        }
        return 6;
    }

    // compute recursion hierarchy
    HierarchyBuilder hierarchy;
    hierarchy.computeHierarchy(module);
    std::list<std::list<llvm::Function*> > sccs = hierarchy.getSccs();

    std::map<llvm::Function*, std::list<llvm::Function*> > funToScc;
    for (std::list<std::list<llvm::Function*> >::iterator i = sccs.begin(), e = sccs.end(); i != e; ++i) {
        std::list<llvm::Function*> scc = *i;
        for (std::list<llvm::Function*>::iterator si = scc.begin(), se = scc.end(); si != se; ++si) {
            funToScc.insert(std::make_pair(*si, scc));
        }
    }
    std::list<llvm::Function*> dependsOnList = hierarchy.getTransitivelyCalledFunctions(function);
    std::set<llvm::Function*> dependsOn;
    dependsOn.insert(dependsOnList.begin(), dependsOnList.end());
    dependsOn.insert(function);
    std::list<std::list<llvm::Function*> > dependsOnSccs;
    for (std::list<std::list<llvm::Function*> >::iterator i = sccs.begin(), e = sccs.end(); i != e; ++i) {
        std::list<llvm::Function*> scc = *i;
        for (std::list<llvm::Function*>::iterator fi = scc.begin(), fe = scc.end(); fi != fe; ++fi) {
            llvm::Function *f = *fi;
            if (dependsOn.find(f) != dependsOn.end()) {
                dependsOnSccs.push_back(scc);
                break;
            }
        }
    }

    // compute may/must info, propagated conditions, and compute loop exiting blocks for all functions
    std::map<llvm::Function*, MayMustMap> mmMap;
    std::map<llvm::Function*, std::set<llvm::GlobalVariable*> > funcMayZapDirect;
    std::map<llvm::Function*, TrueFalseMap> tfMap;
    std::map<llvm::Function*, std::set<llvm::BasicBlock*> > lebMap;
    std::map<llvm::Function*, ConditionMap> elcMap;
    for (std::set<llvm::Function*>::iterator df = dependsOn.begin(), dfe = dependsOn.end(); df != dfe; ++df) {
        llvm::Function *func = *df;
        std::pair<MayMustMap, std::set<llvm::GlobalVariable*> > tmp = getMayMustMap(func);
        mmMap.insert(std::make_pair(func, tmp.first));
        funcMayZapDirect.insert(std::make_pair(func, tmp.second));
        std::set<llvm::BasicBlock*> lcbs;
        if (onlyLoopConditions) {
            lcbs = getLoopConditionBlocks(func);
            lebMap.insert(std::make_pair(func, lcbs));
        }
        if (propagateConditions) {
            tfMap.insert(std::make_pair(func, getConditionPropagationMap(func, lcbs)));
        }
        if (explicitizeLoopConditions) {
            elcMap.insert(std::make_pair(func, getExplicitizedLoopConditionMap(func)));
        }
    }

    // transitively close funcMayZapDirect
    std::map<llvm::Function*, std::set<llvm::GlobalVariable*> > funcMayZap;
    for (std::set<llvm::Function*>::iterator df = dependsOn.begin(), dfe = dependsOn.end(); df != dfe; ++df) {
        llvm::Function *func = *df;
        std::set<llvm::GlobalVariable*> funcTransZap;
        std::list<llvm::Function*> funcDependsOnList = hierarchy.getTransitivelyCalledFunctions(func);
        std::set<llvm::Function*> funcDependsOn;
        funcDependsOn.insert(funcDependsOnList.begin(), funcDependsOnList.end());
        funcDependsOn.insert(func);
        for (std::set<llvm::Function*>::iterator depfi = funcDependsOn.begin(), depfe = funcDependsOn.end(); depfi != depfe; ++depfi) {
            llvm::Function *depf = *depfi;
            std::map<llvm::Function*, std::set<llvm::GlobalVariable*> >::iterator depfZap = funcMayZapDirect.find(depf);
            if (depfZap == funcMayZapDirect.end()) {
                std::cerr << "Could not find alias information (" << __FILE__ << ":" << __LINE__ << ")!" << std::endl;
                exit(9876);
            }
            funcTransZap.insert(depfZap->second.begin(), depfZap->second.end());
        }
        funcMayZap.insert(std::make_pair(func, funcTransZap));
    }

    // convert sccs separately
    unsigned int num = static_cast<unsigned int>(dependsOnSccs.size());
    unsigned int currNum = 0;
    for (std::list<std::list<llvm::Function*> >::iterator scci = dependsOnSccs.begin(), scce = dependsOnSccs.end(); scci != scce; ++scci) {
        std::list<llvm::Function*> scc = *scci;
        std::list<ref<Rule> > allRules;
        std::list<ref<Rule> > allCondensedRules;
        std::list<ref<Rule> > allKittelizedRules;
        std::list<ref<Rule> > allSlicedRules;
        if (debug) {
            std::cout << "========================================" << std::endl;
        }
        if ((!complexityTuples && !uniformComplexityTuples) || debug) {
            std::cout << "///*** " << getPartNumber(++currNum, num) << '_' << getSccName(scc) << " ***///" << std::endl;
        }
        std::set<llvm::Function*> sccSet;
        sccSet.insert(scc.begin(), scc.end());

        std::set<std::string> complexityLHSs;

        for (std::list<llvm::Function*>::iterator fi = scc.begin(), fe = scc.end(); fi != fe; ++fi) {
            llvm::Function *curr = *fi;
            Converter converter(boolType, assumeIsControl, selectIsControl, onlyMultiPredIsControl, boundedIntegers, unsignedEncoding, onlyLoopConditions, divisionConstraintType, bitwiseConditions, complexityTuples || uniformComplexityTuples);
            std::map<llvm::Function*, MayMustMap>::iterator tmp1 = mmMap.find(curr);
            if (tmp1 == mmMap.end()) {
                std::cerr << "Could not find alias information (" << __FILE__ << ":" << __LINE__ << ")!" << std::endl;
                exit(9876);
            }
            MayMustMap curr_mmMap = tmp1->second;
            std::map<llvm::Function*, TrueFalseMap>::iterator tmp2 = tfMap.find(curr);
            TrueFalseMap curr_tfMap;
            if (tmp2 != tfMap.end()) {
                curr_tfMap = tmp2->second;
            }
            std::map<llvm::Function*, std::set<llvm::BasicBlock*> >::iterator tmp3 = lebMap.find(curr);
            std::set<llvm::BasicBlock*> curr_leb;
            if (tmp3 != lebMap.end()) {
                curr_leb = tmp3->second;
            }
            std::map<llvm::Function*, ConditionMap>::iterator tmp4 = elcMap.find(curr);
            ConditionMap curr_elcMap;
            if (tmp4 != elcMap.end()) {
                curr_elcMap = tmp4->second;
            }
            converter.phase1(curr, sccSet, curr_mmMap, funcMayZap, curr_tfMap, curr_leb, curr_elcMap);
            converter.phase2(curr, sccSet, curr_mmMap, funcMayZap, curr_tfMap, curr_leb, curr_elcMap);
            std::list<ref<Rule> > rules = converter.getRules();
            std::list<ref<Rule> > condensedRules = converter.getCondensedRules();
            std::list<ref<Rule> > kittelizedRules = kittelize(condensedRules, smtSolver);
            Slicer slicer(curr, converter.getPhiVariables());
            std::list<ref<Rule> > slicedRules;
            if (noSlicing) {
                slicedRules = kittelizedRules;
            } else {
                slicedRules = slicer.sliceUsage(kittelizedRules);
                slicedRules = slicer.sliceConstraint(slicedRules);
                slicedRules = slicer.sliceDefined(slicedRules);
                slicedRules = slicer.sliceStillUsed(slicedRules, conservativeSlicing);
                slicedRules = slicer.sliceTrivialNondefConstraints(slicedRules);
                slicedRules = slicer.sliceDuplicates(slicedRules);
            }
            if (boundedIntegers) {
                slicedRules = kittelize(addBoundConstraints(slicedRules, converter.getBitwidthMap(), unsignedEncoding), smtSolver);
            }
            if (debug) {
                allRules.insert(allRules.end(), rules.begin(), rules.end());
                allCondensedRules.insert(allCondensedRules.end(), condensedRules.begin(), condensedRules.end());
                allKittelizedRules.insert(allKittelizedRules.end(), kittelizedRules.begin(), kittelizedRules.end());
            }
            if (simplifyConds) {
                slicedRules = simplifyConstraints(slicedRules);
            }
            allSlicedRules.insert(allSlicedRules.end(), slicedRules.begin(), slicedRules.end());

            if (complexityTuples || uniformComplexityTuples) {
                std::set<std::string> tmpLHSs = converter.getComplexityLHSs();
                complexityLHSs.insert(tmpLHSs.begin(), tmpLHSs.end());
            }
        }
        if (debug) {
            std::cout << "========================================" << std::endl;
            for (std::list<ref<Rule> >::iterator i = allRules.begin(), e = allRules.end(); i != e; ++i) {
                ref<Rule> tmp = *i;
                std::cout << tmp->toString() << std::endl;
            }
            std::cout << "========================================" << std::endl;
            for (std::list<ref<Rule> >::iterator i = allCondensedRules.begin(), e = allCondensedRules.end(); i != e; ++i) {
                ref<Rule> tmp = *i;
                std::cout << tmp->toString() << std::endl;
            }
            std::cout << "========================================" << std::endl;
            for (std::list<ref<Rule> >::iterator i = allKittelizedRules.begin(), e = allKittelizedRules.end(); i != e; ++i) {
                ref<Rule> tmp = *i;
                std::cout << tmp->toString() << std::endl;
            }
            std::cout << "========================================" << std::endl;
        }
        if (complexityTuples) {
            printComplexityTuples(allSlicedRules, complexityLHSs, std::cout);
        } else if (uniformComplexityTuples) {
            std::ostringstream startfun;
            startfun << "eval_" << getSccName(scc) << "_start";
            std::string name = startfun.str();
            printUniformComplexityTuples(allSlicedRules, complexityLHSs, name, std::cout);
        } else if (t2output) {
            std::string startFun = "eval_" + getSccName(scc) + "_start";
            printT2System(allSlicedRules, startFun, std::cout);
        } else {
            for (std::list<ref<Rule> >::iterator i = allSlicedRules.begin(), e = allSlicedRules.end(); i != e; ++i) {
                ref<Rule> tmp = *i;
                std::cout << tmp->toKittelString() << std::endl;
            }
        }
    }

    return 0;
}
/*!
  \internal
  Sets the new constraints in the simplex solver and returns whether the problem
  is feasible.

  This method sets the new constraints, normalizes them, creates the simplex matrix
  and runs the first simplex phase.
*/
bool QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints)
{
    ////////////////////////////
    // Reset to initial state //
    ////////////////////////////
    clearDataStructures();

    if (newConstraints.isEmpty())
        return true;    // we are ok with no constraints

    // Make deep copy of constraints. We need this copy because we may change
    // them in the simplification method.
    for (int i = 0; i < newConstraints.size(); ++i) {
        QSimplexConstraint *c = new QSimplexConstraint;
        c->constant = newConstraints[i]->constant;
        c->ratio = newConstraints[i]->ratio;
        c->variables = newConstraints[i]->variables;
        constraints << c;
    }

    // Remove constraints of type Var == K and replace them for their value.
    if (!simplifyConstraints(&constraints)) {
        qWarning() << "QSimplex: No feasible solution!";
        clearDataStructures();
        return false;
    }

    ///////////////////////////////////////
    // Prepare variables and constraints //
    ///////////////////////////////////////

    // Set Variables direct mapping.
    // "variables" is a list that provides a stable, indexed list of all variables
    // used in this problem.
    QSet<QSimplexVariable *> variablesSet;
    for (int i = 0; i < constraints.size(); ++i)
        variablesSet += \
            QSet<QSimplexVariable *>::fromList(constraints[i]->variables.keys());
    variables = variablesSet.toList();

    // Set Variables reverse mapping
    // We also need to be able to find the index for a given variable, to do that
    // we store in each variable its index.
    for (int i = 0; i < variables.size(); ++i) {
        // The variable "0" goes at the column "1", etc...
        variables[i]->index = i + 1;
    }

    // Normalize Constraints
    // In this step, we prepare the constraints in two ways:
    // Firstly, we modify all constraints of type "LessOrEqual" or "MoreOrEqual"
    // by the adding slack or surplus variables and making them "Equal" constraints.
    // Secondly, we need every single constraint to have a direct, easy feasible
    // solution. Constraints that have slack variables are already easy to solve,
    // to all the others we add artificial variables.
    //
    // At the end we modify the constraints as follows:
    //  - LessOrEqual: SLACK variable is added.
    //  - Equal: ARTIFICIAL variable is added.
    //  - More or Equal: ARTIFICIAL and SURPLUS variables are added.
    int variableIndex = variables.size();
    QList <QSimplexVariable *> artificialList;

    for (int i = 0; i < constraints.size(); ++i) {
        QSimplexVariable *slack;
        QSimplexVariable *surplus;
        QSimplexVariable *artificial;

        Q_ASSERT(constraints[i]->helper.first == 0);
        Q_ASSERT(constraints[i]->artificial == 0);

        switch(constraints[i]->ratio) {
        case QSimplexConstraint::LessOrEqual:
            slack = new QSimplexVariable;
            slack->index = ++variableIndex;
            constraints[i]->helper.first = slack;
            constraints[i]->helper.second = 1.0;
            break;
        case QSimplexConstraint::MoreOrEqual:
            surplus = new QSimplexVariable;
            surplus->index = ++variableIndex;
            constraints[i]->helper.first = surplus;
            constraints[i]->helper.second = -1.0;
            // fall through
        case QSimplexConstraint::Equal:
            artificial = new QSimplexVariable;
            constraints[i]->artificial = artificial;
            artificialList += constraints[i]->artificial;
            break;
        }
    }

    // All original, slack and surplus have already had its index set
    // at this point. We now set the index of the artificial variables
    // as to ensure they are at the end of the variable list and therefore
    // can be easily removed at the end of this method.
    firstArtificial = variableIndex + 1;
    for (int i = 0; i < artificialList.size(); ++i)
        artificialList[i]->index = ++variableIndex;
    artificialList.clear();

    /////////////////////////////
    // Fill the Simplex matrix //
    /////////////////////////////

    // One for each variable plus the Basic and BFS columns (first and last)
    columns = variableIndex + 2;
    // One for each constraint plus the objective function
    rows = constraints.size() + 1;

    matrix = (qreal *)malloc(sizeof(qreal) * columns * rows);
    if (!matrix) {
        qWarning() << "QSimplex: Unable to allocate memory!";
        return false;
    }
    for (int i = columns * rows - 1; i >= 0; --i)
        matrix[i] = 0.0;

    // Fill Matrix
    for (int i = 1; i <= constraints.size(); ++i) {
        QSimplexConstraint *c = constraints[i - 1];

        if (c->artificial) {
            // Will use artificial basic variable
            setValueAt(i, 0, c->artificial->index);
            setValueAt(i, c->artificial->index, 1.0);

            if (c->helper.second != 0.0) {
                // Surplus variable
                setValueAt(i, c->helper.first->index, c->helper.second);
            }
        } else {
            // Slack is used as the basic variable
            Q_ASSERT(c->helper.second == 1.0);
            setValueAt(i, 0, c->helper.first->index);
            setValueAt(i, c->helper.first->index, 1.0);
        }

        QHash<QSimplexVariable *, qreal>::const_iterator iter;
        for (iter = c->variables.constBegin();
             iter != c->variables.constEnd();
             ++iter) {
            setValueAt(i, iter.key()->index, iter.value());
        }

        setValueAt(i, columns - 1, c->constant);
    }

    // Set objective for the first-phase Simplex.
    // Z = -1 * sum_of_artificial_vars
    for (int j = firstArtificial; j < columns - 1; ++j)
        setValueAt(0, j, 1.0);

    // Maximize our objective (artificial vars go to zero)
    solveMaxHelper();

    // If there is a solution where the sum of all artificial
    // variables is zero, then all of them can be removed and yet
    // we will have a feasible (but not optimal) solution for the
    // original problem.
    // Otherwise, we clean up our structures and report there is
    // no feasible solution.
    if ((valueAt(0, columns - 1) != 0.0) && (qAbs(valueAt(0, columns - 1)) > 0.00001)) {
        qWarning() << "QSimplex: No feasible solution!";
        clearDataStructures();
        return false;
    }

    // Remove artificial variables. We already have a feasible
    // solution for the first problem, thus we don't need them
    // anymore.
    clearColumns(firstArtificial, columns - 2);

    return true;
}