/*============================================================================== * FUNCTION: CfgTest::testRenameVars * OVERVIEW: Test the renaming of variables *============================================================================*/ void CfgTest::testRenameVars () { BinaryFileFactory bff; BinaryFile* pBF = bff.Load(FRONTIER_PENTIUM); CPPUNIT_ASSERT(pBF != 0); Prog* prog = new Prog; FrontEnd* pFE = new PentiumFrontEnd(pBF, prog, &bff); Type::clearNamedTypes(); prog->setFrontEnd(pFE); pFE->decode(prog); UserProc* pProc = (UserProc*) prog->getProc(0); Cfg* cfg = pProc->getCFG(); DataFlow* df = pProc->getDataFlow(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); df->dominators(cfg); df->placePhiFunctions(pProc); pProc->numberStatements(); // After placing phi functions! df->renameBlockVars(pProc, 0, 1); // Block 0, mem depth 1 // MIKE: something missing here? delete pFE; }
/** * Test the renaming of variables. */ void CfgTest::testRenameVars() { auto prog = Prog::open(FRONTIER_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); DataFlow *df = pProc->getDataFlow(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); df->dominators(cfg); df->placePhiFunctions(pProc); pProc->numberStatements(); // After placing phi functions! df->renameBlockVars(pProc, 0, 1); // Block 0, mem depth 1 // MIKE: something missing here? delete prog; }
/** * Test the placing of phi functions. */ void CfgTest::testPlacePhi() { auto prog = Prog::open(FRONTIER_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); DataFlow *df = pProc->getDataFlow(); df->dominators(cfg); df->placePhiFunctions(pProc); // m[r29 - 8] (x for this program) Exp *e = Location::memOf( new Binary(opMinus, Location::regOf(29), new Const(4))); // A_phi[x] should be the set {7 8 10 15 20 21} (all the join points) std::ostringstream ost; std::set<int> &A_phi = df->getA_phi(e); for (const auto &ii : A_phi) ost << ii << " "; std::string expected("7 8 10 15 20 21 "); CPPUNIT_ASSERT_EQUAL(expected, ost.str()); delete prog; }
/** * Test the dominator frontier code. */ void CfgTest::testDominators() { #define FRONTIER_FOUR 0x08048347 #define FRONTIER_FIVE 0x08048351 #define FRONTIER_TWELVE 0x080483b2 #define FRONTIER_THIRTEEN 0x080483b9 auto prog = Prog::open(FRONTIER_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); bool gotMain; ADDRESS addr = fe->getMainEntryPoint(gotMain); CPPUNIT_ASSERT(addr != NO_ADDRESS); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); DataFlow *df = pProc->getDataFlow(); df->dominators(cfg); // Find BB "5" (as per Appel, Figure 19.5). BasicBlock *bb = nullptr; for (const auto &b : *cfg) { if (b->getLowAddr() == FRONTIER_FIVE) { bb = b; break; } } CPPUNIT_ASSERT(bb); std::ostringstream expected, actual; #if 0 expected << std::hex << FRONTIER_FIVE << " " << FRONTIER_THIRTEEN << " " << FRONTIER_TWELVE << " " << FRONTIER_FOUR << " " << std::dec; #endif expected << std::hex << FRONTIER_THIRTEEN << " " << FRONTIER_FOUR << " " << FRONTIER_TWELVE << " " << FRONTIER_FIVE << " " << std::dec; int n5 = df->pbbToNode(bb); std::set<int> &DFset = df->getDF(n5); for (const auto &ii : DFset) actual << std::hex << (unsigned)df->nodeToBB(ii)->getLowAddr() << std::dec << " "; CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str()); delete prog; }
/*============================================================================== * FUNCTION: CfgTest::testPlacePhi2 * OVERVIEW: Test a case where a phi function is not needed *============================================================================*/ void CfgTest::testPlacePhi2 () { BinaryFileFactory bff; BinaryFile* pBF = bff.Load(IFTHEN_PENTIUM); CPPUNIT_ASSERT(pBF != 0); Prog* prog = new Prog; FrontEnd* pFE = new PentiumFrontEnd(pBF, prog, &bff); Type::clearNamedTypes(); prog->setFrontEnd(pFE); pFE->decode(prog); UserProc* pProc = (UserProc*) prog->getProc(0); Cfg* cfg = pProc->getCFG(); DataFlow* df = pProc->getDataFlow(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); df->dominators(cfg); df->placePhiFunctions(pProc); // In this program, x is allocated at [ebp-4], a at [ebp-8], and // b at [ebp-12] // We check that A_phi[ m[ebp-8] ] is 4, and that // A_phi A_phi[ m[ebp-8] ] is null // (block 4 comes out with n=4) std::string expected = "4 "; std::ostringstream actual; // m[r29 - 8] Exp* e = new Unary(opMemOf, new Binary(opMinus, Location::regOf(29), new Const(8))); std::set<int>& s = df->getA_phi(e); std::set<int>::iterator pp; for (pp = s.begin(); pp != s.end(); pp++) actual << *pp << " "; CPPUNIT_ASSERT_EQUAL(expected, actual.str()); delete e; expected = ""; std::ostringstream actual2; // m[r29 - 12] e = new Unary(opMemOf, new Binary(opMinus, Location::regOf(29), new Const(12))); std::set<int>& s2 = df->getA_phi(e); for (pp = s2.begin(); pp != s2.end(); pp++) actual2 << *pp << " "; CPPUNIT_ASSERT_EQUAL(expected, actual2.str()); delete e; delete pFE; }
/** * Test a case where a phi function is not needed. */ void CfgTest::testPlacePhi2() { auto prog = Prog::open(IFTHEN_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); DataFlow *df = pProc->getDataFlow(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); df->dominators(cfg); df->placePhiFunctions(pProc); // In this program, x is allocated at [ebp-4], a at [ebp-8], and // b at [ebp-12] // We check that A_phi[ m[ebp-8] ] is 4, and that // A_phi A_phi[ m[ebp-8] ] is null // (block 4 comes out with n=4) std::string expected = "4 "; std::ostringstream actual; // m[r29 - 8] Exp *e = Location::memOf( new Binary(opMinus, Location::regOf(29), new Const(8))); std::set<int> &s = df->getA_phi(e); for (const auto &pp : s) actual << pp << " "; CPPUNIT_ASSERT_EQUAL(expected, actual.str()); delete e; expected = ""; std::ostringstream actual2; // m[r29 - 12] e = Location::memOf( new Binary(opMinus, Location::regOf(29), new Const(12))); std::set<int> &s2 = df->getA_phi(e); for (const auto &pp : s2) actual2 << pp << " "; CPPUNIT_ASSERT_EQUAL(expected, actual2.str()); delete e; delete prog; }
/** * Test a case where semi dominators are different to dominators. */ void CfgTest::testSemiDominators() { #define SEMI_L 0x80483b0 #define SEMI_M 0x80483e2 #define SEMI_B 0x8048345 #define SEMI_D 0x8048354 #define SEMI_M 0x80483e2 auto prog = Prog::open(SEMI_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); bool gotMain; ADDRESS addr = fe->getMainEntryPoint(gotMain); CPPUNIT_ASSERT(addr != NO_ADDRESS); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); DataFlow *df = pProc->getDataFlow(); df->dominators(cfg); // Find BB "L (6)" (as per Appel, Figure 19.8). BasicBlock *bb = nullptr; for (const auto &b : *cfg) { if (b->getLowAddr() == SEMI_L) { bb = b; break; } } CPPUNIT_ASSERT(bb); int nL = df->pbbToNode(bb); // The dominator for L should be B, where the semi dominator is D // (book says F) unsigned actual_dom = (unsigned)df->nodeToBB(df->getIdom(nL))->getLowAddr(); unsigned actual_semi = (unsigned)df->nodeToBB(df->getSemi(nL))->getLowAddr(); CPPUNIT_ASSERT_EQUAL((unsigned)SEMI_B, actual_dom); CPPUNIT_ASSERT_EQUAL((unsigned)SEMI_D, actual_semi); // Check the final dominator frontier as well; should be M and B std::ostringstream expected, actual; #if 0 expected << std::hex << SEMI_M << " " << SEMI_B << " " << std::dec; #endif expected << std::hex << SEMI_B << " " << SEMI_M << " " << std::dec; std::set<int> &DFset = df->getDF(nL); for (const auto &ii : DFset) actual << std::hex << (unsigned)df->nodeToBB(ii)->getLowAddr() << std::dec << " "; CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str()); delete prog; }
void CfgTest::testDominators () { BinaryFileFactory bff; BinaryFile *pBF = bff.Load(FRONTIER_PENTIUM); CPPUNIT_ASSERT(pBF != 0); Prog* prog = new Prog; FrontEnd *pFE = new PentiumFrontEnd(pBF, prog, &bff); Type::clearNamedTypes(); prog->setFrontEnd(pFE); pFE->decode(prog); bool gotMain; ADDRESS addr = pFE->getMainEntryPoint(gotMain); CPPUNIT_ASSERT (addr != NO_ADDRESS); UserProc* pProc = (UserProc*) prog->getProc(0); Cfg* cfg = pProc->getCFG(); DataFlow* df = pProc->getDataFlow(); df->dominators(cfg); // Find BB "5" (as per Appel, Figure 19.5). BB_IT it; PBB bb = cfg->getFirstBB(it); while (bb && bb->getLowAddr() != FRONTIER_FIVE) { bb = cfg->getNextBB(it); } CPPUNIT_ASSERT(bb); std::ostringstream expected, actual; //expected << std::hex << FRONTIER_FIVE << " " << FRONTIER_THIRTEEN << " " << FRONTIER_TWELVE << " " << // FRONTIER_FOUR << " "; expected << std::hex << FRONTIER_THIRTEEN << " " << FRONTIER_FOUR << " " << FRONTIER_TWELVE << " " << FRONTIER_FIVE << " "; int n5 = df->pbbToNode(bb); std::set<int>::iterator ii; std::set<int>& DFset = df->getDF(n5); for (ii=DFset.begin(); ii != DFset.end(); ii++) actual << std::hex << (unsigned)df->nodeToBB(*ii)->getLowAddr() << " "; CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str()); pBF->UnLoad(); delete pFE; }
/*! * \brief Constructor * \param procedure Procedure to analyze */ LiveVariables::LiveVariables(const IR::Procedure &procedure, const FlowGraph &flowGraph) : mProcedure(procedure) { Util::Timer timer; timer.start(); // Construct the set of all variables in the procedure std::set<const IR::Symbol*> all; for(const std::unique_ptr<IR::Symbol> &symbol : mProcedure.symbols()) { all.insert(symbol.get()); } // Construct gen/kill sets for data flow analysis. std::map<const IR::Entry*, std::set<const IR::Symbol*>> gen; std::map<const IR::Entry*, std::set<const IR::Symbol*>> kill; for(const IR::Entry *entry : mProcedure.entries()) { for(const IR::Symbol *symbol : all) { std::set<const IR::Symbol*> &g = gen[entry]; if(entry->uses(symbol)) { // An entry which uses a symbol adds that symbol to the set of live symbols g.insert(symbol); } const IR::Symbol *assign = entry->assign(); if(assign && g.find(assign) == g.end()) { // An entry which assigns to a symbol and does not use it kills that symbol // from the live symbol set kill[entry].insert(assign); } } } // Perform a backwards data flow analysis on the procedure, using the gen and kill sets // constructed above. DataFlow<const IR::Symbol*> dataFlow; mMap = dataFlow.analyze(flowGraph, gen, kill, all, DataFlow<const IR::Symbol*>::Meet::Union, DataFlow<const IR::Symbol*>::Direction::Backward); Util::log("opt.time") << " LiveVariables(" << mProcedure.name() << "): " << timer.stop() << "ms" << std::endl; }
void CfgTest::testSemiDominators () { BinaryFileFactory bff; BinaryFile* pBF = bff.Load(SEMI_PENTIUM); CPPUNIT_ASSERT(pBF != 0); Prog* prog = new Prog; FrontEnd* pFE = new PentiumFrontEnd(pBF, prog, &bff); Type::clearNamedTypes(); prog->setFrontEnd(pFE); pFE->decode(prog); bool gotMain; ADDRESS addr = pFE->getMainEntryPoint(gotMain); CPPUNIT_ASSERT (addr != NO_ADDRESS); UserProc* pProc = (UserProc*) prog->getProc(0); Cfg* cfg = pProc->getCFG(); DataFlow* df = pProc->getDataFlow(); df->dominators(cfg); // Find BB "L (6)" (as per Appel, Figure 19.8). BB_IT it; PBB bb = cfg->getFirstBB(it); while (bb && bb->getLowAddr() != SEMI_L) { bb = cfg->getNextBB(it); } CPPUNIT_ASSERT(bb); int nL = df->pbbToNode(bb); // The dominator for L should be B, where the semi dominator is D // (book says F) unsigned actual_dom = (unsigned)df->nodeToBB(df->getIdom(nL))->getLowAddr(); unsigned actual_semi = (unsigned)df->nodeToBB(df->getSemi(nL))->getLowAddr(); CPPUNIT_ASSERT_EQUAL((unsigned)SEMI_B, actual_dom); CPPUNIT_ASSERT_EQUAL((unsigned)SEMI_D, actual_semi); // Check the final dominator frontier as well; should be M and B std::ostringstream expected, actual; //expected << std::hex << SEMI_M << " " << SEMI_B << " "; expected << std::hex << SEMI_B << " " << SEMI_M << " "; std::set<int>::iterator ii; std::set<int>& DFset = df->getDF(nL); for (ii=DFset.begin(); ii != DFset.end(); ii++) actual << std::hex << (unsigned)df->nodeToBB(*ii)->getLowAddr() << " "; CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str()); delete pFE; }
/*============================================================================== * FUNCTION: CfgTest::testPlacePhi * OVERVIEW: Test the placing of phi functions *============================================================================*/ void CfgTest::testPlacePhi () { BinaryFileFactory bff; BinaryFile* pBF = bff.Load(FRONTIER_PENTIUM); CPPUNIT_ASSERT(pBF != 0); Prog* prog = new Prog; FrontEnd* pFE = new PentiumFrontEnd(pBF, prog, &bff); Type::clearNamedTypes(); prog->setFrontEnd(pFE); pFE->decode(prog); UserProc* pProc = (UserProc*) prog->getProc(0); Cfg* cfg = pProc->getCFG(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); DataFlow* df = pProc->getDataFlow(); df->dominators(cfg); df->placePhiFunctions(pProc); // m[r29 - 8] (x for this program) Exp* e = new Unary(opMemOf, new Binary(opMinus, Location::regOf(29), new Const(4))); // A_phi[x] should be the set {7 8 10 15 20 21} (all the join points) std::ostringstream ost; std::set<int>::iterator ii; std::set<int>& A_phi = df->getA_phi(e); for (ii = A_phi.begin(); ii != A_phi.end(); ++ii) ost << *ii << " "; std::string expected("7 8 10 15 20 21 "); CPPUNIT_ASSERT_EQUAL(expected, ost.str()); delete pFE; }
void Generator<Annotation, Runtime, Driver>::generate( const LoopTrees<Annotation> & loop_trees, std::set<std::list<Kernel<Annotation, Runtime> *> > & kernel_lists, LoopMapper<Annotation, Runtime> & loop_mapper, LoopTiler<Annotation, Runtime> & loop_tiler, DataFlow<Annotation, Runtime> & data_flow ) { typedef typename LoopTrees<Annotation>::loop_t loop_t; typedef typename LoopTiler<Annotation, Runtime>::loop_tiling_t loop_tiling_t; typedef Kernel<Annotation, Runtime> Kernel; typename std::set<std::list<Kernel *> >::const_iterator it_kernel_list; typename std::list<Kernel *>::const_iterator it_kernel; typename DataFlow<Annotation, Runtime>::context_t df_ctx; // 0 - init data flow data_flow.createContextFromLoopTree(loop_trees, df_ctx); data_flow.markSplittedData(df_ctx); // 1 - Loop Selection : Generate multiple list of kernel that implement the given LoopTree loop_mapper.createKernels(loop_trees, kernel_lists); // 2 - Data Flow : performs data-flow analysis for each list of kernel for (it_kernel_list = kernel_lists.begin(); it_kernel_list != kernel_lists.end(); it_kernel_list++) data_flow.generateFlowSets(*it_kernel_list, df_ctx); // 3 - Arguments : determines the list of arguments needed by each kernel for (it_kernel_list = kernel_lists.begin(); it_kernel_list != kernel_lists.end(); it_kernel_list++) for (it_kernel = it_kernel_list->begin(); it_kernel != it_kernel_list->end(); it_kernel++) buildArgumentLists(loop_trees, *it_kernel); for (it_kernel_list = kernel_lists.begin(); it_kernel_list != kernel_lists.end(); it_kernel_list++) for (it_kernel = it_kernel_list->begin(); it_kernel != it_kernel_list->end(); it_kernel++) { // 4 - Iterations Mapping : determines the "shape" of every loop of each kernel. // The "shape" of a loop is how this loop is adapted to the execution model. std::map<loop_t *, std::vector<loop_tiling_t *> > tiling_map; loop_tiler.determineTiles(*it_kernel, tiling_map); std::set<std::map<loop_t *, loop_tiling_t *> > loop_tiling_set; buildAllTileConfigs<Annotation, Runtime>( std::map<loop_t *, loop_tiling_t *>(), tiling_map.begin(), tiling_map.end(), loop_tiling_set ); // 5 - Code Generation size_t cnt = 0; typename std::set<std::map<loop_t *, loop_tiling_t *> >::iterator it_loop_tiling_map; for (it_loop_tiling_map = loop_tiling_set.begin(); it_loop_tiling_map != loop_tiling_set.end(); it_loop_tiling_map++) { typename ::MFB::KLT<Kernel>::object_desc_t kernel_desc(cnt++, *it_kernel, p_file_id); kernel_desc.tiling.insert(it_loop_tiling_map->begin(), it_loop_tiling_map->end()); typename Kernel::kernel_desc_t * kernel = p_driver.template build<Kernel>(kernel_desc); (*it_kernel)->addKernel(kernel); } typename std::map<loop_t *, std::vector<loop_tiling_t *> >::const_iterator it_tiling_vect; typename std::vector<loop_tiling_t *>::const_iterator it_tiling; for (it_tiling_vect = tiling_map.begin(); it_tiling_vect != tiling_map.end(); it_tiling_vect++) for (it_tiling = it_tiling_vect->second.begin(); it_tiling != it_tiling_vect->second.end(); it_tiling++) delete *it_tiling; } }
int main(int argc, char **argv) { int exitcode = 0; const char* progname = argv[0]; // build option parser void* argtable[] = { h = arg_lit0("h","help", "print this help and exit"), version = arg_lit0("v","version", "print version information and exit"), verbose = arg_lit0(NULL, "verbose", "more logs"), l = arg_lit0("l", NULL, "list all available components"), d = arg_str0("d","describe","component", "Describe a component, show its parameters"), datablock = arg_int0("s",NULL, "datablocksize", "prefered data block size"), libs = arg_strn("x","loadlibrary","libnames",0,10,"yaafe component library name to load."), dataflow = arg_file0("c",NULL,"file","dataflow to process"), format = arg_str0("o", NULL,"format","output format, see available output formats below."), formatparams = arg_strn("p", NULL,"key=value",0,10,"output format parameters (see below)"), outdir = arg_str0("b", NULL,"dir","output base directory"), files = arg_filen(NULL,NULL,"FILES",0,argc,"audio files to process"), the_end = arg_end(20) }; int nerrors = arg_parse(argc, argv, argtable); /* special case: '--help' takes precedence over error reporting */ if (h->count > 0) { printf("%s is a dataflow processing engine\n", progname); printf("\n"); printf("Usage: %s", progname); arg_print_syntax(stdout,argtable,"\n"); arg_print_glossary(stdout,argtable, " %-25s %s\n"); printf("\n"); exitcode = ComponentFactory::instance()->loadLibrary("yaafe-io"); if (exitcode) { printf("error while loading yaafe-io library !\n"); } else { printOutputFormats(); exitcode = 0; } goto exit; } /* special case: '--version' takes precedence error reporting */ if (version->count > 0) { printf("%s version %s\n", progname, ComponentFactory::version()); exitcode = 0; goto exit; } /* If the parser returned any errors then display them and exit */ if (nerrors > 0) { /* Display the error details contained in the arg_end struct.*/ arg_print_errors(stdout,the_end, progname); printf("Try '%s --help' for more information.\n", progname); exitcode = 1; goto exit; } if (verbose->count) verboseFlag = true; if (datablock->count) DataBlock::setPreferedBlockSize(datablock->ival[0]); // register io components exitcode = ComponentFactory::instance()->loadLibrary("yaafe-io"); if (exitcode) goto exit; // register given dynamic libraries for (int i=0; i<libs->count; i++) { exitcode = ComponentFactory::instance()->loadLibrary(libs->sval[i]); if (exitcode) goto exit; } if (l->count) { listComponents(); goto exit; } if (d->count) { describeComponent(d->sval[0]); goto exit; } if (files->count) { if (!dataflow->count) { cerr << "ERROR: please specify a dataflow file with -c option !" << endl; exitcode = -1; goto exit; } DataFlow df; if (!df.load(dataflow->filename[0])) { cerr << "ERROR: cannot load dataflow from file " << dataflow->filename[0] << endl; exitcode = -1; goto exit; } Engine engine; if (!engine.load(df)) { cerr << "ERROR: cannot initialize dataflow engine" << endl; exitcode = -1; goto exit; } AudioFileProcessor processor; { string formatStr = "csv"; if (format->count) formatStr = format->sval[0]; string outDirStr = ""; if (outdir->count) outDirStr = outdir->sval[0]; ParameterMap params; for (int p=0; p<formatparams->count; p++) { string str = formatparams->sval[p]; size_t keyEnd = str.find('='); if (keyEnd==string::npos) { cerr << "Malformed parameter " << formatparams->sval[p] << endl; continue; } params[str.substr(0,keyEnd)] = str.substr(keyEnd+1,str.size()-keyEnd-1); } if (!processor.setOutputFormat(formatStr,outDirStr,params)) { exitcode = -1; goto exit; } } for (int i=0; i<files->count; i++) { int res = processor.processFile(engine, files->filename[i]); if (res!=0) { cerr << "ERROR: error while processing " << files->filename[i] << endl; } } } #ifdef WITH_TIMERS Timer::print_all_timers(); #endif exit: // release components to avoid definitly lost blocks in valgrind ComponentFactory::destroy(); /* deallocate each non-null entry in argtable[] */ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); return exitcode; }