1 /*
2 
3     This file is part of the Maude 2 interpreter.
4 
5     Copyright 1997-2003 SRI International, Menlo Park, CA 94025, USA.
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20 
21 */
22 
23 //
24 //      Implementation for abstract class SortTable.
25 //
26 #include <map>
27 
28 //	utility stuff
29 #include "macros.hh"
30 #include "vector.hh"
31 #include "indent.hh"
32 
33 //      forward declarations
34 #include "interface.hh"
35 #include "core.hh"
36 
37 //      interface class definitions
38 #include "term.hh"
39 
40 //      core class definitions
41 #include "sortBdds.hh"
42 #include "sortTable.hh"
43 
44 #ifdef COMPILER
45 #include "compilationContext.hh"
46 #endif
47 
48 #include "ctorDiagram.cc"
49 #include "sortErrorAnalysis.cc"
50 
51 /*
52 void
53 SortTable::panic() const // HACK
54 {
55   cerr << ((Symbol*)(this)) << endl;
56   ((Symbol*)(this))->dump(cerr, 0);
57   ((SortTable*)(this))->dumpSortDiagram(cerr, 0);
58 }
59 */
60 
SortTable(int arity)61 SortTable::SortTable(int arity)
62   : nrArgs(arity)
63 {
64   singleNonErrorSort = 0;
65   ctorStatus = 0;
66 }
67 
68 bool
domainSubsumes(int subsumer,int victim) const69 SortTable::domainSubsumes(int subsumer, int victim) const
70 {
71   const Vector<Sort*>& s = opDeclarations[subsumer].getDomainAndRange();
72   const Vector<Sort*>& v = opDeclarations[victim].getDomainAndRange();
73   for (int i = 0; i < nrArgs; ++i)
74     {
75       if (!(leq(v[i], s[i])))
76 	return false;
77     }
78   return true;
79 }
80 
81 void
computeMaximalOpDeclSetTable()82 SortTable::computeMaximalOpDeclSetTable()
83 {
84   //
85   //	Fill out maximalOpDeclSetTable, which for each range sort gives the set
86   //	of operator declaration whose range is less than that sort and whose
87   //	domain is not subsumed by some other declaration in the set.
88   //
89   const ConnectedComponent* range = rangeComponent();
90   int nrSorts = range->nrSorts();
91   maximalOpDeclSetTable.resize(nrSorts);
92   int nrDeclarations = opDeclarations.length();
93   //
94   //	For each range sort.
95   //
96   for (int i = 0; i < nrSorts; ++i)
97     {
98       NatSet& opDeclSet = maximalOpDeclSetTable[i];
99       const Sort* target = range->sort(i);
100       //
101       //	For each declaration.
102       //
103       for (int j = 0; j < nrDeclarations; ++j)
104 	{
105 	  if (leq(opDeclarations[j].getDomainAndRange()[nrArgs], target))
106 	    {
107 	      //
108 	      //	For each previous declaration.
109 	      //
110 	      for (int k = 0; k < j; ++k)
111 		{
112 		  if (opDeclSet.contains(k))
113 		    {
114 		      if(domainSubsumes(k, j))
115 			goto nextDecl;
116 		      else if (domainSubsumes(j, k))
117 			opDeclSet.subtract(k);
118 		    }
119 		}
120 	      opDeclSet.insert(j);
121 	    }
122 	nextDecl:
123 	  ;
124 	}
125     }
126 }
127 
128 void
compileOpDeclarations()129 SortTable::compileOpDeclarations()
130 {
131 #ifndef NO_ASSERT
132   int nrDeclarations = opDeclarations.length();
133   Assert(nrDeclarations > 0, "no operator declarations");
134 #endif
135 
136   componentVector.expandTo(nrArgs + 1);
137   for (int i = 0; i <= nrArgs; i++)
138     {
139       ConnectedComponent* c = (opDeclarations[0].getDomainAndRange()[i])->component();
140 #ifndef NO_ASSERT
141       //
142       //	Check that components really do agree for subsort overloaded
143       //	operator declarations.
144       //
145       for (int j = 1; j < nrDeclarations; j++)
146 	{
147 	  Assert(c == (opDeclarations[j].getDomainAndRange()[i])->component(),
148 		 "Sort declarations for operator " <<
149 		 static_cast<Symbol*>(this) <<  // hack
150 		 " disagree on the sort component for argument " << i + 1);
151 	}
152 #endif
153       componentVector[i] = c;
154     }
155   buildSortDiagram();
156   if (ctorStatus == IS_COMPLEX)
157     buildCtorDiagram();
158 #ifdef DUMP
159   // dumpSortDiagram(cout, 0);
160 #endif
161 }
162 
163 bool
kindLevelDeclarationsOnly() const164 SortTable::kindLevelDeclarationsOnly() const
165 {
166   FOR_EACH_CONST(i, Vector<OpDeclaration>, opDeclarations)
167     {
168       if (i->getDomainAndRange()[nrArgs]->index() != Sort::KIND)
169 	return false;
170     }
171   return true;
172 }
173 
174 bool
canProduceErrorSort() const175 SortTable::canProduceErrorSort() const
176 {
177   if (specialSortHandling())
178     return false;  // optimistic - derived class must overide if it wants to be bad!
179   if (nrArgs == 0)
180     return sortDiagram[0] == 0;
181   NatSet currentStates;
182   currentStates.insert(0);
183   for (int i = 0; i < nrArgs; i++)
184     {
185       ConnectedComponent* component = componentVector[i];
186       int index = component->errorFree() ? component->nrMaximalSorts() : 0;
187       NatSet nextStates;
188       const NatSet::const_iterator e = currentStates.end();
189       for (NatSet::const_iterator j = currentStates.begin(); j != e; ++j)
190 	{
191 	  int state = *j;
192 	  int k = index;
193 	  do
194 	    nextStates.insert(traverse(state, k));
195 	  while (--k > 0);
196 	}
197       currentStates.swap(nextStates);
198     }
199   return currentStates.contains(Sort::ERROR_SORT);
200 }
201 
202 void
finalizeSortInfo()203 SortTable::finalizeSortInfo()
204 {
205   //	For derived classes that don't do any sort constraint dependent
206   //	compile time sort calculations.
207 }
208 
209 bool
partiallySubsumes(int subsumer,int victim,int argNr)210 SortTable::partiallySubsumes(int subsumer, int victim, int argNr)
211 {
212   const Vector<Sort*>& s = opDeclarations[subsumer].getDomainAndRange();
213   const Vector<Sort*>& v = opDeclarations[victim].getDomainAndRange();
214   if (!(leq(s[nrArgs], v[nrArgs])))
215     return false;
216   for (int i = argNr; i < nrArgs; i++)
217     {
218       if (!(leq(v[i], s[i])))
219 	return false;
220     }
221   return true;
222 }
223 
224 void
minimize(NatSet & alive,int argNr)225 SortTable::minimize(NatSet& alive, int argNr)
226 {
227   //
228   //	We don't use NatSet iterators because alive is being modified.
229   //
230   //	If two declarations mutually subsume one another, the earlier one
231   //	removes the later one.
232   //
233   if (!(alive.empty()))
234     {
235       int min = alive.min();
236       int max = alive.max();
237       for (int i = min; i <= max; i++)
238 	{
239 	  if (alive.contains(i))
240 	    {
241 	      for (int j = min; j <= max; j++)
242 		{
243 		  if (j != i && alive.contains(j) && partiallySubsumes(i, j, argNr))
244 		    alive.subtract(j);
245 		}
246 	    }
247 	}
248     }
249 }
250 
251 void
buildSortDiagram()252 SortTable::buildSortDiagram()
253 {
254   Vector<NatSet> currentStates(1);
255   NatSet& all = currentStates[0];
256   int nrDeclarations = opDeclarations.length();
257   for (int i = nrDeclarations - 1; i >= 0; i--)
258     all.insert(i);  // insert in reverse order for efficiency
259   if (nrArgs == 0)
260     {
261       sortDiagram.expandTo(1);
262       bool unique;
263       int sortIndex = findMinSortIndex(all, unique);
264       WarningCheck(unique, "sort declarations for constant " << QUOTE(safeCast(Symbol*, this)) <<
265 		   " do not have an unique least sort.");
266       sortDiagram[0] = sortIndex;
267       singleNonErrorSort = componentVector[0]->sort(sortIndex);
268       return;
269     }
270   enum SpecialSortIndices
271   {
272     UNINITIALIZED = 0,
273     IMPOSSIBLE = -1
274   };
275   int singleNonErrorSortIndex = UNINITIALIZED;
276   Vector<NatSet> nextStates;
277   int currentBase = 0;
278   set<int> badTerminals;
279   //
280   //	For each argument.
281   //
282   for (int i = 0; i < nrArgs; i++)
283     {
284       const ConnectedComponent* component = componentVector[i];
285       int nrSorts = component->nrSorts();
286       int nrCurrentStates = currentStates.length();
287 
288       int nextBase = currentBase + nrSorts * nrCurrentStates;
289       sortDiagram.expandTo(nextBase);
290       int nrNextSorts = (i == nrArgs - 1) ? 0 : componentVector[i + 1]->nrSorts();
291       //
292       //	For each sort that the argument might have.
293       //
294       for (int j = 0; j < nrSorts; j++)
295 	{
296 	  Sort* s = component->sort(j);
297 	  //
298 	  //	Compute the set of declarations that are viable with this argument having this sort.
299 	  //
300 	  NatSet viable;
301 	  for (int k = 0; k < nrDeclarations; k++)
302 	    {
303 	      if (leq(s, opDeclarations[k].getDomainAndRange()[i]))
304 		viable.insert(k);
305 	    }
306 	  //
307 	  //	For each current state, compute a new state or a sort.
308 	  //
309 	  for (int k = 0; k < nrCurrentStates; k++)
310 	    {
311 	      NatSet nextState(viable);
312 	      nextState.intersect(currentStates[k]);
313 	      int index = currentBase + k * nrSorts + j;
314 	      if (nrNextSorts == 0)
315 		{
316 		  //
317 		  //	Final argument case - we compute a sort.
318 		  //
319 		  bool unique;
320 		  int sortIndex = findMinSortIndex(nextState, unique);
321 		  sortDiagram[index] = sortIndex;
322 		  if (!unique)
323 		    badTerminals.insert(index);
324 		  if (sortIndex > 0)
325 		    {
326 		      if (singleNonErrorSortIndex == UNINITIALIZED)
327 			singleNonErrorSortIndex = sortIndex;
328 		      else if (singleNonErrorSortIndex > 0 &&
329 			       singleNonErrorSortIndex != sortIndex)
330 			singleNonErrorSortIndex = IMPOSSIBLE;
331 		    }
332 		}
333 	      else
334 		{
335 		  //
336 		  //	Nonfinal argument case - we compute a new state by discarding
337 		  //	redundant declarations and getting a state number for it.
338 		  //
339 		  minimize(nextState, i + 1);
340 		  sortDiagram[index] =
341 		    nextBase + nrNextSorts * findStateNumber(nextStates, nextState);
342 		}
343 	    }
344 	}
345       currentStates.swap(nextStates);
346       nextStates.contractTo(0);
347       currentBase = nextBase;
348     }
349   if (singleNonErrorSortIndex > 0)
350     singleNonErrorSort = componentVector[nrArgs]->sort(singleNonErrorSortIndex);
351   if (!(badTerminals.empty()))
352     sortErrorAnalysis(true, badTerminals);
353   DebugAdvisory("sort table for " << static_cast<Symbol*>(this) << " has " << sortDiagram.size() << " entries");
354 }
355 
356 int
findStateNumber(Vector<NatSet> & stateSet,const NatSet & state)357 SortTable::findStateNumber(Vector<NatSet>& stateSet, const NatSet& state)
358 {
359   int nrStates = stateSet.length();
360   for (int i = 0; i < nrStates; i++)
361     {
362       if (stateSet[i] == state)
363 	return i;
364     }
365   stateSet.append(state);
366   return nrStates;
367 }
368 
369 int
findMinSortIndex(const NatSet & state,bool & unique)370 SortTable::findMinSortIndex(const NatSet& state, bool& unique)
371 {
372   Sort* minSort = componentVector[nrArgs]->sort(Sort::ERROR_SORT);  // start with error sort
373   NatSet infSoFar(minSort->getLeqSorts());
374   FOR_EACH_CONST(i, NatSet, state)
375     {
376       Sort* rangeSort = opDeclarations[*i].getDomainAndRange()[nrArgs];
377       const NatSet& rangeLeqSorts = rangeSort->getLeqSorts();
378       infSoFar.intersect(rangeLeqSorts);
379       //
380       //	This test only succeeds if rangeSort is less than or equal to
381       //	to the range sorts of the previous declarations in the state.
382       //	Thus in the case of a non-preregular operator we break in favor
383       //	of the earlier declaration
384       //
385       if (infSoFar == rangeLeqSorts)
386 	minSort = rangeSort;
387     }
388   unique = (infSoFar == minSort->getLeqSorts());
389   return minSort->index();
390 }
391 
392 void
computeSortFunctionBdds(const SortBdds & sortBdds,Vector<Bdd> & sortFunctionBdds) const393 SortTable::computeSortFunctionBdds(const SortBdds& sortBdds, Vector<Bdd>& sortFunctionBdds) const
394 {
395   if (sortDiagram.isNull())
396     return;  // operator doesn't use our mechanism
397   //
398   //	We take our sort decision diagram and produce a BDD version, encoding each sort index
399   //	by a bit vector.
400   //
401   if (nrArgs == 0)
402     {
403       //
404       //	Generate constant BDD vector for constant operator.
405       //
406       sortBdds.makeIndexVector(sortBdds.getNrVariables(componentVector[nrArgs]->getIndexWithinModule()),
407 			       singleNonErrorSort->index(),
408 			       sortFunctionBdds);
409       return;
410     }
411   //
412   //	Calculate and allocate the number of BDD variables we will need to represent the domain sorts.
413   //
414   int nrBddVariablesForDomain = 0;
415   for (int i = 0; i < nrArgs; ++i)
416     nrBddVariablesForDomain += sortBdds.getNrVariables(componentVector[i]->getIndexWithinModule());
417   BddUser::setNrVariables(nrBddVariablesForDomain);
418   //
419   //	We have two alternative ways of computing the vector of BDDs to that represent the sort function.
420   //
421   recursiveComputeSortFunctionBdds(sortBdds, sortFunctionBdds);
422   Vector<Bdd> altSortFunctionBdds;
423   linearComputeSortFunctionBdds(sortBdds, altSortFunctionBdds);
424   //
425   //	Consistancy test code.
426   //
427   DebugAdvisory("computeSortFunctionBdds() - consistancy check");
428   int nrBdds = altSortFunctionBdds.size();
429   for (int i = 0; i < nrBdds; ++i)
430     {
431       if (altSortFunctionBdds[i] != sortFunctionBdds[i])
432 	{
433 	  DebugAdvisory("computeSortFunctionBdds() : *** computeSortFunctionBdds() recursive =\n" << sortFunctionBdds[i] <<
434 			"linear =\n" << altSortFunctionBdds[i]);
435 	}
436     }
437 }
438 
439 void
recursiveComputeSortFunctionBdds(const SortBdds & sortBdds,Vector<Bdd> & sortFunctionBdds) const440 SortTable::recursiveComputeSortFunctionBdds(const SortBdds& sortBdds, Vector<Bdd>& sortFunctionBdds) const
441 {
442   //
443   //	Calculate and allocate the number of BDD variables we will need to represent the domain sorts.
444   //
445   int nrBddVariablesForDomain = 0;
446   for (int i = 0; i < nrArgs; ++i)
447     nrBddVariablesForDomain += sortBdds.getNrVariables(componentVector[i]->getIndexWithinModule());
448   BddUser::setNrVariables(nrBddVariablesForDomain);
449 
450   BddTable table(sortDiagram.size());  // only target entries actually used
451   //  for (int i = 0; i < sortDiagram.size(); ++i)
452   //    cerr << sortDiagram[i] << " ";
453   //  cerr << endl;
454   computeBddVector(sortBdds, 0, 0, table, 0);
455   sortFunctionBdds.swap(table[0]);
456 }
457 
458 void
linearComputeSortFunctionBdds(const SortBdds & sortBdds,Vector<Bdd> & sortFunctionBdds) const459 SortTable::linearComputeSortFunctionBdds(const SortBdds& sortBdds, Vector<Bdd>& sortFunctionBdds) const
460 {
461   //
462   //	This is an alternative computation of the same BDDs, directly from the operator declarations.
463   //
464   const ConnectedComponent* rangeComponent = componentVector[nrArgs];
465   int nrBddVariables = sortBdds.getNrVariables(rangeComponent->getIndexWithinModule());
466   //
467   //	We start with the constant error sort everywhere function.
468   //
469   sortBdds.makeIndexVector(nrBddVariables, Sort::ERROR_SORT, sortFunctionBdds);
470   //
471   //	Because this algorithm breaks in favor of later considered declarations we consider the declarations
472   //	in reverse order for consistancy with the standard sort calculation on non-pregular signatures.
473   //
474   for (int i = opDeclarations.length() - 1; i >= 0; --i)
475     {
476       const Vector<Sort*>& opDeclaration = opDeclarations[i].getDomainAndRange();
477       Bdd replaceWithOurRangeSort = bdd_true();
478       //
479       //	First require all arguments to have a sort <= than than that of the
480       //	corresponding sort in the declaration.
481       //
482       int bddVarNr = 0;
483       for (int j = 0; j < nrArgs; ++j)
484 	{
485 	  Sort* sort = opDeclaration[j];
486 	  Bdd leqRelation = sortBdds.getRemappedLeqRelation(sort, bddVarNr);
487 	  replaceWithOurRangeSort = bdd_and(replaceWithOurRangeSort, leqRelation);
488 	  bddVarNr += sortBdds.getNrVariables(componentVector[j]->getIndexWithinModule());
489 	}
490       //
491       //	We require that the currently computed sort is not <= our range sort.
492       //	This allows our sort to replace the current sort in the incomparable case
493       //	and in the > case.
494       //
495       Sort* rangeSort = opDeclaration[nrArgs];
496       Bdd currentLeqOurRange = sortBdds.applyLeqRelation(rangeSort, sortFunctionBdds);
497       replaceWithOurRangeSort = bdd_and(replaceWithOurRangeSort, bdd_not(currentLeqOurRange));
498       //
499       //	We now have a BDD that tells us when to replace the currently computed sort
500       //	with our range sort. We update the currently computed sort BDD using ite.
501       //
502       Vector<Bdd> ourRangeSort;
503       sortBdds.makeIndexVector(nrBddVariables, rangeSort->index(), ourRangeSort);
504 
505       for (int k = 0; k < nrBddVariables; ++k)
506 	sortFunctionBdds[k] = bdd_ite(replaceWithOurRangeSort, ourRangeSort[k], sortFunctionBdds[k]);
507     }
508 }
509 
510 void
computeBddVector(const SortBdds & sortBdds,int bddVarNr,int argNr,BddTable & table,int nodeNr) const511 SortTable::computeBddVector(const SortBdds& sortBdds,
512 			    int bddVarNr,
513 			    int argNr,
514 			    BddTable& table,
515 			    int nodeNr) const
516 {
517   //  DebugAdvisory("starting computeBddVector(bddVarNr=" << bddVarNr << ",  argNr=" << argNr << ", nodeNr=" << nodeNr << ")");
518   Assert(argNr < nrArgs, "bad argNr");
519   BddVector& vec =  table[nodeNr];
520   if (!vec.isNull())
521     return;
522   //
523   //	We fill out the BDD vector vec to make it correspond to sortDiagram[nodeNr].
524   //
525   const ConnectedComponent* component = componentVector[argNr];
526   int nrBddVariables = sortBdds.getNrVariables(component->getIndexWithinModule());
527   //
528   //	We first look at each value of our argument and OR together BDDs for those
529   //	that go to the same place.
530   //
531   //  DebugAdvisory("starting OR phase");
532   int nrSorts = component->nrSorts();
533   typedef map<int, Bdd> BddMap;
534   BddMap disjuncts;
535   for (int i = 0; i < nrSorts; ++i)
536     {
537       Bdd& disjunct = disjuncts[sortDiagram[nodeNr + i]];
538       Bdd indexBdd = sortBdds.makeIndexBdd(bddVarNr, nrBddVariables, i);
539       //DebugAdvisory("disjunct = " << disjunct.id() << " indexBdd = " << indexBdd.id());
540       disjunct = bdd_or(disjunct, indexBdd /*sortBdds.makeIndexBdd(bddVarNr, nrBddVariables, i)*/);
541       //DebugAdvisory("done disjunct = " << disjunct.id());
542     }
543   //
544   //	Now we go through the disjunctions we collected,  ANDing them with the
545   //	vectors at their targets and OR the products together to form our final
546   //	vector.
547   //
548   //  DebugAdvisory("starting OR of ANDs phase");
549   int nrBdds = sortBdds.getNrVariables(componentVector[nrArgs]->getIndexWithinModule());
550   vec.resize(nrBdds);  // default construct sets all the elements to false
551   FOR_EACH_CONST(i, BddMap, disjuncts)
552     {
553       int target = i->first;
554       if (argNr + 1 == nrArgs)
555 	{
556 	  //
557 	  //	Target is actually the index of a sort.
558 	  //
559 	  BddVector t;
560 	  sortBdds.makeIndexVector(nrBdds, target, t);
561 	  for (int j = 0; j < nrBdds; ++j)
562 	    {
563 	      //DebugAdvisory("vec[j] " << vec[j].id());
564 	      //DebugAdvisory("t[j] " << t[j].id());
565 	      vec[j] = bdd_or(vec[j], bdd_and(i->second, t[j]));
566 	    }
567 	}
568       else
569 	{
570 	  computeBddVector(sortBdds, bddVarNr + nrBddVariables, argNr + 1, table, target);
571 	  BddVector& targetVec = table[target];
572 	  for (int j = 0; j < nrBdds; ++j)
573 	    {
574 	      //DebugAdvisory("vec[j] " << vec[j].id());
575 	      //DebugAdvisory("targetVec[j] " << targetVec[j].id());
576 	      vec[j] = bdd_or(vec[j], bdd_and(i->second, targetVec[j]));
577 	    }
578 	}
579     }
580   //DebugAdvisory("done computeBddVector(bddVarNr=" << bddVarNr << ",  argNr=" << argNr << ", nodeNr=" << nodeNr << ")");
581 }
582 
583 #ifdef COMPILER
584 void
generateSortDiagram(CompilationContext & context) const585 SortTable::generateSortDiagram(CompilationContext& context) const
586 {
587   Vector<int> minimum(0, nrArgs);
588   Vector<int> maximum(0, nrArgs);
589   {
590     int min = 0;
591     int max = 0;
592     minimum.append(0);
593     maximum.append(0);
594     for (int i = 0; i < nrArgs - 1; i++)
595       {
596 	int nrSorts = componentVector[i]->nrSorts();
597 	int newMin = UNBOUNDED;
598 	int newMax = 0;
599 	for (int j = min; j < max + nrSorts; j++)
600 	  {
601 	    int t = sortDiagram[j];
602 	    if (t < newMin)
603 	      newMin = t;
604 	    if (t > newMax)
605 	      newMax = t;
606 	  }
607 	min = newMin;
608 	max = newMax;
609         minimum.append(min);
610 	maximum.append(max);
611       }
612   }
613   int index = static_cast<const Symbol*>(this)->getIndexWithinModule();
614   for (int i = nrArgs - 1; i >= 0; i--)
615     {
616       int nrSorts = componentVector[i]->nrSorts();
617       int min = minimum[i];
618       int max = maximum[i];
619 
620       for (int j = min; j <= max; j += nrSorts)
621 	{
622 	  context.head() << "Flags";
623 	  for (int k = i; k < nrArgs - 1; k++)
624 	    context.head() << '*';
625 	  context.head() << " f" << index << '_' << j << "[] = { ";
626 	  for (int k = 0; k < nrSorts; k++)
627 	    {
628 	      if (i == nrArgs - 1)
629 		context.head() << '{' << sortDiagram[j + k] << '}';
630 	      else
631 		context.head() << 'f' << index << '_' << sortDiagram[j + k];
632 	      if (k + 1 < nrSorts)
633 		context.head() << ", ";
634 	    }
635 	  context.head() << " };\n";
636 	}
637     }
638 }
639 #endif
640 
641 #ifdef DUMP
642 void
dumpSortDiagram(ostream & s,int indentLevel)643 SortTable::dumpSortDiagram(ostream& s, int indentLevel)
644 {
645   if (specialSortHandling())
646     return;  // HACK
647   s << Indent(indentLevel) << "Begin{SortDiagram}";
648   indentLevel += 2;
649   set<int> nodes;
650   nodes.insert(0);
651   ConnectedComponent* range = componentVector[nrArgs];
652   if (nrArgs == 0)
653     {
654       int target = sortDiagram[0];
655       s << '\n' << Indent(indentLevel - 1) << "node 0 -> sort " <<
656 	target << " (" << range->sort(target) << ")\n";
657     }
658   for (int i = 0; i < nrArgs; i++)
659     {
660       ConnectedComponent* component = componentVector[i];
661       int nrSorts = component->nrSorts();
662       set<int>  nextNodes;
663       FOR_EACH_CONST(j, set<int>, nodes)
664 	{
665 	  int n = *j;
666 	  s << '\n' << Indent(indentLevel - 1) << "Node " << n <<
667 	    " (testing argument " << i << ")\n";
668 	  for (int k = 0; k < nrSorts; k++)
669 	    {
670 	      int target = sortDiagram[n + k];
671 	      s << Indent(indentLevel) << "sort " << k << " (" <<
672 		component->sort(k) << ") -> ";
673 	      if (i == nrArgs - 1)
674 		{
675 		  s << "sort " << target << " (" <<
676 		    range->sort(target) << ")\n";
677 		}
678 	      else
679 		{
680 		  s << "node " << target << '\n';
681 		  nextNodes.insert(target);
682 		}
683 	    }
684 	}
685       nodes.swap(nextNodes);
686     }
687   s << Indent(indentLevel - 2) << "End{SortDiagram}\n";
688 }
689 
690 #endif
691