1 /*------------------------------------------------------------------------
3 SDCCralloc.c - source file for register allocation. M6502 specific
5 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
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
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.
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 -------------------------------------------------------------------------*/
24 #include "dbuf_string.h"
26 /* Flags to turn on debugging code.
34 #define D(_a, _s) if (_a) { printf _s; fflush(stdout); }
39 /** Local static variables */
51 reg_info regsm6502
[] =
53 {REG_GPR
, A_IDX
, "a", M6502MASK_A
, NULL
, 0, 1},
54 {REG_GPR
, X_IDX
, "x", M6502MASK_X
, NULL
, 0, 1},
55 {REG_GPR
, Y_IDX
, "y", M6502MASK_Y
, NULL
, 0, 1},
56 {REG_CND
, CND_IDX
, "C", 0, NULL
, 0, 1},
57 {REG_GPR
, XA_IDX
, "xa", M6502MASK_XA
, NULL
, 0, 1},
58 // {REG_GPR, YA_IDX, "ya", M6502MASK_YA, NULL, 0, 1},
59 {REG_GPR
, YX_IDX
, "yx", M6502MASK_YX
, NULL
, 0, 1},
60 {0, SP_IDX
, "sp", 0, NULL
, 0, 1},
63 /* Shared with gen.c */
64 int m6502_ptrRegReq
; /* one byte pointer register required */
66 int m6502_nRegs
= sizeof(regsm6502
)/sizeof(reg_info
);
68 reg_info
*m6502_reg_a
;
69 reg_info
*m6502_reg_x
;
70 reg_info
*m6502_reg_y
;
71 reg_info
*m6502_reg_xa
;
72 //reg_info *m6502_reg_ya;
73 reg_info
*m6502_reg_yx
;
74 reg_info
*m6502_reg_sp
;
76 static void m6502SpillThis (symbol
*);
77 static void updateRegUsage (iCode
* ic
);
78 extern void genm6502Code (iCode
*);
81 /*-----------------------------------------------------------------*/
82 /* m6502_regWithIdx - returns pointer to register with index number */
83 /*-----------------------------------------------------------------*/
85 m6502_regWithIdx (int idx
)
89 for (i
= 0; i
< m6502_nRegs
; i
++)
90 if (regsm6502
[i
].rIdx
== idx
)
93 printf("error: regWithIdx %d not found\n",idx
);
97 /*-----------------------------------------------------------------*/
98 /* m6502_freeReg - frees a register */
99 /*-----------------------------------------------------------------*/
101 m6502_freeReg (reg_info
* reg
)
105 werror (E_INTERNAL_ERROR
, __FILE__
, __LINE__
,
106 "m6502_freeReg - Freeing NULL register");
115 if (m6502_reg_x
->isFree
)
116 m6502_reg_xa
->isFree
= 1;
119 if (m6502_reg_a
->isFree
)
120 m6502_reg_xa
->isFree
= 1;
121 if (m6502_reg_y
->isFree
)
122 m6502_reg_yx
->isFree
= 1;
125 if (m6502_reg_x
->isFree
)
126 m6502_reg_yx
->isFree
= 1;
129 m6502_reg_x
->isFree
= 1;
130 m6502_reg_a
->isFree
= 1;
131 if (m6502_reg_y
->isFree
)
132 m6502_reg_yx
->isFree
= 1;
135 // m6502_reg_y->isFree = 1;
136 // m6502_reg_a->isFree = 1;
137 // if (m6502_reg_x->isFree)
138 // m6502_reg_yx->isFree = 1;
141 m6502_reg_y
->isFree
= 1;
142 m6502_reg_x
->isFree
= 1;
143 if (m6502_reg_a
->isFree
)
144 m6502_reg_xa
->isFree
= 1;
151 /*-----------------------------------------------------------------*/
152 /* noOverLap - will iterate through the list looking for over lap */
153 /*-----------------------------------------------------------------*/
155 noOverLap (set
* itmpStack
, symbol
* fsym
)
159 for (sym
= setFirstItem (itmpStack
); sym
; sym
= setNextItem (itmpStack
))
161 if (bitVectBitValue(sym
->clashes
,fsym
->key
))
167 /*-----------------------------------------------------------------*/
168 /* isFree - will return 1 if the a free spil location is found */
169 /*-----------------------------------------------------------------*/
174 V_ARG (symbol
**, sloc
);
175 V_ARG (symbol
*, fsym
);
177 /* if already found */
181 /* if it is free && and the itmp assigned to
182 this does not have any overlapping live ranges
183 with the one currently being assigned and
184 the size can be accommodated */
186 && noOverLap (sym
->usl
.itmpStack
, fsym
)
187 && getSize (sym
->type
) >= getSize (fsym
->type
))
196 /*-----------------------------------------------------------------*/
197 /* createStackSpil - create a location somewhere to spill */
198 /*-----------------------------------------------------------------*/
200 createStackSpil (symbol
* sym
)
205 /* first go try and find a free one that is already
206 existing on the stack */
207 if (applyToSet (_G
.stackSpil
, isFree
, &sloc
, sym
))
209 /* found a free one : just update & return */
210 sym
->usl
.spillLoc
= sloc
;
213 addSetHead (&sloc
->usl
.itmpStack
, sym
);
217 /* could not then have to create one , this is the hard part
218 we need to allocate this on the stack : this is really a
219 hack!! but cannot think of anything better at this time */
221 D (D_ALLOC
, ("createStackSpil: for sym %p %s (old currFunc->stack %ld)\n", sym
, sym
->name
, (long)(currFunc
->stack
)));
223 dbuf_init (&dbuf
, 128);
224 dbuf_printf (&dbuf
, "sloc%d", _G
.slocNum
++);
225 sloc
= newiTemp (dbuf_c_str (&dbuf
));
226 dbuf_destroy (&dbuf
);
228 /* set the type to the spilling symbol */
229 sloc
->type
= copyLinkChain (sym
->type
);
230 sloc
->etype
= getSpec (sloc
->type
);
231 SPEC_SCLS (sloc
->etype
) = (options
.xdata_spill
)?S_XDATA
:S_DATA
;
232 SPEC_EXTR (sloc
->etype
) = 0;
233 SPEC_STAT (sloc
->etype
) = 0;
234 SPEC_VOLATILE(sloc
->etype
) = 0;
235 SPEC_ABSA(sloc
->etype
) = 0;
237 /* we don't allow it to be allocated
238 onto the external stack since : so we
239 temporarily turn it off ; we also
240 turn off memory model to prevent
241 the spil from going to the external storage
244 // useXstack = options.useXstack;
245 // model = options.model;
246 /* noOverlay = options.noOverlay; */
247 /* options.noOverlay = 1; */
248 // options.model = options.useXstack = 0;
252 // options.useXstack = useXstack;
253 // options.model = model;
254 /* options.noOverlay = noOverlay; */
255 sloc
->isref
= 1; /* to prevent compiler warning */
257 /* if it is on the stack then update the stack */
258 if (IN_STACK (sloc
->etype
))
260 currFunc
->stack
+= getSize (sloc
->type
);
261 _G
.stackExtend
+= getSize (sloc
->type
);
265 _G
.dataExtend
+= getSize (sloc
->type
);
268 /* add it to the stackSpil set */
269 addSetHead (&_G
.stackSpil
, sloc
);
270 sym
->usl
.spillLoc
= sloc
;
273 /* add it to the set of itempStack set
274 of the spill location */
275 addSetHead (&sloc
->usl
.itmpStack
, sym
);
277 D (D_ALLOC
, ("createStackSpil: created new %s\n", sloc
->name
));
281 /*-----------------------------------------------------------------*/
282 /* spillThis - spills a specific operand */
283 /*-----------------------------------------------------------------*/
285 m6502SpillThis (symbol
* sym
)
288 /* if this is rematerializable or has a spillLocation
289 we are okay, else we need to create a spillLocation
291 if (!(sym
->remat
|| sym
->usl
.spillLoc
))
292 createStackSpil (sym
);
294 /* mark it as spilt & put it in the spilt set */
295 sym
->isspilt
= sym
->spillA
= 1;
296 _G
.spiltSet
= bitVectSetBit (_G
.spiltSet
, sym
->key
);
298 for (i
= 0; i
< sym
->nRegs
; i
++)
302 m6502_freeReg (sym
->regs
[i
]);
307 if (sym
->usl
.spillLoc
&& !sym
->remat
)
308 sym
->usl
.spillLoc
->allocreq
++;
312 /*-----------------------------------------------------------------*/
313 /* deassignLRs - check the live to and if they have registers & */
314 /* are not spilt then free up the registers */
315 /*-----------------------------------------------------------------*/
317 deassignLRs (iCode
* ic
, eBBlock
* ebp
)
322 for (sym
= hTabFirstItem (liveRanges
, &k
); sym
;
323 sym
= hTabNextItem (liveRanges
, &k
))
325 /* if it does not end here */
326 if (sym
->liveTo
> ic
->seq
)
329 /* if it was spilt on stack then we can
330 mark the stack spil location as free */
335 sym
->usl
.spillLoc
->isFree
= 1;
343 /*------------------------------------------------------------------*/
344 /* verifyRegsAssigned - make sure an iTemp is properly initialized; */
345 /* it should either have registers or have been spilled. Otherwise, */
346 /* there was an uninitialized variable, so just spill this to get */
347 /* the operand in a valid state. */
348 /*------------------------------------------------------------------*/
350 verifyRegsAssigned (operand
*op
, iCode
* ic
)
359 sym
= OP_SYMBOL (op
);
367 m6502SpillThis (sym
);
370 /*-----------------------------------------------------------------*/
371 /* rUmaskForOp :- returns register mask for an operand */
372 /*-----------------------------------------------------------------*/
374 m6502_rUmaskForOp (operand
* op
)
380 /* only temporaries are assigned registers */
384 sym
= OP_SYMBOL (op
);
386 /* if spilt or no registers assigned to it
388 if (sym
->isspilt
|| !sym
->nRegs
)
391 rumask
= newBitVect (m6502_nRegs
);
393 for (j
= 0; j
< sym
->nRegs
; j
++)
395 rumask
= bitVectSetBit (rumask
, sym
->regs
[j
]->rIdx
);
401 /*-----------------------------------------------------------------*/
402 /* regTypeNum - computes the type & number of registers required */
403 /*-----------------------------------------------------------------*/
410 /* for each live range do */
411 for (sym
= hTabFirstItem (liveRanges
, &k
); sym
;
412 sym
= hTabNextItem (liveRanges
, &k
))
414 /* if used zero times then no registers needed */
415 if ((sym
->liveTo
- sym
->liveFrom
) == 0)
418 D (D_ALLOC
, ("regTypeNum: loop on sym %p\n", sym
));
420 /* if the live range is a temporary */
423 /* if the type is marked as a conditional */
424 if (sym
->regType
== REG_CND
)
427 /* if used in return only then we don't
429 if (sym
->ruonly
|| sym
->accuse
)
431 if (IS_AGGREGATE (sym
->type
) || sym
->isptr
)
432 sym
->type
= aggrToPtr (sym
->type
, false);
436 /* if not then we require registers */
438 ("regTypeNum: isagg %u nRegs %u type %p\n", IS_AGGREGATE (sym
->type
) || sym
->isptr
, sym
->nRegs
, sym
->type
));
439 sym
->nRegs
= ((IS_AGGREGATE (sym
->type
) || sym
->isptr
)
440 ? getSize (sym
->type
= aggrToPtr (sym
->type
, false))
441 : getSize (sym
->type
));
442 D (D_ALLOC
, ("regTypeNum: setting nRegs of %s (%p) to %u\n", sym
->name
, sym
, sym
->nRegs
));
444 D (D_ALLOC
, ("regTypeNum: setup to assign regs sym %p\n", sym
));
448 fprintf (stderr
, "allocated more than 8 registers for type ");
449 printTypeChain (sym
->type
, stderr
);
450 fprintf (stderr
, "\n");
453 /* determine the type of register required */
454 if (sym
->nRegs
== 1 && IS_PTR (sym
->type
) && sym
->uptr
)
455 sym
->regType
= REG_PTR
;
457 sym
->regType
= REG_GPR
;
461 /* for the first run we don't provide */
462 /* registers for true symbols we will */
463 /* see how things go */
464 D (D_ALLOC
, ("regTypeNum: #2 setting num of %p to 0\n", sym
));
471 /** Transform weird SDCC handling of writes via pointers
472 into something more sensible. */
474 transformPointerSet (eBBlock
**ebbs
, int count
)
477 for (int i
= 0; i
< count
; i
++)
481 /* for all instructions do */
482 for (ic
= ebbs
[i
]->sch
; ic
; ic
= ic
->next
)
483 if (POINTER_SET (ic
))
485 IC_LEFT (ic
) = IC_RESULT (ic
);
487 ic
->op
= SET_VALUE_AT_ADDRESS
;
493 /*-----------------------------------------------------------------*/
494 /* deallocStackSpil - this will set the stack pointer back */
495 /*-----------------------------------------------------------------*/
497 DEFSETFUNC (deallocStackSpil
)
505 /*-----------------------------------------------------------------*/
506 /* packRegsForAssign - register reduction for assignment */
507 /*-----------------------------------------------------------------*/
509 packRegsForAssign (iCode
* ic
, eBBlock
* ebp
)
513 if (!IS_ITEMP (IC_RIGHT (ic
))
514 || OP_SYMBOL (IC_RIGHT (ic
))->isind
515 || OP_LIVETO (IC_RIGHT (ic
)) > ic
->seq
)
520 /* if the true symbol is defined in far space or on stack
521 then we should not since this will increase register pressure */
523 if (isOperandInFarSpace(IC_RESULT(ic
)) && !farSpacePackable(ic
))
529 /* find the definition of iTempNN scanning backwards if we find
530 a use of the true symbol before we find the definition then
532 for (dic
= ic
->prev
; dic
; dic
= dic
->prev
)
536 /* We can pack across a function call only if it's a local */
537 /* variable or our parameter. Never pack global variables */
538 /* or parameters to a function we call. */
539 if ((dic
->op
== CALL
|| dic
->op
== PCALL
))
541 if (!OP_SYMBOL (IC_RESULT (ic
))->ismyparm
542 && !OP_SYMBOL (IC_RESULT (ic
))->islocal
)
548 /* Don't move an assignment out of a critical block */
549 if (dic
->op
== CRITICAL
)
560 if (IS_SYMOP (IC_COND (dic
))
561 && (IC_COND (dic
)->key
== IC_RESULT (ic
)->key
562 || IC_COND (dic
)->key
== IC_RIGHT (ic
)->key
))
570 if (IS_TRUE_SYMOP (IC_RESULT (dic
))
571 && IS_OP_VOLATILE (IC_RESULT (dic
)))
577 if (IS_SYMOP (IC_RESULT (dic
))
578 && IC_RESULT (dic
)->key
== IC_RIGHT (ic
)->key
)
580 if (POINTER_SET (dic
))
585 if (IS_SYMOP (IC_RIGHT (dic
))
586 && (IC_RIGHT (dic
)->key
== IC_RESULT (ic
)->key
587 || IC_RIGHT (dic
)->key
== IC_RIGHT (ic
)->key
))
593 if (IS_SYMOP (IC_LEFT (dic
))
594 && (IC_LEFT (dic
)->key
== IC_RESULT (ic
)->key
595 || IC_LEFT (dic
)->key
== IC_RIGHT (ic
)->key
))
601 if (POINTER_SET (dic
) &&
602 IC_RESULT (dic
)->key
== IC_RESULT (ic
)->key
)
617 return 0; /* did not find */
619 /* if assignment then check that right is not a bit */
620 if (ASSIGNMENT (ic
) && !POINTER_SET (ic
))
622 sym_link
*etype
= operandType (IC_RESULT (dic
));
623 if (IS_BITFIELD (etype
))
625 /* if result is a bit too then it's ok */
626 etype
= operandType (IC_RESULT (ic
));
627 if (!IS_BITFIELD (etype
))
634 /* found the definition */
636 /* delete from liverange table also
637 delete from all the points inbetween and the new
639 for (sic
= dic
; sic
!= ic
; sic
= sic
->next
)
641 bitVectUnSetBit (sic
->rlive
, IC_RESULT (ic
)->key
);
642 if (IS_ITEMP (IC_RESULT (dic
)))
643 bitVectSetBit (sic
->rlive
, IC_RESULT (dic
)->key
);
646 /* replace the result with the result of */
647 /* this assignment and remove this assignment */
648 bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic
))->defs
, dic
->key
);
649 ReplaceOpWithCheaperOp (&IC_RESULT (dic
), IC_RESULT (ic
));
651 if (IS_ITEMP (IC_RESULT (dic
)) && OP_SYMBOL (IC_RESULT (dic
))->liveFrom
> dic
->seq
)
653 OP_SYMBOL (IC_RESULT (dic
))->liveFrom
= dic
->seq
;
655 // TODO: and the otherway around?
657 remiCodeFromeBBlock (ebp
, ic
);
658 bitVectUnSetBit (OP_DEFS (IC_RESULT (ic
)), ic
->key
);
659 hTabDeleteItem (&iCodehTab
, ic
->key
, ic
, DELETE_ITEM
, NULL
);
660 OP_DEFS (IC_RESULT (dic
)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic
)), dic
->key
);
664 /*------------------------------------------------------------------*/
665 /* findAssignToSym : scanning backwards looks for first assig found */
666 /*------------------------------------------------------------------*/
668 findAssignToSym (operand
* op
, iCode
* ic
)
672 /* This routine is used to find sequences like
674 ...; (intervening ops don't use iTempAA or modify FOO)
675 blah = blah + iTempAA;
677 and eliminate the use of iTempAA, freeing up its register for
680 for (dic
= ic
->prev
; dic
; dic
= dic
->prev
)
682 if (dic
->op
== '=' &&
683 !POINTER_SET (dic
) &&
684 IC_RESULT (dic
)->key
== op
->key
685 && IS_TRUE_SYMOP(IC_RIGHT(dic
))
687 break; /* found where this temp was defined */
689 /* if we find an usage then we cannot delete it */
690 if (IC_LEFT (dic
) && IC_LEFT (dic
)->key
== op
->key
)
693 if (IC_RIGHT (dic
) && IC_RIGHT (dic
)->key
== op
->key
)
696 if (POINTER_SET (dic
) && IC_RESULT (dic
)->key
== op
->key
)
701 return NULL
; /* didn't find any assignment to op */
702 /* we are interested only if defined in far space */
703 /* or in stack space in case of + & - */
705 /* if assigned to a non-symbol then don't repack regs */
706 if (!IS_SYMOP (IC_RIGHT (dic
)))
709 /* if the symbol's address has been taken, there might be a */
710 /* non-obvious assignment to it, and so we should not */
711 if (OP_SYMBOL (IC_RIGHT (dic
))->addrtaken
)
714 /* if the symbol is volatile then we should not */
715 if (isOperandVolatile (IC_RIGHT (dic
), true))
717 /* XXX TODO --- should we be passing false to isOperandVolatile()?
718 What does it mean for an iTemp to be volatile, anyway? Passing
719 true is more cautious but may prevent possible optimizations */
721 /* if the symbol is in far space then we should not */
722 /* if (isOperandInFarSpace (IC_RIGHT (dic)))
726 /* now make sure that the right side of dic
727 is not defined between ic & dic */
730 iCode
*sic
= dic
->next
;
732 for (; sic
!= ic
; sic
= sic
->next
)
733 if (IC_RESULT (sic
) &&
734 IC_RESULT (sic
)->key
== IC_RIGHT (dic
)->key
)
741 /*-----------------------------------------------------------------*/
742 /* reassignAliasedSym - used by packRegsForSupport to replace */
743 /* redundant iTemp with equivalent symbol */
744 /*-----------------------------------------------------------------*/
746 reassignAliasedSym (eBBlock
*ebp
, iCode
*assignment
, iCode
*use
, operand
*op
)
749 unsigned oldSymKey
, newSymKey
;
752 newSymKey
= IC_RIGHT(assignment
)->key
;
754 /* only track live ranges of compiler-generated temporaries */
755 if (!IS_ITEMP(IC_RIGHT(assignment
)))
758 /* update the live-value bitmaps */
759 for (ic
= assignment
; ic
!= use
; ic
= ic
->next
) {
760 bitVectUnSetBit (ic
->rlive
, oldSymKey
);
762 ic
->rlive
= bitVectSetBit (ic
->rlive
, newSymKey
);
765 /* update the sym of the used operand */
766 OP_SYMBOL(op
) = OP_SYMBOL(IC_RIGHT(assignment
));
767 op
->key
= OP_SYMBOL(op
)->key
;
769 /* update the sym's liverange */
770 if ( OP_LIVETO(op
) < ic
->seq
)
771 setToRange(op
, ic
->seq
, false);
773 /* remove the assignment iCode now that its result is unused */
774 remiCodeFromeBBlock (ebp
, assignment
);
775 bitVectUnSetBit(OP_SYMBOL(IC_RESULT(assignment
))->defs
, assignment
->key
);
776 hTabDeleteItem (&iCodehTab
, assignment
->key
, assignment
, DELETE_ITEM
, NULL
);
780 /*-----------------------------------------------------------------*/
781 /* packRegsForSupport :- reduce some registers for support calls */
782 /*-----------------------------------------------------------------*/
784 packRegsForSupport (iCode
* ic
, eBBlock
* ebp
)
789 /* for the left & right operand :- look to see if the
790 left was assigned a true symbol in far space in that
793 if (IS_ITEMP (IC_LEFT (ic
)) &&
794 OP_SYMBOL (IC_LEFT (ic
))->liveTo
<= ic
->seq
)
796 dic
= findAssignToSym (IC_LEFT (ic
), ic
);
800 /* found it we need to remove it from the block */
801 reassignAliasedSym (ebp
, dic
, ic
, IC_LEFT(ic
));
806 /* do the same for the right operand */
807 if (IS_ITEMP (IC_RIGHT (ic
)) &&
808 OP_SYMBOL (IC_RIGHT (ic
))->liveTo
<= ic
->seq
)
810 iCode
*dic
= findAssignToSym (IC_RIGHT (ic
), ic
);
814 /* found it we need to remove it from the block */
815 reassignAliasedSym (ebp
, dic
, ic
, IC_RIGHT(ic
));
823 /*-----------------------------------------------------------------*/
824 /* isBitwiseOptimizable - requirements of JEAN LOUIS VERN */
825 /*-----------------------------------------------------------------*/
827 isBitwiseOptimizable (iCode
* ic
)
829 sym_link
*ltype
= getSpec (operandType (IC_LEFT (ic
)));
830 sym_link
*rtype
= getSpec (operandType (IC_RIGHT (ic
)));
832 /* bitwise operations are considered optimizable
833 under the following conditions (Jean-Louis VERN)
845 if (IS_LITERAL(rtype
) ||
846 (IS_BITVAR (ltype
) && IN_BITSPACE (SPEC_OCLS (ltype
))))
852 /*-----------------------------------------------------------------*/
853 /* packForPush - heuristics to reduce iCode for pushing */
854 /*-----------------------------------------------------------------*/
856 packForPush (iCode
* ic
, eBBlock
** ebpp
, int count
)
860 int disallowHiddenAssignment
= 0;
861 eBBlock
* ebp
= ebpp
[ic
->eBBlockNum
];
863 if ((ic
->op
!= IPUSH
&& ic
->op
!= SEND
) || !IS_ITEMP (IC_LEFT (ic
)))
866 /* must have only definition & one usage */
867 if (bitVectnBitsOn (OP_DEFS (IC_LEFT (ic
))) != 1 ||
868 bitVectnBitsOn (OP_USES (IC_LEFT (ic
))) != 1)
871 /* find the definition */
872 if (!(dic
= hTabItemWithKey (iCodehTab
,
873 bitVectFirstBit (OP_DEFS (IC_LEFT (ic
))))))
876 if (dic
->op
!= '=' || POINTER_SET (dic
))
879 if (dic
->seq
< ebp
->fSeq
|| dic
->seq
> ebp
->lSeq
) // Evelyn did this
882 for (i
=0; i
<count
; i
++)
884 if (dic
->seq
>= ebpp
[i
]->fSeq
&& dic
->seq
<= ebpp
[i
]->lSeq
)
890 if (i
==count
) // Abort if we can't find the definition's block
894 if (IS_SYMOP(IC_RIGHT(dic
)))
896 if (IC_RIGHT (dic
)->isvolatile
)
899 if (OP_SYMBOL (IC_RIGHT (dic
))->addrtaken
|| isOperandGlobal (IC_RIGHT (dic
)))
900 disallowHiddenAssignment
= 1;
902 /* make sure the right side does not have any definitions
904 dbv
= OP_DEFS(IC_RIGHT(dic
));
905 for (lic
= ic
; lic
&& lic
!= dic
; lic
= lic
->prev
)
907 if (bitVectBitValue(dbv
,lic
->key
))
909 if (disallowHiddenAssignment
&& (lic
->op
== CALL
|| lic
->op
== PCALL
|| POINTER_SET (lic
)))
912 /* make sure they have the same type */
913 if (IS_SPEC(operandType(IC_LEFT(ic
))))
915 sym_link
*itype
=operandType(IC_LEFT(ic
));
916 sym_link
*ditype
=operandType(IC_RIGHT(dic
));
918 if (SPEC_USIGN(itype
)!=SPEC_USIGN(ditype
) ||
919 SPEC_LONG(itype
)!=SPEC_LONG(ditype
))
922 /* extend the live range of replaced operand if needed */
923 if (OP_SYMBOL(IC_RIGHT(dic
))->liveTo
< ic
->seq
)
925 OP_SYMBOL(IC_RIGHT(dic
))->liveTo
= ic
->seq
;
927 bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic
))->defs
,dic
->key
);
929 if (IS_ITEMP (IC_RIGHT (dic
)))
930 OP_USES (IC_RIGHT (dic
)) = bitVectSetBit (OP_USES (IC_RIGHT (dic
)), ic
->key
);
932 /* we now we know that it has one & only one def & use
933 and the that the definition is an assignment */
934 ReplaceOpWithCheaperOp(&IC_LEFT (ic
), IC_RIGHT (dic
));
935 remiCodeFromeBBlock (ebp
, dic
);
936 hTabDeleteItem (&iCodehTab
, dic
->key
, dic
, DELETE_ITEM
, NULL
);
939 /*------------------------------------------------------------------*/
940 /* moveSendToCall - move SEND to immediately precede its CALL/PCALL */
941 /*------------------------------------------------------------------*/
943 moveSendToCall (iCode
*sic
, eBBlock
*ebp
)
945 iCode
* prev
= sic
->prev
;
949 /* Go find the CALL/PCALL */
951 while (cic
&& cic
->op
!= CALL
&& cic
->op
!= PCALL
)
956 /* Is there a second SEND? If so, we'll need to move it too. */
957 if (sic
->next
->op
== SEND
)
960 /* relocate the SEND(s) */
961 remiCodeFromeBBlock (ebp
, sic
);
962 addiCodeToeBBlock (ebp
, sic
, cic
);
965 remiCodeFromeBBlock (ebp
, sic2
);
966 addiCodeToeBBlock (ebp
, sic2
, cic
);
969 /* Return the iCode to continue processing at. */
977 /*---------------------------------------------------------------------*/
978 /* packPointerOp - see if we can move an offset from addition iCode */
979 /* to the pointer iCode to used indexed addr mode */
980 /* The z80-related ports do a similar thing in SDCCopt.c, offsetFold() */
981 /*---------------------------------------------------------------------*/
983 packPointerOp (iCode
* ic
, eBBlock
** ebpp
)
987 operand
* nonOffsetOp
;
992 if (POINTER_SET (ic
))
994 pointer
= IC_RESULT (ic
);
995 offsetOp
= IC_LEFT (ic
);
997 else if (POINTER_GET (ic
))
999 pointer
= IC_LEFT (ic
);
1000 offsetOp
= IC_RIGHT (ic
);
1005 if (!IS_ITEMP (pointer
))
1008 /* If the pointer is rematerializable, it's already fully optimized */
1009 if (OP_SYMBOL (pointer
)->remat
)
1012 if (offsetOp
&& IS_OP_LITERAL (offsetOp
) && operandLitValue (offsetOp
) != 0)
1014 if (offsetOp
&& IS_SYMOP (offsetOp
))
1017 /* There must be only one definition */
1018 if (bitVectnBitsOn (OP_DEFS (pointer
)) != 1)
1020 /* find the definition */
1021 if (!(dic
= hTabItemWithKey (iCodehTab
, bitVectFirstBit (OP_DEFS (pointer
)))))
1024 if (dic
->op
== '+' && (IS_OP_LITERAL (IC_RIGHT (dic
)) ||
1025 (IS_ITEMP (IC_RIGHT (dic
)) && OP_SYMBOL (IC_RIGHT (dic
))->remat
)))
1027 nonOffsetOp
= IC_LEFT (dic
);
1028 offsetOp
= IC_RIGHT (dic
);
1030 else if (dic
->op
== '+' && IS_ITEMP (IC_LEFT (dic
)) && OP_SYMBOL (IC_LEFT (dic
))->remat
)
1032 nonOffsetOp
= IC_RIGHT (dic
);
1033 offsetOp
= IC_LEFT (dic
);
1039 /* Now check all of the uses to make sure they are all get/set pointer */
1040 /* and don't already have a non-zero offset operand */
1041 for (key
=0; key
<OP_USES (pointer
)->size
; key
++)
1043 if (bitVectBitValue (OP_USES (pointer
), key
))
1045 uic
= hTabItemWithKey (iCodehTab
, key
);
1046 if (POINTER_GET (uic
))
1048 if (IC_RIGHT (uic
) && IS_OP_LITERAL (IC_RIGHT (uic
)) && operandLitValue (IC_RIGHT (uic
)) != 0)
1050 if (IC_RIGHT (uic
) && IS_SYMOP (IC_RIGHT (uic
)))
1053 else if (POINTER_SET (uic
))
1055 // FIXME: this code will make bug-3385.c fail
1056 // it seems there are some corner cases where this
1057 // optimization is unsafe.
1058 // Other cases might also be unsafe but no test triggers it.
1059 // HC08 is also affected by the same issue.
1061 // remove the return above to trigger the failure.
1062 if (IC_LEFT (uic
) && IS_OP_LITERAL (IC_LEFT (uic
)) && operandLitValue (IC_LEFT (uic
)) != 0)
1064 if (IC_LEFT (uic
) && IS_SYMOP (IC_LEFT (uic
)))
1072 /* Everything checks out. Move the literal or rematerializable offset */
1073 /* to the pointer get/set iCodes */
1074 for (key
=0; key
<OP_USES (pointer
)->size
; key
++)
1076 if (bitVectBitValue (OP_USES (pointer
), key
))
1078 uic
= hTabItemWithKey (iCodehTab
, key
);
1079 if (POINTER_GET (uic
))
1081 IC_RIGHT (uic
) = offsetOp
;
1082 if (IS_SYMOP (offsetOp
))
1083 OP_USES (offsetOp
) = bitVectSetBit (OP_USES (offsetOp
), key
);
1085 else if (POINTER_SET (uic
))
1087 IC_LEFT (uic
) = offsetOp
;
1088 if (IS_SYMOP (offsetOp
))
1089 OP_USES (offsetOp
) = bitVectSetBit (OP_USES (offsetOp
), key
);
1096 /* Put the remaining operand on the right and convert to assignment */
1097 if (IS_SYMOP (offsetOp
))
1098 bitVectUnSetBit (OP_USES (offsetOp
), dic
->key
);
1099 IC_RIGHT (dic
) = nonOffsetOp
;
1100 IC_LEFT (dic
) = NULL
;
1101 SET_ISADDR (IC_RESULT (dic
), 0);
1105 /*-----------------------------------------------------------------*/
1106 /* packRegisters - does some transformations to reduce register */
1108 /*-----------------------------------------------------------------*/
1110 packRegisters (eBBlock
** ebpp
, int count
)
1116 for (blockno
=0; blockno
<count
; blockno
++)
1118 eBBlock
*ebp
= ebpp
[blockno
];
1123 /* look for assignments of the form */
1124 /* iTempNN = TrueSym (someoperation) SomeOperand */
1126 /* TrueSym := iTempNN:1 */
1127 for (ic
= ebp
->sch
; ic
; ic
= ic
->next
)
1129 /* find assignment of the form TrueSym := iTempNN:1 */
1130 if (ic
->op
== '=' && !POINTER_SET (ic
))
1131 change
+= packRegsForAssign (ic
, ebp
);
1136 for (ic
= ebp
->sch
; ic
; ic
= ic
->next
)
1138 //packRegsForLiteral (ic);
1140 /* move SEND to immediately precede its CALL/PCALL */
1141 if (ic
->op
== SEND
&& ic
->next
&&
1142 ic
->next
->op
!= CALL
&& ic
->next
->op
!= PCALL
)
1144 ic
= moveSendToCall (ic
, ebp
);
1147 /* if this is an itemp & result of an address of a true sym
1148 then mark this as rematerialisable */
1149 if (ic
->op
== ADDRESS_OF
&&
1150 IS_ITEMP (IC_RESULT (ic
)) &&
1151 IS_TRUE_SYMOP (IC_LEFT (ic
)) &&
1152 bitVectnBitsOn (OP_DEFS (IC_RESULT (ic
))) == 1 &&
1153 !OP_SYMBOL (IC_LEFT (ic
))->onStack
)
1155 OP_SYMBOL (IC_RESULT (ic
))->remat
= 1;
1156 OP_SYMBOL (IC_RESULT (ic
))->rematiCode
= ic
;
1157 OP_SYMBOL (IC_RESULT (ic
))->usl
.spillLoc
= NULL
;
1160 /* Safe: just propagates the remat flag */
1161 /* if straight assignment then carry remat flag if this is the
1163 if (ic
->op
== '=' &&
1164 !POINTER_SET (ic
) &&
1165 IS_SYMOP (IC_RIGHT (ic
)) &&
1166 OP_SYMBOL (IC_RIGHT (ic
))->remat
&&
1167 bitVectnBitsOn (OP_SYMBOL (IC_RESULT (ic
))->defs
) <= 1 &&
1168 !OP_SYMBOL (IC_RESULT (ic
))->_isparm
&&
1169 !OP_SYMBOL (IC_RESULT (ic
))->addrtaken
&&
1170 !isOperandGlobal (IC_RESULT (ic
)))
1172 OP_SYMBOL (IC_RESULT (ic
))->remat
= OP_SYMBOL (IC_RIGHT (ic
))->remat
;
1173 OP_SYMBOL (IC_RESULT (ic
))->rematiCode
= OP_SYMBOL (IC_RIGHT (ic
))->rematiCode
;
1176 /* if cast to a pointer & the pointer being
1177 cast is remat, then we can remat this cast as well */
1178 if (ic
->op
== CAST
&&
1179 IS_SYMOP(IC_RIGHT(ic
)) &&
1180 OP_SYMBOL(IC_RIGHT(ic
))->remat
&&
1181 bitVectnBitsOn (OP_DEFS (IC_RESULT (ic
))) == 1 &&
1182 !OP_SYMBOL (IC_RESULT (ic
))->_isparm
&&
1183 !OP_SYMBOL (IC_RESULT (ic
))->addrtaken
&&
1184 !isOperandGlobal (IC_RESULT (ic
)))
1186 sym_link
*to_type
= operandType(IC_LEFT(ic
));
1187 sym_link
*from_type
= operandType(IC_RIGHT(ic
));
1188 if (IS_PTR(to_type
) && IS_PTR(from_type
))
1190 OP_SYMBOL (IC_RESULT (ic
))->remat
= 1;
1191 OP_SYMBOL (IC_RESULT (ic
))->rematiCode
= ic
;
1192 OP_SYMBOL (IC_RESULT (ic
))->usl
.spillLoc
= NULL
;
1196 /* if this is a +/- operation with a rematerializable
1197 then mark this as rematerializable as well */
1198 if ((ic
->op
== '+' || ic
->op
== '-') &&
1199 (IS_SYMOP (IC_LEFT (ic
)) &&
1200 IS_ITEMP (IC_RESULT (ic
)) &&
1201 IS_OP_LITERAL (IC_RIGHT (ic
))) &&
1202 OP_SYMBOL (IC_LEFT (ic
))->remat
&&
1203 (!IS_SYMOP (IC_RIGHT (ic
)) || !IS_CAST_ICODE(OP_SYMBOL (IC_RIGHT (ic
))->rematiCode
)) &&
1204 bitVectnBitsOn (OP_DEFS (IC_RESULT (ic
))) == 1)
1206 OP_SYMBOL (IC_RESULT (ic
))->remat
= 1;
1207 OP_SYMBOL (IC_RESULT (ic
))->rematiCode
= ic
;
1208 OP_SYMBOL (IC_RESULT (ic
))->usl
.spillLoc
= NULL
;
1210 /* mark the pointer usages */
1211 if (POINTER_SET (ic
) && IS_SYMOP (IC_RESULT (ic
)))
1212 OP_SYMBOL (IC_RESULT (ic
))->uptr
= 1;
1214 if (POINTER_GET (ic
) && IS_SYMOP (IC_LEFT (ic
)))
1215 OP_SYMBOL (IC_LEFT (ic
))->uptr
= 1;
1217 /* reduce for support function calls */
1218 if (ic
->supportRtn
|| (ic
->op
!= IFX
&& ic
->op
!= JUMPTABLE
))
1219 packRegsForSupport (ic
, ebp
);
1221 /* if the condition of an if instruction
1222 is defined in the previous instruction and
1223 this is the only usage then
1224 mark the itemp as a conditional */
1225 if ((IS_CONDITIONAL (ic
) ||
1226 (IS_BITWISE_OP(ic
) && isBitwiseOptimizable (ic
))) &&
1227 ic
->next
&& ic
->next
->op
== IFX
&&
1228 bitVectnBitsOn (OP_USES(IC_RESULT(ic
)))==1 &&
1229 isOperandEqual (IC_RESULT (ic
), IC_COND (ic
->next
)) &&
1230 OP_SYMBOL (IC_RESULT (ic
))->liveTo
<= ic
->next
->seq
)
1232 OP_SYMBOL (IC_RESULT (ic
))->regType
= REG_CND
;
1237 iTempNN := (some variable in farspace) V1
1242 if (ic
->op
== IPUSH
|| ic
->op
== SEND
)
1244 packForPush (ic
, ebpp
, count
);
1247 if (POINTER_SET (ic
) || POINTER_GET (ic
))
1248 packPointerOp (ic
, ebpp
);
1254 /*-----------------------------------------------------------------*/
1255 /* Mark variables for assignment by the register allocator. */
1256 /*-----------------------------------------------------------------*/
1258 serialRegMark (eBBlock
** ebbs
, int count
)
1261 short int max_alloc_bytes
= SHRT_MAX
; // Byte limit. Set this to a low value to pass only few variables to the register allocator. This can be useful for debugging.
1263 D (D_ALLOC
, ("serialRegMark for %s, currFunc->stack %d\n", currFunc
->name
, currFunc
->stack
));
1265 /* for all blocks */
1266 for (i
= 0; i
< count
; i
++)
1271 && (ebbs
[i
]->entryLabel
!= entryLabel
1272 && ebbs
[i
]->entryLabel
!= returnLabel
))
1275 /* for all instructions do */
1276 for (ic
= ebbs
[i
]->sch
; ic
; ic
= ic
->next
)
1280 /* if result is present && is a true symbol */
1281 if (IC_RESULT (ic
) && ic
->op
!= IFX
&&
1282 IS_TRUE_SYMOP (IC_RESULT (ic
)))
1284 OP_SYMBOL (IC_RESULT (ic
))->allocreq
++;
1287 /* take away registers from live
1288 ranges that end at this instruction */
1289 deassignLRs (ic
, ebbs
[i
]);
1291 /* some don't need registers */
1292 if (SKIP_IC2 (ic
) ||
1293 ic
->op
== JUMPTABLE
||
1296 (IC_RESULT (ic
) && POINTER_SET (ic
)))
1299 /* now we need to allocate registers only for the result */
1302 symbol
*sym
= OP_SYMBOL (IC_RESULT (ic
));
1304 /* Make sure any spill location is definitely allocated */
1305 if (sym
->isspilt
&& !sym
->remat
&& sym
->usl
.spillLoc
&&
1306 !sym
->usl
.spillLoc
->allocreq
)
1308 sym
->usl
.spillLoc
->allocreq
++;
1311 /* if it does not need or is spilt
1312 or is already assigned to registers
1313 or will not live beyond this instructions */
1316 sym
->liveTo
<= ic
->seq
)
1318 D (D_ALLOC
, ("serialRegMark: won't live long enough.\n"));
1322 /* if some liverange has been spilt at the block level
1323 and this one live beyond this block then spill this
1325 if (_G
.blockSpil
&& sym
->liveTo
> ebbs
[i
]->lSeq
)
1327 m6502SpillThis (sym
);
1333 m6502SpillThis (sym
);
1337 if (max_alloc_bytes
>= sym
->nRegs
)
1339 sym
->for_newralloc
= 1;
1340 max_alloc_bytes
-= sym
->nRegs
;
1342 else if (!sym
->for_newralloc
)
1344 m6502SpillThis (sym
);
1345 printf ("Spilt %s due to byte limit.\n", sym
->name
);
1352 /*-----------------------------------------------------------------*/
1354 /*-----------------------------------------------------------------*/
1356 m6502RegFix (eBBlock
** ebbs
, int count
)
1360 /* Check for and fix any problems with uninitialized operands */
1361 for (i
= 0; i
< count
; i
++)
1365 if (ebbs
[i
]->noPath
&& (ebbs
[i
]->entryLabel
!= entryLabel
&& ebbs
[i
]->entryLabel
!= returnLabel
))
1368 for (ic
= ebbs
[i
]->sch
; ic
; ic
= ic
->next
)
1370 deassignLRs (ic
, ebbs
[i
]);
1377 verifyRegsAssigned (IC_COND (ic
), ic
);
1381 if (ic
->op
== JUMPTABLE
)
1383 verifyRegsAssigned (IC_JTCOND (ic
), ic
);
1387 verifyRegsAssigned (IC_RESULT (ic
), ic
);
1388 verifyRegsAssigned (IC_LEFT (ic
), ic
);
1389 verifyRegsAssigned (IC_RIGHT (ic
), ic
);
1394 /*-----------------------------------------------------------------*/
1395 /* assignRegisters - assigns registers to each live range as need */
1396 /*-----------------------------------------------------------------*/
1398 m6502_assignRegisters (ebbIndex
*ebbi
)
1400 eBBlock
** ebbs
= ebbi
->bbOrder
;
1401 int count
= ebbi
->count
;
1405 m6502_ptrRegReq
= _G
.stackExtend
= _G
.dataExtend
= 0;
1406 // TODO: add asserts to make sure IDX is correct
1407 m6502_reg_a
= m6502_regWithIdx(A_IDX
);
1408 m6502_reg_x
= m6502_regWithIdx(X_IDX
);
1409 m6502_reg_y
= m6502_regWithIdx(Y_IDX
);
1410 m6502_reg_xa
= m6502_regWithIdx(XA_IDX
);
1411 // m6502_reg_ya = m6502_regWithIdx(YA_IDX);
1412 m6502_reg_yx
= m6502_regWithIdx(YX_IDX
);
1413 m6502_reg_sp
= m6502_regWithIdx(SP_IDX
);
1415 // transformPointerSet (ebbs, count);
1417 /* change assignments this will remove some
1418 live ranges reducing some register pressure */
1420 packRegisters (ebbs
, count
);
1422 /* liveranges probably changed by register packing
1423 so we compute them again */
1424 recomputeLiveRanges (ebbs
, count
, false);
1426 if (options
.dump_i_code
)
1427 dumpEbbsToFileExt (DUMP_PACK
, ebbi
);
1429 /* first determine for each live range the number of
1430 registers & the type of registers required for each */
1433 /* Mark variables for assignment by the new allocator */
1434 serialRegMark (ebbs
, count
);
1436 /* Invoke optimal register allocator */
1437 ic
= m6502_ralloc2_cc (ebbi
);
1439 /* if stack was extended then tell the user */
1442 // printf("Stack spills for %s: %d\n", currFunc->name, _G.stackExtend);
1448 // printf("Data spills for %s: %d\n", currFunc->name, _G.dataExtend);
1452 /* redo that offsets for stacked automatic variables */
1455 redoStackOffsets ();
1458 if (options
.dump_i_code
)
1460 dumpEbbsToFileExt (DUMP_RASSGN
, ebbi
);
1461 dumpLiveRanges (DUMP_LRANGE
, liveRanges
);
1464 /* now get back the chain */
1465 ic
= iCodeLabelOptimize (iCodeFromeBBlock (ebbs
, count
));
1469 /* free up any _G.stackSpil locations allocated */
1470 applyToSet (_G
.stackSpil
, deallocStackSpil
);
1472 setToNull ((void *) &_G
.stackSpil
);
1473 setToNull ((void *) &_G
.spiltSet
);
1475 /* mark all registers as free */
1476 for (i
= 0; i
< m6502_nRegs
; i
++) {
1477 reg_info
*reg
= m6502_regWithIdx (i
);
1478 m6502_freeReg (reg
);
1479 m6502_dirtyReg (reg
);
1485 /*-----------------------------------------------------------------*/
1486 /* m6502_useReg - marks a register as used */
1487 /*-----------------------------------------------------------------*/
1489 m6502_useReg (reg_info
* reg
)
1496 m6502_reg_xa
->aop
= NULL
;
1497 m6502_reg_xa
->isFree
= 0;
1498 // m6502_reg_ya->aop = NULL;
1499 // m6502_reg_ya->isFree = 0;
1502 m6502_reg_xa
->aop
= NULL
;
1503 m6502_reg_xa
->isFree
= 0;
1504 m6502_reg_yx
->aop
= NULL
;
1505 m6502_reg_yx
->isFree
= 0;
1508 // m6502_reg_ya->aop = NULL;
1509 // m6502_reg_ya->isFree = 0;
1510 m6502_reg_yx
->aop
= NULL
;
1511 m6502_reg_yx
->isFree
= 0;
1514 m6502_reg_x
->aop
= NULL
;
1515 m6502_reg_x
->isFree
= 0;
1516 m6502_reg_a
->aop
= NULL
;
1517 m6502_reg_a
->isFree
= 0;
1520 // m6502_reg_y->aop = NULL;
1521 // m6502_reg_y->isFree = 0;
1522 // m6502_reg_a->aop = NULL;
1523 // m6502_reg_a->isFree = 0;
1526 m6502_reg_y
->aop
= NULL
;
1527 m6502_reg_y
->isFree
= 0;
1528 m6502_reg_x
->aop
= NULL
;
1529 m6502_reg_x
->isFree
= 0;
1536 /*-----------------------------------------------------------------*/
1537 /* m6502_dirtyReg - marks a register as dirty */
1538 /*-----------------------------------------------------------------*/
1540 m6502_dirtyReg (reg_info
* reg
)
1548 m6502_reg_xa
->aop
= NULL
;
1549 m6502_reg_xa
->isLitConst
= 0;
1550 // m6502_reg_ya->aop = NULL;
1551 // m6502_reg_ya->isLitConst = 0;
1554 m6502_reg_xa
->aop
= NULL
;
1555 m6502_reg_xa
->isLitConst
= 0;
1556 m6502_reg_yx
->aop
= NULL
;
1557 m6502_reg_yx
->isLitConst
= 0;
1560 // m6502_reg_ya->aop = NULL;
1561 // m6502_reg_ya->isLitConst = 0;
1562 m6502_reg_yx
->aop
= NULL
;
1563 m6502_reg_yx
->isLitConst
= 0;
1566 m6502_reg_x
->aop
= NULL
;
1567 m6502_reg_x
->isLitConst
= 0;
1568 m6502_reg_a
->aop
= NULL
;
1569 m6502_reg_a
->isLitConst
= 0;
1572 // m6502_reg_y->aop = NULL;
1573 // m6502_reg_y->isLitConst = 0;
1574 // m6502_reg_a->aop = NULL;
1575 // m6502_reg_a->isLitConst = 0;
1578 m6502_reg_y
->aop
= NULL
;
1579 m6502_reg_y
->isLitConst
= 0;
1580 m6502_reg_x
->aop
= NULL
;
1581 m6502_reg_x
->isLitConst
= 0;
1588 /*-----------------------------------------------------------------*/
1589 /* updateRegUsage - update the registers in use at the start of */
1591 /*-----------------------------------------------------------------*/
1593 updateRegUsage (iCode
* ic
)
1597 // update the registers in use at the start of this icode
1598 for (reg
=0; reg
<m6502_nRegs
; reg
++)
1600 if (regsm6502
[reg
].isFree
)
1602 ic
->riu
&= ~(regsm6502
[reg
].mask
);
1606 ic
->riu
|= (regsm6502
[reg
].mask
);