This should fix some, if not all, of the live range problems
[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 %s (df:%d bb:%d lvl:%d): loop Depth = %d noPath = %d lastinLoop = %d\n",
192                ebbs[i]->entryLabel->name,
193                ebbs[i]->dfnum, ebbs[i]->bbnum, ebbs[i]->entryLabel->level,
194                ebbs[i]->depth,
195                ebbs[i]->noPath,
196                ebbs[i]->isLastInLoop);
197
198       // a --nolabelopt makes this more readable
199       fprintf (of, "\nsuccessors: ");
200       for (bb=setFirstItem(ebbs[i]->succList); 
201            bb; 
202            bb=setNextItem(ebbs[i]->succList)) {
203         fprintf (of, "%s ", bb->entryLabel->name);
204       }
205       fprintf (of, "\npredecessors: ");
206       for (bb=setFirstItem(ebbs[i]->predList); 
207            bb; 
208            bb=setNextItem(ebbs[i]->predList)) {
209         fprintf (of, "%s ", bb->entryLabel->name);
210       }
211       {
212         int d;
213         fprintf (of, "\ndominators: ");
214         for (d=0; d<ebbs[i]->domVect->size; d++) {
215           if (bitVectBitValue(ebbs[i]->domVect, d)) {
216             fprintf (of, "%s ", ebbs[d]->entryLabel->name);
217           }
218         }
219       }
220       fprintf (of, "\n");
221   
222       fprintf (of, "\ndefines bitVector :");
223       bitVectDebugOn (ebbs[i]->defSet, of);
224       fprintf (of, "\nlocal defines bitVector :");
225       bitVectDebugOn (ebbs[i]->ldefs, of);
226       fprintf (of, "\npointers Set bitvector :");
227       bitVectDebugOn (ebbs[i]->ptrsSet, of);
228       if (ebbs[i]->isLastInLoop) {
229               fprintf (of, "\nInductions Set bitvector :");
230               bitVectDebugOn (ebbs[i]->linds, of);
231       }
232       fprintf (of, "\n----------------------------------------------------------------\n");
233       printiCChain (ebbs[i]->sch, of);
234     }
235   fflush(of);
236 }
237
238 /*-----------------------------------------------------------------*/
239 /* iCode2eBBlock - converts a sequnce till label to a ebb          */
240 /*-----------------------------------------------------------------*/
241 eBBlock *
242 iCode2eBBlock (iCode * ic)
243 {
244   iCode *loop;
245   eBBlock *ebb = neweBBlock (); /* allocate an entry */
246
247   /* put the first one unconditionally */
248   ebb->sch = ic;
249
250   /* if this is a label then */
251   if (ic->op == LABEL)
252     ebb->entryLabel = ic->label;
253   else
254     {
255       SNPRINTF (buffer, sizeof(buffer), "_eBBlock%d", eBBNum++);
256       ebb->entryLabel = newSymbol (buffer, 1);
257       ebb->entryLabel->key = labelKey++;
258     }
259
260   if (ic &&
261       (ic->op == GOTO ||
262        ic->op == JUMPTABLE ||
263        ic->op == IFX))
264     {
265       ebb->ech = ebb->sch;
266       return ebb;
267     }
268
269   if ((ic->next && ic->next->op == LABEL) ||
270       !ic->next)
271     {
272       ebb->ech = ebb->sch;
273       return ebb;
274     }
275
276   /* loop thru till we find one with a label */
277   for (loop = ic->next; loop; loop = loop->next)
278     {
279
280       /* if this is the last one */
281       if (!loop->next)
282         break;
283       /* if this is a function call */
284       if (loop->op == CALL || loop->op == PCALL)
285         {
286           ebb->hasFcall = 1;
287           if (currFunc)
288             FUNC_HASFCALL(currFunc->type) = 1;
289         }
290
291       /* if the next one is a label */
292       /* if this is a goto or ifx */
293       if (loop->next->op == LABEL ||
294           loop->op == GOTO ||
295           loop->op == JUMPTABLE ||
296           loop->op == IFX)
297         break;
298     }
299
300   /* mark the end of the chain */
301   ebb->ech = loop;
302
303   return ebb;
304 }
305
306 /*-----------------------------------------------------------------*/
307 /* eBBWithEntryLabel - finds the basic block with the entry label  */
308 /*-----------------------------------------------------------------*/
309 eBBlock *
310 eBBWithEntryLabel (eBBlock ** ebbs, symbol * eLabel, int count)
311 {
312   int i;
313
314   for (i = 0; i < count; i++)
315     {
316       if (isSymbolEqual (ebbs[i]->entryLabel, eLabel))
317         return ebbs[i];
318     }
319
320   return NULL;
321 }
322
323
324 /*-----------------------------------------------------------------*/
325 /* ifFromIs - will return 1 if the from block matches this         */
326 /*-----------------------------------------------------------------*/
327 DEFSETFUNC (ifFromIs)
328 {
329   edge *ep = item;
330   V_ARG (eBBlock *, this);
331
332   if (ep->from == this)
333     return 1;
334
335   return 0;
336 }
337
338
339 /*-----------------------------------------------------------------*/
340 /* edgesTo  - returns a set of edges with to == supplied value     */
341 /*-----------------------------------------------------------------*/
342 set *
343 edgesTo (eBBlock * to)
344 {
345   set *result = NULL;
346   edge *loop;
347
348   for (loop = setFirstItem (graphEdges); loop; loop = setNextItem (graphEdges))
349     if (loop->to == to && !loop->from->noPath)
350       addSet (&result, loop->from);
351
352   return result;
353 }
354
355
356 /*-----------------------------------------------------------------*/
357 /* addiCodeToeBBlock - will add an iCode to the end of a block     */
358 /*-----------------------------------------------------------------*/
359 void 
360 addiCodeToeBBlock (eBBlock * ebp, iCode * ic, iCode * ip)
361 {
362   ic->prev = ic->next = NULL;
363   /* if the insert point is given */
364   if (ip)
365     {
366       ic->lineno = ip->lineno;
367       ic->prev = ip->prev;
368       ip->prev = ic;
369       ic->next = ip;
370       if (!ic->prev)
371         ebp->sch = ic;
372       else
373         ic->prev->next = ic;
374       return;
375     }
376
377   /* if the block has no  instructions */
378   if (ebp->ech == NULL)
379     {
380       ebp->sch = ebp->ech = ic;
381       ic->next = NULL;
382       return;
383     }
384
385   /* if the last instruction is a goto */
386   /* we add it just before the goto    */
387   if (ebp->ech->op == GOTO || ebp->ech->op == JUMPTABLE
388       || ebp->ech->op == RETURN)
389     {
390       ic->lineno = ebp->ech->lineno;
391       ic->prev = ebp->ech->prev;
392       ebp->ech->prev = ic;
393       ic->next = ebp->ech;
394       if (!ic->prev)            /* was the last only on in the block */
395         ebp->sch = ic;
396       else
397         ic->prev->next = ic;
398       return;
399     }
400
401   /* if the last one was a ifx statement we check to see */
402   /* if the condition was defined in the previous instruction */
403   /* if this is true then we put it before the condition else */
404   /* we put it before if, this is to reduce register pressure, */
405   /* we don't have to hold  condition too long in a register  */
406   if (ebp->ech->op == IFX)
407     {
408       iCode *ipoint;
409
410 /*  if ( !ebp->ech->prev )  */
411 /*      ipoint = ebp->ech ; */
412 /*  else  */
413 /*      if (!IC_RESULT(ebp->ech->prev)) */
414 /*    ipoint = ebp->ech ; */
415 /*      else */
416 /*    if (IC_COND(ebp->ech)->key == IC_RESULT(ebp->ech->prev)->key) */
417 /*        ipoint = ebp->ech->prev; */
418 /*    else */
419 /*        ipoint = ebp->ech ; */
420       ipoint = ebp->ech;
421       ic->lineno = ipoint->lineno;
422       ic->prev = ipoint->prev;
423       ipoint->prev = ic;
424       ic->next = ipoint;
425       if (!ic->prev)
426         ebp->sch = ic;
427       else
428         ic->prev->next = ic;
429       return;
430     }
431
432   /* will add it to the very end */
433   ip = ebp->ech;
434   ip->next = ic;
435   ic->prev = ip;
436   ic->next = NULL;
437   ebp->ech = ic;
438
439   return;
440 }
441
442 /*-----------------------------------------------------------------*/
443 /* remiCodeFromeBBlock - remove an iCode from BBlock               */
444 /*-----------------------------------------------------------------*/
445 void 
446 remiCodeFromeBBlock (eBBlock * ebb, iCode * ic)
447 {
448   wassert (ic->seq>=ebb->fSeq && ic->seq<=ebb->lSeq);
449   if (ic->prev)
450     ic->prev->next = ic->next;
451   else
452     ebb->sch = ic->next;
453
454   if (ic->next)
455     ic->next->prev = ic->prev;
456   else
457     ebb->ech = ic->prev;
458 }
459
460 /*-----------------------------------------------------------------*/
461 /* iCodeBreakDown : breakDown iCode chain to blocks                */
462 /*-----------------------------------------------------------------*/
463 eBBlock **
464 iCodeBreakDown (iCode * ic, int *count)
465 {
466   eBBlock **ebbs = NULL;
467   iCode *loop = ic;
468
469   *count = 0;
470
471   /* allocate for the first entry */
472
473   ebbs = Safe_alloc (sizeof (eBBlock **));
474
475   while (loop)
476     {
477
478       /* convert 2 block */
479       eBBlock *ebb = iCode2eBBlock (loop);
480       loop = ebb->ech->next;
481
482       ebb->ech->next = NULL;    /* mark the end of this chain */
483       if (loop)
484         loop->prev = NULL;
485       ebb->bbnum = *count;      /* save this block number     */
486       /* put it in the array */
487       ebbs[(*count)++] = ebb;
488
489       /* allocate for the next one. Remember to clear the new */
490       /*  pointer at the end, that was created by realloc. */
491
492       ebbs = Safe_realloc (ebbs, (*count + 1) * sizeof (eBBlock **));
493
494       ebbs[*count] = 0;
495
496       /* if this one ends in a goto or a conditional */
497       /* branch then check if the block it is going  */
498       /* to already exists, if yes then this could   */
499       /* be a loop, add a preheader to the block it  */
500       /* goes to  if it does not already have one    */
501       if (ebbs[(*count) - 1]->ech &&
502           (ebbs[(*count) - 1]->ech->op == GOTO ||
503            ebbs[(*count) - 1]->ech->op == IFX))
504         {
505
506           symbol *label;
507           eBBlock *destBlock;
508
509           if (ebbs[(*count) - 1]->ech->op == GOTO)
510             label = IC_LABEL (ebbs[(*count) - 1]->ech);
511           else if (!(label = IC_TRUE (ebbs[(*count) - 1]->ech)))
512             label = IC_FALSE (ebbs[(*count) - 1]->ech);
513
514           if ((destBlock = eBBWithEntryLabel (ebbs, label, (*count))) &&
515               destBlock->preHeader == NULL &&
516               otherPathsPresent (ebbs, destBlock))
517             {
518
519               symbol *preHeaderLabel = newiTempPreheaderLabel ();
520               int i, j;
521               eBBlock *pBlock;
522
523               /* go thru all block replacing the entryLabel with new label */
524               /* till we reach the block , then we insert a new ebblock    */
525               for (i = 0; i < (*count); i++)
526                 {
527                   if (ebbs[i] == destBlock)
528                     break;
529                   replaceLabel (ebbs[i], label, preHeaderLabel);
530                 }
531
532               (*count)++;
533
534               /* if we have stopped at the block , allocate for an extra one */
535
536               ebbs = Safe_realloc (ebbs, (*count + 1) * sizeof (eBBlock **));
537
538               ebbs[*count] = 0;
539
540               /* then move the block down one count */
541               pBlock = ebbs[j = i];
542               for (i += 1; i < (*count); i++)
543                 {
544                   eBBlock *xBlock;
545
546                   xBlock = ebbs[i];
547                   ebbs[i] = pBlock;
548                   ebbs[i]->bbnum = i;
549                   pBlock = xBlock;
550                 }
551
552               destBlock->preHeader = ebbs[j] = neweBBlock ();
553               ebbs[j]->bbnum = j;
554               ebbs[j]->entryLabel = preHeaderLabel;
555               ebbs[j]->sch = ebbs[j]->ech = newiCodeLabelGoto (LABEL, preHeaderLabel);
556               ebbs[j]->sch->lineno = destBlock->sch->lineno;
557             }
558         }
559     }
560
561   /* mark the end */
562   ebbs[*count] = NULL;
563
564   return ebbs;
565 }
566
567 /*-----------------------------------------------------------------*/
568 /* replaceSymBySym : - replace operand by operand in blocks        */
569 /*                     replaces only left & right in blocks        */
570 /*-----------------------------------------------------------------*/
571 void 
572 replaceSymBySym (set * sset, operand * src, operand * dest)
573 {
574   set *loop;
575   eBBlock *rBlock;
576
577   /* for all blocks in the set do */
578   for (loop = sset; loop; loop = loop->next)
579     {
580       iCode *ic;
581
582       rBlock = loop->item;
583       /* for all instructions in this block do */
584       for (ic = rBlock->sch; ic; ic = ic->next)
585         {
586
587           /* if we find usage */
588           if (ic->op == IFX && isOperandEqual (src, IC_COND (ic)))
589             {
590               bitVectUnSetBit (OP_USES (IC_COND (ic)), ic->key);
591               IC_COND (ic) = operandFromOperand (dest);
592               OP_USES(dest)=bitVectSetBit (OP_USES (dest), ic->key);
593               continue;
594             }
595
596           if (isOperandEqual (IC_RIGHT (ic), src))
597             {
598               bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key);
599               IC_RIGHT (ic) = operandFromOperand (dest);
600               IC_RIGHT (ic)->isaddr = 0;
601               OP_USES(dest)=bitVectSetBit (OP_USES (dest), ic->key);
602             }
603
604           if (isOperandEqual (IC_LEFT (ic), src))
605             {
606               bitVectUnSetBit (OP_USES (IC_LEFT (ic)), ic->key);
607               if (POINTER_GET (ic) && IS_ITEMP (dest))
608                 {
609                   IC_LEFT (ic) = operandFromOperand (dest);
610                   IC_LEFT (ic)->isaddr = 1;
611                 }
612               else
613                 {
614                   IC_LEFT (ic) = operandFromOperand (dest);
615                   IC_LEFT (ic)->isaddr = 0;
616                 }
617               OP_USES(dest)=bitVectSetBit (OP_USES (dest), ic->key);
618             }
619
620           /* special case for pointer sets */
621           if (POINTER_SET (ic) &&
622               isOperandEqual (IC_RESULT (ic), src))
623             {
624               bitVectUnSetBit (OP_USES (IC_RESULT (ic)), ic->key);
625               IC_RESULT (ic) = operandFromOperand (dest);
626               IC_RESULT (ic)->isaddr = 1;
627               OP_USES(dest)=bitVectSetBit (OP_USES (dest), ic->key);
628             }
629         }
630     }
631 }
632
633 /*-----------------------------------------------------------------*/
634 /* replaceLabel - replace reference to one label by another        */
635 /*-----------------------------------------------------------------*/
636 void 
637 replaceLabel (eBBlock * ebp, symbol * fromLbl, symbol * toLbl)
638 {
639   iCode *ic;
640
641   if (!ebp)
642     return;
643
644   for (ic = ebp->sch; ic; ic = ic->next)
645     {
646       switch (ic->op)
647         {
648
649         case GOTO:
650           if (isSymbolEqual (IC_LABEL (ic), fromLbl))
651             IC_LABEL (ic) = toLbl;
652           break;
653
654         case IFX:
655           if (IC_TRUE (ic) && isSymbolEqual (IC_TRUE (ic), fromLbl))
656             IC_TRUE (ic) = toLbl;
657           else if (isSymbolEqual (IC_FALSE (ic), fromLbl))
658             IC_FALSE (ic) = toLbl;
659           break;
660         }
661     }
662
663   return;
664
665 }
666
667
668 /*-----------------------------------------------------------------*/
669 /* iCodeFromeBBlock - convert basic block to iCode chain           */
670 /*-----------------------------------------------------------------*/
671 iCode *
672 iCodeFromeBBlock (eBBlock ** ebbs, int count)
673 {
674   int i = 1;
675   iCode *ric = ebbs[0]->sch;
676   iCode *lic = ebbs[0]->ech;
677
678   for (; i < count; i++)
679     {
680       if (ebbs[i]->sch == NULL)
681         continue;
682
683       if (ebbs[i]->noPath &&
684           (ebbs[i]->entryLabel != entryLabel &&
685            ebbs[i]->entryLabel != returnLabel))
686         {
687           werror (W_CODE_UNREACH, ebbs[i]->sch->filename, ebbs[i]->sch->lineno);
688           continue;
689         }
690
691       lic->next = ebbs[i]->sch;
692       lic->next->prev = lic;
693       lic = ebbs[i]->ech;
694     }
695
696   return ric;
697 }
698
699 /*-----------------------------------------------------------------*/
700 /* otherPathsPresent - determines if there is a path from _entry   */
701 /*      to this block in a half constructed set of blocks          */
702 /*-----------------------------------------------------------------*/
703 int 
704 otherPathsPresent (eBBlock ** ebbs, eBBlock * this)
705 {
706   int i;
707
708   /* for all blocks preceding this block */
709   for (i = 0; i < this->bbnum; i++)
710     {
711       iCode *ic;
712
713       /* if there is a reference to the entry label of this block */
714       for (ic = ebbs[i]->sch; ic; ic = ic->next)
715         {
716           switch (ic->op)
717             {
718             case GOTO:
719               if (IC_LABEL (ic)->key == this->entryLabel->key)
720                 return 1;
721               break;
722
723             case IFX:
724               if (IC_TRUE (ic))
725                 {
726                   if (IC_TRUE (ic)->key == this->entryLabel->key)
727                     return 1;
728                 }
729               else if (IC_FALSE (ic)->key == this->entryLabel->key)
730                 return 1;
731               break;
732             }
733         }
734     }
735
736   /* comes here means we have not found it yet */
737   /* in this case check if the previous block  */
738   /* ends in a goto if it does then we have no */
739   /* path else we have a path                  */
740   if (this->bbnum && ebbs[this->bbnum - 1]->ech &&
741       ebbs[this->bbnum - 1]->ech->op == GOTO)
742     return 0;
743   else
744     return 1;
745 }