1 /*-------------------------------------------------------------------------
2 
3    pcoderegs.c - post code generation register optimizations
4 
5    Written By -  Scott Dattalo scott@dattalo.com
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 -------------------------------------------------------------------------*/
22 
23 /*
24 pcoderegs.c
25 
26   The purpose of the code in this file is to optimize the register usage.
27 
28 */
29 
30 #include "main.h"
31 #include "pcoderegs.h"
32 #include "pcodeflow.h"
33 #include "ralloc.h"
34 
35 
36 static int total_registers_saved=0;
37 static int register_optimization=1;
38 
39 /*-----------------------------------------------------------------*
40 * void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
41 *-----------------------------------------------------------------*/
pCodeRegMapLiveRangesInFlow(pCodeFlow * pcfl)42 static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
43 {
44 
45 	pCode *pc=NULL;
46 
47 	reg_info *reg;
48 
49 	if(!pcfl)
50 		return;
51 
52 
53 	pc = findNextInstruction(pcfl->pc.next);
54 
55 	while(pc && !isPCFL(pc)) {
56 		while (pc && !isPCI(pc) && !isPCFL(pc))
57 		{
58 			pc = pc->next;
59 		} // while
60 		if (!pc || isPCFL(pc)) continue;
61 		assert( isPCI(pc) );
62 
63 		reg = getRegFromInstruction(pc);
64 		#if 0
65 		pc->print(stderr, pc);
66 		fprintf( stderr, "--> reg %p (%s,%u), inCond/outCond: %x/%x\n",
67 			reg, reg ? reg->name : "(null)", reg ? reg->rIdx : -1,
68 			PCI(pc)->inCond, PCI(pc)->outCond );
69 		#endif
70 		if(reg) {
71 		/*
72 		fprintf(stderr, "flow seq %d, inst seq %d  %s  ",PCODE(pcfl)->seq,pc->seq,reg->name);
73 		fprintf(stderr, "addr = 0x%03x, type = %d  rIdx=0x%03x\n",
74 		reg->address,reg->type,reg->rIdx);
75 			*/
76 
77 			addSetIfnotP(& (PCFL(pcfl)->registers), reg);
78 
79 			if(PCC_REGISTER & PCI(pc)->inCond)
80 				addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
81 
82 			if(PCC_REGISTER & PCI(pc)->outCond)
83 				addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
84 
85 			addSetIfnotP(& (reg->reglives.usedpCodes), pc);
86 			reg->wasUsed = TRUE;
87 		}
88 
89 
90 		//pc = findNextInstruction(pc->next);
91 		pc = pc->next;
92 
93 	}
94 
95 }
96 
97 /*-----------------------------------------------------------------*
98 * void pCodeRegMapLiveRanges(pBlock *pb)
99 *-----------------------------------------------------------------*/
pCodeRegMapLiveRanges(pBlock * pb)100 void pCodeRegMapLiveRanges(pBlock *pb)
101 {
102 	pCode *pcflow;
103 
104 	for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
105 	pcflow != NULL;
106 	pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
107 
108 		if(!isPCFL(pcflow)) {
109 			fprintf(stderr, "pCodeRegMapLiveRanges - pcflow is not a flow object ");
110 			continue;
111 		}
112 		pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
113 	}
114 
115 #if 0
116 	for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
117 	pcflow != NULL;
118 	pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
119 
120 		regs *r = setFirstItem(PCFL(pcflow)->registers);
121 		fprintf(stderr,"flow seq %d\n", pcflow->seq);
122 
123 		while (r) {
124 			fprintf(stderr, "  %s\n",r->name);
125 			r = setNextItem(PCFL(pcflow)->registers);
126 
127 		}
128 
129 	}
130 #endif
131 
132 }
133 
134 
135 /*-----------------------------------------------------------------*
136 *
137 *-----------------------------------------------------------------*/
Remove1pcode(pCode * pc,reg_info * reg,int debug_code)138 static void Remove1pcode(pCode *pc, reg_info *reg, int debug_code)
139 {
140 
141 	pCode *pcn=NULL;
142 
143 	if(!reg || !pc)
144 		return;
145 
146 	deleteSetItem (&(reg->reglives.usedpCodes),pc);
147 
148 	if(PCI(pc)->label) {
149 		pcn = findNextInstruction(pc->next);
150 
151 		if(pcn)
152 			PCI(pcn)->label = pBranchAppend(PCI(pcn)->label,PCI(pc)->label);
153 	}
154 
155 	if(PCI(pc)->cline) {
156 		if(!pcn)
157 			pcn = findNextInstruction(pc->next);
158 
159 		if(pcn) {
160 			if(PCI(pcn)->cline) {
161 				//fprintf(stderr, "source line has been optimized completely out\n");
162 				//pc->print(stderr,pc);
163 			} else {
164 				PCI(pcn)->cline = PCI(pc)->cline;
165 			}
166 		}
167 	}
168 
169 
170 	if(1) {
171                 /*
172                  * Debug stuff. Comment out the instruction we're about to delete.
173                  */
174 
175 		char buff1[256];
176 		size_t size = 256;
177 
178 		char *pbuff;
179 		pbuff = &buff1[0];
180 
181 		SNPRINTF(pbuff, size, ";%d", debug_code);
182 		size -= strlen(pbuff);
183 		pbuff += strlen(pbuff);
184 		pCode2str(pbuff, size, pc);
185 		pCodeInsertBefore(pc, newpCodeCharP(buff1));
186 		//fprintf(stderr,"removing instruction:\n%s\n",buff1);
187 	}
188 
189 	pc->destruct(pc);
190 
191 }
192 
193 /*-----------------------------------------------------------------*
194 * void RemoveRegsFromSet(set *regset)
195 *
196 *-----------------------------------------------------------------*/
RemoveRegsFromSet(set * regset)197 static void RemoveRegsFromSet(set *regset)
198 {
199 	reg_info *reg;
200 	int used;
201 
202 	while(regset) {
203 		reg = regset->item;
204 		regset = regset->next;
205 
206 		used = elementsInSet(reg->reglives.usedpCodes);
207 
208 		if(used <= 1) {
209 
210 			//fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
211 			if(used == 0) {
212 				//fprintf(stderr," getting rid of reg %s\n",reg->name);
213 				reg->isFree = TRUE;
214 				reg->wasUsed = FALSE;
215 			} else {
216 				pCode *pc;
217 
218 
219 				pc = setFirstItem(reg->reglives.usedpCodes);
220 
221 				if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern) {
222 					//fprintf(stderr, "not removing SFR reg %s even though used only once\n",reg->name);
223 					continue;
224 				}
225 
226 
227 				if(isPCI(pc)) {
228 					if(PCI(pc)->label) {
229 						pCode *pcn = findNextInstruction(pc->next);
230 
231 						if(pcn && PCI(pcn)->label) {
232 							//fprintf(stderr,"can't delete instruction with label...\n");
233 							//pc->print(stderr,pc);
234 							continue;
235 						}
236 						/* Move the label to the next instruction */
237 
238 						PCI(pcn)->label = PCI(pc)->label;
239 
240 					}
241 
242 					if(isPCI_SKIP(pc)) {
243 						reg_info *r = getRegFromInstruction(pc);
244 						fprintf(stderr, "WARNING, a skip instruction is being optimized out\n");
245 						pc->print(stderr,pc);
246 						fprintf(stderr,"reg %s, type =%d\n",r->name, r->type);
247 					}
248 					//fprintf(stderr," removing reg %s because it is used only once\n",reg->name);
249 					Remove1pcode(pc, reg, 1);
250 					/*
251 					unlinkpCode(pc);
252 					deleteSetItem (&(reg->reglives.usedpCodes),pc);
253 					*/
254 					reg->isFree = TRUE;
255 					reg->wasUsed = FALSE;
256 					total_registers_saved++;  // debugging stats.
257 				}
258 			}
259 		}
260 
261 	}
262 }
263 
pic14_ReMapLiveRanges(void)264 static void pic14_ReMapLiveRanges(void)
265 {
266 	pBlock *pb;
267 	if (!the_pFile) return;
268 	RegsUnMapLiveRanges();
269 	for (pb = the_pFile->pbHead; pb; pb = pb->next)
270 	{
271 	#if 0
272 		pCode *pc = findNextpCode(pb->pcHead, PC_FLOW);
273 		if (pc) {
274 			pc->print( stderr, pc );
275 		} else {
276 			fprintf( stderr, "unnamed pBlock\n");
277 		}
278 		pc = findNextInstruction(pb->pcHead);
279 		while (pc) {
280 		  pc->print( stderr, pc );
281 		  pc = findNextInstruction(pc->next);;
282 		}
283 	#endif
284 		pCodeRegMapLiveRanges(pb);
285 	} // for
286 }
287 
288 /*-----------------------------------------------------------------*
289 * void RemoveUnusedRegisters(void)
290 *
291 *-----------------------------------------------------------------*/
RemoveUnusedRegisters(void)292 void RemoveUnusedRegisters(void)
293 {
294 	/* First, get rid of registers that are used only one time */
295 	pic14_ReMapLiveRanges();
296 
297 	//RemoveRegsFromSet(dynInternalRegs);
298 	RemoveRegsFromSet(dynAllocRegs);
299 	RemoveRegsFromSet(dynStackRegs);
300 	/*
301 	don't do DirectRegs yet - there's a problem with arrays
302 	RemoveRegsFromSet(dynDirectRegs);
303 	*/
304 	RemoveRegsFromSet(dynDirectBitRegs);
305 
306 	if(total_registers_saved) DFPRINTF((stderr, " *** Saved %d registers ***\n", total_registers_saved));
307 }
308 
309 
310 /*-----------------------------------------------------------------*
311 *
312 *-----------------------------------------------------------------*/
Remove2pcodes(pCode * pcflow,pCode * pc1,pCode * pc2,reg_info * reg,int can_free)313 static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, reg_info *reg, int can_free)
314 {
315 	static int debug_code=99;
316 	if(!reg)
317 		return;
318 #if 0
319 	fprintf (stderr, "%s:%d(%s): %d (reg:%s)\n", __FILE__, __LINE__, __FUNCTION__, debug_code, reg ? reg->name : "???");
320 	printpCode (stderr, pc1);
321 	printpCode (stderr, pc2);
322 #endif
323 
324 	//fprintf(stderr,"%s\n",__FUNCTION__);
325 	if(pc1)
326 		Remove1pcode(pc1, reg, debug_code++);
327 
328 	if(pc2) {
329 		Remove1pcode(pc2, reg, debug_code++);
330 		deleteSetItem (&(PCFL(pcflow)->registers), reg);
331 
332 		if(can_free) {
333 			reg->isFree = TRUE;
334 			reg->wasUsed = FALSE;
335 		}
336 
337 	}
338 
339 	pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
340 }
341 
342 /*-----------------------------------------------------------------*
343 *
344 *-----------------------------------------------------------------*/
regUsedinRange(pCode * pc1,pCode * pc2,reg_info * reg)345 static int regUsedinRange(pCode *pc1, pCode *pc2, reg_info *reg)
346 {
347 	int i=0;
348 	reg_info *testreg;
349 
350 	do {
351 		testreg = getRegFromInstruction(pc1);
352 		if(testreg && (testreg->rIdx == reg->rIdx)) {
353 			return 1;
354 		}
355 		if (i++ > 1000) {
356 			fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n");
357 			return 0;
358 		}
359 
360 		pc1 = findNextInstruction(pc1->next);
361 
362 	} while (pc1 && (pc1 != pc2)) ;
363 
364 	return 0;
365 }
366 
regIsSpecial(reg_info * reg,int mayBeGlobal)367 static int regIsSpecial (reg_info *reg, int mayBeGlobal)
368 {
369   if (!reg) return 0;
370 
371   if (reg->type == REG_SFR || reg->type == REG_STK || (!mayBeGlobal && (reg->isPublic || reg->isExtern))) return 1;
372 
373   return 0;
374 }
375 
376 /*-----------------------------------------------------------------*
377 * void pCodeOptime2pCodes(pCode *pc1, pCode *pc2)
378 *
379 * ADHOC pattern checking
380 * Now look for specific sequences that are easy to optimize.
381 * Many of these sequences are characteristic of the compiler
382 * (i.e. it'd probably be a waste of time to apply these adhoc
383 * checks to hand written assembly.)
384 *
385 *
386 *-----------------------------------------------------------------*/
pCodeOptime2pCodes(pCode * pc1,pCode * pc2,pCode * pcfl_used,reg_info * reg,int can_free,int optimize_level)387 static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, reg_info *reg, int can_free, int optimize_level)
388 {
389 	pCode *pct1, *pct2;
390 	reg_info  *reg1, *reg2;
391 
392 	int t = total_registers_saved;
393 
394 	if (!isPCI(pc1) || !isPCI(pc2)) return 0;
395 	if (PCI(pc1)->pcflow != PCI(pc2)->pcflow) return 0;
396 
397 	if (pc2->seq < pc1->seq) {
398 		pct1 = pc2;
399 		pc2 = pc1;
400 		pc1 = pct1;
401 	}
402 
403 	/* disable this optimization for now -- it's buggy */
404 	if (pic14_options.disable_df) return 0;
405 
406 	//fprintf(stderr,"pCodeOptime2pCodes\n");
407 	//pc1->print(stderr,pc1);
408 	//pc2->print(stderr,pc2);
409 
410 	if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){
411 	    /*
412 	     * CLRF sets Z
413 	     * MOVFW affects Z
414 	     * MOVWF does not touch Z
415 	     * MOVLW does not touch Z
416 	     */
417 		pCode *newpc;
418 		/*
419 		clrf  reg    ; pc1
420 		stuff...
421 		movf  reg,w  ; pc2
422 
423 		  can be replaced with (only if following instructions are not going to use W and reg is not used again later)
424 
425 			stuff...
426 			movlw 0 or clrf  reg
427 		*/
428 		DFPRINTF((stderr, "   optimising CLRF reg ... MOVF reg,W to ... MOVLW 0\n"));
429 		pct2 = findNextInstruction(pc2->next);
430 		if (pCodeSearchCondition(pct2, PCC_Z, 0) == -1) {
431 			/* Z is definitely overwritten before use */
432 			newpc = newpCode(POC_MOVLW, newpCodeOpLit(0));
433 
434 			pCodeInsertAfter(pc2, newpc);
435 			PCI(newpc)->pcflow = PCFL(pcfl_used);
436 			newpc->seq = pc2->seq;
437 
438 			//fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF reg, ..., MOVF reg,W)\n", __FILE__, __LINE__, __FUNCTION__);
439 			//Remove2pcodes(pcfl_used, pc2, NULL, reg, 0);
440 			pc2->destruct(pc2);
441 			//total_registers_saved++;  // debugging stats.
442 		}
443 	} else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
444 		DFPRINTF((stderr, "   optimising CLRF/IORFW\n"));
445 
446 		pct2 = findNextInstruction(pc2->next);
447 
448 		/* We must ensure that Z is destroyed before being read---IORLW must be performed unless this is proven. */
449 		if (pCodeSearchCondition(pct2, PCC_Z, 0) != -1) {
450 			pct2 = newpCode(POC_IORLW, newpCodeOpLit(0));
451 			pct2->seq = pc2->seq;
452 			PCI(pct2)->pcflow = PCFL(pcfl_used);
453 			pCodeInsertAfter(pc1,pct2);
454 		}
455 		//fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF/IORFW)\n", __FILE__, __LINE__, __FUNCTION__);
456 		Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
457 		total_registers_saved++;  // debugging stats.
458 
459 	}  else if(PCI(pc1)->op == POC_MOVWF) {
460 		// Optimising MOVWF reg ...
461 
462 		pct2 = findNextInstruction(pc2->next);
463 
464 		if(PCI(pc2)->op == POC_MOVFW) {
465 			// Optimising MOVWF reg ... MOVF reg,W
466 
467 			if(PCI(pct2)->op == POC_MOVWF) {
468 			/*
469 			Change:
470 
471 			  movwf   reg    ; pc1
472 			  stuff...
473 			  movf    reg,w  ; pc2
474 			  movwf   reg2   ; pct2
475 
476 				To: ( as long as 'stuff' does not use reg2 or if following instructions do not use W or reg is not used later)
477 
478 				  movwf   reg2
479 				  stuff...
480 
481 				*/
482 				reg2 = getRegFromInstruction(pct2);
483 				/* Check reg2 is not used for something else before it is loaded with reg */
484 				if (reg2 && !regIsSpecial (reg2, 1) && !regUsedinRange(pc1,pc2,reg2)) {
485 					pCode *pct3 = findNextInstruction(pct2->next);
486 					/* Check following instructions are not relying on the use of W or the Z flag condiction */
487 					/* XXX: We must ensure that this value is destroyed before use---otherwise it might be used in
488 					 *      subsequent flows (checking for < 1 is insufficient). */
489 					if ((pCodeSearchCondition(pct3,PCC_Z,0) == -1) && (pCodeSearchCondition(pct3,PCC_W,0) == -1)) {
490 						DFPRINTF((stderr, "   optimising MOVF reg ... MOVF reg,W MOVWF reg2 to MOVWF reg2 ...\n"));
491 						pct2->seq = pc1->seq;
492 						unlinkpCode(pct2);
493 						pCodeInsertBefore(pc1,pct2);
494 						if(regUsedinRange(pct2,0,reg))
495 						{
496 							//fprintf (stderr, "%s:%d(%s): Remove2pcodes IF (MOVWF reg, ..., MOVW reg,W  MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
497 							Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
498 						} else {
499 							//fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVWF reg, ..., MOVW reg,W  MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
500 							Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
501 						}
502 						total_registers_saved++;  // debugging stats.
503 						return 1;
504 					}
505 				}
506 			}
507 		}
508 
509 		pct1 = findPrevInstruction(pc1->prev);
510 		if(pct1 && (PCI(pct1)->pcflow == PCI(pc1)->pcflow)) {
511 
512 			if ( (PCI(pct1)->op == POC_MOVFW) &&
513 				(PCI(pc2)->op == POC_MOVFW)) {
514 
515 				reg1 = getRegFromInstruction(pct1);
516 				if(reg1 && !regIsSpecial (reg1, 0) && !regUsedinRange(pc1,pc2,reg1)) {
517 					DFPRINTF((stderr, "   optimising MOVF reg1,W MOVWF reg ... MOVF reg,W\n"));
518 					/*
519 					Change:
520 
521 						movf   reg1,w
522 						movwf  reg
523 
524 						stuff...
525 						movf   reg,w
526 
527 					To:
528 
529 						stuff...
530 
531 						movf   reg1,w
532 
533 					Or, if we're not deleting the register then the "To" is:
534 
535 						stuff...
536 
537 						movf   reg1,w
538 						movwf  reg
539 					*/
540 					pct2 = newpCode(PCI(pc2)->op, PCI(pct1)->pcop);
541 					pCodeInsertAfter(pc2, pct2);
542 					PCI(pct2)->pcflow = PCFL(pcfl_used);
543 					pct2->seq = pc2->seq;
544 
545 					if(can_free) {
546 						//fprintf (stderr, "%s:%d(%s): Remove2pcodes CANFREE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
547 						Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
548 					} else {
549 					/* If we're not freeing the register then that means (probably)
550 						* the register is needed somewhere else.*/
551 						unlinkpCode(pc1);
552 						pCodeInsertAfter(pct2, pc1);
553 
554 						//fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
555 						Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
556 					}
557 
558 					//fprintf (stderr, "%s:%d(%s): Remove2pcodes ALWAYS (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
559 					Remove2pcodes(pcfl_used, pct1, NULL, reg1, 0);
560 					total_registers_saved++;  // debugging stats.
561 
562 				}
563 			}
564 		}
565   }
566 
567   return (total_registers_saved != t);
568 }
569 
570 /*-----------------------------------------------------------------*
571 * void pCodeRegOptimeRegUsage(pBlock *pb)
572 *-----------------------------------------------------------------*/
OptimizeRegUsage(set * fregs,int optimize_multi_uses,int optimize_level)573 static void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_level)
574 {
575 	reg_info *reg;
576 	int used;
577 	pCode *pc1=NULL, *pc2=NULL;
578 
579 
580 	while(fregs) {
581 		pCode *pcfl_used, *pcfl_assigned;
582 
583 		/* Step through the set by directly accessing the 'next' pointer.
584 		* We could also step through by using the set API, but the
585 		* the (debug) calls to print instructions affect the state
586 		* of the set pointers */
587 
588 		reg = fregs->item;
589 		fregs = fregs->next;
590 		/*
591 		if (strcmp(reg->name,"_SubState")==0)
592 		fprintf(stderr,"Reg: %s\n",reg->name);
593 		*/
594 
595 		/* Catch inconsistently set-up live ranges
596 		 * (see tracker items #1469504 + #1474602)
597 		 * FIXME: Actually we should rather fix the
598 		 * computation of the liveranges instead...
599 		 */
600 		if (!reg || !reg->reglives.usedpFlows
601 			|| !reg->reglives.assignedpFlows)
602 		{
603 		  //fprintf( stderr, "skipping reg w/o liveranges: %s\n", reg ? reg->name : "(unknown)");
604 		  continue;
605 		}
606 
607 		if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern|| reg->isFixed) {
608 			//fprintf(stderr,"skipping SFR: %s\n",reg->name);
609 			continue;
610 		}
611 
612 		pcfl_used = setFirstItem(reg->reglives.usedpFlows);
613 		pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
614 
615 		used = elementsInSet(reg->reglives.usedpCodes);
616 		if(used == 2) {
617 			/*
618 			In this section, all registers that are used in only in two
619 			instructions are examined. If possible, they're optimized out.
620 			*/
621 
622 			/*
623 			fprintf (stderr, "OptimizeRegUsage: %s  addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
624 			reg->name,
625 			reg->address,
626 			reg->rIdx, reg->type, used);
627 			*/
628 			pc1 = setFirstItem(reg->reglives.usedpCodes);
629 			pc2 = setNextItem(reg->reglives.usedpCodes);
630 
631 			if(pcfl_used && pcfl_assigned) {
632 				/*
633 				expected case - the register has been assigned a value and is
634 				subsequently used
635 				*/
636 
637 				//fprintf(stderr," used only twice\n");
638 				if(pcfl_used->seq == pcfl_assigned->seq) {
639 
640 					//fprintf(stderr, "  and used in same flow\n");
641 
642 					pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 1,optimize_level);
643 
644 				} else {
645 					// fprintf(stderr, "  and used in different flows\n");
646 
647 				}
648 
649 			} else if(pcfl_used) {
650 
651 				/* register has been used twice without ever being assigned */
652 				fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name);
653 
654 			} else {
655 				//fprintf(stderr,"WARNING %s.1: reg %s assigned without being used\n",__FUNCTION__,reg->name);
656 				Remove2pcodes(pcfl_assigned, pc1, pc2, reg, 1);
657 				total_registers_saved++;  // debugging stats.
658 			}
659 		} else {
660 
661 			/* register has been used either once, or more than twice */
662 
663 			if(used && !pcfl_used && pcfl_assigned) {
664 				pCode *pc;
665 
666 				//fprintf(stderr,"WARNING %s.2: reg %s assigned without being used\n",__FUNCTION__,reg->name);
667 
668 				pc = setFirstItem(reg->reglives.usedpCodes);
669 				while(pc) {
670 
671 					pcfl_assigned = PCODE(PCI(pc)->pcflow);
672 					Remove1pcode(pc, reg,2);
673 
674 					deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg);
675 					/*
676 					deleteSetItem (&(reg->reglives.usedpCodes),pc);
677 					pc->destruct(pc);
678 					*/
679 					pc = setNextItem(reg->reglives.usedpCodes);
680 				}
681 
682 
683 				reg->isFree = TRUE;
684 				reg->wasUsed = FALSE;
685 
686 				total_registers_saved++;  // debugging stats.
687 			} else if( (used > 2) && optimize_multi_uses) {
688 
689 				set *rset1=NULL;
690 				set *rset2=NULL;
691 				int searching=1;
692 
693 				pCodeFlow *pcfl1=NULL, *pcfl2=NULL;
694 
695 				/* examine the number of times this register is used */
696 
697 
698 				rset1 = reg->reglives.usedpCodes;
699 				while(rset1 && searching) {
700 
701 					pc1 = rset1->item;
702 					rset2 = rset1->next;
703 
704 					if(pc1 && isPCI(pc1) &&  ( (pcfl1 = PCI(pc1)->pcflow) != NULL) ) {
705 
706 						if(rset2) {
707 
708 							pc2 = rset2->item;
709 							if(pc2 && isPCI(pc2)  &&  ( (pcfl2 = PCI(pc2)->pcflow) != NULL) )  {
710 								if(pcfl2 == pcfl1) {
711 
712 									if(pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 0,optimize_level))
713 										searching = 0;
714 								}
715 							}
716 
717 							//rset2 = rset2->next;
718 
719 						}
720 					}
721 					rset1 = rset2;
722 				}
723 			}
724 		}
725 	}
726 }
727 
728 /*-----------------------------------------------------------------*
729 * void pCodeRegOptimeRegUsage(pBlock *pb)
730 *-----------------------------------------------------------------*/
pCodeRegOptimizeRegUsage(int level)731 void pCodeRegOptimizeRegUsage(int level)
732 {
733 
734 	int passes;
735 	int saved = 0;
736 	int t = total_registers_saved;
737 
738 #if 0
739 	/* This is currently broken (need rewrite to correctly
740 	 * handle arbitrary pCodeOps instead of registers only). */
741 	if (!pic14_options.disable_df)
742 		optimizeDataflow ();
743 #endif
744 
745 	if(!register_optimization)
746 		return;
747 #define OPT_PASSES 4
748 	passes = OPT_PASSES;
749 
750 	do {
751 		saved = total_registers_saved;
752 
753 		/* Identify registers used in one flow sequence */
754 		OptimizeRegUsage(dynAllocRegs,level, (OPT_PASSES-passes));
755 		OptimizeRegUsage(dynStackRegs,level, (OPT_PASSES-passes));
756 		OptimizeRegUsage(dynDirectRegs,0, (OPT_PASSES-passes));
757 
758 		if(total_registers_saved != saved)
759 			DFPRINTF((stderr, " *** pass %d, Saved %d registers, total saved %d ***\n",
760 			(1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved));
761 
762 		passes--;
763 
764 	} while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
765 
766 	if(total_registers_saved == t)
767 		DFPRINTF((stderr, "No registers saved on this pass\n"));
768 }
769 
770 
771 /*-----------------------------------------------------------------*
772 * void RegsUnMapLiveRanges(set *regset)
773 *
774 *-----------------------------------------------------------------*/
RegsSetUnMapLiveRanges(set * regset)775 static void RegsSetUnMapLiveRanges(set *regset)
776 {
777 	reg_info *reg;
778 
779 	while(regset) {
780 		reg = regset->item;
781 		regset = regset->next;
782 
783 
784 		deleteSet(&reg->reglives.usedpCodes);
785 		deleteSet(&reg->reglives.usedpFlows);
786 		deleteSet(&reg->reglives.assignedpFlows);
787 
788 	}
789 
790 }
791 
RegsUnMapLiveRanges(void)792 void  RegsUnMapLiveRanges(void)
793 {
794 
795 	RegsSetUnMapLiveRanges(dynAllocRegs);
796 	RegsSetUnMapLiveRanges(dynStackRegs);
797 	RegsSetUnMapLiveRanges(dynDirectRegs);
798 	RegsSetUnMapLiveRanges(dynProcessorRegs);
799 	RegsSetUnMapLiveRanges(dynDirectBitRegs);
800 	RegsSetUnMapLiveRanges(dynInternalRegs);
801 
802 }
803