* device/lib/mcs51/crtcall.asm: new, added for indirect calls
[fw/sdcc] / src / mcs51 / rtrack.c
1 /*-------------------------------------------------------------------------\r
2   rtrack.c - tracking content of registers on an mcs51\r
3 \r
4   Copyright 2007 Frieder Ferlemann (Frieder Ferlemann AT web.de)\r
5 \r
6   This program is free software; you can redistribute it and/or modify\r
7   it under the terms of the GNU General Public License as published by\r
8   the Free Software Foundation; either version 2 of the License, or\r
9   (at your option) any later version.\r
10 \r
11   This program is distributed in the hope that it will be useful,\r
12   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14   GNU General Public License for more details.\r
15 \r
16   You should have received a copy of the GNU General Public License\r
17   along with this program; if not, write to the Free Software\r
18   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA\r
19 -------------------------------------------------------------------------*/\r
20 \r
21 /*-------------------------------------------------------------------------\r
22   Status:\r
23     - passes regression test suite, still bugs are likely\r
24     - only active if environment variable SDCC_RTRACK is set\r
25 \r
26   Missed opportunities:\r
27     - does not track symbols as in "mov a,#_my_int" or "mov a,#(_my_int+1)"\r
28     - only used with moves to acc so chances to use: "inc dptr",\r
29       "inc r2", "add a,r2" or "mov r2,a" would not be detected)\r
30     - a label causes loss of tracking (no handling of information of blocks\r
31       known to follow/preceed the current block)\r
32     - not used in aopGet or genRet\r
33 -------------------------------------------------------------------------*/\r
34 \r
35 \r
36 #include <stdio.h>\r
37 #include <string.h>\r
38 #include "SDCCglobl.h"\r
39 \r
40 #include "common.h"\r
41 #include "ralloc.h"\r
42 #include "gen.h"\r
43 \r
44 #define DEBUG(x)\r
45 //#define DEBUG(x) x\r
46 \r
47 #define D(x) x\r
48 \r
49 #define REGS8051_SET(idx,val) do{ \\r
50                                   regs8051[idx].value = (val) & 0xff; \\r
51                                   regs8051[idx].valueKnown = 1; \\r
52                                   DEBUG(printf("%s:0x%02x\n",regs8051[idx].name, \\r
53                                                        regs8051[idx].value);) \\r
54                               } while(0)\r
55 \r
56 #define REGS8051_UNSET(idx)   do{ \\r
57                                   regs8051[idx].valueKnown = 0; \\r
58                                   DEBUG(printf("%s:*\n",regs8051[idx].name);) \\r
59                               } while(0)\r
60 \r
61 /* r0..r7 are not in numerical order in struct regs: r2..r7,r0,r1 */\r
62 #define Rx_NUM_TO_IDX(num) (R2_IDX+((num-2)&0x07))\r
63 \r
64 \r
65 /* move this (or rtrackGetLit() and rtrackMoveALit()\r
66    elsewhere? stealing emitcode from gen.c */\r
67 void emitcode (const char *inst, const char *fmt,...);\r
68 \r
69 \r
70 static int enable = -1;\r
71 \r
72 /*\r
73 static void dumpAll()\r
74 {\r
75   unsigned int i;\r
76   unsigned int nl=0;\r
77 \r
78   for (i=0; i<END_IDX; i++)\r
79     {\r
80        if (regs8051[i].valueKnown)\r
81          {\r
82            if (!nl)\r
83              {\r
84                DEBUG(printf("know:");)\r
85              }\r
86            DEBUG(printf(" %s:0x%02x",regs8051[i].name,regs8051[i].value);)\r
87            nl = 1;\r
88          }\r
89     }\r
90   if (nl)\r
91     {\r
92       DEBUG(printf("\n");)\r
93     }\r
94 }\r
95 */\r
96 \r
97 \r
98 static void invalidateAllRx()\r
99 {\r
100   //DEBUG(dumpAll();)\r
101   DEBUG(printf("R0..7:*\n");)\r
102   regs8051[R2_IDX].valueKnown = 0;\r
103   regs8051[R3_IDX].valueKnown = 0;\r
104   regs8051[R4_IDX].valueKnown = 0;\r
105   regs8051[R5_IDX].valueKnown = 0;\r
106   regs8051[R6_IDX].valueKnown = 0;\r
107   regs8051[R7_IDX].valueKnown = 0;\r
108   regs8051[R0_IDX].valueKnown = 0;\r
109   regs8051[R1_IDX].valueKnown = 0;\r
110 }\r
111 \r
112 static void invalidateAll()\r
113 {\r
114   DEBUG(printf("All:* ");)\r
115   invalidateAllRx();\r
116   regs8051[DPL_IDX].valueKnown = 0;\r
117   regs8051[DPH_IDX].valueKnown = 0;\r
118   regs8051[B_IDX].valueKnown = 0;\r
119   regs8051[A_IDX].valueKnown = 0;\r
120 }\r
121 \r
122 static regs * getReg(const char *str)\r
123 {\r
124   char *s;\r
125   int regNum;\r
126 \r
127   regNum = strtol (str, &s, 16);\r
128   if (s == str+1)\r
129     {\r
130       return &regs8051[Rx_NUM_TO_IDX(regNum)];\r
131     }\r
132   return NULL;\r
133 }\r
134 \r
135 /* tracking values within registers by looking\r
136    at the line passed to the assembler.\r
137    Tries to keep regs8051[] up to date */\r
138 void rtrackUpdate (const char *line)\r
139 {\r
140   if (enable == -1)\r
141     enable = (NULL != getenv("SDCC_RTRACK"));\r
142 \r
143   if (!enable ||\r
144       *line == ';' ||                 /* comment */\r
145       (NULL != strstr( line, "==."))) /* dirty check for _G.debugLine */\r
146     return;                           /* nothing to do */\r
147 \r
148   DEBUG(printf("%s\n",line);)\r
149 \r
150   if (!strncmp (line,"mov",3))\r
151     {\r
152       /* check literal mov to accumulator */\r
153       if(!strncmp (line,"mov\ta,#0x",9))\r
154         {\r
155           char *s;\r
156           int value;\r
157 \r
158           value = strtol (line+7, &s, 16);\r
159           if (s != line+7)\r
160               REGS8051_SET (A_IDX, value); /* valid hex found */\r
161           else\r
162               REGS8051_UNSET (A_IDX); /* probably a symbol (not handled) */\r
163 \r
164           return;\r
165         }\r
166 \r
167       if (!strncmp (line,"mov\ta,r",7))\r
168         {\r
169           /* handle mov from Rx if Rx is known */\r
170           regs *r = getReg(line+7);\r
171           if (r && r->valueKnown)\r
172             {\r
173               REGS8051_SET (A_IDX, r->value);\r
174               return;\r
175             }\r
176           REGS8051_UNSET (A_IDX);\r
177           return;\r
178         }\r
179 \r
180       if (!strncmp (line,"mov\ta",5))\r
181         {\r
182           REGS8051_UNSET (A_IDX);\r
183           return;\r
184         }\r
185 \r
186       if (!strncmp (line,"movc\ta",6) ||\r
187           !strncmp (line,"movx\ta",6))\r
188         {\r
189           REGS8051_UNSET (A_IDX);\r
190           return;\r
191         }\r
192 \r
193       /* move direct to symbol, do not care */\r
194       if (!strncmp (line,"mov\t_",5) ||\r
195           !strncmp (line,"mov\t(_",6))\r
196         return;\r
197 \r
198       /* check literal mov to register */\r
199       if (!strncmp (line,"mov\tr",5))\r
200         {\r
201           char *s;\r
202           int value;\r
203           int regNum;\r
204 \r
205           regNum = strtol (line+5, &s, 16);\r
206           if (s == line+6)\r
207             {\r
208               value = strtol (line+8, &s, 16);\r
209               if ((s != line+8) && !strncmp (line+6,",#0x",4))\r
210                 REGS8051_SET (Rx_NUM_TO_IDX(regNum), value);\r
211               else\r
212                 REGS8051_UNSET (Rx_NUM_TO_IDX(regNum));\r
213               return;\r
214             }\r
215         }\r
216 \r
217       /* mov to psw can change register bank */\r
218       if (!strncmp (line,"mov\tpsw,",8))\r
219         {\r
220           invalidateAllRx();\r
221           return;\r
222         }\r
223 \r
224       /* no tracking of these, so we do not care */\r
225       if (!strncmp (line,"mov\tdptr,#",10) ||\r
226           !strncmp (line,"mov\tdpl,",8) ||\r
227           !strncmp (line,"mov\tdph,",8) ||\r
228           !strncmp (line,"mov\tsp,",7) ||\r
229           !strncmp (line,"mov\tb,",6))\r
230         return;\r
231 \r
232       /* mov to xdata memory does not change registers */\r
233       if (!strncmp (line,"movx\t@",6))\r
234         return;\r
235 \r
236       if (!strncmp (line,"mov\t@",5))\r
237         {\r
238           invalidateAllRx();\r
239           return;\r
240         }\r
241     }\r
242 \r
243   /* no tracking of SP */\r
244   if (!strncmp (line,"push",4))\r
245     return;\r
246 \r
247   if (!strncmp (line,"pop\ta",5))\r
248     {\r
249       if (!strncmp (line+4,"acc",3)){ REGS8051_UNSET (A_IDX); return; }\r
250       if (!strncmp (line+4,"ar2",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (2)); return; }\r
251       if (!strncmp (line+4,"ar3",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (3)); return; }\r
252       if (!strncmp (line+4,"ar4",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (4)); return; }\r
253       if (!strncmp (line+4,"ar5",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (5)); return; }\r
254       if (!strncmp (line+4,"ar6",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (6)); return; }\r
255       if (!strncmp (line+4,"ar7",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (7)); return; }\r
256       if (!strncmp (line+4,"ar0",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (0)); return; }\r
257       if (!strncmp (line+4,"ar1",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (1)); return; }\r
258     }\r
259 \r
260   if (!strncmp (line,"inc",3))\r
261     {\r
262       /* no tracking of dptr, ignore */\r
263       if (!strcmp (line,"inc\tdptr") ||\r
264           !strcmp (line,"inc\tdph") ||\r
265           !strcmp (line,"inc\tdpl"))\r
266         return;\r
267 \r
268       if (!strcmp (line,"inc\ta"))\r
269         {\r
270           if (regs8051[A_IDX].valueKnown)\r
271             REGS8051_SET (A_IDX, regs8051[A_IDX].value+1);\r
272           return;\r
273         }\r
274 \r
275       if(!strncmp (line,"inc\tr",5))\r
276         {\r
277           regs *r = getReg(line+5);\r
278           if (r && r->valueKnown)\r
279             {\r
280               REGS8051_SET (r->rIdx, r->value+1);\r
281             }\r
282           return;\r
283         }\r
284     }\r
285 \r
286   /* some bit in acc is cleared\r
287      MB: I'm too lazy to find out which right now */\r
288   if (!strncmp (line,"jbc\tacc",7))\r
289     {\r
290       REGS8051_UNSET (A_IDX);\r
291       return;\r
292     }\r
293 \r
294   /* unfortunately the label typically following these\r
295      will cause loss of tracking */\r
296   if (!strncmp (line,"jc\t",3) ||\r
297       !strncmp (line,"jnc\t",4) ||\r
298       !strncmp (line,"jb\t",3) ||\r
299       !strncmp (line,"jnb\t",4) ||\r
300       !strncmp (line,"jbc\t",4))\r
301     return;\r
302 \r
303   /* if branch not taken in "cjne r2,#0x08,somewhere" \r
304      r2 is known to be 8 */\r
305   if (!strncmp (line,"cjne",4))\r
306     {\r
307       if(!strncmp (line,"cjne\ta,#0x",10))\r
308         {\r
309           char *s;\r
310           int value;\r
311 \r
312           value = strtol (line+8, &s, 16);\r
313           if (s != line+8)\r
314               REGS8051_SET (A_IDX, value); /* valid hex found */\r
315         }\r
316       if(!strncmp (line,"cjne\tr",6))\r
317         {\r
318           char *s;\r
319           int value;\r
320           regs *r = getReg(line+6);\r
321           value = strtol (line+8, &s, 16);\r
322           if (r && s != line+8)\r
323               REGS8051_SET (r->rIdx, value); /* valid hex found */\r
324         }\r
325       return;\r
326     }\r
327 \r
328   /* acc eventually known to be zero */\r
329   if (!strncmp (line,"jz\t",3))\r
330     return;\r
331 \r
332   /* acc eventually known to be zero */\r
333   if (!strncmp (line,"jnz\t",4))\r
334     {\r
335       REGS8051_SET (A_IDX, 0x00); // branch not taken\r
336       return;\r
337     }\r
338 \r
339   if (!strncmp (line,"djnz\tr",6))\r
340     {\r
341       char *s;\r
342       int regNum;\r
343 \r
344       regNum = strtol (line+6, &s, 16);\r
345       if (s == line+7)\r
346         {\r
347           //REGS8051_UNSET (Rx_NUM_TO_IDX(regNum));\r
348           REGS8051_SET (Rx_NUM_TO_IDX(regNum), 0x00); // branch not taken\r
349           return;\r
350         }\r
351     }\r
352 \r
353   /* only carry bit, so we do not care */\r
354   if (!strncmp (line,"setb\tc",6) ||\r
355       !strncmp (line,"clr\tc",5) ||\r
356       !strncmp (line,"cpl\tc",5))\r
357     return;\r
358 \r
359   if (!strncmp (line,"add\ta,",6) ||\r
360       !strncmp (line,"addc\ta,",7)||\r
361       !strncmp (line,"subb\ta,",7)||\r
362       !strncmp (line,"xrl\ta,",6) ||\r
363       !strncmp (line,"orl\ta,",6) ||\r
364       !strncmp (line,"anl\ta,",6) ||\r
365       !strncmp (line,"da\ta",4)   ||\r
366       !strncmp (line,"rlc\ta,",6) ||\r
367       !strncmp (line,"rrc\ta,",6) ||\r
368       !strncmp (line,"setb\ta",6) ||\r
369       !strncmp (line,"clrb\ta,",7)||\r
370       !strncmp (line,"cpl\tacc",7))\r
371     {\r
372       /* could also handle f.e. "add a,Rx" if a, Rx are known or "xrl a,#0x08" */\r
373       REGS8051_UNSET (A_IDX);\r
374       return;\r
375     }\r
376 \r
377 \r
378   if (!strncmp (line,"dec",3))\r
379     {\r
380       /* no tracking of dptr, so we would not care */\r
381       if (!strcmp (line,"dec\tdph") ||\r
382           !strcmp (line,"dec\tdpl"))\r
383         return;\r
384 \r
385       if (!strcmp (line,"dec\ta"))\r
386         {\r
387           if (regs8051[A_IDX].valueKnown)\r
388             REGS8051_SET (A_IDX, regs8051[A_IDX].value-1);\r
389           return;\r
390         }\r
391 \r
392       if(!strncmp (line,"dec\tr",5))\r
393         {\r
394           regs *r = getReg(line+5);\r
395           if (r && r->valueKnown)\r
396             {\r
397               REGS8051_SET (r->rIdx, r->value-1);\r
398             }\r
399           return;\r
400         }\r
401     }\r
402 \r
403 \r
404   if (!strcmp (line,"clr\ta"))\r
405     {\r
406       REGS8051_SET (A_IDX, 0);\r
407       return;\r
408     }\r
409 \r
410   if (!strcmp (line,"cpl\ta"))\r
411     {\r
412       if (regs8051[A_IDX].valueKnown)\r
413         REGS8051_SET (A_IDX, ~regs8051[A_IDX].value);\r
414       return;\r
415     }\r
416   if (!strcmp (line,"rl\ta"))\r
417     {\r
418       if (regs8051[A_IDX].valueKnown)\r
419         REGS8051_SET (A_IDX, (regs8051[A_IDX].value<<1) | \r
420                              (regs8051[A_IDX].value>>7) );\r
421       return;\r
422     }\r
423   if (!strcmp (line,"rr\ta"))\r
424     {\r
425       if (regs8051[A_IDX].valueKnown)\r
426         REGS8051_SET (A_IDX, (regs8051[A_IDX].value>>1) |\r
427                              (regs8051[A_IDX].value<<7));\r
428       return;\r
429     }\r
430   if (!strcmp (line,"swap\ta"))\r
431     {\r
432       if (regs8051[A_IDX].valueKnown)\r
433         REGS8051_SET (A_IDX, (regs8051[A_IDX].value>>4) |\r
434                              (regs8051[A_IDX].value<<4));\r
435       return;\r
436     }\r
437 \r
438   if (!strncmp (line,"mul",3) ||\r
439       !strncmp (line,"div",3)\r
440       )\r
441     {\r
442       REGS8051_UNSET (A_IDX);\r
443       REGS8051_UNSET (B_IDX);\r
444       return;\r
445     }\r
446 \r
447   /* assuming these library functions have no side-effects */\r
448   if (!strcmp (line,"lcall"))\r
449     {\r
450       if (!strcmp (line,"lcall\t__gptrput"))\r
451         {\r
452           /* invalidate R0..R7 because they might have been changed */\r
453           /* MB: too paranoid ? */\r
454           //invalidateAllRx();\r
455           return;\r
456         }\r
457       if (!strcmp (line,"lcall\t__gptrget"))\r
458         {\r
459           REGS8051_UNSET (A_IDX);\r
460           return;\r
461         }\r
462       if (!strcmp (line,"lcall\t__decdptr"))\r
463         {\r
464           return;\r
465         }\r
466      }\r
467 \r
468   if (!strncmp (line,"xch\ta,r",7))\r
469     {\r
470       /* handle xch acc with Rn */\r
471       regs *r = getReg(line+7);\r
472       if (r)\r
473         {\r
474           unsigned swap;\r
475           swap = r->valueKnown;\r
476           r->valueKnown = regs8051[A_IDX].valueKnown;\r
477           regs8051[A_IDX].valueKnown = swap;\r
478 \r
479           swap = r->value;\r
480           r->value = regs8051[A_IDX].value;\r
481           regs8051[A_IDX].value = swap;\r
482           return;\r
483         }\r
484     }\r
485 \r
486   /* all others unrecognized, invalidate */\r
487   invalidateAll();\r
488 }\r
489 \r
490 \r
491 /* expects f.e. "#0x01" and returns either "#0x01"\r
492    if the value is not known to be within registers\r
493    or "a" or "r0".."r7".\r
494    (mov a,r7 or add a,r7 need one byte whereas\r
495     mov a,#0x01 or add a,#0x01 would take two\r
496  */\r
497 char * rtrackGetLit(const char *x)\r
498 {\r
499   unsigned int i;\r
500 \r
501   char *s;\r
502 \r
503   if (enable != 1)\r
504     return (char *)x;\r
505 \r
506   /* was it a numerical literal? */\r
507   if (*x == '#')\r
508     {\r
509       int val = strtol (x+1, &s, 16);\r
510       if (x+1 != s)\r
511         {\r
512           /* try to get from acc */\r
513           regs *r = &regs8051[A_IDX];\r
514           if (r->valueKnown &&\r
515               r->value == val)\r
516             {\r
517               D(emitcode (";", "genFromRTrack 0x%02x=%s", val, r->name));\r
518               return r->name;\r
519             }\r
520           /* try to get from register R0..R7 */\r
521           for (i=0; i<8; i++)\r
522             {\r
523               regs *r = &regs8051[Rx_NUM_TO_IDX(i)];\r
524               if (r->valueKnown &&\r
525                   r->value == val)\r
526                 {\r
527                   D(emitcode (";", "genFromRTrack 0x%02x=%s", val, r->name));\r
528                   return r->name;\r
529                 }\r
530             }\r
531         }\r
532       else\r
533         {\r
534           /* probably a symbolic literal as in "mov r3,#(_i+1)",\r
535              not handled... */\r
536         }\r
537     }\r
538 \r
539   return (char *)x;\r
540 }\r
541 \r
542 /* Similar to the above function \r
543    As the destination is the accumulator try harder yet and\r
544    try to generate the result with arithmetic operations */\r
545 int rtrackMoveALit (const char *x)\r
546 {\r
547 \r
548   if (enable != 1)\r
549     return 0;\r
550 \r
551   /* if it is a literal mov try to get it cheaper */\r
552   if ( *x == '#' )\r
553     {\r
554       regs *a = &regs8051[A_IDX];\r
555 \r
556       char *s;\r
557       int val = strtol (x+1, &s, 16);\r
558 \r
559       /* was it a numerical literal? */\r
560       if (x+1 != s)\r
561         {\r
562           /* prefer mov a,#0x00 */\r
563           if (val == 0 &&\r
564               ((a->valueKnown && a->value != 0) ||\r
565                !a->valueKnown))\r
566             {\r
567               /* peepholes convert to clr a */\r
568               /* MB: why not here ? */\r
569               emitcode ("mov", "a,#0x00");\r
570               return 1;\r
571             }\r
572 \r
573           if (a->valueKnown)\r
574             {\r
575               /* already there? */\r
576               if (val == a->value)\r
577                 {\r
578                   D(emitcode (";", "genFromRTrack acc=0x%02x", a->value));\r
579                   return 1;\r
580                 }\r
581 \r
582               /* can be calculated with an instruction\r
583                  that does not change flags from acc itself? */\r
584               if (val == ((a->value+1) & 0xff) )\r
585                 {\r
586                   D(emitcode (";", "genFromRTrack 0x%02x=0x%02x+1", val, a->value));\r
587                   emitcode ("inc", "a");\r
588                   return 1;\r
589                 }\r
590               if (val == ((a->value-1) & 0xff) )\r
591                 {\r
592                   D(emitcode (";", "genFromRTrack 0x%02x=0x%02x-1", val, a->value));\r
593                   emitcode ("dec", "a");\r
594                   return 1;\r
595                 }\r
596               if (val == ((~a->value) & 0xff) )\r
597                 {\r
598                   D(emitcode (";", "genFromRTrack 0x%02x=~0x%02x", val, a->value));\r
599                   emitcode ("cpl", "a");\r
600                   return 1;\r
601                 }\r
602               if (val == (((a->value>>1) |\r
603                            (a->value<<7)) & 0xff))\r
604                 {\r
605                   D(emitcode (";", "genFromRTrack 0x%02x=rr(0x%02x)", val, a->value));\r
606                   emitcode ("rr", "a");\r
607                   return 1;\r
608                 }\r
609               if (val == (((a->value<<1) |\r
610                            (a->value>>7)) & 0xff ))\r
611                 {\r
612                   D(emitcode (";", "genFromRTrack 0x%02x=rl(0x%02x)", val, a->value));\r
613                   emitcode ("rl", "a");\r
614                   return 1;\r
615                 }\r
616               if (val == ( ((a->value & 0x0f)<<4) |\r
617                            ((a->value & 0xf0)>>4) ))\r
618                 {\r
619                   D(emitcode (";", "genFromRTrack 0x%02x=swap(0x%02x)", val, a->value));\r
620                   emitcode ("swap", "a");\r
621                   return 1;\r
622                 }\r
623               /* Decimal Adjust Accumulator (da a) changes flags so not used */\r
624             }\r
625 \r
626 \r
627           {\r
628             unsigned int i;\r
629             char *ptr= rtrackGetLit(x);\r
630 \r
631             if (x != ptr)\r
632               {\r
633                 /* could get from register, fine */\r
634                 emitcode ("mov", "a,%s", ptr);\r
635                 return 1;\r
636               }\r
637 \r
638             /* not yet giving up - try to calculate from register R0..R7 */\r
639             for (i=0; i<8; i++)\r
640               {\r
641                 regs *r = &regs8051[Rx_NUM_TO_IDX(i)];\r
642 \r
643                 if (a->valueKnown && r->valueKnown)\r
644                   {\r
645                     /* calculate with a single byte instruction from R0..R7? */\r
646                     if (val == (a->value | r->value))\r
647                       {\r
648                         D(emitcode (";", "genFromRTrack 0x%02x=0x%02x|0x%02x",\r
649                                     val, a->value, r->value));\r
650                         emitcode ("orl", "a,%s",r->name);\r
651                         return 1;\r
652                       }\r
653                     if (val == (a->value & r->value))\r
654                       {\r
655                         D(emitcode (";", "genFromRTrack 0x%02x=0x%02x&0x%02x",\r
656                                     val, a->value, r->value));\r
657                         emitcode ("anl", "a,%s", r->name);\r
658                         return 1;\r
659                       }\r
660                     if (val == (a->value ^ r->value))\r
661                       {\r
662                         D(emitcode (";", "genFromRTrack 0x%02x=0x%02x^0x%02x",\r
663                                     val, a->value, r->value));\r
664                         emitcode ("xrl", "a,%s", r->name);\r
665                         return 1;\r
666                       }\r
667                     /* changes flags (does that matter?)\r
668                     if (val == (a->value + r->value))\r
669                       {\r
670                         D(emitcode (";", "genFromRTrack 0x%02x=0x%02x+%0x02x",\r
671                                     val, a->value, r->value));\r
672                         emitcode ("add", "a,%s",r->name);\r
673                         return 1;\r
674                       }\r
675                     so not used */\r
676                   }\r
677               }\r
678           }\r
679       }\r
680     }\r
681 \r
682   return 0;\r
683 }\r
684 \r