FAUST compiler  0.9.9.6b8
klass.cpp
Go to the documentation of this file.
00001 /************************************************************************
00002  ************************************************************************
00003     FAUST compiler
00004     Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
00005     ---------------------------------------------------------------------
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  ************************************************************************
00020  ************************************************************************/
00021 
00022 
00023 
00024  /**********************************************************************
00025             - klass.cpp : class C++ a remplir (projet FAUST) -
00026 
00027 
00028         Historique :
00029         -----------
00030         17-10-2001 : implementation initiale (yo)
00031         18-10-2001 : Ajout de getFreshID (yo)
00032         02-11-2001 : Ajout de sous classes (yo)
00033         06-11-2001 : modif impression des classes (yo)
00034 
00035 ***********************************************************************/
00036 
00037 #include <stdio.h>
00038 #include <iostream>
00039 #include <sstream>
00040 #include <string>
00041 #include <list>
00042 #include <map>
00043 
00044 #include "floats.hh"
00045 #include "smartpointer.hh"
00046 #include "klass.hh"
00047 #include "uitree.hh"
00048 #include "Text.hh"
00049 #include "signals.hh"
00050 #include "ppsig.hh"
00051 #include "recursivness.hh"
00052 
00053 
00054 extern bool gVectorSwitch;
00055 extern bool gDeepFirstSwitch;
00056 extern bool gOpenMPSwitch;
00057 extern bool gOpenMPLoop;
00058 extern bool gSchedulerSwitch;
00059 extern int  gVecSize;
00060 extern bool gUIMacroSwitch;
00061 extern int  gVectorLoopVariant;
00062 extern bool gGroupTaskSwitch;
00063 
00064 extern map<Tree, set<Tree> > gMetaDataSet;
00065 static int gTaskCount = 0;
00066 
00067 void tab (int n, ostream& fout)
00068 {
00069     fout << '\n';
00070     while (n--) fout << '\t';
00071 }
00072 
00073 bool Klass::fNeedPowerDef = false;
00074 
00078 void Klass::setLoopProperty(Tree sig, Loop* l)
00079 {
00080     fLoopProperty.set(sig,l);
00081 }
00082 
00086 bool Klass::getLoopProperty(Tree sig, Loop*& l)
00087 {
00088     return  fLoopProperty.get(sig, l);
00089 }
00090 
00095 void Klass::openLoop(const string& size)
00096 {
00097     fTopLoop = new Loop(fTopLoop, size);
00098     //cerr << "\nOPEN SHARED LOOP(" << size << ") ----> " << fTopLoop << endl;
00099 }
00100 
00106 void Klass::openLoop(Tree recsymbol, const string& size)
00107 {
00108     fTopLoop = new Loop(recsymbol, fTopLoop, size);
00109     //cerr << "\nOPEN REC LOOP(" << *recsymbol << ", " << size << ") ----> " << fTopLoop << endl;
00110 }
00111 
00116 void Klass::closeLoop(Tree sig)
00117 {
00118     assert(fTopLoop);
00119     Loop* l = fTopLoop;
00120     fTopLoop = l->fEnclosingLoop;
00121     assert(fTopLoop);
00122 
00123     //l->println(4, cerr);
00124     //cerr << endl;
00125 
00126     Tree S = symlist(sig);
00127     //cerr << "CLOSE LOOP :" << l << " with symbols " << *S  << endl;
00128     if (l->isEmpty() || fTopLoop->hasRecDependencyIn(S)) {
00129         //cout << " will absorb" << endl;
00130         // empty or dependent loop -> absorbed by enclosing one
00131         //cerr << "absorbed by : " << fTopLoop << endl;
00132         fTopLoop->absorb(l);
00133         //delete l; HACK !!!
00134     } else {
00135         // cout << " will NOT absorb" << endl;
00136         // we have an independent loop
00137         setLoopProperty(sig,l);     // associate the signal
00138         fTopLoop->fBackwardLoopDependencies.insert(l);
00139         // we need to indicate that all recursive symbols defined
00140         // in this loop are defined in this loop
00141         for (Tree lsym=l->fRecSymbolSet; !isNil(lsym); lsym=tl(lsym)) {
00142             this->setLoopProperty(hd(lsym), l);
00143             //cerr << "loop " << l << " defines " << *hd(lsym) << endl;
00144         }
00145     }
00146     //cerr << "\n" << endl;
00147 }
00148 
00152 void printlines(int n, list<string>& lines, ostream& fout)
00153 {
00154     list<string>::iterator s;
00155     for (s = lines.begin(); s != lines.end(); s++) {
00156         tab(n, fout); fout << *s;
00157     }
00158 }
00159 
00163 void printdecllist(int n, const string& decl, list<string>& content, ostream& fout)
00164 {
00165     if (!content.empty()) {
00166         list<string>::iterator s;
00167         fout << "\\";
00168         tab(n, fout); fout << decl;
00169         string sep = "(";
00170         for (s = content.begin(); s != content.end(); s++) {
00171             fout << sep << *s;
00172             sep = ", ";
00173         }
00174         fout << ')';
00175     }
00176 }
00177 
00181 void Klass::printLibrary(ostream& fout)
00182 {
00183     set<string> S;
00184     set<string>::iterator f;
00185 
00186     string sep;
00187     collectLibrary(S);
00188     fout << "/* link with ";
00189     for (f = S.begin(), sep =": "; f != S.end(); f++, sep = ", ")   {
00190         fout << sep << *f;
00191     }
00192     fout << " */\n";
00193 }
00194 
00198 void Klass::printIncludeFile(ostream& fout)
00199 {
00200     set<string> S;
00201     set<string>::iterator f;
00202 
00203     if (gOpenMPSwitch) {
00204         fout << "#include <omp.h>" << "\n";
00205     }
00206 
00207     collectIncludeFile(S);
00208     for (f = S.begin(); f != S.end(); f++)  {
00209         fout << "#include " << *f << "\n";
00210     }
00211 }
00212 
00216 void Klass::printAdditionalCode(ostream& fout)
00217 {
00218     if (fNeedPowerDef) {
00219         // Add faustpower definition to C++ code
00220         fout << "#include <cmath>" << endl;
00221         fout << "template <int N> inline float faustpower(float x)      { return powf(x,N); } " << endl;
00222         fout << "template <int N> inline double faustpower(double x)    { return pow(x,N); }"  << endl;
00223         fout << "template <int N> inline int faustpower(int x)          { return faustpower<N/2>(x) * faustpower<N-N/2>(x); } " << endl;
00224         fout << "template <>     inline int faustpower<0>(int x)        { return 1; }" << endl;
00225         fout << "template <>     inline int faustpower<1>(int x)        { return x; }" << endl;
00226     }
00227 
00228 }
00229 
00233 void Klass::printMetadata(int n, const map<Tree, set<Tree> >& S, ostream& fout)
00234 {
00235     tab(n,fout); fout   << "static void metadata(Meta* m) \t{ ";
00236 
00237     for (map<Tree, set<Tree> >::iterator i = gMetaDataSet.begin(); i != gMetaDataSet.end(); i++) {
00238         if (i->first != tree("author")) {
00239             tab(n+1,fout); fout << "m->declare(\"" << *(i->first) << "\", " << **(i->second.begin()) << ");";
00240         } else {
00241             for (set<Tree>::iterator j = i->second.begin(); j != i->second.end(); j++) {
00242                 if (j == i->second.begin()) {
00243                      tab(n+1,fout); fout << "m->declare(\"" << *(i->first) << "\", " << **j << ");" ;
00244                 } else {
00245                      tab(n+1,fout); fout << "m->declare(\"" << "contributor" << "\", " << **j << ");";
00246                 }
00247             }
00248         }
00249     }
00250 
00251     tab(n,fout); fout << "}" << endl;
00252 }
00253 
00254 inline bool isElement(const set<Loop*>& S, Loop* l)
00255 {
00256     return S.find(l)!= S.end();
00257 }
00258 
00262 void Klass::printLoopDeepFirst(int n, ostream& fout, Loop* l, set<Loop*>& visited)
00263 {
00264     // avoid printing already printed loops
00265     if (isElement(visited, l)) return;
00266 
00267     // remember we have printed this loop
00268     visited.insert(l);
00269 
00270     // print the dependencies loops (that need to be computed before this one)
00271     for (lset::const_iterator p =l->fBackwardLoopDependencies.begin(); p!=l->fBackwardLoopDependencies.end(); p++) {
00272         printLoopDeepFirst(n, fout, *p, visited);
00273     }
00274     // the print the loop itself
00275     tab(n, fout);
00276     tab(n, fout); fout << "// LOOP " << l << ", ORDER " << l->fOrder << endl;
00277     l->println(n+1, fout);
00278 }
00279 
00283 static void computeUseCount(Loop* l)
00284 {
00285     l->fUseCount++;
00286     if (l->fUseCount == 1) {
00287         for (lset::iterator p =l->fBackwardLoopDependencies.begin(); p!=l->fBackwardLoopDependencies.end(); p++) {
00288             computeUseCount(*p);
00289         }
00290     }
00291 }
00292 
00296 static void groupSeqLoops(Loop* l)
00297 {
00298     int n = l->fBackwardLoopDependencies.size();
00299     if (n==0) {
00300         return;
00301     } else if (n==1) {
00302         Loop* f = *(l->fBackwardLoopDependencies.begin());
00303         if (f->fUseCount ==  1) {
00304             l->concat(f);
00305             groupSeqLoops(l);
00306         } else {
00307             groupSeqLoops(f);
00308         }
00309         return;
00310     } else if (n > 1) {
00311         for (lset::iterator p =l->fBackwardLoopDependencies.begin(); p!=l->fBackwardLoopDependencies.end(); p++) {
00312             groupSeqLoops(*p);
00313         }
00314     }
00315 }
00316 
00317 #define WORK_STEALING_INDEX 0
00318 #define LAST_TASK_INDEX 1
00319 #define START_TASK_INDEX LAST_TASK_INDEX + 1
00320 
00321 #define START_TASK_MAX 2
00322 
00323 void Klass::buildTasksList()
00324 {
00325     lgraph G;
00326 
00327     if (gGroupTaskSwitch) {
00328         computeUseCount(fTopLoop);
00329         groupSeqLoops(fTopLoop);
00330     }
00331 
00332     sortGraph(fTopLoop, G);
00333     int index_task = START_TASK_INDEX;
00334 
00335     addDeclCode("TaskGraph fGraph;");
00336     addDeclCode("FAUSTFLOAT** input;");
00337     addDeclCode("FAUSTFLOAT** output;");
00338     addDeclCode("volatile bool fIsFinished;");
00339     addDeclCode("int fFullCount;");
00340     addDeclCode("int fIndex;");
00341     addDeclCode("DSPThreadPool* fThreadPool;");
00342     addDeclCode("int fStaticNumThreads;");
00343     addDeclCode("int fDynamicNumThreads;");
00344 
00345     // Compute forward dependencies
00346     for (int l=G.size()-1; l>=0; l--) {
00347         for (lset::const_iterator p =G[l].begin(); p!=G[l].end(); p++) {
00348             for (lset::const_iterator p1 = (*p)->fBackwardLoopDependencies.begin(); p1!=(*p)->fBackwardLoopDependencies.end(); p1++) {
00349                 (*p1)->fForwardLoopDependencies.insert((*p));
00350             }
00351             (*p)->fIndex = index_task;
00352             index_task++;
00353         }
00354     }
00355 
00356     // Compute ready tasks list
00357     vector<int> task_num;
00358     for (int l=G.size()-1; l>=0; l--) {
00359         lset::const_iterator next;
00360         for (lset::const_iterator p =G[l].begin(); p!=G[l].end(); p++) {
00361             if ((*p)->fBackwardLoopDependencies.size() == 0) {
00362                 task_num.push_back((*p)->fIndex);
00363             }
00364         }
00365     }
00366 
00367     if (task_num.size() < START_TASK_MAX) {
00368 
00369         // Push ready tasks thread 0, execute one task directly
00370 
00371         addZone3("if (cur_thread == 0) {");
00372 
00373         Loop* keep = NULL;
00374         for (int l=G.size()-1; l>=0; l--) {
00375             lset::const_iterator next;
00376             for (lset::const_iterator p =G[l].begin(); p!=G[l].end(); p++) {
00377                 if ((*p)->fBackwardLoopDependencies.size() == 0) {
00378                     if (keep == NULL) {
00379                         keep = *p;
00380                     } else {
00381                         addZone3(subst("    taskqueue.PushHead($0);", T((*p)->fIndex)));
00382                     }
00383                 }
00384             }
00385         }
00386 
00387         if (keep != NULL) {
00388             addZone3(subst("    tasknum = $0;", T(keep->fIndex)));
00389         }
00390 
00391         addZone3("} else {");
00392         addZone3("    tasknum = TaskQueue::GetNextTask(cur_thread, fDynamicNumThreads);");
00393         addZone3("}");
00394 
00395     } else {
00396 
00397         // Cut ready tasks list and have each thread (dynamically) use a subpart
00398         addZone3(subst("int task_list_size = $0;", T((int)task_num.size())));
00399         stringstream buf;
00400         buf << "int task_list[" << task_num.size() << "] = {";
00401         for(size_t i = 0; i < task_num.size(); i++) {
00402             buf << task_num[i];
00403             if (i != (task_num.size() - 1))
00404                 buf << ",";
00405         }
00406         buf << "};";
00407 
00408         addZone3(buf.str());
00409         addZone3("taskqueue.InitTaskList(task_list_size, task_list, fDynamicNumThreads, cur_thread, tasknum);");
00410     }
00411 
00412     // Last stage connected to end task
00413     if (G[0].size() > 1) {
00414         addZone2c("// Initialize end task, if more than one input");
00415         addZone2c(subst("fGraph.InitTask($0,$1);", T(LAST_TASK_INDEX), T((int)G[0].size())));
00416     } else {
00417         addZone2c("// End task has only one input, so will be directly activated");
00418     }
00419 
00420     // Compute init section
00421     addZone2c("// Only initialize taks with more than one input");
00422     for (int l=G.size()-1; l>=0; l--) {
00423         for (lset::const_iterator p =G[l].begin(); p!=G[l].end(); p++) {
00424             if ((*p)->fBackwardLoopDependencies.size() > 1)  { // Only initialize taks with more than 1 input, since taks with one input are "directly" activated.
00425                 addZone2c(subst("fGraph.InitTask($0,$1);", T(START_TASK_INDEX + gTaskCount++), T((int)(*p)->fBackwardLoopDependencies.size())));
00426             } else {
00427                 gTaskCount++;
00428             }
00429         }
00430     }
00431 
00432     addInitCode("fStaticNumThreads = get_max_cpu();");
00433     addInitCode("fDynamicNumThreads = getenv(\"OMP_NUM_THREADS\") ? atoi(getenv(\"OMP_NUM_THREADS\")) : fStaticNumThreads;");
00434     addInitCode("fThreadPool = DSPThreadPool::Init();");
00435     addInitCode("fThreadPool->StartAll(fStaticNumThreads - 1, false);");
00436 
00437     gTaskCount = 0;
00438 }
00439 
00443 void Klass::printLoopGraphVector(int n, ostream& fout)
00444 {
00445     if (gGroupTaskSwitch) {
00446         computeUseCount(fTopLoop);
00447         groupSeqLoops(fTopLoop);
00448     }
00449 
00450     lgraph G;
00451     sortGraph(fTopLoop, G);
00452 
00453 #if 1
00454     // EXPERIMENTAL
00455     if (gVectorSwitch && gDeepFirstSwitch) {
00456         set<Loop*> visited;
00457         printLoopDeepFirst(n, fout, fTopLoop, visited);
00458         return;
00459     }
00460 #endif
00461 
00462     // normal mode
00463     for (int l=G.size()-1; l>=0; l--) {
00464         if (gVectorSwitch) { tab(n, fout); fout << "// SECTION : " << G.size() - l; }
00465         for (lset::const_iterator p =G[l].begin(); p!=G[l].end(); p++) {
00466             (*p)->println(n, fout);
00467         }
00468     }
00469 }
00470 
00474 void Klass::printLoopGraphOpenMP(int n, ostream& fout)
00475 {
00476     if (gGroupTaskSwitch) {
00477         computeUseCount(fTopLoop);
00478         groupSeqLoops(fTopLoop);
00479     }
00480 
00481     lgraph G;
00482     sortGraph(fTopLoop, G);
00483 
00484     // OpenMP mode : add OpenMP directives
00485     for (int l=G.size()-1; l>=0; l--) {
00486         tab(n, fout); fout << "// SECTION : " << G.size() - l;
00487         printLoopLevelOpenMP(n, G.size() - l, G[l], fout);
00488     }
00489 }
00490 
00494 void Klass::printLoopGraphScheduler(int n, ostream& fout)
00495 {
00496     if (gGroupTaskSwitch) {
00497         computeUseCount(fTopLoop);
00498         groupSeqLoops(fTopLoop);
00499     }
00500 
00501     lgraph G;
00502     sortGraph(fTopLoop, G);
00503 
00504     // OpenMP mode : add OpenMP directives
00505     for (int l=G.size()-1; l>0; l--) {
00506         tab(n, fout); fout << "// SECTION : " << G.size() - l;
00507         printLoopLevelScheduler(n, G.size() - l, G[l], fout);
00508     }
00509 
00510     printLastLoopLevelScheduler(n, G.size(), G[0], fout);
00511 }
00512 
00513 
00517 void Klass::printGraphDotFormat(ostream& fout)
00518 {
00519     lgraph G;
00520     sortGraph(fTopLoop, G);
00521 
00522     fout << "strict digraph loopgraph {" << endl;
00523     fout << '\t' << "rankdir=LR;" << endl;
00524     fout << '\t' << "node[color=blue, fillcolor=lightblue, style=filled, fontsize=9];" << endl;
00525 
00526     int lnum = 0;       // used for loop numbers
00527     // for each level of the graph
00528     for (int l=G.size()-1; l>=0; l--) {
00529         // for each task in the level
00530         for (lset::const_iterator t =G[l].begin(); t!=G[l].end(); t++) {
00531             // print task label "Lxxx : 0xffffff"
00532             fout << '\t' << 'L'<<(*t)<<"[label=<<font face=\"verdana,bold\">L"<<lnum++<<"</font> : "<<(*t)<<">];"<<endl;
00533             // for each source of the task
00534             for (lset::const_iterator src = (*t)->fBackwardLoopDependencies.begin(); src!=(*t)->fBackwardLoopDependencies.end(); src++) {
00535                 // print the connection Lxxx -> Lyyy;
00536                 fout << '\t' << 'L'<<(*src)<<"->"<<'L'<<(*t)<<';'<<endl;
00537             }
00538         }
00539     }
00540     fout << "}" << endl;
00541 }
00542 
00546 void Klass::printLoopGraphInternal(int n, ostream& fout)
00547 {
00548     lgraph G;
00549     sortGraph(fTopLoop, G);
00550 
00551     // normal mode
00552     for (int l=G.size()-1; l>=0; l--) {
00553         if (gVectorSwitch) { tab(n, fout); fout << "// SECTION : " << G.size() - l; }
00554         for (lset::const_iterator p =G[l].begin(); p!=G[l].end(); p++) {
00555             (*p)->printoneln(n, fout);
00556         }
00557     }
00558 }
00559 
00563 void Klass::printLoopGraphScalar(int n, ostream& fout)
00564 {
00565     fTopLoop->printoneln(n, fout);
00566 }
00567 
00571 static bool nonRecursiveLevel(const lset& L)
00572 {
00573     for (lset::const_iterator p =L.begin(); p!=L.end(); p++) {
00574         if ((*p)->fIsRecursive) return false;
00575     }
00576     return true;
00577 }
00578 
00583 void Klass::printLoopLevelOpenMP(int n, int lnum, const lset& L, ostream& fout)
00584 {
00585     if (nonRecursiveLevel(L) && L.size()==1) {
00586         for (lset::const_iterator p =L.begin(); p!=L.end(); p++) {
00587             if ((*p)->isEmpty() == false) {
00588                 if (gOpenMPLoop) {
00589                     (*p)->printParLoopln(n, fout);
00590                 } else {
00591                     tab(n, fout); fout << "#pragma omp single ";
00592                     tab(n, fout); fout << "{ ";
00593                     (*p)->println(n+1, fout);
00594                     tab(n, fout); fout << "} ";
00595                 }
00596             }
00597         }
00598 
00599     } else if (L.size() > 1) {
00600         tab(n, fout); fout << "#pragma omp sections ";
00601         tab(n, fout); fout << "{ ";
00602         for (lset::const_iterator p =L.begin(); p!=L.end(); p++) {
00603             tab(n+1, fout); fout << "#pragma omp section ";
00604             tab(n+1, fout); fout << "{";
00605             (*p)->println(n+2, fout);
00606             tab(n+1, fout); fout << "} ";
00607         }
00608         tab(n, fout); fout << "} ";
00609     } else if (L.size() == 1 && !(*L.begin())->isEmpty()) {
00610         tab(n, fout); fout << "#pragma omp single ";
00611         tab(n, fout); fout << "{ ";
00612             for (lset::const_iterator p =L.begin(); p!=L.end(); p++) {
00613                 (*p)->println(n+1, fout);
00614             }
00615         tab(n, fout); fout << "} ";
00616     }
00617 }
00618 
00623 void Klass::printLastLoopLevelScheduler(int n, int lnum, const lset& L, ostream& fout)
00624 {
00625     if (nonRecursiveLevel(L) && L.size() == 1 && !(*L.begin())->isEmpty()) {
00626 
00627         lset::const_iterator p =L.begin();
00628         tab(n, fout); fout << "case " << gTaskCount++ << ": { ";
00629         (*p)->println(n+1, fout);
00630         tab(n+1, fout); fout << "tasknum = LAST_TASK_INDEX;";
00631         tab(n+1, fout); fout << "break;";
00632         tab(n, fout); fout << "} ";
00633 
00634     } else if (L.size() > 1) {
00635 
00636         for (lset::const_iterator p =L.begin(); p!=L.end(); p++) {
00637             tab(n, fout); fout << "case " << gTaskCount++ << ": { ";
00638             (*p)->println(n+1, fout);
00639             tab(n+1, fout); fout << "fGraph.ActivateOneOutputTask(taskqueue, LAST_TASK_INDEX, tasknum);";
00640             tab(n+1, fout); fout << "break;";
00641             tab(n, fout); fout << "} ";
00642         }
00643 
00644     } else if (L.size() == 1 && !(*L.begin())->isEmpty()) {
00645 
00646         lset::const_iterator p =L.begin();
00647         tab(n, fout); fout << "case " << gTaskCount++ << ": { ";
00648         (*p)->println(n+1, fout);
00649         tab(n+1, fout); fout << "tasknum = LAST_TASK_INDEX;";
00650         tab(n+1, fout); fout << "break;";
00651         tab(n, fout); fout << "} ";
00652 
00653     }
00654 }
00655 
00656 void Klass::printOneLoopScheduler(lset::const_iterator p, int n, ostream& fout)
00657 {
00658     tab(n, fout); fout << "case " << gTaskCount++ << ": { ";
00659     (*p)->println(n+1, fout);
00660 
00661     // One output only
00662     if ((*p)->fForwardLoopDependencies.size() == 1) {
00663 
00664         lset::const_iterator p1 = (*p)->fForwardLoopDependencies.begin();
00665         if ((*p1)->fBackwardLoopDependencies.size () == 1) {
00666             tab(n+1, fout); fout << subst("tasknum = $0;", T((*p1)->fIndex));
00667         } else {
00668             tab(n+1, fout); fout << subst("fGraph.ActivateOneOutputTask(taskqueue, $0, tasknum);", T((*p1)->fIndex));
00669         }
00670 
00671     } else {
00672 
00673         Loop* keep = NULL;
00674         // Find one output with only one backward dependencies
00675         for (lset::const_iterator p1 = (*p)->fForwardLoopDependencies.begin(); p1!=(*p)->fForwardLoopDependencies.end(); p1++) {
00676             if ((*p1)->fBackwardLoopDependencies.size () == 1) {
00677                 keep = *p1;
00678                 break;
00679             }
00680         }
00681 
00682         if (keep == NULL) {
00683             tab(n+1, fout); fout << "tasknum = WORK_STEALING_INDEX;";
00684         }
00685 
00686         for (lset::const_iterator p1 = (*p)->fForwardLoopDependencies.begin(); p1!=(*p)->fForwardLoopDependencies.end(); p1++) {
00687             if ((*p1)->fBackwardLoopDependencies.size () == 1) {  // Task is the only input
00688                 if (*p1 != keep) {
00689                     tab(n+1, fout); fout << subst("taskqueue.PushHead($0);", T((*p1)->fIndex));
00690                 }
00691             } else {
00692                 if (keep == NULL) {
00693                     tab(n+1, fout); fout << subst("fGraph.ActivateOutputTask(taskqueue, $0, tasknum);", T((*p1)->fIndex));
00694                 } else {
00695                     tab(n+1, fout); fout << subst("fGraph.ActivateOutputTask(taskqueue, $0);", T((*p1)->fIndex));
00696                 }
00697             }
00698         }
00699 
00700         if (keep != NULL) {
00701             tab(n+1, fout); fout << subst("tasknum = $0;", T(keep->fIndex)); // Last one
00702         } else {
00703             tab(n+1, fout); fout << "fGraph.GetReadyTask(taskqueue, tasknum);"; // Last one
00704         }
00705     }
00706 
00707     tab(n+1, fout); fout << "break;";
00708     tab(n, fout); fout << "} ";
00709 }
00710 
00716 void Klass::printLoopLevelScheduler(int n, int lnum, const lset& L, ostream& fout)
00717 {
00718     if (nonRecursiveLevel(L) && L.size() == 1 && !(*L.begin())->isEmpty()) {
00719         printOneLoopScheduler(L.begin(), n, fout);
00720     } else if (L.size() > 1) {
00721         for (lset::const_iterator p = L.begin(); p != L.end(); p++) {
00722             printOneLoopScheduler(p, n, fout);
00723         }
00724     } else if (L.size() == 1 && !(*L.begin())->isEmpty()) {
00725         printOneLoopScheduler(L.begin(), n, fout);
00726     }
00727 }
00728 
00732 void Klass::println(int n, ostream& fout)
00733 {
00734     list<Klass* >::iterator k;
00735 
00736     if (gSchedulerSwitch) {
00737         tab(n,fout); fout << "class " << fKlassName << " : public " << fSuperKlassName << ", public Runnable {";
00738     } else {
00739         tab(n,fout); fout << "class " << fKlassName << " : public " << fSuperKlassName << " {";
00740     }
00741 
00742     if (gUIMacroSwitch) {
00743         tab(n,fout); fout << "  public:";
00744     } else {
00745         tab(n,fout); fout << "  private:";
00746     }
00747 
00748     for (k = fSubClassList.begin(); k != fSubClassList.end(); k++)  (*k)->println(n+1, fout);
00749 
00750     printlines(n+1, fDeclCode, fout);
00751 
00752     tab(n,fout); fout << "  public:";
00753 
00754     printMetadata(n+1, gMetaDataSet, fout);
00755 
00756     if (gSchedulerSwitch) {
00757         tab(n+1,fout); fout << "virtual ~" << fKlassName << "() \t{ "
00758                             << "DSPThreadPool::Destroy()"
00759                             << "; }";
00760     }
00761 
00762     tab(n+1,fout); fout     << "virtual int getNumInputs() \t{ "
00763                     << "return " << fNumInputs
00764                     << "; }";
00765     tab(n+1,fout); fout     << "virtual int getNumOutputs() \t{ "
00766                     << "return " << fNumOutputs
00767                     << "; }";
00768 
00769     tab(n+1,fout); fout << "static void classInit(int samplingFreq) {";
00770         printlines (n+2, fStaticInitCode, fout);
00771     tab(n+1,fout); fout << "}";
00772 
00773     tab(n+1,fout); fout << "virtual void instanceInit(int samplingFreq) {";
00774         tab(n+2,fout); fout << "fSamplingFreq = samplingFreq;";
00775         printlines (n+2, fInitCode, fout);
00776     tab(n+1,fout); fout << "}";
00777 
00778     tab(n+1,fout); fout << "virtual void init(int samplingFreq) {";
00779         tab(n+2,fout); fout << "classInit(samplingFreq);";
00780          tab(n+2,fout); fout << "instanceInit(samplingFreq);";
00781     tab(n+1,fout); fout << "}";
00782 
00783 
00784     tab(n+1,fout); fout << "virtual void buildUserInterface(UI* interface) {";
00785         printlines (n+2, fUICode, fout);
00786     tab(n+1,fout); fout << "}";
00787 
00788     printComputeMethod(n, fout);
00789 
00790     tab(n,fout); fout << "};\n" << endl;
00791 
00792     printlines(n, fStaticFields, fout);
00793 
00794     // generate user interface macros if needed
00795     if (gUIMacroSwitch) {
00796         tab(n, fout); fout << "#ifdef FAUST_UIMACROS";
00797             tab(n+1,fout); fout << "#define FAUST_INPUTS " << fNumInputs;
00798             tab(n+1,fout); fout << "#define FAUST_OUTPUTS " << fNumOutputs;
00799             tab(n+1,fout); fout << "#define FAUST_ACTIVES " << fNumActives;
00800             tab(n+1,fout); fout << "#define FAUST_PASSIVES " << fNumPassives;
00801             printlines(n+1, fUIMacro, fout);
00802         tab(n, fout); fout << "#endif";
00803     }
00804 
00805     fout << endl;
00806 }
00807 
00811 void Klass::printComputeMethod(int n, ostream& fout)
00812 {
00813     if (gSchedulerSwitch) {
00814         printComputeMethodScheduler (n, fout);
00815     } else if (gOpenMPSwitch) {
00816         printComputeMethodOpenMP (n, fout);
00817     } else if (gVectorSwitch) {
00818         switch (gVectorLoopVariant) {
00819             case 0 : printComputeMethodVectorFaster(n, fout); break;
00820             case 1 : printComputeMethodVectorSimple(n, fout); break;
00821             default : cerr << "unknown loop variant " << gVectorLoopVariant << endl; exit(1);
00822         }
00823    } else {
00824         printComputeMethodScalar(n, fout);
00825     }
00826 }
00827 
00828 void Klass::printComputeMethodScalar(int n, ostream& fout)
00829 {
00830     tab(n+1,fout); fout << subst("virtual void compute (int count, $0** input, $0** output) {", xfloat());
00831         printlines (n+2, fZone1Code, fout);
00832         printlines (n+2, fZone2Code, fout);
00833         printlines (n+2, fZone2bCode, fout);
00834         printlines (n+2, fZone3Code, fout);
00835         printLoopGraphScalar (n+2,fout);
00836     tab(n+1,fout); fout << "}";
00837 }
00838 
00844 void Klass::printComputeMethodVectorFaster(int n, ostream& fout)
00845 {
00846     // in vector mode we need to split loops in smaller pieces not larger
00847     // than gVecSize
00848     tab(n+1,fout); fout << subst("virtual void compute (int fullcount, $0** input, $0** output) {", xfloat());
00849         printlines(n+2, fZone1Code, fout);
00850         printlines(n+2, fZone2Code, fout);
00851         printlines(n+2, fZone2bCode, fout);
00852 
00853         tab(n+2,fout); fout << "int index;";
00854         tab(n+2,fout); fout << "for (index = 0; index <= fullcount - " << gVecSize << "; index += " << gVecSize << ") {";
00855             tab(n+3,fout); fout << "// compute by blocks of " << gVecSize << " samples";
00856             tab(n+3,fout); fout << "const int count = " << gVecSize << ";";
00857             printlines (n+3, fZone3Code, fout);
00858             printLoopGraphVector(n+3,fout);
00859         tab(n+2,fout); fout << "}";
00860 
00861         tab(n+2,fout); fout << "if (index < fullcount) {";
00862             tab(n+3,fout); fout << "// compute the remaining samples if any";
00863             tab(n+3,fout); fout << "int count = fullcount-index;";
00864             printlines (n+3, fZone3Code, fout);
00865              printLoopGraphVector(n+3,fout);
00866         tab(n+2,fout); fout << "}";
00867     tab(n+1,fout); fout << "}";
00868 }
00869 
00873 void Klass::printComputeMethodVectorSimple(int n, ostream& fout)
00874 {
00875     // in vector mode we need to split loops in smaller pieces not larger
00876     // than gVecSize
00877     tab(n+1,fout); fout << subst("virtual void compute (int fullcount, $0** input, $0** output) {", xfloat());
00878         printlines(n+2, fZone1Code, fout);
00879         printlines(n+2, fZone2Code, fout);
00880         printlines(n+2, fZone2bCode, fout);
00881         tab(n+2,fout); fout << "for (int index = 0; index < fullcount; index += " << gVecSize << ") {";
00882             tab(n+3,fout); fout << "int count = min("<< gVecSize << ", fullcount-index);";
00883             printlines (n+3, fZone3Code, fout);
00884             printLoopGraphVector(n+3,fout);
00885         tab(n+2,fout); fout << "}";
00886     tab(n+1,fout); fout << "}";
00887 }
00888 
00889 /*
00890 void Klass::printComputeMethodVectorFix0 (int n, ostream& fout)
00891 {
00892     // in vector mode we need to split loops in smaller pieces not larger
00893     // than gVecSize
00894     tab(n+1,fout); fout << "virtual void compute (int fullcount, float** input, float** output) {";
00895         printlines(n+2, fZone1Code, fout);
00896         printlines(n+2, fZone2Code, fout);
00897         printlines(n+2, fZone2bCode, fout);
00898         tab(n+2,fout); fout << "for (int index = 0; index < fullcount; index += " << gVecSize << ") {";
00899             tab(n+3,fout); fout << "if (fullcount >= index + " << gVecSize << ") {";
00900                 tab(n+4,fout); fout << "// compute by blocks of " << gVecSize << " samples";
00901                 tab(n+4,fout); fout << "const int count = " << gVecSize << ";"; // temporaire
00902                 printlines(n+4, fZone3Code, fout);
00903                 printLoopGraph (n+4,fout);
00904             tab(n+3,fout); fout << "} else if (fullcount > index) {";
00905                 //tab(n+3,fout); fout << "int count = min ("<< gVecSize << ", fullcount-index);";
00906                 tab(n+4,fout); fout << "// compute the remaining samples";
00907                 tab(n+4,fout); fout << "int count = fullcount-index;" ;
00908                 printlines(n+4, fZone3Code, fout);
00909                 printLoopGraph (n+4,fout);
00910             tab(n+3,fout); fout << "}";
00911         tab(n+2,fout); fout << "}";
00912     tab(n+1,fout); fout << "}";
00913 }
00914 
00915 void Klass::printComputeMethodVectorFix1 (int n, ostream& fout)
00916 {
00917     // in vector mode we need to split loops in smaller pieces not larger
00918     // than gVecSize
00919     tab(n+1,fout); fout << "virtual void compute (int fullcount, float** input, float** output) {";
00920         printlines(n+2, fZone1Code, fout);
00921         printlines(n+2, fZone2Code, fout);
00922         printlines(n+2, fZone2bCode, fout);
00923 
00924         tab(n+2,fout); fout << "int \tblock;";
00925         tab(n+2,fout); fout << "for (block = 0; block < fullcount/" << gVecSize << "; block++) {";
00926             tab(n+3,fout); fout << "// compute by blocks of " << gVecSize << " samples";
00927             tab(n+3,fout); fout << "const int index = block*" << gVecSize << ";";
00928             tab(n+3,fout); fout << "const int count = " << gVecSize << ";"; // temporaire
00929             printlines(n+3, fZone3Code, fout);
00930             printLoopGraph (n+3,fout);
00931         tab(n+2,fout); fout << "}";
00932 
00933         tab(n+2,fout); fout << "if (fullcount%" << gVecSize << " != 0) {";
00934             //tab(n+3,fout); fout << "int count = min ("<< gVecSize << ", fullcount-index);";
00935             tab(n+3,fout); fout << "// compute the remaining samples";
00936             tab(n+3,fout); fout << "const int index = block*" << gVecSize << ";";
00937             tab(n+3,fout); fout << "int count = fullcount%" << gVecSize << ";" ;
00938             printlines(n+3, fZone3Code, fout);
00939             printLoopGraph (n+3,fout);
00940         tab(n+2,fout); fout << "}";
00941     tab(n+1,fout); fout << "}";
00942 }*/
00943 
00944 void Klass::printComputeMethodOpenMP(int n, ostream& fout)
00945 {
00946     // in openMP mode we need to split loops in smaller pieces not larger
00947     // than gVecSize and add OpenMP pragmas
00948     tab(n+1,fout); fout << subst("virtual void compute (int fullcount, $0** input, $0** output) {", xfloat());
00949         printlines(n+2, fZone1Code, fout);
00950         printlines(n+2, fZone2Code, fout);
00951         tab(n+2,fout); fout << "#pragma omp parallel";
00952         printdecllist(n+3, "firstprivate", fFirstPrivateDecl, fout);
00953 
00954         tab(n+2,fout); fout << "{";
00955             if (!fZone2bCode.empty()) {
00956                 tab(n+3,fout); fout << "#pragma omp single";
00957                 tab(n+3,fout); fout << "{";
00958                     printlines(n+4, fZone2bCode, fout);
00959                 tab(n+3,fout); fout << "}";
00960             }
00961 
00962             tab(n+3,fout); fout << "for (int index = 0; index < fullcount; index += " << gVecSize << ") {";
00963             tab(n+4,fout); fout << "int count = min ("<< gVecSize << ", fullcount-index);";
00964 
00965             printlines (n+4, fZone3Code, fout);
00966             printLoopGraphOpenMP (n+4,fout);
00967 
00968             tab(n+3,fout); fout << "}";
00969 
00970         tab(n+2,fout); fout << "}";
00971     tab(n+1,fout); fout << "}";
00972 }
00973 
00974 /*
00975 void Klass::printComputeMethodScheduler (int n, ostream& fout)
00976 {
00977     tab(n+1,fout); fout << subst("virtual void compute (int fullcount, $0** input, $0** output) {", xfloat());
00978         printlines (n+2, fZone1Code, fout);
00979         printlines (n+2, fZone2Code, fout);
00980 
00981         // Init input and output
00982         tab(n+2,fout); fout << "// Init input and output";
00983         printlines (n+2, fZone3aCode, fout);
00984         printlines (n+2, fZone3bCode, fout);
00985 
00986         tab(n+2,fout); fout << "// Init graph state";
00987         tab(n+2,fout); fout << "initState(fTasksList);";
00988         tab(n+2,fout); fout << "bool is_finished = false;";
00989         tab(n+2,fout); fout << "unsigned int index_in = 0;";
00990         tab(n+2,fout); fout << "unsigned int index_out = 0;";
00991         tab(n+2,fout); fout << "int count = min ("<< gVecSize << ", fullcount);";
00992 
00993         tab(n+2,fout); fout << "InitSchedulingMap();";
00994         tab(n+2,fout); fout << "#pragma omp parallel";
00995         printdecllist(n+3, "firstprivate", fFirstPrivateDecl, fout);
00996 
00997         tab(n+2,fout); fout << "{";
00998             tab(n+3,fout); fout << "while (!is_finished) {";
00999                 tab(n+4,fout); fout << "Task* task = searchTaskToAcquire(fTasksList);";
01000                 tab(n+4,fout); fout << "if (task != NULL) {";
01001                     tab(n+5,fout); fout << "bool last_cycle_for_thread = false;";
01002                     tab(n+5,fout); fout << "do {";
01003                         tab(n+6,fout); fout << "AddTaskToScheduling(task);";
01004                         tab(n+6,fout); fout << "switch (task->fNum) {";
01005 
01006                             // DSP tasks
01007                             printLoopGraph (n+7,fout);
01008 
01009                             // Input task
01010                             tab(n+7, fout); fout << "case " << gTaskCount++ << ": { ";
01011                             printlines (n+8, fZone6Code, fout);
01012                             tab(n+8, fout); fout << "index_in += count;";
01013                             tab(n+8, fout); fout << "last_cycle_for_thread = (index_in > fullcount);";
01014                             tab(n+8, fout); fout << "break;";
01015                             tab(n+7, fout); fout << "} ";
01016 
01017                             // Output task
01018                             tab(n+7, fout); fout << "case " << gTaskCount++ << ": { ";
01019                             printlines (n+8, fZone7Code, fout);
01020                             tab(n+8, fout); fout << "index_out += count;";
01021                             tab(n+8, fout); fout << "last_cycle_for_thread = (index_out > fullcount);";
01022                             tab(n+8, fout); fout << "break;";
01023                             tab(n+7, fout); fout << "} ";
01024 
01025                             // End task
01026                             tab(n+7, fout); fout << "case " << gTaskCount++ << ": { ";
01027                             tab(n+8, fout); fout << "is_finished = ((index_in >= fullcount) && (index_out >= fullcount));";
01028                             tab(n+8, fout); fout << "break;";
01029                             tab(n+7, fout); fout << "} ";
01030 
01031                         tab(n+6,fout); fout << "}";
01032                         tab(n+6,fout); fout << "if (last_cycle_for_thread) break;";
01033 
01034                     tab(n+5,fout); fout << "} while ((task = task->concludeAndTryToAcquireNext()) != NULL);";
01035                 tab(n+4,fout); fout << "}";
01036             tab(n+3,fout); fout << "}";
01037         tab(n+2,fout); fout << "}";
01038         tab(n+2,fout); fout << "PrintSchedulingMap();";
01039     tab(n+1,fout); fout << "}";
01040 }
01041 */
01042 
01043 void Klass::printComputeMethodScheduler (int n, ostream& fout)
01044 {
01045     tab(n+1,fout); fout << "void display() {";
01046         tab(n+2,fout); fout << "fGraph.Display();";
01047     tab(n+1,fout); fout << "}";
01048 
01049     tab(n+1,fout); fout << subst("virtual void compute (int fullcount, $0** input, $0** output) {", xfloat());
01050 
01051         tab(n+2,fout); fout << "GetRealTime();";
01052 
01053         tab(n+2,fout); fout << "this->input = input;";
01054         tab(n+2,fout); fout << "this->output = output;";
01055 
01056         tab(n+2,fout); fout << "StartMeasure();";
01057 
01058         tab(n+2,fout); fout << "for (fIndex = 0; fIndex < fullcount; fIndex += " << gVecSize << ") {";
01059 
01060         tab(n+3,fout); fout << "fFullCount = min ("<< gVecSize << ", fullcount-fIndex);";
01061         tab(n+3,fout); fout << "TaskQueue::Init();";
01062         printlines (n+3, fZone2cCode, fout);
01063 
01064         tab(n+3,fout); fout << "fIsFinished = false;";
01065         tab(n+3,fout); fout << "fThreadPool->SignalAll(fDynamicNumThreads - 1, this);";
01066         tab(n+3,fout); fout << "computeThread(0);";
01067         tab(n+3,fout); fout << "while (!fThreadPool->IsFinished()) {}";
01068 
01069         tab(n+2,fout); fout << "}";
01070 
01071         tab(n+2,fout); fout << "StopMeasure(fStaticNumThreads, fDynamicNumThreads);";
01072 
01073     tab(n+1,fout); fout << "}";
01074 
01075     tab(n+1,fout); fout << "void computeThread(int cur_thread) {";
01076         printlines (n+2, fZone1Code, fout);
01077         printlines (n+2, fZone2Code, fout);
01078 
01079         tab(n+2,fout); fout << "// Init graph state";
01080 
01081         tab(n+2,fout); fout << "{";
01082             tab(n+3,fout); fout << "TaskQueue taskqueue(cur_thread);";
01083             tab(n+3,fout); fout << "int tasknum = -1;";
01084             tab(n+3,fout); fout << "int count = fFullCount;";
01085 
01086             // Init input and output
01087             tab(n+3,fout); fout << "// Init input and output";
01088             printlines (n+3, fZone3Code, fout);
01089 
01090             tab(n+3,fout); fout << "while (!fIsFinished) {";
01091                  tab(n+4,fout); fout << "switch (tasknum) {";
01092 
01093                     // Work stealing task
01094                     tab(n+5, fout); fout << "case WORK_STEALING_INDEX: { ";
01095                         tab(n+6, fout); fout << "tasknum = TaskQueue::GetNextTask(cur_thread, fDynamicNumThreads);";
01096                         tab(n+6, fout); fout << "break;";
01097                     tab(n+5, fout); fout << "} ";
01098 
01099                     // End task
01100                     tab(n+5, fout); fout << "case LAST_TASK_INDEX: { ";
01101                         tab(n+6, fout); fout << "fIsFinished = true;";
01102                         tab(n+6, fout); fout << "break;";
01103                     tab(n+5, fout); fout << "} ";
01104 
01105                     gTaskCount = START_TASK_INDEX;
01106 
01107                     // DSP tasks
01108                     printLoopGraphScheduler (n+5,fout);
01109 
01110                  tab(n+4,fout); fout << "}";
01111             tab(n+3,fout); fout << "}";
01112         tab(n+2,fout); fout << "}";
01113     tab(n+1,fout); fout << "}";
01114 }
01115 
01119 void SigIntGenKlass::println(int n, ostream& fout)
01120 {
01121     list<Klass* >::iterator k;
01122 
01123     tab(n,fout); fout << "class " << fKlassName << " {";
01124 
01125     tab(n,fout); fout << "  private:";
01126         tab(n+1,fout); fout << "int \tfSamplingFreq;";
01127 
01128         for (k = fSubClassList.begin(); k != fSubClassList.end(); k++)  (*k)->println(n+1, fout);
01129 
01130         printlines(n+1, fDeclCode, fout);
01131 
01132     tab(n,fout); fout << "  public:";
01133 
01134         tab(n+1,fout); fout     << "int getNumInputs() \t{ "
01135                         << "return " << fNumInputs << "; }";
01136         tab(n+1,fout); fout     << "int getNumOutputs() \t{ "
01137                         << "return " << fNumOutputs << "; }";
01138 
01139         tab(n+1,fout); fout << "void init(int samplingFreq) {";
01140             tab(n+2,fout); fout << "fSamplingFreq = samplingFreq;";
01141         tab(n+1,fout); fout << "}";
01142 
01143         tab(n+1,fout); fout << "void fill (int count, int output[]) {";
01144             printlines (n+2, fZone1Code, fout);
01145             printlines (n+2, fZone2Code, fout);
01146             printlines (n+2, fZone2bCode, fout);
01147             printlines (n+2, fZone3Code, fout);
01148             printLoopGraphInternal (n+2,fout);
01149         tab(n+1,fout); fout << "}";
01150 
01151     tab(n,fout); fout << "};\n" << endl;
01152 }
01153 
01157 void SigFloatGenKlass::println(int n, ostream& fout)
01158 {
01159     list<Klass* >::iterator k;
01160 
01161     tab(n,fout); fout << "class " << fKlassName << " {";
01162 
01163     tab(n,fout); fout << "  private:";
01164         tab(n+1,fout); fout << "int \tfSamplingFreq;";
01165 
01166         for (k = fSubClassList.begin(); k != fSubClassList.end(); k++)  (*k)->println(n+1, fout);
01167 
01168         printlines(n+1, fDeclCode, fout);
01169 
01170     tab(n,fout); fout << "  public:";
01171 
01172         tab(n+1,fout); fout     << "int getNumInputs() \t{ "
01173                         << "return " << fNumInputs << "; }";
01174         tab(n+1,fout); fout     << "int getNumOutputs() \t{ "
01175                         << "return " << fNumOutputs << "; }";
01176 
01177         tab(n+1,fout); fout << "void init(int samplingFreq) {";
01178             tab(n+2,fout); fout << "fSamplingFreq = samplingFreq;";
01179             printlines(n+2, fInitCode, fout);
01180         tab(n+1,fout); fout << "}";
01181 
01182         tab(n+1,fout); fout << subst("void fill (int count, $0 output[]) {", ifloat());
01183             printlines (n+2, fZone1Code, fout);
01184             printlines (n+2, fZone2Code, fout);
01185             printlines (n+2, fZone2bCode, fout);
01186             printlines (n+2, fZone3Code, fout);
01187             printLoopGraphInternal(n+2,fout);
01188         tab(n+1,fout); fout << "}";
01189 
01190     tab(n,fout); fout << "};\n" << endl;
01191 }
01192 
01193 static void merge (set<string>& dst, set<string>& src)
01194 {
01195     set<string>::iterator i;
01196     for (i = src.begin(); i != src.end(); i++)  dst.insert(*i);
01197 }
01198 
01199 void Klass::collectIncludeFile(set<string>& S)
01200 {
01201     list<Klass* >::iterator     k;
01202 
01203     for (k = fSubClassList.begin(); k != fSubClassList.end(); k++)  (*k)->collectIncludeFile(S);
01204     merge(S, fIncludeFileSet);
01205 }
01206 
01207 void Klass::collectLibrary(set<string>& S)
01208 {
01209     list<Klass* >::iterator     k;
01210 
01211     for (k = fSubClassList.begin(); k != fSubClassList.end(); k++)  (*k)->collectLibrary(S);
01212     merge(S, fLibrarySet);
01213 }