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
38 #define STRCASECMP strcasecmp
41 #define DUMP_DF_GRAPHS 0
43 /****************************************************************/
44 /****************************************************************/
46 static peepCommand peepCommands[] = {
48 {NOTBITSKIP, "_NOTBITSKIP_"},
49 {BITSKIP, "_BITSKIP_"},
50 {INVERTBITSKIP, "_INVERTBITSKIP_"},
57 // Eventually this will go into device dependent files:
58 pCodeOpReg pic16_pc_status = {{PO_STATUS, "STATUS"}, -1, NULL,0,NULL};
59 pCodeOpReg pic16_pc_intcon = {{PO_INTCON, "INTCON"}, -1, NULL,0,NULL};
60 pCodeOpReg pic16_pc_pcl = {{PO_PCL, "PCL"}, -1, NULL,0,NULL};
61 pCodeOpReg pic16_pc_pclath = {{PO_PCLATH, "PCLATH"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_pclatu = {{PO_PCLATU, "PCLATU"}, -1, NULL,0,NULL}; // patch 14
63 pCodeOpReg pic16_pc_wreg = {{PO_WREG, "WREG"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_bsr = {{PO_BSR, "BSR"}, -1, NULL,0,NULL};
66 pCodeOpReg pic16_pc_tosl = {{PO_SFR_REGISTER, "TOSL"}, -1, NULL,0,NULL}; // patch 14
67 pCodeOpReg pic16_pc_tosh = {{PO_SFR_REGISTER, "TOSH"}, -1, NULL,0,NULL}; //
68 pCodeOpReg pic16_pc_tosu = {{PO_SFR_REGISTER, "TOSU"}, -1, NULL,0,NULL}; // patch 14
70 pCodeOpReg pic16_pc_tblptrl = {{PO_SFR_REGISTER, "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
71 pCodeOpReg pic16_pc_tblptrh = {{PO_SFR_REGISTER, "TBLPTRH"}, -1, NULL,0,NULL}; //
72 pCodeOpReg pic16_pc_tblptru = {{PO_SFR_REGISTER, "TBLPTRU"}, -1, NULL,0,NULL}; //
73 pCodeOpReg pic16_pc_tablat = {{PO_SFR_REGISTER, "TABLAT"}, -1, NULL,0,NULL}; // patch 15
75 //pCodeOpReg pic16_pc_fsr0 = {{PO_FSR0, "FSR0"}, -1, NULL,0,NULL}; //deprecated !
77 pCodeOpReg pic16_pc_fsr0l = {{PO_FSR0, "FSR0L"}, -1, NULL, 0, NULL};
78 pCodeOpReg pic16_pc_fsr0h = {{PO_FSR0, "FSR0H"}, -1, NULL, 0, NULL};
79 pCodeOpReg pic16_pc_fsr1l = {{PO_FSR0, "FSR1L"}, -1, NULL, 0, NULL};
80 pCodeOpReg pic16_pc_fsr1h = {{PO_FSR0, "FSR1H"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr2l = {{PO_FSR0, "FSR2L"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr2h = {{PO_FSR0, "FSR2H"}, -1, NULL, 0, NULL};
84 pCodeOpReg pic16_pc_indf0 = {{PO_INDF0, "INDF0"}, -1, NULL,0,NULL};
85 pCodeOpReg pic16_pc_postinc0 = {{PO_INDF0, "POSTINC0"}, -1, NULL, 0, NULL};
86 pCodeOpReg pic16_pc_postdec0 = {{PO_INDF0, "POSTDEC0"}, -1, NULL, 0, NULL};
87 pCodeOpReg pic16_pc_preinc0 = {{PO_INDF0, "PREINC0"}, -1, NULL, 0, NULL};
88 pCodeOpReg pic16_pc_plusw0 = {{PO_INDF0, "PLUSW0"}, -1, NULL, 0, NULL};
90 pCodeOpReg pic16_pc_indf1 = {{PO_INDF0, "INDF1"}, -1, NULL,0,NULL};
91 pCodeOpReg pic16_pc_postinc1 = {{PO_INDF0, "POSTINC1"}, -1, NULL, 0, NULL};
92 pCodeOpReg pic16_pc_postdec1 = {{PO_INDF0, "POSTDEC1"}, -1, NULL, 0, NULL};
93 pCodeOpReg pic16_pc_preinc1 = {{PO_INDF0, "PREINC1"}, -1, NULL, 0, NULL};
94 pCodeOpReg pic16_pc_plusw1 = {{PO_INDF0, "PLUSW1"}, -1, NULL, 0, NULL};
96 pCodeOpReg pic16_pc_indf2 = {{PO_INDF0, "INDF2"}, -1, NULL,0,NULL};
97 pCodeOpReg pic16_pc_postinc2 = {{PO_INDF0, "POSTINC2"}, -1, NULL, 0, NULL};
98 pCodeOpReg pic16_pc_postdec2 = {{PO_INDF0, "POSTDEC2"}, -1, NULL, 0, NULL};
99 pCodeOpReg pic16_pc_preinc2 = {{PO_INDF0, "PREINC2"}, -1, NULL, 0, NULL};
100 pCodeOpReg pic16_pc_plusw2 = {{PO_INDF0, "PLUSW2"}, -1, NULL, 0, NULL};
102 pCodeOpReg pic16_pc_prodl = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_prodh = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
105 /* EEPROM registers */
106 pCodeOpReg pic16_pc_eecon1 = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
107 pCodeOpReg pic16_pc_eecon2 = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
108 pCodeOpReg pic16_pc_eedata = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
109 pCodeOpReg pic16_pc_eeadr = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
111 pCodeOpReg pic16_pc_kzero = {{PO_GPR_REGISTER, "KZ"}, -1, NULL,0,NULL};
112 pCodeOpReg pic16_pc_wsave = {{PO_GPR_REGISTER, "WSAVE"}, -1, NULL,0,NULL};
113 pCodeOpReg pic16_pc_ssave = {{PO_GPR_REGISTER, "SSAVE"}, -1, NULL,0,NULL};
115 pCodeOpReg *pic16_stackpnt_lo;
116 pCodeOpReg *pic16_stackpnt_hi;
117 pCodeOpReg *pic16_stack_postinc;
118 pCodeOpReg *pic16_stack_postdec;
119 pCodeOpReg *pic16_stack_preinc;
120 pCodeOpReg *pic16_stack_plusw;
122 pCodeOpReg *pic16_framepnt_lo;
123 pCodeOpReg *pic16_framepnt_hi;
124 pCodeOpReg *pic16_frame_postinc;
125 pCodeOpReg *pic16_frame_postdec;
126 pCodeOpReg *pic16_frame_preinc;
127 pCodeOpReg *pic16_frame_plusw;
129 pCodeOpReg pic16_pc_gpsimio = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
130 pCodeOpReg pic16_pc_gpsimio2 = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
132 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
133 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
136 static int mnemonics_initialized = 0;
139 static hTab *pic16MnemonicsHash = NULL;
140 static hTab *pic16pCodePeepCommandsHash = NULL;
142 static pFile *the_pFile = NULL;
143 static pBlock *pb_dead_pcodes = NULL;
145 /* Hardcoded flags to change the behavior of the PIC port */
146 static int peepOptimizing = 1; /* run the peephole optimizer if nonzero */
147 static int functionInlining = 1; /* inline functions if nonzero */
148 int pic16_debug_verbose = 0; /* Set true to inundate .asm file */
150 int pic16_pcode_verbose = 0;
152 //static int GpCodeSequenceNumber = 1;
153 static int GpcFlowSeq = 1;
155 extern void pic16_RemoveUnusedRegisters(void);
156 extern void pic16_RegsUnMapLiveRanges(void);
157 extern void pic16_BuildFlowTree(pBlock *pb);
158 extern void pic16_pCodeRegOptimizeRegUsage(int level);
159 extern int pic16_picIsInitialized(void);
160 extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
161 extern int mnem2key(char const *mnem);
163 /****************************************************************/
164 /* Forward declarations */
165 /****************************************************************/
167 void pic16_unlinkpCode(pCode *pc);
169 static void genericAnalyze(pCode *pc);
170 static void AnalyzeGOTO(pCode *pc);
171 static void AnalyzeSKIP(pCode *pc);
172 static void AnalyzeRETURN(pCode *pc);
175 static void genericDestruct(pCode *pc);
176 static void genericPrint(FILE *of,pCode *pc);
178 static void pCodePrintLabel(FILE *of, pCode *pc);
179 static void pCodePrintFunction(FILE *of, pCode *pc);
180 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
181 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
182 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
183 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
184 int pic16_pCodePeepMatchRule(pCode *pc);
185 static void pBlockStats(FILE *of, pBlock *pb);
186 static pBlock *newpBlock(void);
187 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
188 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
189 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
190 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
191 void OptimizeLocalRegs(void);
192 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
194 char *dumpPicOptype(PIC_OPTYPE type);
196 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
197 pCodeOp *pic16_popGetLit(int);
198 pCodeOp *pic16_popGetWithString(char *);
199 extern int inWparamList(char *s);
201 /** data flow optimization helpers **/
202 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
203 static void pic16_vcg_dump (FILE *of, pBlock *pb);
204 static void pic16_vcg_dump_default (pBlock *pb);
206 static int pic16_pCodeIsAlive (pCode *pc);
207 static void pic16_df_stats ();
208 static void pic16_createDF (pBlock *pb);
209 static int pic16_removeUnusedRegistersDF ();
210 static void pic16_destructDF (pBlock *pb);
211 static void releaseStack ();
213 /****************************************************************/
214 /* PIC Instructions */
215 /****************************************************************/
217 pCodeInstruction pic16_pciADDWF = {
218 {PC_OPCODE, NULL, NULL, 0, NULL,
232 1,0, // dest, bit instruction
234 0, // literal operand
236 0, // fast call/return mode select bit
237 0, // second memory operand
238 0, // second literal operand
240 (PCC_W | PCC_REGISTER), // inCond
241 (PCC_REGISTER | PCC_STATUS), // outCond
245 pCodeInstruction pic16_pciADDFW = {
246 {PC_OPCODE, NULL, NULL, 0, NULL,
260 0,0, // dest, bit instruction
262 0, // literal operand
264 0, // fast call/return mode select bit
265 0, // second memory operand
266 0, // second literal operand
268 (PCC_W | PCC_REGISTER), // inCond
269 (PCC_W | PCC_STATUS), // outCond
273 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
274 {PC_OPCODE, NULL, NULL, 0, NULL,
288 1,0, // dest, bit instruction
290 0, // literal operand
292 0, // fast call/return mode select bit
293 0, // second memory operand
294 0, // second literal operand
296 (PCC_W | PCC_REGISTER | PCC_C), // inCond
297 (PCC_REGISTER | PCC_STATUS), // outCond
301 pCodeInstruction pic16_pciADDFWC = {
302 {PC_OPCODE, NULL, NULL, 0, NULL,
316 0,0, // dest, bit instruction
318 0, // literal operand
320 0, // fast call/return mode select bit
321 0, // second memory operand
322 0, // second literal operand
324 (PCC_W | PCC_REGISTER | PCC_C), // inCond
325 (PCC_W | PCC_STATUS), // outCond
329 pCodeInstruction pic16_pciADDLW = {
330 {PC_OPCODE, NULL, NULL, 0, NULL,
344 0,0, // dest, bit instruction
346 1, // literal operand
348 0, // fast call/return mode select bit
349 0, // second memory operand
350 0, // second literal operand
352 (PCC_W | PCC_LITERAL), // inCond
353 (PCC_W | PCC_STATUS), // outCond
357 pCodeInstruction pic16_pciANDLW = {
358 {PC_OPCODE, NULL, NULL, 0, NULL,
372 0,0, // dest, bit instruction
374 1, // literal operand
376 0, // fast call/return mode select bit
377 0, // second memory operand
378 0, // second literal operand
380 (PCC_W | PCC_LITERAL), // inCond
381 (PCC_W | PCC_Z | PCC_N), // outCond
385 pCodeInstruction pic16_pciANDWF = {
386 {PC_OPCODE, NULL, NULL, 0, NULL,
400 1,0, // dest, bit instruction
402 0, // literal operand
404 0, // fast call/return mode select bit
405 0, // second memory operand
406 0, // second literal operand
408 (PCC_W | PCC_REGISTER), // inCond
409 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
413 pCodeInstruction pic16_pciANDFW = {
414 {PC_OPCODE, NULL, NULL, 0, NULL,
428 0,0, // dest, bit instruction
430 0, // literal operand
432 0, // fast call/return mode select bit
433 0, // second memory operand
434 0, // second literal operand
436 (PCC_W | PCC_REGISTER), // inCond
437 (PCC_W | PCC_Z | PCC_N) // outCond
440 pCodeInstruction pic16_pciBC = { // mdubuc - New
441 {PC_OPCODE, NULL, NULL, 0, NULL,
455 0,0, // dest, bit instruction
457 0, // literal operand
459 0, // fast call/return mode select bit
460 0, // second memory operand
461 0, // second literal operand
463 (PCC_REL_ADDR | PCC_C), // inCond
468 pCodeInstruction pic16_pciBCF = {
469 {PC_OPCODE, NULL, NULL, 0, NULL,
483 1,1, // dest, bit instruction
485 0, // literal operand
487 0, // fast call/return mode select bit
488 0, // second memory operand
489 0, // second literal operand
491 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
492 PCC_REGISTER, // outCond
496 pCodeInstruction pic16_pciBN = { // mdubuc - New
497 {PC_OPCODE, NULL, NULL, 0, NULL,
511 0,0, // dest, bit instruction
513 0, // literal operand
515 0, // fast call/return mode select bit
516 0, // second memory operand
517 0, // second literal operand
519 (PCC_REL_ADDR | PCC_N), // inCond
520 PCC_NONE , // outCond
524 pCodeInstruction pic16_pciBNC = { // mdubuc - New
525 {PC_OPCODE, NULL, NULL, 0, NULL,
539 0,0, // dest, bit instruction
541 0, // literal operand
543 0, // fast call/return mode select bit
544 0, // second memory operand
545 0, // second literal operand
547 (PCC_REL_ADDR | PCC_C), // inCond
548 PCC_NONE , // outCond
552 pCodeInstruction pic16_pciBNN = { // mdubuc - New
553 {PC_OPCODE, NULL, NULL, 0, NULL,
567 0,0, // dest, bit instruction
569 0, // literal operand
571 0, // fast call/return mode select bit
572 0, // second memory operand
573 0, // second literal operand
575 (PCC_REL_ADDR | PCC_N), // inCond
576 PCC_NONE , // outCond
580 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
581 {PC_OPCODE, NULL, NULL, 0, NULL,
595 0,0, // dest, bit instruction
597 0, // literal operand
599 0, // fast call/return mode select bit
600 0, // second memory operand
601 0, // second literal operand
603 (PCC_REL_ADDR | PCC_OV), // inCond
604 PCC_NONE , // outCond
608 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
609 {PC_OPCODE, NULL, NULL, 0, NULL,
623 0,0, // dest, bit instruction
625 0, // literal operand
627 0, // fast call/return mode select bit
628 0, // second memory operand
629 0, // second literal operand
631 (PCC_REL_ADDR | PCC_Z), // inCond
632 PCC_NONE , // outCond
636 pCodeInstruction pic16_pciBOV = { // mdubuc - New
637 {PC_OPCODE, NULL, NULL, 0, NULL,
651 0,0, // dest, bit instruction
653 0, // literal operand
655 0, // fast call/return mode select bit
656 0, // second memory operand
657 0, // second literal operand
659 (PCC_REL_ADDR | PCC_OV), // inCond
660 PCC_NONE , // outCond
664 pCodeInstruction pic16_pciBRA = { // mdubuc - New
665 {PC_OPCODE, NULL, NULL, 0, NULL,
679 0,0, // dest, bit instruction
681 0, // literal operand
683 0, // fast call/return mode select bit
684 0, // second memory operand
685 0, // second literal operand
687 PCC_REL_ADDR, // inCond
688 PCC_NONE , // outCond
692 pCodeInstruction pic16_pciBSF = {
693 {PC_OPCODE, NULL, NULL, 0, NULL,
707 1,1, // dest, bit instruction
709 0, // literal operand
711 0, // fast call/return mode select bit
712 0, // second memory operand
713 0, // second literal operand
715 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
716 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
720 pCodeInstruction pic16_pciBTFSC = {
721 {PC_OPCODE, NULL, NULL, 0, NULL,
735 0,1, // dest, bit instruction
737 0, // literal operand
739 0, // fast call/return mode select bit
740 0, // second memory operand
741 0, // second literal operand
743 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
744 PCC_EXAMINE_PCOP, // outCond
748 pCodeInstruction pic16_pciBTFSS = {
749 {PC_OPCODE, NULL, NULL, 0, NULL,
763 0,1, // dest, bit instruction
765 0, // literal operand
767 0, // fast call/return mode select bit
768 0, // second memory operand
769 0, // second literal operand
771 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
772 PCC_EXAMINE_PCOP, // outCond
776 pCodeInstruction pic16_pciBTG = { // mdubuc - New
777 {PC_OPCODE, NULL, NULL, 0, NULL,
791 0,1, // dest, bit instruction
793 0, // literal operand
795 0, // fast call/return mode select bit
796 0, // second memory operand
797 0, // second literal operand
799 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
800 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
804 pCodeInstruction pic16_pciBZ = { // mdubuc - New
805 {PC_OPCODE, NULL, NULL, 0, NULL,
819 0,0, // dest, bit instruction
821 0, // literal operand
823 0, // fast call/return mode select bit
824 0, // second memory operand
825 0, // second literal operand
827 (PCC_REL_ADDR | PCC_Z), // inCond
832 pCodeInstruction pic16_pciCALL = {
833 {PC_OPCODE, NULL, NULL, 0, NULL,
847 0,0, // dest, bit instruction
849 0, // literal operand
851 1, // fast call/return mode select bit
852 0, // second memory operand
853 0, // second literal operand
860 pCodeInstruction pic16_pciCOMF = {
861 {PC_OPCODE, NULL, NULL, 0, NULL,
875 1,0, // dest, bit instruction
877 0, // literal operand
879 0, // fast call/return mode select bit
880 0, // second memory operand
881 0, // second literal operand
883 PCC_REGISTER, // inCond
884 (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
888 pCodeInstruction pic16_pciCOMFW = {
889 {PC_OPCODE, NULL, NULL, 0, NULL,
903 0,0, // dest, bit instruction
905 0, // literal operand
907 0, // fast call/return mode select bit
908 0, // second memory operand
909 0, // second literal operand
911 PCC_REGISTER, // inCond
912 (PCC_W | PCC_Z | PCC_N) , // outCond
916 pCodeInstruction pic16_pciCLRF = {
917 {PC_OPCODE, NULL, NULL, 0, NULL,
931 0,0, // dest, bit instruction
933 0, // literal operand
935 0, // fast call/return mode select bit
936 0, // second memory operand
937 0, // second literal operand
940 (PCC_REGISTER | PCC_Z), // outCond
944 pCodeInstruction pic16_pciCLRWDT = {
945 {PC_OPCODE, NULL, NULL, 0, NULL,
959 0,0, // dest, bit instruction
961 0, // literal operand
963 0, // fast call/return mode select bit
964 0, // second memory operand
965 0, // second literal operand
968 PCC_NONE , // outCond
972 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
973 {PC_OPCODE, NULL, NULL, 0, NULL,
987 0,0, // dest, bit instruction
989 0, // literal operand
991 0, // fast call/return mode select bit
992 0, // second memory operand
993 0, // second literal operand
995 (PCC_W | PCC_REGISTER), // inCond
996 PCC_NONE , // outCond
1000 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1001 {PC_OPCODE, NULL, NULL, 0, NULL,
1008 NULL, // from branch
1015 0,0, // dest, bit instruction
1016 1,1, // branch, skip
1017 0, // literal operand
1018 1, // RAM access bit
1019 0, // fast call/return mode select bit
1020 0, // second memory operand
1021 0, // second literal operand
1023 (PCC_W | PCC_REGISTER), // inCond
1024 PCC_NONE , // outCond
1028 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1029 {PC_OPCODE, NULL, NULL, 0, NULL,
1036 NULL, // from branch
1043 1,0, // dest, bit instruction
1044 1,1, // branch, skip
1045 0, // literal operand
1046 1, // RAM access bit
1047 0, // fast call/return mode select bit
1048 0, // second memory operand
1049 0, // second literal operand
1051 (PCC_W | PCC_REGISTER), // inCond
1052 PCC_NONE , // outCond
1056 pCodeInstruction pic16_pciDAW = {
1057 {PC_OPCODE, NULL, NULL, 0, NULL,
1064 NULL, // from branch
1071 0,0, // dest, bit instruction
1072 0,0, // branch, skip
1073 0, // literal operand
1074 0, // RAM access bit
1075 0, // fast call/return mode select bit
1076 0, // second memory operand
1077 0, // second literal operand
1080 (PCC_W | PCC_C), // outCond
1084 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1085 {PC_OPCODE, NULL, NULL, 0, NULL,
1092 NULL, // from branch
1099 1,0, // dest, bit instruction
1100 1,1, // branch, skip
1101 0, // literal operand
1102 1, // RAM access bit
1103 0, // fast call/return mode select bit
1104 0, // second memory operand
1105 0, // second literal operand
1107 PCC_REGISTER, // inCond
1108 PCC_REGISTER , // outCond
1112 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1113 {PC_OPCODE, NULL, NULL, 0, NULL,
1120 NULL, // from branch
1127 0,0, // dest, bit instruction
1128 1,1, // branch, skip
1129 0, // literal operand
1130 1, // RAM access bit
1131 0, // fast call/return mode select bit
1132 0, // second memory operand
1133 0, // second literal operand
1135 PCC_REGISTER, // inCond
1140 pCodeInstruction pic16_pciDECF = {
1141 {PC_OPCODE, NULL, NULL, 0, NULL,
1148 NULL, // from branch
1155 1,0, // dest, bit instruction
1156 0,0, // branch, skip
1157 0, // literal operand
1158 1, // RAM access bit
1159 0, // fast call/return mode select bit
1160 0, // second memory operand
1161 0, // second literal operand
1163 PCC_REGISTER, // inCond
1164 (PCC_REGISTER | PCC_STATUS) , // outCond
1168 pCodeInstruction pic16_pciDECFW = {
1169 {PC_OPCODE, NULL, NULL, 0, NULL,
1176 NULL, // from branch
1183 0,0, // dest, bit instruction
1184 0,0, // branch, skip
1185 0, // literal operand
1186 1, // RAM access bit
1187 0, // fast call/return mode select bit
1188 0, // second memory operand
1189 0, // second literal operand
1191 PCC_REGISTER, // inCond
1192 (PCC_W | PCC_STATUS) , // outCond
1196 pCodeInstruction pic16_pciDECFSZ = {
1197 {PC_OPCODE, NULL, NULL, 0, NULL,
1204 NULL, // from branch
1211 1,0, // dest, bit instruction
1212 1,1, // branch, skip
1213 0, // literal operand
1214 1, // RAM access bit
1215 0, // fast call/return mode select bit
1216 0, // second memory operand
1217 0, // second literal operand
1219 PCC_REGISTER, // inCond
1220 PCC_REGISTER , // outCond
1224 pCodeInstruction pic16_pciDECFSZW = {
1225 {PC_OPCODE, NULL, NULL, 0, NULL,
1232 NULL, // from branch
1239 0,0, // dest, bit instruction
1240 1,1, // branch, skip
1241 0, // literal operand
1242 1, // RAM access bit
1243 0, // fast call/return mode select bit
1244 0, // second memory operand
1245 0, // second literal operand
1247 PCC_REGISTER, // inCond
1252 pCodeInstruction pic16_pciGOTO = {
1253 {PC_OPCODE, NULL, NULL, 0, NULL,
1260 NULL, // from branch
1267 0,0, // dest, bit instruction
1268 1,0, // branch, skip
1269 0, // literal operand
1270 0, // RAM access bit
1271 0, // fast call/return mode select bit
1272 0, // second memory operand
1273 0, // second literal operand
1275 PCC_REL_ADDR, // inCond
1276 PCC_NONE , // outCond
1280 pCodeInstruction pic16_pciINCF = {
1281 {PC_OPCODE, NULL, NULL, 0, NULL,
1288 NULL, // from branch
1295 1,0, // dest, bit instruction
1296 0,0, // branch, skip
1297 0, // literal operand
1298 1, // RAM access bit
1299 0, // fast call/return mode select bit
1300 0, // second memory operand
1301 0, // second literal operand
1303 PCC_REGISTER, // inCond
1304 (PCC_REGISTER | PCC_STATUS), // outCond
1308 pCodeInstruction pic16_pciINCFW = {
1309 {PC_OPCODE, NULL, NULL, 0, NULL,
1316 NULL, // from branch
1323 0,0, // dest, bit instruction
1324 0,0, // branch, skip
1325 0, // literal operand
1326 1, // RAM access bit
1327 0, // fast call/return mode select bit
1328 0, // second memory operand
1329 0, // second literal operand
1331 PCC_REGISTER, // inCond
1332 (PCC_W | PCC_STATUS) , // outCond
1336 pCodeInstruction pic16_pciINCFSZ = {
1337 {PC_OPCODE, NULL, NULL, 0, NULL,
1344 NULL, // from branch
1351 1,0, // dest, bit instruction
1352 1,1, // branch, skip
1353 0, // literal operand
1354 1, // RAM access bit
1355 0, // fast call/return mode select bit
1356 0, // second memory operand
1357 0, // second literal operand
1359 PCC_REGISTER, // inCond
1360 PCC_REGISTER , // outCond
1364 pCodeInstruction pic16_pciINCFSZW = {
1365 {PC_OPCODE, NULL, NULL, 0, NULL,
1372 NULL, // from branch
1379 0,0, // dest, bit instruction
1380 1,1, // branch, skip
1381 0, // literal operand
1382 1, // RAM access bit
1383 0, // fast call/return mode select bit
1384 0, // second memory operand
1385 0, // second literal operand
1387 PCC_REGISTER, // inCond
1392 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1393 {PC_OPCODE, NULL, NULL, 0, NULL,
1400 NULL, // from branch
1407 1,0, // dest, bit instruction
1408 1,1, // branch, skip
1409 0, // literal operand
1410 1, // RAM access bit
1411 0, // fast call/return mode select bit
1412 0, // second memory operand
1413 0, // second literal operand
1415 PCC_REGISTER, // inCond
1416 PCC_REGISTER , // outCond
1420 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1421 {PC_OPCODE, NULL, NULL, 0, NULL,
1428 NULL, // from branch
1435 0,0, // dest, bit instruction
1436 1,1, // branch, skip
1437 0, // literal operand
1438 1, // RAM access bit
1439 0, // fast call/return mode select bit
1440 0, // second memory operand
1441 0, // second literal operand
1443 PCC_REGISTER, // inCond
1448 pCodeInstruction pic16_pciIORWF = {
1449 {PC_OPCODE, NULL, NULL, 0, NULL,
1456 NULL, // from branch
1463 1,0, // dest, bit instruction
1464 0,0, // branch, skip
1465 0, // literal operand
1466 1, // RAM access bit
1467 0, // fast call/return mode select bit
1468 0, // second memory operand
1469 0, // second literal operand
1471 (PCC_W | PCC_REGISTER), // inCond
1472 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1476 pCodeInstruction pic16_pciIORFW = {
1477 {PC_OPCODE, NULL, NULL, 0, NULL,
1484 NULL, // from branch
1491 0,0, // dest, bit instruction
1492 0,0, // branch, skip
1493 0, // literal operand
1494 1, // RAM access bit
1495 0, // fast call/return mode select bit
1496 0, // second memory operand
1497 0, // second literal operand
1499 (PCC_W | PCC_REGISTER), // inCond
1500 (PCC_W | PCC_Z | PCC_N), // outCond
1504 pCodeInstruction pic16_pciIORLW = {
1505 {PC_OPCODE, NULL, NULL, 0, NULL,
1512 NULL, // from branch
1519 0,0, // dest, bit instruction
1520 0,0, // branch, skip
1521 1, // literal operand
1522 0, // RAM access bit
1523 0, // fast call/return mode select bit
1524 0, // second memory operand
1525 0, // second literal operand
1527 (PCC_W | PCC_LITERAL), // inCond
1528 (PCC_W | PCC_Z | PCC_N), // outCond
1532 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1533 {PC_OPCODE, NULL, NULL, 0, NULL,
1540 NULL, // from branch
1547 0,0, // dest, bit instruction
1548 0,0, // branch, skip
1549 1, // literal operand
1550 0, // RAM access bit
1551 0, // fast call/return mode select bit
1552 0, // second memory operand
1553 1, // second literal operand
1555 PCC_LITERAL, // inCond
1556 PCC_NONE, // outCond
1560 pCodeInstruction pic16_pciMOVF = {
1561 {PC_OPCODE, NULL, NULL, 0, NULL,
1568 NULL, // from branch
1575 1,0, // dest, bit instruction
1576 0,0, // branch, skip
1577 0, // literal operand
1578 1, // RAM access bit
1579 0, // fast call/return mode select bit
1580 0, // second memory operand
1581 0, // second literal operand
1583 PCC_REGISTER, // inCond
1584 (PCC_Z | PCC_N), // outCond
1588 pCodeInstruction pic16_pciMOVFW = {
1589 {PC_OPCODE, NULL, NULL, 0, NULL,
1596 NULL, // from branch
1603 0,0, // dest, bit instruction
1604 0,0, // branch, skip
1605 0, // literal operand
1606 1, // RAM access bit
1607 0, // fast call/return mode select bit
1608 0, // second memory operand
1609 0, // second literal operand
1611 PCC_REGISTER, // inCond
1612 (PCC_W | PCC_N | PCC_Z), // outCond
1616 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1617 {PC_OPCODE, NULL, NULL, 0, NULL,
1624 NULL, // from branch
1631 0,0, // dest, bit instruction
1632 0,0, // branch, skip
1633 0, // literal operand
1634 0, // RAM access bit
1635 0, // fast call/return mode select bit
1636 1, // second memory operand
1637 0, // second literal operand
1639 PCC_REGISTER, // inCond
1640 PCC_REGISTER2, // outCond
1644 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1645 {PC_OPCODE, NULL, NULL, 0, NULL,
1651 NULL, // from branch
1658 0,0, // dest, bit instruction
1659 0,0, // branch, skip
1660 1, // literal operand
1661 0, // RAM access bit
1662 0, // fast call/return mode select bit
1663 0, // second memory operand
1664 0, // second literal operand
1666 (PCC_NONE | PCC_LITERAL), // inCond
1667 PCC_REGISTER, // outCond - BSR
1671 pCodeInstruction pic16_pciMOVLW = {
1672 {PC_OPCODE, NULL, NULL, 0, NULL,
1678 NULL, // from branch
1685 0,0, // dest, bit instruction
1686 0,0, // branch, skip
1687 1, // literal operand
1688 0, // RAM access bit
1689 0, // fast call/return mode select bit
1690 0, // second memory operand
1691 0, // second literal operand
1693 (PCC_NONE | PCC_LITERAL), // inCond
1698 pCodeInstruction pic16_pciMOVWF = {
1699 {PC_OPCODE, NULL, NULL, 0, NULL,
1706 NULL, // from branch
1713 0,0, // dest, bit instruction
1714 0,0, // branch, skip
1715 0, // literal operand
1716 1, // RAM access bit
1717 0, // fast call/return mode select bit
1718 0, // second memory operand
1719 0, // second literal operand
1722 PCC_REGISTER, // outCond
1726 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1727 {PC_OPCODE, NULL, NULL, 0, NULL,
1733 NULL, // from branch
1740 0,0, // dest, bit instruction
1741 0,0, // branch, skip
1742 1, // literal operand
1743 0, // RAM access bit
1744 0, // fast call/return mode select bit
1745 0, // second memory operand
1746 0, // second literal operand
1748 (PCC_W | PCC_LITERAL), // inCond
1749 PCC_NONE, // outCond - PROD
1753 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1754 {PC_OPCODE, NULL, NULL, 0, NULL,
1760 NULL, // from branch
1767 0,0, // dest, bit instruction
1768 0,0, // branch, skip
1769 0, // literal operand
1770 1, // RAM access bit
1771 0, // fast call/return mode select bit
1772 0, // second memory operand
1773 0, // second literal operand
1775 (PCC_W | PCC_REGISTER), // inCond
1776 PCC_REGISTER, // outCond - PROD
1780 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1781 {PC_OPCODE, NULL, NULL, 0, NULL,
1787 NULL, // from branch
1794 0,0, // dest, bit instruction
1795 0,0, // branch, skip
1796 0, // literal operand
1797 1, // RAM access bit
1798 0, // fast call/return mode select bit
1799 0, // second memory operand
1800 0, // second literal operand
1802 PCC_REGISTER, // inCond
1803 (PCC_REGISTER | PCC_STATUS), // outCond
1807 pCodeInstruction pic16_pciNOP = {
1808 {PC_OPCODE, NULL, NULL, 0, NULL,
1814 NULL, // from branch
1821 0,0, // dest, bit instruction
1822 0,0, // branch, skip
1823 0, // literal operand
1824 0, // RAM access bit
1825 0, // fast call/return mode select bit
1826 0, // second memory operand
1827 0, // second literal operand
1830 PCC_NONE, // outCond
1834 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1835 {PC_OPCODE, NULL, NULL, 0, NULL,
1841 NULL, // from branch
1848 0,0, // dest, bit instruction
1849 0,0, // branch, skip
1850 0, // literal operand
1851 0, // RAM access bit
1852 0, // fast call/return mode select bit
1853 0, // second memory operand
1854 0, // second literal operand
1857 PCC_NONE , // outCond
1861 pCodeInstruction pic16_pciPUSH = {
1862 {PC_OPCODE, NULL, NULL, 0, NULL,
1868 NULL, // from branch
1875 0,0, // dest, bit instruction
1876 0,0, // branch, skip
1877 0, // literal operand
1878 0, // RAM access bit
1879 0, // fast call/return mode select bit
1880 0, // second memory operand
1881 0, // second literal operand
1884 PCC_NONE , // outCond
1888 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1889 {PC_OPCODE, NULL, NULL, 0, NULL,
1895 NULL, // from branch
1902 0,0, // dest, bit instruction
1903 1,0, // branch, skip
1904 0, // literal operand
1905 0, // RAM access bit
1906 0, // fast call/return mode select bit
1907 0, // second memory operand
1908 0, // second literal operand
1910 PCC_REL_ADDR, // inCond
1911 PCC_NONE , // outCond
1915 pCodeInstruction pic16_pciRETFIE = {
1916 {PC_OPCODE, NULL, NULL, 0, NULL,
1923 NULL, // from branch
1930 0,0, // dest, bit instruction
1931 1,0, // branch, skip
1932 0, // literal operand
1933 0, // RAM access bit
1934 1, // fast call/return mode select bit
1935 0, // second memory operand
1936 0, // second literal operand
1939 PCC_NONE, // outCond (not true... affects the GIE bit too)
1943 pCodeInstruction pic16_pciRETLW = {
1944 {PC_OPCODE, NULL, NULL, 0, NULL,
1951 NULL, // from branch
1958 0,0, // dest, bit instruction
1959 1,0, // branch, skip
1960 1, // literal operand
1961 0, // RAM access bit
1962 0, // fast call/return mode select bit
1963 0, // second memory operand
1964 0, // second literal operand
1966 PCC_LITERAL, // inCond
1971 pCodeInstruction pic16_pciRETURN = {
1972 {PC_OPCODE, NULL, NULL, 0, NULL,
1979 NULL, // from branch
1986 0,0, // dest, bit instruction
1987 1,0, // branch, skip
1988 0, // literal operand
1989 0, // RAM access bit
1990 1, // fast call/return mode select bit
1991 0, // second memory operand
1992 0, // second literal operand
1995 PCC_NONE, // outCond
1998 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
1999 {PC_OPCODE, NULL, NULL, 0, NULL,
2006 NULL, // from branch
2013 1,0, // dest, bit instruction
2014 0,0, // branch, skip
2015 0, // literal operand
2016 1, // RAM access bit
2017 0, // fast call/return mode select bit
2018 0, // second memory operand
2019 0, // second literal operand
2021 (PCC_C | PCC_REGISTER), // inCond
2022 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2026 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2027 {PC_OPCODE, NULL, NULL, 0, NULL,
2034 NULL, // from branch
2041 0,0, // dest, bit instruction
2042 0,0, // branch, skip
2043 0, // literal operand
2044 1, // RAM access bit
2045 0, // fast call/return mode select bit
2046 0, // second memory operand
2047 0, // second literal operand
2049 (PCC_C | PCC_REGISTER), // inCond
2050 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2054 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2055 {PC_OPCODE, NULL, NULL, 0, NULL,
2062 NULL, // from branch
2069 1,0, // dest, bit instruction
2070 0,0, // branch, skip
2071 0, // literal operand
2072 1, // RAM access bit
2073 0, // fast call/return mode select bit
2074 0, // second memory operand
2075 0, // second literal operand
2077 PCC_REGISTER, // inCond
2078 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2081 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2082 {PC_OPCODE, NULL, NULL, 0, NULL,
2089 NULL, // from branch
2096 0,0, // dest, bit instruction
2097 0,0, // branch, skip
2098 0, // literal operand
2099 1, // RAM access bit
2100 0, // fast call/return mode select bit
2101 0, // second memory operand
2102 0, // second literal operand
2104 PCC_REGISTER, // inCond
2105 (PCC_W | PCC_Z | PCC_N), // outCond
2108 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2109 {PC_OPCODE, NULL, NULL, 0, NULL,
2116 NULL, // from branch
2123 1,0, // dest, bit instruction
2124 0,0, // branch, skip
2125 0, // literal operand
2126 1, // RAM access bit
2127 0, // fast call/return mode select bit
2128 0, // second memory operand
2129 0, // second literal operand
2131 (PCC_C | PCC_REGISTER), // inCond
2132 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2135 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2136 {PC_OPCODE, NULL, NULL, 0, NULL,
2143 NULL, // from branch
2150 0,0, // dest, bit instruction
2151 0,0, // branch, skip
2152 0, // literal operand
2153 1, // RAM access bit
2154 0, // fast call/return mode select bit
2155 0, // second memory operand
2156 0, // second literal operand
2158 (PCC_C | PCC_REGISTER), // inCond
2159 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2162 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2163 {PC_OPCODE, NULL, NULL, 0, NULL,
2170 NULL, // from branch
2177 1,0, // dest, bit instruction
2178 0,0, // branch, skip
2179 0, // literal operand
2180 1, // RAM access bit
2181 0, // fast call/return mode select bit
2182 0, // second memory operand
2183 0, // second literal operand
2185 PCC_REGISTER, // inCond
2186 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2190 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2191 {PC_OPCODE, NULL, NULL, 0, NULL,
2198 NULL, // from branch
2205 0,0, // dest, bit instruction
2206 0,0, // branch, skip
2207 0, // literal operand
2208 1, // RAM access bit
2209 0, // fast call/return mode select bit
2210 0, // second memory operand
2211 0, // second literal operand
2213 PCC_REGISTER, // inCond
2214 (PCC_W | PCC_Z | PCC_N), // outCond
2218 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2219 {PC_OPCODE, NULL, NULL, 0, NULL,
2226 NULL, // from branch
2233 0,0, // dest, bit instruction
2234 0,0, // branch, skip
2235 0, // literal operand
2236 1, // RAM access bit
2237 0, // fast call/return mode select bit
2238 0, // second memory operand
2239 0, // second literal operand
2242 PCC_REGISTER , // outCond
2246 pCodeInstruction pic16_pciSUBLW = {
2247 {PC_OPCODE, NULL, NULL, 0, NULL,
2254 NULL, // from branch
2261 0,0, // dest, bit instruction
2262 0,0, // branch, skip
2263 1, // literal operand
2264 0, // RAM access bit
2265 0, // fast call/return mode select bit
2266 0, // second memory operand
2267 0, // second literal operand
2269 (PCC_W | PCC_LITERAL), // inCond
2270 (PCC_W | PCC_STATUS), // outCond
2274 pCodeInstruction pic16_pciSUBFWB = {
2275 {PC_OPCODE, NULL, NULL, 0, NULL,
2282 NULL, // from branch
2289 1,0, // dest, bit instruction
2290 0,0, // branch, skip
2291 0, // literal operand
2292 1, // RAM access bit
2293 0, // fast call/return mode select bit
2294 0, // second memory operand
2295 0, // second literal operand
2297 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2298 (PCC_W | PCC_STATUS), // outCond
2302 pCodeInstruction pic16_pciSUBWF = {
2303 {PC_OPCODE, NULL, NULL, 0, NULL,
2310 NULL, // from branch
2317 1,0, // dest, bit instruction
2318 0,0, // branch, skip
2319 0, // literal operand
2320 1, // RAM access bit
2321 0, // fast call/return mode select bit
2322 0, // second memory operand
2323 0, // second literal operand
2325 (PCC_W | PCC_REGISTER), // inCond
2326 (PCC_REGISTER | PCC_STATUS), // outCond
2330 pCodeInstruction pic16_pciSUBFW = {
2331 {PC_OPCODE, NULL, NULL, 0, NULL,
2338 NULL, // from branch
2345 0,0, // dest, bit instruction
2346 0,0, // branch, skip
2347 0, // literal operand
2348 1, // RAM access bit
2349 0, // fast call/return mode select bit
2350 0, // second memory operand
2351 0, // second literal operand
2353 (PCC_W | PCC_REGISTER), // inCond
2354 (PCC_W | PCC_STATUS), // outCond
2358 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2359 {PC_OPCODE, NULL, NULL, 0, NULL,
2366 NULL, // from branch
2373 1,0, // dest, bit instruction
2374 0,0, // branch, skip
2375 0, // literal operand
2376 1, // RAM access bit
2377 0, // fast call/return mode select bit
2378 0, // second memory operand
2379 0, // second literal operand
2381 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2382 (PCC_REGISTER | PCC_STATUS), // outCond
2386 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2387 {PC_OPCODE, NULL, NULL, 0, NULL,
2394 NULL, // from branch
2401 0,0, // dest, bit instruction
2402 0,0, // branch, skip
2403 0, // literal operand
2404 1, // RAM access bit
2405 0, // fast call/return mode select bit
2406 0, // second memory operand
2407 0, // second literal operand
2409 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2410 (PCC_W | PCC_STATUS), // outCond
2414 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2415 {PC_OPCODE, NULL, NULL, 0, NULL,
2422 NULL, // from branch
2429 1,0, // dest, bit instruction
2430 0,0, // branch, skip
2431 0, // literal operand
2432 1, // RAM access bit
2433 0, // fast call/return mode select bit
2434 0, // second memory operand
2435 0, // second literal operand
2437 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2438 (PCC_REGISTER | PCC_STATUS), // outCond
2442 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2443 {PC_OPCODE, NULL, NULL, 0, NULL,
2450 NULL, // from branch
2457 0,0, // dest, bit instruction
2458 0,0, // branch, skip
2459 0, // literal operand
2460 1, // RAM access bit
2461 0, // fast call/return mode select bit
2462 0, // second memory operand
2463 0, // second literal operand
2465 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2466 (PCC_W | PCC_STATUS), // outCond
2470 pCodeInstruction pic16_pciSWAPF = {
2471 {PC_OPCODE, NULL, NULL, 0, NULL,
2478 NULL, // from branch
2485 1,0, // dest, bit instruction
2486 0,0, // branch, skip
2487 0, // literal operand
2488 1, // RAM access bit
2489 0, // fast call/return mode select bit
2490 0, // second memory operand
2491 0, // second literal operand
2493 (PCC_REGISTER), // inCond
2494 (PCC_REGISTER), // outCond
2498 pCodeInstruction pic16_pciSWAPFW = {
2499 {PC_OPCODE, NULL, NULL, 0, NULL,
2506 NULL, // from branch
2513 0,0, // dest, bit instruction
2514 0,0, // branch, skip
2515 0, // literal operand
2516 1, // RAM access bit
2517 0, // fast call/return mode select bit
2518 0, // second memory operand
2519 0, // second literal operand
2521 (PCC_REGISTER), // inCond
2526 pCodeInstruction pic16_pciTBLRD = { // patch 15
2527 {PC_OPCODE, NULL, NULL, 0, NULL,
2533 NULL, // from branch
2540 0,0, // dest, bit instruction
2541 0,0, // branch, skip
2542 0, // literal operand
2543 0, // RAM access bit
2544 0, // fast call/return mode select bit
2545 0, // second memory operand
2546 0, // second literal operand
2549 PCC_NONE , // outCond
2553 pCodeInstruction pic16_pciTBLRD_POSTINC = { // patch 15
2554 {PC_OPCODE, NULL, NULL, 0, NULL,
2560 NULL, // from branch
2567 0,0, // dest, bit instruction
2568 0,0, // branch, skip
2569 0, // literal operand
2570 0, // RAM access bit
2571 0, // fast call/return mode select bit
2572 0, // second memory operand
2573 0, // second literal operand
2576 PCC_NONE , // outCond
2580 pCodeInstruction pic16_pciTBLRD_POSTDEC = { // patch 15
2581 {PC_OPCODE, NULL, NULL, 0, NULL,
2587 NULL, // from branch
2594 0,0, // dest, bit instruction
2595 0,0, // branch, skip
2596 0, // literal operand
2597 0, // RAM access bit
2598 0, // fast call/return mode select bit
2599 0, // second memory operand
2600 0, // second literal operand
2603 PCC_NONE , // outCond
2607 pCodeInstruction pic16_pciTBLRD_PREINC = { // patch 15
2608 {PC_OPCODE, NULL, NULL, 0, NULL,
2614 NULL, // from branch
2621 0,0, // dest, bit instruction
2622 0,0, // branch, skip
2623 0, // literal operand
2624 0, // RAM access bit
2625 0, // fast call/return mode select bit
2626 0, // second memory operand
2627 0, // second literal operand
2630 PCC_NONE , // outCond
2634 pCodeInstruction pic16_pciTBLWT = { // patch 15
2635 {PC_OPCODE, NULL, NULL, 0, NULL,
2641 NULL, // from branch
2648 0,0, // dest, bit instruction
2649 0,0, // branch, skip
2650 0, // literal operand
2651 0, // RAM access bit
2652 0, // fast call/return mode select bit
2653 0, // second memory operand
2654 0, // second literal operand
2657 PCC_NONE , // outCond
2661 pCodeInstruction pic16_pciTBLWT_POSTINC = { // patch 15
2662 {PC_OPCODE, NULL, NULL, 0, NULL,
2668 NULL, // from branch
2675 0,0, // dest, bit instruction
2676 0,0, // branch, skip
2677 0, // literal operand
2678 0, // RAM access bit
2679 0, // fast call/return mode select bit
2680 0, // second memory operand
2681 0, // second literal operand
2684 PCC_NONE , // outCond
2688 pCodeInstruction pic16_pciTBLWT_POSTDEC = { // patch 15
2689 {PC_OPCODE, NULL, NULL, 0, NULL,
2695 NULL, // from branch
2702 0,0, // dest, bit instruction
2703 0,0, // branch, skip
2704 0, // literal operand
2705 0, // RAM access bit
2706 0, // fast call/return mode select bit
2707 0, // second memory operand
2708 0, // second literal operand
2711 PCC_NONE , // outCond
2715 pCodeInstruction pic16_pciTBLWT_PREINC = { // patch 15
2716 {PC_OPCODE, NULL, NULL, 0, NULL,
2722 NULL, // from branch
2729 0,0, // dest, bit instruction
2730 0,0, // branch, skip
2731 0, // literal operand
2732 0, // RAM access bit
2733 0, // fast call/return mode select bit
2734 0, // second memory operand
2735 0, // second literal operand
2738 PCC_NONE , // outCond
2742 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2743 {PC_OPCODE, NULL, NULL, 0, NULL,
2750 NULL, // from branch
2757 0,0, // dest, bit instruction
2758 1,1, // branch, skip
2759 0, // literal operand
2760 1, // RAM access bit
2761 0, // fast call/return mode select bit
2762 0, // second memory operand
2763 0, // second literal operand
2765 PCC_REGISTER, // inCond
2766 PCC_NONE, // outCond
2770 pCodeInstruction pic16_pciXORWF = {
2771 {PC_OPCODE, NULL, NULL, 0, NULL,
2778 NULL, // from branch
2785 1,0, // dest, bit instruction
2786 0,0, // branch, skip
2787 0, // literal operand
2788 1, // RAM access bit
2789 0, // fast call/return mode select bit
2790 0, // second memory operand
2791 0, // second literal operand
2793 (PCC_W | PCC_REGISTER), // inCond
2794 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2798 pCodeInstruction pic16_pciXORFW = {
2799 {PC_OPCODE, NULL, NULL, 0, NULL,
2806 NULL, // from branch
2813 0,0, // dest, bit instruction
2814 0,0, // branch, skip
2815 0, // literal operand
2816 1, // RAM access bit
2817 0, // fast call/return mode select bit
2818 0, // second memory operand
2819 0, // second literal operand
2821 (PCC_W | PCC_REGISTER), // inCond
2822 (PCC_W | PCC_Z | PCC_N), // outCond
2826 pCodeInstruction pic16_pciXORLW = {
2827 {PC_OPCODE, NULL, NULL, 0, NULL,
2834 NULL, // from branch
2841 0,0, // dest, bit instruction
2842 0,0, // branch, skip
2843 1, // literal operand
2844 1, // RAM access bit
2845 0, // fast call/return mode select bit
2846 0, // second memory operand
2847 0, // second literal operand
2849 (PCC_W | PCC_LITERAL), // inCond
2850 (PCC_W | PCC_Z | PCC_N), // outCond
2855 pCodeInstruction pic16_pciBANKSEL = {
2856 {PC_OPCODE, NULL, NULL, 0, NULL,
2862 NULL, // from branch
2869 0,0, // dest, bit instruction
2870 0,0, // branch, skip
2871 0, // literal operand
2872 0, // RAM access bit
2873 0, // fast call/return mode select bit
2874 0, // second memory operand
2875 0, // second literal operand
2878 PCC_NONE, // outCond
2883 #define MAX_PIC16MNEMONICS 100
2884 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2886 //#define USE_VSNPRINTF
2889 #ifdef USE_VSNPRINTF
2890 // Alas, vsnprintf is not ANSI standard, and does not exist
2891 // on Solaris (and probably other non-Gnu flavored Unixes).
2893 /*-----------------------------------------------------------------*/
2894 /* SAFE_snprintf - like snprintf except the string pointer is */
2895 /* after the string has been printed to. This is */
2896 /* useful for printing to string as though if it */
2897 /* were a stream. */
2898 /*-----------------------------------------------------------------*/
2899 void SAFE_snprintf(char **str, size_t *size, const char *format, ...)
2907 va_start(val, format);
2909 vsnprintf(*str, *size, format, val);
2915 fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2916 fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2925 // This version is *not* safe, despite the name.
2927 void SAFE_snprintf(char **str, size_t *size, const char *format, ...)
2931 static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2936 va_start(val, format);
2938 vsprintf(buffer, format, val);
2941 len = strlen(buffer);
2943 fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2944 fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2947 strcpy(*str, buffer);
2953 #endif // USE_VSNPRINTF
2956 extern set *externs;
2957 extern void pic16_initStack(int base_address, int size);
2958 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2959 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2960 extern void pic16_init_pic(char *);
2962 void pic16_pCodeInitRegisters(void)
2964 static int initialized=0;
2971 // pic16_initStack(0xfff, 8);
2972 pic16_init_pic(port->processor);
2974 pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2975 pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2976 pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2977 pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2978 pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2979 pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2980 pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2982 pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2983 pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2984 pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2986 pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2987 pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2988 pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2989 pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2991 pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2992 pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2993 pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2994 pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2995 pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2996 pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2998 pic16_stackpnt_lo = &pic16_pc_fsr1l;
2999 pic16_stackpnt_hi = &pic16_pc_fsr1h;
3000 pic16_stack_postdec = &pic16_pc_postdec1;
3001 pic16_stack_postinc = &pic16_pc_postinc1;
3002 pic16_stack_preinc = &pic16_pc_preinc1;
3003 pic16_stack_plusw = &pic16_pc_plusw1;
3005 pic16_framepnt_lo = &pic16_pc_fsr2l;
3006 pic16_framepnt_hi = &pic16_pc_fsr2h;
3007 pic16_frame_postdec = &pic16_pc_postdec2;
3008 pic16_frame_postinc = &pic16_pc_postinc2;
3009 pic16_frame_preinc = &pic16_pc_preinc2;
3010 pic16_frame_plusw = &pic16_pc_plusw2;
3012 pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3013 pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3014 pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3015 pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3016 pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3018 pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3019 pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3020 pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3021 pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3022 pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3024 pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3025 pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3026 pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3027 pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3028 pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3030 pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3031 pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3034 pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3035 pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3036 pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3037 pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3040 pic16_pc_status.rIdx = IDX_STATUS;
3041 pic16_pc_intcon.rIdx = IDX_INTCON;
3042 pic16_pc_pcl.rIdx = IDX_PCL;
3043 pic16_pc_pclath.rIdx = IDX_PCLATH;
3044 pic16_pc_pclatu.rIdx = IDX_PCLATU;
3045 pic16_pc_wreg.rIdx = IDX_WREG;
3046 pic16_pc_bsr.rIdx = IDX_BSR;
3048 pic16_pc_tosl.rIdx = IDX_TOSL;
3049 pic16_pc_tosh.rIdx = IDX_TOSH;
3050 pic16_pc_tosu.rIdx = IDX_TOSU;
3052 pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3053 pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3054 pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3055 pic16_pc_tablat.rIdx = IDX_TABLAT;
3057 pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3058 pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3059 pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3060 pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3061 pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3062 pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3063 pic16_pc_indf0.rIdx = IDX_INDF0;
3064 pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3065 pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3066 pic16_pc_preinc0.rIdx = IDX_PREINC0;
3067 pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3068 pic16_pc_indf1.rIdx = IDX_INDF1;
3069 pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3070 pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3071 pic16_pc_preinc1.rIdx = IDX_PREINC1;
3072 pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3073 pic16_pc_indf2.rIdx = IDX_INDF2;
3074 pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3075 pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3076 pic16_pc_preinc2.rIdx = IDX_PREINC2;
3077 pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3078 pic16_pc_prodl.rIdx = IDX_PRODL;
3079 pic16_pc_prodh.rIdx = IDX_PRODH;
3081 pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3082 pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3083 pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3085 pic16_pc_kzero.rIdx = IDX_KZ;
3086 pic16_pc_wsave.rIdx = IDX_WSAVE;
3087 pic16_pc_ssave.rIdx = IDX_SSAVE;
3089 pic16_pc_eecon1.rIdx = IDX_EECON1;
3090 pic16_pc_eecon2.rIdx = IDX_EECON2;
3091 pic16_pc_eedata.rIdx = IDX_EEDATA;
3092 pic16_pc_eeadr.rIdx = IDX_EEADR;
3095 pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3096 pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3098 pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3099 pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3101 /* probably should put this in a separate initialization routine */
3102 pb_dead_pcodes = newpBlock();
3107 /*-----------------------------------------------------------------*/
3108 /* mnem2key - convert a pic mnemonic into a hash key */
3109 /* (BTW - this spreads the mnemonics quite well) */
3111 /*-----------------------------------------------------------------*/
3113 int mnem2key(char const *mnem)
3122 key += toupper(*mnem++) +1;
3126 return (key & 0x1f);
3131 void pic16initMnemonics(void)
3136 pCodeInstruction *pci;
3138 if(mnemonics_initialized)
3141 // NULL out the array before making the assignments
3142 // since we check the array contents below this initialization.
3144 for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3145 pic16Mnemonics[i] = NULL;
3148 pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3149 pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3150 pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3151 pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3152 pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3153 pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3154 pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3155 pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3156 pic16Mnemonics[POC_BC] = &pic16_pciBC;
3157 pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3158 pic16Mnemonics[POC_BN] = &pic16_pciBN;
3159 pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3160 pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3161 pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3162 pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3163 pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3164 pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3165 pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3166 pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3167 pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3168 pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3169 pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3170 pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3171 pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3172 pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3173 pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3174 pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3175 pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3176 pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3177 pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3178 pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3179 pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3180 pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3181 pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3182 pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3183 pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3184 pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3185 pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3186 pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3187 pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3188 pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3189 pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3190 pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3191 pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3192 pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3193 pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3194 pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3195 pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3196 pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3197 pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3198 pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3199 pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3200 pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3201 pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3202 pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3203 pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3204 pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3205 pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3206 pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3207 pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3208 pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3209 pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3210 pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3211 pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3212 pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3213 pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3214 pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3215 pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3216 pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3217 pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3218 pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3219 pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3220 pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3221 pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3222 pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3223 pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3224 pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3225 pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3226 pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3227 pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3228 pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3229 pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3230 pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3231 pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3232 pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3233 pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3234 pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3235 pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3236 pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3237 pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3238 pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3239 pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3240 pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3241 pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3243 for(i=0; i<MAX_PIC16MNEMONICS; i++)
3244 if(pic16Mnemonics[i])
3245 hTabAddItem(&pic16MnemonicsHash, mnem2key(pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3246 pci = hTabFirstItem(pic16MnemonicsHash, &key);
3249 DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3250 pci = hTabNextItem(pic16MnemonicsHash, &key);
3253 mnemonics_initialized = 1;
3256 int pic16_getpCodePeepCommand(char *cmd);
3258 int pic16_getpCode(char *mnem,unsigned dest)
3261 pCodeInstruction *pci;
3262 int key = mnem2key(mnem);
3264 if(!mnemonics_initialized)
3265 pic16initMnemonics();
3267 pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3271 if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3272 if((pci->num_ops <= 1)
3273 || (pci->isModReg == dest)
3275 || (pci->num_ops <= 2 && pci->isAccess)
3276 || (pci->num_ops <= 2 && pci->isFastCall)
3277 || (pci->num_ops <= 2 && pci->is2MemOp)
3278 || (pci->num_ops <= 2 && pci->is2LitOp) )
3282 pci = hTabNextItemWK (pic16MnemonicsHash);
3289 /*-----------------------------------------------------------------*
3290 * pic16initpCodePeepCommands
3292 *-----------------------------------------------------------------*/
3293 void pic16initpCodePeepCommands(void)
3301 hTabAddItem(&pic16pCodePeepCommandsHash,
3302 mnem2key(peepCommands[i].cmd), &peepCommands[i]);
3304 } while (peepCommands[i].cmd);
3306 pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3309 //fprintf(stderr, "peep command %s key %d\n",pcmd->cmd,pcmd->id);
3310 pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3315 /*-----------------------------------------------------------------
3318 *-----------------------------------------------------------------*/
3320 int pic16_getpCodePeepCommand(char *cmd)
3324 int key = mnem2key(cmd);
3327 pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3330 // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3331 if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3335 pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3342 static char getpBlock_dbName(pBlock *pb)
3348 return pb->cmemmap->dbName;
3352 void pic16_pBlockConvert2ISR(pBlock *pb)
3356 if(pb->cmemmap)pb->cmemmap = NULL;
3360 if(pic16_pcode_verbose)
3361 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3364 void pic16_pBlockConvert2Absolute(pBlock *pb)
3367 if(pb->cmemmap)pb->cmemmap = NULL;
3371 if(pic16_pcode_verbose)
3372 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3375 /*-----------------------------------------------------------------*/
3376 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all */
3377 /* instances to the front of the doubly linked */
3378 /* list of pBlocks */
3379 /*-----------------------------------------------------------------*/
3381 void pic16_movepBlock2Head(char dbName)
3386 /* this can happen in sources without code,
3387 * only variable definitions */
3388 if(!the_pFile)return;
3390 pb = the_pFile->pbHead;
3394 if(getpBlock_dbName(pb) == dbName) {
3395 pBlock *pbn = pb->next;
3396 pb->next = the_pFile->pbHead;
3397 the_pFile->pbHead->prev = pb;
3398 the_pFile->pbHead = pb;
3401 pb->prev->next = pbn;
3403 // If the pBlock that we just moved was the last
3404 // one in the link of all of the pBlocks, then we
3405 // need to point the tail to the block just before
3406 // the one we moved.
3407 // Note: if pb->next is NULL, then pb must have
3408 // been the last pBlock in the chain.
3411 pbn->prev = pb->prev;
3413 the_pFile->pbTail = pb->prev;
3424 void pic16_copypCode(FILE *of, char dbName)
3428 if(!of || !the_pFile)
3431 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3432 if(getpBlock_dbName(pb) == dbName) {
3433 // fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3435 pic16_printpBlock(of,pb);
3440 void pic16_pcode_test(void)
3443 DFPRINTF((stderr,"pcode is alive!\n"));
3453 /* create the file name */
3454 strcpy(buffer,dstFileName);
3455 strcat(buffer,".p");
3457 if( !(pFile = fopen(buffer, "w" ))) {
3458 werror(E_FILE_OPEN_ERR,buffer);
3462 fprintf(pFile,"pcode dump\n\n");
3464 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3465 fprintf(pFile,"\n\tNew pBlock\n\n");
3467 fprintf(pFile,"%s",pb->cmemmap->sname);
3469 fprintf(pFile,"internal pblock");
3471 fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3472 pic16_printpBlock(pFile,pb);
3478 unsigned long pic16_countInstructions(void)
3482 unsigned long isize=0;
3484 if(!the_pFile)return -1;
3486 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3487 for(pc = pb->pcHead; pc; pc = pc->next) {
3488 if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3495 /*-----------------------------------------------------------------*/
3496 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg- */
3497 /* ister, RegCond will return the bit being referenced. */
3499 /* fixme - why not just OR in the pcop bit field */
3500 /*-----------------------------------------------------------------*/
3502 static int RegCond(pCodeOp *pcop)
3508 if(!pcop->name)return 0;
3510 if(pcop->type == PO_GPR_BIT && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3511 switch(PCORB(pcop)->bit) {
3525 /*-----------------------------------------------------------------*/
3526 /* pic16_newpCode - create and return a newly initialized pCode */
3528 /* fixme - rename this */
3530 /* The purpose of this routine is to create a new Instruction */
3531 /* pCode. This is called by gen.c while the assembly code is being */
3535 /* PIC_OPCODE op - the assembly instruction we wish to create. */
3536 /* (note that the op is analogous to but not the */
3537 /* same thing as the opcode of the instruction.) */
3538 /* pCdoeOp *pcop - pointer to the operand of the instruction. */
3541 /* a pointer to the new malloc'd pCode is returned. */
3545 /*-----------------------------------------------------------------*/
3546 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3548 pCodeInstruction *pci ;
3550 if(!mnemonics_initialized)
3551 pic16initMnemonics();
3553 pci = Safe_calloc(1, sizeof(pCodeInstruction));
3555 if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3556 memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3559 if(pci->inCond & PCC_EXAMINE_PCOP)
3560 pci->inCond |= RegCond(pcop);
3562 if(pci->outCond & PCC_EXAMINE_PCOP)
3563 pci->outCond |= RegCond(pcop);
3565 pci->pc.prev = pci->pc.next = NULL;
3566 return (pCode *)pci;
3569 fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3575 /*-----------------------------------------------------------------*/
3576 /* pic16_newpCodeWild - create a "wild" as in wild card pCode */
3578 /* Wild pcodes are used during the peep hole optimizer to serve */
3579 /* as place holders for any instruction. When a snippet of code is */
3580 /* compared to a peep hole rule, the wild card opcode will match */
3581 /* any instruction. However, the optional operand and label are */
3582 /* additional qualifiers that must also be matched before the */
3583 /* line (of assembly code) is declared matched. Note that the */
3584 /* operand may be wild too. */
3586 /* Note, a wild instruction is specified just like a wild var: */
3587 /* %4 ; A wild instruction, */
3588 /* See the peeph.def file for additional examples */
3590 /*-----------------------------------------------------------------*/
3592 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3597 pcw = Safe_calloc(1,sizeof(pCodeWild));
3599 pcw->pci.pc.type = PC_WILD;
3600 pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3601 pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3602 pcw->pci.pc.pb = NULL;
3604 // pcw->pci.pc.analyze = genericAnalyze;
3605 pcw->pci.pc.destruct = genericDestruct;
3606 pcw->pci.pc.print = genericPrint;
3608 pcw->id = pCodeID; // this is the 'n' in %n
3609 pcw->operand = optional_operand;
3610 pcw->label = optional_label;
3612 pcw->mustBeBitSkipInst = 0;
3613 pcw->mustNotBeBitSkipInst = 0;
3614 pcw->invertBitSkipInst = 0;
3616 return ( (pCode *)pcw);
3620 /*-----------------------------------------------------------------*/
3621 /* newPcodeInlineP - create a new pCode from a char string */
3622 /*-----------------------------------------------------------------*/
3625 pCode *pic16_newpCodeInlineP(char *cP)
3630 pcc = Safe_calloc(1,sizeof(pCodeComment));
3632 pcc->pc.type = PC_INLINE;
3633 pcc->pc.prev = pcc->pc.next = NULL;
3634 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3637 // pcc->pc.analyze = genericAnalyze;
3638 pcc->pc.destruct = genericDestruct;
3639 pcc->pc.print = genericPrint;
3642 pcc->comment = Safe_strdup(cP);
3644 pcc->comment = NULL;
3646 return ( (pCode *)pcc);
3650 /*-----------------------------------------------------------------*/
3651 /* newPcodeCharP - create a new pCode from a char string */
3652 /*-----------------------------------------------------------------*/
3654 pCode *pic16_newpCodeCharP(char *cP)
3659 pcc = Safe_calloc(1,sizeof(pCodeComment));
3661 pcc->pc.type = PC_COMMENT;
3662 pcc->pc.prev = pcc->pc.next = NULL;
3663 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3666 // pcc->pc.analyze = genericAnalyze;
3667 pcc->pc.destruct = genericDestruct;
3668 pcc->pc.print = genericPrint;
3671 pcc->comment = Safe_strdup(cP);
3673 pcc->comment = NULL;
3675 return ( (pCode *)pcc);
3679 /*-----------------------------------------------------------------*/
3680 /* pic16_newpCodeFunction - */
3681 /*-----------------------------------------------------------------*/
3684 pCode *pic16_newpCodeFunction(char *mod,char *f)
3688 pcf = Safe_calloc(1,sizeof(pCodeFunction));
3690 pcf->pc.type = PC_FUNCTION;
3691 pcf->pc.prev = pcf->pc.next = NULL;
3692 //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3695 // pcf->pc.analyze = genericAnalyze;
3696 pcf->pc.destruct = genericDestruct;
3697 pcf->pc.print = pCodePrintFunction;
3703 pcf->modname = Safe_calloc(1,strlen(mod)+1);
3704 strcpy(pcf->modname,mod);
3706 pcf->modname = NULL;
3709 pcf->fname = Safe_calloc(1,strlen(f)+1);
3710 strcpy(pcf->fname,f);
3714 pcf->stackusage = 0;
3716 return ( (pCode *)pcf);
3719 /*-----------------------------------------------------------------*/
3720 /* pic16_newpCodeFlow */
3721 /*-----------------------------------------------------------------*/
3722 static void destructpCodeFlow(pCode *pc)
3724 if(!pc || !isPCFL(pc))
3731 pic16_unlinkpCode(pc);
3733 deleteSet(&PCFL(pc)->registers);
3734 deleteSet(&PCFL(pc)->from);
3735 deleteSet(&PCFL(pc)->to);
3737 /* Instead of deleting the memory used by this pCode, mark
3738 * the object as bad so that if there's a pointer to this pCode
3739 * dangling around somewhere then (hopefully) when the type is
3740 * checked we'll catch it.
3744 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3750 pCode *pic16_newpCodeFlow(void )
3754 //_ALLOC(pcflow,sizeof(pCodeFlow));
3755 pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3757 pcflow->pc.type = PC_FLOW;
3758 pcflow->pc.prev = pcflow->pc.next = NULL;
3759 pcflow->pc.pb = NULL;
3761 // pcflow->pc.analyze = genericAnalyze;
3762 pcflow->pc.destruct = destructpCodeFlow;
3763 pcflow->pc.print = genericPrint;
3765 pcflow->pc.seq = GpcFlowSeq++;
3767 pcflow->from = pcflow->to = NULL;
3769 pcflow->inCond = PCC_NONE;
3770 pcflow->outCond = PCC_NONE;
3772 pcflow->firstBank = -1;
3773 pcflow->lastBank = -1;
3775 pcflow->FromConflicts = 0;
3776 pcflow->ToConflicts = 0;
3780 pcflow->registers = newSet();
3782 return ( (pCode *)pcflow);
3786 /*-----------------------------------------------------------------*/
3787 /*-----------------------------------------------------------------*/
3788 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3790 pCodeFlowLink *pcflowLink;
3792 pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3794 pcflowLink->pcflow = pcflow;
3795 pcflowLink->bank_conflict = 0;
3800 /*-----------------------------------------------------------------*/
3801 /* pic16_newpCodeCSource - create a new pCode Source Symbol */
3802 /*-----------------------------------------------------------------*/
3804 pCode *pic16_newpCodeCSource(int ln, char *f, char *l)
3809 pccs = Safe_calloc(1,sizeof(pCodeCSource));
3811 pccs->pc.type = PC_CSOURCE;
3812 pccs->pc.prev = pccs->pc.next = NULL;
3815 pccs->pc.destruct = genericDestruct;
3816 pccs->pc.print = genericPrint;
3818 pccs->line_number = ln;
3820 pccs->line = Safe_strdup(l);
3825 pccs->file_name = Safe_strdup(f);
3827 pccs->file_name = NULL;
3829 return ( (pCode *)pccs);
3834 /*******************************************************************/
3835 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive */
3836 /* added by VR 6-Jun-2003 */
3837 /*******************************************************************/
3839 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3846 pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3847 pcad->pci.pc.type = PC_ASMDIR;
3848 pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3849 pcad->pci.pc.pb = NULL;
3850 pcad->pci.isize = 2;
3851 pcad->pci.pc.destruct = genericDestruct;
3852 pcad->pci.pc.print = genericPrint;
3854 if(asdir && *asdir) {
3856 while(isspace(*asdir))asdir++; // strip any white space from the beginning
3858 pcad->directive = Safe_strdup( asdir );
3861 va_start(ap, argfmt);
3863 memset(buffer, 0, sizeof(buffer));
3864 if(argfmt && *argfmt)
3865 vsprintf(buffer, argfmt, ap);
3869 while(isspace(*lbp))lbp++;
3872 pcad->arg = Safe_strdup( lbp );
3874 return ((pCode *)pcad);
3877 /*-----------------------------------------------------------------*/
3878 /* pCodeLabelDestruct - free memory used by a label. */
3879 /*-----------------------------------------------------------------*/
3880 static void pCodeLabelDestruct(pCode *pc)
3886 // if((pc->type == PC_LABEL) && PCL(pc)->label)
3887 // Safe_free(PCL(pc)->label);
3889 /* Instead of deleting the memory used by this pCode, mark
3890 * the object as bad so that if there's a pointer to this pCode
3891 * dangling around somewhere then (hopefully) when the type is
3892 * checked we'll catch it.
3896 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3902 pCode *pic16_newpCodeLabel(char *name, int key)
3908 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3910 pcl->pc.type = PC_LABEL;
3911 pcl->pc.prev = pcl->pc.next = NULL;
3912 //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3915 // pcl->pc.analyze = genericAnalyze;
3916 pcl->pc.destruct = pCodeLabelDestruct;
3917 pcl->pc.print = pCodePrintLabel;
3924 sprintf(s,"_%05d_DS_",key);
3929 pcl->label = Safe_strdup(s);
3931 // if(pic16_pcode_verbose)
3932 // fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3935 return ( (pCode *)pcl);
3939 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3941 pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3945 return ( (pCode *)pcl );
3948 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3952 pci = Safe_calloc(1, sizeof(pCodeInfo));
3953 pci->pci.pc.type = PC_INFO;
3954 pci->pci.pc.prev = pci->pci.pc.next = NULL;
3955 pci->pci.pc.pb = NULL;
3956 pci->pci.label = NULL;
3958 pci->pci.pc.destruct = genericDestruct;
3959 pci->pci.pc.print = genericPrint;
3964 return ((pCode *)pci);
3968 /*-----------------------------------------------------------------*/
3969 /* newpBlock - create and return a pointer to a new pBlock */
3970 /*-----------------------------------------------------------------*/
3971 static pBlock *newpBlock(void)
3976 PpB = Safe_calloc(1,sizeof(pBlock) );
3977 PpB->next = PpB->prev = NULL;
3979 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3980 PpB->tregisters = NULL;
3982 PpB->FlowTree = NULL;
3988 /*-----------------------------------------------------------------*/
3989 /* pic16_newpCodeChain - create a new chain of pCodes */
3990 /*-----------------------------------------------------------------*
3992 * This function will create a new pBlock and the pointer to the
3993 * pCode that is passed in will be the first pCode in the block.
3994 *-----------------------------------------------------------------*/
3997 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
4000 pBlock *pB = newpBlock();
4002 pB->pcHead = pB->pcTail = pc;
4011 /*-----------------------------------------------------------------*/
4012 /* pic16_newpCodeOpLabel - Create a new label given the key */
4013 /* Note, a negative key means that the label is part of wild card */
4014 /* (and hence a wild card label) used in the pCodePeep */
4015 /* optimizations). */
4016 /*-----------------------------------------------------------------*/
4018 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4021 static int label_key=-1;
4025 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4026 pcop->type = PO_LABEL;
4031 sprintf(s=buffer,"_%05d_DS_",key);
4033 s = name, key = label_key--;
4036 pcop->name = Safe_strdup(s);
4038 ((pCodeOpLabel *)pcop)->key = key;
4040 //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4044 /*-----------------------------------------------------------------*/
4045 /*-----------------------------------------------------------------*/
4046 pCodeOp *pic16_newpCodeOpLit(int lit)
4052 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4053 pcop->type = PO_LITERAL;
4057 sprintf(s,"0x%02hhx", (unsigned char)lit);
4059 // sprintf(s, "%i", lit);
4062 pcop->name = Safe_strdup(s);
4064 ((pCodeOpLit *)pcop)->lit = lit;
4069 /*-----------------------------------------------------------------*/
4070 /*-----------------------------------------------------------------*/
4071 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4073 char *s = buffer, tbuf[256], *tb=tbuf;
4077 tb = pic16_get_op(arg2, NULL, 0);
4078 pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4079 pcop->type = PO_LITERAL;
4083 sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4085 pcop->name = Safe_strdup(s);
4088 ((pCodeOpLit2 *)pcop)->lit = lit;
4089 ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4094 /*-----------------------------------------------------------------*/
4095 /*-----------------------------------------------------------------*/
4096 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4100 pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4101 pcop->type = PO_IMMEDIATE;
4103 regs *r = pic16_dirregWithName(name);
4104 pcop->name = Safe_strdup(name);
4108 // fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4109 PCOI(pcop)->rIdx = r->rIdx;
4111 // fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4112 PCOI(pcop)->rIdx = -1;
4114 // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4119 PCOI(pcop)->index = index;
4120 PCOI(pcop)->offset = offset;
4121 PCOI(pcop)->_const = code_space;
4126 /*-----------------------------------------------------------------*/
4127 /*-----------------------------------------------------------------*/
4128 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4134 if(!pcwb || !subtype) {
4135 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4139 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4140 pcop->type = PO_WILD;
4141 sprintf(s,"%%%d",id);
4142 pcop->name = Safe_strdup(s);
4144 PCOW(pcop)->id = id;
4145 PCOW(pcop)->pcwb = pcwb;
4146 PCOW(pcop)->subtype = subtype;
4147 PCOW(pcop)->matched = NULL;
4149 PCOW(pcop)->pcop2 = NULL;
4154 /*-----------------------------------------------------------------*/
4155 /*-----------------------------------------------------------------*/
4156 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4162 if(!pcwb || !subtype || !subtype2) {
4163 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4167 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4168 pcop->type = PO_WILD;
4169 sprintf(s,"%%%d",id);
4170 pcop->name = Safe_strdup(s);
4172 PCOW(pcop)->id = id;
4173 PCOW(pcop)->pcwb = pcwb;
4174 PCOW(pcop)->subtype = subtype;
4175 PCOW(pcop)->matched = NULL;
4177 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4179 if(!subtype2->name) {
4180 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4181 PCOW2(pcop)->pcop.type = PO_WILD;
4182 sprintf(s, "%%%d", id2);
4183 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4184 PCOW2(pcop)->id = id2;
4185 PCOW2(pcop)->subtype = subtype2;
4187 // fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4188 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4190 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4192 // fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4193 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4202 /*-----------------------------------------------------------------*/
4203 /*-----------------------------------------------------------------*/
4204 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4208 pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4209 pcop->type = PO_GPR_BIT;
4211 pcop->name = Safe_strdup(s);
4215 PCORB(pcop)->bit = bit;
4216 PCORB(pcop)->inBitSpace = inBitSpace;
4217 PCORB(pcop)->subtype = subt;
4219 /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4220 PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4221 // fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4222 // PCOR(pcop)->rIdx = 0;
4227 /*-----------------------------------------------------------------*
4228 * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4230 * If rIdx >=0 then a specific register from the set of registers
4231 * will be selected. If rIdx <0, then a new register will be searched
4233 *-----------------------------------------------------------------*/
4235 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4239 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4244 PCOR(pcop)->rIdx = rIdx;
4245 PCOR(pcop)->r = pic16_regWithIdx(rIdx);
4247 PCOR(pcop)->r = pic16_findFreeReg(REG_GPR);
4250 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4252 fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4253 __FUNCTION__, __LINE__);
4258 pcop->type = PCOR(pcop)->r->pc_type;
4263 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4268 pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4271 r = pic16_findFreeReg(REG_GPR);
4274 if(!bitVectBitValue(bv, r->rIdx)) {
4276 PCOR(pcop)->rIdx = r->rIdx;
4277 pcop->type = r->pc_type;
4281 r = pic16_findFreeRegNext(REG_GPR, r);
4289 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4294 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4295 PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4296 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4297 pcop->type = PCOR(pcop)->r->pc_type;
4298 pcop->name = PCOR(pcop)->r->name;
4300 // if(pic16_pcode_verbose) {
4301 // fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4302 // __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4308 /*-----------------------------------------------------------------*/
4309 /*-----------------------------------------------------------------*/
4310 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4314 pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4317 pcop->key = Safe_strdup( key );
4319 return (PCOP(pcop));
4322 /*-----------------------------------------------------------------*/
4323 /*-----------------------------------------------------------------*/
4324 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4326 pCodeOpLocalReg *pcop;
4328 pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4332 return (PCOP(pcop));
4336 /*-----------------------------------------------------------------*/
4337 /*-----------------------------------------------------------------*/
4339 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4346 pcop = pic16_newpCodeOpBit(name, -1,0, type);
4350 pcop = pic16_newpCodeOpLit(-1);
4354 pcop = pic16_newpCodeOpLabel(NULL,-1);
4357 pcop = pic16_newpCodeOpReg(-1);
4360 case PO_GPR_REGISTER:
4362 pcop = pic16_newpCodeOpRegFromStr(name);
4364 pcop = pic16_newpCodeOpReg(-1);
4368 pcop = Safe_calloc(1,sizeof(pCodeOp) );
4371 pcop->name = Safe_strdup(name);
4379 #define DB_ITEMS_PER_LINE 8
4381 typedef struct DBdata
4388 static int DBd_init = -1;
4390 /*-----------------------------------------------------------------*/
4391 /* Initialiase "DB" data buffer */
4392 /*-----------------------------------------------------------------*/
4393 void pic16_initDB(void)
4399 /*-----------------------------------------------------------------*/
4400 /* Flush pending "DB" data to a pBlock */
4402 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4403 /*-----------------------------------------------------------------*/
4404 void pic16_flushDB(char ptype, void *p)
4408 pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4411 fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4414 fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4418 DBd.buffer[0] = '\0';
4423 /*-----------------------------------------------------------------*/
4424 /* Add "DB" directives to a pBlock */
4425 /*-----------------------------------------------------------------*/
4426 void pic16_emitDB(char c, char ptype, void *p)
4431 // we need to initialize
4434 DBd.buffer[0] = '\0';
4437 l = strlen(DBd.buffer);
4438 sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4440 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4443 if (DBd.count>= DB_ITEMS_PER_LINE)
4444 pic16_flushDB(ptype, p);
4447 void pic16_emitDS(char *s, char ptype, void *p)
4452 // we need to initialize
4455 DBd.buffer[0] = '\0';
4458 l = strlen(DBd.buffer);
4459 sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4461 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4463 DBd.count++; //=strlen(s);
4465 pic16_flushDB(ptype, p);
4469 /*-----------------------------------------------------------------*/
4470 /*-----------------------------------------------------------------*/
4471 void pic16_pCodeConstString(char *name, char *value)
4475 // fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value);
4480 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4482 pic16_addpBlock(pb);
4484 // sprintf(buffer,"; %s = ", name);
4485 // strcat(buffer, value);
4486 // fputs(buffer, stderr);
4488 // pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4489 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4492 pic16_emitDB(*value, 'p', (void *)pb);
4494 pic16_flushDB('p', (void *)pb);
4497 /*-----------------------------------------------------------------*/
4498 /*-----------------------------------------------------------------*/
4500 static void pCodeReadCodeTable(void)
4504 fprintf(stderr, " %s\n",__FUNCTION__);
4506 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4508 pic16_addpBlock(pb);
4510 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4511 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4512 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4513 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4515 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4516 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4517 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4518 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4523 /*-----------------------------------------------------------------*/
4524 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */
4525 /*-----------------------------------------------------------------*/
4526 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4533 /* If this is the first pcode to be added to a block that
4534 * was initialized with a NULL pcode, then go ahead and
4535 * make this pcode the head and tail */
4536 pb->pcHead = pb->pcTail = pc;
4539 pb->pcTail->next = pc;
4541 pc->prev = pb->pcTail;
4548 /*-----------------------------------------------------------------*/
4549 /* pic16_addpBlock - place a pBlock into the pFile */
4550 /*-----------------------------------------------------------------*/
4551 void pic16_addpBlock(pBlock *pb)
4553 // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4556 /* First time called, we'll pass through here. */
4557 //_ALLOC(the_pFile,sizeof(pFile));
4558 the_pFile = Safe_calloc(1,sizeof(pFile));
4559 the_pFile->pbHead = the_pFile->pbTail = pb;
4560 the_pFile->functions = NULL;
4564 the_pFile->pbTail->next = pb;
4565 pb->prev = the_pFile->pbTail;
4567 the_pFile->pbTail = pb;
4570 /*-----------------------------------------------------------------*/
4571 /* removepBlock - remove a pBlock from the pFile */
4572 /*-----------------------------------------------------------------*/
4573 static void removepBlock(pBlock *pb)
4581 //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4583 for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4586 if(pbs == the_pFile->pbHead)
4587 the_pFile->pbHead = pbs->next;
4589 if (pbs == the_pFile->pbTail)
4590 the_pFile->pbTail = pbs->prev;
4593 pbs->next->prev = pbs->prev;
4596 pbs->prev->next = pbs->next;
4603 fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4607 /*-----------------------------------------------------------------*/
4608 /* printpCode - write the contents of a pCode to a file */
4609 /*-----------------------------------------------------------------*/
4610 static void printpCode(FILE *of, pCode *pc)
4621 fprintf(of,"warning - unable to print pCode\n");
4624 /*-----------------------------------------------------------------*/
4625 /* pic16_printpBlock - write the contents of a pBlock to a file */
4626 /*-----------------------------------------------------------------*/
4627 void pic16_printpBlock(FILE *of, pBlock *pb)
4635 for(pc = pb->pcHead; pc; pc = pc->next) {
4636 if(isPCF(pc) && PCF(pc)->fname) {
4637 fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4638 if(pb->dbName == 'A') {
4640 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4641 // fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4642 if(!strcmp(ab->name, PCF(pc)->fname)) {
4643 // fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4644 if(ab->address != -1)
4645 fprintf(of, "\t0X%06X", ab->address);
4656 /*-----------------------------------------------------------------*/
4658 /* pCode processing */
4662 /*-----------------------------------------------------------------*/
4663 pCode * pic16_findNextInstruction(pCode *pci);
4664 pCode * pic16_findPrevInstruction(pCode *pci);
4666 void pic16_unlinkpCode(pCode *pc)
4672 fprintf(stderr,"Unlinking: ");
4673 printpCode(stderr, pc);
4676 pc->prev->next = pc->next;
4678 pc->next->prev = pc->prev;
4680 /* move C source line down (or up) */
4681 if (isPCI(pc) && PCI(pc)->cline) {
4682 prev = pic16_findNextInstruction (pc->next);
4683 if (prev && isPCI(prev) && !PCI(prev)->cline) {
4684 PCI(prev)->cline = PCI(pc)->cline;
4686 prev = pic16_findPrevInstruction (pc->prev);
4687 if (prev && isPCI(prev) && !PCI(prev)->cline)
4688 PCI(prev)->cline = PCI(pc)->cline;
4691 pc->prev = pc->next = NULL;
4695 /*-----------------------------------------------------------------*/
4696 /*-----------------------------------------------------------------*/
4698 static void genericDestruct(pCode *pc)
4701 pic16_unlinkpCode(pc);
4704 /* For instructions, tell the register (if there's one used)
4705 * that it's no longer needed */
4706 regs *reg = pic16_getRegFromInstruction(pc);
4708 deleteSetItem (&(reg->reglives.usedpCodes),pc);
4710 if(PCI(pc)->is2MemOp) {
4711 reg = pic16_getRegFromInstruction2(pc);
4713 deleteSetItem(&(reg->reglives.usedpCodes), pc);
4717 /* Instead of deleting the memory used by this pCode, mark
4718 * the object as bad so that if there's a pointer to this pCode
4719 * dangling around somewhere then (hopefully) when the type is
4720 * checked we'll catch it.
4724 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4730 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4731 /*-----------------------------------------------------------------*/
4732 /*-----------------------------------------------------------------*/
4733 /* modifiers for constant immediate */
4734 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4736 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4741 int use_buffer = 1; // copy the string to the passed buffer pointer
4746 use_buffer = 0; // Don't bother copying the string to the buffer.
4750 switch(pcop->type) {
4758 SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4761 return PCOR(pcop)->r->name;
4764 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4766 SAFE_snprintf(&buffer,&size,"%s",r->name);
4773 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4774 if(PCOI(pcop)->index) {
4775 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4776 immdmod[ PCOI(pcop)->offset ],
4780 SAFE_snprintf(&s,&size,"%s(%s)",
4781 immdmod[ PCOI(pcop)->offset ],
4785 if(PCOI(pcop)->index) {
4786 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4791 SAFE_snprintf(&s,&size, "%s(%s)",
4798 case PO_GPR_REGISTER:
4801 // size = sizeof(buffer);
4802 if( PCOR(pcop)->instance) {
4803 SAFE_snprintf(&s,&size,"(%s + %d)",
4805 PCOR(pcop)->instance );
4807 SAFE_snprintf(&s,&size,"%s",pcop->name);
4812 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4813 SAFE_snprintf(&s, &size, "%s", pcop->name);
4815 if(PCORB(pcop)->pcor.instance)
4816 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4818 SAFE_snprintf(&s, &size, "%s", pcop->name);
4825 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4834 return "NO operand1";
4837 /*-----------------------------------------------------------------*/
4838 /* pic16_get_op2 - variant to support two memory operand commands */
4839 /*-----------------------------------------------------------------*/
4840 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4845 int use_buffer = 1; // copy the string to the passed buffer pointer
4850 use_buffer = 0; // Don't bother copying the string to the buffer.
4854 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",
4855 __FUNCTION__, __LINE__, PCOR(PCOR2(pcop)->pcop2)->r->name, PCOR2(pcop)->pcop2->type,
4856 PO_DIR, PO_GPR_TEMP, PO_IMMEDIATE, PO_INDF0, PO_FSR0);
4860 switch(PCOR2(pcop)->pcop2->type) {
4868 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4871 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4874 r = pic16_regWithIdx(PCOR(PCOR2(pcop)->pcop2)->r->rIdx);
4877 SAFE_snprintf(&buffer,&size,"%s",r->name);
4888 if(PCOI(pcop)->_const) {
4889 if( PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4890 SAFE_snprintf(&s,&size,"(((%s+%d) >> %d)&0xff)",
4893 8 * PCOI(pcop)->offset );
4895 SAFE_snprintf(&s,&size,"LOW(%s+%d)",pcop->name,PCOI(pcop)->index);
4897 if( PCOI(pcop)->index) {
4898 SAFE_snprintf(&s,&size,"(%s + %d)",
4900 PCOI(pcop)->index );
4902 if(PCOI(pcop)->offset)
4903 SAFE_snprintf(&s,&size,"(%s >> %d)&0xff",pcop->name, 8*PCOI(pcop)->offset);
4905 SAFE_snprintf(&s,&size,"%s",pcop->name);
4912 if( PCOR(PCOR2(pcop)->pcop2)->instance) {
4913 SAFE_snprintf(&s,&size,"(%s + %d)",
4914 PCOR(PCOR2(pcop)->pcop2)->r->name,
4915 PCOR(PCOR2(pcop)->pcop2)->instance );
4917 SAFE_snprintf(&s,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4922 if(PCOR(PCOR2(pcop)->pcop2)->r->name) {
4924 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4927 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4932 return "NO operand2";
4935 /*-----------------------------------------------------------------*/
4936 /*-----------------------------------------------------------------*/
4937 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4941 return pic16_get_op(pcc->pcop,NULL,0);
4943 /* gcc 3.2: warning: concatenation of string literals with __FUNCTION__ is deprecated
4944 * return ("ERROR Null: "__FUNCTION__);
4946 return ("ERROR Null: pic16_get_op_from_instruction");
4950 /*-----------------------------------------------------------------*/
4951 /*-----------------------------------------------------------------*/
4952 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4955 fprintf(of,"pcodeopprint- not implemented\n");
4958 /*-----------------------------------------------------------------*/
4959 /* pic16_pCode2str - convert a pCode instruction to string */
4960 /*-----------------------------------------------------------------*/
4961 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4967 if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4968 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4969 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4977 SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4979 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4981 if(PCI(pc)->is2MemOp) {
4982 SAFE_snprintf(&s,&size, "%s, %s",
4983 pic16_get_op(PCOP(PCI(pc)->pcop), NULL, 0),
4984 pic16_get_op2(PCOP(PCI(pc)->pcop), NULL, 0));
4988 if(PCI(pc)->is2LitOp) {
4989 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4993 if(PCI(pc)->isBitInst) {
4994 if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4995 if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4996 SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)",
4997 PCI(pc)->pcop->name ,
4998 PCI(pc)->pcop->name );
5000 SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
5001 // (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
5002 (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
5004 } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5005 SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5007 SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5008 //PCI(pc)->pcop->t.bit );
5011 if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5012 if( PCI(pc)->num_ops == 3)
5013 SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5015 SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5020 SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5023 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5024 if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5025 SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5027 r = pic16_getRegFromInstruction(pc);
5028 // fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5029 // __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?r->accessBank:-1);
5031 if(r && !r->accessBank)SAFE_snprintf(&s,&size,", %s", (!pic16_mplab_comp?"B":"BANKED"));
5039 /* assuming that comment ends with a \n */
5040 SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5044 SAFE_snprintf(&s,&size,"; info ==>");
5045 switch( PCINF(pc)->type ) {
5046 case INF_OPTIMIZATION:
5047 SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5050 SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5055 /* assuming that inline code ends with a \n */
5056 SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5060 SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5063 SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5066 SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5069 SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5072 // SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5073 SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5074 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5077 if(PCAD(pc)->directive) {
5078 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5081 /* special case to handle inline labels without a tab */
5082 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5087 SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5095 /*-----------------------------------------------------------------*/
5096 /* genericPrint - the contents of a pCode to a file */
5097 /*-----------------------------------------------------------------*/
5098 static void genericPrint(FILE *of, pCode *pc)
5106 // fputs(((pCodeComment *)pc)->comment, of);
5107 fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5112 pBranch *pbl = PCI(pc)->label;
5113 while(pbl && pbl->pc) {
5114 if(pbl->pc->type == PC_LABEL)
5115 pCodePrintLabel(of, pbl->pc);
5120 if(pic16_pcode_verbose) {
5121 fprintf(of, "; info ==>");
5122 switch(((pCodeInfo *)pc)->type) {
5123 case INF_OPTIMIZATION:
5124 fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5127 fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5135 fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5139 // If the opcode has a label, print that first
5141 pBranch *pbl = PCI(pc)->label;
5142 while(pbl && pbl->pc) {
5143 if(pbl->pc->type == PC_LABEL)
5144 pCodePrintLabel(of, pbl->pc);
5150 genericPrint(of,PCODE(PCI(pc)->cline));
5155 pic16_pCode2str(str, 256, pc);
5157 fprintf(of,"%s",str);
5159 if(pic16_debug_verbose) {
5160 fprintf(of, "\t;key=%03x",pc->seq);
5162 fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5169 fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5170 if(PCW(pc)->pci.label)
5171 pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5173 if(PCW(pc)->operand) {
5174 fprintf(of,";\toperand ");
5175 pCodeOpPrint(of,PCW(pc)->operand );
5180 if(pic16_debug_verbose) {
5181 fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5182 if(PCFL(pc)->ancestor)
5183 fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5190 // fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5191 fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5192 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5198 pBranch *pbl = PCAD(pc)->pci.label;
5199 while(pbl && pbl->pc) {
5200 if(pbl->pc->type == PC_LABEL)
5201 pCodePrintLabel(of, pbl->pc);
5205 if(PCAD(pc)->directive) {
5206 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5209 /* special case to handle inline labels without tab */
5210 fprintf(of, "%s\n", PCAD(pc)->arg);
5216 fprintf(of,"unknown pCode type %d\n",pc->type);
5221 /*-----------------------------------------------------------------*/
5222 /* pCodePrintFunction - prints function begin/end */
5223 /*-----------------------------------------------------------------*/
5225 static void pCodePrintFunction(FILE *of, pCode *pc)
5232 if( ((pCodeFunction *)pc)->modname)
5233 fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5236 if(!PCF(pc)->absblock) {
5237 if(PCF(pc)->fname) {
5238 pBranch *exits = PCF(pc)->to;
5241 fprintf(of,"%s:", PCF(pc)->fname);
5243 if(pic16_pcode_verbose)
5244 fprintf(of, "\t;Function start");
5250 exits = exits->next;
5254 if(pic16_pcode_verbose)
5255 fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5258 if((PCF(pc)->from &&
5259 PCF(pc)->from->pc->type == PC_FUNCTION &&
5260 PCF(PCF(pc)->from->pc)->fname) ) {
5262 if(pic16_pcode_verbose)
5263 fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5265 if(pic16_pcode_verbose)
5266 fprintf(of,"; exit point [can't find entry point]\n");
5272 /*-----------------------------------------------------------------*/
5273 /* pCodePrintLabel - prints label */
5274 /*-----------------------------------------------------------------*/
5276 static void pCodePrintLabel(FILE *of, pCode *pc)
5283 fprintf(of,"%s:\n",PCL(pc)->label);
5284 else if (PCL(pc)->key >=0)
5285 fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5287 fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5290 /*-----------------------------------------------------------------*/
5291 /* unlinkpCodeFromBranch - Search for a label in a pBranch and */
5292 /* remove it if it is found. */
5293 /*-----------------------------------------------------------------*/
5294 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5301 if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5302 b = PCI(pcl)->label;
5304 fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5309 //fprintf (stderr, "%s \n",__FUNCTION__);
5310 //pcl->print(stderr,pcl);
5311 //pc->print(stderr,pc);
5314 //fprintf (stderr, "found label\n");
5315 //pc->print(stderr, pc);
5319 bprev->next = b->next; /* Not first pCode in chain */
5323 PCI(pcl)->label = b->next; /* First pCode in chain */
5326 return; /* A label can't occur more than once */
5334 /*-----------------------------------------------------------------*/
5335 /*-----------------------------------------------------------------*/
5336 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5355 /*-----------------------------------------------------------------*/
5356 /* pBranchLink - given two pcodes, this function will link them */
5357 /* together through their pBranches */
5358 /*-----------------------------------------------------------------*/
5359 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5363 // Declare a new branch object for the 'from' pCode.
5365 //_ALLOC(b,sizeof(pBranch));
5366 b = Safe_calloc(1,sizeof(pBranch));
5367 b->pc = PCODE(t); // The link to the 'to' pCode.
5370 f->to = pic16_pBranchAppend(f->to,b);
5372 // Now do the same for the 'to' pCode.
5374 //_ALLOC(b,sizeof(pBranch));
5375 b = Safe_calloc(1,sizeof(pBranch));
5379 t->from = pic16_pBranchAppend(t->from,b);
5384 /*-----------------------------------------------------------------*/
5385 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5387 /*-----------------------------------------------------------------*/
5388 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5401 /*-----------------------------------------------------------------*/
5402 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain. */
5403 /*-----------------------------------------------------------------*/
5404 void pic16_pCodeUnlink(pCode *pc)
5409 if(!pc->prev || !pc->next) {
5410 fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5414 /* move C source line down (or up) */
5415 if (isPCI(pc) && PCI(pc)->cline) {
5416 pc1 = pic16_findNextInstruction (pc->next);
5417 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5418 PCI(pc1)->cline = PCI(pc)->cline;
5420 pc1 = pic16_findPrevInstruction (pc->prev);
5421 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5422 PCI(pc1)->cline = PCI(pc)->cline;
5426 /* first remove the pCode from the chain */
5427 pc->prev->next = pc->next;
5428 pc->next->prev = pc->prev;
5430 pc->prev = pc->next = NULL;
5432 /* Now for the hard part... */
5434 /* Remove the branches */
5436 pb1 = PCI(pc)->from;
5438 pc1 = pb1->pc; /* Get the pCode that branches to the
5439 * one we're unlinking */
5441 /* search for the link back to this pCode (the one we're
5443 if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5444 pb2->pc = PCI(pc)->to->pc; // make the replacement
5446 /* if the pCode we're unlinking contains multiple 'to'
5447 * branches (e.g. this a skip instruction) then we need
5448 * to copy these extra branches to the chain. */
5449 if(PCI(pc)->to->next)
5450 pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5459 /*-----------------------------------------------------------------*/
5460 /*-----------------------------------------------------------------*/
5462 static void genericAnalyze(pCode *pc)
5472 // Go through the pCodes that are in pCode chain and link
5473 // them together through the pBranches. Note, the pCodes
5474 // are linked together as a contiguous stream like the
5475 // assembly source code lines. The linking here mimics this
5476 // except that comments are not linked in.
5478 pCode *npc = pc->next;
5480 if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5481 pBranchLink(pc,npc);
5486 /* reached the end of the pcode chain without finding
5487 * an instruction we could link to. */
5491 fprintf(stderr,"analyze PC_FLOW\n");
5495 fprintf(stderr,,";A bad pCode is being used\n");
5501 /*-----------------------------------------------------------------*/
5502 /*-----------------------------------------------------------------*/
5503 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5507 if(pc->type == PC_LABEL) {
5508 if( ((pCodeLabel *)pc)->key == pcop_label->key)
5511 if((pc->type == PC_OPCODE)
5512 || (pc->type == PC_ASMDIR)
5514 pbr = PCI(pc)->label;
5516 if(pbr->pc->type == PC_LABEL) {
5517 if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
5527 /*-----------------------------------------------------------------*/
5528 /*-----------------------------------------------------------------*/
5529 static int checkLabel(pCode *pc)
5533 if(pc && isPCI(pc)) {
5534 pbr = PCI(pc)->label;
5536 if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5546 /*-----------------------------------------------------------------*/
5547 /* findLabelinpBlock - Search the pCode for a particular label */
5548 /*-----------------------------------------------------------------*/
5549 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5556 for(pc = pb->pcHead; pc; pc = pc->next)
5557 if(compareLabel(pc,pcop_label))
5563 /*-----------------------------------------------------------------*/
5564 /* findLabel - Search the pCode for a particular label */
5565 /*-----------------------------------------------------------------*/
5566 static pCode * findLabel(pCodeOpLabel *pcop_label)
5574 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5575 if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5579 fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5583 /*-----------------------------------------------------------------*/
5584 /* pic16_findNextpCode - given a pCode, find the next of type 'pct' */
5585 /* in the linked list */
5586 /*-----------------------------------------------------------------*/
5587 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5600 /*-----------------------------------------------------------------*/
5601 /* findPrevpCode - given a pCode, find the previous of type 'pct' */
5602 /* in the linked list */
5603 /*-----------------------------------------------------------------*/
5604 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5618 //#define PCODE_DEBUG
5619 /*-----------------------------------------------------------------*/
5620 /* pic16_findNextInstruction - given a pCode, find the next instruction */
5621 /* in the linked list */
5622 /*-----------------------------------------------------------------*/
5623 pCode * pic16_findNextInstruction(pCode *pci)
5628 if((pc->type == PC_OPCODE)
5629 || (pc->type == PC_WILD)
5630 || (pc->type == PC_ASMDIR)
5635 fprintf(stderr,"pic16_findNextInstruction: ");
5636 printpCode(stderr, pc);
5641 //fprintf(stderr,"Couldn't find instruction\n");
5645 /*-----------------------------------------------------------------*/
5646 /* pic16_findPrevInstruction - given a pCode, find the next instruction */
5647 /* in the linked list */
5648 /*-----------------------------------------------------------------*/
5649 pCode * pic16_findPrevInstruction(pCode *pci)
5655 if((pc->type == PC_OPCODE)
5656 || (pc->type == PC_WILD)
5657 || (pc->type == PC_ASMDIR)
5663 fprintf(stderr,"pic16_findPrevInstruction: ");
5664 printpCode(stderr, pc);
5669 //fprintf(stderr,"Couldn't find instruction\n");
5676 /*-----------------------------------------------------------------*/
5677 /* findFunctionEnd - given a pCode find the end of the function */
5678 /* that contains it */
5679 /*-----------------------------------------------------------------*/
5680 static pCode * findFunctionEnd(pCode *pc)
5684 if(pc->type == PC_FUNCTION && !(PCF(pc)->fname))
5690 fprintf(stderr,"Couldn't find function end\n");
5695 /*-----------------------------------------------------------------*/
5696 /* AnalyzeLabel - if the pCode is a label, then merge it with the */
5697 /* instruction with which it is associated. */
5698 /*-----------------------------------------------------------------*/
5699 static void AnalyzeLabel(pCode *pc)
5702 pic16_pCodeUnlink(pc);
5708 static void AnalyzeGOTO(pCode *pc)
5711 pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5715 static void AnalyzeSKIP(pCode *pc)
5718 pBranchLink(pc,pic16_findNextInstruction(pc->next));
5719 pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5723 static void AnalyzeRETURN(pCode *pc)
5726 // branch_link(pc,findFunctionEnd(pc->next));
5732 /*-------------------------------------------------------------------*/
5733 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp */
5734 /* if one is present. This is the common */
5735 /* part of pic16_getRegFromInstruction(2) */
5736 /*-------------------------------------------------------------------*/
5738 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5739 if (!pcop) return NULL;
5741 switch(pcop->type) {
5754 return PCOR(pcop)->r;
5756 case PO_SFR_REGISTER:
5757 //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5758 return PCOR(pcop)->r;
5762 // fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5763 return PCOR(pcop)->r;
5766 // return pic16_dirregWithName(PCOI(pcop)->r->name);
5769 return (PCOI(pcop)->r);
5774 return PCOR(pcop)->r;
5776 case PO_GPR_REGISTER:
5778 // fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5779 return PCOR(pcop)->r;
5782 //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5787 //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5792 /* this should never turn up */
5793 //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5800 fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5808 /*-----------------------------------------------------------------*/
5809 /*-----------------------------------------------------------------*/
5810 regs * pic16_getRegFromInstruction(pCode *pc)
5816 PCI(pc)->num_ops == 0 ||
5817 (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5821 fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5822 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5825 return pic16_getRegFrompCodeOp (PCI(pc)->pcop);
5828 /*-------------------------------------------------------------------------------*/
5829 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5830 /*-------------------------------------------------------------------------------*/
5831 regs * pic16_getRegFromInstruction2(pCode *pc)
5837 PCI(pc)->num_ops == 0 ||
5838 (PCI(pc)->num_ops == 1)) // accept only 2 operand commands
5843 fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5844 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5847 return pic16_getRegFrompCodeOp (PCOR2(PCI(pc)->pcop)->pcop2);
5850 /*-----------------------------------------------------------------*/
5851 /*-----------------------------------------------------------------*/
5853 static void AnalyzepBlock(pBlock *pb)
5860 /* Find all of the registers used in this pBlock
5861 * by looking at each instruction and examining it's
5864 for(pc = pb->pcHead; pc; pc = pc->next) {
5866 /* Is this an instruction with operands? */
5867 if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5869 if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5871 /* Loop through all of the registers declared so far in
5872 this block and see if we find this one there */
5874 regs *r = setFirstItem(pb->tregisters);
5877 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5878 PCOR(PCI(pc)->pcop)->r = r;
5881 r = setNextItem(pb->tregisters);
5885 /* register wasn't found */
5886 //r = Safe_calloc(1, sizeof(regs));
5887 //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5888 //addSet(&pb->tregisters, r);
5889 addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5890 //PCOR(PCI(pc)->pcop)->r = r;
5891 //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5893 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5896 if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5897 if(PCOR(PCI(pc)->pcop)->r) {
5898 pic16_allocWithIdx (PCOR(PCI(pc)->pcop)->r->rIdx);
5899 DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5901 if(PCI(pc)->pcop->name)
5902 fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5904 fprintf(stderr,"ERROR: NULL register\n");
5913 /*-----------------------------------------------------------------*/
5915 /*-----------------------------------------------------------------*/
5916 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5918 static void InsertpFlow(pCode *pc, pCode **pflow)
5921 PCFL(*pflow)->end = pc;
5923 if(!pc || !pc->next)
5926 *pflow = pic16_newpCodeFlow();
5927 pic16_pCodeInsertAfter(pc, *pflow);
5930 /*-----------------------------------------------------------------*/
5931 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5932 /* the flow blocks. */
5934 * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5935 * point the instruction flow changes.
5937 /*-----------------------------------------------------------------*/
5938 void pic16_BuildFlow(pBlock *pb)
5941 pCode *last_pci=NULL;
5948 //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq);
5949 /* Insert a pCodeFlow object at the beginning of a pBlock */
5951 InsertpFlow(pb->pcHead, &pflow);
5953 //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */
5954 //pflow->next = pb->pcHead; /* Make the current head the next object */
5955 //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */
5956 //pb->pcHead = pflow; /* Make the Flow object the head */
5959 for( pc = pic16_findNextInstruction(pb->pcHead);
5961 pc=pic16_findNextInstruction(pc)) {
5964 PCI(pc)->pcflow = PCFL(pflow);
5966 //fprintf(stderr," build: ");
5967 //pflow->print(stderr,pflow);
5969 if (checkLabel(pc)) {
5971 /* This instruction marks the beginning of a
5972 * new flow segment */
5977 /* If the previous pCode is not a flow object, then
5978 * insert a new flow object. (This check prevents
5979 * two consecutive flow objects from being insert in
5980 * the case where a skip instruction preceeds an
5981 * instruction containing a label.) */
5983 if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5984 InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5986 PCI(pc)->pcflow = PCFL(pflow);
5990 if( PCI(pc)->isSkip) {
5992 /* The two instructions immediately following this one
5993 * mark the beginning of a new flow segment */
5995 while(pc && PCI(pc)->isSkip) {
5997 PCI(pc)->pcflow = PCFL(pflow);
6001 InsertpFlow(pc, &pflow);
6002 pc=pic16_findNextInstruction(pc->next);
6010 PCI(pc)->pcflow = PCFL(pflow);
6012 InsertpFlow(pc, &pflow);
6014 } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) {
6016 InsertpFlow(pc, &pflow);
6024 //fprintf (stderr,",end seq %d",GpcFlowSeq);
6026 PCFL(pflow)->end = pb->pcTail;
6029 /*-------------------------------------------------------------------*/
6030 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */
6031 /* the flow blocks. */
6033 * unBuildFlow removes pCodeFlow objects from a pCode chain
6035 /*-----------------------------------------------------------------*/
6036 static void unBuildFlow(pBlock *pb)
6051 if(PCI(pc)->pcflow) {
6052 //Safe_free(PCI(pc)->pcflow);
6053 PCI(pc)->pcflow = NULL;
6056 } else if(isPCFL(pc) )
6065 /*-----------------------------------------------------------------*/
6066 /*-----------------------------------------------------------------*/
6067 static void dumpCond(int cond)
6070 static char *pcc_str[] = {
6084 int ncond = sizeof(pcc_str) / sizeof(char *);
6087 fprintf(stderr, "0x%04X\n",cond);
6089 for(i=0,j=1; i<ncond; i++, j<<=1)
6091 fprintf(stderr, " %s\n",pcc_str[i]);
6097 /*-----------------------------------------------------------------*/
6098 /*-----------------------------------------------------------------*/
6099 static void FlowStats(pCodeFlow *pcflow)
6107 fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6109 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6112 fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6117 fprintf(stderr, " FlowStats inCond: ");
6118 dumpCond(pcflow->inCond);
6119 fprintf(stderr, " FlowStats outCond: ");
6120 dumpCond(pcflow->outCond);
6124 /*-----------------------------------------------------------------*
6125 * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6126 * if it affects the banking bits.
6128 * return: -1 == Banking bits are unaffected by this pCode.
6130 * return: > 0 == Banking bits are affected.
6132 * If the banking bits are affected, then the returned value describes
6133 * which bits are affected and how they're affected. The lower half
6134 * of the integer maps to the bits that are affected, the upper half
6135 * to whether they're set or cleared.
6137 *-----------------------------------------------------------------*/
6139 static int isBankInstruction(pCode *pc)
6147 if( PCI(pc)->op == POC_MOVLB ||
6148 (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6149 bank = PCOL(pc)->lit;
6156 /*-----------------------------------------------------------------*/
6157 /*-----------------------------------------------------------------*/
6158 static void FillFlow(pCodeFlow *pcflow)
6167 // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6169 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6172 //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6179 isBankInstruction(pc);
6181 } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6185 fprintf(stderr, " FillFlow - Bad end of flow\n");
6187 fprintf(stderr, " FillFlow - Ending flow with\n ");
6188 pc->print(stderr,pc);
6191 fprintf(stderr, " FillFlow inCond: ");
6192 dumpCond(pcflow->inCond);
6193 fprintf(stderr, " FillFlow outCond: ");
6194 dumpCond(pcflow->outCond);
6198 /*-----------------------------------------------------------------*/
6199 /*-----------------------------------------------------------------*/
6200 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6202 pCodeFlowLink *fromLink, *toLink;
6204 if(!from || !to || !to->pcflow || !from->pcflow)
6207 fromLink = pic16_newpCodeFlowLink(from->pcflow);
6208 toLink = pic16_newpCodeFlowLink(to->pcflow);
6210 addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
6211 addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6215 pCode *pic16_getJumptabpCode (pCode *pc) {
6218 //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6219 //pc->print (stderr, pc);
6222 if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6223 if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6224 switch (PCOO(PCINF(pcinf)->oper1)->type) {
6225 case OPT_JUMPTABLE_BEGIN:
6226 /* leading begin of jump table -- in one */
6227 pcinf = pic16_findPrevInstruction (pcinf);
6231 case OPT_JUMPTABLE_END:
6232 /* leading end of jumptable -- not in one */
6237 /* ignore all other PCInfos */
6241 pcinf = pcinf->prev;
6244 /* no PCInfo found -- not in a jumptable */
6248 /*-----------------------------------------------------------------*
6249 * void LinkFlow(pBlock *pb)
6251 * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6252 * non-branching segments. In LinkFlow, we determine the execution
6253 * order of these segments. For example, if one of the segments ends
6254 * with a skip, then we know that there are two possible flow segments
6255 * to which control may be passed.
6256 *-----------------------------------------------------------------*/
6257 static void LinkFlow(pBlock *pb)
6262 pCode *jumptab_pre = NULL;
6264 //fprintf(stderr,"linkflow \n");
6266 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6268 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6271 fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6273 //fprintf(stderr," link: ");
6274 //pcflow->print(stderr,pcflow);
6276 //FillFlow(PCFL(pcflow));
6278 pc = PCFL(pcflow)->end;
6280 //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6281 if(isPCI_SKIP(pc)) {
6282 // fprintf(stderr, "ends with skip\n");
6283 // pc->print(stderr,pc);
6285 pct=pic16_findNextInstruction(pc->next);
6286 LinkFlow_pCode(PCI(pc),PCI(pct));
6287 pct=pic16_findNextInstruction(pct->next);
6288 LinkFlow_pCode(PCI(pc),PCI(pct));
6292 if(isPCI_BRANCH(pc)) {
6293 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6295 /* handle GOTOs in jumptables */
6296 if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6297 /* link to previous flow */
6298 //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6299 LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6302 switch (PCI(pc)->op) {
6308 /* unconditional branches -- do not link to next instruction */
6309 //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6314 /* unconditional calls -- link to next instruction */
6315 //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6316 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6327 /* conditional branches -- also link to next instruction */
6328 //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6329 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6333 fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6334 assert (0 && "unhandled branching instruction");
6338 //fprintf(stderr, "ends with branch\n ");
6339 //pc->print(stderr,pc);
6341 if(!(pcol && isPCOLAB(pcol))) {
6342 if((PCI(pc)->op != POC_RETLW)
6343 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6345 /* continue if label is '$' which assembler knows how to parse */
6346 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6348 if(pic16_pcode_verbose) {
6349 pc->print(stderr,pc);
6350 fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6356 if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6357 LinkFlow_pCode(PCI(pc),PCI(pct));
6359 fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6360 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6362 // fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6368 //fprintf(stderr, "ends with non-branching instruction:\n");
6369 //pc->print(stderr,pc);
6371 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6377 //fprintf(stderr, "ends with unknown\n");
6378 //pc->print(stderr,pc);
6382 //fprintf(stderr, "ends with nothing: ERROR\n");
6386 /*-----------------------------------------------------------------*/
6387 /*-----------------------------------------------------------------*/
6389 /*-----------------------------------------------------------------*/
6390 /*-----------------------------------------------------------------*/
6391 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6397 if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6400 if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6410 /*-----------------------------------------------------------------*/
6411 /* insertBankSwitch - inserts a bank switch statement in the */
6412 /* assembly listing */
6414 /* position == 0: insert before */
6415 /* position == 1: insert after pc */
6416 /* position == 2: like 0 but previous was a skip instruction */
6417 /*-----------------------------------------------------------------*/
6418 pCodeOp *pic16_popGetLabel(unsigned int key);
6419 extern int pic16_labelOffset;
6421 static void insertBankSwitch(unsigned char position, pCode *pc)
6428 /* emit BANKSEL [symbol] */
6431 new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6433 // position = 0; // position is always before (sanity check!)
6436 fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6437 pc->print(stderr, pc);
6442 /* insert the bank switch after this pc instruction */
6443 pCode *pcnext = pic16_findNextInstruction(pc);
6445 pic16_pCodeInsertAfter(pc, new_pc);
6446 if(pcnext)pc = pcnext;
6450 /* insert the bank switch BEFORE this pc instruction */
6451 pic16_pCodeInsertAfter(pc->prev, new_pc);
6456 pCode *pcnext, *pcprev, *npci, *ppc;
6458 int ofs1=0, ofs2=0, len=0;
6460 /* just like 0, but previous was a skip instruction,
6461 * so some care should be taken */
6463 pic16_labelOffset += 10000;
6464 tlbl = newiTempLabel(NULL);
6466 /* invert skip instruction */
6467 pcprev = pic16_findPrevInstruction(pc->prev);
6468 ipci = PCI(pcprev)->inverted_op;
6469 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6471 // fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6473 /* copy info from old pCode */
6474 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6475 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6476 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6477 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6478 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6479 PCI(npci)->op = PCI(pcprev)->inverted_op;
6481 /* unlink old pCode */
6483 ppc->next = pcprev->next;
6484 pcprev->next->prev = ppc;
6485 pic16_pCodeInsertAfter(ppc, npci);
6487 /* extra instructions to handle invertion */
6488 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6489 pic16_pCodeInsertAfter(npci, pcnext);
6490 pic16_pCodeInsertAfter(pc->prev, new_pc);
6492 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6493 pic16_pCodeInsertAfter(pc, pcnext);
6498 /* Move the label, if there is one */
6499 if(PCI(pc)->label) {
6500 // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6501 // __FILE__, __LINE__, pc, new_pc);
6502 PCAD(new_pc)->pci.label = PCI(pc)->label;
6503 PCI(pc)->label = NULL;
6508 /*-----------------------------------------------------------------*/
6509 /*int compareBankFlow - compare the banking requirements between */
6511 /*-----------------------------------------------------------------*/
6512 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6515 if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6518 if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6521 if(pcflow->firstBank == -1)
6525 if(pcflowLink->pcflow->firstBank == -1) {
6526 pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6527 pcflowLink->pcflow->to :
6528 pcflowLink->pcflow->from);
6529 return compareBankFlow(pcflow, pctl, toORfrom);
6533 if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6536 pcflowLink->bank_conflict++;
6537 pcflowLink->pcflow->FromConflicts++;
6538 pcflow->ToConflicts++;
6541 if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6544 pcflowLink->bank_conflict++;
6545 pcflowLink->pcflow->ToConflicts++;
6546 pcflow->FromConflicts++;
6550 fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6551 pcflowLink->pcflow->pc.seq,
6552 pcflowLink->pcflow->FromConflicts,
6553 pcflowLink->pcflow->ToConflicts);
6560 /*-----------------------------------------------------------------*/
6561 /*-----------------------------------------------------------------*/
6562 static void DumpFlow(pBlock *pb)
6566 pCodeFlowLink *pcfl;
6569 fprintf(stderr,"Dump flow \n");
6570 pb->pcHead->print(stderr, pb->pcHead);
6572 pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6573 pcflow->print(stderr,pcflow);
6575 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6577 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6579 if(!isPCFL(pcflow)) {
6580 fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6583 fprintf(stderr,"dumping: ");
6584 pcflow->print(stderr,pcflow);
6585 FlowStats(PCFL(pcflow));
6587 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6589 pc = PCODE(pcfl->pcflow);
6591 fprintf(stderr, " from seq %d:\n",pc->seq);
6593 fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6594 pc->print(stderr,pc);
6599 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6601 pc = PCODE(pcfl->pcflow);
6603 fprintf(stderr, " to seq %d:\n",pc->seq);
6605 fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6606 pc->print(stderr,pc);
6615 /*-----------------------------------------------------------------*/
6616 /*-----------------------------------------------------------------*/
6617 static int OptimizepBlock(pBlock *pb)
6622 if(!pb || !peepOptimizing)
6625 DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6627 for(pc = pb->pcHead; pc; pc = pc->next)
6628 matches += pic16_pCodePeepMatchRule(pc);
6631 pc = pic16_findNextInstruction(pb->pcHead);
6639 if(pic16_pCodePeepMatchRule(pc)) {
6644 pc = pic16_findNextInstruction(pcprev->next);
6646 pc = pic16_findNextInstruction(pb->pcHead);
6648 pc = pic16_findNextInstruction(pc->next);
6652 DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6657 /*-----------------------------------------------------------------*/
6658 /*-----------------------------------------------------------------*/
6659 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6663 for(pc = pcs; pc; pc = pc->next) {
6665 if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6667 (PCI(pc)->pcop->type == PO_LABEL) &&
6668 (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6676 /*-----------------------------------------------------------------*/
6677 /*-----------------------------------------------------------------*/
6678 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6685 (PCI(pc)->pcop->type == PO_LABEL)) {
6687 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6689 // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6690 // if(pcol->pcop.name)
6691 // Safe_free(pcol->pcop.name);
6693 /* If the key is negative, then we (probably) have a label to
6694 * a function and the name is already defined */
6697 sprintf(s=buffer,"_%05d_DS_",pcl->key);
6701 //sprintf(buffer,"_%05d_DS_",pcl->key);
6703 fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6705 pcol->pcop.name = Safe_strdup(s);
6706 pcol->key = pcl->key;
6707 //pc->print(stderr,pc);
6714 /*-----------------------------------------------------------------*/
6715 /* pBlockRemoveUnusedLabels - remove the pCode labels from the */
6716 /* pCode chain if they're not used. */
6717 /*-----------------------------------------------------------------*/
6718 static void pBlockRemoveUnusedLabels(pBlock *pb)
6720 pCode *pc; pCodeLabel *pcl;
6725 for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6727 pBranch *pbr = PCI(pc)->label;
6728 if(pbr && pbr->next) {
6729 pCode *pcd = pb->pcHead;
6731 // fprintf(stderr, "multiple labels\n");
6732 // pc->print(stderr,pc);
6737 while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6738 //fprintf(stderr,"Used by:\n");
6739 //pcd->print(stderr,pcd);
6741 exchangeLabels(PCL(pbr->pc),pcd);
6750 for(pc = pb->pcHead; pc; pc = pc->next) {
6752 if(isPCL(pc)) // pc->type == PC_LABEL)
6754 else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6755 pcl = PCL(PCI(pc)->label->pc);
6758 // fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6760 /* This pCode is a label, so search the pBlock to see if anyone
6763 if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6765 //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6766 /* Couldn't find an instruction that refers to this label
6767 * So, unlink the pCode label from it's pCode chain
6768 * and destroy the label */
6769 // fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6771 DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6772 if(pc->type == PC_LABEL) {
6773 pic16_unlinkpCode(pc);
6774 pCodeLabelDestruct(pc);
6776 unlinkpCodeFromBranch(pc, PCODE(pcl));
6777 /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6778 Safe_free(pc->label);
6788 /*-----------------------------------------------------------------*/
6789 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */
6790 /* chain and put them into pBranches that are */
6791 /* associated with the appropriate pCode */
6793 /*-----------------------------------------------------------------*/
6794 void pic16_pBlockMergeLabels(pBlock *pb)
6797 pCode *pc, *pcnext=NULL;
6802 /* First, Try to remove any unused labels */
6803 //pBlockRemoveUnusedLabels(pb);
6805 /* Now loop through the pBlock and merge the labels with the opcodes */
6808 // for(pc = pb->pcHead; pc; pc = pc->next) {
6811 pCode *pcn = pc->next;
6813 if(pc->type == PC_LABEL) {
6815 // fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6816 // fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6818 if((pcnext = pic16_findNextInstruction(pc) )) {
6820 // pcnext->print(stderr, pcnext);
6822 // Unlink the pCode label from it's pCode chain
6823 pic16_unlinkpCode(pc);
6825 // fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6826 // And link it into the instruction's pBranch labels. (Note, since
6827 // it's possible to have multiple labels associated with one instruction
6828 // we must provide a means to accomodate the additional labels. Thus
6829 // the labels are placed into the singly-linked list "label" as
6830 // opposed to being a single member of the pCodeInstruction.)
6832 //_ALLOC(pbr,sizeof(pBranch));
6834 pbr = Safe_calloc(1,sizeof(pBranch));
6838 PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6841 if(pic16_pcode_verbose)
6842 fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6844 } else if(pc->type == PC_CSOURCE) {
6846 /* merge the source line symbolic info into the next instruction */
6847 if((pcnext = pic16_findNextInstruction(pc) )) {
6849 // Unlink the pCode label from it's pCode chain
6850 pic16_unlinkpCode(pc);
6851 PCI(pcnext)->cline = PCCS(pc);
6852 //fprintf(stderr, "merging CSRC\n");
6853 //genericPrint(stderr,pcnext);
6859 pBlockRemoveUnusedLabels(pb);
6863 /*-----------------------------------------------------------------*/
6864 /*-----------------------------------------------------------------*/
6865 static int OptimizepCode(char dbName)
6867 #define MAX_PASSES 4
6876 DFPRINTF((stderr," Optimizing pCode\n"));
6880 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6881 if('*' == dbName || getpBlock_dbName(pb) == dbName)
6882 matches += OptimizepBlock(pb);
6885 while(matches && ++passes < MAX_PASSES);
6892 const char *pic16_pCodeOpType(pCodeOp *pcop);
6893 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6896 /*-----------------------------------------------------------------*/
6897 /* pic16_popCopyGPR2Bit - copy a pcode operator */
6898 /*-----------------------------------------------------------------*/
6900 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6904 // fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6907 pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6909 if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6912 assert(pcop != NULL);
6914 if( !( (pcop->type == PO_LABEL) ||
6915 (pcop->type == PO_LITERAL) ||
6916 (pcop->type == PO_STR) ))
6917 PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */
6918 PCOR(pcop)->r->wasUsed = 1;
6919 PCOR(pcop)->instance = PCOR(pc)->instance;
6925 /*----------------------------------------------------------------------*
6926 * pic16_areRegsSame - check to see if the names of two registers match *
6927 *----------------------------------------------------------------------*/
6928 int pic16_areRegsSame(regs *r1, regs *r2)
6930 if(!strcmp(r1->name, r2->name))return 1;
6936 /*-----------------------------------------------------------------*/
6937 /*-----------------------------------------------------------------*/
6938 static void pic16_FixRegisterBanking(pBlock *pb)
6942 regs *reg, *prevreg;
6943 unsigned char flag=0;
6948 pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6951 /* loop through all of the flow blocks with in one pblock */
6953 // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6957 /* at this point, pc should point to a PC_FLOW object */
6958 /* for each flow block, determine the register banking
6962 /* if label, then might come from other point, force banksel */
6963 if(isPCL(pc))prevreg = NULL;
6965 if(!isPCI(pc))goto loop;
6967 if(PCI(pc)->label)prevreg = NULL;
6969 if(PCI(pc)->is2MemOp)goto loop;
6971 /* if goto, then force banksel */
6972 // if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6974 reg = pic16_getRegFromInstruction(pc);
6977 pc->print(stderr, pc);
6978 fprintf(stderr, "reg = %p\n", reg);
6981 fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6982 fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6983 reg->address,reg->isBitField, reg->isFixed);
6987 /* now make some tests to make sure that instruction needs bank switch */
6989 /* if no register exists, and if not a bit opcode goto loop */
6991 if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6994 if(isPCI_SKIP(pc)) {
6995 // fprintf(stderr, "instruction is SKIP instruction\n");
6998 if(reg && isACCESS_BANK(reg))goto loop;
7000 if(!isBankInstruction(pc))goto loop;
7002 if(isPCI_LIT(pc))goto loop;
7004 if(PCI(pc)->op == POC_CALL)goto loop;
7006 /* Examine the instruction before this one to make sure it is
7007 * not a skip type instruction */
7008 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7010 flag = 0; /* add before this instruction */
7012 /* if previous instruction is a skip one, then set flag
7013 * to 2 and call insertBankSwitch */
7014 if(pcprev && isPCI_SKIP(pcprev)) {
7019 if(pic16_options.opt_banksel>0) {
7020 char op1[128], op2[128];
7023 strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7024 strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7025 if(!strcmp(op1, op2))goto loop;
7029 insertBankSwitch(flag, pc);
7031 // fprintf(stderr, "BANK SWITCH inserted\n");
7039 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7041 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7042 int instrSize (pCode *pc)
7047 if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7048 return 4; // assumes only regular instructions using <= 4 bytes
7051 if (isPCI(pc)) return PCI(pc)->isize;
7056 /* Returns 1 if pc is referenced by the given label (either
7057 * pc is the label itself or is an instruction with an attached
7059 * Returns 0 if pc is not preceeded by the specified label.
7061 int isLabel (pCode *pc, char *label)
7065 // label attached to the pCode?
7066 if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7067 pBranch *lab = NULL;
7068 lab = PCI(pc)->label;
7071 if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7078 // is inline assembly label?
7079 if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7080 // do not compare trailing ':'
7081 if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7088 if (strcmp(PCL(pc)->label,label) == 0) {
7093 // no label/no label attached/wrong label(s)
7097 /* Returns the distance to the given label in terms of words.
7098 * Labels are searched only within -max .. max words from pc.
7099 * Returns max if the label could not be found or
7100 * its distance from pc in (-max..+max).
7102 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7103 int dist = instrSize(pc);
7107 while (dist < max && curr && !isLabel (curr, label)) {
7109 dist += instrSize(curr); // sizeof (instruction)
7111 if (curr && dist < max) {
7112 if (target != NULL) *target = curr;
7117 curr = pic16_findNextInstruction (pc->next);
7119 while (dist < max && curr && !isLabel (curr, label)) {
7120 dist += instrSize(curr); // sizeof (instruction)
7123 if (curr && dist < max) {
7124 if (target != NULL) *target = curr;
7128 if (target != NULL) *target = NULL;
7132 /* Returns -1 if pc does NOT denote an instruction like
7134 * Otherwise we return
7135 * (a) 0x10 + i for BTFSS
7136 * (b) 0x00 + i for BTFSC
7138 int isSkipOnStatus (pCode *pc)
7142 if (!pc || !isPCI(pc)) return -1;
7143 if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7144 else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7147 pcop = PCI(pc)->pcop;
7149 if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7150 return res + ((pCodeOpRegBit *)pcop)->bit;
7156 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7157 * returns 0 otherwise. */
7158 int isConditionalBranch (pCode *pc)
7160 if (!pc || !isPCI_BRANCH(pc)) return 0;
7162 switch (PCI(pc)->op) {
7180 /* Returns 1 if pc has a label attached to it.
7181 * This can be either a label stored in the pCode itself (.label)
7182 * or a label making up its own pCode preceding this pc.
7183 * Returns 0 if pc cannot be reached directly via a label.
7185 int hasNoLabel (pCode *pc)
7190 // are there any label pCodes between pc and the previous instruction?
7191 prev = pic16_findPrevInstruction (pc->prev);
7192 while (pc && pc != prev) {
7193 // pCode with attached label?
7194 if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7195 && PCI(pc)->label) {
7198 // is inline assembly label?
7199 if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7200 if (isPCW(pc) && PCW(pc)->label) return 0;
7203 if (isPCL(pc)) return 0;
7212 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7217 vsprintf (buf, fmt, va);
7220 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7223 /* Replaces the old pCode with the new one, moving the labels,
7224 * C source line and probably flow information to the new pCode.
7226 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7227 if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7230 /* first move all labels from old to new */
7231 PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7232 PCI(oldPC)->label = NULL;
7235 /* move C source line (if possible) */
7236 if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7237 PCI(newPC)->cline = PCI(oldPC)->cline;
7240 /* keep flow information intact */
7241 newPC->seq = oldPC->seq;
7242 PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7243 if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7244 PCI(newPC)->pcflow->end = newPC;
7247 /* insert a comment stating which pCode has been replaced */
7249 if (pic16_pcode_verbose || pic16_debug_verbose) {
7251 pic16_pCode2str (pc_str, 256, oldPC);
7252 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7256 /* insert new pCode into pBlock */
7257 pic16_pCodeInsertAfter (oldPC, newPC);
7258 pic16_unlinkpCode (oldPC);
7260 /* destruct replaced pCode */
7261 oldPC->destruct (oldPC);
7264 /* Returns the inverted conditional branch (if any) or NULL.
7265 * pcop must be set to the new jump target.
7267 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7271 if (!bcc || !isPCI(bcc)) return NULL;
7273 switch (PCI(bcc)->op) {
7274 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7275 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7276 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7277 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7278 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7279 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7280 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7281 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7288 #define MAX_DIST_GOTO 0x7FFFFFFF
7289 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7290 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7291 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7292 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7294 /* Follows GOTO/BRA instructions to their target instructions, stores the
7295 * final destination (not a GOTO or BRA instruction) in target and returns
7296 * the distance from the original pc to *target.
7298 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7301 pCodeOp *lastPCOP = NULL;
7305 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7307 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7308 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7309 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7311 lastPCOP = PCI(curr)->pcop;
7312 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7313 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7316 if (target) *target = last;
7317 if (pcop) *pcop = lastPCOP;
7321 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7322 * Otherwise the first pCode after the jumptable (after
7323 * the OPT_JUMPTABLE_END tag) is returned.
7325 pCode *skipJumptables (pCode *pc, int *isJumptable)
7328 if (!pc) return NULL;
7330 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7332 //fprintf (stderr, "SKIPPING jumptable\n");
7334 //pc->print(stderr, pc);
7336 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7337 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7338 //fprintf (stderr, "<<JUMPTAB:\n");
7339 // skip OPT_END as well
7340 if (pc) pc = pc->next;
7346 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7350 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7351 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7352 pc = skipJumptables (pc, &isJumptab);
7354 // pc is the first pCode after the jumptable
7357 // pc has not been changed by skipJumptables()
7365 /* Turn GOTOs into BRAs if distance between GOTO and label
7366 * is less than 1024 bytes.
7368 * This method is especially useful if GOTOs after BTFS[SC]
7369 * can be turned into BRAs as GOTO would cost another NOP
7372 void pic16_OptimizeJumps ()
7375 pCode *pc_prev = NULL;
7376 pCode *pc_next = NULL;
7379 int change, iteration, isJumptab;
7382 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7384 if (!the_pFile) return;
7386 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7388 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7389 int matchedInvertRule = 1;
7392 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7394 pc = pic16_findNextInstruction (pb->pcHead);
7397 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7399 // skip jumptable, i.e. start over with no pc_prev!
7405 /* (1) resolve chained jumps
7406 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7407 * (a) leave dead code in and
7408 * (b) skip over the dead code with an (unneccessary) jump.
7410 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7411 pCodeOp *lastTargetOp = NULL;
7412 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7413 int maxDist = MAX_DIST_BCC;
7414 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7415 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7417 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7418 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7419 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7420 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7421 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7422 PCI(pc)->pcop->name = lastTargetOp->name;
7431 int condBraType = isSkipOnStatus(pc_prev);
7432 label = PCI(pc)->pcop->name;
7433 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7434 if (dist < 0) dist = -dist;
7435 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7439 /* (2) remove "GOTO label; label:" */
7440 if (isLabel (pc_next, label)) {
7441 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7442 // first remove all preceeding SKIP instructions
7443 while (pc_prev && isPCI_SKIP(pc_prev)) {
7444 // attach labels on this instruction to pc_next
7445 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7446 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7447 PCI(pc_prev)->label = NULL;
7448 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7449 pic16_unlinkpCode (pc_prev);
7450 pc_prev = pic16_findPrevInstruction (pc);
7452 // now remove the redundant goto itself
7453 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7454 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7455 pic16_unlinkpCode (pc);
7456 pc = pic16_findPrevInstruction(pc_next->prev);
7457 isHandled = 1; // do not perform further optimizations
7463 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7464 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7465 if (dist < MAX_DIST_BCC) {
7467 switch (condBraType) {
7468 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7469 // no BDC on DIGIT CARRY available
7470 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7471 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7472 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7473 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7474 // no BNDC on DIGIT CARRY available
7475 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7476 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7477 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7479 // no replacement possible
7484 // ATTENTION: keep labels attached to BTFSx!
7485 // HINT: GOTO is label free (checked above)
7486 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7487 isHandled = 1; // do not perform further optimizations
7488 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7489 pic16_pCodeReplace (pc_prev, bcc);
7496 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7502 // (4) eliminate the following (common) tripel:
7504 // labels1: Bcc label2;
7505 // GOTO somewhere; ; <-- instruction referenced by pc
7507 // and replace it by
7508 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7510 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7511 // to <cont.> instead
7512 // ATTENTION: This optimization is only valid if <pred.> is
7513 // not a skip operation!
7514 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7515 // ATTENTION: no label may be attached to the GOTO instruction!
7516 if (isConditionalBranch(pc_prev)
7517 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7518 && (dist < MAX_DIST_BCC)
7519 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7520 && hasNoLabel(pc)) {
7521 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7524 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7525 isHandled = 1; // do not perform further optimizations
7526 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7527 pic16_pCodeReplace (pc_prev, newBcc);
7532 matchedInvertRule++;
7537 /* (5) now just turn GOTO into BRA */
7538 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7539 if (dist < MAX_DIST_BRA) {
7540 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7541 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7542 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7543 pic16_pCodeReplace (pc, newBra);
7548 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7551 } // if (!isHandled)
7558 pBlockRemoveUnusedLabels (pb);
7560 // This line enables goto chain resolution!
7561 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7564 } while (change); /* fixpoint iteration per pBlock */
7567 // emit some statistics concerning goto-optimization
7569 if (pic16_debug_verbose || pic16_pcode_verbose) {
7570 fprintf (stderr, "optimize-goto:\n"
7571 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7572 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7573 "\t%5d conditional \"skipping\" jumps inverted\n"
7574 "\t%5d GOTOs to next instruction removed\n"
7575 "\t%5d chained GOTOs resolved\n",
7576 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7579 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7583 #undef MAX_JUMPCHAIN_DEPTH
7584 #undef MAX_DIST_GOTO
7588 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7590 static void pBlockDestruct(pBlock *pb)
7601 /*-----------------------------------------------------------------*/
7602 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7603 /* name dbName and combine them */
7604 /* into one block */
7605 /*-----------------------------------------------------------------*/
7606 static void mergepBlocks(char dbName)
7609 pBlock *pb, *pbmerged = NULL,*pbn;
7611 pb = the_pFile->pbHead;
7613 //fprintf(stderr," merging blocks named %c\n",dbName);
7617 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7618 if( getpBlock_dbName(pb) == dbName) {
7620 //fprintf(stderr," merged block %c\n",dbName);
7625 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7626 /* pic16_addpCode2pBlock doesn't handle the tail: */
7627 pbmerged->pcTail = pb->pcTail;
7629 pb->prev->next = pbn;
7631 pbn->prev = pb->prev;
7636 //pic16_printpBlock(stderr, pbmerged);
7643 /*-----------------------------------------------------------------*/
7644 /* AnalyzeFlow - Examine the flow of the code and optimize */
7646 /* level 0 == minimal optimization */
7647 /* optimize registers that are used only by two instructions */
7648 /* level 1 == maximal optimization */
7649 /* optimize by looking at pairs of instructions that use the */
7651 /*-----------------------------------------------------------------*/
7653 static void AnalyzeFlow(int level)
7655 static int times_called=0;
7659 /* remove unused allocated registers before exiting */
7660 pic16_RemoveUnusedRegisters();
7665 /* if this is not the first time this function has been called,
7666 * then clean up old flow information */
7667 if(times_called++) {
7668 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7670 pic16_RegsUnMapLiveRanges();
7674 /* Phase 2 - Flow Analysis - Register Banking
7676 * In this phase, the individual flow blocks are examined
7677 * and register banking is fixed.
7681 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7682 pic16_FixRegisterBanking(pb);
7685 /* Phase 2 - Flow Analysis
7687 * In this phase, the pCode is partition into pCodeFlow
7688 * blocks. The flow blocks mark the points where a continuous
7689 * stream of instructions changes flow (e.g. because of
7690 * a call or goto or whatever).
7693 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7694 pic16_BuildFlow(pb);
7697 /* Phase 2 - Flow Analysis - linking flow blocks
7699 * In this phase, the individual flow blocks are examined
7700 * to determine their order of excution.
7703 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7707 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7708 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7709 pic16_createDF (pb);
7710 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7711 pic16_vcg_dump_default (pb);
7713 //pic16_destructDF (pb);
7717 if (0) releaseStack (); // releasing is costly...
7721 /* Phase 3 - Flow Analysis - Flow Tree
7723 * In this phase, the individual flow blocks are examined
7724 * to determine their order of execution.
7727 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7728 pic16_BuildFlowTree(pb);
7731 /* Phase x - Flow Analysis - Used Banks
7733 * In this phase, the individual flow blocks are examined
7734 * to determine the Register Banks they use
7738 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7743 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7744 pic16_pCodeRegMapLiveRanges(pb);
7746 pic16_RemoveUnusedRegisters();
7747 pic16_removeUnusedRegistersDF ();
7749 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7750 pic16_pCodeRegOptimizeRegUsage(level);
7759 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7764 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7767 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7768 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7769 pcflow = pcflow->next) {
7770 FillFlow(PCFL(pcflow));
7775 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7778 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7779 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7780 pcflow = pcflow->next) {
7781 FlowStats(PCFL(pcflow));
7787 /* VR -- no need to analyze banking in flow, but left here :
7788 * 1. because it may be used in the future for other purposes
7789 * 2. because if omitted we'll miss some optimization done here
7791 * Perhaps I should rename it to something else
7794 /*-----------------------------------------------------------------*/
7795 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7796 /* assigned to the registers. */
7798 /*-----------------------------------------------------------------*/
7800 void pic16_AnalyzeBanking(void)
7804 /* Phase x - Flow Analysis - Used Banks
7806 * In this phase, the individual flow blocks are examined
7807 * to determine the Register Banks they use
7817 if(!the_pFile)return;
7819 if(!pic16_options.no_banksel) {
7820 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7821 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7822 pic16_FixRegisterBanking(pb);
7827 /*-----------------------------------------------------------------*/
7828 /* buildCallTree - Look at the flow and extract all of the calls. */
7829 /*-----------------------------------------------------------------*/
7830 static set *register_usage(pBlock *pb);
7832 static void buildCallTree(void )
7844 /* Now build the call tree.
7845 First we examine all of the pCodes for functions.
7846 Keep in mind that the function boundaries coincide
7847 with pBlock boundaries.
7849 The algorithm goes something like this:
7850 We have two nested loops. The outer loop iterates
7851 through all of the pBlocks/functions. The inner
7852 loop iterates through all of the pCodes for
7853 a given pBlock. When we begin iterating through
7854 a pBlock, the variable pc_fstart, pCode of the start
7855 of a function, is cleared. We then search for pCodes
7856 of type PC_FUNCTION. When one is encountered, we
7857 initialize pc_fstart to this and at the same time
7858 associate a new pBranch object that signifies a
7859 branch entry. If a return is found, then this signifies
7860 a function exit point. We'll link the pCodes of these
7861 returns to the matching pc_fstart.
7863 When we're done, a doubly linked list of pBranches
7864 will exist. The head of this list is stored in
7865 `the_pFile', which is the meta structure for all
7866 of the pCode. Look at the pic16_printCallTree function
7867 on how the pBranches are linked together.
7870 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7871 pCode *pc_fstart=NULL;
7872 for(pc = pb->pcHead; pc; pc = pc->next) {
7874 if(isPCI(pc) && pc_fstart) {
7875 if(PCI(pc)->is2MemOp) {
7876 r = pic16_getRegFromInstruction2(pc);
7877 if(r && !strcmp(r->name, "POSTDEC1"))
7878 PCF(pc_fstart)->stackusage++;
7880 r = pic16_getRegFromInstruction(pc);
7881 if(r && !strcmp(r->name, "PREINC1"))
7882 PCF(pc_fstart)->stackusage--;
7887 if (PCF(pc)->fname) {
7890 sprintf(buf, "%smain", port->fun_prefix);
7891 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7892 //fprintf(stderr," found main \n");
7893 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7897 pbr = Safe_calloc(1,sizeof(pBranch));
7898 pbr->pc = pc_fstart = pc;
7901 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7903 // Here's a better way of doing the same:
7904 addSet(&pb->function_entries, pc);
7907 // Found an exit point in a function, e.g. return
7908 // (Note, there may be more than one return per function)
7910 pBranchLink(PCF(pc_fstart), PCF(pc));
7912 addSet(&pb->function_exits, pc);
7914 } else if(isCALL(pc)) {
7915 addSet(&pb->function_calls,pc);
7922 /* This is not needed because currently all register used
7923 * by a function are stored in stack -- VR */
7925 /* Re-allocate the registers so that there are no collisions
7926 * between local variables when one function call another */
7929 // pic16_deallocateAllRegs();
7931 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7939 /*-----------------------------------------------------------------*/
7940 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7941 /* all of the logical connections. */
7943 /* Essentially what's done here is that the pCode flow is */
7945 /*-----------------------------------------------------------------*/
7947 void pic16_AnalyzepCode(char dbName)
7958 /* Phase 1 - Register allocation and peep hole optimization
7960 * The first part of the analysis is to determine the registers
7961 * that are used in the pCode. Once that is done, the peep rules
7962 * are applied to the code. We continue to loop until no more
7963 * peep rule optimizations are found (or until we exceed the
7964 * MAX_PASSES threshold).
7966 * When done, the required registers will be determined.
7972 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7973 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7975 /* First, merge the labels with the instructions */
7976 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7977 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7979 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7980 //fprintf(stderr," analyze and merging block %c\n",dbName);
7981 pic16_pBlockMergeLabels(pb);
7984 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7989 changes = OptimizepCode(dbName);
7992 } while(changes && (i++ < MAX_PASSES));
7999 /* convert a series of movff's of local regs to stack, with a single call to
8000 * a support functions which does the same thing via loop */
8001 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8005 char *fname[]={"__lr_store", "__lr_restore"};
8007 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8009 pct = pic16_findNextInstruction(pcstart->next);
8012 pct = pc->next; //pic16_findNextInstruction(pc->next);
8013 // pc->print(stderr, pc);
8014 if(isPCI(pc) && PCI(pc)->label) {
8015 pbr = PCI(pc)->label;
8016 while(pbr && pbr->pc) {
8017 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8021 // pc->print(stderr, pc);
8023 pc->prev->next = pct;
8024 pct->prev = pc->prev;
8028 } while ((pc) && (pc != pcend));
8030 /* unlink movff instructions */
8031 pcstart->next = pcend;
8032 pcend->prev = pcstart;
8036 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8037 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8040 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8041 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8042 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8045 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8046 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8053 sym = newSymbol( fname[ entry?0:1 ], 0 );
8054 strcpy(sym->rname, fname[ entry?0:1 ]);
8055 checkAddSym(&externs, sym);
8057 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8062 /*-----------------------------------------------------------------*/
8063 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
8064 /* local registers to a support function call */
8065 /*-----------------------------------------------------------------*/
8066 void pic16_OptimizeLocalRegs(void)
8071 pCodeOpLocalReg *pclr;
8074 regs *r, *lastr=NULL, *firstr=NULL;
8075 pCode *pcstart=NULL, *pcend=NULL;
8080 * local_regs begin mark
8081 * MOVFF r0x01, POSTDEC1
8082 * MOVFF r0x02, POSTDEC1
8085 * MOVFF r0x0n, POSTDEC1
8086 * local_regs end mark
8088 * convert the above to the below:
8089 * MOVLW starting_register_index
8091 * MOVLW register_count
8092 * call __save_registers_in_stack
8098 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8099 inRegCount = regCount = 0;
8100 firstr = lastr = NULL;
8101 for(pc = pb->pcHead; pc; pc = pc->next) {
8103 /* hold current function name */
8104 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8106 if(pc && (pc->type == PC_INFO)) {
8109 if(pci->type == INF_LOCALREGS) {
8110 pclr = PCOLR(pci->oper1);
8112 if((pclr->type == LR_ENTRY_BEGIN)
8113 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8116 switch(pclr->type) {
8117 case LR_ENTRY_BEGIN:
8119 inRegCount = 1; regCount = 0;
8120 pcstart = pc; //pic16_findNextInstruction(pc->next);
8121 firstr = lastr = NULL;
8127 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8130 if(curFunc && inWparamList(curFunc+1)) {
8131 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8135 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8140 firstr = lastr = NULL;
8144 if(inRegCount == -1) {
8145 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8151 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8153 r = pic16_getRegFromInstruction(pc);
8155 r = pic16_getRegFromInstruction2(pc);
8156 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8157 if(!firstr)firstr = r;
8159 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8171 /*-----------------------------------------------------------------*/
8172 /* ispCodeFunction - returns true if *pc is the pCode of a */
8174 /*-----------------------------------------------------------------*/
8175 static bool ispCodeFunction(pCode *pc)
8178 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8184 /*-----------------------------------------------------------------*/
8185 /* findFunction - Search for a function by name (given the name) */
8186 /* in the set of all functions that are in a pBlock */
8187 /* (note - I expect this to change because I'm planning to limit */
8188 /* pBlock's to just one function declaration */
8189 /*-----------------------------------------------------------------*/
8190 static pCode *findFunction(char *fname)
8197 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8199 pc = setFirstItem(pb->function_entries);
8202 if((pc->type == PC_FUNCTION) &&
8204 (strcmp(fname, PCF(pc)->fname)==0))
8207 pc = setNextItem(pb->function_entries);
8215 static void MarkUsedRegisters(set *regset)
8220 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8221 // fprintf(stderr, "marking register = %s\t", r1->name);
8222 r2 = pic16_regWithIdx(r1->rIdx);
8223 // fprintf(stderr, "to register = %s\n", r2->name);
8229 static void pBlockStats(FILE *of, pBlock *pb)
8235 if(!pic16_pcode_verbose)return;
8237 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8239 // for now just print the first element of each set
8240 pc = setFirstItem(pb->function_entries);
8242 fprintf(of,";entry: ");
8245 pc = setFirstItem(pb->function_exits);
8247 fprintf(of,";has an exit\n");
8251 pc = setFirstItem(pb->function_calls);
8253 fprintf(of,";functions called:\n");
8256 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8257 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8259 pc = setNextItem(pb->function_calls);
8263 r = setFirstItem(pb->tregisters);
8265 int n = elementsInSet(pb->tregisters);
8267 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8270 fprintf(of, "; %s\n",r->name);
8271 r = setNextItem(pb->tregisters);
8275 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8278 /*-----------------------------------------------------------------*/
8279 /*-----------------------------------------------------------------*/
8281 static void sequencepCode(void)
8287 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8289 pb->seq = GpCodeSequenceNumber+1;
8291 for( pc = pb->pcHead; pc; pc = pc->next)
8292 pc->seq = ++GpCodeSequenceNumber;
8298 /*-----------------------------------------------------------------*/
8299 /*-----------------------------------------------------------------*/
8300 static set *register_usage(pBlock *pb)
8303 set *registers=NULL;
8304 set *registersInCallPath = NULL;
8306 /* check recursion */
8308 pc = setFirstItem(pb->function_entries);
8315 if(pc->type != PC_FUNCTION)
8316 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8318 pc = setFirstItem(pb->function_calls);
8319 for( ; pc; pc = setNextItem(pb->function_calls)) {
8321 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8322 char *dest = pic16_get_op_from_instruction(PCI(pc));
8324 pcn = findFunction(dest);
8326 registersInCallPath = register_usage(pcn->pb);
8328 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8333 pBlockStats(stderr,pb); // debug
8336 // Mark the registers in this block as used.
8338 MarkUsedRegisters(pb->tregisters);
8339 if(registersInCallPath) {
8340 /* registers were used in the functions this pBlock has called */
8341 /* so now, we need to see if these collide with the ones we are */
8344 regs *r1,*r2, *newreg;
8346 DFPRINTF((stderr,"comparing registers\n"));
8348 r1 = setFirstItem(registersInCallPath);
8351 r2 = setFirstItem(pb->tregisters);
8353 while(r2 && (r1->type != REG_STK)) {
8355 if(r2->rIdx == r1->rIdx) {
8356 newreg = pic16_findFreeReg(REG_GPR);
8360 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8364 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8365 r1->rIdx, newreg->rIdx));
8366 r2->rIdx = newreg->rIdx;
8367 //if(r2->name) Safe_free(r2->name);
8369 r2->name = Safe_strdup(newreg->name);
8373 newreg->wasUsed = 1;
8375 r2 = setNextItem(pb->tregisters);
8378 r1 = setNextItem(registersInCallPath);
8381 /* Collisions have been resolved. Now free the registers in the call path */
8382 r1 = setFirstItem(registersInCallPath);
8384 if(r1->type != REG_STK) {
8385 newreg = pic16_regWithIdx(r1->rIdx);
8388 r1 = setNextItem(registersInCallPath);
8392 // MarkUsedRegisters(pb->registers);
8394 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8397 DFPRINTF((stderr,"returning regs\n"));
8399 DFPRINTF((stderr,"not returning regs\n"));
8401 DFPRINTF((stderr,"pBlock after register optim.\n"));
8402 pBlockStats(stderr,pb); // debug
8408 /*-----------------------------------------------------------------*/
8409 /* pct2 - writes the call tree to a file */
8411 /*-----------------------------------------------------------------*/
8412 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8416 // set *registersInCallPath = NULL;
8422 fprintf(of, "recursive function\n");
8423 return; //recursion ?
8426 pc = setFirstItem(pb->function_entries);
8433 for(i=0;i<indent;i++) // Indentation
8437 if(pc->type == PC_FUNCTION) {
8438 usedstack += PCF(pc)->stackusage;
8439 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8440 } else return; // ???
8443 pc = setFirstItem(pb->function_calls);
8444 for( ; pc; pc = setNextItem(pb->function_calls)) {
8446 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8447 char *dest = pic16_get_op_from_instruction(PCI(pc));
8449 pcn = findFunction(dest);
8451 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8453 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8461 /*-----------------------------------------------------------------*/
8462 /* pic16_printCallTree - writes the call tree to a file */
8464 /*-----------------------------------------------------------------*/
8466 void pic16_printCallTree(FILE *of)
8478 fprintf(of, "\npBlock statistics\n");
8479 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8483 fprintf(of,"Call Tree\n");
8484 pbr = the_pFile->functions;
8488 if(!ispCodeFunction(pc))
8489 fprintf(of,"bug in call tree");
8492 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8494 while(pc->next && !ispCodeFunction(pc->next)) {
8496 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8497 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8505 fprintf(of,"\n**************\n\na better call tree\n");
8506 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8511 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8512 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8518 /*-----------------------------------------------------------------*/
8520 /*-----------------------------------------------------------------*/
8522 static void InlineFunction(pBlock *pb)
8530 pc = setFirstItem(pb->function_calls);
8532 for( ; pc; pc = setNextItem(pb->function_calls)) {
8535 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8541 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8543 //fprintf(stderr,"Cool can inline:\n");
8544 //pcn->print(stderr,pcn);
8546 //fprintf(stderr,"recursive call Inline\n");
8547 InlineFunction(pcn->pb);
8548 //fprintf(stderr,"return from recursive call Inline\n");
8551 At this point, *pc points to a CALL mnemonic, and
8552 *pcn points to the function that is being called.
8554 To in-line this call, we need to remove the CALL
8555 and RETURN(s), and link the function pCode in with
8561 /* Remove the CALL */
8565 /* remove callee pBlock from the pBlock linked list */
8566 removepBlock(pcn->pb);
8574 /* Remove the Function pCode */
8575 pct = pic16_findNextInstruction(pcn->next);
8577 /* Link the function with the callee */
8578 pc->next = pcn->next;
8579 pcn->next->prev = pc;
8581 /* Convert the function name into a label */
8583 pbr = Safe_calloc(1,sizeof(pBranch));
8584 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8586 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8587 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8589 /* turn all of the return's except the last into goto's */
8590 /* check case for 2 instruction pBlocks */
8591 pce = pic16_findNextInstruction(pcn->next);
8593 pCode *pce_next = pic16_findNextInstruction(pce->next);
8595 if(pce_next == NULL) {
8596 /* found the last return */
8597 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8599 //fprintf(stderr,"found last return\n");
8600 //pce->print(stderr,pce);
8601 pce->prev->next = pc_call->next;
8602 pc_call->next->prev = pce->prev;
8603 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8613 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8619 /*-----------------------------------------------------------------*/
8621 /*-----------------------------------------------------------------*/
8623 void pic16_InlinepCode(void)
8632 if(!functionInlining)
8635 /* Loop through all of the function definitions and count the
8636 * number of times each one is called */
8637 //fprintf(stderr,"inlining %d\n",__LINE__);
8639 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8641 pc = setFirstItem(pb->function_calls);
8643 for( ; pc; pc = setNextItem(pb->function_calls)) {
8646 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8647 if(pcn && isPCF(pcn)) {
8648 PCF(pcn)->ncalled++;
8651 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8656 //fprintf(stderr,"inlining %d\n",__LINE__);
8658 /* Now, Loop through the function definitions again, but this
8659 * time inline those functions that have only been called once. */
8661 InlineFunction(the_pFile->pbHead);
8662 //fprintf(stderr,"inlining %d\n",__LINE__);
8664 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8669 char *pic_optype_names[]={
8670 "PO_NONE", // No operand e.g. NOP
8671 "PO_W", // The working register (as a destination)
8672 "PO_WREG", // The working register (as a file register)
8673 "PO_STATUS", // The 'STATUS' register
8674 "PO_BSR", // The 'BSR' register
8675 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8677 "PO_INDF0", // The Indirect register
8678 "PO_INTCON", // Interrupt Control register
8679 "PO_GPR_REGISTER", // A general purpose register
8680 "PO_GPR_BIT", // A bit of a general purpose register
8681 "PO_GPR_TEMP", // A general purpose temporary register
8682 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8683 "PO_PCL", // Program counter Low register
8684 "PO_PCLATH", // Program counter Latch high register
8685 "PO_PCLATU", // Program counter Latch upper register
8686 "PO_PRODL", // Product Register Low
8687 "PO_PRODH", // Product Register High
8688 "PO_LITERAL", // A constant
8689 "PO_REL_ADDR", // A relative address
8690 "PO_IMMEDIATE", // (8051 legacy)
8691 "PO_DIR", // Direct memory (8051 legacy)
8692 "PO_CRY", // bit memory (8051 legacy)
8693 "PO_BIT", // bit operand.
8694 "PO_STR", // (8051 legacy)
8696 "PO_WILD" // Wild card operand in peep optimizer
8700 char *dumpPicOptype(PIC_OPTYPE type)
8702 return (pic_optype_names[ type ]);
8706 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8709 #define MAX_COMMON_BANK_SIZE 32
8710 #define FIRST_PSEUDO_BANK_NR 1000
8712 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8713 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8714 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8717 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8720 pseudoBankNr bank; // number assigned to this pseudoBank
8721 unsigned int size; // number of operands assigned to this bank
8722 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8725 /*----------------------------------------------------------------------*/
8726 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8727 /*----------------------------------------------------------------------*/
8728 unsigned int hashSymbol (const char *str)
8730 unsigned int res = 0;
8735 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8742 /*-----------------------------------------------------------------------*/
8743 /* compareSymbol - return 1 iff sym1 equals sym2 */
8744 /*-----------------------------------------------------------------------*/
8745 int compareSymbol (const void *sym1, const void *sym2)
8747 char *s1 = (char*) sym1;
8748 char *s2 = (char*) sym2;
8750 return (strcmp (s1,s2) == 0);
8753 /*-----------------------------------------------------------------------*/
8754 /* comparePre - return 1 iff p1 == p2 */
8755 /*-----------------------------------------------------------------------*/
8756 int comparePtr (const void *p1, const void *p2)
8761 /*----------------------------------------------------------*/
8762 /* getSymbolFromOperand - return a pointer to the symbol in */
8763 /* the given operand and its length */
8764 /*----------------------------------------------------------*/
8765 char *getSymbolFromOperand (char *op, unsigned int *len)
8770 if (!op) return NULL;
8772 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8774 if (*sym == '(') sym++;
8777 while (((*curr >= 'A') && (*curr <= 'Z'))
8778 || ((*curr >= 'a') && (*curr <= 'z'))
8779 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8780 || (*curr == '_')) {
8781 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8789 /*--------------------------------------------------------------------------*/
8790 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8791 /*--------------------------------------------------------------------------*/
8792 char *getSymFromBank (pseudoBankNr bank)
8796 if (bank < 0) return "<INVALID BANK NR>";
8797 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8800 /*-----------------------------------------------------------------------*/
8801 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8802 /* bank number (uses hTab sym2bank), if the */
8803 /* symbol is not yet assigned a pseudo bank it */
8804 /* is assigned one here */
8805 /*-----------------------------------------------------------------------*/
8806 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8808 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8814 hash = hashSymbol (op) % sym2bank->size;
8815 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8816 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8818 if (bank == UNKNOWN_BANK) {
8819 // create a pseudo bank for the operand
8821 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8822 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8823 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8824 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8826 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8834 /*--------------------------------------------------------------------*/
8835 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8836 /*--------------------------------------------------------------------*/
8837 int isBanksel (pCode *pc)
8841 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8842 // BANKSEL <variablename> or MOVLB <banknr>
8843 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8847 // check for inline assembler BANKSELs
8848 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8849 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8850 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8854 // assume pc is no BANKSEL instruction
8858 /*---------------------------------------------------------------------------------*/
8859 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8860 /* This method can not guarantee to find all modifications of the */
8861 /* BSR (e.g. via INDirection registers) but covers all compiler */
8862 /* generated plus some cases. */
8863 /*---------------------------------------------------------------------------------*/
8864 int invalidatesBSR(pCode *pc)
8866 // assembler directives invalidate BSR (well, they might, we don't know)
8867 if (isPCAD(pc)) return 1;
8869 // only ASMDIRs and pCodeInstructions can invalidate BSR
8870 if (!isPCI(pc)) return 0;
8872 // we have a pCodeInstruction
8874 // check for BSR modifying instructions
8875 switch (PCI(pc)->op) {
8879 case POC_RETFIE: // might be used as CALL replacement
8880 case POC_RETLW: // might be used as CALL replacement
8881 case POC_RETURN: // might be used as CALL replacement
8886 default: // other instruction do not change BSR unless BSR is an explicit operand!
8887 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8891 // no change of BSR possible/probable
8895 /*------------------------------------------------------------*/
8896 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8897 /* the symbol referenced in this BANKSEL */
8898 /*------------------------------------------------------------*/
8899 pseudoBankNr getBankFromBanksel (pCode *pc)
8902 int data = (int)NULL;
8904 if (!pc) return INVALID_BANK;
8906 if (isPCAD(pc) && PCAD(pc)->directive) {
8907 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8908 // get symbolname from PCAD(pc)->arg
8909 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8910 sym = PCAD(pc)->arg;
8911 data = getPseudoBankNrFromOperand (sym);
8912 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8913 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8914 // get (literal) bank number from PCAD(pc)->arg
8915 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8916 assert (0 && "not yet implemented - turn off banksel optimization for now");
8918 } else if (isPCI(pc)) {
8919 if (PCI(pc)->op == POC_BANKSEL) {
8920 // get symbolname from PCI(pc)->pcop->name (?)
8921 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8922 sym = PCI(pc)->pcop->name;
8923 data = getPseudoBankNrFromOperand (sym);
8924 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8925 } else if (PCI(pc)->op == POC_MOVLB) {
8926 // get (literal) bank number from PCI(pc)->pcop->name
8927 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8928 assert (0 && "not yet implemented - turn off banksel optimization for now");
8933 // no assigned bank could be found
8934 return UNKNOWN_BANK;
8939 /*------------------------------------------------------------------------------*/
8940 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8941 /*------------------------------------------------------------------------------*/
8942 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8946 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8949 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8950 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8952 if (data->bank != bank)
8959 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8963 /*------------------------------------------------------------------*/
8964 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8965 /* bank is selected at a given pCode */
8966 /*------------------------------------------------------------------*/
8968 /* Create a graph with pseudo banks as its nodes and switches between
8969 * these as edges (with the edge weight representing the absolute
8970 * number of BANKSELs from one to the other).
8971 * Removes redundand BANKSELs instead iff mod == 1.
8972 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8973 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8975 * TODO: check ALL instructions operands if they modify BSR directly...
8977 * pb - the pBlock to annotate
8978 * mod - select either graph creation (0) or BANKSEL removal (1)
8980 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8982 pCode *pc, *pc_next;
8983 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8984 int isBankselect = 0;
8985 unsigned int banksels=0;
8989 pc = pic16_findNextInstruction(pb->pcHead);
8991 isBankselect = isBanksel (pc);
8992 pc_next = pic16_findNextInstruction (pc->next);
8994 if (!hasNoLabel (pc)) {
8995 // we don't know our predecessors -- assume different BSRs
8996 prevBSR = UNKNOWN_BANK;
8997 pseudoBSR = UNKNOWN_BANK;
8998 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9001 // check if this is a BANKSEL instruction
9003 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9004 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9006 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9007 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9008 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9009 pic16_unlinkpCode (pc);
9013 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9018 if (!isBankselect && invalidatesBSR(pc)) {
9019 // check if this instruction invalidates the pseudoBSR
9020 pseudoBSR = UNKNOWN_BANK;
9021 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9024 prevBSR = pseudoBSR;
9031 /*------------------------------------------------------------------------------------*/
9032 /* assignToSameBank - returns 0 on success or an error code */
9033 /* 1 - common bank would be too large */
9034 /* 2 - assignment to fixed (absolute) bank not performed */
9036 /* This functions assumes that unsplittable operands are already assigned to the same */
9037 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
9038 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
9039 /* TODO: Symbols with an abslute address must be handled specially! */
9040 /*------------------------------------------------------------------------------------*/
9041 int assignToSameBank (int bank0, int bank1, int doAbs)
9043 int eff0, eff1, dummy;
9044 pseudoBank *pbank0, *pbank1;
9047 eff0 = getEffectiveBank (bank0);
9048 eff1 = getEffectiveBank (bank1);
9050 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9052 // nothing to do if already same bank
9053 if (eff0 == eff1) return 0;
9055 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9058 // ensure eff0 < eff1
9060 // swap eff0 and eff1
9069 // now assign bank eff1 to bank eff0
9070 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9072 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9073 pbank0->bank = eff0;
9076 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9080 hitem = hTabSearch (coerce, eff1 % coerce->size);
9081 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9082 hitem = hitem->next;
9084 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9087 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9088 pbank0->bank, pbank0->size,
9089 getSymFromBank (eff0), getSymFromBank (eff1));
9093 if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9095 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9096 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9097 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9098 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9102 pbank0->size += pbank1->size;
9104 if (pbank1->ref == 0) Safe_free (pbank1);
9110 hitem->item = pbank0;
9112 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9115 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9120 /*----------------------------------------------------------------*/
9121 /* mergeGraphNodes - combines two nodes into one and modifies all */
9122 /* edges to and from the nodes accordingly */
9123 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9124 /* then also (B,A) must be an edge (possibly with weight 0). */
9125 /*----------------------------------------------------------------*/
9126 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9128 GraphEdge *edge, *backedge, *nextedge;
9132 assert (node1 && node2);
9133 assert (node1 != node2);
9135 // add all edges starting at node2 to node1
9138 nextedge = edge->next;
9140 backedge = getGEdge (node, node2);
9142 backweight = backedge->weight;
9145 // insert edges (node1,node) and (node,node1)
9146 addGEdge2 (node1, node, edge->weight, backweight);
9147 // remove edges (node, node2) and (node2, node)
9148 remGEdge (node2, node);
9149 remGEdge (node, node2);
9153 // now node2 should not be referenced by any other GraphNode...
9154 //remGNode (adj, node2->data, node2->hash);
9157 /*----------------------------------------------------------------*/
9158 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9159 /*----------------------------------------------------------------*/
9160 void showGraph (Graph *g)
9164 pseudoBankNr bankNr;
9171 bankNr = getEffectiveBank (node->hash);
9172 assert (bankNr >= 0);
9173 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9175 bankNr = pbank->bank;
9181 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9184 if (edge->weight > 0)
9185 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9192 /*---------------------------------------------------------------*/
9193 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9194 /*---------------------------------------------------------------*/
9195 void pic16_OptimizeBanksel ()
9197 GraphNode *node, *node1, *node1next;
9200 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9201 GraphEdge *edge, *backedge;
9203 int maxWeight, weight, mergeMore, absMaxWeight;
9204 pseudoBankNr curr0, curr1;
9207 pseudoBankNr bankNr;
9208 char *base_symbol0, *base_symbol1;
9213 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9215 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9217 if (!the_pFile || !the_pFile->pbHead) return;
9219 adj = newGraph (NULL);
9220 sym2bank = newHashTable ( 255 );
9221 bank2sym = newHashTable ( 255 );
9222 coerce = newHashTable ( 255 );
9224 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9225 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9226 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9230 // assign symbols with absolute addresses to their respective bank nrs
9231 set = pic16_fix_udata;
9232 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9233 bankNr = reg->address >> 8;
9234 node = getOrAddGNode (adj, NULL, bankNr);
9235 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9236 assignToSameBank (node->hash, bankNr, 1);
9238 assert (bankNr >= 0);
9239 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9241 pbank = Safe_calloc (1, sizeof (pseudoBank));
9242 pbank->bank = reg->address >> 8; //FIXED_BANK;
9245 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9247 assert (pbank->bank == (reg->address >> 8));
9248 pbank->bank = reg->address >> 8; //FIXED_BANK;
9250 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9255 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9256 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9259 if (node->hash < 0) { node = node->next; continue; }
9260 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9263 if (node1->hash < 0) { node1 = node1->next; continue; }
9264 node1next = node1->next;
9265 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9266 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9267 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9268 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9269 if (assignToSameBank (node->hash, node1->hash, 0)) {
9270 fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9271 assert (0 && "Could not assign a symbol to a bank!");
9273 mergeGraphNodes (node, node1);
9275 if (node->hash < node1->hash)
9276 mergeGraphNodes (node, node1);
9278 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9288 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9289 // assign tightly coupled operands to the same (pseudo) bank
9290 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9298 curr0 = getEffectiveBank (node->hash);
9299 if (curr0 < 0) { node = node->next; continue; }
9302 assert (edge->src == node);
9303 backedge = getGEdge (edge->node, edge->src);
9304 weight = edge->weight + (backedge ? backedge->weight : 0);
9305 curr1 = getEffectiveBank (edge->node->hash);
9306 if (curr1 < 0) { edge = edge->next; continue; }
9308 // merging is only useful if the items are not assigned to the same bank already...
9309 if (curr0 != curr1 && weight > maxWeight) {
9310 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9319 if (maxWeight > 0) {
9321 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9322 max->src->hash, getSymFromBank (max->src->hash),
9323 max->node->hash, getSymFromBank (max->node->hash));
9326 node = getGNode (adj, max->src->data, max->src->hash);
9327 node1 = getGNode (adj, max->node->data, max->node->hash);
9329 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9330 if (max->src->hash < max->node->hash)
9331 mergeGraphNodes (node, node1);
9333 mergeGraphNodes (node1, node);
9335 remGEdge (node, node1);
9336 remGEdge (node1, node);
9347 // remove redundant BANKSELs
9348 //fprintf (stderr, "removing redundant BANKSELs\n");
9349 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9350 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9355 fprintf (stderr, "display graph\n");
9360 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9363 /*** END of stuff belonging to the BANKSEL optimization ***/
9367 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9369 typedef unsigned int symbol_t;
9370 typedef unsigned int valnum_t;
9371 //typedef unsigned int hash_t;
9374 #define INT_TO_PTR(x) (((char *) 0) + (x))
9378 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9382 static unsigned int pic16_df_removed_pcodes = 0;
9383 static unsigned int pic16_df_saved_bytes = 0;
9384 static unsigned int df_findall_sameflow = 0;
9385 static unsigned int df_findall_otherflow = 0;
9386 static unsigned int df_findall_in_vals = 0;
9388 static void pic16_df_stats () {
9390 if (pic16_debug_verbose || pic16_pcode_verbose) {
9391 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9392 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9393 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9397 /* Remove a pCode iff possible:
9398 * - previous pCode is no SKIP
9400 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9401 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9402 pCode *pcprev, *pcnext;
9403 char buf[256], *total=NULL;
9406 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9408 pcprev = pic16_findPrevInstruction (pc->prev);
9409 pcnext = pic16_findNextInstruction (pc->next);
9411 /* if previous instruction is a skip -- do not remove */
9412 if (pcprev && isPCI_SKIP(pcprev)) return 0;
9414 /* move labels to next instruction (if possible) */
9415 if (PCI(pc)->label && !pcnext) return 0;
9417 if (PCI(pc)->label) {
9418 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9419 //pc->print (stderr, pc);
9420 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9421 PCI(pc)->label = NULL;
9424 /* update statistics */
9425 pic16_df_removed_pcodes++;
9426 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9428 /* remove the pCode */
9429 pic16_pCode2str (buf, 256, pc);
9430 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9431 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9432 len = strlen (buf) + strlen (comment) + 10;
9433 total = (char *) Safe_malloc (len);
9434 snprintf (total, len, "%s: %s", comment, buf);
9435 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9439 /* actually unlink it from the pBlock -- also remove from to/from lists */
9440 pic16_pCodeUnlink (pc);
9442 /* remove the pCode -- release registers */
9445 /* report success */
9450 /* ======================================================================== */
9451 /* === SYMBOL HANDLING ==================================================== */
9452 /* ======================================================================== */
9454 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9455 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9456 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9458 /** Calculate a hash for a given string.
9459 * If len == 0 the string is assumed to be NUL terminated. */
9460 static hash_t symbolHash (const char *str, unsigned int len) {
9464 hash = (hash << 2) ^ *str;
9469 hash = (hash << 2) ^ *str;
9476 /** Return 1 iff strings v1 and v2 are identical. */
9477 static int symcmp (const void *v1, const void *v2) {
9478 return !strcmp ((const char *) v1, (const char *) v2);
9481 /** Return 1 iff pointers v1 and v2 are identical. */
9482 static int ptrcmp (const void *v1, const void *v2) {
9486 enum { SPO_WREG=0x1000,
9526 /* Return the unique symbol_t for the given string. */
9527 static symbol_t symFromStr (const char *str) {
9532 if (!map_symToStr) {
9534 map_strToSym = newHashTable (128);
9535 map_symToStr = newHashTable (128);
9537 struct { char *name; symbol_t sym; } predefsyms[] = {
9539 {"STATUS", SPO_STATUS},
9540 {"PRODL", SPO_PRODL},
9541 {"PRODH", SPO_PRODH},
9542 {"INDF0", SPO_INDF0},
9543 {"POSTDEC0", SPO_POSTDEC0},
9544 {"POSTINC0", SPO_POSTINC0},
9545 {"PREINC0", SPO_PREINC0},
9546 {"PLUSW0", SPO_PLUSW0},
9547 {"INDF1", SPO_INDF1},
9548 {"POSTDEC1", SPO_POSTDEC1},
9549 {"POSTINC1", SPO_POSTINC1},
9550 {"PREINC1", SPO_PREINC1},
9551 {"PLUSW1", SPO_PLUSW1},
9552 {"INDF2", SPO_INDF2},
9553 {"POSTDEC2", SPO_POSTDEC2},
9554 {"POSTINC2", SPO_POSTINC2},
9555 {"PREINC2", SPO_PREINC2},
9556 {"PLUSW2", SPO_PLUSW2},
9557 {"STKPTR", SPO_STKPTR},
9562 {"FSR0L", SPO_FSR0L},
9563 {"FSR0H", SPO_FSR0H},
9564 {"FSR1L", SPO_FSR1L},
9565 {"FSR1H", SPO_FSR1H},
9566 {"FSR2L", SPO_FSR2L},
9567 {"FSR2H", SPO_FSR2H},
9569 {"PCLATH", SPO_PCLATH},
9570 {"PCLATU", SPO_PCLATU},
9571 {"TABLAT", SPO_TABLAT},
9572 {"TBLPTRL", SPO_TBLPTRL},
9573 {"TBLPTRH", SPO_TBLPTRH},
9574 {"TBLPTRU", SPO_TBLPTRU},
9578 for (i=0; predefsyms[i].name; i++) {
9581 /* enter new symbol */
9582 sym = predefsyms[i].sym;
9583 name = predefsyms[i].name;
9584 res = Safe_strdup (name);
9585 hash = symbolHash (name, 0);
9587 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9588 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9592 hash = symbolHash (str, 0) % map_strToSym->size;
9594 /* find symbol in table */
9595 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9597 //fprintf (stderr, "found symbol %u for %s\n", sym, str);
9601 /* enter new symbol */
9603 res = Safe_strdup (str);
9605 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9606 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9608 //fprintf (stderr, "created symbol %u for %s\n", sym, res);
9614 static const char *strFromSym (symbol_t sym) {
9615 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9619 /* ======================================================================== */
9620 /* === DEFINITION MAP HANDLING ============================================ */
9621 /* ======================================================================== */
9623 /* A defmap provides information about which symbol is defined by which pCode.
9624 * The most recent definitions are prepended to the list, so that the most
9625 * recent definition can be found by forward scanning the list.
9626 * pc2: MOVFF r0x00, r0x01
9628 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9630 * We attach one defmap to each flow object, and each pCode will occur at
9631 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9632 * used to find definitions for a pCode in its own defmap that precede pCode.
9635 typedef struct defmap_s {
9636 symbol_t sym; /** symbol this item refers to */
9639 unsigned int in_mask:8; /** mask leaving in accessed bits */
9640 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9641 int isRead:1; /** sym/mask is read */
9642 int isWrite:1; /** sym/mask is written */
9646 pCode *pc; /** pCode this symbol is refrenced at */
9647 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9648 valnum_t val; /** new unique number for this value (if isWrite) */
9649 struct defmap_s *prev, *next; /** link to previous an next definition */
9652 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9653 static int defmap_free_count = 0; /** number of released defmap items */
9655 /* Returns a defmap_t with the specified data; this will be the new list head.
9656 * next - pointer to the current list head */
9657 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9662 defmap_free = map->next;
9663 --defmap_free_count;
9665 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9668 map->access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9669 map->access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9670 map->access.isRead = (isRead != 0);
9671 map->access.isWrite = (isWrite != 0);
9674 map->val = (isWrite ? val : 0);
9677 if (next) next->prev = map;
9682 /* Returns a copy of the single defmap item. */
9683 static defmap_t *copyDefmap (defmap_t *map) {
9684 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9685 memcpy (res, map, sizeof (defmap_t));
9691 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9692 * item is copied before insertion into chain and therefore left untouched.
9693 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9694 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9697 while (dummy && (dummy->sym != item->sym
9698 || dummy->pc != item->pc
9699 || dummy->accessmethod != item->accessmethod
9700 || dummy->val != item->val
9701 || dummy->in_val != item->in_val)) {
9702 dummy = dummy->next;
9705 /* item already present? */
9706 if (dummy) return 0;
9708 /* otherwise: insert copy of item */
9709 dummy = copyDefmap (item);
9710 dummy->next = *head;
9711 if (*head) (*head)->prev = dummy;
9717 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9718 static void deleteDefmap (defmap_t *map) {
9721 /* unlink from chain -- fails for the first item (head is not updated!) */
9722 if (map->next) map->next->prev = map->prev;
9723 if (map->prev) map->prev->next = map->next;
9726 memset (map, 0, sizeof (defmap_t));
9728 /* save for future use */
9729 map->next = defmap_free;
9731 ++defmap_free_count;
9734 /* Release all defmaps referenced from map. */
9735 static void deleteDefmapChain (defmap_t **_map) {
9736 defmap_t *map, *next;
9742 /* find list head */
9743 while (map && map->prev) map = map->prev;
9745 /* delete all items */
9755 /* Free all defmap items. */
9756 static void freeDefmap (defmap_t **_map) {
9764 /* find list head */
9765 while (map->prev) map = map->prev;
9767 /* release all items */
9777 /* Returns the most recent definition for the given symbol preceeding pc.
9778 * If no definition is found, NULL is returned.
9779 * If pc == NULL the whole list is scanned. */
9780 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9781 defmap_t *curr = map;
9784 /* skip all definitions up to pc */
9785 while (curr && (curr->pc != pc)) curr = curr->next;
9787 /* pc not in the list -- scan the whole list for definitions */
9789 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9792 /* skip all definitions performed by pc */
9793 while (curr && (curr->pc == pc)) curr = curr->next;
9797 /* find definition for sym */
9798 while (curr && (!curr->access.isWrite || (curr->sym != sym))) {
9806 /* Returns the first use (read) of the given symbol AFTER pc.
9807 * If no such use is found, NULL is returned.
9808 * If pc == NULL the whole list is scanned. */
9809 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9810 defmap_t *curr = map, *prev = NULL;
9813 /* skip all definitions up to pc */
9814 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9816 /* pc not in the list -- scan the whole list for definitions */
9818 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9822 /* find end of list */
9823 while (curr && curr->next) curr = curr->next;
9826 /* find use of sym (scan list backwards) */
9827 while (curr && (!curr->access.isRead || (curr->sym != sym))) curr = curr->prev;
9833 /* Return the defmap entry for sym AT pc.
9834 * If none is found, NULL is returned.
9835 * If more than one entry is found an assertion is triggered. */
9836 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9837 defmap_t *res = NULL;
9839 /* find entries for pc */
9840 while (map && map->pc != pc) map = map->next;
9842 /* find first entry for sym @ pc */
9843 while (map && map->pc == pc && map->sym != sym) map = map->next;
9845 /* no entry found */
9846 if (!map) return NULL;
9848 /* check for more entries */
9851 while (map && map->pc == pc) {
9852 /* more than one entry for sym @ pc found? */
9853 assert (map->sym != sym);
9857 /* return single entry for sym @ pc */
9861 /* Modifies the definition of sym at pCode to newval.
9862 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9864 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9867 /* find definitions of pc */
9868 while (m && m->pc != pc) m = m->next;
9870 /* find definition of sym at pc */
9871 while (m && m->pc == pc && (!m->access.isWrite || (m->sym != sym))) m = m->next;
9873 /* no definition found */
9879 /* update following uses of sym */
9880 while (m && m->pc == pc) m = m->prev;
9882 if (m->sym == sym) {
9884 if (m->access.isWrite) m = NULL;
9892 /* ======================================================================== */
9893 /* === STACK ROUTINES ===================================================== */
9894 /* ======================================================================== */
9896 typedef struct stack_s {
9898 struct stack_s *next;
9901 typedef stackitem_t *stack_t;
9902 static stackitem_t *free_stackitems = NULL;
9904 /* Create a stack with one item. */
9905 static stack_t *newStack () {
9906 stack_t *s = (stack_t *) Safe_malloc (sizeof (stack_t));
9911 /* Remove a stack -- its items are only marked free. */
9912 static void deleteStack (stack_t *s) {
9918 i->next = free_stackitems;
9919 free_stackitems = i;
9924 /* Release all stackitems. */
9925 static void releaseStack () {
9928 while (free_stackitems) {
9929 i = free_stackitems->next;
9930 Safe_free(free_stackitems);
9931 free_stackitems = i;
9935 static void stackPush (stack_t *stack, void *data) {
9938 if (free_stackitems) {
9939 i = free_stackitems;
9940 free_stackitems = free_stackitems->next;
9942 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9949 static void *stackPop (stack_t *stack) {
9953 if (stack && *stack) {
9954 data = (*stack)->data;
9956 *stack = (*stack)->next;
9957 i->next = free_stackitems;
9958 free_stackitems = i;
9966 static int stackContains (stack_t *s, void *data) {
9971 if (i->data == data) return 1;
9980 static int stackIsEmpty (stack_t *s) {
9981 return (*s == NULL);
9990 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9991 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9993 s->lastdef = lastdef;
9997 static void deleteState (state_t *s) {
10001 static int stateIsNew (state_t *state, stack_t *todo, stack_t *done) {
10004 /* scan working list for state */
10008 /* is i == state? -- state not new */
10009 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10017 /* is i == state? -- state not new */
10018 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10023 /* not found -- state is new */
10027 static inline valnum_t newValnum ();
10029 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10032 if (!pb) return "<unknown function>";
10034 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10035 if (pc && isPCF(pc)) return PCF(pc)->fname;
10036 else return "<unknown function>";
10039 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10043 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10045 /* find initial value (assigning pc == NULL) */
10046 map = PCFL(pcfl)->in_vals;
10047 while (map && map->sym != sym) map = map->next;
10049 /* initial value already present? */
10051 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10055 /* create a new initial value */
10056 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10057 PCFL(pcfl)->in_vals = map;
10058 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10062 /* insert map as last item in pcfl's defmap */
10063 if (!prev) prev = PCFL(pcfl)->defmap;
10065 PCFL(pcfl)->defmap = map;
10067 while (prev->next) prev = prev->next;
10076 /* Find all reaching definitions for sym at pc.
10077 * A new (!) list of definitions is returned.
10078 * Returns the number of reaching definitions found.
10079 * The defining defmap entries are returned in *chain.
10081 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10086 pCodeFlowLink *succ;
10088 stack_t *todo; /** stack of state_t */
10089 stack_t *done; /** stack of state_t */
10091 int firstState, n_defs;
10093 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10096 /* initialize return list */
10099 /* wildcard symbol? */
10100 if (!sym) return 0;
10102 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10104 map = PCI(pc)->pcflow->defmap;
10106 res = defmapFindDef (map, sym, pc);
10107 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10109 #define USE_PRECALCED_INVALS 1
10110 #if USE_PRECALCED_INVALS
10111 if (!res && PCI(pc)->pcflow->in_vals) {
10112 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10114 //fprintf (stderr, "found def in init values\n");
10115 df_findall_in_vals++;
10121 // found a single definition (in pc's flow)
10122 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10123 defmapAddCopyIfNew (chain, res);
10124 df_findall_sameflow++;
10128 #if USE_PRECALCED_INVALS
10130 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10136 #define FORWARD_FLOW_ANALYSIS 1
10137 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10138 /* no definition found in pc's flow preceeding pc */
10139 todo = newStack ();
10140 done = newStack ();
10141 n_defs = 0; firstState = 1;
10142 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10144 while (!stackIsEmpty (todo)) {
10145 state = (state_t *) stackPop (todo);
10146 stackPush (done, state);
10147 curr = state->flow;
10148 res = state->lastdef;
10149 //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);
10151 /* there are no definitions BEFORE pc in pc's flow (see above) */
10152 if (curr == PCI(pc)->pcflow) {
10154 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10155 res = pic16_pBlockAddInval (pc->pb, sym);
10156 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10159 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10160 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10164 /* save last definition of sym in this flow as initial def in successors */
10165 res = defmapFindDef (curr->defmap, sym, NULL);
10166 if (!res) res = state->lastdef;
10168 /* add successors to working list */
10169 state = newState (NULL, NULL);
10170 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10172 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10173 state->flow = succ->pcflow;
10174 state->lastdef = res;
10175 if (stateIsNew (state, todo, done)) {
10176 stackPush (todo, state);
10177 state = newState (NULL, NULL);
10179 succ = (pCodeFlowLink *) setNextItem (curr->to);
10181 deleteState (state);
10184 #else // !FORWARD_FLOW_ANALYSIS
10186 /* no definition found in pc's flow preceeding pc */
10187 todo = newStack ();
10188 done = newStack ();
10189 n_defs = 0; firstState = 1;
10190 stackPush (todo, newState (PCI(pc)->pcflow, res));
10192 while (!stackIsEmpty (todo)) {
10193 state = (state_t *) stackPop (todo);
10194 curr = state->flow;
10198 /* only check predecessor flows */
10200 /* get (last) definition of sym in this flow */
10201 res = defmapFindDef (curr->defmap, sym, NULL);
10205 /* definition found */
10206 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10207 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10209 /* no definition found -- check predecessor flows */
10210 state = newState (NULL, NULL);
10211 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10213 /* if no flow predecessor available -- sym might be uninitialized */
10215 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10216 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10217 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10218 deleteDefmap (res); res = NULL;
10222 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10223 state->flow = succ->pcflow;
10224 state->lastdef = res;
10225 if (stateIsNew (state, todo, done)) {
10226 stackPush (todo, state);
10227 state = newState (NULL, NULL);
10229 succ = (pCodeFlowLink *) setNextItem (curr->from);
10231 deleteState (state);
10237 /* clean up done stack */
10238 while (!stackIsEmpty(done)) {
10239 deleteState ((state_t *) stackPop (done));
10241 deleteStack (done);
10243 /* return number of items in result set */
10245 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10246 } else if (n_defs == 1) {
10248 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10249 } else if (n_defs > 0) {
10250 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10254 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10259 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10260 df_findall_otherflow++;
10264 /* ======================================================================== */
10265 /* === VALUE NUMBER HANDLING ============================================== */
10266 /* ======================================================================== */
10268 static valnum_t nextValnum = 0x1000;
10269 static hTab *map_symToValnum = NULL;
10271 /** Return a new value number. */
10272 static inline valnum_t newValnum () {
10273 return (nextValnum += 4);
10276 static valnum_t valnumFromStr (const char *str) {
10281 sym = symFromStr (str);
10283 if (!map_symToValnum) {
10284 map_symToValnum = newHashTable (128);
10287 /* literal already known? */
10288 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10290 /* return existing valnum */
10291 if (res) return (valnum_t) PTR_TO_INT(res);
10293 /* create new valnum */
10295 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10299 /* Create a valnum for a literal. */
10300 static valnum_t valnumFromLit (unsigned int lit) {
10301 return ((valnum_t) 0x100 + (lit & 0x0FF));
10304 /* Return the (positive) literal value represented by val
10305 * or -1 iff val is no known literal's valnum. */
10306 static int litFromValnum (valnum_t val) {
10307 if (val >= 0x100 && val < 0x200) {
10308 /* valnum is a (known) literal */
10309 return val & 0x00FF;
10311 /* valnum is not a known literal */
10317 /* Sanity check - all flows in a block must be reachable from initial flow. */
10318 static int verifyAllFlowsReachable (pBlock *pb) {
10324 pCodeFlowLink *succ;
10327 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10330 flowInBlock = NULL;
10332 /* mark initial flow as reached (and "not needs to be reached") */
10333 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10335 addSetHead (&reached, pc);
10336 addSetHead (&checked, pc);
10338 /* mark all further flows in block as "need to be reached" */
10341 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10342 pc = pic16_findNextInstruction (pc->next);
10345 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10346 /* mark as reached and "not need to be reached" */
10347 deleteSetItem (&reached, pcfl);
10348 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10350 /* flow is no longer considered unreachable */
10351 deleteSetItem (&flowInBlock, pcfl);
10353 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10354 if (!isinSet (checked, succ->pcflow)) {
10355 /* flow has never been reached before */
10356 addSetHead (&reached, succ->pcflow);
10357 addSetHead (&checked, succ->pcflow);
10362 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10364 /* by now every flow should have been reached
10365 * --> flowInBlock should be empty */
10366 res = (flowInBlock == NULL);
10370 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10371 while (flowInBlock) {
10372 pcfl = indexSet (flowInBlock, 0);
10373 fprintf (stderr, "not reached: flow %p\n", pcfl);
10374 deleteSetItem (&flowInBlock, pcfl);
10380 deleteSet (&reached);
10381 deleteSet (&flowInBlock);
10382 deleteSet (&checked);
10384 /* if we reached every flow, succ is NULL by now... */
10385 //assert (res); // will fire on unreachable code...
10390 /* Checks a flow for accesses to sym AFTER pc.
10392 * Returns -1 if the symbol is read in this flow (before redefinition),
10393 * returns 0 if the symbol is redefined in this flow or
10394 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10396 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10397 defmap_t *map, *mappc;
10399 /* find pc or start of definitions */
10400 map = pcfl->defmap;
10401 while (map && (map->pc != pc) && map->next) map = map->next;
10402 /* if we found pc -- ignore it */
10403 while (map && map->pc == pc) map = map->prev;
10405 /* scan list backwards (first definition first) */
10406 while (map && mask) {
10407 // if (map->sym == sym) {
10408 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10410 /* scan list for reads at this pc first */
10411 while (map && map->pc == mappc->pc) {
10412 /* is the symbol (partially) read? */
10413 if ((map->sym == sym) && (map->access.isRead && ((map->access.in_mask & mask) != 0))) {
10414 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10421 while (map && map->pc == mappc->pc) {
10422 /* honor (partial) redefinitions of sym */
10423 if ((map->sym == sym) && (map->access.isWrite)) {
10424 mask &= ~map->access.mask;
10425 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10430 /* map already points to the first defmap for the next pCode */
10431 //map = mappc->prev;
10434 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10435 * is still alive; return the appropriate mask of alive bits */
10439 /* Check whether a symbol is alive (AFTER pc). */
10440 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10443 stack_t *todo, *done;
10446 pCodeFlowLink *succ;
10450 assert (isPCI(pc));
10451 pcfl = PCI(pc)->pcflow;
10452 map = pcfl->defmap;
10454 todo = newStack ();
10455 done = newStack ();
10457 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10458 stackPush (todo, state);
10461 while (!stackIsEmpty (todo)) {
10462 state = (state_t *) stackPop (todo);
10463 pcfl = state->flow;
10464 mask = PTR_TO_INT(state->lastdef);
10465 if (visit) stackPush (done, state); else deleteState(state);
10466 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10467 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10468 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10471 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10472 if (mask == 0) continue;
10474 /* symbol is (partially) read before redefinition in flow */
10475 if (mask == -1) break;
10477 /* symbol is neither read nor completely redefined -- check successor flows */
10478 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10479 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10480 if (stateIsNew (state, todo, done)) {
10481 stackPush (todo, state);
10483 deleteState (state);
10488 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10489 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10491 /* symbol is read in at least one flow -- is alive */
10492 if (mask == -1) return 1;
10494 /* symbol is read in no flow */
10498 /* Returns whether access to the given symbol has side effects. */
10499 static int pic16_symIsSpecial (symbol_t sym) {
10500 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10520 /* no special effects known */
10527 /* Check whether a register should be considered local (to the current function) or not. */
10528 static int pic16_regIsLocal (regs *r) {
10531 sym = symFromStr (r->name);
10534 case SPO_FSR0L: // used in ptrget/ptrput
10535 case SPO_FSR0H: // ... as well
10536 case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10537 case SPO_FSR1H: // ... as well
10538 case SPO_FSR2L: // used as frame pointer
10539 case SPO_FSR2H: // ... as well
10540 case SPO_PRODL: // used to return values from functions
10541 case SPO_PRODH: // ... as well
10542 /* these registers (and some more...) are considered local */
10546 /* for unknown regs: check is marked local, leave if not */
10550 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10556 /* if in doubt, assume non-local... */
10560 /* Check all symbols touched by pc whether their newly assigned values are read.
10561 * Returns 0 if no symbol is used later on, 1 otherwise. */
10562 static int pic16_pCodeIsAlive (pCode *pc) {
10563 pCodeInstruction *pci;
10564 defmap_t *map, *lastpc;
10567 /* we can only handle PCIs */
10568 if (!isPCI(pc)) return 1;
10570 //pc->print (stderr, pc);
10573 assert (pci && pci->pcflow && pci->pcflow->defmap);
10575 /* NEVER remove instructions with implicit side effects */
10578 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10579 case POC_TBLRD_POSTDEC:
10580 case POC_TBLRD_PREINC:
10581 case POC_TBLWT: /* modify program memory */
10582 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10583 case POC_TBLWT_POSTDEC:
10584 case POC_TBLWT_PREINC:
10585 case POC_CLRWDT: /* clear watchdog timer */
10586 case POC_PUSH: /* should be safe to remove though... */
10587 case POC_POP: /* should be safe to remove though... */
10592 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10596 /* no special instruction */
10600 /* prevent us from removing assignments to non-local variables */
10602 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10603 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10605 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10606 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10607 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10608 //pc->print (stderr, pc);
10611 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10612 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10617 /* OVERKILL: prevent us from removing reads from non-local variables
10618 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10619 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10621 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10622 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10624 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10625 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10626 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10627 //pc->print (stderr, pc);
10630 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10631 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10636 /* now check that the defined symbols are not used */
10637 map = pci->pcflow->defmap;
10639 /* find items for pc */
10640 while (map && map->pc != pc) map = map->next;
10642 /* no entries found? something is fishy with DF analysis... -- play safe */
10643 if (!map) { fprintf (stderr, "%s: defmap not found\n", __FUNCTION__); return 1; }
10645 /* remember first item assigned to pc for later use */
10648 /* check all symbols being modified by pc */
10649 while (map && map->pc == pc) {
10650 if (map->sym == 0) { map = map->next; continue; }
10652 /* keep pc if it references special symbols (like POSTDEC0) */
10656 pic16_pCode2str (buf, 256, pc);
10657 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10660 if (pic16_symIsSpecial (map->sym)) {
10661 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10664 if (map->access.isWrite) {
10665 if (pic16_isAlive (map->sym, pc)) {
10666 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10673 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10677 pic16_pCode2str (buf, 256, pc);
10678 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10684 /* Adds implied operands to the list.
10685 * sym - operand being accessed in the pCode
10686 * list - list to append the operand
10687 * isRead - set to 1 iff sym is read in pCode
10688 * listRead - set to 1 iff all operands being read are to be listed
10690 * Returns 0 for "normal" operands, 1 for special operands.
10692 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10693 /* check whether accessing REG accesses other REGs as well */
10697 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10698 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10699 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10703 /* reads FSR0x and WREG */
10704 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10705 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10706 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10707 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10713 /* reads/modifies FSR0x */
10714 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10715 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10716 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10721 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10722 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10723 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10727 /* reads FSR1x and WREG */
10728 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10729 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10730 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10731 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10737 /* reads/modifies FSR1x */
10738 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10739 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10740 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10745 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10746 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10747 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10751 /* reads FSR2x and WREG */
10752 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10753 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10754 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10755 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10761 /* reads/modifies FSR2x */
10762 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10763 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10764 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10768 /* modifies PCLATH and PCLATU */
10769 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10771 /* reading PCL updates PCLATx */
10772 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10773 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10776 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10777 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10778 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10783 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10784 /* nothing special */
10789 /* has been a special operand */
10793 static symbol_t pic16_fsrsym_idx[][2] = {
10794 {SPO_FSR0L, SPO_FSR0H},
10795 {SPO_FSR1L, SPO_FSR1H},
10796 {SPO_FSR2L, SPO_FSR2H}
10799 /** Prepend list with the reads and definitions performed by pc. */
10800 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10801 pCodeInstruction *pci;
10802 int cond, inCond, outCond;
10803 int mask = 0xff, smask;
10804 int isSpecial, isSpecial2;
10805 symbol_t sym, sym2;
10809 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10810 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10811 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10812 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10815 assert (isPCI(pc));
10818 /* handle bit instructions */
10819 if (pci->isBitInst) {
10820 assert (pci->pcop->type == PO_GPR_BIT);
10821 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10824 /* handle (additional) implicit arguments */
10830 lit = PCOL(pci->pcop)->lit;
10831 assert (lit >= 0 && lit < 3);
10832 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, ((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10833 val = valnumFromStr (((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10834 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10835 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10836 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...
10840 case POC_MOVLB: // BSR
10841 case POC_BANKSEL: // BSR
10842 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10845 case POC_MULWF: // PRODx
10846 case POC_MULLW: // PRODx
10847 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10848 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10851 case POC_POP: // TOS, STKPTR
10852 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10853 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10854 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10855 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10858 case POC_PUSH: // STKPTR
10859 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10860 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10861 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10862 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10865 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10866 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10867 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10868 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10869 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10870 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10872 /* needs correctly set-up stack pointer */
10873 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10874 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10877 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10878 /* pseudo read on (possible) return values */
10879 // WREG is handled below via outCond
10880 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10881 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10882 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10884 /* caller's stack pointers must be restored */
10885 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10886 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10887 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10888 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10891 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10892 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10893 /* pseudo read on (possible) return values */
10894 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10895 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10896 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10897 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10899 /* caller's stack pointers must be restored */
10900 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10901 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10902 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10903 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10907 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10908 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10909 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10910 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10913 case POC_TBLRD_POSTINC:
10914 case POC_TBLRD_POSTDEC:
10915 case POC_TBLRD_PREINC:
10916 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10917 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10918 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10919 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10923 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10924 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10925 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10926 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10929 case POC_TBLWT_POSTINC:
10930 case POC_TBLWT_POSTDEC:
10931 case POC_TBLWT_PREINC:
10932 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10933 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10934 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10935 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10939 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10943 /* handle explicit arguments */
10944 inCond = pci->inCond;
10945 outCond = pci->outCond;
10946 cond = inCond | outCond;
10947 if (cond & PCC_W) {
10948 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10951 /* keep STATUS read BEFORE STATUS write in the list */
10952 if (inCond & PCC_STATUS) {
10954 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10955 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10956 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10957 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10958 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10960 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10961 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10964 if (outCond & PCC_STATUS) {
10966 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10967 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10968 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10969 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10970 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
10972 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
10973 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10976 isSpecial = isSpecial2 = 0;
10978 if (cond & PCC_REGISTER) {
10979 name = pic16_get_op (pci->pcop, NULL, 0);
10980 sym = symFromStr (name);
10981 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
10982 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
10985 if (cond & PCC_REGISTER2) {
10986 name = pic16_get_op2 (pci->pcop, NULL, 0);
10987 sym2 = symFromStr (name);
10988 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
10989 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
10993 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10994 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11000 static void printDefmap (defmap_t *map) {
11004 fprintf (stderr, "defmap @ %p:\n", curr);
11006 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11007 curr->access.isRead ? "R" : " ",
11008 curr->access.isWrite ? "W": " ",
11009 curr->in_val, curr->val,
11010 curr->access.in_mask, curr->access.mask,
11011 strFromSym(curr->sym), curr->sym,
11015 fprintf (stderr, "<EOL>\n");
11019 /* Add "additional" definitions to uniq.
11020 * 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.
11021 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11023 * If symbols defined in additional are not present in uniq, a definition is created.
11024 * Otherwise the present definition is altered to reflect the newer assignments.
11026 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11027 * before `------- noted in additional --------' after
11029 * I assume that each symbol occurs AT MOST ONCE in uniq.
11032 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11037 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11038 /* find tail of additional list (holds the first assignment) */
11040 while (curr && curr->next) curr = curr->next;
11044 /* find next assignment in additionals */
11045 while (curr && !curr->access.isWrite) curr = curr->prev;
11049 /* find item in uniq */
11051 //printDefmap (*uniq);
11052 while (old && (old->sym != curr->sym)) old = old->next;
11055 /* definition found -- replace */
11056 if (old->val != curr->val) {
11057 old->val = curr->val;
11061 /* new definition */
11062 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11069 /* return 0 iff uniq remained unchanged */
11073 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11074 * lists of its predecessor flows.
11075 * Initially *combined should be NULL, alt_in will be copied to combined.
11076 * If *combined != NULL, combined will be altered:
11077 * - for symbols defined in *combined but not in alt_in,
11078 * *combined is altered to 0 (value unknown, either *combined or INIT).
11079 * - for symbols defined in alt_in but not in *combined,
11080 * a 0 definition is created (value unknown, either INIT or alt).
11081 * - for symbols defined in both, *combined is:
11082 * > left unchanged if *combined->val == alt_in->val or
11083 * > modified to 0 otherwise (value unknown, either alt or *combined).
11085 * I assume that each symbol occurs AT MOST ONCE in each list!
11087 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11093 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11095 if (!(*combined)) {
11096 return defmapUpdateUniqueSym (combined, alt_in);
11099 /* merge the two */
11102 /* find symbols definition in *combined */
11104 while (old && (old->sym != curr->sym)) old = old->next;
11107 /* definition found */
11108 if (old->val && (old->val != curr->val)) {
11109 old->val = 0; /* value unknown */
11113 /* no definition found -- can be either INIT or alt_in's value */
11114 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11115 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11116 if (val != curr->val) change++;
11122 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11125 if (old->val != 0) {
11126 /* find definition in alt_in */
11128 while (curr && curr->sym != old->sym) curr = curr->next;
11130 /* symbol defined in *combined only -- can be either INIT or *combined */
11131 val = pic16_pBlockAddInval (pb, old->sym)->val;
11132 if (old->val != val) {
11145 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11146 defmap_t *curr1, *curr2;
11149 /* identical maps are equal */
11150 if (map1 == map2) return 0;
11152 if (!map1) return -1;
11153 if (!map2) return 1;
11155 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11160 while (curr1 && curr2) {
11161 curr1 = curr1->next;
11162 curr2 = curr2->next;
11165 /* one of them longer? */
11166 if (curr1) return 1;
11167 if (curr2) return -1;
11169 /* both lists are of equal length -- compare (in O(n^2)) */
11174 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11175 if (!curr2) return 1; // symbol not found in curr2
11176 if (curr2->val != curr1->val) return 1; // values differ
11178 /* compare next symbol */
11179 curr1 = curr1->next;
11182 /* no difference found */
11187 /* Prepare a list of all reaching definitions per flow.
11188 * This is done using a forward dataflow analysis.
11190 static void createReachingDefinitions (pBlock *pb) {
11191 defmap_t *out_vals, *in_vals;
11194 pCodeFlowLink *link;
11198 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11199 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11201 deleteDefmapChain (&PCFL(pc)->in_vals);
11202 deleteDefmapChain (&PCFL(pc)->out_vals);
11203 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11207 pc = pic16_findNextInstruction (pb->pcHead);
11208 todo = NULL; blacklist = NULL;
11209 addSetHead (&todo, PCI(pc)->pcflow);
11211 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11212 while (elementsInSet (todo)) {
11213 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11214 pcfl = PCFL(indexSet (todo, 0));
11215 deleteSetItem (&todo, pcfl);
11216 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11220 if (isinSet (blacklist, pcfl)) {
11221 fprintf (stderr, "ignoring blacklisted flow\n");
11225 /* create in_vals from predecessors out_vals */
11226 link = setFirstItem (pcfl->from);
11228 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11229 link = setNextItem (pcfl->from);
11232 //printDefmap (in_vals);
11233 //printDefmap (pcfl->in_vals);
11235 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11236 //fprintf (stderr, "in_vals changed\n");
11237 /* in_vals changed -- update out_vals */
11238 deleteDefmapChain (&pcfl->in_vals);
11239 pcfl->in_vals = in_vals;
11241 /* create out_val from in_val and defmap */
11243 defmapUpdateUniqueSym (&out_vals, in_vals);
11244 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11246 /* is out_vals different from pcfl->out_vals */
11247 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11248 //fprintf (stderr, "out_vals changed\n");
11249 deleteDefmapChain (&pcfl->out_vals);
11250 pcfl->out_vals = out_vals;
11252 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11253 addSet (&blacklist, pcfl);
11256 /* reschedule all successors */
11257 link = setFirstItem (pcfl->to);
11259 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11260 addSetIfnotP (&todo, link->pcflow);
11261 link = setNextItem (pcfl->to);
11264 deleteDefmapChain (&out_vals);
11267 deleteDefmapChain (&in_vals);
11273 static void showAllDefs (symbol_t sym, pCode *pc) {
11277 assert (isPCI(pc));
11278 count = defmapFindAll (sym, pc, &map);
11280 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11283 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11286 pic16_pCode2str (buf, 256, map->pc);
11287 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11291 deleteDefmapChain (&map);
11295 /* safepCodeUnlink and remove pc from defmap. */
11296 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11297 defmap_t *map, *next, **head;
11301 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11302 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11303 res = pic16_safepCodeUnlink (pc, comment);
11306 /* remove pc from defmap */
11309 if (map->pc == pc) {
11310 if (!map->prev && head) *head = map->next;
11311 deleteDefmap (map);
11320 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11322 /* This breaks the defmap chain's references to pCodes... fix it! */
11323 map = PCI(pc)->pcflow->defmap;
11325 while (map && map->pc != pc) map = map->next;
11327 while (map && map->pc == pc) {
11333 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym) {
11335 if (!isPCI(pc)) return;
11337 map = PCI(pc)->pcflow->defmap;
11339 while (map && map->pc != pc) map = map->next;
11340 while (map && map->pc == pc) {
11341 if (map->sym == sym) map->sym = newsym;
11346 /* Assign "better" valnums to results. */
11347 static void assignValnums (pCode *pc) {
11348 pCodeInstruction *pci;
11350 symbol_t sym1, sym2;
11351 int cond, isSpecial1, isSpecial2, count, mask, lit;
11352 defmap_t *list, *val, *oldval, *dummy;
11353 regs *reg1 = NULL, *reg2 = NULL;
11356 /* only works for pCodeInstructions... */
11357 if (!isPCI(pc)) return;
11360 cond = pci->inCond | pci->outCond;
11361 list = pci->pcflow->defmap;
11362 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11364 if (cond & PCC_REGISTER) {
11365 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11366 reg1 = pic16_getRegFromInstruction (pc);
11367 isSpecial1 = pic16_symIsSpecial (sym1);
11369 if (cond & PCC_REGISTER2) {
11370 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11371 reg2 = pic16_getRegFromInstruction (pc);
11372 isSpecial2 = pic16_symIsSpecial (sym2);
11375 /* determine input values */
11377 while (val && val->pc != pc) val = val->next;
11378 //list = val; /* might save some time later... */
11379 while (val && val->pc == pc) {
11381 if (val->sym != 0 && (1 || val->access.isRead)) {
11382 /* get valnum for sym */
11383 count = defmapFindAll (val->sym, pc, &oldval);
11384 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11386 if ((val->access.in_mask & oldval->access.mask) == val->access.in_mask) {
11387 val->in_val = oldval->val;
11391 } else if (count == 0) {
11392 /* no definition found */
11395 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11397 dummy = oldval->next;
11398 mask = oldval->access.mask;
11399 val->in_val = oldval->val;
11400 while (dummy && (dummy->val == val->in_val)) {
11401 mask &= dummy->access.mask;
11402 dummy = dummy->next;
11405 /* found other values or to restictive mask */
11406 if (dummy || ((mask & val->access.in_mask) != val->access.in_mask)) {
11410 if (count > 0) deleteDefmapChain (&oldval);
11415 /* handle valnum assignment */
11417 case POC_CLRF: /* modifies STATUS (Z) */
11418 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11419 oldval = defmapCurr (list, sym1, pc);
11420 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11421 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11422 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11424 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11428 case POC_SETF: /* SETF does not touch STATUS */
11429 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11430 oldval = defmapCurr (list, sym1, pc);
11431 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11432 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11433 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11435 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11439 case POC_MOVLW: /* does not touch STATUS */
11440 oldval = defmapCurr (list, SPO_WREG, pc);
11441 if (pci->pcop->type == PO_LITERAL) {
11442 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11443 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11445 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11446 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11448 if (oldval && oldval->in_val == litnum) {
11449 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11450 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11452 defmapUpdate (list, SPO_WREG, pc, litnum);
11455 case POC_ANDLW: /* modifies STATUS (Z,N) */
11456 case POC_IORLW: /* modifies STATUS (Z,N) */
11457 case POC_XORLW: /* modifies STATUS (Z,N) */
11458 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11459 if (pci->pcop->type == PO_LITERAL) {
11460 lit = (unsigned char) PCOL(pci->pcop)->lit;
11462 val = defmapCurr (list, SPO_WREG, pc);
11463 if (val) vallit = litFromValnum (val->in_val);
11464 if (vallit != -1) {
11465 /* xxxLW <literal>, WREG contains a known literal */
11466 fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11467 if (pci->op == POC_ANDLW) {
11469 } else if (pci->op == POC_IORLW) {
11471 } else if (pci->op == POC_XORLW) {
11474 assert (0 && "invalid operation");
11476 if (vallit == lit) {
11477 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11478 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11480 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11487 /* check if old value matches new value */
11490 assert (pci->pcop->type == PO_LITERAL);
11492 lit = PCOL(pci->pcop)->lit;
11494 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11496 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11497 fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11499 /* cannot remove this LFSR */
11503 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11504 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11505 fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11511 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11516 case POC_MOVWF: /* does not touch flags */
11517 /* find value of WREG */
11518 val = defmapCurr (list, SPO_WREG, pc);
11519 oldval = defmapCurr (list, sym1, pc);
11520 if (val) lit = litFromValnum (val->in_val);
11522 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11524 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11525 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11526 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11528 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11530 assert (lit == 0x0ff);
11531 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11533 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11534 pic16_pCodeReplace (pc, newpc);
11535 defmapReplaceSymRef (pc, SPO_WREG, 0);
11536 pic16_fixDefmap (pc, newpc);
11539 /* This breaks the defmap chain's references to pCodes... fix it! */
11540 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11541 deleteDefmap (val); // delete reference to WREG as in value
11543 oldval = PCI(pc)->pcflow->defmap;
11545 if (oldval->pc == pc) oldval->pc = newpc;
11546 oldval = oldval->next;
11548 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11549 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11550 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11552 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11555 case POC_MOVFW: /* modifies STATUS (Z,N) */
11556 /* find value of REG */
11557 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11558 val = defmapCurr (list, sym1, pc);
11559 oldval = defmapCurr (list, SPO_WREG, pc);
11560 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11561 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11562 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11564 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11568 case POC_MOVFF: /* does not touch STATUS */
11569 /* find value of REG */
11570 val = defmapCurr (list, sym1, pc);
11571 oldval = defmapCurr (list, sym2, pc);
11572 if (val) lit = litFromValnum (val->in_val);
11575 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11576 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11578 newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11579 } else if (lit == 0x00ff) {
11580 newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11585 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11586 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11587 pic16_pCodeReplace (pc, newpc);
11588 defmapReplaceSymRef (pc, sym1, 0);
11589 pic16_fixDefmap (pc, newpc);
11591 break; // do not process instruction as MOVFF...
11593 } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) {
11594 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11595 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11596 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11598 if (!pic16_isAlive (sym1, pc)) {
11599 defmap_t *copy = NULL;
11600 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11601 * This should help eliminate
11603 * <do something not changing A or using B>
11605 * <B is not alive anymore>
11607 * <do something not changing A or using B>
11611 /* scan defmap for symbols storing sym1's value */
11612 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11613 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11614 /* unique reaching definition for sym found */
11615 if (copy->val && copy->val == val->in_val) {
11616 //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);
11617 if (copy->sym == SPO_WREG) {
11618 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11620 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11621 // /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop),
11622 pic16_pCodeOpCopy (PCI(copy->pc)->pcop),
11623 pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11625 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11626 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11627 pic16_pCodeReplace (pc, newpc);
11628 assert (val->sym == sym1 && val->access.isRead && !val->access.isWrite);
11629 defmapReplaceSymRef (pc, sym1, copy->sym);
11630 pic16_fixDefmap (pc, newpc);
11634 deleteDefmapChain (©);
11637 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11642 /* cannot optimize */
11647 static void pic16_destructDF (pBlock *pb) {
11650 /* remove old defmaps */
11651 pc = pic16_findNextInstruction (pb->pcHead);
11653 next = pic16_findNextInstruction (pc->next);
11655 assert (isPCI(pc) || isPCAD(pc));
11656 assert (PCI(pc)->pcflow);
11657 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11658 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11659 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11664 if (defmap_free || defmap_free_count) {
11665 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11666 freeDefmap (&defmap_free);
11667 defmap_free_count = 0;
11671 /* Checks whether a pBlock contains ASMDIRs. */
11672 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11675 pc = pic16_findNextInstruction (pb->pcHead);
11677 if (isPCAD(pc)) return 1;
11679 pc = pic16_findNextInstruction (pc->next);
11682 /* no PCADs found */
11687 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11688 static int pic16_removeUnusedRegistersDF () {
11691 regs *reg1, *reg2, *reg3;
11692 set *seenRegs = NULL;
11694 int islocal, change = 0;
11697 if (!the_pFile || !the_pFile->pbHead) return 0;
11699 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11700 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11702 /* find set of using pCodes per register */
11703 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11704 pc = pic16_findNextInstruction(pc->next)) {
11706 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11707 reg1 = reg2 = NULL;
11708 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11709 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11712 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11713 addSetIfnotP (&seenRegs, reg1);
11714 addSetIfnotP (®1->reglives.usedpCodes, pc);
11717 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11718 addSetIfnotP (&seenRegs, reg2);
11719 addSetIfnotP (®2->reglives.usedpCodes, pc);
11723 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11724 /* may not use pic16_regIsLocal() here -- in interrupt routines
11725 * WREG, PRODx, FSR0x must be saved */
11726 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11727 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11729 for (i=0; i < 2; i++) {
11730 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11731 if (!pc2) pc2 = pc;
11732 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11733 reg2 = pic16_getRegFromInstruction (pc);
11734 reg3 = pic16_getRegFromInstruction2 (pc);
11736 || (reg2->rIdx != pic16_stack_preinc->rIdx
11737 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11739 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11740 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11741 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11742 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11746 deleteSet (®1->reglives.usedpCodes);
11749 deleteSet (&seenRegs);
11756 /* Set up pCodeFlow's defmap_ts.
11757 * Needs correctly set up to/from fields. */
11758 static void pic16_createDF (pBlock *pb) {
11762 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11764 pic16_destructDF (pb);
11766 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11767 if (pic16_pBlockHasAsmdirs (pb)) {
11768 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11772 /* integrity check -- we need to reach all flows to guarantee
11773 * correct data flow analysis (reaching definitions, aliveness) */
11775 if (!verifyAllFlowsReachable (pb)) {
11776 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11781 /* establish new defmaps */
11782 pc = pic16_findNextInstruction (pb->pcHead);
11784 next = pic16_findNextInstruction (pc->next);
11786 assert (PCI(pc)->pcflow);
11787 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11792 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11793 createReachingDefinitions (pb);
11796 /* assign better valnums */
11797 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11798 pc = pic16_findNextInstruction (pb->pcHead);
11800 next = pic16_findNextInstruction (pc->next);
11802 assert (PCI(pc)->pcflow);
11803 assignValnums (pc);
11810 /* remove dead pCodes */
11811 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11814 pc = pic16_findNextInstruction (pb->pcHead);
11816 next = pic16_findNextInstruction (pc->next);
11818 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11819 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11829 /* ======================================================================= */
11830 /* === DEPRECATED CONTROL FLOW CREATION ROUTINES ========================= */
11831 /* ======================================================================= */
11835 /* connect pCode f anf t via their to/from pBranches */
11836 static void pic16_pCodeLink (pCode *f, pCode *t) {
11838 pCodeInstruction *_f, *_t;
11840 if (!f || !t) return;
11843 fprintf (stderr, "linking:\n");
11844 f->print(stderr, f);
11845 f->print(stderr, t);
11848 assert (isPCI(f) || isPCAD(f));
11849 assert (isPCI(t) || isPCAD(t));
11853 /* define t to be CF successor of f */
11854 br = Safe_malloc (sizeof (pBranch));
11857 _f->to = pic16_pBranchAppend (_f->to, br);
11859 /* define f to be CF predecessor of t */
11860 br = Safe_malloc (sizeof (pBranch));
11863 _t->from = pic16_pBranchAppend (_t->from, br);
11865 /* also update pcflow information */
11866 if (_f->pcflow && _t->pcflow && _f->pcflow != _t->pcflow) {
11867 //fprintf (stderr, "creating flow %p --> %p\n", _f->pcflow, _t->pcflow);
11868 LinkFlow_pCode (_f, _t);
11872 static void pic16_destructCF (pBlock *pb) {
11876 /* remove old CF information */
11880 while (PCI(pc)->to) {
11881 br = PCI(pc)->to->next;
11882 Safe_free (PCI(pc)->to);
11885 while (PCI(pc)->from) {
11886 br = PCI(pc)->from->next;
11887 Safe_free (PCI(pc)->from);
11888 PCI(pc)->from = br;
11890 } else if (isPCFL(pc)) {
11891 deleteSet (&PCFL(pc)->to);
11892 deleteSet (&PCFL(pc)->from);
11900 /* Set up pCodeInstruction's to and from pBranches. */
11901 static void pic16_createCF (pBlock *pb) {
11903 pCode *next, *dest;
11906 //fprintf (stderr, "creating CF for %p\n", pb);
11908 pic16_destructCF (pb);
11910 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11911 if (pic16_pBlockHasAsmdirs (pb)) {
11912 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11916 pc = pic16_findNextInstruction(pb->pcHead);
11918 next = pic16_findNextInstruction(pc->next);
11919 if (isPCI_SKIP(pc)) {
11920 pic16_pCodeLink(pc, next);
11921 pic16_pCodeLink(pc, pic16_findNextInstruction(next->next));
11922 } else if (isPCI_BRANCH(pc)) {
11923 // Bcc, BRA, CALL, GOTO
11924 if (PCI(pc)->pcop) {
11925 switch (PCI(pc)->pcop->type) {
11927 label = PCOLAB(PCI(pc)->pcop)->pcop.name;
11928 dest = findLabelinpBlock (pc->pb, PCOLAB(PCI(pc)->pcop));
11932 /* needed for GOTO ___irq_handler */
11933 label = PCI(pc)->pcop->name;
11938 assert (0 && "invalid label format");
11946 switch (PCI(pc)->op) {
11949 if (dest != NULL) {
11950 pic16_pCodeLink(pc, dest);
11952 //fprintf (stderr, "jump target \"%s\" not found!\n", label);
11958 pic16_pCodeLink(pc, next);
11968 if (dest != NULL) {
11969 pic16_pCodeLink(pc, dest);
11971 //fprintf (stderr, "jump target \"%s\"not found!\n", label);
11973 pic16_pCodeLink(pc, next);
11976 fprintf (stderr, "BRANCH instruction: %s\n", PCI(pc)->mnemonic);
11977 assert (0 && "unhandled branch instruction");
11981 pic16_pCodeLink (pc, next);
11988 /* ======================================================================== */
11989 /* === VCG DUMPER ROUTINES ================================================ */
11990 /* ======================================================================== */
11991 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11992 hTab *dumpedNodes = NULL;
11994 /** Dump VCG header into of. */
11995 static void pic16_vcg_init (FILE *of) {
11996 /* graph defaults */
11997 fprintf (of, "graph:{\n");
11998 fprintf (of, "title:\"graph1\"\n");
11999 fprintf (of, "label:\"graph1\"\n");
12000 fprintf (of, "color:white\n");
12001 fprintf (of, "textcolor:black\n");
12002 fprintf (of, "bordercolor:black\n");
12003 fprintf (of, "borderwidth:1\n");
12004 fprintf (of, "textmode:center\n");
12006 fprintf (of, "layoutalgorithm:dfs\n");
12007 fprintf (of, "late_edge_labels:yes\n");
12008 fprintf (of, "display_edge_labels:yes\n");
12009 fprintf (of, "dirty_edge_labels:yes\n");
12010 fprintf (of, "finetuning:yes\n");
12011 fprintf (of, "ignoresingles:no\n");
12012 fprintf (of, "straight_phase:yes\n");
12013 fprintf (of, "priority_phase:yes\n");
12014 fprintf (of, "manhattan_edges:yes\n");
12015 fprintf (of, "smanhattan_edges:no\n");
12016 fprintf (of, "nearedges:no\n");
12017 fprintf (of, "node_alignment:center\n"); // bottom|top|center
12018 fprintf (of, "port_sharing:no\n");
12019 fprintf (of, "arrowmode:free\n"); // fixed|free
12020 fprintf (of, "crossingphase2:yes\n");
12021 fprintf (of, "crossingoptimization:yes\n");
12022 fprintf (of, "edges:yes\n");
12023 fprintf (of, "nodes:yes\n");
12024 fprintf (of, "splines:no\n");
12026 /* node defaults */
12027 fprintf (of, "node.color:lightyellow\n");
12028 fprintf (of, "node.textcolor:black\n");
12029 fprintf (of, "node.textmode:center\n");
12030 fprintf (of, "node.shape:box\n");
12031 fprintf (of, "node.bordercolor:black\n");
12032 fprintf (of, "node.borderwidth:1\n");
12034 /* edge defaults */
12035 fprintf (of, "edge.textcolor:black\n");
12036 fprintf (of, "edge.color:black\n");
12037 fprintf (of, "edge.thickness:1\n");
12038 fprintf (of, "edge.arrowcolor:black\n");
12039 fprintf (of, "edge.backarrowcolor:black\n");
12040 fprintf (of, "edge.arrowsize:15\n");
12041 fprintf (of, "edge.backarrowsize:15\n");
12042 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12043 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12044 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12046 fprintf (of, "\n");
12048 /* prepare data structures */
12050 hTabDeleteAll (dumpedNodes);
12051 dumpedNodes = NULL;
12053 dumpedNodes = newHashTable (128);
12056 /** Dump VCG footer into of. */
12057 static void pic16_vcg_close (FILE *of) {
12058 fprintf (of, "}\n");
12061 #define BUF_SIZE 128
12062 #define pcTitle(pc) (snprintf (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12065 static int ptrcmp (const void *p1, const void *p2) {
12070 /** Dump a pCode node as VCG to of. */
12071 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12072 char buf[BUF_SIZE];
12074 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12078 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12079 //fprintf (stderr, "dumping %p\n", pc);
12081 /* only dump pCodeInstructions and Flow nodes */
12082 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12085 fprintf (of, "node:{");
12086 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12087 fprintf (of, "label:\"%s\n", pcTitle(pc));
12089 fprintf (of, "<PCFLOW>");
12090 } else if (isPCI(pc) || isPCAD(pc)) {
12091 pc->print (of, pc);
12093 fprintf (of, "<!PCI>");
12095 fprintf (of, "\" ");
12096 fprintf (of, "}\n");
12098 if (1 && isPCFL(pc)) {
12099 defmap_t *map, *prev;
12101 map = PCFL(pc)->defmap;
12104 if (map->sym != 0) {
12107 /* emit definition node */
12108 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12109 fprintf (of, "label:\"");
12113 fprintf (of, "%s%c%c: val %4x|%4x & %02x|%02x, sym %s", (prev == map) ? "" : "\n", map->access.isRead ? 'R' : ' ', map->access.isWrite ? 'W' : ' ', map->in_val, map->val, map->access.in_mask, map->access.mask, strFromSym (map->sym));
12116 } while (map && prev->pc == map->pc);
12119 fprintf (of, "\" ");
12121 fprintf (of, "color:green ");
12122 fprintf (of, "}\n");
12124 /* emit edge to previous definition */
12125 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12127 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12129 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12131 fprintf (of, "color:green ");
12132 fprintf (of, "}\n");
12135 pic16_vcg_dumpnode (map->pc, of);
12136 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12137 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12144 /* emit additional nodes (e.g. operands) */
12147 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12148 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12149 char buf[BUF_SIZE];
12150 pCodeInstruction *pci;
12154 if (1 && isPCFL(pc)) {
12155 /* emit edges to flow successors */
12157 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12158 pcfl = setFirstItem (PCFL(pc)->to);
12160 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12161 pic16_vcg_dumpnode (pc, of);
12162 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12163 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12164 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12165 pcfl = setNextItem (PCFL(pc)->to);
12169 if (!isPCI(pc) && !isPCAD(pc)) return;
12173 /* emit control flow edges (forward only) */
12177 pic16_vcg_dumpnode (curr->pc, of);
12178 fprintf (of, "edge:{");
12179 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12180 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12181 fprintf (of, "color:red ");
12182 fprintf (of, "}\n");
12187 /* dump "flow" edge (link pCode according to pBlock order) */
12190 pcnext = pic16_findNextInstruction (pc->next);
12192 pic16_vcg_dumpnode (pcnext, of);
12193 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12194 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12202 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12203 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12204 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12208 /* emit data flow edges (backward only) */
12209 /* TODO: gather data flow information... */
12212 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12215 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12216 if (pic16_pBlockHasAsmdirs (pb)) {
12217 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12221 for (pc=pb->pcHead; pc; pc = pc->next) {
12222 pic16_vcg_dumpnode (pc, of);
12225 for (pc=pb->pcHead; pc; pc = pc->next) {
12226 pic16_vcg_dumpedges (pc, of);
12230 static void pic16_vcg_dump_default (pBlock *pb) {
12232 char buf[BUF_SIZE];
12235 /* get function name */
12237 while (pc && !isPCF(pc)) pc = pc->next;
12239 snprintf (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12241 snprintf (buf, BUF_SIZE, "pb_%p.vcg", pb);
12244 //fprintf (stderr, "now dumping %s\n", buf);
12245 of = fopen (buf, "w");
12246 pic16_vcg_init (of);
12247 pic16_vcg_dump (of, pb);
12248 pic16_vcg_close (of);
12253 /*** END of helpers for pCode dataflow optimizations ***/