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     tab(n,fout); fout << "#define FAUSTCLASS "<< fKlassName << endl;
00737 
00738     if (gSchedulerSwitch) {
00739         tab(n,fout); fout << "class " << fKlassName << " : public " << fSuperKlassName << ", public Runnable {";
00740     } else {
00741         tab(n,fout); fout << "class " << fKlassName << " : public " << fSuperKlassName << " {";
00742     }
00743 
00744     if (gUIMacroSwitch) {
00745         tab(n,fout); fout << "  public:";
00746     } else {
00747         tab(n,fout); fout << "  private:";
00748     }
00749 
00750     for (k = fSubClassList.begin(); k != fSubClassList.end(); k++)  (*k)->println(n+1, fout);
00751 
00752     printlines(n+1, fDeclCode, fout);
00753 
00754     tab(n,fout); fout << "  public:";
00755 
00756     printMetadata(n+1, gMetaDataSet, fout);
00757 
00758     if (gSchedulerSwitch) {
00759         tab(n+1,fout); fout << "virtual ~" << fKlassName << "() \t{ "
00760                             << "DSPThreadPool::Destroy()"
00761                             << "; }";
00762     }
00763 
00764     tab(n+1,fout); fout     << "virtual int getNumInputs() \t{ "
00765                     << "return " << fNumInputs
00766                     << "; }";
00767     tab(n+1,fout); fout     << "virtual int getNumOutputs() \t{ "
00768                     << "return " << fNumOutputs
00769                     << "; }";
00770 
00771     tab(n+1,fout); fout << "static void classInit(int samplingFreq) {";
00772         printlines (n+2, fStaticInitCode, fout);
00773     tab(n+1,fout); fout << "}";
00774 
00775     tab(n+1,fout); fout << "virtual void instanceInit(int samplingFreq) {";
00776         tab(n+2,fout); fout << "fSamplingFreq = samplingFreq;";
00777         printlines (n+2, fInitCode, fout);
00778     tab(n+1,fout); fout << "}";
00779 
00780     tab(n+1,fout); fout << "virtual void init(int samplingFreq) {";
00781         tab(n+2,fout); fout << "classInit(samplingFreq);";
00782          tab(n+2,fout); fout << "instanceInit(samplingFreq);";
00783     tab(n+1,fout); fout << "}";
00784 
00785 
00786     tab(n+1,fout); fout << "virtual void buildUserInterface(UI* interface) {";
00787         printlines (n+2, fUICode, fout);
00788     tab(n+1,fout); fout << "}";
00789 
00790     printComputeMethod(n, fout);
00791 
00792     tab(n,fout); fout << "};\n" << endl;
00793 
00794     printlines(n, fStaticFields, fout);
00795 
00796     // generate user interface macros if needed
00797     if (gUIMacroSwitch) {
00798         tab(n, fout); fout << "#ifdef FAUST_UIMACROS";
00799             tab(n+1,fout); fout << "#define FAUST_INPUTS " << fNumInputs;
00800             tab(n+1,fout); fout << "#define FAUST_OUTPUTS " << fNumOutputs;
00801             tab(n+1,fout); fout << "#define FAUST_ACTIVES " << fNumActives;
00802             tab(n+1,fout); fout << "#define FAUST_PASSIVES " << fNumPassives;
00803             printlines(n+1, fUIMacro, fout);
00804         tab(n, fout); fout << "#endif";
00805     }
00806 
00807     fout << endl;
00808 }
00809 
00813 void Klass::printComputeMethod(int n, ostream& fout)
00814 {
00815     if (gSchedulerSwitch) {
00816         printComputeMethodScheduler (n, fout);
00817     } else if (gOpenMPSwitch) {
00818         printComputeMethodOpenMP (n, fout);
00819     } else if (gVectorSwitch) {
00820         switch (gVectorLoopVariant) {
00821             case 0 : printComputeMethodVectorFaster(n, fout); break;
00822             case 1 : printComputeMethodVectorSimple(n, fout); break;
00823             default : cerr << "unknown loop variant " << gVectorLoopVariant << endl; exit(1);
00824         }
00825    } else {
00826         printComputeMethodScalar(n, fout);
00827     }
00828 }
00829 
00830 void Klass::printComputeMethodScalar(int n, ostream& fout)
00831 {
00832     tab(n+1,fout); fout << subst("virtual void compute (int count, $0** input, $0** output) {", xfloat());
00833         printlines (n+2, fZone1Code, fout);
00834         printlines (n+2, fZone2Code, fout);
00835         printlines (n+2, fZone2bCode, fout);
00836         printlines (n+2, fZone3Code, fout);
00837         printLoopGraphScalar (n+2,fout);
00838     tab(n+1,fout); fout << "}";
00839 }
00840 
00846 void Klass::printComputeMethodVectorFaster(int n, ostream& fout)
00847 {
00848     // in vector mode we need to split loops in smaller pieces not larger
00849     // than gVecSize
00850     tab(n+1,fout); fout << subst("virtual void compute (int fullcount, $0** input, $0** output) {", xfloat());
00851         printlines(n+2, fZone1Code, fout);
00852         printlines(n+2, fZone2Code, fout);
00853         printlines(n+2, fZone2bCode, fout);
00854 
00855         tab(n+2,fout); fout << "int index;";
00856         tab(n+2,fout); fout << "for (index = 0; index <= fullcount - " << gVecSize << "; index += " << gVecSize << ") {";
00857             tab(n+3,fout); fout << "// compute by blocks of " << gVecSize << " samples";
00858             tab(n+3,fout); fout << "const int count = " << gVecSize << ";";
00859             printlines (n+3, fZone3Code, fout);
00860             printLoopGraphVector(n+3,fout);
00861         tab(n+2,fout); fout << "}";
00862 
00863         tab(n+2,fout); fout << "if (index < fullcount) {";
00864             tab(n+3,fout); fout << "// compute the remaining samples if any";
00865             tab(n+3,fout); fout << "int count = fullcount-index;";
00866             printlines (n+3, fZone3Code, fout);
00867              printLoopGraphVector(n+3,fout);
00868         tab(n+2,fout); fout << "}";
00869     tab(n+1,fout); fout << "}";
00870 }
00871 
00875 void Klass::printComputeMethodVectorSimple(int n, ostream& fout)
00876 {
00877     // in vector mode we need to split loops in smaller pieces not larger
00878     // than gVecSize
00879     tab(n+1,fout); fout << subst("virtual void compute (int fullcount, $0** input, $0** output) {", xfloat());
00880         printlines(n+2, fZone1Code, fout);
00881         printlines(n+2, fZone2Code, fout);
00882         printlines(n+2, fZone2bCode, fout);
00883         tab(n+2,fout); fout << "for (int index = 0; index < fullcount; index += " << gVecSize << ") {";
00884             tab(n+3,fout); fout << "int count = min("<< gVecSize << ", fullcount-index);";
00885             printlines (n+3, fZone3Code, fout);
00886             printLoopGraphVector(n+3,fout);
00887         tab(n+2,fout); fout << "}";
00888     tab(n+1,fout); fout << "}";
00889 }
00890 
00891 /*
00892 void Klass::printComputeMethodVectorFix0 (int n, ostream& fout)
00893 {
00894     // in vector mode we need to split loops in smaller pieces not larger
00895     // than gVecSize
00896     tab(n+1,fout); fout << "virtual void compute (int fullcount, float** input, float** output) {";
00897         printlines(n+2, fZone1Code, fout);
00898         printlines(n+2, fZone2Code, fout);
00899         printlines(n+2, fZone2bCode, fout);
00900         tab(n+2,fout); fout << "for (int index = 0; index < fullcount; index += " << gVecSize << ") {";
00901             tab(n+3,fout); fout << "if (fullcount >= index + " << gVecSize << ") {";
00902                 tab(n+4,fout); fout << "// compute by blocks of " << gVecSize << " samples";
00903                 tab(n+4,fout); fout << "const int count = " << gVecSize << ";"; // temporaire
00904                 printlines(n+4, fZone3Code, fout);
00905                 printLoopGraph (n+4,fout);
00906             tab(n+3,fout); fout << "} else if (fullcount > index) {";
00907                 //tab(n+3,fout); fout << "int count = min ("<< gVecSize << ", fullcount-index);";
00908                 tab(n+4,fout); fout << "// compute the remaining samples";
00909                 tab(n+4,fout); fout << "int count = fullcount-index;" ;
00910                 printlines(n+4, fZone3Code, fout);
00911                 printLoopGraph (n+4,fout);
00912             tab(n+3,fout); fout << "}";
00913         tab(n+2,fout); fout << "}";
00914     tab(n+1,fout); fout << "}";
00915 }
00916 
00917 void Klass::printComputeMethodVectorFix1 (int n, ostream& fout)
00918 {
00919     // in vector mode we need to split loops in smaller pieces not larger
00920     // than gVecSize
00921     tab(n+1,fout); fout << "virtual void compute (int fullcount, float** input, float** output) {";
00922         printlines(n+2, fZone1Code, fout);
00923         printlines(n+2, fZone2Code, fout);
00924         printlines(n+2, fZone2bCode, fout);
00925 
00926         tab(n+2,fout); fout << "int \tblock;";
00927         tab(n+2,fout); fout << "for (block = 0; block < fullcount/" << gVecSize << "; block++) {";
00928             tab(n+3,fout); fout << "// compute by blocks of " << gVecSize << " samples";
00929             tab(n+3,fout); fout << "const int index = block*" << gVecSize << ";";
00930             tab(n+3,fout); fout << "const int count = " << gVecSize << ";"; // temporaire
00931             printlines(n+3, fZone3Code, fout);
00932             printLoopGraph (n+3,fout);
00933         tab(n+2,fout); fout << "}";
00934 
00935         tab(n+2,fout); fout << "if (fullcount%" << gVecSize << " != 0) {";
00936             //tab(n+3,fout); fout << "int count = min ("<< gVecSize << ", fullcount-index);";
00937             tab(n+3,fout); fout << "// compute the remaining samples";
00938             tab(n+3,fout); fout << "const int index = block*" << gVecSize << ";";
00939             tab(n+3,fout); fout << "int count = fullcount%" << gVecSize << ";" ;
00940             printlines(n+3, fZone3Code, fout);
00941             printLoopGraph (n+3,fout);
00942         tab(n+2,fout); fout << "}";
00943     tab(n+1,fout); fout << "}";
00944 }*/
00945 
00946 void Klass::printComputeMethodOpenMP(int n, ostream& fout)
00947 {
00948     // in openMP mode we need to split loops in smaller pieces not larger
00949     // than gVecSize and add OpenMP pragmas
00950     tab(n+1,fout); fout << subst("virtual void compute (int fullcount, $0** input, $0** output) {", xfloat());
00951         printlines(n+2, fZone1Code, fout);
00952         printlines(n+2, fZone2Code, fout);
00953         tab(n+2,fout); fout << "#pragma omp parallel";
00954         printdecllist(n+3, "firstprivate", fFirstPrivateDecl, fout);
00955 
00956         tab(n+2,fout); fout << "{";
00957             if (!fZone2bCode.empty()) {
00958                 tab(n+3,fout); fout << "#pragma omp single";
00959                 tab(n+3,fout); fout << "{";
00960                     printlines(n+4, fZone2bCode, fout);
00961                 tab(n+3,fout); fout << "}";
00962             }
00963 
00964             tab(n+3,fout); fout << "for (int index = 0; index < fullcount; index += " << gVecSize << ") {";
00965             tab(n+4,fout); fout << "int count = min ("<< gVecSize << ", fullcount-index);";
00966 
00967             printlines (n+4, fZone3Code, fout);
00968             printLoopGraphOpenMP (n+4,fout);
00969 
00970             tab(n+3,fout); fout << "}";
00971 
00972         tab(n+2,fout); fout << "}";
00973     tab(n+1,fout); fout << "}";
00974 }
00975 
00976 /*
00977 void Klass::printComputeMethodScheduler (int n, ostream& fout)
00978 {
00979     tab(n+1,fout); fout << subst("virtual void compute (int fullcount, $0** input, $0** output) {", xfloat());
00980         printlines (n+2, fZone1Code, fout);
00981         printlines (n+2, fZone2Code, fout);
00982 
00983         // Init input and output
00984         tab(n+2,fout); fout << "// Init input and output";
00985         printlines (n+2, fZone3aCode, fout);
00986         printlines (n+2, fZone3bCode, fout);
00987 
00988         tab(n+2,fout); fout << "// Init graph state";
00989         tab(n+2,fout); fout << "initState(fTasksList);";
00990         tab(n+2,fout); fout << "bool is_finished = false;";
00991         tab(n+2,fout); fout << "unsigned int index_in = 0;";
00992         tab(n+2,fout); fout << "unsigned int index_out = 0;";
00993         tab(n+2,fout); fout << "int count = min ("<< gVecSize << ", fullcount);";
00994 
00995         tab(n+2,fout); fout << "InitSchedulingMap();";
00996         tab(n+2,fout); fout << "#pragma omp parallel";
00997         printdecllist(n+3, "firstprivate", fFirstPrivateDecl, fout);
00998 
00999         tab(n+2,fout); fout << "{";
01000             tab(n+3,fout); fout << "while (!is_finished) {";
01001                 tab(n+4,fout); fout << "Task* task = searchTaskToAcquire(fTasksList);";
01002                 tab(n+4,fout); fout << "if (task != NULL) {";
01003                     tab(n+5,fout); fout << "bool last_cycle_for_thread = false;";
01004                     tab(n+5,fout); fout << "do {";
01005                         tab(n+6,fout); fout << "AddTaskToScheduling(task);";
01006                         tab(n+6,fout); fout << "switch (task->fNum) {";
01007 
01008                             // DSP tasks
01009                             printLoopGraph (n+7,fout);
01010 
01011                             // Input task
01012                             tab(n+7, fout); fout << "case " << gTaskCount++ << ": { ";
01013                             printlines (n+8, fZone6Code, fout);
01014                             tab(n+8, fout); fout << "index_in += count;";
01015                             tab(n+8, fout); fout << "last_cycle_for_thread = (index_in > fullcount);";
01016                             tab(n+8, fout); fout << "break;";
01017                             tab(n+7, fout); fout << "} ";
01018 
01019                             // Output task
01020                             tab(n+7, fout); fout << "case " << gTaskCount++ << ": { ";
01021                             printlines (n+8, fZone7Code, fout);
01022                             tab(n+8, fout); fout << "index_out += count;";
01023                             tab(n+8, fout); fout << "last_cycle_for_thread = (index_out > fullcount);";
01024                             tab(n+8, fout); fout << "break;";
01025                             tab(n+7, fout); fout << "} ";
01026 
01027                             // End task
01028                             tab(n+7, fout); fout << "case " << gTaskCount++ << ": { ";
01029                             tab(n+8, fout); fout << "is_finished = ((index_in >= fullcount) && (index_out >= fullcount));";
01030                             tab(n+8, fout); fout << "break;";
01031                             tab(n+7, fout); fout << "} ";
01032 
01033                         tab(n+6,fout); fout << "}";
01034                         tab(n+6,fout); fout << "if (last_cycle_for_thread) break;";
01035 
01036                     tab(n+5,fout); fout << "} while ((task = task->concludeAndTryToAcquireNext()) != NULL);";
01037                 tab(n+4,fout); fout << "}";
01038             tab(n+3,fout); fout << "}";
01039         tab(n+2,fout); fout << "}";
01040         tab(n+2,fout); fout << "PrintSchedulingMap();";
01041     tab(n+1,fout); fout << "}";
01042 }
01043 */
01044 
01045 void Klass::printComputeMethodScheduler (int n, ostream& fout)
01046 {
01047     tab(n+1,fout); fout << "void display() {";
01048         tab(n+2,fout); fout << "fGraph.Display();";
01049     tab(n+1,fout); fout << "}";
01050 
01051     tab(n+1,fout); fout << subst("virtual void compute (int fullcount, $0** input, $0** output) {", xfloat());
01052 
01053         tab(n+2,fout); fout << "GetRealTime();";
01054 
01055         tab(n+2,fout); fout << "this->input = input;";
01056         tab(n+2,fout); fout << "this->output = output;";
01057 
01058         tab(n+2,fout); fout << "StartMeasure();";
01059 
01060         tab(n+2,fout); fout << "for (fIndex = 0; fIndex < fullcount; fIndex += " << gVecSize << ") {";
01061 
01062         tab(n+3,fout); fout << "fFullCount = min ("<< gVecSize << ", fullcount-fIndex);";
01063         tab(n+3,fout); fout << "TaskQueue::Init();";
01064         printlines (n+3, fZone2cCode, fout);
01065 
01066         tab(n+3,fout); fout << "fIsFinished = false;";
01067         tab(n+3,fout); fout << "fThreadPool->SignalAll(fDynamicNumThreads - 1, this);";
01068         tab(n+3,fout); fout << "computeThread(0);";
01069         tab(n+3,fout); fout << "while (!fThreadPool->IsFinished()) {}";
01070 
01071         tab(n+2,fout); fout << "}";
01072 
01073         tab(n+2,fout); fout << "StopMeasure(fStaticNumThreads, fDynamicNumThreads);";
01074 
01075     tab(n+1,fout); fout << "}";
01076 
01077     tab(n+1,fout); fout << "void computeThread(int cur_thread) {";
01078         printlines (n+2, fZone1Code, fout);
01079         printlines (n+2, fZone2Code, fout);
01080 
01081         tab(n+2,fout); fout << "// Init graph state";
01082 
01083         tab(n+2,fout); fout << "{";
01084             tab(n+3,fout); fout << "TaskQueue taskqueue(cur_thread);";
01085             tab(n+3,fout); fout << "int tasknum = -1;";
01086             tab(n+3,fout); fout << "int count = fFullCount;";
01087 
01088             // Init input and output
01089             tab(n+3,fout); fout << "// Init input and output";
01090             printlines (n+3, fZone3Code, fout);
01091 
01092             tab(n+3,fout); fout << "while (!fIsFinished) {";
01093                  tab(n+4,fout); fout << "switch (tasknum) {";
01094 
01095                     // Work stealing task
01096                     tab(n+5, fout); fout << "case WORK_STEALING_INDEX: { ";
01097                         tab(n+6, fout); fout << "tasknum = TaskQueue::GetNextTask(cur_thread, fDynamicNumThreads);";
01098                         tab(n+6, fout); fout << "break;";
01099                     tab(n+5, fout); fout << "} ";
01100 
01101                     // End task
01102                     tab(n+5, fout); fout << "case LAST_TASK_INDEX: { ";
01103                         tab(n+6, fout); fout << "fIsFinished = true;";
01104                         tab(n+6, fout); fout << "break;";
01105                     tab(n+5, fout); fout << "} ";
01106 
01107                     gTaskCount = START_TASK_INDEX;
01108 
01109                     // DSP tasks
01110                     printLoopGraphScheduler (n+5,fout);
01111 
01112                  tab(n+4,fout); fout << "}";
01113             tab(n+3,fout); fout << "}";
01114         tab(n+2,fout); fout << "}";
01115     tab(n+1,fout); fout << "}";
01116 }
01117 
01121 void SigIntGenKlass::println(int n, ostream& fout)
01122 {
01123     list<Klass* >::iterator k;
01124 
01125     tab(n,fout); fout << "class " << fKlassName << " {";
01126 
01127     tab(n,fout); fout << "  private:";
01128         tab(n+1,fout); fout << "int \tfSamplingFreq;";
01129 
01130         for (k = fSubClassList.begin(); k != fSubClassList.end(); k++)  (*k)->println(n+1, fout);
01131 
01132         printlines(n+1, fDeclCode, fout);
01133 
01134     tab(n,fout); fout << "  public:";
01135 
01136         tab(n+1,fout); fout     << "int getNumInputs() \t{ "
01137                         << "return " << fNumInputs << "; }";
01138         tab(n+1,fout); fout     << "int getNumOutputs() \t{ "
01139                         << "return " << fNumOutputs << "; }";
01140 
01141         tab(n+1,fout); fout << "void init(int samplingFreq) {";
01142             tab(n+2,fout); fout << "fSamplingFreq = samplingFreq;";
01143         tab(n+1,fout); fout << "}";
01144 
01145         tab(n+1,fout); fout << "void fill (int count, int output[]) {";
01146             printlines (n+2, fZone1Code, fout);
01147             printlines (n+2, fZone2Code, fout);
01148             printlines (n+2, fZone2bCode, fout);
01149             printlines (n+2, fZone3Code, fout);
01150             printLoopGraphInternal (n+2,fout);
01151         tab(n+1,fout); fout << "}";
01152 
01153     tab(n,fout); fout << "};\n" << endl;
01154 }
01155 
01159 void SigFloatGenKlass::println(int n, ostream& fout)
01160 {
01161     list<Klass* >::iterator k;
01162 
01163     tab(n,fout); fout << "class " << fKlassName << " {";
01164 
01165     tab(n,fout); fout << "  private:";
01166         tab(n+1,fout); fout << "int \tfSamplingFreq;";
01167 
01168         for (k = fSubClassList.begin(); k != fSubClassList.end(); k++)  (*k)->println(n+1, fout);
01169 
01170         printlines(n+1, fDeclCode, fout);
01171 
01172     tab(n,fout); fout << "  public:";
01173 
01174         tab(n+1,fout); fout     << "int getNumInputs() \t{ "
01175                         << "return " << fNumInputs << "; }";
01176         tab(n+1,fout); fout     << "int getNumOutputs() \t{ "
01177                         << "return " << fNumOutputs << "; }";
01178 
01179         tab(n+1,fout); fout << "void init(int samplingFreq) {";
01180             tab(n+2,fout); fout << "fSamplingFreq = samplingFreq;";
01181             printlines(n+2, fInitCode, fout);
01182         tab(n+1,fout); fout << "}";
01183 
01184         tab(n+1,fout); fout << subst("void fill (int count, $0 output[]) {", ifloat());
01185             printlines (n+2, fZone1Code, fout);
01186             printlines (n+2, fZone2Code, fout);
01187             printlines (n+2, fZone2bCode, fout);
01188             printlines (n+2, fZone3Code, fout);
01189             printLoopGraphInternal(n+2,fout);
01190         tab(n+1,fout); fout << "}";
01191 
01192     tab(n,fout); fout << "};\n" << endl;
01193 }
01194 
01195 static void merge (set<string>& dst, set<string>& src)
01196 {
01197     set<string>::iterator i;
01198     for (i = src.begin(); i != src.end(); i++)  dst.insert(*i);
01199 }
01200 
01201 void Klass::collectIncludeFile(set<string>& S)
01202 {
01203     list<Klass* >::iterator     k;
01204 
01205     for (k = fSubClassList.begin(); k != fSubClassList.end(); k++)  (*k)->collectIncludeFile(S);
01206     merge(S, fIncludeFileSet);
01207 }
01208 
01209 void Klass::collectLibrary(set<string>& S)
01210 {
01211     list<Klass* >::iterator     k;
01212 
01213     for (k = fSubClassList.begin(); k != fSubClassList.end(); k++)  (*k)->collectLibrary(S);
01214     merge(S, fLibrarySet);
01215 }