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; }