This makes the dump files more readable
[fw/sdcc] / src / SDCCBBlock.c
1 /*-------------------------------------------------------------------------
2
3   SDCCBBlock.c - routines to manipulate basic Blocks
4
5              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
6
7    This program is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by the
9    Free Software Foundation; either version 2, or (at your option) any
10    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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21    In other words, you are welcome to use, share and improve this program.
22    You are forbidden to forbid anyone else to use, share and improve
23    what you give them.   Help stamp out software-hoarding!
24 -------------------------------------------------------------------------*/
25
26 #include "common.h"
27
28 int eBBNum = 0;
29 set *graphEdges = NULL;         /* list of edges in this flow graph */
30
31 struct _dumpFiles dumpFiles[] = {
32   {DUMP_RAW0, ".dumpraw0", NULL},
33   {DUMP_RAW1, ".dumpraw1", NULL},
34   {DUMP_CSE, ".dumpcse", NULL},
35   {DUMP_DFLOW, ".dumpdflow", NULL},
36   {DUMP_GCSE, ".dumpgcse", NULL},
37   {DUMP_DEADCODE, ".dumpdeadcode", NULL},
38   {DUMP_LOOP, ".dumploop", NULL},
39   {DUMP_LOOPG, ".dumploopg", NULL},
40   {DUMP_LOOPD, ".dumploopd", NULL},
41   {DUMP_RANGE, ".dumprange", NULL},
42   {DUMP_PACK, ".dumppack", NULL},
43   {DUMP_RASSGN, ".dumprassgn", NULL},
44   {DUMP_LRANGE, ".dumplrange", NULL},
45   {0, NULL, NULL}
46 };
47
48 /*-----------------------------------------------------------------*/
49 /* printEntryLabel - prints entry label of a ebblock               */
50 /*-----------------------------------------------------------------*/
51 DEFSETFUNC (printEntryLabel)
52 {
53   eBBlock *bp = item;
54
55   fprintf (stdout, " %-20s ", bp->entryLabel->name);
56   return 0;
57 }
58
59 /*-----------------------------------------------------------------*/
60 /* neweBBlock - allocate & return a new extended basic block       */
61 /*-----------------------------------------------------------------*/
62 eBBlock *
63 neweBBlock ()
64 {
65   eBBlock *ebb;
66
67   ebb = Safe_alloc (sizeof (eBBlock));
68   return ebb;
69 }
70
71 /*-----------------------------------------------------------------*/
72 /* newEdge - allocates & initialises an edge to given values       */
73 /*-----------------------------------------------------------------*/
74 edge *
75 newEdge (eBBlock * from, eBBlock * to)
76 {
77   edge *ep;
78
79   ep = Safe_alloc (sizeof (edge));
80
81   ep->from = from;
82   ep->to = to;
83   return ep;
84 }
85
86 /*-----------------------------------------------------------------*/
87 /* createDumpFile - create the dump file                           */
88 /*-----------------------------------------------------------------*/
89 FILE *createDumpFile (int id) {
90   struct _dumpFiles *dumpFilesPtr=dumpFiles;
91
92   while (dumpFilesPtr->id) {
93     if (dumpFilesPtr->id==id)
94       break;
95     dumpFilesPtr++;
96   }
97
98   if (!dumpFilesPtr->id) {
99     fprintf (stdout, "internal error: createDumpFile: unknown dump file.\n");
100     exit (1);
101   }
102
103   if (!dumpFilesPtr->filePtr) {
104     // not used before, create it
105     strncpyz (scratchFileName, dstFileName, PATH_MAX);
106     strncatz (scratchFileName, dumpFilesPtr->ext, PATH_MAX);
107     if (!(dumpFilesPtr->filePtr = fopen (scratchFileName, "w"))) {
108       werror (E_FILE_OPEN_ERR, scratchFileName);
109       exit (1);
110     }
111   } 
112   return dumpFilesPtr->filePtr;
113 }
114
115 /*-----------------------------------------------------------------*/
116 /* closeDumpFiles - close possible opened dumpfiles                */
117 /*-----------------------------------------------------------------*/
118 void closeDumpFiles() {
119   struct _dumpFiles *dumpFilesPtr;
120
121   for (dumpFilesPtr=dumpFiles; dumpFilesPtr->id; dumpFilesPtr++) {
122     if (dumpFilesPtr->filePtr) {
123       fclose (dumpFilesPtr->filePtr);
124     }
125   }
126 }
127
128 /*-----------------------------------------------------------------*/
129 /* dumpLiveRanges - dump liverange information into a file         */
130 /*-----------------------------------------------------------------*/
131 void 
132 dumpLiveRanges (int id, hTab * liveRanges)
133 {
134   FILE *file;
135   symbol *sym;
136   int k;
137
138   if (id) {
139     file=createDumpFile(id);
140   } else {
141     file = stdout;
142   }
143   
144   if (currFunc) 
145       fprintf(file,"------------- Func %s -------------\n",currFunc->name);
146   for (sym = hTabFirstItem (liveRanges, &k); sym;
147        sym = hTabNextItem (liveRanges, &k))
148     {
149
150       fprintf (file, "%s [k%d lr%d:%d so:%d]{ re%d rm%d}",
151                (sym->rname[0] ? sym->rname : sym->name),
152                sym->key,
153                sym->liveFrom, sym->liveTo,
154                sym->stack,
155                sym->isreqv, sym->remat
156         );
157
158       fprintf (file, "{");
159       printTypeChain (sym->type, file);
160       if (sym->usl.spillLoc)
161         {
162           fprintf (file, "}{ sir@ %s", sym->usl.spillLoc->rname);
163         }
164       fprintf (file, "} clashes with ");
165       bitVectDebugOn(sym->clashes,file);
166       fprintf (file, "\n");
167     }
168
169   fflush(file);
170 }
171
172 /*-----------------------------------------------------------------*/
173 /* dumpEbbsToFileExt - writeall the basic blocks to a file         */
174 /*-----------------------------------------------------------------*/
175 void 
176 dumpEbbsToFileExt (int id, eBBlock ** ebbs, int count)
177 {
178   FILE *of;
179   int i;
180   eBBlock *bb;
181
182   if (id) {
183     of=createDumpFile(id);
184   } else {
185     of = stdout;
186   }
187
188   for (i = 0; i < count; i++)
189     {
190       fprintf (of, "\n----------------------------------------------------------------\n");
191       fprintf (of, "Basic Block %d %s : loop Depth = %d noPath = %d lastinLoop = %d\n",
192                ebbs[i]->dfnum,
193                ebbs[i]->entryLabel->name,
194                ebbs[i]->depth,
195                ebbs[i]->noPath,
196                ebbs[i]->isLastInLoop);
197
198       if (!optimize.label4) { 
199         // this only makes sense with --nolabelopt
200         fprintf (of, "\nsuccessors: ");
201         for (bb=setFirstItem(ebbs[i]->succList); 
202              bb; 
203              bb=setNextItem(ebbs[i]->succList)) {
204           fprintf (of, "%s ", bb->entryLabel->name);
205         }
206         fprintf (of, "\npredecessors: ");
207         for (bb=setFirstItem(ebbs[i]->predList); 
208              bb; 
209              bb=setNextItem(ebbs[i]->predList)) {
210           fprintf (of, "%s ", bb->entryLabel->name);
211         }
212 #if 0 // jwk: TODO: this can't be true
213         {
214           int d;
215           fprintf (of, "\ndominators ???: ");
216           for (d=0; d<ebbs[i]->domVect->size; d++) {
217             if (bitVectBitValue(ebbs[d]->domVect, d)) {
218               fprintf (of, "%s ", ebbs[d]->entryLabel->name);
219             }
220           }
221         }
222 #endif
223         fprintf (of, "\n");
224       }
225   
226       fprintf (of, "\ndefines bitVector :");
227       bitVectDebugOn (ebbs[i]->defSet, of);
228       fprintf (of, "\nlocal defines bitVector :");
229       bitVectDebugOn (ebbs[i]->ldefs, of);
230       fprintf (of, "\npointers Set bitvector :");
231       bitVectDebugOn (ebbs[i]->ptrsSet, of);
232       if (ebbs[i]->isLastInLoop) {
233               fprintf (of, "\nInductions Set bitvector :");
234               bitVectDebugOn (ebbs[i]->linds, of);
235       }
236       fprintf (of, "\n----------------------------------------------------------------\n");
237       printiCChain (ebbs[i]->sch, of);
238     }
239   fflush(of);
240 }
241
242 /*-----------------------------------------------------------------*/
243 /* iCode2eBBlock - converts a sequnce till label to a ebb          */
244 /*-----------------------------------------------------------------*/
245 eBBlock *
246 iCode2eBBlock (iCode * ic)
247 {
248   iCode *loop;
249   eBBlock *ebb = neweBBlock (); /* allocate an entry */
250
251   /* put the first one unconditionally */
252   ebb->sch = ic;
253
254   /* if this is a label then */
255   if (ic->op == LABEL)
256     ebb->entryLabel = ic->label;
257   else
258     {
259       SNPRINTF (buffer, sizeof(buffer), "_eBBlock%d", eBBNum++);
260       ebb->entryLabel = newSymbol (buffer, 1);
261       ebb->entryLabel->key = labelKey++;
262     }
263
264   if (ic &&
265       (ic->op == GOTO ||
266        ic->op == JUMPTABLE ||
267        ic->op == IFX))
268     {
269       ebb->ech = ebb->sch;
270       return ebb;
271     }
272
273   if ((ic->next && ic->next->op == LABEL) ||
274       !ic->next)
275     {
276       ebb->ech = ebb->sch;
277       return ebb;
278     }
279
280   /* loop thru till we find one with a label */
281   for (loop = ic->next; loop; loop = loop->next)
282     {
283
284       /* if this is the last one */
285       if (!loop->next)
286         break;
287       /* if this is a function call */
288       if (loop->op == CALL || loop->op == PCALL)
289         {
290           ebb->hasFcall = 1;
291           if (currFunc)
292             FUNC_HASFCALL(currFunc->type) = 1;
293         }
294
295       /* if the next one is a label */
296       /* if this is a goto or ifx */
297       if (loop->next->op == LABEL ||
298           loop->op == GOTO ||
299           loop->op == JUMPTABLE ||
300           loop->op == IFX)
301         break;
302     }
303
304   /* mark the end of the chain */
305   ebb->ech = loop;
306
307   return ebb;
308 }
309
310 /*-----------------------------------------------------------------*/
311 /* eBBWithEntryLabel - finds the basic block with the entry label  */
312 /*-----------------------------------------------------------------*/
313 eBBlock *
314 eBBWithEntryLabel (eBBlock ** ebbs, symbol * eLabel, int count)
315 {
316   int i;
317
318   for (i = 0; i < count; i++)
319     {
320       if (isSymbolEqual (ebbs[i]->entryLabel, eLabel))
321         return ebbs[i];
322     }
323
324   return NULL;
325 }
326
327
328 /*-----------------------------------------------------------------*/
329 /* ifFromIs - will return 1 if the from block matches this         */
330 /*-----------------------------------------------------------------*/
331 DEFSETFUNC (ifFromIs)
332 {
333   edge *ep = item;
334   V_ARG (eBBlock *, this);
335
336   if (ep->from == this)
337     return 1;
338
339   return 0;
340 }
341
342
343 /*-----------------------------------------------------------------*/
344 /* edgesTo  - returns a set of edges with to == supplied value     */
345 /*-----------------------------------------------------------------*/
346 set *
347 edgesTo (eBBlock * to)
348 {
349   set *result = NULL;
350   edge *loop;
351
352   for (loop = setFirstItem (graphEdges); loop; loop = setNextItem (graphEdges))
353     if (loop->to == to && !loop->from->noPath)
354       addSet (&result, loop->from);
355
356   return result;
357 }
358
359
360 /*-----------------------------------------------------------------*/
361 /* addiCodeToeBBlock - will add an iCode to the end of a block     */
362 /*-----------------------------------------------------------------*/
363 void 
364 addiCodeToeBBlock (eBBlock * ebp, iCode * ic, iCode * ip)
365 {
366   ic->prev = ic->next = NULL;
367   /* if the insert point is given */
368   if (ip)
369     {
370       ic->lineno = ip->lineno;
371       ic->prev = ip->prev;
372       ip->prev = ic;
373       ic->next = ip;
374       if (!ic->prev)
375         ebp->sch = ic;
376       else
377         ic->prev->next = ic;
378       return;
379     }
380
381   /* if the block has no  instructions */
382   if (ebp->ech == NULL)
383     {
384       ebp->sch = ebp->ech = ic;
385       ic->next = NULL;
386       return;
387     }
388
389   /* if the last instruction is a goto */
390   /* we add it just before the goto    */
391   if (ebp->ech->op == GOTO || ebp->ech->op == JUMPTABLE
392       || ebp->ech->op == RETURN)
393     {
394       ic->lineno = ebp->ech->lineno;
395       ic->prev = ebp->ech->prev;
396       ebp->ech->prev = ic;
397       ic->next = ebp->ech;
398       if (!ic->prev)            /* was the last only on in the block */
399         ebp->sch = ic;
400       else
401         ic->prev->next = ic;
402       return;
403     }
404
405   /* if the last one was a ifx statement we check to see */
406   /* if the condition was defined in the previous instruction */
407   /* if this is true then we put it before the condition else */
408   /* we put it before if, this is to reduce register pressure, */
409   /* we don't have to hold  condition too long in a register  */
410   if (ebp->ech->op == IFX)
411     {
412       iCode *ipoint;
413
414 /*  if ( !ebp->ech->prev )  */
415 /*      ipoint = ebp->ech ; */
416 /*  else  */
417 /*      if (!IC_RESULT(ebp->ech->prev)) */
418 /*    ipoint = ebp->ech ; */
419 /*      else */
420 /*    if (IC_COND(ebp->ech)->key == IC_RESULT(ebp->ech->prev)->key) */
421 /*        ipoint = ebp->ech->prev; */
422 /*    else */
423 /*        ipoint = ebp->ech ; */
424       ipoint = ebp->ech;
425       ic->lineno = ipoint->lineno;
426       ic->prev = ipoint->prev;
427       ipoint->prev = ic;
428       ic->next = ipoint;
429       if (!ic->prev)
430         ebp->sch = ic;
431       else
432         ic->prev->next = ic;
433       return;
434     }
435
436   /* will add it to the very end */
437   ip = ebp->ech;
438   ip->next = ic;
439   ic->prev = ip;
440   ic->next = NULL;
441   ebp->ech = ic;
442
443   return;
444 }
445
446 /*-----------------------------------------------------------------*/
447 /* remiCodeFromeBBlock - remove an iCode from BBlock               */
448 /*-----------------------------------------------------------------*/
449 void 
450 remiCodeFromeBBlock (eBBlock * ebb, iCode * ic)
451 {
452   wassert (ic->seq>=ebb->fSeq && ic->seq<=ebb->lSeq);
453   if (ic->prev)
454     ic->prev->next = ic->next;
455   else
456     ebb->sch = ic->next;
457
458   if (ic->next)
459     ic->next->prev = ic->prev;
460   else
461     ebb->ech = ic->prev;
462 }
463
464 /*-----------------------------------------------------------------*/
465 /* iCodeBreakDown : breakDown iCode chain to blocks                */
466 /*-----------------------------------------------------------------*/
467 eBBlock **
468 iCodeBreakDown (iCode * ic, int *count)
469 {
470   eBBlock **ebbs = NULL;
471   iCode *loop = ic;
472
473   *count = 0;
474
475   /* allocate for the first entry */
476
477   ebbs = Safe_alloc (sizeof (eBBlock **));
478
479   while (loop)
480     {
481
482       /* convert 2 block */
483       eBBlock *ebb = iCode2eBBlock (loop);
484       loop = ebb->ech->next;
485
486       ebb->ech->next = NULL;    /* mark the end of this chain */
487       if (loop)
488         loop->prev = NULL;
489       ebb->bbnum = *count;      /* save this block number     */
490       /* put it in the array */
491       ebbs[(*count)++] = ebb;
492
493       /* allocate for the next one. Remember to clear the new */
494       /*  pointer at the end, that was created by realloc. */
495
496       ebbs = Safe_realloc (ebbs, (*count + 1) * sizeof (eBBlock **));
497
498       ebbs[*count] = 0;
499
500       /* if this one ends in a goto or a conditional */
501       /* branch then check if the block it is going  */
502       /* to already exists, if yes then this could   */
503       /* be a loop, add a preheader to the block it  */
504       /* goes to  if it does not already have one    */
505       if (ebbs[(*count) - 1]->ech &&
506           (ebbs[(*count) - 1]->ech->op == GOTO ||
507            ebbs[(*count) - 1]->ech->op == IFX))
508         {
509
510           symbol *label;
511           eBBlock *destBlock;
512
513           if (ebbs[(*count) - 1]->ech->op == GOTO)
514             label = IC_LABEL (ebbs[(*count) - 1]->ech);
515           else if (!(label = IC_TRUE (ebbs[(*count) - 1]->ech)))
516             label = IC_FALSE (ebbs[(*count) - 1]->ech);
517
518           if ((destBlock = eBBWithEntryLabel (ebbs, label, (*count))) &&
519               destBlock->preHeader == NULL &&
520               otherPathsPresent (ebbs, destBlock))
521             {
522
523               symbol *preHeaderLabel = newiTempPreheaderLabel ();
524               int i, j;
525               eBBlock *pBlock;
526
527               /* go thru all block replacing the entryLabel with new label */
528               /* till we reach the block , then we insert a new ebblock    */
529               for (i = 0; i < (*count); i++)
530                 {
531                   if (ebbs[i] == destBlock)
532                     break;
533                   replaceLabel (ebbs[i], label, preHeaderLabel);
534                 }
535
536               (*count)++;
537
538               /* if we have stopped at the block , allocate for an extra one */
539
540               ebbs = Safe_realloc (ebbs, (*count + 1) * sizeof (eBBlock **));
541
542               ebbs[*count] = 0;
543
544               /* then move the block down one count */
545               pBlock = ebbs[j = i];
546               for (i += 1; i < (*count); i++)
547                 {
548                   eBBlock *xBlock;
549
550                   xBlock = ebbs[i];
551                   ebbs[i] = pBlock;
552                   ebbs[i]->bbnum = i;
553                   pBlock = xBlock;
554                 }
555
556               destBlock->preHeader = ebbs[j] = neweBBlock ();
557               ebbs[j]->bbnum = j;
558               ebbs[j]->entryLabel = preHeaderLabel;
559               ebbs[j]->sch = ebbs[j]->ech = newiCodeLabelGoto (LABEL, preHeaderLabel);
560               ebbs[j]->sch->lineno = destBlock->sch->lineno;
561             }
562         }
563     }
564
565   /* mark the end */
566   ebbs[*count] = NULL;
567
568   return ebbs;
569 }
570
571 /*-----------------------------------------------------------------*/
572 /* replaceSymBySym : - replace operand by operand in blocks        */
573 /*                     replaces only left & right in blocks        */
574 /*-----------------------------------------------------------------*/
575 void 
576 replaceSymBySym (set * sset, operand * src, operand * dest)
577 {
578   set *loop;
579   eBBlock *rBlock;
580
581   /* for all blocks in the set do */
582   for (loop = sset; loop; loop = loop->next)
583     {
584       iCode *ic;
585
586       rBlock = loop->item;
587       /* for all instructions in this block do */
588       for (ic = rBlock->sch; ic; ic = ic->next)
589         {
590
591           /* if we find usage */
592           if (ic->op == IFX && isOperandEqual (src, IC_COND (ic)))
593             {
594               bitVectUnSetBit (OP_USES (IC_COND (ic)), ic->key);
595               IC_COND (ic) = operandFromOperand (dest);
596               OP_USES(dest)=bitVectSetBit (OP_USES (dest), ic->key);
597               continue;
598             }
599
600           if (isOperandEqual (IC_RIGHT (ic), src))
601             {
602               bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key);
603               IC_RIGHT (ic) = operandFromOperand (dest);
604               IC_RIGHT (ic)->isaddr = 0;
605               OP_USES(dest)=bitVectSetBit (OP_USES (dest), ic->key);
606             }
607
608           if (isOperandEqual (IC_LEFT (ic), src))
609             {
610               bitVectUnSetBit (OP_USES (IC_LEFT (ic)), ic->key);
611               if (POINTER_GET (ic) && IS_ITEMP (dest))
612                 {
613                   IC_LEFT (ic) = operandFromOperand (dest);
614                   IC_LEFT (ic)->isaddr = 1;
615                 }
616               else
617                 {
618                   IC_LEFT (ic) = operandFromOperand (dest);
619                   IC_LEFT (ic)->isaddr = 0;
620                 }
621               OP_USES(dest)=bitVectSetBit (OP_USES (dest), ic->key);
622             }
623
624           /* special case for pointer sets */
625           if (POINTER_SET (ic) &&
626               isOperandEqual (IC_RESULT (ic), src))
627             {
628               bitVectUnSetBit (OP_USES (IC_RESULT (ic)), ic->key);
629               IC_RESULT (ic) = operandFromOperand (dest);
630               IC_RESULT (ic)->isaddr = 1;
631               OP_USES(dest)=bitVectSetBit (OP_USES (dest), ic->key);
632             }
633         }
634     }
635 }
636
637 /*-----------------------------------------------------------------*/
638 /* replaceLabel - replace reference to one label by another        */
639 /*-----------------------------------------------------------------*/
640 void 
641 replaceLabel (eBBlock * ebp, symbol * fromLbl, symbol * toLbl)
642 {
643   iCode *ic;
644
645   if (!ebp)
646     return;
647
648   for (ic = ebp->sch; ic; ic = ic->next)
649     {
650       switch (ic->op)
651         {
652
653         case GOTO:
654           if (isSymbolEqual (IC_LABEL (ic), fromLbl))
655             IC_LABEL (ic) = toLbl;
656           break;
657
658         case IFX:
659           if (IC_TRUE (ic) && isSymbolEqual (IC_TRUE (ic), fromLbl))
660             IC_TRUE (ic) = toLbl;
661           else if (isSymbolEqual (IC_FALSE (ic), fromLbl))
662             IC_FALSE (ic) = toLbl;
663           break;
664         }
665     }
666
667   return;
668
669 }
670
671
672 /*-----------------------------------------------------------------*/
673 /* iCodeFromeBBlock - convert basic block to iCode chain           */
674 /*-----------------------------------------------------------------*/
675 iCode *
676 iCodeFromeBBlock (eBBlock ** ebbs, int count)
677 {
678   int i = 1;
679   iCode *ric = ebbs[0]->sch;
680   iCode *lic = ebbs[0]->ech;
681
682   for (; i < count; i++)
683     {
684       if (ebbs[i]->sch == NULL)
685         continue;
686
687       if (ebbs[i]->noPath &&
688           (ebbs[i]->entryLabel != entryLabel &&
689            ebbs[i]->entryLabel != returnLabel))
690         {
691           werror (W_CODE_UNREACH, ebbs[i]->sch->filename, ebbs[i]->sch->lineno);
692           continue;
693         }
694
695       lic->next = ebbs[i]->sch;
696       lic->next->prev = lic;
697       lic = ebbs[i]->ech;
698     }
699
700   return ric;
701 }
702
703 /*-----------------------------------------------------------------*/
704 /* otherPathsPresent - determines if there is a path from _entry   */
705 /*      to this block in a half constructed set of blocks          */
706 /*-----------------------------------------------------------------*/
707 int 
708 otherPathsPresent (eBBlock ** ebbs, eBBlock * this)
709 {
710   int i;
711
712   /* for all blocks preceding this block */
713   for (i = 0; i < this->bbnum; i++)
714     {
715       iCode *ic;
716
717       /* if there is a reference to the entry label of this block */
718       for (ic = ebbs[i]->sch; ic; ic = ic->next)
719         {
720           switch (ic->op)
721             {
722             case GOTO:
723               if (IC_LABEL (ic)->key == this->entryLabel->key)
724                 return 1;
725               break;
726
727             case IFX:
728               if (IC_TRUE (ic))
729                 {
730                   if (IC_TRUE (ic)->key == this->entryLabel->key)
731                     return 1;
732                 }
733               else if (IC_FALSE (ic)->key == this->entryLabel->key)
734                 return 1;
735               break;
736             }
737         }
738     }
739
740   /* comes here means we have not found it yet */
741   /* in this case check if the previous block  */
742   /* ends in a goto if it does then we have no */
743   /* path else we have a path                  */
744   if (this->bbnum && ebbs[this->bbnum - 1]->ech &&
745       ebbs[this->bbnum - 1]->ech->op == GOTO)
746     return 0;
747   else
748     return 1;
749 }