1 /*-------------------------------------------------------------------------
3 pcode.c - post code generation
5 Written By - Scott Dattalo scott@dattalo.com
6 Ported to PIC16 By - Martin Dubuc m.dubuc@rogers.com
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 -------------------------------------------------------------------------*/
25 #include "common.h" // Include everything in the SDCC src directory
31 #include "pcodeflow.h"
35 #if defined(__BORLANDC__) || defined(_MSC_VER)
36 #define STRCASECMP stricmp
39 #define STRCASECMP strcasecmp
42 #define DUMP_DF_GRAPHS 0
44 /****************************************************************/
45 /****************************************************************/
47 static peepCommand peepCommands[] = {
49 {NOTBITSKIP, "_NOTBITSKIP_"},
50 {BITSKIP, "_BITSKIP_"},
51 {INVERTBITSKIP, "_INVERTBITSKIP_"},
58 // Eventually this will go into device dependent files:
59 pCodeOpReg pic16_pc_status = {{PO_STATUS, "STATUS"}, -1, NULL,0,NULL};
60 pCodeOpReg pic16_pc_intcon = {{PO_INTCON, "INTCON"}, -1, NULL,0,NULL};
61 pCodeOpReg pic16_pc_pcl = {{PO_PCL, "PCL"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_pclath = {{PO_PCLATH, "PCLATH"}, -1, NULL,0,NULL};
63 pCodeOpReg pic16_pc_pclatu = {{PO_PCLATU, "PCLATU"}, -1, NULL,0,NULL}; // patch 14
64 pCodeOpReg pic16_pc_wreg = {{PO_WREG, "WREG"}, -1, NULL,0,NULL};
65 pCodeOpReg pic16_pc_bsr = {{PO_BSR, "BSR"}, -1, NULL,0,NULL};
67 pCodeOpReg pic16_pc_tosl = {{PO_SFR_REGISTER, "TOSL"}, -1, NULL,0,NULL}; // patch 14
68 pCodeOpReg pic16_pc_tosh = {{PO_SFR_REGISTER, "TOSH"}, -1, NULL,0,NULL}; //
69 pCodeOpReg pic16_pc_tosu = {{PO_SFR_REGISTER, "TOSU"}, -1, NULL,0,NULL}; // patch 14
71 pCodeOpReg pic16_pc_tblptrl = {{PO_SFR_REGISTER, "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
72 pCodeOpReg pic16_pc_tblptrh = {{PO_SFR_REGISTER, "TBLPTRH"}, -1, NULL,0,NULL}; //
73 pCodeOpReg pic16_pc_tblptru = {{PO_SFR_REGISTER, "TBLPTRU"}, -1, NULL,0,NULL}; //
74 pCodeOpReg pic16_pc_tablat = {{PO_SFR_REGISTER, "TABLAT"}, -1, NULL,0,NULL}; // patch 15
76 //pCodeOpReg pic16_pc_fsr0 = {{PO_FSR0, "FSR0"}, -1, NULL,0,NULL}; //deprecated !
78 pCodeOpReg pic16_pc_fsr0l = {{PO_FSR0, "FSR0L"}, -1, NULL, 0, NULL};
79 pCodeOpReg pic16_pc_fsr0h = {{PO_FSR0, "FSR0H"}, -1, NULL, 0, NULL};
80 pCodeOpReg pic16_pc_fsr1l = {{PO_FSR0, "FSR1L"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr1h = {{PO_FSR0, "FSR1H"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr2l = {{PO_FSR0, "FSR2L"}, -1, NULL, 0, NULL};
83 pCodeOpReg pic16_pc_fsr2h = {{PO_FSR0, "FSR2H"}, -1, NULL, 0, NULL};
85 pCodeOpReg pic16_pc_indf0 = {{PO_INDF0, "INDF0"}, -1, NULL,0,NULL};
86 pCodeOpReg pic16_pc_postinc0 = {{PO_INDF0, "POSTINC0"}, -1, NULL, 0, NULL};
87 pCodeOpReg pic16_pc_postdec0 = {{PO_INDF0, "POSTDEC0"}, -1, NULL, 0, NULL};
88 pCodeOpReg pic16_pc_preinc0 = {{PO_INDF0, "PREINC0"}, -1, NULL, 0, NULL};
89 pCodeOpReg pic16_pc_plusw0 = {{PO_INDF0, "PLUSW0"}, -1, NULL, 0, NULL};
91 pCodeOpReg pic16_pc_indf1 = {{PO_INDF0, "INDF1"}, -1, NULL,0,NULL};
92 pCodeOpReg pic16_pc_postinc1 = {{PO_INDF0, "POSTINC1"}, -1, NULL, 0, NULL};
93 pCodeOpReg pic16_pc_postdec1 = {{PO_INDF0, "POSTDEC1"}, -1, NULL, 0, NULL};
94 pCodeOpReg pic16_pc_preinc1 = {{PO_INDF0, "PREINC1"}, -1, NULL, 0, NULL};
95 pCodeOpReg pic16_pc_plusw1 = {{PO_INDF0, "PLUSW1"}, -1, NULL, 0, NULL};
97 pCodeOpReg pic16_pc_indf2 = {{PO_INDF0, "INDF2"}, -1, NULL,0,NULL};
98 pCodeOpReg pic16_pc_postinc2 = {{PO_INDF0, "POSTINC2"}, -1, NULL, 0, NULL};
99 pCodeOpReg pic16_pc_postdec2 = {{PO_INDF0, "POSTDEC2"}, -1, NULL, 0, NULL};
100 pCodeOpReg pic16_pc_preinc2 = {{PO_INDF0, "PREINC2"}, -1, NULL, 0, NULL};
101 pCodeOpReg pic16_pc_plusw2 = {{PO_INDF0, "PLUSW2"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_prodl = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
104 pCodeOpReg pic16_pc_prodh = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
106 /* EEPROM registers */
107 pCodeOpReg pic16_pc_eecon1 = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
108 pCodeOpReg pic16_pc_eecon2 = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
109 pCodeOpReg pic16_pc_eedata = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
110 pCodeOpReg pic16_pc_eeadr = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
112 pCodeOpReg pic16_pc_kzero = {{PO_GPR_REGISTER, "KZ"}, -1, NULL,0,NULL};
113 pCodeOpReg pic16_pc_wsave = {{PO_GPR_REGISTER, "WSAVE"}, -1, NULL,0,NULL};
114 pCodeOpReg pic16_pc_ssave = {{PO_GPR_REGISTER, "SSAVE"}, -1, NULL,0,NULL};
116 pCodeOpReg *pic16_stackpnt_lo;
117 pCodeOpReg *pic16_stackpnt_hi;
118 pCodeOpReg *pic16_stack_postinc;
119 pCodeOpReg *pic16_stack_postdec;
120 pCodeOpReg *pic16_stack_preinc;
121 pCodeOpReg *pic16_stack_plusw;
123 pCodeOpReg *pic16_framepnt_lo;
124 pCodeOpReg *pic16_framepnt_hi;
125 pCodeOpReg *pic16_frame_postinc;
126 pCodeOpReg *pic16_frame_postdec;
127 pCodeOpReg *pic16_frame_preinc;
128 pCodeOpReg *pic16_frame_plusw;
130 pCodeOpReg pic16_pc_gpsimio = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
131 pCodeOpReg pic16_pc_gpsimio2 = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
133 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
134 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
137 static int mnemonics_initialized = 0;
140 static hTab *pic16MnemonicsHash = NULL;
141 static hTab *pic16pCodePeepCommandsHash = NULL;
143 static pFile *the_pFile = NULL;
144 static pBlock *pb_dead_pcodes = NULL;
146 /* Hardcoded flags to change the behavior of the PIC port */
147 static int peepOptimizing = 1; /* run the peephole optimizer if nonzero */
148 static int functionInlining = 1; /* inline functions if nonzero */
149 int pic16_debug_verbose = 0; /* Set true to inundate .asm file */
151 int pic16_pcode_verbose = 0;
153 //static int GpCodeSequenceNumber = 1;
154 static int GpcFlowSeq = 1;
156 extern void pic16_RemoveUnusedRegisters(void);
157 extern void pic16_RegsUnMapLiveRanges(void);
158 extern void pic16_BuildFlowTree(pBlock *pb);
159 extern void pic16_pCodeRegOptimizeRegUsage(int level);
160 extern int pic16_picIsInitialized(void);
161 extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
162 extern int mnem2key(char const *mnem);
164 /****************************************************************/
165 /* Forward declarations */
166 /****************************************************************/
168 void pic16_unlinkpCode(pCode *pc);
170 static void genericAnalyze(pCode *pc);
171 static void AnalyzeGOTO(pCode *pc);
172 static void AnalyzeSKIP(pCode *pc);
173 static void AnalyzeRETURN(pCode *pc);
176 static void genericDestruct(pCode *pc);
177 static void genericPrint(FILE *of,pCode *pc);
179 static void pCodePrintLabel(FILE *of, pCode *pc);
180 static void pCodePrintFunction(FILE *of, pCode *pc);
181 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
182 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
183 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
184 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
185 int pic16_pCodePeepMatchRule(pCode *pc);
186 static void pBlockStats(FILE *of, pBlock *pb);
187 static pBlock *newpBlock(void);
188 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
189 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
190 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
191 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
192 void OptimizeLocalRegs(void);
193 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
195 char *dumpPicOptype(PIC_OPTYPE type);
197 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
198 pCodeOp *pic16_popGetLit(int);
199 pCodeOp *pic16_popGetWithString(char *);
200 extern int inWparamList(char *s);
202 /** data flow optimization helpers **/
203 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
204 static void pic16_vcg_dump (FILE *of, pBlock *pb);
205 static void pic16_vcg_dump_default (pBlock *pb);
207 static int pic16_pCodeIsAlive (pCode *pc);
208 static void pic16_df_stats ();
209 static void pic16_createDF (pBlock *pb);
210 static int pic16_removeUnusedRegistersDF ();
211 static void pic16_destructDF (pBlock *pb);
212 static void releaseStack ();
214 /****************************************************************/
215 /* PIC Instructions */
216 /****************************************************************/
218 pCodeInstruction pic16_pciADDWF = {
219 {PC_OPCODE, NULL, NULL, 0, NULL,
233 1,0, // dest, bit instruction
235 0, // literal operand
237 0, // fast call/return mode select bit
238 0, // second memory operand
239 0, // second literal operand
241 (PCC_W | PCC_REGISTER), // inCond
242 (PCC_REGISTER | PCC_STATUS), // outCond
246 pCodeInstruction pic16_pciADDFW = {
247 {PC_OPCODE, NULL, NULL, 0, NULL,
261 0,0, // dest, bit instruction
263 0, // literal operand
265 0, // fast call/return mode select bit
266 0, // second memory operand
267 0, // second literal operand
269 (PCC_W | PCC_REGISTER), // inCond
270 (PCC_W | PCC_STATUS), // outCond
274 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
275 {PC_OPCODE, NULL, NULL, 0, NULL,
289 1,0, // dest, bit instruction
291 0, // literal operand
293 0, // fast call/return mode select bit
294 0, // second memory operand
295 0, // second literal operand
297 (PCC_W | PCC_REGISTER | PCC_C), // inCond
298 (PCC_REGISTER | PCC_STATUS), // outCond
302 pCodeInstruction pic16_pciADDFWC = {
303 {PC_OPCODE, NULL, NULL, 0, NULL,
317 0,0, // dest, bit instruction
319 0, // literal operand
321 0, // fast call/return mode select bit
322 0, // second memory operand
323 0, // second literal operand
325 (PCC_W | PCC_REGISTER | PCC_C), // inCond
326 (PCC_W | PCC_STATUS), // outCond
330 pCodeInstruction pic16_pciADDLW = {
331 {PC_OPCODE, NULL, NULL, 0, NULL,
345 0,0, // dest, bit instruction
347 1, // literal operand
349 0, // fast call/return mode select bit
350 0, // second memory operand
351 0, // second literal operand
353 (PCC_W | PCC_LITERAL), // inCond
354 (PCC_W | PCC_STATUS), // outCond
358 pCodeInstruction pic16_pciANDLW = {
359 {PC_OPCODE, NULL, NULL, 0, NULL,
373 0,0, // dest, bit instruction
375 1, // literal operand
377 0, // fast call/return mode select bit
378 0, // second memory operand
379 0, // second literal operand
381 (PCC_W | PCC_LITERAL), // inCond
382 (PCC_W | PCC_Z | PCC_N), // outCond
386 pCodeInstruction pic16_pciANDWF = {
387 {PC_OPCODE, NULL, NULL, 0, NULL,
401 1,0, // dest, bit instruction
403 0, // literal operand
405 0, // fast call/return mode select bit
406 0, // second memory operand
407 0, // second literal operand
409 (PCC_W | PCC_REGISTER), // inCond
410 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
414 pCodeInstruction pic16_pciANDFW = {
415 {PC_OPCODE, NULL, NULL, 0, NULL,
429 0,0, // dest, bit instruction
431 0, // literal operand
433 0, // fast call/return mode select bit
434 0, // second memory operand
435 0, // second literal operand
437 (PCC_W | PCC_REGISTER), // inCond
438 (PCC_W | PCC_Z | PCC_N) // outCond
441 pCodeInstruction pic16_pciBC = { // mdubuc - New
442 {PC_OPCODE, NULL, NULL, 0, NULL,
456 0,0, // dest, bit instruction
458 0, // literal operand
460 0, // fast call/return mode select bit
461 0, // second memory operand
462 0, // second literal operand
464 (PCC_REL_ADDR | PCC_C), // inCond
469 pCodeInstruction pic16_pciBCF = {
470 {PC_OPCODE, NULL, NULL, 0, NULL,
484 1,1, // dest, bit instruction
486 0, // literal operand
488 0, // fast call/return mode select bit
489 0, // second memory operand
490 0, // second literal operand
492 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
493 PCC_REGISTER, // outCond
497 pCodeInstruction pic16_pciBN = { // mdubuc - New
498 {PC_OPCODE, NULL, NULL, 0, NULL,
512 0,0, // dest, bit instruction
514 0, // literal operand
516 0, // fast call/return mode select bit
517 0, // second memory operand
518 0, // second literal operand
520 (PCC_REL_ADDR | PCC_N), // inCond
521 PCC_NONE , // outCond
525 pCodeInstruction pic16_pciBNC = { // mdubuc - New
526 {PC_OPCODE, NULL, NULL, 0, NULL,
540 0,0, // dest, bit instruction
542 0, // literal operand
544 0, // fast call/return mode select bit
545 0, // second memory operand
546 0, // second literal operand
548 (PCC_REL_ADDR | PCC_C), // inCond
549 PCC_NONE , // outCond
553 pCodeInstruction pic16_pciBNN = { // mdubuc - New
554 {PC_OPCODE, NULL, NULL, 0, NULL,
568 0,0, // dest, bit instruction
570 0, // literal operand
572 0, // fast call/return mode select bit
573 0, // second memory operand
574 0, // second literal operand
576 (PCC_REL_ADDR | PCC_N), // inCond
577 PCC_NONE , // outCond
581 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
582 {PC_OPCODE, NULL, NULL, 0, NULL,
596 0,0, // dest, bit instruction
598 0, // literal operand
600 0, // fast call/return mode select bit
601 0, // second memory operand
602 0, // second literal operand
604 (PCC_REL_ADDR | PCC_OV), // inCond
605 PCC_NONE , // outCond
609 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
610 {PC_OPCODE, NULL, NULL, 0, NULL,
624 0,0, // dest, bit instruction
626 0, // literal operand
628 0, // fast call/return mode select bit
629 0, // second memory operand
630 0, // second literal operand
632 (PCC_REL_ADDR | PCC_Z), // inCond
633 PCC_NONE , // outCond
637 pCodeInstruction pic16_pciBOV = { // mdubuc - New
638 {PC_OPCODE, NULL, NULL, 0, NULL,
652 0,0, // dest, bit instruction
654 0, // literal operand
656 0, // fast call/return mode select bit
657 0, // second memory operand
658 0, // second literal operand
660 (PCC_REL_ADDR | PCC_OV), // inCond
661 PCC_NONE , // outCond
665 pCodeInstruction pic16_pciBRA = { // mdubuc - New
666 {PC_OPCODE, NULL, NULL, 0, NULL,
680 0,0, // dest, bit instruction
682 0, // literal operand
684 0, // fast call/return mode select bit
685 0, // second memory operand
686 0, // second literal operand
688 PCC_REL_ADDR, // inCond
689 PCC_NONE , // outCond
693 pCodeInstruction pic16_pciBSF = {
694 {PC_OPCODE, NULL, NULL, 0, NULL,
708 1,1, // dest, bit instruction
710 0, // literal operand
712 0, // fast call/return mode select bit
713 0, // second memory operand
714 0, // second literal operand
716 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
717 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
721 pCodeInstruction pic16_pciBTFSC = {
722 {PC_OPCODE, NULL, NULL, 0, NULL,
736 0,1, // dest, bit instruction
738 0, // literal operand
740 0, // fast call/return mode select bit
741 0, // second memory operand
742 0, // second literal operand
744 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
745 PCC_EXAMINE_PCOP, // outCond
749 pCodeInstruction pic16_pciBTFSS = {
750 {PC_OPCODE, NULL, NULL, 0, NULL,
764 0,1, // dest, bit instruction
766 0, // literal operand
768 0, // fast call/return mode select bit
769 0, // second memory operand
770 0, // second literal operand
772 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
773 PCC_EXAMINE_PCOP, // outCond
777 pCodeInstruction pic16_pciBTG = { // mdubuc - New
778 {PC_OPCODE, NULL, NULL, 0, NULL,
792 0,1, // dest, bit instruction
794 0, // literal operand
796 0, // fast call/return mode select bit
797 0, // second memory operand
798 0, // second literal operand
800 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
801 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
805 pCodeInstruction pic16_pciBZ = { // mdubuc - New
806 {PC_OPCODE, NULL, NULL, 0, NULL,
820 0,0, // dest, bit instruction
822 0, // literal operand
824 0, // fast call/return mode select bit
825 0, // second memory operand
826 0, // second literal operand
828 (PCC_REL_ADDR | PCC_Z), // inCond
833 pCodeInstruction pic16_pciCALL = {
834 {PC_OPCODE, NULL, NULL, 0, NULL,
848 0,0, // dest, bit instruction
850 0, // literal operand
852 1, // fast call/return mode select bit
853 0, // second memory operand
854 0, // second literal operand
861 pCodeInstruction pic16_pciCOMF = {
862 {PC_OPCODE, NULL, NULL, 0, NULL,
876 1,0, // dest, bit instruction
878 0, // literal operand
880 0, // fast call/return mode select bit
881 0, // second memory operand
882 0, // second literal operand
884 PCC_REGISTER, // inCond
885 (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
889 pCodeInstruction pic16_pciCOMFW = {
890 {PC_OPCODE, NULL, NULL, 0, NULL,
904 0,0, // dest, bit instruction
906 0, // literal operand
908 0, // fast call/return mode select bit
909 0, // second memory operand
910 0, // second literal operand
912 PCC_REGISTER, // inCond
913 (PCC_W | PCC_Z | PCC_N) , // outCond
917 pCodeInstruction pic16_pciCLRF = {
918 {PC_OPCODE, NULL, NULL, 0, NULL,
932 0,0, // dest, bit instruction
934 0, // literal operand
936 0, // fast call/return mode select bit
937 0, // second memory operand
938 0, // second literal operand
941 (PCC_REGISTER | PCC_Z), // outCond
945 pCodeInstruction pic16_pciCLRWDT = {
946 {PC_OPCODE, NULL, NULL, 0, NULL,
960 0,0, // dest, bit instruction
962 0, // literal operand
964 0, // fast call/return mode select bit
965 0, // second memory operand
966 0, // second literal operand
969 PCC_NONE , // outCond
973 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
974 {PC_OPCODE, NULL, NULL, 0, NULL,
988 0,0, // dest, bit instruction
990 0, // literal operand
992 0, // fast call/return mode select bit
993 0, // second memory operand
994 0, // second literal operand
996 (PCC_W | PCC_REGISTER), // inCond
997 PCC_NONE , // outCond
1001 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1002 {PC_OPCODE, NULL, NULL, 0, NULL,
1009 NULL, // from branch
1016 0,0, // dest, bit instruction
1017 1,1, // branch, skip
1018 0, // literal operand
1019 1, // RAM access bit
1020 0, // fast call/return mode select bit
1021 0, // second memory operand
1022 0, // second literal operand
1024 (PCC_W | PCC_REGISTER), // inCond
1025 PCC_NONE , // outCond
1029 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1030 {PC_OPCODE, NULL, NULL, 0, NULL,
1037 NULL, // from branch
1044 1,0, // dest, bit instruction
1045 1,1, // branch, skip
1046 0, // literal operand
1047 1, // RAM access bit
1048 0, // fast call/return mode select bit
1049 0, // second memory operand
1050 0, // second literal operand
1052 (PCC_W | PCC_REGISTER), // inCond
1053 PCC_NONE , // outCond
1057 pCodeInstruction pic16_pciDAW = {
1058 {PC_OPCODE, NULL, NULL, 0, NULL,
1065 NULL, // from branch
1072 0,0, // dest, bit instruction
1073 0,0, // branch, skip
1074 0, // literal operand
1075 0, // RAM access bit
1076 0, // fast call/return mode select bit
1077 0, // second memory operand
1078 0, // second literal operand
1081 (PCC_W | PCC_C), // outCond
1085 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1086 {PC_OPCODE, NULL, NULL, 0, NULL,
1093 NULL, // from branch
1100 1,0, // dest, bit instruction
1101 1,1, // branch, skip
1102 0, // literal operand
1103 1, // RAM access bit
1104 0, // fast call/return mode select bit
1105 0, // second memory operand
1106 0, // second literal operand
1108 PCC_REGISTER, // inCond
1109 PCC_REGISTER , // outCond
1113 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1114 {PC_OPCODE, NULL, NULL, 0, NULL,
1121 NULL, // from branch
1128 0,0, // dest, bit instruction
1129 1,1, // branch, skip
1130 0, // literal operand
1131 1, // RAM access bit
1132 0, // fast call/return mode select bit
1133 0, // second memory operand
1134 0, // second literal operand
1136 PCC_REGISTER, // inCond
1141 pCodeInstruction pic16_pciDECF = {
1142 {PC_OPCODE, NULL, NULL, 0, NULL,
1149 NULL, // from branch
1156 1,0, // dest, bit instruction
1157 0,0, // branch, skip
1158 0, // literal operand
1159 1, // RAM access bit
1160 0, // fast call/return mode select bit
1161 0, // second memory operand
1162 0, // second literal operand
1164 PCC_REGISTER, // inCond
1165 (PCC_REGISTER | PCC_STATUS) , // outCond
1169 pCodeInstruction pic16_pciDECFW = {
1170 {PC_OPCODE, NULL, NULL, 0, NULL,
1177 NULL, // from branch
1184 0,0, // dest, bit instruction
1185 0,0, // branch, skip
1186 0, // literal operand
1187 1, // RAM access bit
1188 0, // fast call/return mode select bit
1189 0, // second memory operand
1190 0, // second literal operand
1192 PCC_REGISTER, // inCond
1193 (PCC_W | PCC_STATUS) , // outCond
1197 pCodeInstruction pic16_pciDECFSZ = {
1198 {PC_OPCODE, NULL, NULL, 0, NULL,
1205 NULL, // from branch
1212 1,0, // dest, bit instruction
1213 1,1, // branch, skip
1214 0, // literal operand
1215 1, // RAM access bit
1216 0, // fast call/return mode select bit
1217 0, // second memory operand
1218 0, // second literal operand
1220 PCC_REGISTER, // inCond
1221 PCC_REGISTER , // outCond
1225 pCodeInstruction pic16_pciDECFSZW = {
1226 {PC_OPCODE, NULL, NULL, 0, NULL,
1233 NULL, // from branch
1240 0,0, // dest, bit instruction
1241 1,1, // branch, skip
1242 0, // literal operand
1243 1, // RAM access bit
1244 0, // fast call/return mode select bit
1245 0, // second memory operand
1246 0, // second literal operand
1248 PCC_REGISTER, // inCond
1253 pCodeInstruction pic16_pciGOTO = {
1254 {PC_OPCODE, NULL, NULL, 0, NULL,
1261 NULL, // from branch
1268 0,0, // dest, bit instruction
1269 1,0, // branch, skip
1270 0, // literal operand
1271 0, // RAM access bit
1272 0, // fast call/return mode select bit
1273 0, // second memory operand
1274 0, // second literal operand
1276 PCC_REL_ADDR, // inCond
1277 PCC_NONE , // outCond
1281 pCodeInstruction pic16_pciINCF = {
1282 {PC_OPCODE, NULL, NULL, 0, NULL,
1289 NULL, // from branch
1296 1,0, // dest, bit instruction
1297 0,0, // branch, skip
1298 0, // literal operand
1299 1, // RAM access bit
1300 0, // fast call/return mode select bit
1301 0, // second memory operand
1302 0, // second literal operand
1304 PCC_REGISTER, // inCond
1305 (PCC_REGISTER | PCC_STATUS), // outCond
1309 pCodeInstruction pic16_pciINCFW = {
1310 {PC_OPCODE, NULL, NULL, 0, NULL,
1317 NULL, // from branch
1324 0,0, // dest, bit instruction
1325 0,0, // branch, skip
1326 0, // literal operand
1327 1, // RAM access bit
1328 0, // fast call/return mode select bit
1329 0, // second memory operand
1330 0, // second literal operand
1332 PCC_REGISTER, // inCond
1333 (PCC_W | PCC_STATUS) , // outCond
1337 pCodeInstruction pic16_pciINCFSZ = {
1338 {PC_OPCODE, NULL, NULL, 0, NULL,
1345 NULL, // from branch
1352 1,0, // dest, bit instruction
1353 1,1, // branch, skip
1354 0, // literal operand
1355 1, // RAM access bit
1356 0, // fast call/return mode select bit
1357 0, // second memory operand
1358 0, // second literal operand
1360 PCC_REGISTER, // inCond
1361 PCC_REGISTER , // outCond
1365 pCodeInstruction pic16_pciINCFSZW = {
1366 {PC_OPCODE, NULL, NULL, 0, NULL,
1373 NULL, // from branch
1380 0,0, // dest, bit instruction
1381 1,1, // branch, skip
1382 0, // literal operand
1383 1, // RAM access bit
1384 0, // fast call/return mode select bit
1385 0, // second memory operand
1386 0, // second literal operand
1388 PCC_REGISTER, // inCond
1393 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1394 {PC_OPCODE, NULL, NULL, 0, NULL,
1401 NULL, // from branch
1408 1,0, // dest, bit instruction
1409 1,1, // branch, skip
1410 0, // literal operand
1411 1, // RAM access bit
1412 0, // fast call/return mode select bit
1413 0, // second memory operand
1414 0, // second literal operand
1416 PCC_REGISTER, // inCond
1417 PCC_REGISTER , // outCond
1421 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1422 {PC_OPCODE, NULL, NULL, 0, NULL,
1429 NULL, // from branch
1436 0,0, // dest, bit instruction
1437 1,1, // branch, skip
1438 0, // literal operand
1439 1, // RAM access bit
1440 0, // fast call/return mode select bit
1441 0, // second memory operand
1442 0, // second literal operand
1444 PCC_REGISTER, // inCond
1449 pCodeInstruction pic16_pciIORWF = {
1450 {PC_OPCODE, NULL, NULL, 0, NULL,
1457 NULL, // from branch
1464 1,0, // dest, bit instruction
1465 0,0, // branch, skip
1466 0, // literal operand
1467 1, // RAM access bit
1468 0, // fast call/return mode select bit
1469 0, // second memory operand
1470 0, // second literal operand
1472 (PCC_W | PCC_REGISTER), // inCond
1473 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1477 pCodeInstruction pic16_pciIORFW = {
1478 {PC_OPCODE, NULL, NULL, 0, NULL,
1485 NULL, // from branch
1492 0,0, // dest, bit instruction
1493 0,0, // branch, skip
1494 0, // literal operand
1495 1, // RAM access bit
1496 0, // fast call/return mode select bit
1497 0, // second memory operand
1498 0, // second literal operand
1500 (PCC_W | PCC_REGISTER), // inCond
1501 (PCC_W | PCC_Z | PCC_N), // outCond
1505 pCodeInstruction pic16_pciIORLW = {
1506 {PC_OPCODE, NULL, NULL, 0, NULL,
1513 NULL, // from branch
1520 0,0, // dest, bit instruction
1521 0,0, // branch, skip
1522 1, // literal operand
1523 0, // RAM access bit
1524 0, // fast call/return mode select bit
1525 0, // second memory operand
1526 0, // second literal operand
1528 (PCC_W | PCC_LITERAL), // inCond
1529 (PCC_W | PCC_Z | PCC_N), // outCond
1533 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1534 {PC_OPCODE, NULL, NULL, 0, NULL,
1541 NULL, // from branch
1548 0,0, // dest, bit instruction
1549 0,0, // branch, skip
1550 1, // literal operand
1551 0, // RAM access bit
1552 0, // fast call/return mode select bit
1553 0, // second memory operand
1554 1, // second literal operand
1556 PCC_LITERAL, // inCond
1557 PCC_NONE, // outCond
1561 pCodeInstruction pic16_pciMOVF = {
1562 {PC_OPCODE, NULL, NULL, 0, NULL,
1569 NULL, // from branch
1576 1,0, // dest, bit instruction
1577 0,0, // branch, skip
1578 0, // literal operand
1579 1, // RAM access bit
1580 0, // fast call/return mode select bit
1581 0, // second memory operand
1582 0, // second literal operand
1584 PCC_REGISTER, // inCond
1585 (PCC_Z | PCC_N), // outCond
1589 pCodeInstruction pic16_pciMOVFW = {
1590 {PC_OPCODE, NULL, NULL, 0, NULL,
1597 NULL, // from branch
1604 0,0, // dest, bit instruction
1605 0,0, // branch, skip
1606 0, // literal operand
1607 1, // RAM access bit
1608 0, // fast call/return mode select bit
1609 0, // second memory operand
1610 0, // second literal operand
1612 PCC_REGISTER, // inCond
1613 (PCC_W | PCC_N | PCC_Z), // outCond
1617 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1618 {PC_OPCODE, NULL, NULL, 0, NULL,
1625 NULL, // from branch
1632 0,0, // dest, bit instruction
1633 0,0, // branch, skip
1634 0, // literal operand
1635 0, // RAM access bit
1636 0, // fast call/return mode select bit
1637 1, // second memory operand
1638 0, // second literal operand
1640 PCC_REGISTER, // inCond
1641 PCC_REGISTER2, // outCond
1645 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1646 {PC_OPCODE, NULL, NULL, 0, NULL,
1652 NULL, // from branch
1659 0,0, // dest, bit instruction
1660 0,0, // branch, skip
1661 1, // literal operand
1662 0, // RAM access bit
1663 0, // fast call/return mode select bit
1664 0, // second memory operand
1665 0, // second literal operand
1667 (PCC_NONE | PCC_LITERAL), // inCond
1668 PCC_REGISTER, // outCond - BSR
1672 pCodeInstruction pic16_pciMOVLW = {
1673 {PC_OPCODE, NULL, NULL, 0, NULL,
1679 NULL, // from branch
1686 0,0, // dest, bit instruction
1687 0,0, // branch, skip
1688 1, // literal operand
1689 0, // RAM access bit
1690 0, // fast call/return mode select bit
1691 0, // second memory operand
1692 0, // second literal operand
1694 (PCC_NONE | PCC_LITERAL), // inCond
1699 pCodeInstruction pic16_pciMOVWF = {
1700 {PC_OPCODE, NULL, NULL, 0, NULL,
1707 NULL, // from branch
1714 0,0, // dest, bit instruction
1715 0,0, // branch, skip
1716 0, // literal operand
1717 1, // RAM access bit
1718 0, // fast call/return mode select bit
1719 0, // second memory operand
1720 0, // second literal operand
1723 PCC_REGISTER, // outCond
1727 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1728 {PC_OPCODE, NULL, NULL, 0, NULL,
1734 NULL, // from branch
1741 0,0, // dest, bit instruction
1742 0,0, // branch, skip
1743 1, // literal operand
1744 0, // RAM access bit
1745 0, // fast call/return mode select bit
1746 0, // second memory operand
1747 0, // second literal operand
1749 (PCC_W | PCC_LITERAL), // inCond
1750 PCC_NONE, // outCond - PROD
1754 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1755 {PC_OPCODE, NULL, NULL, 0, NULL,
1761 NULL, // from branch
1768 0,0, // dest, bit instruction
1769 0,0, // branch, skip
1770 0, // literal operand
1771 1, // RAM access bit
1772 0, // fast call/return mode select bit
1773 0, // second memory operand
1774 0, // second literal operand
1776 (PCC_W | PCC_REGISTER), // inCond
1777 PCC_REGISTER, // outCond - PROD
1781 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1782 {PC_OPCODE, NULL, NULL, 0, NULL,
1788 NULL, // from branch
1795 0,0, // dest, bit instruction
1796 0,0, // branch, skip
1797 0, // literal operand
1798 1, // RAM access bit
1799 0, // fast call/return mode select bit
1800 0, // second memory operand
1801 0, // second literal operand
1803 PCC_REGISTER, // inCond
1804 (PCC_REGISTER | PCC_STATUS), // outCond
1808 pCodeInstruction pic16_pciNOP = {
1809 {PC_OPCODE, NULL, NULL, 0, NULL,
1815 NULL, // from branch
1822 0,0, // dest, bit instruction
1823 0,0, // branch, skip
1824 0, // literal operand
1825 0, // RAM access bit
1826 0, // fast call/return mode select bit
1827 0, // second memory operand
1828 0, // second literal operand
1831 PCC_NONE, // outCond
1835 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1836 {PC_OPCODE, NULL, NULL, 0, NULL,
1842 NULL, // from branch
1849 0,0, // dest, bit instruction
1850 0,0, // branch, skip
1851 0, // literal operand
1852 0, // RAM access bit
1853 0, // fast call/return mode select bit
1854 0, // second memory operand
1855 0, // second literal operand
1858 PCC_NONE , // outCond
1862 pCodeInstruction pic16_pciPUSH = {
1863 {PC_OPCODE, NULL, NULL, 0, NULL,
1869 NULL, // from branch
1876 0,0, // dest, bit instruction
1877 0,0, // branch, skip
1878 0, // literal operand
1879 0, // RAM access bit
1880 0, // fast call/return mode select bit
1881 0, // second memory operand
1882 0, // second literal operand
1885 PCC_NONE , // outCond
1889 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1890 {PC_OPCODE, NULL, NULL, 0, NULL,
1896 NULL, // from branch
1903 0,0, // dest, bit instruction
1904 1,0, // branch, skip
1905 0, // literal operand
1906 0, // RAM access bit
1907 0, // fast call/return mode select bit
1908 0, // second memory operand
1909 0, // second literal operand
1911 PCC_REL_ADDR, // inCond
1912 PCC_NONE , // outCond
1916 pCodeInstruction pic16_pciRETFIE = {
1917 {PC_OPCODE, NULL, NULL, 0, NULL,
1924 NULL, // from branch
1931 0,0, // dest, bit instruction
1932 1,0, // branch, skip
1933 0, // literal operand
1934 0, // RAM access bit
1935 1, // fast call/return mode select bit
1936 0, // second memory operand
1937 0, // second literal operand
1940 PCC_NONE, // outCond (not true... affects the GIE bit too)
1944 pCodeInstruction pic16_pciRETLW = {
1945 {PC_OPCODE, NULL, NULL, 0, NULL,
1952 NULL, // from branch
1959 0,0, // dest, bit instruction
1960 1,0, // branch, skip
1961 1, // literal operand
1962 0, // RAM access bit
1963 0, // fast call/return mode select bit
1964 0, // second memory operand
1965 0, // second literal operand
1967 PCC_LITERAL, // inCond
1972 pCodeInstruction pic16_pciRETURN = {
1973 {PC_OPCODE, NULL, NULL, 0, NULL,
1980 NULL, // from branch
1987 0,0, // dest, bit instruction
1988 1,0, // branch, skip
1989 0, // literal operand
1990 0, // RAM access bit
1991 1, // fast call/return mode select bit
1992 0, // second memory operand
1993 0, // second literal operand
1996 PCC_NONE, // outCond
1999 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
2000 {PC_OPCODE, NULL, NULL, 0, NULL,
2007 NULL, // from branch
2014 1,0, // dest, bit instruction
2015 0,0, // branch, skip
2016 0, // literal operand
2017 1, // RAM access bit
2018 0, // fast call/return mode select bit
2019 0, // second memory operand
2020 0, // second literal operand
2022 (PCC_C | PCC_REGISTER), // inCond
2023 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2027 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2028 {PC_OPCODE, NULL, NULL, 0, NULL,
2035 NULL, // from branch
2042 0,0, // dest, bit instruction
2043 0,0, // branch, skip
2044 0, // literal operand
2045 1, // RAM access bit
2046 0, // fast call/return mode select bit
2047 0, // second memory operand
2048 0, // second literal operand
2050 (PCC_C | PCC_REGISTER), // inCond
2051 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2055 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2056 {PC_OPCODE, NULL, NULL, 0, NULL,
2063 NULL, // from branch
2070 1,0, // dest, bit instruction
2071 0,0, // branch, skip
2072 0, // literal operand
2073 1, // RAM access bit
2074 0, // fast call/return mode select bit
2075 0, // second memory operand
2076 0, // second literal operand
2078 PCC_REGISTER, // inCond
2079 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2082 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2083 {PC_OPCODE, NULL, NULL, 0, NULL,
2090 NULL, // from branch
2097 0,0, // dest, bit instruction
2098 0,0, // branch, skip
2099 0, // literal operand
2100 1, // RAM access bit
2101 0, // fast call/return mode select bit
2102 0, // second memory operand
2103 0, // second literal operand
2105 PCC_REGISTER, // inCond
2106 (PCC_W | PCC_Z | PCC_N), // outCond
2109 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2110 {PC_OPCODE, NULL, NULL, 0, NULL,
2117 NULL, // from branch
2124 1,0, // dest, bit instruction
2125 0,0, // branch, skip
2126 0, // literal operand
2127 1, // RAM access bit
2128 0, // fast call/return mode select bit
2129 0, // second memory operand
2130 0, // second literal operand
2132 (PCC_C | PCC_REGISTER), // inCond
2133 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2136 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2137 {PC_OPCODE, NULL, NULL, 0, NULL,
2144 NULL, // from branch
2151 0,0, // dest, bit instruction
2152 0,0, // branch, skip
2153 0, // literal operand
2154 1, // RAM access bit
2155 0, // fast call/return mode select bit
2156 0, // second memory operand
2157 0, // second literal operand
2159 (PCC_C | PCC_REGISTER), // inCond
2160 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2163 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2164 {PC_OPCODE, NULL, NULL, 0, NULL,
2171 NULL, // from branch
2178 1,0, // dest, bit instruction
2179 0,0, // branch, skip
2180 0, // literal operand
2181 1, // RAM access bit
2182 0, // fast call/return mode select bit
2183 0, // second memory operand
2184 0, // second literal operand
2186 PCC_REGISTER, // inCond
2187 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2191 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2192 {PC_OPCODE, NULL, NULL, 0, NULL,
2199 NULL, // from branch
2206 0,0, // dest, bit instruction
2207 0,0, // branch, skip
2208 0, // literal operand
2209 1, // RAM access bit
2210 0, // fast call/return mode select bit
2211 0, // second memory operand
2212 0, // second literal operand
2214 PCC_REGISTER, // inCond
2215 (PCC_W | PCC_Z | PCC_N), // outCond
2219 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2220 {PC_OPCODE, NULL, NULL, 0, NULL,
2227 NULL, // from branch
2234 0,0, // dest, bit instruction
2235 0,0, // branch, skip
2236 0, // literal operand
2237 1, // RAM access bit
2238 0, // fast call/return mode select bit
2239 0, // second memory operand
2240 0, // second literal operand
2243 PCC_REGISTER , // outCond
2247 pCodeInstruction pic16_pciSUBLW = {
2248 {PC_OPCODE, NULL, NULL, 0, NULL,
2255 NULL, // from branch
2262 0,0, // dest, bit instruction
2263 0,0, // branch, skip
2264 1, // literal operand
2265 0, // RAM access bit
2266 0, // fast call/return mode select bit
2267 0, // second memory operand
2268 0, // second literal operand
2270 (PCC_W | PCC_LITERAL), // inCond
2271 (PCC_W | PCC_STATUS), // outCond
2275 pCodeInstruction pic16_pciSUBFWB = {
2276 {PC_OPCODE, NULL, NULL, 0, NULL,
2283 NULL, // from branch
2290 1,0, // dest, bit instruction
2291 0,0, // branch, skip
2292 0, // literal operand
2293 1, // RAM access bit
2294 0, // fast call/return mode select bit
2295 0, // second memory operand
2296 0, // second literal operand
2298 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2299 (PCC_W | PCC_STATUS), // outCond
2303 pCodeInstruction pic16_pciSUBWF = {
2304 {PC_OPCODE, NULL, NULL, 0, NULL,
2311 NULL, // from branch
2318 1,0, // dest, bit instruction
2319 0,0, // branch, skip
2320 0, // literal operand
2321 1, // RAM access bit
2322 0, // fast call/return mode select bit
2323 0, // second memory operand
2324 0, // second literal operand
2326 (PCC_W | PCC_REGISTER), // inCond
2327 (PCC_REGISTER | PCC_STATUS), // outCond
2331 pCodeInstruction pic16_pciSUBFW = {
2332 {PC_OPCODE, NULL, NULL, 0, NULL,
2339 NULL, // from branch
2346 0,0, // dest, bit instruction
2347 0,0, // branch, skip
2348 0, // literal operand
2349 1, // RAM access bit
2350 0, // fast call/return mode select bit
2351 0, // second memory operand
2352 0, // second literal operand
2354 (PCC_W | PCC_REGISTER), // inCond
2355 (PCC_W | PCC_STATUS), // outCond
2359 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2360 {PC_OPCODE, NULL, NULL, 0, NULL,
2367 NULL, // from branch
2374 1,0, // dest, bit instruction
2375 0,0, // branch, skip
2376 0, // literal operand
2377 1, // RAM access bit
2378 0, // fast call/return mode select bit
2379 0, // second memory operand
2380 0, // second literal operand
2382 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2383 (PCC_REGISTER | PCC_STATUS), // outCond
2387 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2388 {PC_OPCODE, NULL, NULL, 0, NULL,
2395 NULL, // from branch
2402 0,0, // dest, bit instruction
2403 0,0, // branch, skip
2404 0, // literal operand
2405 1, // RAM access bit
2406 0, // fast call/return mode select bit
2407 0, // second memory operand
2408 0, // second literal operand
2410 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2411 (PCC_W | PCC_STATUS), // outCond
2415 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2416 {PC_OPCODE, NULL, NULL, 0, NULL,
2423 NULL, // from branch
2430 1,0, // dest, bit instruction
2431 0,0, // branch, skip
2432 0, // literal operand
2433 1, // RAM access bit
2434 0, // fast call/return mode select bit
2435 0, // second memory operand
2436 0, // second literal operand
2438 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2439 (PCC_REGISTER | PCC_STATUS), // outCond
2443 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2444 {PC_OPCODE, NULL, NULL, 0, NULL,
2451 NULL, // from branch
2458 0,0, // dest, bit instruction
2459 0,0, // branch, skip
2460 0, // literal operand
2461 1, // RAM access bit
2462 0, // fast call/return mode select bit
2463 0, // second memory operand
2464 0, // second literal operand
2466 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2467 (PCC_W | PCC_STATUS), // outCond
2471 pCodeInstruction pic16_pciSWAPF = {
2472 {PC_OPCODE, NULL, NULL, 0, NULL,
2479 NULL, // from branch
2486 1,0, // dest, bit instruction
2487 0,0, // branch, skip
2488 0, // literal operand
2489 1, // RAM access bit
2490 0, // fast call/return mode select bit
2491 0, // second memory operand
2492 0, // second literal operand
2494 (PCC_REGISTER), // inCond
2495 (PCC_REGISTER), // outCond
2499 pCodeInstruction pic16_pciSWAPFW = {
2500 {PC_OPCODE, NULL, NULL, 0, NULL,
2507 NULL, // from branch
2514 0,0, // dest, bit instruction
2515 0,0, // branch, skip
2516 0, // literal operand
2517 1, // RAM access bit
2518 0, // fast call/return mode select bit
2519 0, // second memory operand
2520 0, // second literal operand
2522 (PCC_REGISTER), // inCond
2527 pCodeInstruction pic16_pciTBLRD = { // patch 15
2528 {PC_OPCODE, NULL, NULL, 0, NULL,
2534 NULL, // from branch
2541 0,0, // dest, bit instruction
2542 0,0, // branch, skip
2543 0, // literal operand
2544 0, // RAM access bit
2545 0, // fast call/return mode select bit
2546 0, // second memory operand
2547 0, // second literal operand
2550 PCC_NONE , // outCond
2554 pCodeInstruction pic16_pciTBLRD_POSTINC = { // patch 15
2555 {PC_OPCODE, NULL, NULL, 0, NULL,
2561 NULL, // from branch
2568 0,0, // dest, bit instruction
2569 0,0, // branch, skip
2570 0, // literal operand
2571 0, // RAM access bit
2572 0, // fast call/return mode select bit
2573 0, // second memory operand
2574 0, // second literal operand
2577 PCC_NONE , // outCond
2581 pCodeInstruction pic16_pciTBLRD_POSTDEC = { // patch 15
2582 {PC_OPCODE, NULL, NULL, 0, NULL,
2588 NULL, // from branch
2595 0,0, // dest, bit instruction
2596 0,0, // branch, skip
2597 0, // literal operand
2598 0, // RAM access bit
2599 0, // fast call/return mode select bit
2600 0, // second memory operand
2601 0, // second literal operand
2604 PCC_NONE , // outCond
2608 pCodeInstruction pic16_pciTBLRD_PREINC = { // patch 15
2609 {PC_OPCODE, NULL, NULL, 0, NULL,
2615 NULL, // from branch
2622 0,0, // dest, bit instruction
2623 0,0, // branch, skip
2624 0, // literal operand
2625 0, // RAM access bit
2626 0, // fast call/return mode select bit
2627 0, // second memory operand
2628 0, // second literal operand
2631 PCC_NONE , // outCond
2635 pCodeInstruction pic16_pciTBLWT = { // patch 15
2636 {PC_OPCODE, NULL, NULL, 0, NULL,
2642 NULL, // from branch
2649 0,0, // dest, bit instruction
2650 0,0, // branch, skip
2651 0, // literal operand
2652 0, // RAM access bit
2653 0, // fast call/return mode select bit
2654 0, // second memory operand
2655 0, // second literal operand
2658 PCC_NONE , // outCond
2662 pCodeInstruction pic16_pciTBLWT_POSTINC = { // patch 15
2663 {PC_OPCODE, NULL, NULL, 0, NULL,
2669 NULL, // from branch
2676 0,0, // dest, bit instruction
2677 0,0, // branch, skip
2678 0, // literal operand
2679 0, // RAM access bit
2680 0, // fast call/return mode select bit
2681 0, // second memory operand
2682 0, // second literal operand
2685 PCC_NONE , // outCond
2689 pCodeInstruction pic16_pciTBLWT_POSTDEC = { // patch 15
2690 {PC_OPCODE, NULL, NULL, 0, NULL,
2696 NULL, // from branch
2703 0,0, // dest, bit instruction
2704 0,0, // branch, skip
2705 0, // literal operand
2706 0, // RAM access bit
2707 0, // fast call/return mode select bit
2708 0, // second memory operand
2709 0, // second literal operand
2712 PCC_NONE , // outCond
2716 pCodeInstruction pic16_pciTBLWT_PREINC = { // patch 15
2717 {PC_OPCODE, NULL, NULL, 0, NULL,
2723 NULL, // from branch
2730 0,0, // dest, bit instruction
2731 0,0, // branch, skip
2732 0, // literal operand
2733 0, // RAM access bit
2734 0, // fast call/return mode select bit
2735 0, // second memory operand
2736 0, // second literal operand
2739 PCC_NONE , // outCond
2743 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2744 {PC_OPCODE, NULL, NULL, 0, NULL,
2751 NULL, // from branch
2758 0,0, // dest, bit instruction
2759 1,1, // branch, skip
2760 0, // literal operand
2761 1, // RAM access bit
2762 0, // fast call/return mode select bit
2763 0, // second memory operand
2764 0, // second literal operand
2766 PCC_REGISTER, // inCond
2767 PCC_NONE, // outCond
2771 pCodeInstruction pic16_pciXORWF = {
2772 {PC_OPCODE, NULL, NULL, 0, NULL,
2779 NULL, // from branch
2786 1,0, // dest, bit instruction
2787 0,0, // branch, skip
2788 0, // literal operand
2789 1, // RAM access bit
2790 0, // fast call/return mode select bit
2791 0, // second memory operand
2792 0, // second literal operand
2794 (PCC_W | PCC_REGISTER), // inCond
2795 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2799 pCodeInstruction pic16_pciXORFW = {
2800 {PC_OPCODE, NULL, NULL, 0, NULL,
2807 NULL, // from branch
2814 0,0, // dest, bit instruction
2815 0,0, // branch, skip
2816 0, // literal operand
2817 1, // RAM access bit
2818 0, // fast call/return mode select bit
2819 0, // second memory operand
2820 0, // second literal operand
2822 (PCC_W | PCC_REGISTER), // inCond
2823 (PCC_W | PCC_Z | PCC_N), // outCond
2827 pCodeInstruction pic16_pciXORLW = {
2828 {PC_OPCODE, NULL, NULL, 0, NULL,
2835 NULL, // from branch
2842 0,0, // dest, bit instruction
2843 0,0, // branch, skip
2844 1, // literal operand
2845 1, // RAM access bit
2846 0, // fast call/return mode select bit
2847 0, // second memory operand
2848 0, // second literal operand
2850 (PCC_W | PCC_LITERAL), // inCond
2851 (PCC_W | PCC_Z | PCC_N), // outCond
2856 pCodeInstruction pic16_pciBANKSEL = {
2857 {PC_OPCODE, NULL, NULL, 0, NULL,
2863 NULL, // from branch
2870 0,0, // dest, bit instruction
2871 0,0, // branch, skip
2872 0, // literal operand
2873 0, // RAM access bit
2874 0, // fast call/return mode select bit
2875 0, // second memory operand
2876 0, // second literal operand
2879 PCC_NONE, // outCond
2884 #define MAX_PIC16MNEMONICS 100
2885 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2887 //#define USE_VSNPRINTF
2890 #ifdef USE_VSNPRINTF
2891 // Alas, vsnprintf is not ANSI standard, and does not exist
2892 // on Solaris (and probably other non-Gnu flavored Unixes).
2894 /*-----------------------------------------------------------------*/
2895 /* SAFE_snprintf - like snprintf except the string pointer is */
2896 /* after the string has been printed to. This is */
2897 /* useful for printing to string as though if it */
2898 /* were a stream. */
2899 /*-----------------------------------------------------------------*/
2900 void SAFE_snprintf(char **str, size_t *size, const char *format, ...)
2908 va_start(val, format);
2910 vsnprintf(*str, *size, format, val);
2916 fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2917 fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2926 // This version is *not* safe, despite the name.
2928 void SAFE_snprintf(char **str, size_t *size, const char *format, ...)
2932 static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2937 va_start(val, format);
2939 vsprintf(buffer, format, val);
2942 len = strlen(buffer);
2944 fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2945 fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2948 strcpy(*str, buffer);
2954 #endif // USE_VSNPRINTF
2957 extern set *externs;
2958 extern void pic16_initStack(int base_address, int size);
2959 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2960 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2961 extern void pic16_init_pic(char *);
2963 void pic16_pCodeInitRegisters(void)
2965 static int initialized=0;
2972 // pic16_initStack(0xfff, 8);
2973 pic16_init_pic(port->processor);
2975 pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2976 pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2977 pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2978 pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2979 pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2980 pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2981 pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2983 pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2984 pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2985 pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2987 pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2988 pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2989 pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2990 pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2992 pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2993 pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2994 pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2995 pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2996 pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2997 pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2999 pic16_stackpnt_lo = &pic16_pc_fsr1l;
3000 pic16_stackpnt_hi = &pic16_pc_fsr1h;
3001 pic16_stack_postdec = &pic16_pc_postdec1;
3002 pic16_stack_postinc = &pic16_pc_postinc1;
3003 pic16_stack_preinc = &pic16_pc_preinc1;
3004 pic16_stack_plusw = &pic16_pc_plusw1;
3006 pic16_framepnt_lo = &pic16_pc_fsr2l;
3007 pic16_framepnt_hi = &pic16_pc_fsr2h;
3008 pic16_frame_postdec = &pic16_pc_postdec2;
3009 pic16_frame_postinc = &pic16_pc_postinc2;
3010 pic16_frame_preinc = &pic16_pc_preinc2;
3011 pic16_frame_plusw = &pic16_pc_plusw2;
3013 pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3014 pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3015 pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3016 pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3017 pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3019 pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3020 pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3021 pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3022 pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3023 pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3025 pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3026 pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3027 pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3028 pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3029 pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3031 pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3032 pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3035 pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3036 pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3037 pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3038 pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3041 pic16_pc_status.rIdx = IDX_STATUS;
3042 pic16_pc_intcon.rIdx = IDX_INTCON;
3043 pic16_pc_pcl.rIdx = IDX_PCL;
3044 pic16_pc_pclath.rIdx = IDX_PCLATH;
3045 pic16_pc_pclatu.rIdx = IDX_PCLATU;
3046 pic16_pc_wreg.rIdx = IDX_WREG;
3047 pic16_pc_bsr.rIdx = IDX_BSR;
3049 pic16_pc_tosl.rIdx = IDX_TOSL;
3050 pic16_pc_tosh.rIdx = IDX_TOSH;
3051 pic16_pc_tosu.rIdx = IDX_TOSU;
3053 pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3054 pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3055 pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3056 pic16_pc_tablat.rIdx = IDX_TABLAT;
3058 pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3059 pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3060 pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3061 pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3062 pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3063 pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3064 pic16_pc_indf0.rIdx = IDX_INDF0;
3065 pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3066 pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3067 pic16_pc_preinc0.rIdx = IDX_PREINC0;
3068 pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3069 pic16_pc_indf1.rIdx = IDX_INDF1;
3070 pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3071 pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3072 pic16_pc_preinc1.rIdx = IDX_PREINC1;
3073 pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3074 pic16_pc_indf2.rIdx = IDX_INDF2;
3075 pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3076 pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3077 pic16_pc_preinc2.rIdx = IDX_PREINC2;
3078 pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3079 pic16_pc_prodl.rIdx = IDX_PRODL;
3080 pic16_pc_prodh.rIdx = IDX_PRODH;
3082 pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3083 pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3084 pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3086 pic16_pc_kzero.rIdx = IDX_KZ;
3087 pic16_pc_wsave.rIdx = IDX_WSAVE;
3088 pic16_pc_ssave.rIdx = IDX_SSAVE;
3090 pic16_pc_eecon1.rIdx = IDX_EECON1;
3091 pic16_pc_eecon2.rIdx = IDX_EECON2;
3092 pic16_pc_eedata.rIdx = IDX_EEDATA;
3093 pic16_pc_eeadr.rIdx = IDX_EEADR;
3096 pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3097 pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3099 pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3100 pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3102 /* probably should put this in a separate initialization routine */
3103 pb_dead_pcodes = newpBlock();
3108 /*-----------------------------------------------------------------*/
3109 /* mnem2key - convert a pic mnemonic into a hash key */
3110 /* (BTW - this spreads the mnemonics quite well) */
3112 /*-----------------------------------------------------------------*/
3114 int mnem2key(char const *mnem)
3123 key += toupper(*mnem++) +1;
3127 return (key & 0x1f);
3132 void pic16initMnemonics(void)
3137 pCodeInstruction *pci;
3139 if(mnemonics_initialized)
3142 // NULL out the array before making the assignments
3143 // since we check the array contents below this initialization.
3145 for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3146 pic16Mnemonics[i] = NULL;
3149 pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3150 pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3151 pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3152 pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3153 pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3154 pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3155 pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3156 pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3157 pic16Mnemonics[POC_BC] = &pic16_pciBC;
3158 pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3159 pic16Mnemonics[POC_BN] = &pic16_pciBN;
3160 pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3161 pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3162 pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3163 pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3164 pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3165 pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3166 pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3167 pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3168 pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3169 pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3170 pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3171 pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3172 pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3173 pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3174 pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3175 pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3176 pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3177 pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3178 pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3179 pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3180 pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3181 pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3182 pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3183 pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3184 pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3185 pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3186 pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3187 pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3188 pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3189 pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3190 pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3191 pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3192 pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3193 pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3194 pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3195 pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3196 pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3197 pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3198 pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3199 pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3200 pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3201 pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3202 pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3203 pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3204 pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3205 pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3206 pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3207 pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3208 pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3209 pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3210 pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3211 pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3212 pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3213 pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3214 pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3215 pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3216 pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3217 pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3218 pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3219 pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3220 pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3221 pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3222 pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3223 pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3224 pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3225 pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3226 pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3227 pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3228 pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3229 pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3230 pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3231 pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3232 pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3233 pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3234 pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3235 pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3236 pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3237 pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3238 pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3239 pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3240 pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3241 pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3242 pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3244 for(i=0; i<MAX_PIC16MNEMONICS; i++)
3245 if(pic16Mnemonics[i])
3246 hTabAddItem(&pic16MnemonicsHash, mnem2key(pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3247 pci = hTabFirstItem(pic16MnemonicsHash, &key);
3250 DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3251 pci = hTabNextItem(pic16MnemonicsHash, &key);
3254 mnemonics_initialized = 1;
3257 int pic16_getpCodePeepCommand(char *cmd);
3259 int pic16_getpCode(char *mnem,unsigned dest)
3262 pCodeInstruction *pci;
3263 int key = mnem2key(mnem);
3265 if(!mnemonics_initialized)
3266 pic16initMnemonics();
3268 pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3272 if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3273 if((pci->num_ops <= 1)
3274 || (pci->isModReg == dest)
3276 || (pci->num_ops <= 2 && pci->isAccess)
3277 || (pci->num_ops <= 2 && pci->isFastCall)
3278 || (pci->num_ops <= 2 && pci->is2MemOp)
3279 || (pci->num_ops <= 2 && pci->is2LitOp) )
3283 pci = hTabNextItemWK (pic16MnemonicsHash);
3290 /*-----------------------------------------------------------------*
3291 * pic16initpCodePeepCommands
3293 *-----------------------------------------------------------------*/
3294 void pic16initpCodePeepCommands(void)
3302 hTabAddItem(&pic16pCodePeepCommandsHash,
3303 mnem2key(peepCommands[i].cmd), &peepCommands[i]);
3305 } while (peepCommands[i].cmd);
3307 pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3310 //fprintf(stderr, "peep command %s key %d\n",pcmd->cmd,pcmd->id);
3311 pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3316 /*-----------------------------------------------------------------
3319 *-----------------------------------------------------------------*/
3321 int pic16_getpCodePeepCommand(char *cmd)
3325 int key = mnem2key(cmd);
3328 pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3331 // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3332 if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3336 pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3343 static char getpBlock_dbName(pBlock *pb)
3349 return pb->cmemmap->dbName;
3353 void pic16_pBlockConvert2ISR(pBlock *pb)
3357 if(pb->cmemmap)pb->cmemmap = NULL;
3361 if(pic16_pcode_verbose)
3362 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3365 void pic16_pBlockConvert2Absolute(pBlock *pb)
3368 if(pb->cmemmap)pb->cmemmap = NULL;
3372 if(pic16_pcode_verbose)
3373 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3376 /*-----------------------------------------------------------------*/
3377 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all */
3378 /* instances to the front of the doubly linked */
3379 /* list of pBlocks */
3380 /*-----------------------------------------------------------------*/
3382 void pic16_movepBlock2Head(char dbName)
3387 /* this can happen in sources without code,
3388 * only variable definitions */
3389 if(!the_pFile)return;
3391 pb = the_pFile->pbHead;
3395 if(getpBlock_dbName(pb) == dbName) {
3396 pBlock *pbn = pb->next;
3397 pb->next = the_pFile->pbHead;
3398 the_pFile->pbHead->prev = pb;
3399 the_pFile->pbHead = pb;
3402 pb->prev->next = pbn;
3404 // If the pBlock that we just moved was the last
3405 // one in the link of all of the pBlocks, then we
3406 // need to point the tail to the block just before
3407 // the one we moved.
3408 // Note: if pb->next is NULL, then pb must have
3409 // been the last pBlock in the chain.
3412 pbn->prev = pb->prev;
3414 the_pFile->pbTail = pb->prev;
3425 void pic16_copypCode(FILE *of, char dbName)
3429 if(!of || !the_pFile)
3432 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3433 if(getpBlock_dbName(pb) == dbName) {
3434 // fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3436 pic16_printpBlock(of,pb);
3441 void pic16_pcode_test(void)
3444 DFPRINTF((stderr,"pcode is alive!\n"));
3454 /* create the file name */
3455 strcpy(buffer,dstFileName);
3456 strcat(buffer,".p");
3458 if( !(pFile = fopen(buffer, "w" ))) {
3459 werror(E_FILE_OPEN_ERR,buffer);
3463 fprintf(pFile,"pcode dump\n\n");
3465 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3466 fprintf(pFile,"\n\tNew pBlock\n\n");
3468 fprintf(pFile,"%s",pb->cmemmap->sname);
3470 fprintf(pFile,"internal pblock");
3472 fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3473 pic16_printpBlock(pFile,pb);
3479 unsigned long pic16_countInstructions(void)
3483 unsigned long isize=0;
3485 if(!the_pFile)return -1;
3487 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3488 for(pc = pb->pcHead; pc; pc = pc->next) {
3489 if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3496 /*-----------------------------------------------------------------*/
3497 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg- */
3498 /* ister, RegCond will return the bit being referenced. */
3500 /* fixme - why not just OR in the pcop bit field */
3501 /*-----------------------------------------------------------------*/
3503 static int RegCond(pCodeOp *pcop)
3509 if(!pcop->name)return 0;
3511 if(pcop->type == PO_GPR_BIT && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3512 switch(PCORB(pcop)->bit) {
3526 /*-----------------------------------------------------------------*/
3527 /* pic16_newpCode - create and return a newly initialized pCode */
3529 /* fixme - rename this */
3531 /* The purpose of this routine is to create a new Instruction */
3532 /* pCode. This is called by gen.c while the assembly code is being */
3536 /* PIC_OPCODE op - the assembly instruction we wish to create. */
3537 /* (note that the op is analogous to but not the */
3538 /* same thing as the opcode of the instruction.) */
3539 /* pCdoeOp *pcop - pointer to the operand of the instruction. */
3542 /* a pointer to the new malloc'd pCode is returned. */
3546 /*-----------------------------------------------------------------*/
3547 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3549 pCodeInstruction *pci ;
3551 if(!mnemonics_initialized)
3552 pic16initMnemonics();
3554 pci = Safe_calloc(1, sizeof(pCodeInstruction));
3556 if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3557 memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3560 if(pci->inCond & PCC_EXAMINE_PCOP)
3561 pci->inCond |= RegCond(pcop);
3563 if(pci->outCond & PCC_EXAMINE_PCOP)
3564 pci->outCond |= RegCond(pcop);
3566 pci->pc.prev = pci->pc.next = NULL;
3567 return (pCode *)pci;
3570 fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3576 /*-----------------------------------------------------------------*/
3577 /* pic16_newpCodeWild - create a "wild" as in wild card pCode */
3579 /* Wild pcodes are used during the peep hole optimizer to serve */
3580 /* as place holders for any instruction. When a snippet of code is */
3581 /* compared to a peep hole rule, the wild card opcode will match */
3582 /* any instruction. However, the optional operand and label are */
3583 /* additional qualifiers that must also be matched before the */
3584 /* line (of assembly code) is declared matched. Note that the */
3585 /* operand may be wild too. */
3587 /* Note, a wild instruction is specified just like a wild var: */
3588 /* %4 ; A wild instruction, */
3589 /* See the peeph.def file for additional examples */
3591 /*-----------------------------------------------------------------*/
3593 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3598 pcw = Safe_calloc(1,sizeof(pCodeWild));
3600 pcw->pci.pc.type = PC_WILD;
3601 pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3602 pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3603 pcw->pci.pc.pb = NULL;
3605 // pcw->pci.pc.analyze = genericAnalyze;
3606 pcw->pci.pc.destruct = genericDestruct;
3607 pcw->pci.pc.print = genericPrint;
3609 pcw->id = pCodeID; // this is the 'n' in %n
3610 pcw->operand = optional_operand;
3611 pcw->label = optional_label;
3613 pcw->mustBeBitSkipInst = 0;
3614 pcw->mustNotBeBitSkipInst = 0;
3615 pcw->invertBitSkipInst = 0;
3617 return ( (pCode *)pcw);
3621 /*-----------------------------------------------------------------*/
3622 /* newPcodeInlineP - create a new pCode from a char string */
3623 /*-----------------------------------------------------------------*/
3626 pCode *pic16_newpCodeInlineP(char *cP)
3631 pcc = Safe_calloc(1,sizeof(pCodeComment));
3633 pcc->pc.type = PC_INLINE;
3634 pcc->pc.prev = pcc->pc.next = NULL;
3635 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3638 // pcc->pc.analyze = genericAnalyze;
3639 pcc->pc.destruct = genericDestruct;
3640 pcc->pc.print = genericPrint;
3643 pcc->comment = Safe_strdup(cP);
3645 pcc->comment = NULL;
3647 return ( (pCode *)pcc);
3651 /*-----------------------------------------------------------------*/
3652 /* newPcodeCharP - create a new pCode from a char string */
3653 /*-----------------------------------------------------------------*/
3655 pCode *pic16_newpCodeCharP(char *cP)
3660 pcc = Safe_calloc(1,sizeof(pCodeComment));
3662 pcc->pc.type = PC_COMMENT;
3663 pcc->pc.prev = pcc->pc.next = NULL;
3664 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3667 // pcc->pc.analyze = genericAnalyze;
3668 pcc->pc.destruct = genericDestruct;
3669 pcc->pc.print = genericPrint;
3672 pcc->comment = Safe_strdup(cP);
3674 pcc->comment = NULL;
3676 return ( (pCode *)pcc);
3680 /*-----------------------------------------------------------------*/
3681 /* pic16_newpCodeFunction - */
3682 /*-----------------------------------------------------------------*/
3685 pCode *pic16_newpCodeFunction(char *mod,char *f)
3689 pcf = Safe_calloc(1,sizeof(pCodeFunction));
3691 pcf->pc.type = PC_FUNCTION;
3692 pcf->pc.prev = pcf->pc.next = NULL;
3693 //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3696 // pcf->pc.analyze = genericAnalyze;
3697 pcf->pc.destruct = genericDestruct;
3698 pcf->pc.print = pCodePrintFunction;
3704 pcf->modname = Safe_calloc(1,strlen(mod)+1);
3705 strcpy(pcf->modname,mod);
3707 pcf->modname = NULL;
3710 pcf->fname = Safe_calloc(1,strlen(f)+1);
3711 strcpy(pcf->fname,f);
3715 pcf->stackusage = 0;
3717 return ( (pCode *)pcf);
3720 /*-----------------------------------------------------------------*/
3721 /* pic16_newpCodeFlow */
3722 /*-----------------------------------------------------------------*/
3723 static void destructpCodeFlow(pCode *pc)
3725 if(!pc || !isPCFL(pc))
3732 pic16_unlinkpCode(pc);
3734 deleteSet(&PCFL(pc)->registers);
3735 deleteSet(&PCFL(pc)->from);
3736 deleteSet(&PCFL(pc)->to);
3738 /* Instead of deleting the memory used by this pCode, mark
3739 * the object as bad so that if there's a pointer to this pCode
3740 * dangling around somewhere then (hopefully) when the type is
3741 * checked we'll catch it.
3745 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3751 pCode *pic16_newpCodeFlow(void )
3755 //_ALLOC(pcflow,sizeof(pCodeFlow));
3756 pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3758 pcflow->pc.type = PC_FLOW;
3759 pcflow->pc.prev = pcflow->pc.next = NULL;
3760 pcflow->pc.pb = NULL;
3762 // pcflow->pc.analyze = genericAnalyze;
3763 pcflow->pc.destruct = destructpCodeFlow;
3764 pcflow->pc.print = genericPrint;
3766 pcflow->pc.seq = GpcFlowSeq++;
3768 pcflow->from = pcflow->to = NULL;
3770 pcflow->inCond = PCC_NONE;
3771 pcflow->outCond = PCC_NONE;
3773 pcflow->firstBank = -1;
3774 pcflow->lastBank = -1;
3776 pcflow->FromConflicts = 0;
3777 pcflow->ToConflicts = 0;
3781 pcflow->registers = newSet();
3783 return ( (pCode *)pcflow);
3787 /*-----------------------------------------------------------------*/
3788 /*-----------------------------------------------------------------*/
3789 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3791 pCodeFlowLink *pcflowLink;
3793 pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3795 pcflowLink->pcflow = pcflow;
3796 pcflowLink->bank_conflict = 0;
3801 /*-----------------------------------------------------------------*/
3802 /* pic16_newpCodeCSource - create a new pCode Source Symbol */
3803 /*-----------------------------------------------------------------*/
3805 pCode *pic16_newpCodeCSource(int ln, char *f, char *l)
3810 pccs = Safe_calloc(1,sizeof(pCodeCSource));
3812 pccs->pc.type = PC_CSOURCE;
3813 pccs->pc.prev = pccs->pc.next = NULL;
3816 pccs->pc.destruct = genericDestruct;
3817 pccs->pc.print = genericPrint;
3819 pccs->line_number = ln;
3821 pccs->line = Safe_strdup(l);
3826 pccs->file_name = Safe_strdup(f);
3828 pccs->file_name = NULL;
3830 return ( (pCode *)pccs);
3835 /*******************************************************************/
3836 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive */
3837 /* added by VR 6-Jun-2003 */
3838 /*******************************************************************/
3840 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3847 pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3848 pcad->pci.pc.type = PC_ASMDIR;
3849 pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3850 pcad->pci.pc.pb = NULL;
3851 pcad->pci.isize = 2;
3852 pcad->pci.pc.destruct = genericDestruct;
3853 pcad->pci.pc.print = genericPrint;
3855 if(asdir && *asdir) {
3857 while(isspace(*asdir))asdir++; // strip any white space from the beginning
3859 pcad->directive = Safe_strdup( asdir );
3862 va_start(ap, argfmt);
3864 memset(buffer, 0, sizeof(buffer));
3865 if(argfmt && *argfmt)
3866 vsprintf(buffer, argfmt, ap);
3870 while(isspace(*lbp))lbp++;
3873 pcad->arg = Safe_strdup( lbp );
3875 return ((pCode *)pcad);
3878 /*-----------------------------------------------------------------*/
3879 /* pCodeLabelDestruct - free memory used by a label. */
3880 /*-----------------------------------------------------------------*/
3881 static void pCodeLabelDestruct(pCode *pc)
3887 // if((pc->type == PC_LABEL) && PCL(pc)->label)
3888 // Safe_free(PCL(pc)->label);
3890 /* Instead of deleting the memory used by this pCode, mark
3891 * the object as bad so that if there's a pointer to this pCode
3892 * dangling around somewhere then (hopefully) when the type is
3893 * checked we'll catch it.
3897 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3903 pCode *pic16_newpCodeLabel(char *name, int key)
3909 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3911 pcl->pc.type = PC_LABEL;
3912 pcl->pc.prev = pcl->pc.next = NULL;
3913 //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3916 // pcl->pc.analyze = genericAnalyze;
3917 pcl->pc.destruct = pCodeLabelDestruct;
3918 pcl->pc.print = pCodePrintLabel;
3925 sprintf(s,"_%05d_DS_",key);
3930 pcl->label = Safe_strdup(s);
3932 // if(pic16_pcode_verbose)
3933 // fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3936 return ( (pCode *)pcl);
3940 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3942 pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3946 return ( (pCode *)pcl );
3949 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3953 pci = Safe_calloc(1, sizeof(pCodeInfo));
3954 pci->pci.pc.type = PC_INFO;
3955 pci->pci.pc.prev = pci->pci.pc.next = NULL;
3956 pci->pci.pc.pb = NULL;
3957 pci->pci.label = NULL;
3959 pci->pci.pc.destruct = genericDestruct;
3960 pci->pci.pc.print = genericPrint;
3965 return ((pCode *)pci);
3969 /*-----------------------------------------------------------------*/
3970 /* newpBlock - create and return a pointer to a new pBlock */
3971 /*-----------------------------------------------------------------*/
3972 static pBlock *newpBlock(void)
3977 PpB = Safe_calloc(1,sizeof(pBlock) );
3978 PpB->next = PpB->prev = NULL;
3980 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3981 PpB->tregisters = NULL;
3983 PpB->FlowTree = NULL;
3989 /*-----------------------------------------------------------------*/
3990 /* pic16_newpCodeChain - create a new chain of pCodes */
3991 /*-----------------------------------------------------------------*
3993 * This function will create a new pBlock and the pointer to the
3994 * pCode that is passed in will be the first pCode in the block.
3995 *-----------------------------------------------------------------*/
3998 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
4001 pBlock *pB = newpBlock();
4003 pB->pcHead = pB->pcTail = pc;
4012 /*-----------------------------------------------------------------*/
4013 /* pic16_newpCodeOpLabel - Create a new label given the key */
4014 /* Note, a negative key means that the label is part of wild card */
4015 /* (and hence a wild card label) used in the pCodePeep */
4016 /* optimizations). */
4017 /*-----------------------------------------------------------------*/
4019 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4022 static int label_key=-1;
4026 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4027 pcop->type = PO_LABEL;
4032 sprintf(s=buffer,"_%05d_DS_",key);
4034 s = name, key = label_key--;
4037 pcop->name = Safe_strdup(s);
4039 ((pCodeOpLabel *)pcop)->key = key;
4041 //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4045 /*-----------------------------------------------------------------*/
4046 /*-----------------------------------------------------------------*/
4047 pCodeOp *pic16_newpCodeOpLit(int lit)
4053 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4054 pcop->type = PO_LITERAL;
4058 sprintf(s,"0x%02hhx", (unsigned char)lit);
4060 // sprintf(s, "%i", lit);
4063 pcop->name = Safe_strdup(s);
4065 ((pCodeOpLit *)pcop)->lit = lit;
4070 /*-----------------------------------------------------------------*/
4071 /*-----------------------------------------------------------------*/
4072 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4074 char *s = buffer, tbuf[256], *tb=tbuf;
4078 tb = pic16_get_op(arg2, NULL, 0);
4079 pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4080 pcop->type = PO_LITERAL;
4084 sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4086 pcop->name = Safe_strdup(s);
4089 ((pCodeOpLit2 *)pcop)->lit = lit;
4090 ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4095 /*-----------------------------------------------------------------*/
4096 /*-----------------------------------------------------------------*/
4097 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4101 pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4102 pcop->type = PO_IMMEDIATE;
4104 regs *r = pic16_dirregWithName(name);
4105 pcop->name = Safe_strdup(name);
4109 // fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4110 PCOI(pcop)->rIdx = r->rIdx;
4112 // fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4113 PCOI(pcop)->rIdx = -1;
4115 // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4120 PCOI(pcop)->index = index;
4121 PCOI(pcop)->offset = offset;
4122 PCOI(pcop)->_const = code_space;
4127 /*-----------------------------------------------------------------*/
4128 /*-----------------------------------------------------------------*/
4129 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4135 if(!pcwb || !subtype) {
4136 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4140 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4141 pcop->type = PO_WILD;
4142 sprintf(s,"%%%d",id);
4143 pcop->name = Safe_strdup(s);
4145 PCOW(pcop)->id = id;
4146 PCOW(pcop)->pcwb = pcwb;
4147 PCOW(pcop)->subtype = subtype;
4148 PCOW(pcop)->matched = NULL;
4150 PCOW(pcop)->pcop2 = NULL;
4155 /*-----------------------------------------------------------------*/
4156 /*-----------------------------------------------------------------*/
4157 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4163 if(!pcwb || !subtype || !subtype2) {
4164 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4168 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4169 pcop->type = PO_WILD;
4170 sprintf(s,"%%%d",id);
4171 pcop->name = Safe_strdup(s);
4173 PCOW(pcop)->id = id;
4174 PCOW(pcop)->pcwb = pcwb;
4175 PCOW(pcop)->subtype = subtype;
4176 PCOW(pcop)->matched = NULL;
4178 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4180 if(!subtype2->name) {
4181 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4182 PCOW2(pcop)->pcop.type = PO_WILD;
4183 sprintf(s, "%%%d", id2);
4184 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4185 PCOW2(pcop)->id = id2;
4186 PCOW2(pcop)->subtype = subtype2;
4188 // fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4189 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4191 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4193 // fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4194 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4203 /*-----------------------------------------------------------------*/
4204 /*-----------------------------------------------------------------*/
4205 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4209 pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4210 pcop->type = PO_GPR_BIT;
4212 pcop->name = Safe_strdup(s);
4216 PCORB(pcop)->bit = bit;
4217 PCORB(pcop)->inBitSpace = inBitSpace;
4218 PCORB(pcop)->subtype = subt;
4220 /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4221 PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4222 // fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4223 // PCOR(pcop)->rIdx = 0;
4228 /*-----------------------------------------------------------------*
4229 * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4231 * If rIdx >=0 then a specific register from the set of registers
4232 * will be selected. If rIdx <0, then a new register will be searched
4234 *-----------------------------------------------------------------*/
4236 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4240 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4245 PCOR(pcop)->rIdx = rIdx;
4246 PCOR(pcop)->r = pic16_regWithIdx(rIdx);
4248 PCOR(pcop)->r = pic16_findFreeReg(REG_GPR);
4251 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4253 fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4254 __FUNCTION__, __LINE__);
4259 pcop->type = PCOR(pcop)->r->pc_type;
4264 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4269 pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4272 r = pic16_findFreeReg(REG_GPR);
4275 if(!bitVectBitValue(bv, r->rIdx)) {
4277 PCOR(pcop)->rIdx = r->rIdx;
4278 pcop->type = r->pc_type;
4282 r = pic16_findFreeRegNext(REG_GPR, r);
4290 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4295 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4296 PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4297 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4298 pcop->type = PCOR(pcop)->r->pc_type;
4299 pcop->name = PCOR(pcop)->r->name;
4301 // if(pic16_pcode_verbose) {
4302 // fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4303 // __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4309 /*-----------------------------------------------------------------*/
4310 /*-----------------------------------------------------------------*/
4311 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4315 pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4318 pcop->key = Safe_strdup( key );
4320 return (PCOP(pcop));
4323 /*-----------------------------------------------------------------*/
4324 /*-----------------------------------------------------------------*/
4325 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4327 pCodeOpLocalReg *pcop;
4329 pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4333 return (PCOP(pcop));
4337 /*-----------------------------------------------------------------*/
4338 /*-----------------------------------------------------------------*/
4340 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4347 pcop = pic16_newpCodeOpBit(name, -1,0, type);
4351 pcop = pic16_newpCodeOpLit(-1);
4355 pcop = pic16_newpCodeOpLabel(NULL,-1);
4358 pcop = pic16_newpCodeOpReg(-1);
4361 case PO_GPR_REGISTER:
4363 pcop = pic16_newpCodeOpRegFromStr(name);
4365 pcop = pic16_newpCodeOpReg(-1);
4369 pcop = Safe_calloc(1,sizeof(pCodeOp) );
4372 pcop->name = Safe_strdup(name);
4380 #define DB_ITEMS_PER_LINE 8
4382 typedef struct DBdata
4389 static int DBd_init = -1;
4391 /*-----------------------------------------------------------------*/
4392 /* Initialiase "DB" data buffer */
4393 /*-----------------------------------------------------------------*/
4394 void pic16_initDB(void)
4400 /*-----------------------------------------------------------------*/
4401 /* Flush pending "DB" data to a pBlock */
4403 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4404 /*-----------------------------------------------------------------*/
4405 void pic16_flushDB(char ptype, void *p)
4409 pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4412 fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4415 fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4419 DBd.buffer[0] = '\0';
4424 /*-----------------------------------------------------------------*/
4425 /* Add "DB" directives to a pBlock */
4426 /*-----------------------------------------------------------------*/
4427 void pic16_emitDB(char c, char ptype, void *p)
4432 // we need to initialize
4435 DBd.buffer[0] = '\0';
4438 l = strlen(DBd.buffer);
4439 sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4441 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4444 if (DBd.count>= DB_ITEMS_PER_LINE)
4445 pic16_flushDB(ptype, p);
4448 void pic16_emitDS(char *s, char ptype, void *p)
4453 // we need to initialize
4456 DBd.buffer[0] = '\0';
4459 l = strlen(DBd.buffer);
4460 sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4462 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4464 DBd.count++; //=strlen(s);
4466 pic16_flushDB(ptype, p);
4470 /*-----------------------------------------------------------------*/
4471 /*-----------------------------------------------------------------*/
4472 void pic16_pCodeConstString(char *name, char *value)
4476 // fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value);
4481 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4483 pic16_addpBlock(pb);
4485 // sprintf(buffer,"; %s = ", name);
4486 // strcat(buffer, value);
4487 // fputs(buffer, stderr);
4489 // pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4490 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4493 pic16_emitDB(*value, 'p', (void *)pb);
4495 pic16_flushDB('p', (void *)pb);
4498 /*-----------------------------------------------------------------*/
4499 /*-----------------------------------------------------------------*/
4501 static void pCodeReadCodeTable(void)
4505 fprintf(stderr, " %s\n",__FUNCTION__);
4507 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4509 pic16_addpBlock(pb);
4511 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4512 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4513 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4514 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4516 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4517 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4518 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4519 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4524 /*-----------------------------------------------------------------*/
4525 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */
4526 /*-----------------------------------------------------------------*/
4527 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4534 /* If this is the first pcode to be added to a block that
4535 * was initialized with a NULL pcode, then go ahead and
4536 * make this pcode the head and tail */
4537 pb->pcHead = pb->pcTail = pc;
4540 pb->pcTail->next = pc;
4542 pc->prev = pb->pcTail;
4549 /*-----------------------------------------------------------------*/
4550 /* pic16_addpBlock - place a pBlock into the pFile */
4551 /*-----------------------------------------------------------------*/
4552 void pic16_addpBlock(pBlock *pb)
4554 // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4557 /* First time called, we'll pass through here. */
4558 //_ALLOC(the_pFile,sizeof(pFile));
4559 the_pFile = Safe_calloc(1,sizeof(pFile));
4560 the_pFile->pbHead = the_pFile->pbTail = pb;
4561 the_pFile->functions = NULL;
4565 the_pFile->pbTail->next = pb;
4566 pb->prev = the_pFile->pbTail;
4568 the_pFile->pbTail = pb;
4571 /*-----------------------------------------------------------------*/
4572 /* removepBlock - remove a pBlock from the pFile */
4573 /*-----------------------------------------------------------------*/
4574 static void removepBlock(pBlock *pb)
4582 //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4584 for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4587 if(pbs == the_pFile->pbHead)
4588 the_pFile->pbHead = pbs->next;
4590 if (pbs == the_pFile->pbTail)
4591 the_pFile->pbTail = pbs->prev;
4594 pbs->next->prev = pbs->prev;
4597 pbs->prev->next = pbs->next;
4604 fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4608 /*-----------------------------------------------------------------*/
4609 /* printpCode - write the contents of a pCode to a file */
4610 /*-----------------------------------------------------------------*/
4611 static void printpCode(FILE *of, pCode *pc)
4622 fprintf(of,"warning - unable to print pCode\n");
4625 /*-----------------------------------------------------------------*/
4626 /* pic16_printpBlock - write the contents of a pBlock to a file */
4627 /*-----------------------------------------------------------------*/
4628 void pic16_printpBlock(FILE *of, pBlock *pb)
4636 for(pc = pb->pcHead; pc; pc = pc->next) {
4637 if(isPCF(pc) && PCF(pc)->fname) {
4638 fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4639 if(pb->dbName == 'A') {
4641 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4642 // fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4643 if(!strcmp(ab->name, PCF(pc)->fname)) {
4644 // fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4645 if(ab->address != -1)
4646 fprintf(of, "\t0X%06X", ab->address);
4657 /*-----------------------------------------------------------------*/
4659 /* pCode processing */
4663 /*-----------------------------------------------------------------*/
4664 pCode * pic16_findNextInstruction(pCode *pci);
4665 pCode * pic16_findPrevInstruction(pCode *pci);
4667 void pic16_unlinkpCode(pCode *pc)
4673 fprintf(stderr,"Unlinking: ");
4674 printpCode(stderr, pc);
4677 pc->prev->next = pc->next;
4679 pc->next->prev = pc->prev;
4681 /* move C source line down (or up) */
4682 if (isPCI(pc) && PCI(pc)->cline) {
4683 prev = pic16_findNextInstruction (pc->next);
4684 if (prev && isPCI(prev) && !PCI(prev)->cline) {
4685 PCI(prev)->cline = PCI(pc)->cline;
4687 prev = pic16_findPrevInstruction (pc->prev);
4688 if (prev && isPCI(prev) && !PCI(prev)->cline)
4689 PCI(prev)->cline = PCI(pc)->cline;
4692 pc->prev = pc->next = NULL;
4696 /*-----------------------------------------------------------------*/
4697 /*-----------------------------------------------------------------*/
4699 static void genericDestruct(pCode *pc)
4702 pic16_unlinkpCode(pc);
4705 /* For instructions, tell the register (if there's one used)
4706 * that it's no longer needed */
4707 regs *reg = pic16_getRegFromInstruction(pc);
4709 deleteSetItem (&(reg->reglives.usedpCodes),pc);
4711 if(PCI(pc)->is2MemOp) {
4712 reg = pic16_getRegFromInstruction2(pc);
4714 deleteSetItem(&(reg->reglives.usedpCodes), pc);
4718 /* Instead of deleting the memory used by this pCode, mark
4719 * the object as bad so that if there's a pointer to this pCode
4720 * dangling around somewhere then (hopefully) when the type is
4721 * checked we'll catch it.
4725 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4731 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4732 /*-----------------------------------------------------------------*/
4733 /*-----------------------------------------------------------------*/
4734 /* modifiers for constant immediate */
4735 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4737 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4742 int use_buffer = 1; // copy the string to the passed buffer pointer
4747 use_buffer = 0; // Don't bother copying the string to the buffer.
4751 switch(pcop->type) {
4759 SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4762 return PCOR(pcop)->r->name;
4765 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4767 SAFE_snprintf(&buffer,&size,"%s",r->name);
4774 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4775 if(PCOI(pcop)->index) {
4776 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4777 immdmod[ PCOI(pcop)->offset ],
4781 SAFE_snprintf(&s,&size,"%s(%s)",
4782 immdmod[ PCOI(pcop)->offset ],
4786 if(PCOI(pcop)->index) {
4787 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4792 SAFE_snprintf(&s,&size, "%s(%s)",
4799 case PO_GPR_REGISTER:
4802 // size = sizeof(buffer);
4803 if( PCOR(pcop)->instance) {
4804 SAFE_snprintf(&s,&size,"(%s + %d)",
4806 PCOR(pcop)->instance );
4808 SAFE_snprintf(&s,&size,"%s",pcop->name);
4813 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4814 SAFE_snprintf(&s, &size, "%s", pcop->name);
4816 if(PCORB(pcop)->pcor.instance)
4817 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4819 SAFE_snprintf(&s, &size, "%s", pcop->name);
4826 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4835 return "NO operand1";
4838 /*-----------------------------------------------------------------*/
4839 /* pic16_get_op2 - variant to support two memory operand commands */
4840 /*-----------------------------------------------------------------*/
4841 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4846 int use_buffer = 1; // copy the string to the passed buffer pointer
4851 use_buffer = 0; // Don't bother copying the string to the buffer.
4855 fprintf(stderr, "%s:%d second operand %s is %d\tPO_DIR(%d) PO_GPR_TEMP(%d) PO_IMMEDIATE(%d) PO_INDF0(%d) PO_FSR0(%d)\n",
4856 __FUNCTION__, __LINE__, PCOR(PCOR2(pcop)->pcop2)->r->name, PCOR2(pcop)->pcop2->type,
4857 PO_DIR, PO_GPR_TEMP, PO_IMMEDIATE, PO_INDF0, PO_FSR0);
4861 switch(PCOR2(pcop)->pcop2->type) {
4869 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4872 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4875 r = pic16_regWithIdx(PCOR(PCOR2(pcop)->pcop2)->r->rIdx);
4878 SAFE_snprintf(&buffer,&size,"%s",r->name);
4889 if(PCOI(pcop)->_const) {
4890 if( PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4891 SAFE_snprintf(&s,&size,"(((%s+%d) >> %d)&0xff)",
4894 8 * PCOI(pcop)->offset );
4896 SAFE_snprintf(&s,&size,"LOW(%s+%d)",pcop->name,PCOI(pcop)->index);
4898 if( PCOI(pcop)->index) {
4899 SAFE_snprintf(&s,&size,"(%s + %d)",
4901 PCOI(pcop)->index );
4903 if(PCOI(pcop)->offset)
4904 SAFE_snprintf(&s,&size,"(%s >> %d)&0xff",pcop->name, 8*PCOI(pcop)->offset);
4906 SAFE_snprintf(&s,&size,"%s",pcop->name);
4913 if( PCOR(PCOR2(pcop)->pcop2)->instance) {
4914 SAFE_snprintf(&s,&size,"(%s + %d)",
4915 PCOR(PCOR2(pcop)->pcop2)->r->name,
4916 PCOR(PCOR2(pcop)->pcop2)->instance );
4918 SAFE_snprintf(&s,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4923 if(PCOR(PCOR2(pcop)->pcop2)->r->name) {
4925 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4928 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4933 return "NO operand2";
4936 /*-----------------------------------------------------------------*/
4937 /*-----------------------------------------------------------------*/
4938 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4942 return pic16_get_op(pcc->pcop,NULL,0);
4944 /* gcc 3.2: warning: concatenation of string literals with __FUNCTION__ is deprecated
4945 * return ("ERROR Null: "__FUNCTION__);
4947 return ("ERROR Null: pic16_get_op_from_instruction");
4951 /*-----------------------------------------------------------------*/
4952 /*-----------------------------------------------------------------*/
4953 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4956 fprintf(of,"pcodeopprint- not implemented\n");
4959 /*-----------------------------------------------------------------*/
4960 /* pic16_pCode2str - convert a pCode instruction to string */
4961 /*-----------------------------------------------------------------*/
4962 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4968 if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4969 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4970 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4978 SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4980 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4982 if(PCI(pc)->is2MemOp) {
4983 SAFE_snprintf(&s,&size, "%s, %s",
4984 pic16_get_op(PCOP(PCI(pc)->pcop), NULL, 0),
4985 pic16_get_op2(PCOP(PCI(pc)->pcop), NULL, 0));
4989 if(PCI(pc)->is2LitOp) {
4990 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4994 if(PCI(pc)->isBitInst) {
4995 if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4996 if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4997 SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)",
4998 PCI(pc)->pcop->name ,
4999 PCI(pc)->pcop->name );
5001 SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
5002 // (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
5003 (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
5005 } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5006 SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5008 SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5009 //PCI(pc)->pcop->t.bit );
5012 if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5013 if( PCI(pc)->num_ops == 3)
5014 SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5016 SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5021 SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5024 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5025 if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5026 SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5028 r = pic16_getRegFromInstruction(pc);
5029 // fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5030 // __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?r->accessBank:-1);
5032 if(r && !r->accessBank)SAFE_snprintf(&s,&size,", %s", (!pic16_mplab_comp?"B":"BANKED"));
5040 /* assuming that comment ends with a \n */
5041 SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5045 SAFE_snprintf(&s,&size,"; info ==>");
5046 switch( PCINF(pc)->type ) {
5047 case INF_OPTIMIZATION:
5048 SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5051 SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5056 /* assuming that inline code ends with a \n */
5057 SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5061 SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5064 SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5067 SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5070 SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5073 // SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5074 SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5075 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5078 if(PCAD(pc)->directive) {
5079 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5082 /* special case to handle inline labels without a tab */
5083 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5088 SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5096 /*-----------------------------------------------------------------*/
5097 /* genericPrint - the contents of a pCode to a file */
5098 /*-----------------------------------------------------------------*/
5099 static void genericPrint(FILE *of, pCode *pc)
5107 // fputs(((pCodeComment *)pc)->comment, of);
5108 fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5113 pBranch *pbl = PCI(pc)->label;
5114 while(pbl && pbl->pc) {
5115 if(pbl->pc->type == PC_LABEL)
5116 pCodePrintLabel(of, pbl->pc);
5121 if(pic16_pcode_verbose) {
5122 fprintf(of, "; info ==>");
5123 switch(((pCodeInfo *)pc)->type) {
5124 case INF_OPTIMIZATION:
5125 fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5128 fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5136 fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5140 // If the opcode has a label, print that first
5142 pBranch *pbl = PCI(pc)->label;
5143 while(pbl && pbl->pc) {
5144 if(pbl->pc->type == PC_LABEL)
5145 pCodePrintLabel(of, pbl->pc);
5151 genericPrint(of,PCODE(PCI(pc)->cline));
5156 pic16_pCode2str(str, 256, pc);
5158 fprintf(of,"%s",str);
5160 if(pic16_debug_verbose) {
5161 fprintf(of, "\t;key=%03x",pc->seq);
5163 fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5170 fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5171 if(PCW(pc)->pci.label)
5172 pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5174 if(PCW(pc)->operand) {
5175 fprintf(of,";\toperand ");
5176 pCodeOpPrint(of,PCW(pc)->operand );
5181 if(pic16_debug_verbose) {
5182 fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5183 if(PCFL(pc)->ancestor)
5184 fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5191 // fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5192 fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5193 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5199 pBranch *pbl = PCAD(pc)->pci.label;
5200 while(pbl && pbl->pc) {
5201 if(pbl->pc->type == PC_LABEL)
5202 pCodePrintLabel(of, pbl->pc);
5206 if(PCAD(pc)->directive) {
5207 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5210 /* special case to handle inline labels without tab */
5211 fprintf(of, "%s\n", PCAD(pc)->arg);
5217 fprintf(of,"unknown pCode type %d\n",pc->type);
5222 /*-----------------------------------------------------------------*/
5223 /* pCodePrintFunction - prints function begin/end */
5224 /*-----------------------------------------------------------------*/
5226 static void pCodePrintFunction(FILE *of, pCode *pc)
5233 if( ((pCodeFunction *)pc)->modname)
5234 fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5237 if(!PCF(pc)->absblock) {
5238 if(PCF(pc)->fname) {
5239 pBranch *exits = PCF(pc)->to;
5242 fprintf(of,"%s:", PCF(pc)->fname);
5244 if(pic16_pcode_verbose)
5245 fprintf(of, "\t;Function start");
5251 exits = exits->next;
5255 if(pic16_pcode_verbose)
5256 fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5259 if((PCF(pc)->from &&
5260 PCF(pc)->from->pc->type == PC_FUNCTION &&
5261 PCF(PCF(pc)->from->pc)->fname) ) {
5263 if(pic16_pcode_verbose)
5264 fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5266 if(pic16_pcode_verbose)
5267 fprintf(of,"; exit point [can't find entry point]\n");
5273 /*-----------------------------------------------------------------*/
5274 /* pCodePrintLabel - prints label */
5275 /*-----------------------------------------------------------------*/
5277 static void pCodePrintLabel(FILE *of, pCode *pc)
5284 fprintf(of,"%s:\n",PCL(pc)->label);
5285 else if (PCL(pc)->key >=0)
5286 fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5288 fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5291 /*-----------------------------------------------------------------*/
5292 /* unlinkpCodeFromBranch - Search for a label in a pBranch and */
5293 /* remove it if it is found. */
5294 /*-----------------------------------------------------------------*/
5295 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5302 if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5303 b = PCI(pcl)->label;
5305 fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5310 //fprintf (stderr, "%s \n",__FUNCTION__);
5311 //pcl->print(stderr,pcl);
5312 //pc->print(stderr,pc);
5315 //fprintf (stderr, "found label\n");
5316 //pc->print(stderr, pc);
5320 bprev->next = b->next; /* Not first pCode in chain */
5324 PCI(pcl)->label = b->next; /* First pCode in chain */
5327 return; /* A label can't occur more than once */
5335 /*-----------------------------------------------------------------*/
5336 /*-----------------------------------------------------------------*/
5337 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5356 /*-----------------------------------------------------------------*/
5357 /* pBranchLink - given two pcodes, this function will link them */
5358 /* together through their pBranches */
5359 /*-----------------------------------------------------------------*/
5360 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5364 // Declare a new branch object for the 'from' pCode.
5366 //_ALLOC(b,sizeof(pBranch));
5367 b = Safe_calloc(1,sizeof(pBranch));
5368 b->pc = PCODE(t); // The link to the 'to' pCode.
5371 f->to = pic16_pBranchAppend(f->to,b);
5373 // Now do the same for the 'to' pCode.
5375 //_ALLOC(b,sizeof(pBranch));
5376 b = Safe_calloc(1,sizeof(pBranch));
5380 t->from = pic16_pBranchAppend(t->from,b);
5385 /*-----------------------------------------------------------------*/
5386 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5388 /*-----------------------------------------------------------------*/
5389 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5402 /*-----------------------------------------------------------------*/
5403 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain. */
5404 /*-----------------------------------------------------------------*/
5405 void pic16_pCodeUnlink(pCode *pc)
5410 if(!pc->prev || !pc->next) {
5411 fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5415 /* move C source line down (or up) */
5416 if (isPCI(pc) && PCI(pc)->cline) {
5417 pc1 = pic16_findNextInstruction (pc->next);
5418 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5419 PCI(pc1)->cline = PCI(pc)->cline;
5421 pc1 = pic16_findPrevInstruction (pc->prev);
5422 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5423 PCI(pc1)->cline = PCI(pc)->cline;
5427 /* first remove the pCode from the chain */
5428 pc->prev->next = pc->next;
5429 pc->next->prev = pc->prev;
5431 pc->prev = pc->next = NULL;
5433 /* Now for the hard part... */
5435 /* Remove the branches */
5437 pb1 = PCI(pc)->from;
5439 pc1 = pb1->pc; /* Get the pCode that branches to the
5440 * one we're unlinking */
5442 /* search for the link back to this pCode (the one we're
5444 if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5445 pb2->pc = PCI(pc)->to->pc; // make the replacement
5447 /* if the pCode we're unlinking contains multiple 'to'
5448 * branches (e.g. this a skip instruction) then we need
5449 * to copy these extra branches to the chain. */
5450 if(PCI(pc)->to->next)
5451 pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5460 /*-----------------------------------------------------------------*/
5461 /*-----------------------------------------------------------------*/
5463 static void genericAnalyze(pCode *pc)
5473 // Go through the pCodes that are in pCode chain and link
5474 // them together through the pBranches. Note, the pCodes
5475 // are linked together as a contiguous stream like the
5476 // assembly source code lines. The linking here mimics this
5477 // except that comments are not linked in.
5479 pCode *npc = pc->next;
5481 if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5482 pBranchLink(pc,npc);
5487 /* reached the end of the pcode chain without finding
5488 * an instruction we could link to. */
5492 fprintf(stderr,"analyze PC_FLOW\n");
5496 fprintf(stderr,,";A bad pCode is being used\n");
5502 /*-----------------------------------------------------------------*/
5503 /*-----------------------------------------------------------------*/
5504 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5508 if(pc->type == PC_LABEL) {
5509 if( ((pCodeLabel *)pc)->key == pcop_label->key)
5512 if((pc->type == PC_OPCODE)
5513 || (pc->type == PC_ASMDIR)
5515 pbr = PCI(pc)->label;
5517 if(pbr->pc->type == PC_LABEL) {
5518 if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
5528 /*-----------------------------------------------------------------*/
5529 /*-----------------------------------------------------------------*/
5530 static int checkLabel(pCode *pc)
5534 if(pc && isPCI(pc)) {
5535 pbr = PCI(pc)->label;
5537 if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5547 /*-----------------------------------------------------------------*/
5548 /* findLabelinpBlock - Search the pCode for a particular label */
5549 /*-----------------------------------------------------------------*/
5550 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5557 for(pc = pb->pcHead; pc; pc = pc->next)
5558 if(compareLabel(pc,pcop_label))
5564 /*-----------------------------------------------------------------*/
5565 /* findLabel - Search the pCode for a particular label */
5566 /*-----------------------------------------------------------------*/
5567 static pCode * findLabel(pCodeOpLabel *pcop_label)
5575 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5576 if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5580 fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5584 /*-----------------------------------------------------------------*/
5585 /* pic16_findNextpCode - given a pCode, find the next of type 'pct' */
5586 /* in the linked list */
5587 /*-----------------------------------------------------------------*/
5588 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5601 /*-----------------------------------------------------------------*/
5602 /* findPrevpCode - given a pCode, find the previous of type 'pct' */
5603 /* in the linked list */
5604 /*-----------------------------------------------------------------*/
5605 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5619 //#define PCODE_DEBUG
5620 /*-----------------------------------------------------------------*/
5621 /* pic16_findNextInstruction - given a pCode, find the next instruction */
5622 /* in the linked list */
5623 /*-----------------------------------------------------------------*/
5624 pCode * pic16_findNextInstruction(pCode *pci)
5629 if((pc->type == PC_OPCODE)
5630 || (pc->type == PC_WILD)
5631 || (pc->type == PC_ASMDIR)
5636 fprintf(stderr,"pic16_findNextInstruction: ");
5637 printpCode(stderr, pc);
5642 //fprintf(stderr,"Couldn't find instruction\n");
5646 /*-----------------------------------------------------------------*/
5647 /* pic16_findPrevInstruction - given a pCode, find the next instruction */
5648 /* in the linked list */
5649 /*-----------------------------------------------------------------*/
5650 pCode * pic16_findPrevInstruction(pCode *pci)
5656 if((pc->type == PC_OPCODE)
5657 || (pc->type == PC_WILD)
5658 || (pc->type == PC_ASMDIR)
5664 fprintf(stderr,"pic16_findPrevInstruction: ");
5665 printpCode(stderr, pc);
5670 //fprintf(stderr,"Couldn't find instruction\n");
5677 /*-----------------------------------------------------------------*/
5678 /* findFunctionEnd - given a pCode find the end of the function */
5679 /* that contains it */
5680 /*-----------------------------------------------------------------*/
5681 static pCode * findFunctionEnd(pCode *pc)
5685 if(pc->type == PC_FUNCTION && !(PCF(pc)->fname))
5691 fprintf(stderr,"Couldn't find function end\n");
5696 /*-----------------------------------------------------------------*/
5697 /* AnalyzeLabel - if the pCode is a label, then merge it with the */
5698 /* instruction with which it is associated. */
5699 /*-----------------------------------------------------------------*/
5700 static void AnalyzeLabel(pCode *pc)
5703 pic16_pCodeUnlink(pc);
5709 static void AnalyzeGOTO(pCode *pc)
5712 pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5716 static void AnalyzeSKIP(pCode *pc)
5719 pBranchLink(pc,pic16_findNextInstruction(pc->next));
5720 pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5724 static void AnalyzeRETURN(pCode *pc)
5727 // branch_link(pc,findFunctionEnd(pc->next));
5733 /*-------------------------------------------------------------------*/
5734 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp */
5735 /* if one is present. This is the common */
5736 /* part of pic16_getRegFromInstruction(2) */
5737 /*-------------------------------------------------------------------*/
5739 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5740 if (!pcop) return NULL;
5742 switch(pcop->type) {
5755 return PCOR(pcop)->r;
5757 case PO_SFR_REGISTER:
5758 //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5759 return PCOR(pcop)->r;
5763 // fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5764 return PCOR(pcop)->r;
5767 // return pic16_dirregWithName(PCOI(pcop)->r->name);
5770 return (PCOI(pcop)->r);
5775 return PCOR(pcop)->r;
5777 case PO_GPR_REGISTER:
5779 // fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5780 return PCOR(pcop)->r;
5783 //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5788 //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5793 /* this should never turn up */
5794 //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5801 fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5809 /*-----------------------------------------------------------------*/
5810 /*-----------------------------------------------------------------*/
5811 regs * pic16_getRegFromInstruction(pCode *pc)
5817 PCI(pc)->num_ops == 0 ||
5818 (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5822 fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5823 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5826 return pic16_getRegFrompCodeOp (PCI(pc)->pcop);
5829 /*-------------------------------------------------------------------------------*/
5830 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5831 /*-------------------------------------------------------------------------------*/
5832 regs * pic16_getRegFromInstruction2(pCode *pc)
5838 PCI(pc)->num_ops == 0 ||
5839 (PCI(pc)->num_ops == 1)) // accept only 2 operand commands
5844 fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5845 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5848 return pic16_getRegFrompCodeOp (PCOR2(PCI(pc)->pcop)->pcop2);
5851 /*-----------------------------------------------------------------*/
5852 /*-----------------------------------------------------------------*/
5854 static void AnalyzepBlock(pBlock *pb)
5861 /* Find all of the registers used in this pBlock
5862 * by looking at each instruction and examining it's
5865 for(pc = pb->pcHead; pc; pc = pc->next) {
5867 /* Is this an instruction with operands? */
5868 if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5870 if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5872 /* Loop through all of the registers declared so far in
5873 this block and see if we find this one there */
5875 regs *r = setFirstItem(pb->tregisters);
5878 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5879 PCOR(PCI(pc)->pcop)->r = r;
5882 r = setNextItem(pb->tregisters);
5886 /* register wasn't found */
5887 //r = Safe_calloc(1, sizeof(regs));
5888 //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5889 //addSet(&pb->tregisters, r);
5890 addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5891 //PCOR(PCI(pc)->pcop)->r = r;
5892 //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5894 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5897 if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5898 if(PCOR(PCI(pc)->pcop)->r) {
5899 pic16_allocWithIdx (PCOR(PCI(pc)->pcop)->r->rIdx);
5900 DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5902 if(PCI(pc)->pcop->name)
5903 fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5905 fprintf(stderr,"ERROR: NULL register\n");
5914 /*-----------------------------------------------------------------*/
5916 /*-----------------------------------------------------------------*/
5917 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5919 static void InsertpFlow(pCode *pc, pCode **pflow)
5922 PCFL(*pflow)->end = pc;
5924 if(!pc || !pc->next)
5927 *pflow = pic16_newpCodeFlow();
5928 pic16_pCodeInsertAfter(pc, *pflow);
5931 /*-----------------------------------------------------------------*/
5932 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5933 /* the flow blocks. */
5935 * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5936 * point the instruction flow changes.
5938 /*-----------------------------------------------------------------*/
5939 void pic16_BuildFlow(pBlock *pb)
5942 pCode *last_pci=NULL;
5949 //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq);
5950 /* Insert a pCodeFlow object at the beginning of a pBlock */
5952 InsertpFlow(pb->pcHead, &pflow);
5954 //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */
5955 //pflow->next = pb->pcHead; /* Make the current head the next object */
5956 //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */
5957 //pb->pcHead = pflow; /* Make the Flow object the head */
5960 for( pc = pic16_findNextInstruction(pb->pcHead);
5962 pc=pic16_findNextInstruction(pc)) {
5965 PCI(pc)->pcflow = PCFL(pflow);
5967 //fprintf(stderr," build: ");
5968 //pflow->print(stderr,pflow);
5970 if (checkLabel(pc)) {
5972 /* This instruction marks the beginning of a
5973 * new flow segment */
5978 /* If the previous pCode is not a flow object, then
5979 * insert a new flow object. (This check prevents
5980 * two consecutive flow objects from being insert in
5981 * the case where a skip instruction preceeds an
5982 * instruction containing a label.) */
5984 if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5985 InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5987 PCI(pc)->pcflow = PCFL(pflow);
5991 if( PCI(pc)->isSkip) {
5993 /* The two instructions immediately following this one
5994 * mark the beginning of a new flow segment */
5996 while(pc && PCI(pc)->isSkip) {
5998 PCI(pc)->pcflow = PCFL(pflow);
6002 InsertpFlow(pc, &pflow);
6003 pc=pic16_findNextInstruction(pc->next);
6011 PCI(pc)->pcflow = PCFL(pflow);
6013 InsertpFlow(pc, &pflow);
6015 } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) {
6017 InsertpFlow(pc, &pflow);
6025 //fprintf (stderr,",end seq %d",GpcFlowSeq);
6027 PCFL(pflow)->end = pb->pcTail;
6030 /*-------------------------------------------------------------------*/
6031 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */
6032 /* the flow blocks. */
6034 * unBuildFlow removes pCodeFlow objects from a pCode chain
6036 /*-----------------------------------------------------------------*/
6037 static void unBuildFlow(pBlock *pb)
6052 if(PCI(pc)->pcflow) {
6053 //Safe_free(PCI(pc)->pcflow);
6054 PCI(pc)->pcflow = NULL;
6057 } else if(isPCFL(pc) )
6066 /*-----------------------------------------------------------------*/
6067 /*-----------------------------------------------------------------*/
6068 static void dumpCond(int cond)
6071 static char *pcc_str[] = {
6085 int ncond = sizeof(pcc_str) / sizeof(char *);
6088 fprintf(stderr, "0x%04X\n",cond);
6090 for(i=0,j=1; i<ncond; i++, j<<=1)
6092 fprintf(stderr, " %s\n",pcc_str[i]);
6098 /*-----------------------------------------------------------------*/
6099 /*-----------------------------------------------------------------*/
6100 static void FlowStats(pCodeFlow *pcflow)
6108 fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6110 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6113 fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6118 fprintf(stderr, " FlowStats inCond: ");
6119 dumpCond(pcflow->inCond);
6120 fprintf(stderr, " FlowStats outCond: ");
6121 dumpCond(pcflow->outCond);
6125 /*-----------------------------------------------------------------*
6126 * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6127 * if it affects the banking bits.
6129 * return: -1 == Banking bits are unaffected by this pCode.
6131 * return: > 0 == Banking bits are affected.
6133 * If the banking bits are affected, then the returned value describes
6134 * which bits are affected and how they're affected. The lower half
6135 * of the integer maps to the bits that are affected, the upper half
6136 * to whether they're set or cleared.
6138 *-----------------------------------------------------------------*/
6140 static int isBankInstruction(pCode *pc)
6148 if( PCI(pc)->op == POC_MOVLB ||
6149 (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6150 bank = PCOL(pc)->lit;
6157 /*-----------------------------------------------------------------*/
6158 /*-----------------------------------------------------------------*/
6159 static void FillFlow(pCodeFlow *pcflow)
6168 // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6170 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6173 //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6180 isBankInstruction(pc);
6182 } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6186 fprintf(stderr, " FillFlow - Bad end of flow\n");
6188 fprintf(stderr, " FillFlow - Ending flow with\n ");
6189 pc->print(stderr,pc);
6192 fprintf(stderr, " FillFlow inCond: ");
6193 dumpCond(pcflow->inCond);
6194 fprintf(stderr, " FillFlow outCond: ");
6195 dumpCond(pcflow->outCond);
6199 /*-----------------------------------------------------------------*/
6200 /*-----------------------------------------------------------------*/
6201 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6203 pCodeFlowLink *fromLink, *toLink;
6205 if(!from || !to || !to->pcflow || !from->pcflow)
6208 fromLink = pic16_newpCodeFlowLink(from->pcflow);
6209 toLink = pic16_newpCodeFlowLink(to->pcflow);
6211 addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
6212 addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6216 pCode *pic16_getJumptabpCode (pCode *pc) {
6219 //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6220 //pc->print (stderr, pc);
6223 if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6224 if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6225 switch (PCOO(PCINF(pcinf)->oper1)->type) {
6226 case OPT_JUMPTABLE_BEGIN:
6227 /* leading begin of jump table -- in one */
6228 pcinf = pic16_findPrevInstruction (pcinf);
6232 case OPT_JUMPTABLE_END:
6233 /* leading end of jumptable -- not in one */
6238 /* ignore all other PCInfos */
6242 pcinf = pcinf->prev;
6245 /* no PCInfo found -- not in a jumptable */
6249 /*-----------------------------------------------------------------*
6250 * void LinkFlow(pBlock *pb)
6252 * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6253 * non-branching segments. In LinkFlow, we determine the execution
6254 * order of these segments. For example, if one of the segments ends
6255 * with a skip, then we know that there are two possible flow segments
6256 * to which control may be passed.
6257 *-----------------------------------------------------------------*/
6258 static void LinkFlow(pBlock *pb)
6263 pCode *jumptab_pre = NULL;
6265 //fprintf(stderr,"linkflow \n");
6267 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6269 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6272 fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6274 //fprintf(stderr," link: ");
6275 //pcflow->print(stderr,pcflow);
6277 //FillFlow(PCFL(pcflow));
6279 pc = PCFL(pcflow)->end;
6281 //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6282 if(isPCI_SKIP(pc)) {
6283 // fprintf(stderr, "ends with skip\n");
6284 // pc->print(stderr,pc);
6286 pct=pic16_findNextInstruction(pc->next);
6287 LinkFlow_pCode(PCI(pc),PCI(pct));
6288 pct=pic16_findNextInstruction(pct->next);
6289 LinkFlow_pCode(PCI(pc),PCI(pct));
6293 if(isPCI_BRANCH(pc)) {
6294 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6296 /* handle GOTOs in jumptables */
6297 if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6298 /* link to previous flow */
6299 //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6300 LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6303 switch (PCI(pc)->op) {
6309 /* unconditional branches -- do not link to next instruction */
6310 //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6315 /* unconditional calls -- link to next instruction */
6316 //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6317 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6328 /* conditional branches -- also link to next instruction */
6329 //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6330 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6334 fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6335 assert (0 && "unhandled branching instruction");
6339 //fprintf(stderr, "ends with branch\n ");
6340 //pc->print(stderr,pc);
6342 if(!(pcol && isPCOLAB(pcol))) {
6343 if((PCI(pc)->op != POC_RETLW)
6344 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6346 /* continue if label is '$' which assembler knows how to parse */
6347 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6349 if(pic16_pcode_verbose) {
6350 pc->print(stderr,pc);
6351 fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6357 if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6358 LinkFlow_pCode(PCI(pc),PCI(pct));
6360 fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6361 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6363 // fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6369 //fprintf(stderr, "ends with non-branching instruction:\n");
6370 //pc->print(stderr,pc);
6372 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6378 //fprintf(stderr, "ends with unknown\n");
6379 //pc->print(stderr,pc);
6383 //fprintf(stderr, "ends with nothing: ERROR\n");
6387 /*-----------------------------------------------------------------*/
6388 /*-----------------------------------------------------------------*/
6390 /*-----------------------------------------------------------------*/
6391 /*-----------------------------------------------------------------*/
6392 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6398 if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6401 if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6411 /*-----------------------------------------------------------------*/
6412 /* insertBankSwitch - inserts a bank switch statement in the */
6413 /* assembly listing */
6415 /* position == 0: insert before */
6416 /* position == 1: insert after pc */
6417 /* position == 2: like 0 but previous was a skip instruction */
6418 /*-----------------------------------------------------------------*/
6419 pCodeOp *pic16_popGetLabel(unsigned int key);
6420 extern int pic16_labelOffset;
6422 static void insertBankSwitch(unsigned char position, pCode *pc)
6429 /* emit BANKSEL [symbol] */
6432 new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6434 // position = 0; // position is always before (sanity check!)
6437 fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6438 pc->print(stderr, pc);
6443 /* insert the bank switch after this pc instruction */
6444 pCode *pcnext = pic16_findNextInstruction(pc);
6446 pic16_pCodeInsertAfter(pc, new_pc);
6447 if(pcnext)pc = pcnext;
6451 /* insert the bank switch BEFORE this pc instruction */
6452 pic16_pCodeInsertAfter(pc->prev, new_pc);
6457 pCode *pcnext, *pcprev, *npci, *ppc;
6459 int ofs1=0, ofs2=0, len=0;
6461 /* just like 0, but previous was a skip instruction,
6462 * so some care should be taken */
6464 pic16_labelOffset += 10000;
6465 tlbl = newiTempLabel(NULL);
6467 /* invert skip instruction */
6468 pcprev = pic16_findPrevInstruction(pc->prev);
6469 ipci = PCI(pcprev)->inverted_op;
6470 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6472 // fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6474 /* copy info from old pCode */
6475 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6476 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6477 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6478 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6479 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6480 PCI(npci)->op = PCI(pcprev)->inverted_op;
6482 /* unlink old pCode */
6484 ppc->next = pcprev->next;
6485 pcprev->next->prev = ppc;
6486 pic16_pCodeInsertAfter(ppc, npci);
6488 /* extra instructions to handle invertion */
6489 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6490 pic16_pCodeInsertAfter(npci, pcnext);
6491 pic16_pCodeInsertAfter(pc->prev, new_pc);
6493 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6494 pic16_pCodeInsertAfter(pc, pcnext);
6499 /* Move the label, if there is one */
6500 if(PCI(pc)->label) {
6501 // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6502 // __FILE__, __LINE__, pc, new_pc);
6503 PCAD(new_pc)->pci.label = PCI(pc)->label;
6504 PCI(pc)->label = NULL;
6509 /*-----------------------------------------------------------------*/
6510 /*int compareBankFlow - compare the banking requirements between */
6512 /*-----------------------------------------------------------------*/
6513 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6516 if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6519 if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6522 if(pcflow->firstBank == -1)
6526 if(pcflowLink->pcflow->firstBank == -1) {
6527 pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6528 pcflowLink->pcflow->to :
6529 pcflowLink->pcflow->from);
6530 return compareBankFlow(pcflow, pctl, toORfrom);
6534 if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6537 pcflowLink->bank_conflict++;
6538 pcflowLink->pcflow->FromConflicts++;
6539 pcflow->ToConflicts++;
6542 if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6545 pcflowLink->bank_conflict++;
6546 pcflowLink->pcflow->ToConflicts++;
6547 pcflow->FromConflicts++;
6551 fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6552 pcflowLink->pcflow->pc.seq,
6553 pcflowLink->pcflow->FromConflicts,
6554 pcflowLink->pcflow->ToConflicts);
6561 /*-----------------------------------------------------------------*/
6562 /*-----------------------------------------------------------------*/
6563 static void DumpFlow(pBlock *pb)
6567 pCodeFlowLink *pcfl;
6570 fprintf(stderr,"Dump flow \n");
6571 pb->pcHead->print(stderr, pb->pcHead);
6573 pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6574 pcflow->print(stderr,pcflow);
6576 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6578 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6580 if(!isPCFL(pcflow)) {
6581 fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6584 fprintf(stderr,"dumping: ");
6585 pcflow->print(stderr,pcflow);
6586 FlowStats(PCFL(pcflow));
6588 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6590 pc = PCODE(pcfl->pcflow);
6592 fprintf(stderr, " from seq %d:\n",pc->seq);
6594 fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6595 pc->print(stderr,pc);
6600 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6602 pc = PCODE(pcfl->pcflow);
6604 fprintf(stderr, " to seq %d:\n",pc->seq);
6606 fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6607 pc->print(stderr,pc);
6616 /*-----------------------------------------------------------------*/
6617 /*-----------------------------------------------------------------*/
6618 static int OptimizepBlock(pBlock *pb)
6623 if(!pb || !peepOptimizing)
6626 DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6628 for(pc = pb->pcHead; pc; pc = pc->next)
6629 matches += pic16_pCodePeepMatchRule(pc);
6632 pc = pic16_findNextInstruction(pb->pcHead);
6640 if(pic16_pCodePeepMatchRule(pc)) {
6645 pc = pic16_findNextInstruction(pcprev->next);
6647 pc = pic16_findNextInstruction(pb->pcHead);
6649 pc = pic16_findNextInstruction(pc->next);
6653 DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6658 /*-----------------------------------------------------------------*/
6659 /*-----------------------------------------------------------------*/
6660 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6664 for(pc = pcs; pc; pc = pc->next) {
6666 if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6668 (PCI(pc)->pcop->type == PO_LABEL) &&
6669 (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6677 /*-----------------------------------------------------------------*/
6678 /*-----------------------------------------------------------------*/
6679 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6686 (PCI(pc)->pcop->type == PO_LABEL)) {
6688 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6690 // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6691 // if(pcol->pcop.name)
6692 // Safe_free(pcol->pcop.name);
6694 /* If the key is negative, then we (probably) have a label to
6695 * a function and the name is already defined */
6698 sprintf(s=buffer,"_%05d_DS_",pcl->key);
6702 //sprintf(buffer,"_%05d_DS_",pcl->key);
6704 fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6706 pcol->pcop.name = Safe_strdup(s);
6707 pcol->key = pcl->key;
6708 //pc->print(stderr,pc);
6715 /*-----------------------------------------------------------------*/
6716 /* pBlockRemoveUnusedLabels - remove the pCode labels from the */
6717 /* pCode chain if they're not used. */
6718 /*-----------------------------------------------------------------*/
6719 static void pBlockRemoveUnusedLabels(pBlock *pb)
6721 pCode *pc; pCodeLabel *pcl;
6726 for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6728 pBranch *pbr = PCI(pc)->label;
6729 if(pbr && pbr->next) {
6730 pCode *pcd = pb->pcHead;
6732 // fprintf(stderr, "multiple labels\n");
6733 // pc->print(stderr,pc);
6738 while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6739 //fprintf(stderr,"Used by:\n");
6740 //pcd->print(stderr,pcd);
6742 exchangeLabels(PCL(pbr->pc),pcd);
6751 for(pc = pb->pcHead; pc; pc = pc->next) {
6753 if(isPCL(pc)) // pc->type == PC_LABEL)
6755 else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6756 pcl = PCL(PCI(pc)->label->pc);
6759 // fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6761 /* This pCode is a label, so search the pBlock to see if anyone
6764 if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6766 //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6767 /* Couldn't find an instruction that refers to this label
6768 * So, unlink the pCode label from it's pCode chain
6769 * and destroy the label */
6770 // fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6772 DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6773 if(pc->type == PC_LABEL) {
6774 pic16_unlinkpCode(pc);
6775 pCodeLabelDestruct(pc);
6777 unlinkpCodeFromBranch(pc, PCODE(pcl));
6778 /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6779 Safe_free(pc->label);
6789 /*-----------------------------------------------------------------*/
6790 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */
6791 /* chain and put them into pBranches that are */
6792 /* associated with the appropriate pCode */
6794 /*-----------------------------------------------------------------*/
6795 void pic16_pBlockMergeLabels(pBlock *pb)
6798 pCode *pc, *pcnext=NULL;
6803 /* First, Try to remove any unused labels */
6804 //pBlockRemoveUnusedLabels(pb);
6806 /* Now loop through the pBlock and merge the labels with the opcodes */
6809 // for(pc = pb->pcHead; pc; pc = pc->next) {
6812 pCode *pcn = pc->next;
6814 if(pc->type == PC_LABEL) {
6816 // fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6817 // fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6819 if((pcnext = pic16_findNextInstruction(pc) )) {
6821 // pcnext->print(stderr, pcnext);
6823 // Unlink the pCode label from it's pCode chain
6824 pic16_unlinkpCode(pc);
6826 // fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6827 // And link it into the instruction's pBranch labels. (Note, since
6828 // it's possible to have multiple labels associated with one instruction
6829 // we must provide a means to accomodate the additional labels. Thus
6830 // the labels are placed into the singly-linked list "label" as
6831 // opposed to being a single member of the pCodeInstruction.)
6833 //_ALLOC(pbr,sizeof(pBranch));
6835 pbr = Safe_calloc(1,sizeof(pBranch));
6839 PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6842 if(pic16_pcode_verbose)
6843 fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6845 } else if(pc->type == PC_CSOURCE) {
6847 /* merge the source line symbolic info into the next instruction */
6848 if((pcnext = pic16_findNextInstruction(pc) )) {
6850 // Unlink the pCode label from it's pCode chain
6851 pic16_unlinkpCode(pc);
6852 PCI(pcnext)->cline = PCCS(pc);
6853 //fprintf(stderr, "merging CSRC\n");
6854 //genericPrint(stderr,pcnext);
6860 pBlockRemoveUnusedLabels(pb);
6864 /*-----------------------------------------------------------------*/
6865 /*-----------------------------------------------------------------*/
6866 static int OptimizepCode(char dbName)
6868 #define MAX_PASSES 4
6877 DFPRINTF((stderr," Optimizing pCode\n"));
6881 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6882 if('*' == dbName || getpBlock_dbName(pb) == dbName)
6883 matches += OptimizepBlock(pb);
6886 while(matches && ++passes < MAX_PASSES);
6893 const char *pic16_pCodeOpType(pCodeOp *pcop);
6894 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6897 /*-----------------------------------------------------------------*/
6898 /* pic16_popCopyGPR2Bit - copy a pcode operator */
6899 /*-----------------------------------------------------------------*/
6901 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6905 // fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6908 pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6910 if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6913 assert(pcop != NULL);
6915 if( !( (pcop->type == PO_LABEL) ||
6916 (pcop->type == PO_LITERAL) ||
6917 (pcop->type == PO_STR) ))
6918 PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */
6919 PCOR(pcop)->r->wasUsed = 1;
6920 PCOR(pcop)->instance = PCOR(pc)->instance;
6926 /*----------------------------------------------------------------------*
6927 * pic16_areRegsSame - check to see if the names of two registers match *
6928 *----------------------------------------------------------------------*/
6929 int pic16_areRegsSame(regs *r1, regs *r2)
6931 if(!strcmp(r1->name, r2->name))return 1;
6937 /*-----------------------------------------------------------------*/
6938 /*-----------------------------------------------------------------*/
6939 static void pic16_FixRegisterBanking(pBlock *pb)
6943 regs *reg, *prevreg;
6944 unsigned char flag=0;
6949 pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6952 /* loop through all of the flow blocks with in one pblock */
6954 // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6958 /* at this point, pc should point to a PC_FLOW object */
6959 /* for each flow block, determine the register banking
6963 /* if label, then might come from other point, force banksel */
6964 if(isPCL(pc))prevreg = NULL;
6966 if(!isPCI(pc))goto loop;
6968 if(PCI(pc)->label)prevreg = NULL;
6970 if(PCI(pc)->is2MemOp)goto loop;
6972 /* if goto, then force banksel */
6973 // if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6975 reg = pic16_getRegFromInstruction(pc);
6978 pc->print(stderr, pc);
6979 fprintf(stderr, "reg = %p\n", reg);
6982 fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6983 fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6984 reg->address,reg->isBitField, reg->isFixed);
6988 /* now make some tests to make sure that instruction needs bank switch */
6990 /* if no register exists, and if not a bit opcode goto loop */
6992 if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6995 if(isPCI_SKIP(pc)) {
6996 // fprintf(stderr, "instruction is SKIP instruction\n");
6999 if(reg && isACCESS_BANK(reg))goto loop;
7001 if(!isBankInstruction(pc))goto loop;
7003 if(isPCI_LIT(pc))goto loop;
7005 if(PCI(pc)->op == POC_CALL)goto loop;
7007 /* Examine the instruction before this one to make sure it is
7008 * not a skip type instruction */
7009 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7011 flag = 0; /* add before this instruction */
7013 /* if previous instruction is a skip one, then set flag
7014 * to 2 and call insertBankSwitch */
7015 if(pcprev && isPCI_SKIP(pcprev)) {
7020 if(pic16_options.opt_banksel>0) {
7021 char op1[128], op2[128];
7024 strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7025 strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7026 if(!strcmp(op1, op2))goto loop;
7030 insertBankSwitch(flag, pc);
7032 // fprintf(stderr, "BANK SWITCH inserted\n");
7040 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7042 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7043 int instrSize (pCode *pc)
7048 if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7049 return 4; // assumes only regular instructions using <= 4 bytes
7052 if (isPCI(pc)) return PCI(pc)->isize;
7057 /* Returns 1 if pc is referenced by the given label (either
7058 * pc is the label itself or is an instruction with an attached
7060 * Returns 0 if pc is not preceeded by the specified label.
7062 int isLabel (pCode *pc, char *label)
7066 // label attached to the pCode?
7067 if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7068 pBranch *lab = NULL;
7069 lab = PCI(pc)->label;
7072 if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7079 // is inline assembly label?
7080 if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7081 // do not compare trailing ':'
7082 if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7089 if (strcmp(PCL(pc)->label,label) == 0) {
7094 // no label/no label attached/wrong label(s)
7098 /* Returns the distance to the given label in terms of words.
7099 * Labels are searched only within -max .. max words from pc.
7100 * Returns max if the label could not be found or
7101 * its distance from pc in (-max..+max).
7103 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7104 int dist = instrSize(pc);
7108 while (dist < max && curr && !isLabel (curr, label)) {
7110 dist += instrSize(curr); // sizeof (instruction)
7112 if (curr && dist < max) {
7113 if (target != NULL) *target = curr;
7118 curr = pic16_findNextInstruction (pc->next);
7120 while (dist < max && curr && !isLabel (curr, label)) {
7121 dist += instrSize(curr); // sizeof (instruction)
7124 if (curr && dist < max) {
7125 if (target != NULL) *target = curr;
7129 if (target != NULL) *target = NULL;
7133 /* Returns -1 if pc does NOT denote an instruction like
7135 * Otherwise we return
7136 * (a) 0x10 + i for BTFSS
7137 * (b) 0x00 + i for BTFSC
7139 int isSkipOnStatus (pCode *pc)
7143 if (!pc || !isPCI(pc)) return -1;
7144 if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7145 else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7148 pcop = PCI(pc)->pcop;
7150 if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7151 return res + ((pCodeOpRegBit *)pcop)->bit;
7157 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7158 * returns 0 otherwise. */
7159 int isConditionalBranch (pCode *pc)
7161 if (!pc || !isPCI_BRANCH(pc)) return 0;
7163 switch (PCI(pc)->op) {
7181 /* Returns 1 if pc has a label attached to it.
7182 * This can be either a label stored in the pCode itself (.label)
7183 * or a label making up its own pCode preceding this pc.
7184 * Returns 0 if pc cannot be reached directly via a label.
7186 int hasNoLabel (pCode *pc)
7191 // are there any label pCodes between pc and the previous instruction?
7192 prev = pic16_findPrevInstruction (pc->prev);
7193 while (pc && pc != prev) {
7194 // pCode with attached label?
7195 if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7196 && PCI(pc)->label) {
7199 // is inline assembly label?
7200 if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7201 if (isPCW(pc) && PCW(pc)->label) return 0;
7204 if (isPCL(pc)) return 0;
7213 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7218 vsprintf (buf, fmt, va);
7221 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7224 /* Replaces the old pCode with the new one, moving the labels,
7225 * C source line and probably flow information to the new pCode.
7227 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7228 if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7231 /* first move all labels from old to new */
7232 PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7233 PCI(oldPC)->label = NULL;
7236 /* move C source line (if possible) */
7237 if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7238 PCI(newPC)->cline = PCI(oldPC)->cline;
7241 /* keep flow information intact */
7242 newPC->seq = oldPC->seq;
7243 PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7244 if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7245 PCI(newPC)->pcflow->end = newPC;
7248 /* insert a comment stating which pCode has been replaced */
7250 if (pic16_pcode_verbose || pic16_debug_verbose) {
7252 pic16_pCode2str (pc_str, 256, oldPC);
7253 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7257 /* insert new pCode into pBlock */
7258 pic16_pCodeInsertAfter (oldPC, newPC);
7259 pic16_unlinkpCode (oldPC);
7261 /* destruct replaced pCode */
7262 oldPC->destruct (oldPC);
7265 /* Returns the inverted conditional branch (if any) or NULL.
7266 * pcop must be set to the new jump target.
7268 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7272 if (!bcc || !isPCI(bcc)) return NULL;
7274 switch (PCI(bcc)->op) {
7275 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7276 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7277 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7278 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7279 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7280 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7281 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7282 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7289 #define MAX_DIST_GOTO 0x7FFFFFFF
7290 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7291 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7292 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7293 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7295 /* Follows GOTO/BRA instructions to their target instructions, stores the
7296 * final destination (not a GOTO or BRA instruction) in target and returns
7297 * the distance from the original pc to *target.
7299 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7302 pCodeOp *lastPCOP = NULL;
7306 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7308 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7309 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7310 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7312 lastPCOP = PCI(curr)->pcop;
7313 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7314 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7317 if (target) *target = last;
7318 if (pcop) *pcop = lastPCOP;
7322 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7323 * Otherwise the first pCode after the jumptable (after
7324 * the OPT_JUMPTABLE_END tag) is returned.
7326 pCode *skipJumptables (pCode *pc, int *isJumptable)
7329 if (!pc) return NULL;
7331 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7333 //fprintf (stderr, "SKIPPING jumptable\n");
7335 //pc->print(stderr, pc);
7337 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7338 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7339 //fprintf (stderr, "<<JUMPTAB:\n");
7340 // skip OPT_END as well
7341 if (pc) pc = pc->next;
7347 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7351 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7352 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7353 pc = skipJumptables (pc, &isJumptab);
7355 // pc is the first pCode after the jumptable
7358 // pc has not been changed by skipJumptables()
7366 /* Turn GOTOs into BRAs if distance between GOTO and label
7367 * is less than 1024 bytes.
7369 * This method is especially useful if GOTOs after BTFS[SC]
7370 * can be turned into BRAs as GOTO would cost another NOP
7373 void pic16_OptimizeJumps ()
7376 pCode *pc_prev = NULL;
7377 pCode *pc_next = NULL;
7380 int change, iteration, isJumptab;
7383 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7385 if (!the_pFile) return;
7387 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7389 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7390 int matchedInvertRule = 1;
7393 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7395 pc = pic16_findNextInstruction (pb->pcHead);
7398 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7400 // skip jumptable, i.e. start over with no pc_prev!
7406 /* (1) resolve chained jumps
7407 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7408 * (a) leave dead code in and
7409 * (b) skip over the dead code with an (unneccessary) jump.
7411 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7412 pCodeOp *lastTargetOp = NULL;
7413 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7414 int maxDist = MAX_DIST_BCC;
7415 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7416 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7418 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7419 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7420 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7421 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7422 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7423 PCI(pc)->pcop->name = lastTargetOp->name;
7432 int condBraType = isSkipOnStatus(pc_prev);
7433 label = PCI(pc)->pcop->name;
7434 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7435 if (dist < 0) dist = -dist;
7436 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7440 /* (2) remove "GOTO label; label:" */
7441 if (isLabel (pc_next, label)) {
7442 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7443 // first remove all preceeding SKIP instructions
7444 while (pc_prev && isPCI_SKIP(pc_prev)) {
7445 // attach labels on this instruction to pc_next
7446 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7447 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7448 PCI(pc_prev)->label = NULL;
7449 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7450 pic16_unlinkpCode (pc_prev);
7451 pc_prev = pic16_findPrevInstruction (pc);
7453 // now remove the redundant goto itself
7454 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7455 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7456 pic16_unlinkpCode (pc);
7457 pc = pic16_findPrevInstruction(pc_next->prev);
7458 isHandled = 1; // do not perform further optimizations
7464 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7465 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7466 if (dist < MAX_DIST_BCC) {
7468 switch (condBraType) {
7469 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7470 // no BDC on DIGIT CARRY available
7471 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7472 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7473 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7474 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7475 // no BNDC on DIGIT CARRY available
7476 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7477 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7478 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7480 // no replacement possible
7485 // ATTENTION: keep labels attached to BTFSx!
7486 // HINT: GOTO is label free (checked above)
7487 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7488 isHandled = 1; // do not perform further optimizations
7489 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7490 pic16_pCodeReplace (pc_prev, bcc);
7497 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7503 // (4) eliminate the following (common) tripel:
7505 // labels1: Bcc label2;
7506 // GOTO somewhere; ; <-- instruction referenced by pc
7508 // and replace it by
7509 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7511 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7512 // to <cont.> instead
7513 // ATTENTION: This optimization is only valid if <pred.> is
7514 // not a skip operation!
7515 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7516 // ATTENTION: no label may be attached to the GOTO instruction!
7517 if (isConditionalBranch(pc_prev)
7518 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7519 && (dist < MAX_DIST_BCC)
7520 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7521 && hasNoLabel(pc)) {
7522 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7525 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7526 isHandled = 1; // do not perform further optimizations
7527 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7528 pic16_pCodeReplace (pc_prev, newBcc);
7533 matchedInvertRule++;
7538 /* (5) now just turn GOTO into BRA */
7539 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7540 if (dist < MAX_DIST_BRA) {
7541 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7542 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7543 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7544 pic16_pCodeReplace (pc, newBra);
7549 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7552 } // if (!isHandled)
7559 pBlockRemoveUnusedLabels (pb);
7561 // This line enables goto chain resolution!
7562 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7565 } while (change); /* fixpoint iteration per pBlock */
7568 // emit some statistics concerning goto-optimization
7570 if (pic16_debug_verbose || pic16_pcode_verbose) {
7571 fprintf (stderr, "optimize-goto:\n"
7572 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7573 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7574 "\t%5d conditional \"skipping\" jumps inverted\n"
7575 "\t%5d GOTOs to next instruction removed\n"
7576 "\t%5d chained GOTOs resolved\n",
7577 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7580 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7584 #undef MAX_JUMPCHAIN_DEPTH
7585 #undef MAX_DIST_GOTO
7589 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7591 static void pBlockDestruct(pBlock *pb)
7602 /*-----------------------------------------------------------------*/
7603 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7604 /* name dbName and combine them */
7605 /* into one block */
7606 /*-----------------------------------------------------------------*/
7607 static void mergepBlocks(char dbName)
7610 pBlock *pb, *pbmerged = NULL,*pbn;
7612 pb = the_pFile->pbHead;
7614 //fprintf(stderr," merging blocks named %c\n",dbName);
7618 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7619 if( getpBlock_dbName(pb) == dbName) {
7621 //fprintf(stderr," merged block %c\n",dbName);
7626 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7627 /* pic16_addpCode2pBlock doesn't handle the tail: */
7628 pbmerged->pcTail = pb->pcTail;
7630 pb->prev->next = pbn;
7632 pbn->prev = pb->prev;
7637 //pic16_printpBlock(stderr, pbmerged);
7644 /*-----------------------------------------------------------------*/
7645 /* AnalyzeFlow - Examine the flow of the code and optimize */
7647 /* level 0 == minimal optimization */
7648 /* optimize registers that are used only by two instructions */
7649 /* level 1 == maximal optimization */
7650 /* optimize by looking at pairs of instructions that use the */
7652 /*-----------------------------------------------------------------*/
7654 static void AnalyzeFlow(int level)
7656 static int times_called=0;
7660 /* remove unused allocated registers before exiting */
7661 pic16_RemoveUnusedRegisters();
7666 /* if this is not the first time this function has been called,
7667 * then clean up old flow information */
7668 if(times_called++) {
7669 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7671 pic16_RegsUnMapLiveRanges();
7675 /* Phase 2 - Flow Analysis - Register Banking
7677 * In this phase, the individual flow blocks are examined
7678 * and register banking is fixed.
7682 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7683 pic16_FixRegisterBanking(pb);
7686 /* Phase 2 - Flow Analysis
7688 * In this phase, the pCode is partition into pCodeFlow
7689 * blocks. The flow blocks mark the points where a continuous
7690 * stream of instructions changes flow (e.g. because of
7691 * a call or goto or whatever).
7694 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7695 pic16_BuildFlow(pb);
7698 /* Phase 2 - Flow Analysis - linking flow blocks
7700 * In this phase, the individual flow blocks are examined
7701 * to determine their order of excution.
7704 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7708 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7709 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7710 pic16_createDF (pb);
7711 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7712 pic16_vcg_dump_default (pb);
7714 //pic16_destructDF (pb);
7718 if (0) releaseStack (); // releasing is costly...
7722 /* Phase 3 - Flow Analysis - Flow Tree
7724 * In this phase, the individual flow blocks are examined
7725 * to determine their order of execution.
7728 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7729 pic16_BuildFlowTree(pb);
7732 /* Phase x - Flow Analysis - Used Banks
7734 * In this phase, the individual flow blocks are examined
7735 * to determine the Register Banks they use
7739 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7744 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7745 pic16_pCodeRegMapLiveRanges(pb);
7747 pic16_RemoveUnusedRegisters();
7748 pic16_removeUnusedRegistersDF ();
7750 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7751 pic16_pCodeRegOptimizeRegUsage(level);
7760 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7765 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7768 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7769 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7770 pcflow = pcflow->next) {
7771 FillFlow(PCFL(pcflow));
7776 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7779 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7780 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7781 pcflow = pcflow->next) {
7782 FlowStats(PCFL(pcflow));
7788 /* VR -- no need to analyze banking in flow, but left here :
7789 * 1. because it may be used in the future for other purposes
7790 * 2. because if omitted we'll miss some optimization done here
7792 * Perhaps I should rename it to something else
7795 /*-----------------------------------------------------------------*/
7796 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7797 /* assigned to the registers. */
7799 /*-----------------------------------------------------------------*/
7801 void pic16_AnalyzeBanking(void)
7805 /* Phase x - Flow Analysis - Used Banks
7807 * In this phase, the individual flow blocks are examined
7808 * to determine the Register Banks they use
7818 if(!the_pFile)return;
7820 if(!pic16_options.no_banksel) {
7821 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7822 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7823 pic16_FixRegisterBanking(pb);
7828 /*-----------------------------------------------------------------*/
7829 /* buildCallTree - Look at the flow and extract all of the calls. */
7830 /*-----------------------------------------------------------------*/
7831 static set *register_usage(pBlock *pb);
7833 static void buildCallTree(void )
7845 /* Now build the call tree.
7846 First we examine all of the pCodes for functions.
7847 Keep in mind that the function boundaries coincide
7848 with pBlock boundaries.
7850 The algorithm goes something like this:
7851 We have two nested loops. The outer loop iterates
7852 through all of the pBlocks/functions. The inner
7853 loop iterates through all of the pCodes for
7854 a given pBlock. When we begin iterating through
7855 a pBlock, the variable pc_fstart, pCode of the start
7856 of a function, is cleared. We then search for pCodes
7857 of type PC_FUNCTION. When one is encountered, we
7858 initialize pc_fstart to this and at the same time
7859 associate a new pBranch object that signifies a
7860 branch entry. If a return is found, then this signifies
7861 a function exit point. We'll link the pCodes of these
7862 returns to the matching pc_fstart.
7864 When we're done, a doubly linked list of pBranches
7865 will exist. The head of this list is stored in
7866 `the_pFile', which is the meta structure for all
7867 of the pCode. Look at the pic16_printCallTree function
7868 on how the pBranches are linked together.
7871 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7872 pCode *pc_fstart=NULL;
7873 for(pc = pb->pcHead; pc; pc = pc->next) {
7875 if(isPCI(pc) && pc_fstart) {
7876 if(PCI(pc)->is2MemOp) {
7877 r = pic16_getRegFromInstruction2(pc);
7878 if(r && !strcmp(r->name, "POSTDEC1"))
7879 PCF(pc_fstart)->stackusage++;
7881 r = pic16_getRegFromInstruction(pc);
7882 if(r && !strcmp(r->name, "PREINC1"))
7883 PCF(pc_fstart)->stackusage--;
7888 if (PCF(pc)->fname) {
7891 sprintf(buf, "%smain", port->fun_prefix);
7892 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7893 //fprintf(stderr," found main \n");
7894 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7898 pbr = Safe_calloc(1,sizeof(pBranch));
7899 pbr->pc = pc_fstart = pc;
7902 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7904 // Here's a better way of doing the same:
7905 addSet(&pb->function_entries, pc);
7908 // Found an exit point in a function, e.g. return
7909 // (Note, there may be more than one return per function)
7911 pBranchLink(PCF(pc_fstart), PCF(pc));
7913 addSet(&pb->function_exits, pc);
7915 } else if(isCALL(pc)) {
7916 addSet(&pb->function_calls,pc);
7923 /* This is not needed because currently all register used
7924 * by a function are stored in stack -- VR */
7926 /* Re-allocate the registers so that there are no collisions
7927 * between local variables when one function call another */
7930 // pic16_deallocateAllRegs();
7932 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7940 /*-----------------------------------------------------------------*/
7941 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7942 /* all of the logical connections. */
7944 /* Essentially what's done here is that the pCode flow is */
7946 /*-----------------------------------------------------------------*/
7948 void pic16_AnalyzepCode(char dbName)
7959 /* Phase 1 - Register allocation and peep hole optimization
7961 * The first part of the analysis is to determine the registers
7962 * that are used in the pCode. Once that is done, the peep rules
7963 * are applied to the code. We continue to loop until no more
7964 * peep rule optimizations are found (or until we exceed the
7965 * MAX_PASSES threshold).
7967 * When done, the required registers will be determined.
7973 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7974 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7976 /* First, merge the labels with the instructions */
7977 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7978 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7980 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7981 //fprintf(stderr," analyze and merging block %c\n",dbName);
7982 pic16_pBlockMergeLabels(pb);
7985 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7990 changes = OptimizepCode(dbName);
7993 } while(changes && (i++ < MAX_PASSES));
8000 /* convert a series of movff's of local regs to stack, with a single call to
8001 * a support functions which does the same thing via loop */
8002 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8006 char *fname[]={"__lr_store", "__lr_restore"};
8008 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8010 pct = pic16_findNextInstruction(pcstart->next);
8013 pct = pc->next; //pic16_findNextInstruction(pc->next);
8014 // pc->print(stderr, pc);
8015 if(isPCI(pc) && PCI(pc)->label) {
8016 pbr = PCI(pc)->label;
8017 while(pbr && pbr->pc) {
8018 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8022 // pc->print(stderr, pc);
8024 pc->prev->next = pct;
8025 pct->prev = pc->prev;
8029 } while ((pc) && (pc != pcend));
8031 /* unlink movff instructions */
8032 pcstart->next = pcend;
8033 pcend->prev = pcstart;
8037 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8038 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8041 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8042 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8043 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8046 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8047 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8054 sym = newSymbol( fname[ entry?0:1 ], 0 );
8055 strcpy(sym->rname, fname[ entry?0:1 ]);
8056 checkAddSym(&externs, sym);
8058 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8063 /*-----------------------------------------------------------------*/
8064 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
8065 /* local registers to a support function call */
8066 /*-----------------------------------------------------------------*/
8067 void pic16_OptimizeLocalRegs(void)
8072 pCodeOpLocalReg *pclr;
8075 regs *r, *lastr=NULL, *firstr=NULL;
8076 pCode *pcstart=NULL, *pcend=NULL;
8081 * local_regs begin mark
8082 * MOVFF r0x01, POSTDEC1
8083 * MOVFF r0x02, POSTDEC1
8086 * MOVFF r0x0n, POSTDEC1
8087 * local_regs end mark
8089 * convert the above to the below:
8090 * MOVLW starting_register_index
8092 * MOVLW register_count
8093 * call __save_registers_in_stack
8099 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8100 inRegCount = regCount = 0;
8101 firstr = lastr = NULL;
8102 for(pc = pb->pcHead; pc; pc = pc->next) {
8104 /* hold current function name */
8105 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8107 if(pc && (pc->type == PC_INFO)) {
8110 if(pci->type == INF_LOCALREGS) {
8111 pclr = PCOLR(pci->oper1);
8113 if((pclr->type == LR_ENTRY_BEGIN)
8114 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8117 switch(pclr->type) {
8118 case LR_ENTRY_BEGIN:
8120 inRegCount = 1; regCount = 0;
8121 pcstart = pc; //pic16_findNextInstruction(pc->next);
8122 firstr = lastr = NULL;
8128 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8131 if(curFunc && inWparamList(curFunc+1)) {
8132 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8136 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8141 firstr = lastr = NULL;
8145 if(inRegCount == -1) {
8146 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8152 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8154 r = pic16_getRegFromInstruction(pc);
8156 r = pic16_getRegFromInstruction2(pc);
8157 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8158 if(!firstr)firstr = r;
8160 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8172 /*-----------------------------------------------------------------*/
8173 /* ispCodeFunction - returns true if *pc is the pCode of a */
8175 /*-----------------------------------------------------------------*/
8176 static bool ispCodeFunction(pCode *pc)
8179 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8185 /*-----------------------------------------------------------------*/
8186 /* findFunction - Search for a function by name (given the name) */
8187 /* in the set of all functions that are in a pBlock */
8188 /* (note - I expect this to change because I'm planning to limit */
8189 /* pBlock's to just one function declaration */
8190 /*-----------------------------------------------------------------*/
8191 static pCode *findFunction(char *fname)
8198 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8200 pc = setFirstItem(pb->function_entries);
8203 if((pc->type == PC_FUNCTION) &&
8205 (strcmp(fname, PCF(pc)->fname)==0))
8208 pc = setNextItem(pb->function_entries);
8216 static void MarkUsedRegisters(set *regset)
8221 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8222 // fprintf(stderr, "marking register = %s\t", r1->name);
8223 r2 = pic16_regWithIdx(r1->rIdx);
8224 // fprintf(stderr, "to register = %s\n", r2->name);
8230 static void pBlockStats(FILE *of, pBlock *pb)
8236 if(!pic16_pcode_verbose)return;
8238 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8240 // for now just print the first element of each set
8241 pc = setFirstItem(pb->function_entries);
8243 fprintf(of,";entry: ");
8246 pc = setFirstItem(pb->function_exits);
8248 fprintf(of,";has an exit\n");
8252 pc = setFirstItem(pb->function_calls);
8254 fprintf(of,";functions called:\n");
8257 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8258 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8260 pc = setNextItem(pb->function_calls);
8264 r = setFirstItem(pb->tregisters);
8266 int n = elementsInSet(pb->tregisters);
8268 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8271 fprintf(of, "; %s\n",r->name);
8272 r = setNextItem(pb->tregisters);
8276 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8279 /*-----------------------------------------------------------------*/
8280 /*-----------------------------------------------------------------*/
8282 static void sequencepCode(void)
8288 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8290 pb->seq = GpCodeSequenceNumber+1;
8292 for( pc = pb->pcHead; pc; pc = pc->next)
8293 pc->seq = ++GpCodeSequenceNumber;
8299 /*-----------------------------------------------------------------*/
8300 /*-----------------------------------------------------------------*/
8301 static set *register_usage(pBlock *pb)
8304 set *registers=NULL;
8305 set *registersInCallPath = NULL;
8307 /* check recursion */
8309 pc = setFirstItem(pb->function_entries);
8316 if(pc->type != PC_FUNCTION)
8317 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8319 pc = setFirstItem(pb->function_calls);
8320 for( ; pc; pc = setNextItem(pb->function_calls)) {
8322 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8323 char *dest = pic16_get_op_from_instruction(PCI(pc));
8325 pcn = findFunction(dest);
8327 registersInCallPath = register_usage(pcn->pb);
8329 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8334 pBlockStats(stderr,pb); // debug
8337 // Mark the registers in this block as used.
8339 MarkUsedRegisters(pb->tregisters);
8340 if(registersInCallPath) {
8341 /* registers were used in the functions this pBlock has called */
8342 /* so now, we need to see if these collide with the ones we are */
8345 regs *r1,*r2, *newreg;
8347 DFPRINTF((stderr,"comparing registers\n"));
8349 r1 = setFirstItem(registersInCallPath);
8352 r2 = setFirstItem(pb->tregisters);
8354 while(r2 && (r1->type != REG_STK)) {
8356 if(r2->rIdx == r1->rIdx) {
8357 newreg = pic16_findFreeReg(REG_GPR);
8361 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8365 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8366 r1->rIdx, newreg->rIdx));
8367 r2->rIdx = newreg->rIdx;
8368 //if(r2->name) Safe_free(r2->name);
8370 r2->name = Safe_strdup(newreg->name);
8374 newreg->wasUsed = 1;
8376 r2 = setNextItem(pb->tregisters);
8379 r1 = setNextItem(registersInCallPath);
8382 /* Collisions have been resolved. Now free the registers in the call path */
8383 r1 = setFirstItem(registersInCallPath);
8385 if(r1->type != REG_STK) {
8386 newreg = pic16_regWithIdx(r1->rIdx);
8389 r1 = setNextItem(registersInCallPath);
8393 // MarkUsedRegisters(pb->registers);
8395 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8398 DFPRINTF((stderr,"returning regs\n"));
8400 DFPRINTF((stderr,"not returning regs\n"));
8402 DFPRINTF((stderr,"pBlock after register optim.\n"));
8403 pBlockStats(stderr,pb); // debug
8409 /*-----------------------------------------------------------------*/
8410 /* pct2 - writes the call tree to a file */
8412 /*-----------------------------------------------------------------*/
8413 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8417 // set *registersInCallPath = NULL;
8423 fprintf(of, "recursive function\n");
8424 return; //recursion ?
8427 pc = setFirstItem(pb->function_entries);
8434 for(i=0;i<indent;i++) // Indentation
8438 if(pc->type == PC_FUNCTION) {
8439 usedstack += PCF(pc)->stackusage;
8440 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8441 } else return; // ???
8444 pc = setFirstItem(pb->function_calls);
8445 for( ; pc; pc = setNextItem(pb->function_calls)) {
8447 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8448 char *dest = pic16_get_op_from_instruction(PCI(pc));
8450 pcn = findFunction(dest);
8452 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8454 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8462 /*-----------------------------------------------------------------*/
8463 /* pic16_printCallTree - writes the call tree to a file */
8465 /*-----------------------------------------------------------------*/
8467 void pic16_printCallTree(FILE *of)
8479 fprintf(of, "\npBlock statistics\n");
8480 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8484 fprintf(of,"Call Tree\n");
8485 pbr = the_pFile->functions;
8489 if(!ispCodeFunction(pc))
8490 fprintf(of,"bug in call tree");
8493 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8495 while(pc->next && !ispCodeFunction(pc->next)) {
8497 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8498 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8506 fprintf(of,"\n**************\n\na better call tree\n");
8507 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8512 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8513 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8519 /*-----------------------------------------------------------------*/
8521 /*-----------------------------------------------------------------*/
8523 static void InlineFunction(pBlock *pb)
8531 pc = setFirstItem(pb->function_calls);
8533 for( ; pc; pc = setNextItem(pb->function_calls)) {
8536 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8542 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8544 //fprintf(stderr,"Cool can inline:\n");
8545 //pcn->print(stderr,pcn);
8547 //fprintf(stderr,"recursive call Inline\n");
8548 InlineFunction(pcn->pb);
8549 //fprintf(stderr,"return from recursive call Inline\n");
8552 At this point, *pc points to a CALL mnemonic, and
8553 *pcn points to the function that is being called.
8555 To in-line this call, we need to remove the CALL
8556 and RETURN(s), and link the function pCode in with
8562 /* Remove the CALL */
8566 /* remove callee pBlock from the pBlock linked list */
8567 removepBlock(pcn->pb);
8575 /* Remove the Function pCode */
8576 pct = pic16_findNextInstruction(pcn->next);
8578 /* Link the function with the callee */
8579 pc->next = pcn->next;
8580 pcn->next->prev = pc;
8582 /* Convert the function name into a label */
8584 pbr = Safe_calloc(1,sizeof(pBranch));
8585 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8587 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8588 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8590 /* turn all of the return's except the last into goto's */
8591 /* check case for 2 instruction pBlocks */
8592 pce = pic16_findNextInstruction(pcn->next);
8594 pCode *pce_next = pic16_findNextInstruction(pce->next);
8596 if(pce_next == NULL) {
8597 /* found the last return */
8598 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8600 //fprintf(stderr,"found last return\n");
8601 //pce->print(stderr,pce);
8602 pce->prev->next = pc_call->next;
8603 pc_call->next->prev = pce->prev;
8604 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8614 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8620 /*-----------------------------------------------------------------*/
8622 /*-----------------------------------------------------------------*/
8624 void pic16_InlinepCode(void)
8633 if(!functionInlining)
8636 /* Loop through all of the function definitions and count the
8637 * number of times each one is called */
8638 //fprintf(stderr,"inlining %d\n",__LINE__);
8640 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8642 pc = setFirstItem(pb->function_calls);
8644 for( ; pc; pc = setNextItem(pb->function_calls)) {
8647 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8648 if(pcn && isPCF(pcn)) {
8649 PCF(pcn)->ncalled++;
8652 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8657 //fprintf(stderr,"inlining %d\n",__LINE__);
8659 /* Now, Loop through the function definitions again, but this
8660 * time inline those functions that have only been called once. */
8662 InlineFunction(the_pFile->pbHead);
8663 //fprintf(stderr,"inlining %d\n",__LINE__);
8665 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8670 char *pic_optype_names[]={
8671 "PO_NONE", // No operand e.g. NOP
8672 "PO_W", // The working register (as a destination)
8673 "PO_WREG", // The working register (as a file register)
8674 "PO_STATUS", // The 'STATUS' register
8675 "PO_BSR", // The 'BSR' register
8676 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8678 "PO_INDF0", // The Indirect register
8679 "PO_INTCON", // Interrupt Control register
8680 "PO_GPR_REGISTER", // A general purpose register
8681 "PO_GPR_BIT", // A bit of a general purpose register
8682 "PO_GPR_TEMP", // A general purpose temporary register
8683 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8684 "PO_PCL", // Program counter Low register
8685 "PO_PCLATH", // Program counter Latch high register
8686 "PO_PCLATU", // Program counter Latch upper register
8687 "PO_PRODL", // Product Register Low
8688 "PO_PRODH", // Product Register High
8689 "PO_LITERAL", // A constant
8690 "PO_REL_ADDR", // A relative address
8691 "PO_IMMEDIATE", // (8051 legacy)
8692 "PO_DIR", // Direct memory (8051 legacy)
8693 "PO_CRY", // bit memory (8051 legacy)
8694 "PO_BIT", // bit operand.
8695 "PO_STR", // (8051 legacy)
8697 "PO_WILD" // Wild card operand in peep optimizer
8701 char *dumpPicOptype(PIC_OPTYPE type)
8703 return (pic_optype_names[ type ]);
8707 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8710 #define MAX_COMMON_BANK_SIZE 32
8711 #define FIRST_PSEUDO_BANK_NR 1000
8713 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8714 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8715 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8718 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8721 pseudoBankNr bank; // number assigned to this pseudoBank
8722 unsigned int size; // number of operands assigned to this bank
8723 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8726 /*----------------------------------------------------------------------*/
8727 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8728 /*----------------------------------------------------------------------*/
8729 unsigned int hashSymbol (const char *str)
8731 unsigned int res = 0;
8736 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8743 /*-----------------------------------------------------------------------*/
8744 /* compareSymbol - return 1 iff sym1 equals sym2 */
8745 /*-----------------------------------------------------------------------*/
8746 int compareSymbol (const void *sym1, const void *sym2)
8748 char *s1 = (char*) sym1;
8749 char *s2 = (char*) sym2;
8751 return (strcmp (s1,s2) == 0);
8754 /*-----------------------------------------------------------------------*/
8755 /* comparePre - return 1 iff p1 == p2 */
8756 /*-----------------------------------------------------------------------*/
8757 int comparePtr (const void *p1, const void *p2)
8762 /*----------------------------------------------------------*/
8763 /* getSymbolFromOperand - return a pointer to the symbol in */
8764 /* the given operand and its length */
8765 /*----------------------------------------------------------*/
8766 char *getSymbolFromOperand (char *op, unsigned int *len)
8771 if (!op) return NULL;
8773 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8775 if (*sym == '(') sym++;
8778 while (((*curr >= 'A') && (*curr <= 'Z'))
8779 || ((*curr >= 'a') && (*curr <= 'z'))
8780 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8781 || (*curr == '_')) {
8782 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8790 /*--------------------------------------------------------------------------*/
8791 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8792 /*--------------------------------------------------------------------------*/
8793 char *getSymFromBank (pseudoBankNr bank)
8797 if (bank < 0) return "<INVALID BANK NR>";
8798 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8801 /*-----------------------------------------------------------------------*/
8802 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8803 /* bank number (uses hTab sym2bank), if the */
8804 /* symbol is not yet assigned a pseudo bank it */
8805 /* is assigned one here */
8806 /*-----------------------------------------------------------------------*/
8807 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8809 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8815 hash = hashSymbol (op) % sym2bank->size;
8816 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8817 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8819 if (bank == UNKNOWN_BANK) {
8820 // create a pseudo bank for the operand
8822 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8823 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8824 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8825 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8827 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8835 /*--------------------------------------------------------------------*/
8836 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8837 /*--------------------------------------------------------------------*/
8838 int isBanksel (pCode *pc)
8842 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8843 // BANKSEL <variablename> or MOVLB <banknr>
8844 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8848 // check for inline assembler BANKSELs
8849 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8850 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8851 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8855 // assume pc is no BANKSEL instruction
8859 /*---------------------------------------------------------------------------------*/
8860 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8861 /* This method can not guarantee to find all modifications of the */
8862 /* BSR (e.g. via INDirection registers) but covers all compiler */
8863 /* generated plus some cases. */
8864 /*---------------------------------------------------------------------------------*/
8865 int invalidatesBSR(pCode *pc)
8867 // assembler directives invalidate BSR (well, they might, we don't know)
8868 if (isPCAD(pc)) return 1;
8870 // only ASMDIRs and pCodeInstructions can invalidate BSR
8871 if (!isPCI(pc)) return 0;
8873 // we have a pCodeInstruction
8875 // check for BSR modifying instructions
8876 switch (PCI(pc)->op) {
8880 case POC_RETFIE: // might be used as CALL replacement
8881 case POC_RETLW: // might be used as CALL replacement
8882 case POC_RETURN: // might be used as CALL replacement
8887 default: // other instruction do not change BSR unless BSR is an explicit operand!
8888 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8892 // no change of BSR possible/probable
8896 /*------------------------------------------------------------*/
8897 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8898 /* the symbol referenced in this BANKSEL */
8899 /*------------------------------------------------------------*/
8900 pseudoBankNr getBankFromBanksel (pCode *pc)
8903 int data = (int)NULL;
8905 if (!pc) return INVALID_BANK;
8907 if (isPCAD(pc) && PCAD(pc)->directive) {
8908 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8909 // get symbolname from PCAD(pc)->arg
8910 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8911 sym = PCAD(pc)->arg;
8912 data = getPseudoBankNrFromOperand (sym);
8913 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8914 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8915 // get (literal) bank number from PCAD(pc)->arg
8916 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8917 assert (0 && "not yet implemented - turn off banksel optimization for now");
8919 } else if (isPCI(pc)) {
8920 if (PCI(pc)->op == POC_BANKSEL) {
8921 // get symbolname from PCI(pc)->pcop->name (?)
8922 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8923 sym = PCI(pc)->pcop->name;
8924 data = getPseudoBankNrFromOperand (sym);
8925 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8926 } else if (PCI(pc)->op == POC_MOVLB) {
8927 // get (literal) bank number from PCI(pc)->pcop->name
8928 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8929 assert (0 && "not yet implemented - turn off banksel optimization for now");
8934 // no assigned bank could be found
8935 return UNKNOWN_BANK;
8940 /*------------------------------------------------------------------------------*/
8941 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8942 /*------------------------------------------------------------------------------*/
8943 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8947 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8950 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8951 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8953 if (data->bank != bank)
8960 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8964 /*------------------------------------------------------------------*/
8965 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8966 /* bank is selected at a given pCode */
8967 /*------------------------------------------------------------------*/
8969 /* Create a graph with pseudo banks as its nodes and switches between
8970 * these as edges (with the edge weight representing the absolute
8971 * number of BANKSELs from one to the other).
8972 * Removes redundand BANKSELs instead iff mod == 1.
8973 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8974 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8976 * TODO: check ALL instructions operands if they modify BSR directly...
8978 * pb - the pBlock to annotate
8979 * mod - select either graph creation (0) or BANKSEL removal (1)
8981 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8983 pCode *pc, *pc_next;
8984 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8985 int isBankselect = 0;
8986 unsigned int banksels=0;
8990 pc = pic16_findNextInstruction(pb->pcHead);
8992 isBankselect = isBanksel (pc);
8993 pc_next = pic16_findNextInstruction (pc->next);
8995 if (!hasNoLabel (pc)) {
8996 // we don't know our predecessors -- assume different BSRs
8997 prevBSR = UNKNOWN_BANK;
8998 pseudoBSR = UNKNOWN_BANK;
8999 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9002 // check if this is a BANKSEL instruction
9004 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9005 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9007 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9008 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9009 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9010 pic16_unlinkpCode (pc);
9014 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9019 if (!isBankselect && invalidatesBSR(pc)) {
9020 // check if this instruction invalidates the pseudoBSR
9021 pseudoBSR = UNKNOWN_BANK;
9022 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9025 prevBSR = pseudoBSR;
9032 /*------------------------------------------------------------------------------------*/
9033 /* assignToSameBank - returns 0 on success or an error code */
9034 /* 1 - common bank would be too large */
9035 /* 2 - assignment to fixed (absolute) bank not performed */
9037 /* This functions assumes that unsplittable operands are already assigned to the same */
9038 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
9039 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
9040 /* TODO: Symbols with an abslute address must be handled specially! */
9041 /*------------------------------------------------------------------------------------*/
9042 int assignToSameBank (int bank0, int bank1, int doAbs)
9044 int eff0, eff1, dummy;
9045 pseudoBank *pbank0, *pbank1;
9048 eff0 = getEffectiveBank (bank0);
9049 eff1 = getEffectiveBank (bank1);
9051 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9053 // nothing to do if already same bank
9054 if (eff0 == eff1) return 0;
9056 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9059 // ensure eff0 < eff1
9061 // swap eff0 and eff1
9070 // now assign bank eff1 to bank eff0
9071 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9073 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9074 pbank0->bank = eff0;
9077 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9081 hitem = hTabSearch (coerce, eff1 % coerce->size);
9082 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9083 hitem = hitem->next;
9085 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9088 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9089 pbank0->bank, pbank0->size,
9090 getSymFromBank (eff0), getSymFromBank (eff1));
9094 if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9096 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9097 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9098 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9099 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9103 pbank0->size += pbank1->size;
9105 if (pbank1->ref == 0) Safe_free (pbank1);
9111 hitem->item = pbank0;
9113 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9116 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9121 /*----------------------------------------------------------------*/
9122 /* mergeGraphNodes - combines two nodes into one and modifies all */
9123 /* edges to and from the nodes accordingly */
9124 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9125 /* then also (B,A) must be an edge (possibly with weight 0). */
9126 /*----------------------------------------------------------------*/
9127 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9129 GraphEdge *edge, *backedge, *nextedge;
9133 assert (node1 && node2);
9134 assert (node1 != node2);
9136 // add all edges starting at node2 to node1
9139 nextedge = edge->next;
9141 backedge = getGEdge (node, node2);
9143 backweight = backedge->weight;
9146 // insert edges (node1,node) and (node,node1)
9147 addGEdge2 (node1, node, edge->weight, backweight);
9148 // remove edges (node, node2) and (node2, node)
9149 remGEdge (node2, node);
9150 remGEdge (node, node2);
9154 // now node2 should not be referenced by any other GraphNode...
9155 //remGNode (adj, node2->data, node2->hash);
9158 /*----------------------------------------------------------------*/
9159 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9160 /*----------------------------------------------------------------*/
9161 void showGraph (Graph *g)
9165 pseudoBankNr bankNr;
9172 bankNr = getEffectiveBank (node->hash);
9173 assert (bankNr >= 0);
9174 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9176 bankNr = pbank->bank;
9182 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9185 if (edge->weight > 0)
9186 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9193 /*---------------------------------------------------------------*/
9194 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9195 /*---------------------------------------------------------------*/
9196 void pic16_OptimizeBanksel ()
9198 GraphNode *node, *node1, *node1next;
9201 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9202 GraphEdge *edge, *backedge;
9204 int maxWeight, weight, mergeMore, absMaxWeight;
9205 pseudoBankNr curr0, curr1;
9208 pseudoBankNr bankNr;
9209 char *base_symbol0, *base_symbol1;
9214 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9216 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9218 if (!the_pFile || !the_pFile->pbHead) return;
9220 adj = newGraph (NULL);
9221 sym2bank = newHashTable ( 255 );
9222 bank2sym = newHashTable ( 255 );
9223 coerce = newHashTable ( 255 );
9225 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9226 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9227 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9231 // assign symbols with absolute addresses to their respective bank nrs
9232 set = pic16_fix_udata;
9233 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9234 bankNr = reg->address >> 8;
9235 node = getOrAddGNode (adj, NULL, bankNr);
9236 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9237 assignToSameBank (node->hash, bankNr, 1);
9239 assert (bankNr >= 0);
9240 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9242 pbank = Safe_calloc (1, sizeof (pseudoBank));
9243 pbank->bank = reg->address >> 8; //FIXED_BANK;
9246 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9248 assert (pbank->bank == (reg->address >> 8));
9249 pbank->bank = reg->address >> 8; //FIXED_BANK;
9251 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9256 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9257 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9260 if (node->hash < 0) { node = node->next; continue; }
9261 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9264 if (node1->hash < 0) { node1 = node1->next; continue; }
9265 node1next = node1->next;
9266 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9267 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9268 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9269 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9270 if (assignToSameBank (node->hash, node1->hash, 0)) {
9271 fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9272 assert (0 && "Could not assign a symbol to a bank!");
9274 mergeGraphNodes (node, node1);
9276 if (node->hash < node1->hash)
9277 mergeGraphNodes (node, node1);
9279 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9289 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9290 // assign tightly coupled operands to the same (pseudo) bank
9291 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9299 curr0 = getEffectiveBank (node->hash);
9300 if (curr0 < 0) { node = node->next; continue; }
9303 assert (edge->src == node);
9304 backedge = getGEdge (edge->node, edge->src);
9305 weight = edge->weight + (backedge ? backedge->weight : 0);
9306 curr1 = getEffectiveBank (edge->node->hash);
9307 if (curr1 < 0) { edge = edge->next; continue; }
9309 // merging is only useful if the items are not assigned to the same bank already...
9310 if (curr0 != curr1 && weight > maxWeight) {
9311 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9320 if (maxWeight > 0) {
9322 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9323 max->src->hash, getSymFromBank (max->src->hash),
9324 max->node->hash, getSymFromBank (max->node->hash));
9327 node = getGNode (adj, max->src->data, max->src->hash);
9328 node1 = getGNode (adj, max->node->data, max->node->hash);
9330 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9331 if (max->src->hash < max->node->hash)
9332 mergeGraphNodes (node, node1);
9334 mergeGraphNodes (node1, node);
9336 remGEdge (node, node1);
9337 remGEdge (node1, node);
9348 // remove redundant BANKSELs
9349 //fprintf (stderr, "removing redundant BANKSELs\n");
9350 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9351 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9356 fprintf (stderr, "display graph\n");
9361 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9364 /*** END of stuff belonging to the BANKSEL optimization ***/
9368 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9370 typedef unsigned int symbol_t;
9371 typedef unsigned int valnum_t;
9372 //typedef unsigned int hash_t;
9375 #define INT_TO_PTR(x) (((char *) 0) + (x))
9379 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9383 static unsigned int pic16_df_removed_pcodes = 0;
9384 static unsigned int pic16_df_saved_bytes = 0;
9385 static unsigned int df_findall_sameflow = 0;
9386 static unsigned int df_findall_otherflow = 0;
9387 static unsigned int df_findall_in_vals = 0;
9389 static void pic16_df_stats () {
9391 if (pic16_debug_verbose || pic16_pcode_verbose) {
9392 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9393 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9394 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9398 /* Remove a pCode iff possible:
9399 * - previous pCode is no SKIP
9401 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9402 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9403 pCode *pcprev, *pcnext;
9404 char buf[256], *total=NULL;
9407 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9409 pcprev = pic16_findPrevInstruction (pc->prev);
9410 pcnext = pic16_findNextInstruction (pc->next);
9412 /* if previous instruction is a skip -- do not remove */
9413 if (pcprev && isPCI_SKIP(pcprev)) return 0;
9415 /* move labels to next instruction (if possible) */
9416 if (PCI(pc)->label && !pcnext) return 0;
9418 if (PCI(pc)->label) {
9419 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9420 //pc->print (stderr, pc);
9421 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9422 PCI(pc)->label = NULL;
9425 /* update statistics */
9426 pic16_df_removed_pcodes++;
9427 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9429 /* remove the pCode */
9430 pic16_pCode2str (buf, 256, pc);
9431 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9432 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9433 len = strlen (buf) + strlen (comment) + 10;
9434 total = (char *) Safe_malloc (len);
9435 SNPRINTF (total, len, "%s: %s", comment, buf);
9436 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9440 /* actually unlink it from the pBlock -- also remove from to/from lists */
9441 pic16_pCodeUnlink (pc);
9443 /* remove the pCode -- release registers */
9446 /* report success */
9451 /* ======================================================================== */
9452 /* === SYMBOL HANDLING ==================================================== */
9453 /* ======================================================================== */
9455 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9456 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9457 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9459 /** Calculate a hash for a given string.
9460 * If len == 0 the string is assumed to be NUL terminated. */
9461 static hash_t symbolHash (const char *str, unsigned int len) {
9465 hash = (hash << 2) ^ *str;
9470 hash = (hash << 2) ^ *str;
9477 /** Return 1 iff strings v1 and v2 are identical. */
9478 static int symcmp (const void *v1, const void *v2) {
9479 return !strcmp ((const char *) v1, (const char *) v2);
9482 /** Return 1 iff pointers v1 and v2 are identical. */
9483 static int ptrcmp (const void *v1, const void *v2) {
9487 enum { SPO_WREG=0x1000,
9527 /* Return the unique symbol_t for the given string. */
9528 static symbol_t symFromStr (const char *str) {
9533 if (!map_symToStr) {
9535 struct { char *name; symbol_t sym; } predefsyms[] = {
9537 {"STATUS", SPO_STATUS},
9538 {"PRODL", SPO_PRODL},
9539 {"PRODH", SPO_PRODH},
9540 {"INDF0", SPO_INDF0},
9541 {"POSTDEC0", SPO_POSTDEC0},
9542 {"POSTINC0", SPO_POSTINC0},
9543 {"PREINC0", SPO_PREINC0},
9544 {"PLUSW0", SPO_PLUSW0},
9545 {"INDF1", SPO_INDF1},
9546 {"POSTDEC1", SPO_POSTDEC1},
9547 {"POSTINC1", SPO_POSTINC1},
9548 {"PREINC1", SPO_PREINC1},
9549 {"PLUSW1", SPO_PLUSW1},
9550 {"INDF2", SPO_INDF2},
9551 {"POSTDEC2", SPO_POSTDEC2},
9552 {"POSTINC2", SPO_POSTINC2},
9553 {"PREINC2", SPO_PREINC2},
9554 {"PLUSW2", SPO_PLUSW2},
9555 {"STKPTR", SPO_STKPTR},
9560 {"FSR0L", SPO_FSR0L},
9561 {"FSR0H", SPO_FSR0H},
9562 {"FSR1L", SPO_FSR1L},
9563 {"FSR1H", SPO_FSR1H},
9564 {"FSR2L", SPO_FSR2L},
9565 {"FSR2H", SPO_FSR2H},
9567 {"PCLATH", SPO_PCLATH},
9568 {"PCLATU", SPO_PCLATU},
9569 {"TABLAT", SPO_TABLAT},
9570 {"TBLPTRL", SPO_TBLPTRL},
9571 {"TBLPTRH", SPO_TBLPTRH},
9572 {"TBLPTRU", SPO_TBLPTRU},
9576 map_strToSym = newHashTable (128);
9577 map_symToStr = newHashTable (128);
9579 for (i=0; predefsyms[i].name; i++) {
9582 /* enter new symbol */
9583 sym = predefsyms[i].sym;
9584 name = predefsyms[i].name;
9585 res = Safe_strdup (name);
9586 hash = symbolHash (name, 0);
9588 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9589 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9593 hash = symbolHash (str, 0) % map_strToSym->size;
9595 /* find symbol in table */
9596 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9598 //fprintf (stderr, "found symbol %u for %s\n", sym, str);
9602 /* enter new symbol */
9604 res = Safe_strdup (str);
9606 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9607 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9609 //fprintf (stderr, "created symbol %u for %s\n", sym, res);
9615 static const char *strFromSym (symbol_t sym) {
9616 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9620 /* ======================================================================== */
9621 /* === DEFINITION MAP HANDLING ============================================ */
9622 /* ======================================================================== */
9624 /* A defmap provides information about which symbol is defined by which pCode.
9625 * The most recent definitions are prepended to the list, so that the most
9626 * recent definition can be found by forward scanning the list.
9627 * pc2: MOVFF r0x00, r0x01
9629 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9631 * We attach one defmap to each flow object, and each pCode will occur at
9632 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9633 * used to find definitions for a pCode in its own defmap that precede pCode.
9636 typedef struct defmap_s {
9637 symbol_t sym; /** symbol this item refers to */
9640 unsigned int in_mask:8; /** mask leaving in accessed bits */
9641 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9642 int isRead:1; /** sym/mask is read */
9643 int isWrite:1; /** sym/mask is written */
9647 pCode *pc; /** pCode this symbol is refrenced at */
9648 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9649 valnum_t val; /** new unique number for this value (if isWrite) */
9650 struct defmap_s *prev, *next; /** link to previous an next definition */
9653 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9654 static int defmap_free_count = 0; /** number of released defmap items */
9656 /* Returns a defmap_t with the specified data; this will be the new list head.
9657 * next - pointer to the current list head */
9658 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9663 defmap_free = map->next;
9664 --defmap_free_count;
9666 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9669 map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9670 map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9671 map->acc.access.isRead = (isRead != 0);
9672 map->acc.access.isWrite = (isWrite != 0);
9675 map->val = (isWrite ? val : 0);
9678 if (next) next->prev = map;
9683 /* Returns a copy of the single defmap item. */
9684 static defmap_t *copyDefmap (defmap_t *map) {
9685 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9686 memcpy (res, map, sizeof (defmap_t));
9692 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9693 * item is copied before insertion into chain and therefore left untouched.
9694 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9695 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9698 while (dummy && (dummy->sym != item->sym
9699 || dummy->pc != item->pc
9700 || dummy->acc.accessmethod != item->acc.accessmethod
9701 || dummy->val != item->val
9702 || dummy->in_val != item->in_val)) {
9703 dummy = dummy->next;
9706 /* item already present? */
9707 if (dummy) return 0;
9709 /* otherwise: insert copy of item */
9710 dummy = copyDefmap (item);
9711 dummy->next = *head;
9712 if (*head) (*head)->prev = dummy;
9718 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9719 static void deleteDefmap (defmap_t *map) {
9722 /* unlink from chain -- fails for the first item (head is not updated!) */
9723 if (map->next) map->next->prev = map->prev;
9724 if (map->prev) map->prev->next = map->next;
9727 memset (map, 0, sizeof (defmap_t));
9729 /* save for future use */
9730 map->next = defmap_free;
9732 ++defmap_free_count;
9735 /* Release all defmaps referenced from map. */
9736 static void deleteDefmapChain (defmap_t **_map) {
9737 defmap_t *map, *next;
9743 /* find list head */
9744 while (map && map->prev) map = map->prev;
9746 /* delete all items */
9756 /* Free all defmap items. */
9757 static void freeDefmap (defmap_t **_map) {
9765 /* find list head */
9766 while (map->prev) map = map->prev;
9768 /* release all items */
9778 /* Returns the most recent definition for the given symbol preceeding pc.
9779 * If no definition is found, NULL is returned.
9780 * If pc == NULL the whole list is scanned. */
9781 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9782 defmap_t *curr = map;
9785 /* skip all definitions up to pc */
9786 while (curr && (curr->pc != pc)) curr = curr->next;
9788 /* pc not in the list -- scan the whole list for definitions */
9790 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9793 /* skip all definitions performed by pc */
9794 while (curr && (curr->pc == pc)) curr = curr->next;
9798 /* find definition for sym */
9799 while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9807 /* Returns the first use (read) of the given symbol AFTER pc.
9808 * If no such use is found, NULL is returned.
9809 * If pc == NULL the whole list is scanned. */
9810 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9811 defmap_t *curr = map, *prev = NULL;
9814 /* skip all definitions up to pc */
9815 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9817 /* pc not in the list -- scan the whole list for definitions */
9819 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9823 /* find end of list */
9824 while (curr && curr->next) curr = curr->next;
9827 /* find use of sym (scan list backwards) */
9828 while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9834 /* Return the defmap entry for sym AT pc.
9835 * If none is found, NULL is returned.
9836 * If more than one entry is found an assertion is triggered. */
9837 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9838 defmap_t *res = NULL;
9840 /* find entries for pc */
9841 while (map && map->pc != pc) map = map->next;
9843 /* find first entry for sym @ pc */
9844 while (map && map->pc == pc && map->sym != sym) map = map->next;
9846 /* no entry found */
9847 if (!map) return NULL;
9849 /* check for more entries */
9852 while (map && map->pc == pc) {
9853 /* more than one entry for sym @ pc found? */
9854 assert (map->sym != sym);
9858 /* return single entry for sym @ pc */
9862 /* Modifies the definition of sym at pCode to newval.
9863 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9865 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9868 /* find definitions of pc */
9869 while (m && m->pc != pc) m = m->next;
9871 /* find definition of sym at pc */
9872 while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9874 /* no definition found */
9880 /* update following uses of sym */
9881 while (m && m->pc == pc) m = m->prev;
9883 if (m->sym == sym) {
9885 if (m->acc.access.isWrite) m = NULL;
9893 /* ======================================================================== */
9894 /* === STACK ROUTINES ===================================================== */
9895 /* ======================================================================== */
9897 typedef struct stack_s {
9899 struct stack_s *next;
9902 typedef stackitem_t *stack_t;
9903 static stackitem_t *free_stackitems = NULL;
9905 /* Create a stack with one item. */
9906 static stack_t *newStack () {
9907 stack_t *s = (stack_t *) Safe_malloc (sizeof (stack_t));
9912 /* Remove a stack -- its items are only marked free. */
9913 static void deleteStack (stack_t *s) {
9919 i->next = free_stackitems;
9920 free_stackitems = i;
9925 /* Release all stackitems. */
9926 static void releaseStack () {
9929 while (free_stackitems) {
9930 i = free_stackitems->next;
9931 Safe_free(free_stackitems);
9932 free_stackitems = i;
9936 static void stackPush (stack_t *stack, void *data) {
9939 if (free_stackitems) {
9940 i = free_stackitems;
9941 free_stackitems = free_stackitems->next;
9943 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9950 static void *stackPop (stack_t *stack) {
9954 if (stack && *stack) {
9955 data = (*stack)->data;
9957 *stack = (*stack)->next;
9958 i->next = free_stackitems;
9959 free_stackitems = i;
9967 static int stackContains (stack_t *s, void *data) {
9972 if (i->data == data) return 1;
9981 static int stackIsEmpty (stack_t *s) {
9982 return (*s == NULL);
9991 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9992 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9994 s->lastdef = lastdef;
9998 static void deleteState (state_t *s) {
10002 static int stateIsNew (state_t *state, stack_t *todo, stack_t *done) {
10005 /* scan working list for state */
10009 /* is i == state? -- state not new */
10010 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10018 /* is i == state? -- state not new */
10019 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10024 /* not found -- state is new */
10028 static inline valnum_t newValnum ();
10030 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10033 if (!pb) return "<unknown function>";
10035 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10036 if (pc && isPCF(pc)) return PCF(pc)->fname;
10037 else return "<unknown function>";
10040 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10044 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10046 /* find initial value (assigning pc == NULL) */
10047 map = PCFL(pcfl)->in_vals;
10048 while (map && map->sym != sym) map = map->next;
10050 /* initial value already present? */
10052 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10056 /* create a new initial value */
10057 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10058 PCFL(pcfl)->in_vals = map;
10059 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10063 /* insert map as last item in pcfl's defmap */
10064 if (!prev) prev = PCFL(pcfl)->defmap;
10066 PCFL(pcfl)->defmap = map;
10068 while (prev->next) prev = prev->next;
10077 /* Find all reaching definitions for sym at pc.
10078 * A new (!) list of definitions is returned.
10079 * Returns the number of reaching definitions found.
10080 * The defining defmap entries are returned in *chain.
10082 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10087 pCodeFlowLink *succ;
10089 stack_t *todo; /** stack of state_t */
10090 stack_t *done; /** stack of state_t */
10092 int firstState, n_defs;
10094 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10097 /* initialize return list */
10100 /* wildcard symbol? */
10101 if (!sym) return 0;
10103 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10105 map = PCI(pc)->pcflow->defmap;
10107 res = defmapFindDef (map, sym, pc);
10108 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10110 #define USE_PRECALCED_INVALS 1
10111 #if USE_PRECALCED_INVALS
10112 if (!res && PCI(pc)->pcflow->in_vals) {
10113 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10115 //fprintf (stderr, "found def in init values\n");
10116 df_findall_in_vals++;
10122 // found a single definition (in pc's flow)
10123 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10124 defmapAddCopyIfNew (chain, res);
10125 df_findall_sameflow++;
10129 #if USE_PRECALCED_INVALS
10131 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10137 #define FORWARD_FLOW_ANALYSIS 1
10138 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10139 /* no definition found in pc's flow preceeding pc */
10140 todo = newStack ();
10141 done = newStack ();
10142 n_defs = 0; firstState = 1;
10143 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10145 while (!stackIsEmpty (todo)) {
10146 state = (state_t *) stackPop (todo);
10147 stackPush (done, state);
10148 curr = state->flow;
10149 res = state->lastdef;
10150 //fprintf (stderr, "searching def of sym %s in pcFlow %p (lastdef %x @ %p)\n", strFromSym(sym), curr, res ? res->val : 0, res ? res->pc : NULL);
10152 /* there are no definitions BEFORE pc in pc's flow (see above) */
10153 if (curr == PCI(pc)->pcflow) {
10155 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10156 res = pic16_pBlockAddInval (pc->pb, sym);
10157 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10160 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10161 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10165 /* save last definition of sym in this flow as initial def in successors */
10166 res = defmapFindDef (curr->defmap, sym, NULL);
10167 if (!res) res = state->lastdef;
10169 /* add successors to working list */
10170 state = newState (NULL, NULL);
10171 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10173 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10174 state->flow = succ->pcflow;
10175 state->lastdef = res;
10176 if (stateIsNew (state, todo, done)) {
10177 stackPush (todo, state);
10178 state = newState (NULL, NULL);
10180 succ = (pCodeFlowLink *) setNextItem (curr->to);
10182 deleteState (state);
10185 #else // !FORWARD_FLOW_ANALYSIS
10187 /* no definition found in pc's flow preceeding pc */
10188 todo = newStack ();
10189 done = newStack ();
10190 n_defs = 0; firstState = 1;
10191 stackPush (todo, newState (PCI(pc)->pcflow, res));
10193 while (!stackIsEmpty (todo)) {
10194 state = (state_t *) stackPop (todo);
10195 curr = state->flow;
10199 /* only check predecessor flows */
10201 /* get (last) definition of sym in this flow */
10202 res = defmapFindDef (curr->defmap, sym, NULL);
10206 /* definition found */
10207 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10208 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10210 /* no definition found -- check predecessor flows */
10211 state = newState (NULL, NULL);
10212 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10214 /* if no flow predecessor available -- sym might be uninitialized */
10216 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10217 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10218 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10219 deleteDefmap (res); res = NULL;
10223 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10224 state->flow = succ->pcflow;
10225 state->lastdef = res;
10226 if (stateIsNew (state, todo, done)) {
10227 stackPush (todo, state);
10228 state = newState (NULL, NULL);
10230 succ = (pCodeFlowLink *) setNextItem (curr->from);
10232 deleteState (state);
10238 /* clean up done stack */
10239 while (!stackIsEmpty(done)) {
10240 deleteState ((state_t *) stackPop (done));
10242 deleteStack (done);
10244 /* return number of items in result set */
10246 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10247 } else if (n_defs == 1) {
10249 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10250 } else if (n_defs > 0) {
10251 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10255 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10260 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10261 df_findall_otherflow++;
10265 /* ======================================================================== */
10266 /* === VALUE NUMBER HANDLING ============================================== */
10267 /* ======================================================================== */
10269 static valnum_t nextValnum = 0x1000;
10270 static hTab *map_symToValnum = NULL;
10272 /** Return a new value number. */
10273 static inline valnum_t newValnum () {
10274 return (nextValnum += 4);
10277 static valnum_t valnumFromStr (const char *str) {
10282 sym = symFromStr (str);
10284 if (!map_symToValnum) {
10285 map_symToValnum = newHashTable (128);
10288 /* literal already known? */
10289 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10291 /* return existing valnum */
10292 if (res) return (valnum_t) PTR_TO_INT(res);
10294 /* create new valnum */
10296 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10300 /* Create a valnum for a literal. */
10301 static valnum_t valnumFromLit (unsigned int lit) {
10302 return ((valnum_t) 0x100 + (lit & 0x0FF));
10305 /* Return the (positive) literal value represented by val
10306 * or -1 iff val is no known literal's valnum. */
10307 static int litFromValnum (valnum_t val) {
10308 if (val >= 0x100 && val < 0x200) {
10309 /* valnum is a (known) literal */
10310 return val & 0x00FF;
10312 /* valnum is not a known literal */
10318 /* Sanity check - all flows in a block must be reachable from initial flow. */
10319 static int verifyAllFlowsReachable (pBlock *pb) {
10325 pCodeFlowLink *succ;
10328 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10331 flowInBlock = NULL;
10333 /* mark initial flow as reached (and "not needs to be reached") */
10334 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10336 addSetHead (&reached, pc);
10337 addSetHead (&checked, pc);
10339 /* mark all further flows in block as "need to be reached" */
10342 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10343 pc = pic16_findNextInstruction (pc->next);
10346 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10347 /* mark as reached and "not need to be reached" */
10348 deleteSetItem (&reached, pcfl);
10349 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10351 /* flow is no longer considered unreachable */
10352 deleteSetItem (&flowInBlock, pcfl);
10354 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10355 if (!isinSet (checked, succ->pcflow)) {
10356 /* flow has never been reached before */
10357 addSetHead (&reached, succ->pcflow);
10358 addSetHead (&checked, succ->pcflow);
10363 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10365 /* by now every flow should have been reached
10366 * --> flowInBlock should be empty */
10367 res = (flowInBlock == NULL);
10371 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10372 while (flowInBlock) {
10373 pcfl = indexSet (flowInBlock, 0);
10374 fprintf (stderr, "not reached: flow %p\n", pcfl);
10375 deleteSetItem (&flowInBlock, pcfl);
10381 deleteSet (&reached);
10382 deleteSet (&flowInBlock);
10383 deleteSet (&checked);
10385 /* if we reached every flow, succ is NULL by now... */
10386 //assert (res); // will fire on unreachable code...
10391 /* Checks a flow for accesses to sym AFTER pc.
10393 * Returns -1 if the symbol is read in this flow (before redefinition),
10394 * returns 0 if the symbol is redefined in this flow or
10395 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10397 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10398 defmap_t *map, *mappc;
10400 /* find pc or start of definitions */
10401 map = pcfl->defmap;
10402 while (map && (map->pc != pc) && map->next) map = map->next;
10403 /* if we found pc -- ignore it */
10404 while (map && map->pc == pc) map = map->prev;
10406 /* scan list backwards (first definition first) */
10407 while (map && mask) {
10408 // if (map->sym == sym) {
10409 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10411 /* scan list for reads at this pc first */
10412 while (map && map->pc == mappc->pc) {
10413 /* is the symbol (partially) read? */
10414 if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10415 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10422 while (map && map->pc == mappc->pc) {
10423 /* honor (partial) redefinitions of sym */
10424 if ((map->sym == sym) && (map->acc.access.isWrite)) {
10425 mask &= ~map->acc.access.mask;
10426 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10431 /* map already points to the first defmap for the next pCode */
10432 //map = mappc->prev;
10435 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10436 * is still alive; return the appropriate mask of alive bits */
10440 /* Check whether a symbol is alive (AFTER pc). */
10441 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10444 stack_t *todo, *done;
10447 pCodeFlowLink *succ;
10451 assert (isPCI(pc));
10452 pcfl = PCI(pc)->pcflow;
10453 map = pcfl->defmap;
10455 todo = newStack ();
10456 done = newStack ();
10458 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10459 stackPush (todo, state);
10462 while (!stackIsEmpty (todo)) {
10463 state = (state_t *) stackPop (todo);
10464 pcfl = state->flow;
10465 mask = PTR_TO_INT(state->lastdef);
10466 if (visit) stackPush (done, state); else deleteState(state);
10467 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10468 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10469 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10472 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10473 if (mask == 0) continue;
10475 /* symbol is (partially) read before redefinition in flow */
10476 if (mask == -1) break;
10478 /* symbol is neither read nor completely redefined -- check successor flows */
10479 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10480 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10481 if (stateIsNew (state, todo, done)) {
10482 stackPush (todo, state);
10484 deleteState (state);
10489 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10490 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10492 /* symbol is read in at least one flow -- is alive */
10493 if (mask == -1) return 1;
10495 /* symbol is read in no flow */
10499 /* Returns whether access to the given symbol has side effects. */
10500 static int pic16_symIsSpecial (symbol_t sym) {
10501 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10521 /* no special effects known */
10528 /* Check whether a register should be considered local (to the current function) or not. */
10529 static int pic16_regIsLocal (regs *r) {
10532 sym = symFromStr (r->name);
10535 case SPO_FSR0L: // used in ptrget/ptrput
10536 case SPO_FSR0H: // ... as well
10537 case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10538 case SPO_FSR1H: // ... as well
10539 case SPO_FSR2L: // used as frame pointer
10540 case SPO_FSR2H: // ... as well
10541 case SPO_PRODL: // used to return values from functions
10542 case SPO_PRODH: // ... as well
10543 /* these registers (and some more...) are considered local */
10547 /* for unknown regs: check is marked local, leave if not */
10551 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10557 /* if in doubt, assume non-local... */
10561 /* Check all symbols touched by pc whether their newly assigned values are read.
10562 * Returns 0 if no symbol is used later on, 1 otherwise. */
10563 static int pic16_pCodeIsAlive (pCode *pc) {
10564 pCodeInstruction *pci;
10565 defmap_t *map, *lastpc;
10568 /* we can only handle PCIs */
10569 if (!isPCI(pc)) return 1;
10571 //pc->print (stderr, pc);
10574 assert (pci && pci->pcflow && pci->pcflow->defmap);
10576 /* NEVER remove instructions with implicit side effects */
10579 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10580 case POC_TBLRD_POSTDEC:
10581 case POC_TBLRD_PREINC:
10582 case POC_TBLWT: /* modify program memory */
10583 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10584 case POC_TBLWT_POSTDEC:
10585 case POC_TBLWT_PREINC:
10586 case POC_CLRWDT: /* clear watchdog timer */
10587 case POC_PUSH: /* should be safe to remove though... */
10588 case POC_POP: /* should be safe to remove though... */
10593 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10597 /* no special instruction */
10601 /* prevent us from removing assignments to non-local variables */
10603 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10604 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10606 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10607 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10608 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10609 //pc->print (stderr, pc);
10612 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10613 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10618 /* OVERKILL: prevent us from removing reads from non-local variables
10619 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10620 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10622 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10623 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10625 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10626 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10627 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10628 //pc->print (stderr, pc);
10631 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10632 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10637 /* now check that the defined symbols are not used */
10638 map = pci->pcflow->defmap;
10640 /* find items for pc */
10641 while (map && map->pc != pc) map = map->next;
10643 /* no entries found? something is fishy with DF analysis... -- play safe */
10644 if (!map) { fprintf (stderr, "%s: defmap not found\n", __FUNCTION__); return 1; }
10646 /* remember first item assigned to pc for later use */
10649 /* check all symbols being modified by pc */
10650 while (map && map->pc == pc) {
10651 if (map->sym == 0) { map = map->next; continue; }
10653 /* keep pc if it references special symbols (like POSTDEC0) */
10657 pic16_pCode2str (buf, 256, pc);
10658 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10661 if (pic16_symIsSpecial (map->sym)) {
10662 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10665 if (map->acc.access.isWrite) {
10666 if (pic16_isAlive (map->sym, pc)) {
10667 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10674 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10678 pic16_pCode2str (buf, 256, pc);
10679 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10685 /* Adds implied operands to the list.
10686 * sym - operand being accessed in the pCode
10687 * list - list to append the operand
10688 * isRead - set to 1 iff sym is read in pCode
10689 * listRead - set to 1 iff all operands being read are to be listed
10691 * Returns 0 for "normal" operands, 1 for special operands.
10693 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10694 /* check whether accessing REG accesses other REGs as well */
10698 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10699 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10700 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10704 /* reads FSR0x and WREG */
10705 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10706 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10707 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10708 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10714 /* reads/modifies FSR0x */
10715 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10716 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10717 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10722 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10723 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10724 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10728 /* reads FSR1x and WREG */
10729 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10730 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10731 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10732 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10738 /* reads/modifies FSR1x */
10739 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10740 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10741 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10746 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10747 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10748 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10752 /* reads FSR2x and WREG */
10753 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10754 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10755 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10756 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10762 /* reads/modifies FSR2x */
10763 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10764 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10765 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10769 /* modifies PCLATH and PCLATU */
10770 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10772 /* reading PCL updates PCLATx */
10773 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10774 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10777 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10778 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10779 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10784 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10785 /* nothing special */
10790 /* has been a special operand */
10794 static symbol_t pic16_fsrsym_idx[][2] = {
10795 {SPO_FSR0L, SPO_FSR0H},
10796 {SPO_FSR1L, SPO_FSR1H},
10797 {SPO_FSR2L, SPO_FSR2H}
10800 /** Prepend list with the reads and definitions performed by pc. */
10801 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10802 pCodeInstruction *pci;
10803 int cond, inCond, outCond;
10804 int mask = 0xff, smask;
10805 int isSpecial, isSpecial2;
10806 symbol_t sym, sym2;
10810 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10811 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10812 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10813 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10816 assert (isPCI(pc));
10819 /* handle bit instructions */
10820 if (pci->isBitInst) {
10821 assert (pci->pcop->type == PO_GPR_BIT);
10822 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10825 /* handle (additional) implicit arguments */
10831 lit = PCOL(pci->pcop)->lit;
10832 assert (lit >= 0 && lit < 3);
10833 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, ((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10834 val = valnumFromStr (((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10835 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10836 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10837 list = newDefmap (pic16_fsrsym_idx[lit][1], 0x00, 0xff, 0, 1, pc, val+1, list); // val+1 is guaranteed not be used as a valnum...
10841 case POC_MOVLB: // BSR
10842 case POC_BANKSEL: // BSR
10843 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10846 case POC_MULWF: // PRODx
10847 case POC_MULLW: // PRODx
10848 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10849 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10852 case POC_POP: // TOS, STKPTR
10853 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10854 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10855 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10856 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10859 case POC_PUSH: // STKPTR
10860 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10861 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10862 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10863 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10866 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10867 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10868 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10869 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10870 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10871 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10873 /* needs correctly set-up stack pointer */
10874 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10875 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10878 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10879 /* pseudo read on (possible) return values */
10880 // WREG is handled below via outCond
10881 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10882 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10883 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10885 /* caller's stack pointers must be restored */
10886 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10887 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10888 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10889 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10892 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10893 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10894 /* pseudo read on (possible) return values */
10895 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10896 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10897 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10898 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10900 /* caller's stack pointers must be restored */
10901 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10902 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10903 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10904 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10908 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10909 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10910 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10911 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10914 case POC_TBLRD_POSTINC:
10915 case POC_TBLRD_POSTDEC:
10916 case POC_TBLRD_PREINC:
10917 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10918 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10919 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10920 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10924 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10925 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10926 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10927 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10930 case POC_TBLWT_POSTINC:
10931 case POC_TBLWT_POSTDEC:
10932 case POC_TBLWT_PREINC:
10933 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10934 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10935 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10936 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10940 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10944 /* handle explicit arguments */
10945 inCond = pci->inCond;
10946 outCond = pci->outCond;
10947 cond = inCond | outCond;
10948 if (cond & PCC_W) {
10949 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10952 /* keep STATUS read BEFORE STATUS write in the list */
10953 if (inCond & PCC_STATUS) {
10955 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10956 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10957 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10958 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10959 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10961 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10962 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10965 if (outCond & PCC_STATUS) {
10967 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10968 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10969 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10970 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10971 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
10973 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
10974 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10977 isSpecial = isSpecial2 = 0;
10979 if (cond & PCC_REGISTER) {
10980 name = pic16_get_op (pci->pcop, NULL, 0);
10981 sym = symFromStr (name);
10982 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
10983 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
10986 if (cond & PCC_REGISTER2) {
10987 name = pic16_get_op2 (pci->pcop, NULL, 0);
10988 sym2 = symFromStr (name);
10989 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
10990 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
10994 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10995 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11001 static void printDefmap (defmap_t *map) {
11005 fprintf (stderr, "defmap @ %p:\n", curr);
11007 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11008 curr->acc.access.isRead ? "R" : " ",
11009 curr->acc.access.isWrite ? "W": " ",
11010 curr->in_val, curr->val,
11011 curr->acc.access.in_mask, curr->acc.access.mask,
11012 strFromSym(curr->sym), curr->sym,
11016 fprintf (stderr, "<EOL>\n");
11020 /* Add "additional" definitions to uniq.
11021 * This can be used to merge the in_values and the flow's defmap to create an in_value-list for the flow's successors.
11022 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11024 * If symbols defined in additional are not present in uniq, a definition is created.
11025 * Otherwise the present definition is altered to reflect the newer assignments.
11027 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11028 * before `------- noted in additional --------' after
11030 * I assume that each symbol occurs AT MOST ONCE in uniq.
11033 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11038 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11039 /* find tail of additional list (holds the first assignment) */
11041 while (curr && curr->next) curr = curr->next;
11045 /* find next assignment in additionals */
11046 while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11050 /* find item in uniq */
11052 //printDefmap (*uniq);
11053 while (old && (old->sym != curr->sym)) old = old->next;
11056 /* definition found -- replace */
11057 if (old->val != curr->val) {
11058 old->val = curr->val;
11062 /* new definition */
11063 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11070 /* return 0 iff uniq remained unchanged */
11074 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11075 * lists of its predecessor flows.
11076 * Initially *combined should be NULL, alt_in will be copied to combined.
11077 * If *combined != NULL, combined will be altered:
11078 * - for symbols defined in *combined but not in alt_in,
11079 * *combined is altered to 0 (value unknown, either *combined or INIT).
11080 * - for symbols defined in alt_in but not in *combined,
11081 * a 0 definition is created (value unknown, either INIT or alt).
11082 * - for symbols defined in both, *combined is:
11083 * > left unchanged if *combined->val == alt_in->val or
11084 * > modified to 0 otherwise (value unknown, either alt or *combined).
11086 * I assume that each symbol occurs AT MOST ONCE in each list!
11088 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11094 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11096 if (!(*combined)) {
11097 return defmapUpdateUniqueSym (combined, alt_in);
11100 /* merge the two */
11103 /* find symbols definition in *combined */
11105 while (old && (old->sym != curr->sym)) old = old->next;
11108 /* definition found */
11109 if (old->val && (old->val != curr->val)) {
11110 old->val = 0; /* value unknown */
11114 /* no definition found -- can be either INIT or alt_in's value */
11115 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11116 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11117 if (val != curr->val) change++;
11123 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11126 if (old->val != 0) {
11127 /* find definition in alt_in */
11129 while (curr && curr->sym != old->sym) curr = curr->next;
11131 /* symbol defined in *combined only -- can be either INIT or *combined */
11132 val = pic16_pBlockAddInval (pb, old->sym)->val;
11133 if (old->val != val) {
11146 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11147 defmap_t *curr1, *curr2;
11150 /* identical maps are equal */
11151 if (map1 == map2) return 0;
11153 if (!map1) return -1;
11154 if (!map2) return 1;
11156 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11161 while (curr1 && curr2) {
11162 curr1 = curr1->next;
11163 curr2 = curr2->next;
11166 /* one of them longer? */
11167 if (curr1) return 1;
11168 if (curr2) return -1;
11170 /* both lists are of equal length -- compare (in O(n^2)) */
11175 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11176 if (!curr2) return 1; // symbol not found in curr2
11177 if (curr2->val != curr1->val) return 1; // values differ
11179 /* compare next symbol */
11180 curr1 = curr1->next;
11183 /* no difference found */
11188 /* Prepare a list of all reaching definitions per flow.
11189 * This is done using a forward dataflow analysis.
11191 static void createReachingDefinitions (pBlock *pb) {
11192 defmap_t *out_vals, *in_vals;
11195 pCodeFlowLink *link;
11199 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11200 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11202 deleteDefmapChain (&PCFL(pc)->in_vals);
11203 deleteDefmapChain (&PCFL(pc)->out_vals);
11204 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11208 pc = pic16_findNextInstruction (pb->pcHead);
11209 todo = NULL; blacklist = NULL;
11210 addSetHead (&todo, PCI(pc)->pcflow);
11212 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11213 while (elementsInSet (todo)) {
11214 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11215 pcfl = PCFL(indexSet (todo, 0));
11216 deleteSetItem (&todo, pcfl);
11217 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11221 if (isinSet (blacklist, pcfl)) {
11222 fprintf (stderr, "ignoring blacklisted flow\n");
11226 /* create in_vals from predecessors out_vals */
11227 link = setFirstItem (pcfl->from);
11229 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11230 link = setNextItem (pcfl->from);
11233 //printDefmap (in_vals);
11234 //printDefmap (pcfl->in_vals);
11236 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11237 //fprintf (stderr, "in_vals changed\n");
11238 /* in_vals changed -- update out_vals */
11239 deleteDefmapChain (&pcfl->in_vals);
11240 pcfl->in_vals = in_vals;
11242 /* create out_val from in_val and defmap */
11244 defmapUpdateUniqueSym (&out_vals, in_vals);
11245 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11247 /* is out_vals different from pcfl->out_vals */
11248 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11249 //fprintf (stderr, "out_vals changed\n");
11250 deleteDefmapChain (&pcfl->out_vals);
11251 pcfl->out_vals = out_vals;
11253 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11254 addSet (&blacklist, pcfl);
11257 /* reschedule all successors */
11258 link = setFirstItem (pcfl->to);
11260 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11261 addSetIfnotP (&todo, link->pcflow);
11262 link = setNextItem (pcfl->to);
11265 deleteDefmapChain (&out_vals);
11268 deleteDefmapChain (&in_vals);
11274 static void showAllDefs (symbol_t sym, pCode *pc) {
11278 assert (isPCI(pc));
11279 count = defmapFindAll (sym, pc, &map);
11281 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11284 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11287 pic16_pCode2str (buf, 256, map->pc);
11288 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11292 deleteDefmapChain (&map);
11296 /* safepCodeUnlink and remove pc from defmap. */
11297 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11298 defmap_t *map, *next, **head;
11302 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11303 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11304 res = pic16_safepCodeUnlink (pc, comment);
11307 /* remove pc from defmap */
11310 if (map->pc == pc) {
11311 if (!map->prev && head) *head = map->next;
11312 deleteDefmap (map);
11321 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11323 /* This breaks the defmap chain's references to pCodes... fix it! */
11324 map = PCI(pc)->pcflow->defmap;
11326 while (map && map->pc != pc) map = map->next;
11328 while (map && map->pc == pc) {
11334 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym) {
11336 if (!isPCI(pc)) return;
11338 map = PCI(pc)->pcflow->defmap;
11340 while (map && map->pc != pc) map = map->next;
11341 while (map && map->pc == pc) {
11342 if (map->sym == sym) map->sym = newsym;
11347 /* Assign "better" valnums to results. */
11348 static void assignValnums (pCode *pc) {
11349 pCodeInstruction *pci;
11351 symbol_t sym1, sym2;
11352 int cond, isSpecial1, isSpecial2, count, mask, lit;
11353 defmap_t *list, *val, *oldval, *dummy;
11354 regs *reg1 = NULL, *reg2 = NULL;
11357 /* only works for pCodeInstructions... */
11358 if (!isPCI(pc)) return;
11361 cond = pci->inCond | pci->outCond;
11362 list = pci->pcflow->defmap;
11363 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11365 if (cond & PCC_REGISTER) {
11366 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11367 reg1 = pic16_getRegFromInstruction (pc);
11368 isSpecial1 = pic16_symIsSpecial (sym1);
11370 if (cond & PCC_REGISTER2) {
11371 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11372 reg2 = pic16_getRegFromInstruction (pc);
11373 isSpecial2 = pic16_symIsSpecial (sym2);
11376 /* determine input values */
11378 while (val && val->pc != pc) val = val->next;
11379 //list = val; /* might save some time later... */
11380 while (val && val->pc == pc) {
11382 if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11383 /* get valnum for sym */
11384 count = defmapFindAll (val->sym, pc, &oldval);
11385 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11387 if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11388 val->in_val = oldval->val;
11392 } else if (count == 0) {
11393 /* no definition found */
11396 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11398 dummy = oldval->next;
11399 mask = oldval->acc.access.mask;
11400 val->in_val = oldval->val;
11401 while (dummy && (dummy->val == val->in_val)) {
11402 mask &= dummy->acc.access.mask;
11403 dummy = dummy->next;
11406 /* found other values or to restictive mask */
11407 if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11411 if (count > 0) deleteDefmapChain (&oldval);
11416 /* handle valnum assignment */
11418 case POC_CLRF: /* modifies STATUS (Z) */
11419 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11420 oldval = defmapCurr (list, sym1, pc);
11421 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11422 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11423 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11425 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11429 case POC_SETF: /* SETF does not touch STATUS */
11430 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11431 oldval = defmapCurr (list, sym1, pc);
11432 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11433 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11434 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11436 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11440 case POC_MOVLW: /* does not touch STATUS */
11441 oldval = defmapCurr (list, SPO_WREG, pc);
11442 if (pci->pcop->type == PO_LITERAL) {
11443 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11444 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11446 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11447 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11449 if (oldval && oldval->in_val == litnum) {
11450 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11451 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11453 defmapUpdate (list, SPO_WREG, pc, litnum);
11456 case POC_ANDLW: /* modifies STATUS (Z,N) */
11457 case POC_IORLW: /* modifies STATUS (Z,N) */
11458 case POC_XORLW: /* modifies STATUS (Z,N) */
11459 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11460 if (pci->pcop->type == PO_LITERAL) {
11462 lit = (unsigned char) PCOL(pci->pcop)->lit;
11463 val = defmapCurr (list, SPO_WREG, pc);
11464 if (val) vallit = litFromValnum (val->in_val);
11465 if (vallit != -1) {
11466 /* xxxLW <literal>, WREG contains a known literal */
11467 fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11468 if (pci->op == POC_ANDLW) {
11470 } else if (pci->op == POC_IORLW) {
11472 } else if (pci->op == POC_XORLW) {
11475 assert (0 && "invalid operation");
11477 if (vallit == lit) {
11478 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11479 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11481 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11488 /* check if old value matches new value */
11491 assert (pci->pcop->type == PO_LITERAL);
11493 lit = PCOL(pci->pcop)->lit;
11495 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11497 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11498 fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11500 /* cannot remove this LFSR */
11504 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11505 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11506 fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11512 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11517 case POC_MOVWF: /* does not touch flags */
11518 /* find value of WREG */
11519 val = defmapCurr (list, SPO_WREG, pc);
11520 oldval = defmapCurr (list, sym1, pc);
11521 if (val) lit = litFromValnum (val->in_val);
11523 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11525 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11526 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11527 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11529 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11531 assert (lit == 0x0ff);
11532 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11534 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11535 pic16_pCodeReplace (pc, newpc);
11536 defmapReplaceSymRef (pc, SPO_WREG, 0);
11537 pic16_fixDefmap (pc, newpc);
11540 /* This breaks the defmap chain's references to pCodes... fix it! */
11541 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11542 deleteDefmap (val); // delete reference to WREG as in value
11544 oldval = PCI(pc)->pcflow->defmap;
11546 if (oldval->pc == pc) oldval->pc = newpc;
11547 oldval = oldval->next;
11549 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11550 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11551 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11553 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11556 case POC_MOVFW: /* modifies STATUS (Z,N) */
11557 /* find value of REG */
11558 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11559 val = defmapCurr (list, sym1, pc);
11560 oldval = defmapCurr (list, SPO_WREG, pc);
11561 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11562 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11563 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11565 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11569 case POC_MOVFF: /* does not touch STATUS */
11570 /* find value of REG */
11571 val = defmapCurr (list, sym1, pc);
11572 oldval = defmapCurr (list, sym2, pc);
11573 if (val) lit = litFromValnum (val->in_val);
11576 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11577 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11579 newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11580 } else if (lit == 0x00ff) {
11581 newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11586 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11587 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11588 pic16_pCodeReplace (pc, newpc);
11589 defmapReplaceSymRef (pc, sym1, 0);
11590 pic16_fixDefmap (pc, newpc);
11592 break; // do not process instruction as MOVFF...
11594 } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) {
11595 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11596 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11597 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11599 if (!pic16_isAlive (sym1, pc)) {
11600 defmap_t *copy = NULL;
11601 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11602 * This should help eliminate
11604 * <do something not changing A or using B>
11606 * <B is not alive anymore>
11608 * <do something not changing A or using B>
11612 /* scan defmap for symbols storing sym1's value */
11613 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11614 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11615 /* unique reaching definition for sym found */
11616 if (copy->val && copy->val == val->in_val) {
11617 //fprintf (stderr, "found replacement symbol for %s (val %x) <-- %s (assigned %x @ %p)\n", strFromSym(sym1), val->in_val, strFromSym(copy->sym), copy->val, copy->pc);
11618 if (copy->sym == SPO_WREG) {
11619 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11621 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11622 // /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop),
11623 pic16_pCodeOpCopy (PCI(copy->pc)->pcop),
11624 pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11626 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11627 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11628 pic16_pCodeReplace (pc, newpc);
11629 assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11630 defmapReplaceSymRef (pc, sym1, copy->sym);
11631 pic16_fixDefmap (pc, newpc);
11635 deleteDefmapChain (©);
11638 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11643 /* cannot optimize */
11648 static void pic16_destructDF (pBlock *pb) {
11651 /* remove old defmaps */
11652 pc = pic16_findNextInstruction (pb->pcHead);
11654 next = pic16_findNextInstruction (pc->next);
11656 assert (isPCI(pc) || isPCAD(pc));
11657 assert (PCI(pc)->pcflow);
11658 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11659 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11660 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11665 if (defmap_free || defmap_free_count) {
11666 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11667 freeDefmap (&defmap_free);
11668 defmap_free_count = 0;
11672 /* Checks whether a pBlock contains ASMDIRs. */
11673 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11676 pc = pic16_findNextInstruction (pb->pcHead);
11678 if (isPCAD(pc)) return 1;
11680 pc = pic16_findNextInstruction (pc->next);
11683 /* no PCADs found */
11688 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11689 static int pic16_removeUnusedRegistersDF () {
11692 regs *reg1, *reg2, *reg3;
11693 set *seenRegs = NULL;
11695 int islocal, change = 0;
11698 if (!the_pFile || !the_pFile->pbHead) return 0;
11700 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11701 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11703 /* find set of using pCodes per register */
11704 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11705 pc = pic16_findNextInstruction(pc->next)) {
11707 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11708 reg1 = reg2 = NULL;
11709 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11710 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11713 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11714 addSetIfnotP (&seenRegs, reg1);
11715 addSetIfnotP (®1->reglives.usedpCodes, pc);
11718 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11719 addSetIfnotP (&seenRegs, reg2);
11720 addSetIfnotP (®2->reglives.usedpCodes, pc);
11724 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11725 /* may not use pic16_regIsLocal() here -- in interrupt routines
11726 * WREG, PRODx, FSR0x must be saved */
11727 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11728 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11730 for (i=0; i < 2; i++) {
11731 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11732 if (!pc2) pc2 = pc;
11733 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11734 reg2 = pic16_getRegFromInstruction (pc);
11735 reg3 = pic16_getRegFromInstruction2 (pc);
11737 || (reg2->rIdx != pic16_stack_preinc->rIdx
11738 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11740 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11741 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11742 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11743 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11747 deleteSet (®1->reglives.usedpCodes);
11750 deleteSet (&seenRegs);
11757 /* Set up pCodeFlow's defmap_ts.
11758 * Needs correctly set up to/from fields. */
11759 static void pic16_createDF (pBlock *pb) {
11763 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11765 pic16_destructDF (pb);
11767 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11768 if (pic16_pBlockHasAsmdirs (pb)) {
11769 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11773 /* integrity check -- we need to reach all flows to guarantee
11774 * correct data flow analysis (reaching definitions, aliveness) */
11776 if (!verifyAllFlowsReachable (pb)) {
11777 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11782 /* establish new defmaps */
11783 pc = pic16_findNextInstruction (pb->pcHead);
11785 next = pic16_findNextInstruction (pc->next);
11787 assert (PCI(pc)->pcflow);
11788 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11793 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11794 createReachingDefinitions (pb);
11797 /* assign better valnums */
11798 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11799 pc = pic16_findNextInstruction (pb->pcHead);
11801 next = pic16_findNextInstruction (pc->next);
11803 assert (PCI(pc)->pcflow);
11804 assignValnums (pc);
11811 /* remove dead pCodes */
11812 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11815 pc = pic16_findNextInstruction (pb->pcHead);
11817 next = pic16_findNextInstruction (pc->next);
11819 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11820 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11830 /* ======================================================================= */
11831 /* === DEPRECATED CONTROL FLOW CREATION ROUTINES ========================= */
11832 /* ======================================================================= */
11836 /* connect pCode f anf t via their to/from pBranches */
11837 static void pic16_pCodeLink (pCode *f, pCode *t) {
11839 pCodeInstruction *_f, *_t;
11841 if (!f || !t) return;
11844 fprintf (stderr, "linking:\n");
11845 f->print(stderr, f);
11846 f->print(stderr, t);
11849 assert (isPCI(f) || isPCAD(f));
11850 assert (isPCI(t) || isPCAD(t));
11854 /* define t to be CF successor of f */
11855 br = Safe_malloc (sizeof (pBranch));
11858 _f->to = pic16_pBranchAppend (_f->to, br);
11860 /* define f to be CF predecessor of t */
11861 br = Safe_malloc (sizeof (pBranch));
11864 _t->from = pic16_pBranchAppend (_t->from, br);
11866 /* also update pcflow information */
11867 if (_f->pcflow && _t->pcflow && _f->pcflow != _t->pcflow) {
11868 //fprintf (stderr, "creating flow %p --> %p\n", _f->pcflow, _t->pcflow);
11869 LinkFlow_pCode (_f, _t);
11873 static void pic16_destructCF (pBlock *pb) {
11877 /* remove old CF information */
11881 while (PCI(pc)->to) {
11882 br = PCI(pc)->to->next;
11883 Safe_free (PCI(pc)->to);
11886 while (PCI(pc)->from) {
11887 br = PCI(pc)->from->next;
11888 Safe_free (PCI(pc)->from);
11889 PCI(pc)->from = br;
11891 } else if (isPCFL(pc)) {
11892 deleteSet (&PCFL(pc)->to);
11893 deleteSet (&PCFL(pc)->from);
11901 /* Set up pCodeInstruction's to and from pBranches. */
11902 static void pic16_createCF (pBlock *pb) {
11904 pCode *next, *dest;
11907 //fprintf (stderr, "creating CF for %p\n", pb);
11909 pic16_destructCF (pb);
11911 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11912 if (pic16_pBlockHasAsmdirs (pb)) {
11913 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11917 pc = pic16_findNextInstruction(pb->pcHead);
11919 next = pic16_findNextInstruction(pc->next);
11920 if (isPCI_SKIP(pc)) {
11921 pic16_pCodeLink(pc, next);
11922 pic16_pCodeLink(pc, pic16_findNextInstruction(next->next));
11923 } else if (isPCI_BRANCH(pc)) {
11924 // Bcc, BRA, CALL, GOTO
11925 if (PCI(pc)->pcop) {
11926 switch (PCI(pc)->pcop->type) {
11928 label = PCOLAB(PCI(pc)->pcop)->pcop.name;
11929 dest = findLabelinpBlock (pc->pb, PCOLAB(PCI(pc)->pcop));
11933 /* needed for GOTO ___irq_handler */
11934 label = PCI(pc)->pcop->name;
11939 assert (0 && "invalid label format");
11947 switch (PCI(pc)->op) {
11950 if (dest != NULL) {
11951 pic16_pCodeLink(pc, dest);
11953 //fprintf (stderr, "jump target \"%s\" not found!\n", label);
11959 pic16_pCodeLink(pc, next);
11969 if (dest != NULL) {
11970 pic16_pCodeLink(pc, dest);
11972 //fprintf (stderr, "jump target \"%s\"not found!\n", label);
11974 pic16_pCodeLink(pc, next);
11977 fprintf (stderr, "BRANCH instruction: %s\n", PCI(pc)->mnemonic);
11978 assert (0 && "unhandled branch instruction");
11982 pic16_pCodeLink (pc, next);
11989 /* ======================================================================== */
11990 /* === VCG DUMPER ROUTINES ================================================ */
11991 /* ======================================================================== */
11992 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11993 hTab *dumpedNodes = NULL;
11995 /** Dump VCG header into of. */
11996 static void pic16_vcg_init (FILE *of) {
11997 /* graph defaults */
11998 fprintf (of, "graph:{\n");
11999 fprintf (of, "title:\"graph1\"\n");
12000 fprintf (of, "label:\"graph1\"\n");
12001 fprintf (of, "color:white\n");
12002 fprintf (of, "textcolor:black\n");
12003 fprintf (of, "bordercolor:black\n");
12004 fprintf (of, "borderwidth:1\n");
12005 fprintf (of, "textmode:center\n");
12007 fprintf (of, "layoutalgorithm:dfs\n");
12008 fprintf (of, "late_edge_labels:yes\n");
12009 fprintf (of, "display_edge_labels:yes\n");
12010 fprintf (of, "dirty_edge_labels:yes\n");
12011 fprintf (of, "finetuning:yes\n");
12012 fprintf (of, "ignoresingles:no\n");
12013 fprintf (of, "straight_phase:yes\n");
12014 fprintf (of, "priority_phase:yes\n");
12015 fprintf (of, "manhattan_edges:yes\n");
12016 fprintf (of, "smanhattan_edges:no\n");
12017 fprintf (of, "nearedges:no\n");
12018 fprintf (of, "node_alignment:center\n"); // bottom|top|center
12019 fprintf (of, "port_sharing:no\n");
12020 fprintf (of, "arrowmode:free\n"); // fixed|free
12021 fprintf (of, "crossingphase2:yes\n");
12022 fprintf (of, "crossingoptimization:yes\n");
12023 fprintf (of, "edges:yes\n");
12024 fprintf (of, "nodes:yes\n");
12025 fprintf (of, "splines:no\n");
12027 /* node defaults */
12028 fprintf (of, "node.color:lightyellow\n");
12029 fprintf (of, "node.textcolor:black\n");
12030 fprintf (of, "node.textmode:center\n");
12031 fprintf (of, "node.shape:box\n");
12032 fprintf (of, "node.bordercolor:black\n");
12033 fprintf (of, "node.borderwidth:1\n");
12035 /* edge defaults */
12036 fprintf (of, "edge.textcolor:black\n");
12037 fprintf (of, "edge.color:black\n");
12038 fprintf (of, "edge.thickness:1\n");
12039 fprintf (of, "edge.arrowcolor:black\n");
12040 fprintf (of, "edge.backarrowcolor:black\n");
12041 fprintf (of, "edge.arrowsize:15\n");
12042 fprintf (of, "edge.backarrowsize:15\n");
12043 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12044 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12045 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12047 fprintf (of, "\n");
12049 /* prepare data structures */
12051 hTabDeleteAll (dumpedNodes);
12052 dumpedNodes = NULL;
12054 dumpedNodes = newHashTable (128);
12057 /** Dump VCG footer into of. */
12058 static void pic16_vcg_close (FILE *of) {
12059 fprintf (of, "}\n");
12062 #define BUF_SIZE 128
12063 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12066 static int ptrcmp (const void *p1, const void *p2) {
12071 /** Dump a pCode node as VCG to of. */
12072 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12073 char buf[BUF_SIZE];
12075 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12079 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12080 //fprintf (stderr, "dumping %p\n", pc);
12082 /* only dump pCodeInstructions and Flow nodes */
12083 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12086 fprintf (of, "node:{");
12087 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12088 fprintf (of, "label:\"%s\n", pcTitle(pc));
12090 fprintf (of, "<PCFLOW>");
12091 } else if (isPCI(pc) || isPCAD(pc)) {
12092 pc->print (of, pc);
12094 fprintf (of, "<!PCI>");
12096 fprintf (of, "\" ");
12097 fprintf (of, "}\n");
12099 if (1 && isPCFL(pc)) {
12100 defmap_t *map, *prev;
12102 map = PCFL(pc)->defmap;
12105 if (map->sym != 0) {
12108 /* emit definition node */
12109 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12110 fprintf (of, "label:\"");
12114 fprintf (of, "%s%c%c: val %4x|%4x & %02x|%02x, sym %s", (prev == map) ? "" : "\n", map->acc.access.isRead ? 'R' : ' ', map->acc.access.isWrite ? 'W' : ' ', map->in_val, map->val, map->acc.access.in_mask, map->acc.access.mask, strFromSym (map->sym));
12117 } while (map && prev->pc == map->pc);
12120 fprintf (of, "\" ");
12122 fprintf (of, "color:green ");
12123 fprintf (of, "}\n");
12125 /* emit edge to previous definition */
12126 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12128 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12130 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12132 fprintf (of, "color:green ");
12133 fprintf (of, "}\n");
12136 pic16_vcg_dumpnode (map->pc, of);
12137 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12138 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12145 /* emit additional nodes (e.g. operands) */
12148 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12149 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12150 char buf[BUF_SIZE];
12151 pCodeInstruction *pci;
12155 if (1 && isPCFL(pc)) {
12156 /* emit edges to flow successors */
12158 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12159 pcfl = setFirstItem (PCFL(pc)->to);
12161 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12162 pic16_vcg_dumpnode (pc, of);
12163 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12164 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12165 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12166 pcfl = setNextItem (PCFL(pc)->to);
12170 if (!isPCI(pc) && !isPCAD(pc)) return;
12174 /* emit control flow edges (forward only) */
12178 pic16_vcg_dumpnode (curr->pc, of);
12179 fprintf (of, "edge:{");
12180 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12181 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12182 fprintf (of, "color:red ");
12183 fprintf (of, "}\n");
12188 /* dump "flow" edge (link pCode according to pBlock order) */
12191 pcnext = pic16_findNextInstruction (pc->next);
12193 pic16_vcg_dumpnode (pcnext, of);
12194 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12195 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12203 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12204 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12205 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12209 /* emit data flow edges (backward only) */
12210 /* TODO: gather data flow information... */
12213 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12216 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12217 if (pic16_pBlockHasAsmdirs (pb)) {
12218 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12222 for (pc=pb->pcHead; pc; pc = pc->next) {
12223 pic16_vcg_dumpnode (pc, of);
12226 for (pc=pb->pcHead; pc; pc = pc->next) {
12227 pic16_vcg_dumpedges (pc, of);
12231 static void pic16_vcg_dump_default (pBlock *pb) {
12233 char buf[BUF_SIZE];
12236 /* get function name */
12238 while (pc && !isPCF(pc)) pc = pc->next;
12240 SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12242 SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12245 //fprintf (stderr, "now dumping %s\n", buf);
12246 of = fopen (buf, "w");
12247 pic16_vcg_init (of);
12248 pic16_vcg_dump (of, pb);
12249 pic16_vcg_close (of);
12254 /*** END of helpers for pCode dataflow optimizations ***/