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;
7244 /* insert a comment stating which pCode has been replaced */
7246 if (pic16_pcode_verbose || pic16_debug_verbose) {
7248 pic16_pCode2str (pc_str, 256, oldPC);
7249 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7253 /* insert new pCode into pBlock */
7254 pic16_pCodeInsertAfter (oldPC, newPC);
7255 pic16_unlinkpCode (oldPC);
7257 /* destruct replaced pCode */
7258 oldPC->destruct (oldPC);
7261 /* Returns the inverted conditional branch (if any) or NULL.
7262 * pcop must be set to the new jump target.
7264 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7268 if (!bcc || !isPCI(bcc)) return NULL;
7270 switch (PCI(bcc)->op) {
7271 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7272 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7273 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7274 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7275 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7276 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7277 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7278 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7285 #define MAX_DIST_GOTO 0x7FFFFFFF
7286 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7287 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7288 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7289 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7291 /* Follows GOTO/BRA instructions to their target instructions, stores the
7292 * final destination (not a GOTO or BRA instruction) in target and returns
7293 * the distance from the original pc to *target.
7295 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7298 pCodeOp *lastPCOP = NULL;
7302 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7304 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7305 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7306 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7308 lastPCOP = PCI(curr)->pcop;
7309 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7310 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7313 if (target) *target = last;
7314 if (pcop) *pcop = lastPCOP;
7318 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7319 * Otherwise the first pCode after the jumptable (after
7320 * the OPT_JUMPTABLE_END tag) is returned.
7322 pCode *skipJumptables (pCode *pc, int *isJumptable)
7325 if (!pc) return NULL;
7327 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7329 //fprintf (stderr, "SKIPPING jumptable\n");
7331 //pc->print(stderr, pc);
7333 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7334 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7335 //fprintf (stderr, "<<JUMPTAB:\n");
7336 // skip OPT_END as well
7337 if (pc) pc = pc->next;
7343 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7347 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7348 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7349 pc = skipJumptables (pc, &isJumptab);
7351 // pc is the first pCode after the jumptable
7354 // pc has not been changed by skipJumptables()
7362 /* Turn GOTOs into BRAs if distance between GOTO and label
7363 * is less than 1024 bytes.
7365 * This method is especially useful if GOTOs after BTFS[SC]
7366 * can be turned into BRAs as GOTO would cost another NOP
7369 void pic16_OptimizeJumps ()
7372 pCode *pc_prev = NULL;
7373 pCode *pc_next = NULL;
7376 int change, iteration, isJumptab;
7379 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7381 if (!the_pFile) return;
7383 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7385 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7386 int matchedInvertRule = 1;
7389 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7391 pc = pic16_findNextInstruction (pb->pcHead);
7394 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7396 // skip jumptable, i.e. start over with no pc_prev!
7402 /* (1) resolve chained jumps
7403 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7404 * (a) leave dead code in and
7405 * (b) skip over the dead code with an (unneccessary) jump.
7407 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7408 pCodeOp *lastTargetOp = NULL;
7409 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7410 int maxDist = MAX_DIST_BCC;
7411 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7412 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7414 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7415 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7416 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7417 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7418 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7419 PCI(pc)->pcop->name = lastTargetOp->name;
7428 int condBraType = isSkipOnStatus(pc_prev);
7429 label = PCI(pc)->pcop->name;
7430 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7431 if (dist < 0) dist = -dist;
7432 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7436 /* (2) remove "GOTO label; label:" */
7437 if (isLabel (pc_next, label)) {
7438 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7439 // first remove all preceeding SKIP instructions
7440 while (pc_prev && isPCI_SKIP(pc_prev)) {
7441 // attach labels on this instruction to pc_next
7442 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7443 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7444 PCI(pc_prev)->label = NULL;
7445 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7446 pic16_unlinkpCode (pc_prev);
7447 pc_prev = pic16_findPrevInstruction (pc);
7449 // now remove the redundant goto itself
7450 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7451 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7452 pic16_unlinkpCode (pc);
7453 pc = pic16_findPrevInstruction(pc_next->prev);
7454 isHandled = 1; // do not perform further optimizations
7460 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7461 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7462 if (dist < MAX_DIST_BCC) {
7464 switch (condBraType) {
7465 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7466 // no BDC on DIGIT CARRY available
7467 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7468 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7469 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7470 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7471 // no BNDC on DIGIT CARRY available
7472 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7473 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7474 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7476 // no replacement possible
7481 // ATTENTION: keep labels attached to BTFSx!
7482 // HINT: GOTO is label free (checked above)
7483 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7484 isHandled = 1; // do not perform further optimizations
7485 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7486 pic16_pCodeReplace (pc_prev, bcc);
7493 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7499 // (4) eliminate the following (common) tripel:
7501 // labels1: Bcc label2;
7502 // GOTO somewhere; ; <-- instruction referenced by pc
7504 // and replace it by
7505 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7507 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7508 // to <cont.> instead
7509 // ATTENTION: This optimization is only valid if <pred.> is
7510 // not a skip operation!
7511 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7512 // ATTENTION: no label may be attached to the GOTO instruction!
7513 if (isConditionalBranch(pc_prev)
7514 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7515 && (dist < MAX_DIST_BCC)
7516 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7517 && hasNoLabel(pc)) {
7518 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7521 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7522 isHandled = 1; // do not perform further optimizations
7523 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7524 pic16_pCodeReplace (pc_prev, newBcc);
7529 matchedInvertRule++;
7534 /* (5) now just turn GOTO into BRA */
7535 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7536 if (dist < MAX_DIST_BRA) {
7537 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7538 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7539 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7540 pic16_pCodeReplace (pc, newBra);
7545 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7548 } // if (!isHandled)
7555 pBlockRemoveUnusedLabels (pb);
7557 // This line enables goto chain resolution!
7558 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7561 } while (change); /* fixpoint iteration per pBlock */
7564 // emit some statistics concerning goto-optimization
7566 if (pic16_debug_verbose || pic16_pcode_verbose) {
7567 fprintf (stderr, "optimize-goto:\n"
7568 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7569 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7570 "\t%5d conditional \"skipping\" jumps inverted\n"
7571 "\t%5d GOTOs to next instruction removed\n"
7572 "\t%5d chained GOTOs resolved\n",
7573 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7576 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7580 #undef MAX_JUMPCHAIN_DEPTH
7581 #undef MAX_DIST_GOTO
7585 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7587 static void pBlockDestruct(pBlock *pb)
7598 /*-----------------------------------------------------------------*/
7599 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7600 /* name dbName and combine them */
7601 /* into one block */
7602 /*-----------------------------------------------------------------*/
7603 static void mergepBlocks(char dbName)
7606 pBlock *pb, *pbmerged = NULL,*pbn;
7608 pb = the_pFile->pbHead;
7610 //fprintf(stderr," merging blocks named %c\n",dbName);
7614 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7615 if( getpBlock_dbName(pb) == dbName) {
7617 //fprintf(stderr," merged block %c\n",dbName);
7622 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7623 /* pic16_addpCode2pBlock doesn't handle the tail: */
7624 pbmerged->pcTail = pb->pcTail;
7626 pb->prev->next = pbn;
7628 pbn->prev = pb->prev;
7633 //pic16_printpBlock(stderr, pbmerged);
7640 /*-----------------------------------------------------------------*/
7641 /* AnalyzeFlow - Examine the flow of the code and optimize */
7643 /* level 0 == minimal optimization */
7644 /* optimize registers that are used only by two instructions */
7645 /* level 1 == maximal optimization */
7646 /* optimize by looking at pairs of instructions that use the */
7648 /*-----------------------------------------------------------------*/
7650 static void AnalyzeFlow(int level)
7652 static int times_called=0;
7656 /* remove unused allocated registers before exiting */
7657 pic16_RemoveUnusedRegisters();
7662 /* if this is not the first time this function has been called,
7663 * then clean up old flow information */
7664 if(times_called++) {
7665 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7667 pic16_RegsUnMapLiveRanges();
7671 /* Phase 2 - Flow Analysis - Register Banking
7673 * In this phase, the individual flow blocks are examined
7674 * and register banking is fixed.
7678 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7679 pic16_FixRegisterBanking(pb);
7682 /* Phase 2 - Flow Analysis
7684 * In this phase, the pCode is partition into pCodeFlow
7685 * blocks. The flow blocks mark the points where a continuous
7686 * stream of instructions changes flow (e.g. because of
7687 * a call or goto or whatever).
7690 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7691 pic16_BuildFlow(pb);
7694 /* Phase 2 - Flow Analysis - linking flow blocks
7696 * In this phase, the individual flow blocks are examined
7697 * to determine their order of excution.
7700 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7704 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7705 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7706 pic16_createDF (pb);
7707 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7708 pic16_vcg_dump_default (pb);
7710 //pic16_destructDF (pb);
7714 if (0) releaseStack (); // releasing is costly...
7718 /* Phase 3 - Flow Analysis - Flow Tree
7720 * In this phase, the individual flow blocks are examined
7721 * to determine their order of execution.
7724 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7725 pic16_BuildFlowTree(pb);
7728 /* Phase x - Flow Analysis - Used Banks
7730 * In this phase, the individual flow blocks are examined
7731 * to determine the Register Banks they use
7735 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7740 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7741 pic16_pCodeRegMapLiveRanges(pb);
7743 pic16_RemoveUnusedRegisters();
7744 pic16_removeUnusedRegistersDF ();
7746 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7747 pic16_pCodeRegOptimizeRegUsage(level);
7756 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7761 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7764 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7765 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7766 pcflow = pcflow->next) {
7767 FillFlow(PCFL(pcflow));
7772 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7775 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7776 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7777 pcflow = pcflow->next) {
7778 FlowStats(PCFL(pcflow));
7784 /* VR -- no need to analyze banking in flow, but left here :
7785 * 1. because it may be used in the future for other purposes
7786 * 2. because if omitted we'll miss some optimization done here
7788 * Perhaps I should rename it to something else
7791 /*-----------------------------------------------------------------*/
7792 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7793 /* assigned to the registers. */
7795 /*-----------------------------------------------------------------*/
7797 void pic16_AnalyzeBanking(void)
7801 /* Phase x - Flow Analysis - Used Banks
7803 * In this phase, the individual flow blocks are examined
7804 * to determine the Register Banks they use
7814 if(!the_pFile)return;
7816 if(!pic16_options.no_banksel) {
7817 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7818 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7819 pic16_FixRegisterBanking(pb);
7824 /*-----------------------------------------------------------------*/
7825 /* buildCallTree - Look at the flow and extract all of the calls. */
7826 /*-----------------------------------------------------------------*/
7827 static set *register_usage(pBlock *pb);
7829 static void buildCallTree(void )
7841 /* Now build the call tree.
7842 First we examine all of the pCodes for functions.
7843 Keep in mind that the function boundaries coincide
7844 with pBlock boundaries.
7846 The algorithm goes something like this:
7847 We have two nested loops. The outer loop iterates
7848 through all of the pBlocks/functions. The inner
7849 loop iterates through all of the pCodes for
7850 a given pBlock. When we begin iterating through
7851 a pBlock, the variable pc_fstart, pCode of the start
7852 of a function, is cleared. We then search for pCodes
7853 of type PC_FUNCTION. When one is encountered, we
7854 initialize pc_fstart to this and at the same time
7855 associate a new pBranch object that signifies a
7856 branch entry. If a return is found, then this signifies
7857 a function exit point. We'll link the pCodes of these
7858 returns to the matching pc_fstart.
7860 When we're done, a doubly linked list of pBranches
7861 will exist. The head of this list is stored in
7862 `the_pFile', which is the meta structure for all
7863 of the pCode. Look at the pic16_printCallTree function
7864 on how the pBranches are linked together.
7867 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7868 pCode *pc_fstart=NULL;
7869 for(pc = pb->pcHead; pc; pc = pc->next) {
7871 if(isPCI(pc) && pc_fstart) {
7872 if(PCI(pc)->is2MemOp) {
7873 r = pic16_getRegFromInstruction2(pc);
7874 if(r && !strcmp(r->name, "POSTDEC1"))
7875 PCF(pc_fstart)->stackusage++;
7877 r = pic16_getRegFromInstruction(pc);
7878 if(r && !strcmp(r->name, "PREINC1"))
7879 PCF(pc_fstart)->stackusage--;
7884 if (PCF(pc)->fname) {
7887 sprintf(buf, "%smain", port->fun_prefix);
7888 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7889 //fprintf(stderr," found main \n");
7890 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7894 pbr = Safe_calloc(1,sizeof(pBranch));
7895 pbr->pc = pc_fstart = pc;
7898 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7900 // Here's a better way of doing the same:
7901 addSet(&pb->function_entries, pc);
7904 // Found an exit point in a function, e.g. return
7905 // (Note, there may be more than one return per function)
7907 pBranchLink(PCF(pc_fstart), PCF(pc));
7909 addSet(&pb->function_exits, pc);
7911 } else if(isCALL(pc)) {
7912 addSet(&pb->function_calls,pc);
7919 /* This is not needed because currently all register used
7920 * by a function are stored in stack -- VR */
7922 /* Re-allocate the registers so that there are no collisions
7923 * between local variables when one function call another */
7926 // pic16_deallocateAllRegs();
7928 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7936 /*-----------------------------------------------------------------*/
7937 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7938 /* all of the logical connections. */
7940 /* Essentially what's done here is that the pCode flow is */
7942 /*-----------------------------------------------------------------*/
7944 void pic16_AnalyzepCode(char dbName)
7955 /* Phase 1 - Register allocation and peep hole optimization
7957 * The first part of the analysis is to determine the registers
7958 * that are used in the pCode. Once that is done, the peep rules
7959 * are applied to the code. We continue to loop until no more
7960 * peep rule optimizations are found (or until we exceed the
7961 * MAX_PASSES threshold).
7963 * When done, the required registers will be determined.
7969 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7970 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7972 /* First, merge the labels with the instructions */
7973 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7974 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7976 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7977 //fprintf(stderr," analyze and merging block %c\n",dbName);
7978 pic16_pBlockMergeLabels(pb);
7981 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7986 changes = OptimizepCode(dbName);
7989 } while(changes && (i++ < MAX_PASSES));
7996 /* convert a series of movff's of local regs to stack, with a single call to
7997 * a support functions which does the same thing via loop */
7998 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8002 char *fname[]={"__lr_store", "__lr_restore"};
8004 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8006 pct = pic16_findNextInstruction(pcstart->next);
8009 pct = pc->next; //pic16_findNextInstruction(pc->next);
8010 // pc->print(stderr, pc);
8011 if(isPCI(pc) && PCI(pc)->label) {
8012 pbr = PCI(pc)->label;
8013 while(pbr && pbr->pc) {
8014 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8018 // pc->print(stderr, pc);
8020 pc->prev->next = pct;
8021 pct->prev = pc->prev;
8025 } while ((pc) && (pc != pcend));
8027 /* unlink movff instructions */
8028 pcstart->next = pcend;
8029 pcend->prev = pcstart;
8033 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8034 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8037 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8038 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8039 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8042 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8043 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8050 sym = newSymbol( fname[ entry?0:1 ], 0 );
8051 strcpy(sym->rname, fname[ entry?0:1 ]);
8052 checkAddSym(&externs, sym);
8054 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8059 /*-----------------------------------------------------------------*/
8060 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
8061 /* local registers to a support function call */
8062 /*-----------------------------------------------------------------*/
8063 void pic16_OptimizeLocalRegs(void)
8068 pCodeOpLocalReg *pclr;
8071 regs *r, *lastr=NULL, *firstr=NULL;
8072 pCode *pcstart=NULL, *pcend=NULL;
8077 * local_regs begin mark
8078 * MOVFF r0x01, POSTDEC1
8079 * MOVFF r0x02, POSTDEC1
8082 * MOVFF r0x0n, POSTDEC1
8083 * local_regs end mark
8085 * convert the above to the below:
8086 * MOVLW starting_register_index
8088 * MOVLW register_count
8089 * call __save_registers_in_stack
8095 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8096 inRegCount = regCount = 0;
8097 firstr = lastr = NULL;
8098 for(pc = pb->pcHead; pc; pc = pc->next) {
8100 /* hold current function name */
8101 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8103 if(pc && (pc->type == PC_INFO)) {
8106 if(pci->type == INF_LOCALREGS) {
8107 pclr = PCOLR(pci->oper1);
8109 if((pclr->type == LR_ENTRY_BEGIN)
8110 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8113 switch(pclr->type) {
8114 case LR_ENTRY_BEGIN:
8116 inRegCount = 1; regCount = 0;
8117 pcstart = pc; //pic16_findNextInstruction(pc->next);
8118 firstr = lastr = NULL;
8124 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8127 if(curFunc && inWparamList(curFunc+1)) {
8128 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8132 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8137 firstr = lastr = NULL;
8141 if(inRegCount == -1) {
8142 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8148 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8150 r = pic16_getRegFromInstruction(pc);
8152 r = pic16_getRegFromInstruction2(pc);
8153 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8154 if(!firstr)firstr = r;
8156 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8168 /*-----------------------------------------------------------------*/
8169 /* ispCodeFunction - returns true if *pc is the pCode of a */
8171 /*-----------------------------------------------------------------*/
8172 static bool ispCodeFunction(pCode *pc)
8175 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8181 /*-----------------------------------------------------------------*/
8182 /* findFunction - Search for a function by name (given the name) */
8183 /* in the set of all functions that are in a pBlock */
8184 /* (note - I expect this to change because I'm planning to limit */
8185 /* pBlock's to just one function declaration */
8186 /*-----------------------------------------------------------------*/
8187 static pCode *findFunction(char *fname)
8194 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8196 pc = setFirstItem(pb->function_entries);
8199 if((pc->type == PC_FUNCTION) &&
8201 (strcmp(fname, PCF(pc)->fname)==0))
8204 pc = setNextItem(pb->function_entries);
8212 static void MarkUsedRegisters(set *regset)
8217 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8218 // fprintf(stderr, "marking register = %s\t", r1->name);
8219 r2 = pic16_regWithIdx(r1->rIdx);
8220 // fprintf(stderr, "to register = %s\n", r2->name);
8226 static void pBlockStats(FILE *of, pBlock *pb)
8232 if(!pic16_pcode_verbose)return;
8234 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8236 // for now just print the first element of each set
8237 pc = setFirstItem(pb->function_entries);
8239 fprintf(of,";entry: ");
8242 pc = setFirstItem(pb->function_exits);
8244 fprintf(of,";has an exit\n");
8248 pc = setFirstItem(pb->function_calls);
8250 fprintf(of,";functions called:\n");
8253 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8254 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8256 pc = setNextItem(pb->function_calls);
8260 r = setFirstItem(pb->tregisters);
8262 int n = elementsInSet(pb->tregisters);
8264 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8267 fprintf(of, "; %s\n",r->name);
8268 r = setNextItem(pb->tregisters);
8272 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8275 /*-----------------------------------------------------------------*/
8276 /*-----------------------------------------------------------------*/
8278 static void sequencepCode(void)
8284 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8286 pb->seq = GpCodeSequenceNumber+1;
8288 for( pc = pb->pcHead; pc; pc = pc->next)
8289 pc->seq = ++GpCodeSequenceNumber;
8295 /*-----------------------------------------------------------------*/
8296 /*-----------------------------------------------------------------*/
8297 static set *register_usage(pBlock *pb)
8300 set *registers=NULL;
8301 set *registersInCallPath = NULL;
8303 /* check recursion */
8305 pc = setFirstItem(pb->function_entries);
8312 if(pc->type != PC_FUNCTION)
8313 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8315 pc = setFirstItem(pb->function_calls);
8316 for( ; pc; pc = setNextItem(pb->function_calls)) {
8318 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8319 char *dest = pic16_get_op_from_instruction(PCI(pc));
8321 pcn = findFunction(dest);
8323 registersInCallPath = register_usage(pcn->pb);
8325 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8330 pBlockStats(stderr,pb); // debug
8333 // Mark the registers in this block as used.
8335 MarkUsedRegisters(pb->tregisters);
8336 if(registersInCallPath) {
8337 /* registers were used in the functions this pBlock has called */
8338 /* so now, we need to see if these collide with the ones we are */
8341 regs *r1,*r2, *newreg;
8343 DFPRINTF((stderr,"comparing registers\n"));
8345 r1 = setFirstItem(registersInCallPath);
8348 r2 = setFirstItem(pb->tregisters);
8350 while(r2 && (r1->type != REG_STK)) {
8352 if(r2->rIdx == r1->rIdx) {
8353 newreg = pic16_findFreeReg(REG_GPR);
8357 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8361 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8362 r1->rIdx, newreg->rIdx));
8363 r2->rIdx = newreg->rIdx;
8364 //if(r2->name) Safe_free(r2->name);
8366 r2->name = Safe_strdup(newreg->name);
8370 newreg->wasUsed = 1;
8372 r2 = setNextItem(pb->tregisters);
8375 r1 = setNextItem(registersInCallPath);
8378 /* Collisions have been resolved. Now free the registers in the call path */
8379 r1 = setFirstItem(registersInCallPath);
8381 if(r1->type != REG_STK) {
8382 newreg = pic16_regWithIdx(r1->rIdx);
8385 r1 = setNextItem(registersInCallPath);
8389 // MarkUsedRegisters(pb->registers);
8391 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8394 DFPRINTF((stderr,"returning regs\n"));
8396 DFPRINTF((stderr,"not returning regs\n"));
8398 DFPRINTF((stderr,"pBlock after register optim.\n"));
8399 pBlockStats(stderr,pb); // debug
8405 /*-----------------------------------------------------------------*/
8406 /* pct2 - writes the call tree to a file */
8408 /*-----------------------------------------------------------------*/
8409 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8413 // set *registersInCallPath = NULL;
8419 fprintf(of, "recursive function\n");
8420 return; //recursion ?
8423 pc = setFirstItem(pb->function_entries);
8430 for(i=0;i<indent;i++) // Indentation
8434 if(pc->type == PC_FUNCTION) {
8435 usedstack += PCF(pc)->stackusage;
8436 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8437 } else return; // ???
8440 pc = setFirstItem(pb->function_calls);
8441 for( ; pc; pc = setNextItem(pb->function_calls)) {
8443 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8444 char *dest = pic16_get_op_from_instruction(PCI(pc));
8446 pcn = findFunction(dest);
8448 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8450 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8458 /*-----------------------------------------------------------------*/
8459 /* pic16_printCallTree - writes the call tree to a file */
8461 /*-----------------------------------------------------------------*/
8463 void pic16_printCallTree(FILE *of)
8475 fprintf(of, "\npBlock statistics\n");
8476 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8480 fprintf(of,"Call Tree\n");
8481 pbr = the_pFile->functions;
8485 if(!ispCodeFunction(pc))
8486 fprintf(of,"bug in call tree");
8489 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8491 while(pc->next && !ispCodeFunction(pc->next)) {
8493 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8494 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8502 fprintf(of,"\n**************\n\na better call tree\n");
8503 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8508 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8509 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8515 /*-----------------------------------------------------------------*/
8517 /*-----------------------------------------------------------------*/
8519 static void InlineFunction(pBlock *pb)
8527 pc = setFirstItem(pb->function_calls);
8529 for( ; pc; pc = setNextItem(pb->function_calls)) {
8532 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8538 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8540 //fprintf(stderr,"Cool can inline:\n");
8541 //pcn->print(stderr,pcn);
8543 //fprintf(stderr,"recursive call Inline\n");
8544 InlineFunction(pcn->pb);
8545 //fprintf(stderr,"return from recursive call Inline\n");
8548 At this point, *pc points to a CALL mnemonic, and
8549 *pcn points to the function that is being called.
8551 To in-line this call, we need to remove the CALL
8552 and RETURN(s), and link the function pCode in with
8558 /* Remove the CALL */
8562 /* remove callee pBlock from the pBlock linked list */
8563 removepBlock(pcn->pb);
8571 /* Remove the Function pCode */
8572 pct = pic16_findNextInstruction(pcn->next);
8574 /* Link the function with the callee */
8575 pc->next = pcn->next;
8576 pcn->next->prev = pc;
8578 /* Convert the function name into a label */
8580 pbr = Safe_calloc(1,sizeof(pBranch));
8581 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8583 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8584 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8586 /* turn all of the return's except the last into goto's */
8587 /* check case for 2 instruction pBlocks */
8588 pce = pic16_findNextInstruction(pcn->next);
8590 pCode *pce_next = pic16_findNextInstruction(pce->next);
8592 if(pce_next == NULL) {
8593 /* found the last return */
8594 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8596 //fprintf(stderr,"found last return\n");
8597 //pce->print(stderr,pce);
8598 pce->prev->next = pc_call->next;
8599 pc_call->next->prev = pce->prev;
8600 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8610 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8616 /*-----------------------------------------------------------------*/
8618 /*-----------------------------------------------------------------*/
8620 void pic16_InlinepCode(void)
8629 if(!functionInlining)
8632 /* Loop through all of the function definitions and count the
8633 * number of times each one is called */
8634 //fprintf(stderr,"inlining %d\n",__LINE__);
8636 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8638 pc = setFirstItem(pb->function_calls);
8640 for( ; pc; pc = setNextItem(pb->function_calls)) {
8643 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8644 if(pcn && isPCF(pcn)) {
8645 PCF(pcn)->ncalled++;
8648 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8653 //fprintf(stderr,"inlining %d\n",__LINE__);
8655 /* Now, Loop through the function definitions again, but this
8656 * time inline those functions that have only been called once. */
8658 InlineFunction(the_pFile->pbHead);
8659 //fprintf(stderr,"inlining %d\n",__LINE__);
8661 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8666 char *pic_optype_names[]={
8667 "PO_NONE", // No operand e.g. NOP
8668 "PO_W", // The working register (as a destination)
8669 "PO_WREG", // The working register (as a file register)
8670 "PO_STATUS", // The 'STATUS' register
8671 "PO_BSR", // The 'BSR' register
8672 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8674 "PO_INDF0", // The Indirect register
8675 "PO_INTCON", // Interrupt Control register
8676 "PO_GPR_REGISTER", // A general purpose register
8677 "PO_GPR_BIT", // A bit of a general purpose register
8678 "PO_GPR_TEMP", // A general purpose temporary register
8679 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8680 "PO_PCL", // Program counter Low register
8681 "PO_PCLATH", // Program counter Latch high register
8682 "PO_PCLATU", // Program counter Latch upper register
8683 "PO_PRODL", // Product Register Low
8684 "PO_PRODH", // Product Register High
8685 "PO_LITERAL", // A constant
8686 "PO_REL_ADDR", // A relative address
8687 "PO_IMMEDIATE", // (8051 legacy)
8688 "PO_DIR", // Direct memory (8051 legacy)
8689 "PO_CRY", // bit memory (8051 legacy)
8690 "PO_BIT", // bit operand.
8691 "PO_STR", // (8051 legacy)
8693 "PO_WILD" // Wild card operand in peep optimizer
8697 char *dumpPicOptype(PIC_OPTYPE type)
8699 return (pic_optype_names[ type ]);
8703 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8706 #define MAX_COMMON_BANK_SIZE 32
8707 #define FIRST_PSEUDO_BANK_NR 1000
8709 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8710 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8711 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8714 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8717 pseudoBankNr bank; // number assigned to this pseudoBank
8718 unsigned int size; // number of operands assigned to this bank
8719 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8722 /*----------------------------------------------------------------------*/
8723 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8724 /*----------------------------------------------------------------------*/
8725 unsigned int hashSymbol (const char *str)
8727 unsigned int res = 0;
8732 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8739 /*-----------------------------------------------------------------------*/
8740 /* compareSymbol - return 1 iff sym1 equals sym2 */
8741 /*-----------------------------------------------------------------------*/
8742 int compareSymbol (const void *sym1, const void *sym2)
8744 char *s1 = (char*) sym1;
8745 char *s2 = (char*) sym2;
8747 return (strcmp (s1,s2) == 0);
8750 /*-----------------------------------------------------------------------*/
8751 /* comparePre - return 1 iff p1 == p2 */
8752 /*-----------------------------------------------------------------------*/
8753 int comparePtr (const void *p1, const void *p2)
8758 /*----------------------------------------------------------*/
8759 /* getSymbolFromOperand - return a pointer to the symbol in */
8760 /* the given operand and its length */
8761 /*----------------------------------------------------------*/
8762 char *getSymbolFromOperand (char *op, unsigned int *len)
8767 if (!op) return NULL;
8769 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8771 if (*sym == '(') sym++;
8774 while (((*curr >= 'A') && (*curr <= 'Z'))
8775 || ((*curr >= 'a') && (*curr <= 'z'))
8776 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8777 || (*curr == '_')) {
8778 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8786 /*--------------------------------------------------------------------------*/
8787 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8788 /*--------------------------------------------------------------------------*/
8789 char *getSymFromBank (pseudoBankNr bank)
8793 if (bank < 0) return "<INVALID BANK NR>";
8794 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8797 /*-----------------------------------------------------------------------*/
8798 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8799 /* bank number (uses hTab sym2bank), if the */
8800 /* symbol is not yet assigned a pseudo bank it */
8801 /* is assigned one here */
8802 /*-----------------------------------------------------------------------*/
8803 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8805 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8811 hash = hashSymbol (op) % sym2bank->size;
8812 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8813 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8815 if (bank == UNKNOWN_BANK) {
8816 // create a pseudo bank for the operand
8818 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8819 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8820 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8821 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8823 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8831 /*--------------------------------------------------------------------*/
8832 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8833 /*--------------------------------------------------------------------*/
8834 int isBanksel (pCode *pc)
8838 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8839 // BANKSEL <variablename> or MOVLB <banknr>
8840 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8844 // check for inline assembler BANKSELs
8845 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8846 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8847 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8851 // assume pc is no BANKSEL instruction
8855 /*---------------------------------------------------------------------------------*/
8856 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8857 /* This method can not guarantee to find all modifications of the */
8858 /* BSR (e.g. via INDirection registers) but covers all compiler */
8859 /* generated plus some cases. */
8860 /*---------------------------------------------------------------------------------*/
8861 int invalidatesBSR(pCode *pc)
8863 // assembler directives invalidate BSR (well, they might, we don't know)
8864 if (isPCAD(pc)) return 1;
8866 // only ASMDIRs and pCodeInstructions can invalidate BSR
8867 if (!isPCI(pc)) return 0;
8869 // we have a pCodeInstruction
8871 // check for BSR modifying instructions
8872 switch (PCI(pc)->op) {
8876 case POC_RETFIE: // might be used as CALL replacement
8877 case POC_RETLW: // might be used as CALL replacement
8878 case POC_RETURN: // might be used as CALL replacement
8883 default: // other instruction do not change BSR unless BSR is an explicit operand!
8884 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8888 // no change of BSR possible/probable
8892 /*------------------------------------------------------------*/
8893 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8894 /* the symbol referenced in this BANKSEL */
8895 /*------------------------------------------------------------*/
8896 pseudoBankNr getBankFromBanksel (pCode *pc)
8899 int data = (int)NULL;
8901 if (!pc) return INVALID_BANK;
8903 if (isPCAD(pc) && PCAD(pc)->directive) {
8904 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8905 // get symbolname from PCAD(pc)->arg
8906 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8907 sym = PCAD(pc)->arg;
8908 data = getPseudoBankNrFromOperand (sym);
8909 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8910 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8911 // get (literal) bank number from PCAD(pc)->arg
8912 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8913 assert (0 && "not yet implemented - turn off banksel optimization for now");
8915 } else if (isPCI(pc)) {
8916 if (PCI(pc)->op == POC_BANKSEL) {
8917 // get symbolname from PCI(pc)->pcop->name (?)
8918 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8919 sym = PCI(pc)->pcop->name;
8920 data = getPseudoBankNrFromOperand (sym);
8921 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8922 } else if (PCI(pc)->op == POC_MOVLB) {
8923 // get (literal) bank number from PCI(pc)->pcop->name
8924 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8925 assert (0 && "not yet implemented - turn off banksel optimization for now");
8930 // no assigned bank could be found
8931 return UNKNOWN_BANK;
8936 /*------------------------------------------------------------------------------*/
8937 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8938 /*------------------------------------------------------------------------------*/
8939 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8943 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8946 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8947 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8949 if (data->bank != bank)
8956 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8960 /*------------------------------------------------------------------*/
8961 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8962 /* bank is selected at a given pCode */
8963 /*------------------------------------------------------------------*/
8965 /* Create a graph with pseudo banks as its nodes and switches between
8966 * these as edges (with the edge weight representing the absolute
8967 * number of BANKSELs from one to the other).
8968 * Removes redundand BANKSELs instead iff mod == 1.
8969 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8970 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8972 * TODO: check ALL instructions operands if they modify BSR directly...
8974 * pb - the pBlock to annotate
8975 * mod - select either graph creation (0) or BANKSEL removal (1)
8977 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8979 pCode *pc, *pc_next;
8980 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8981 int isBankselect = 0;
8982 unsigned int banksels=0;
8986 pc = pic16_findNextInstruction(pb->pcHead);
8988 isBankselect = isBanksel (pc);
8989 pc_next = pic16_findNextInstruction (pc->next);
8991 if (!hasNoLabel (pc)) {
8992 // we don't know our predecessors -- assume different BSRs
8993 prevBSR = UNKNOWN_BANK;
8994 pseudoBSR = UNKNOWN_BANK;
8995 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8998 // check if this is a BANKSEL instruction
9000 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9001 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9003 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9004 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9005 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9006 pic16_unlinkpCode (pc);
9010 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9015 if (!isBankselect && invalidatesBSR(pc)) {
9016 // check if this instruction invalidates the pseudoBSR
9017 pseudoBSR = UNKNOWN_BANK;
9018 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9021 prevBSR = pseudoBSR;
9028 /*------------------------------------------------------------------------------------*/
9029 /* assignToSameBank - returns 0 on success or an error code */
9030 /* 1 - common bank would be too large */
9031 /* 2 - assignment to fixed (absolute) bank not performed */
9033 /* This functions assumes that unsplittable operands are already assigned to the same */
9034 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
9035 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
9036 /* TODO: Symbols with an abslute address must be handled specially! */
9037 /*------------------------------------------------------------------------------------*/
9038 int assignToSameBank (int bank0, int bank1, int doAbs)
9040 int eff0, eff1, dummy;
9041 pseudoBank *pbank0, *pbank1;
9044 eff0 = getEffectiveBank (bank0);
9045 eff1 = getEffectiveBank (bank1);
9047 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9049 // nothing to do if already same bank
9050 if (eff0 == eff1) return 0;
9052 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9055 // ensure eff0 < eff1
9057 // swap eff0 and eff1
9066 // now assign bank eff1 to bank eff0
9067 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9069 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9070 pbank0->bank = eff0;
9073 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9077 hitem = hTabSearch (coerce, eff1 % coerce->size);
9078 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9079 hitem = hitem->next;
9081 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9084 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9085 pbank0->bank, pbank0->size,
9086 getSymFromBank (eff0), getSymFromBank (eff1));
9090 if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9092 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9093 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9094 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9095 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9099 pbank0->size += pbank1->size;
9101 if (pbank1->ref == 0) Safe_free (pbank1);
9107 hitem->item = pbank0;
9109 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9112 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9117 /*----------------------------------------------------------------*/
9118 /* mergeGraphNodes - combines two nodes into one and modifies all */
9119 /* edges to and from the nodes accordingly */
9120 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9121 /* then also (B,A) must be an edge (possibly with weight 0). */
9122 /*----------------------------------------------------------------*/
9123 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9125 GraphEdge *edge, *backedge, *nextedge;
9129 assert (node1 && node2);
9130 assert (node1 != node2);
9132 // add all edges starting at node2 to node1
9135 nextedge = edge->next;
9137 backedge = getGEdge (node, node2);
9139 backweight = backedge->weight;
9142 // insert edges (node1,node) and (node,node1)
9143 addGEdge2 (node1, node, edge->weight, backweight);
9144 // remove edges (node, node2) and (node2, node)
9145 remGEdge (node2, node);
9146 remGEdge (node, node2);
9150 // now node2 should not be referenced by any other GraphNode...
9151 //remGNode (adj, node2->data, node2->hash);
9154 /*----------------------------------------------------------------*/
9155 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9156 /*----------------------------------------------------------------*/
9157 void showGraph (Graph *g)
9161 pseudoBankNr bankNr;
9168 bankNr = getEffectiveBank (node->hash);
9169 assert (bankNr >= 0);
9170 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9172 bankNr = pbank->bank;
9178 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9181 if (edge->weight > 0)
9182 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9189 /*---------------------------------------------------------------*/
9190 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9191 /*---------------------------------------------------------------*/
9192 void pic16_OptimizeBanksel ()
9194 GraphNode *node, *node1, *node1next;
9197 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9198 GraphEdge *edge, *backedge;
9200 int maxWeight, weight, mergeMore, absMaxWeight;
9201 pseudoBankNr curr0, curr1;
9204 pseudoBankNr bankNr;
9205 char *base_symbol0, *base_symbol1;
9210 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9212 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9214 if (!the_pFile || !the_pFile->pbHead) return;
9216 adj = newGraph (NULL);
9217 sym2bank = newHashTable ( 255 );
9218 bank2sym = newHashTable ( 255 );
9219 coerce = newHashTable ( 255 );
9221 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9222 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9223 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9227 // assign symbols with absolute addresses to their respective bank nrs
9228 set = pic16_fix_udata;
9229 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9230 bankNr = reg->address >> 8;
9231 node = getOrAddGNode (adj, NULL, bankNr);
9232 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9233 assignToSameBank (node->hash, bankNr, 1);
9235 assert (bankNr >= 0);
9236 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9238 pbank = Safe_calloc (1, sizeof (pseudoBank));
9239 pbank->bank = reg->address >> 8; //FIXED_BANK;
9242 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9244 assert (pbank->bank == (reg->address >> 8));
9245 pbank->bank = reg->address >> 8; //FIXED_BANK;
9247 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9252 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9253 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9256 if (node->hash < 0) { node = node->next; continue; }
9257 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9260 if (node1->hash < 0) { node1 = node1->next; continue; }
9261 node1next = node1->next;
9262 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9263 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9264 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9265 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9266 if (assignToSameBank (node->hash, node1->hash, 0)) {
9267 fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9268 assert (0 && "Could not assign a symbol to a bank!");
9270 mergeGraphNodes (node, node1);
9272 if (node->hash < node1->hash)
9273 mergeGraphNodes (node, node1);
9275 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9285 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9286 // assign tightly coupled operands to the same (pseudo) bank
9287 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9295 curr0 = getEffectiveBank (node->hash);
9296 if (curr0 < 0) { node = node->next; continue; }
9299 assert (edge->src == node);
9300 backedge = getGEdge (edge->node, edge->src);
9301 weight = edge->weight + (backedge ? backedge->weight : 0);
9302 curr1 = getEffectiveBank (edge->node->hash);
9303 if (curr1 < 0) { edge = edge->next; continue; }
9305 // merging is only useful if the items are not assigned to the same bank already...
9306 if (curr0 != curr1 && weight > maxWeight) {
9307 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9316 if (maxWeight > 0) {
9318 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9319 max->src->hash, getSymFromBank (max->src->hash),
9320 max->node->hash, getSymFromBank (max->node->hash));
9323 node = getGNode (adj, max->src->data, max->src->hash);
9324 node1 = getGNode (adj, max->node->data, max->node->hash);
9326 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9327 if (max->src->hash < max->node->hash)
9328 mergeGraphNodes (node, node1);
9330 mergeGraphNodes (node1, node);
9332 remGEdge (node, node1);
9333 remGEdge (node1, node);
9344 // remove redundant BANKSELs
9345 //fprintf (stderr, "removing redundant BANKSELs\n");
9346 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9347 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9352 fprintf (stderr, "display graph\n");
9357 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9360 /*** END of stuff belonging to the BANKSEL optimization ***/
9364 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9366 typedef unsigned int symbol_t;
9367 typedef unsigned int valnum_t;
9368 //typedef unsigned int hash_t;
9371 #define INT_TO_PTR(x) (((char *) 0) + (x))
9375 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9379 static unsigned int pic16_df_removed_pcodes = 0;
9380 static unsigned int pic16_df_saved_bytes = 0;
9381 static unsigned int df_findall_sameflow = 0;
9382 static unsigned int df_findall_otherflow = 0;
9383 static unsigned int df_findall_in_vals = 0;
9385 static void pic16_df_stats () {
9387 if (pic16_debug_verbose || pic16_pcode_verbose) {
9388 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9389 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9390 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9394 /* Remove a pCode iff possible:
9395 * - previous pCode is no SKIP
9397 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9398 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9399 pCode *pcprev, *pcnext;
9400 char buf[256], *total=NULL;
9403 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9405 pcprev = pic16_findPrevInstruction (pc->prev);
9406 pcnext = pic16_findNextInstruction (pc->next);
9408 /* if previous instruction is a skip -- do not remove */
9409 if (pcprev && isPCI_SKIP(pcprev)) return 0;
9411 /* move labels to next instruction (if possible) */
9412 if (PCI(pc)->label && !pcnext) return 0;
9414 if (PCI(pc)->label) {
9415 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9416 //pc->print (stderr, pc);
9417 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9418 PCI(pc)->label = NULL;
9421 /* update statistics */
9422 pic16_df_removed_pcodes++;
9423 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9425 /* remove the pCode */
9426 pic16_pCode2str (buf, 256, pc);
9427 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9428 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9429 len = strlen (buf) + strlen (comment) + 10;
9430 total = (char *) Safe_malloc (len);
9431 snprintf (total, len, "%s: %s", comment, buf);
9432 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9436 /* actually unlink it from the pBlock -- also remove from to/from lists */
9437 pic16_pCodeUnlink (pc);
9439 /* remove the pCode -- release registers */
9442 /* report success */
9447 /* ======================================================================== */
9448 /* === SYMBOL HANDLING ==================================================== */
9449 /* ======================================================================== */
9451 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9452 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9453 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9455 /** Calculate a hash for a given string.
9456 * If len == 0 the string is assumed to be NUL terminated. */
9457 static hash_t symbolHash (const char *str, unsigned int len) {
9461 hash = (hash << 2) ^ *str;
9466 hash = (hash << 2) ^ *str;
9473 /** Return 1 iff strings v1 and v2 are identical. */
9474 static int symcmp (const void *v1, const void *v2) {
9475 return !strcmp ((const char *) v1, (const char *) v2);
9478 /** Return 1 iff pointers v1 and v2 are identical. */
9479 static int ptrcmp (const void *v1, const void *v2) {
9483 enum { SPO_WREG=0x1000,
9523 /* Return the unique symbol_t for the given string. */
9524 static symbol_t symFromStr (const char *str) {
9529 if (!map_symToStr) {
9531 map_strToSym = newHashTable (128);
9532 map_symToStr = newHashTable (128);
9534 struct { char *name; symbol_t sym; } predefsyms[] = {
9536 {"STATUS", SPO_STATUS},
9537 {"PRODL", SPO_PRODL},
9538 {"PRODH", SPO_PRODH},
9539 {"INDF0", SPO_INDF0},
9540 {"POSTDEC0", SPO_POSTDEC0},
9541 {"POSTINC0", SPO_POSTINC0},
9542 {"PREINC0", SPO_PREINC0},
9543 {"PLUSW0", SPO_PLUSW0},
9544 {"INDF1", SPO_INDF1},
9545 {"POSTDEC1", SPO_POSTDEC1},
9546 {"POSTINC1", SPO_POSTINC1},
9547 {"PREINC1", SPO_PREINC1},
9548 {"PLUSW1", SPO_PLUSW1},
9549 {"INDF2", SPO_INDF2},
9550 {"POSTDEC2", SPO_POSTDEC2},
9551 {"POSTINC2", SPO_POSTINC2},
9552 {"PREINC2", SPO_PREINC2},
9553 {"PLUSW2", SPO_PLUSW2},
9554 {"STKPTR", SPO_STKPTR},
9559 {"FSR0L", SPO_FSR0L},
9560 {"FSR0H", SPO_FSR0H},
9561 {"FSR1L", SPO_FSR1L},
9562 {"FSR1H", SPO_FSR1H},
9563 {"FSR2L", SPO_FSR2L},
9564 {"FSR2H", SPO_FSR2H},
9566 {"PCLATH", SPO_PCLATH},
9567 {"PCLATU", SPO_PCLATU},
9568 {"TABLAT", SPO_TABLAT},
9569 {"TBLPTRL", SPO_TBLPTRL},
9570 {"TBLPTRH", SPO_TBLPTRH},
9571 {"TBLPTRU", SPO_TBLPTRU},
9575 for (i=0; predefsyms[i].name; i++) {
9578 /* enter new symbol */
9579 sym = predefsyms[i].sym;
9580 name = predefsyms[i].name;
9581 res = Safe_strdup (name);
9582 hash = symbolHash (name, 0);
9584 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9585 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9589 hash = symbolHash (str, 0) % map_strToSym->size;
9591 /* find symbol in table */
9592 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9594 //fprintf (stderr, "found symbol %u for %s\n", sym, str);
9598 /* enter new symbol */
9600 res = Safe_strdup (str);
9602 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9603 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9605 //fprintf (stderr, "created symbol %u for %s\n", sym, res);
9611 static const char *strFromSym (symbol_t sym) {
9612 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9616 /* ======================================================================== */
9617 /* === DEFINITION MAP HANDLING ============================================ */
9618 /* ======================================================================== */
9620 /* A defmap provides information about which symbol is defined by which pCode.
9621 * The most recent definitions are prepended to the list, so that the most
9622 * recent definition can be found by forward scanning the list.
9623 * pc2: MOVFF r0x00, r0x01
9625 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9627 * We attach one defmap to each flow object, and each pCode will occur at
9628 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9629 * used to find definitions for a pCode in its own defmap that precede pCode.
9632 typedef struct defmap_s {
9633 symbol_t sym; /** symbol this item refers to */
9636 unsigned int in_mask:8; /** mask leaving in accessed bits */
9637 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9638 int isRead:1; /** sym/mask is read */
9639 int isWrite:1; /** sym/mask is written */
9643 pCode *pc; /** pCode this symbol is refrenced at */
9644 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9645 valnum_t val; /** new unique number for this value (if isWrite) */
9646 struct defmap_s *prev, *next; /** link to previous an next definition */
9649 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9650 static int defmap_free_count = 0; /** number of released defmap items */
9652 /* Returns a defmap_t with the specified data; this will be the new list head.
9653 * next - pointer to the current list head */
9654 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9659 defmap_free = map->next;
9660 --defmap_free_count;
9662 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9665 map->access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9666 map->access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9667 map->access.isRead = (isRead != 0);
9668 map->access.isWrite = (isWrite != 0);
9671 map->val = (isWrite ? val : 0);
9674 if (next) next->prev = map;
9679 /* Returns a copy of the single defmap item. */
9680 static defmap_t *copyDefmap (defmap_t *map) {
9681 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9682 memcpy (res, map, sizeof (defmap_t));
9688 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9689 * item is copied before insertion into chain and therefore left untouched.
9690 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9691 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9694 while (dummy && (dummy->sym != item->sym
9695 || dummy->pc != item->pc
9696 || dummy->accessmethod != item->accessmethod
9697 || dummy->val != item->val
9698 || dummy->in_val != item->in_val)) {
9699 dummy = dummy->next;
9702 /* item already present? */
9703 if (dummy) return 0;
9705 /* otherwise: insert copy of item */
9706 dummy = copyDefmap (item);
9707 dummy->next = *head;
9708 if (*head) (*head)->prev = dummy;
9714 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9715 static void deleteDefmap (defmap_t *map) {
9718 /* unlink from chain -- fails for the first item (head is not updated!) */
9719 if (map->next) map->next->prev = map->prev;
9720 if (map->prev) map->prev->next = map->next;
9723 memset (map, 0, sizeof (defmap_t));
9725 /* save for future use */
9726 map->next = defmap_free;
9728 ++defmap_free_count;
9731 /* Release all defmaps referenced from map. */
9732 static void deleteDefmapChain (defmap_t **_map) {
9733 defmap_t *map, *next;
9739 /* find list head */
9740 while (map && map->prev) map = map->prev;
9742 /* delete all items */
9752 /* Free all defmap items. */
9753 static void freeDefmap (defmap_t **_map) {
9761 /* find list head */
9762 while (map->prev) map = map->prev;
9764 /* release all items */
9774 /* Returns the most recent definition for the given symbol preceeding pc.
9775 * If no definition is found, NULL is returned.
9776 * If pc == NULL the whole list is scanned. */
9777 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9778 defmap_t *curr = map;
9781 /* skip all definitions up to pc */
9782 while (curr && (curr->pc != pc)) curr = curr->next;
9784 /* pc not in the list -- scan the whole list for definitions */
9786 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9789 /* skip all definitions performed by pc */
9790 while (curr && (curr->pc == pc)) curr = curr->next;
9794 /* find definition for sym */
9795 while (curr && (!curr->access.isWrite || (curr->sym != sym))) {
9803 /* Returns the first use (read) of the given symbol AFTER pc.
9804 * If no such use is found, NULL is returned.
9805 * If pc == NULL the whole list is scanned. */
9806 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9807 defmap_t *curr = map, *prev = NULL;
9810 /* skip all definitions up to pc */
9811 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9813 /* pc not in the list -- scan the whole list for definitions */
9815 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9819 /* find end of list */
9820 while (curr && curr->next) curr = curr->next;
9823 /* find use of sym (scan list backwards) */
9824 while (curr && (!curr->access.isRead || (curr->sym != sym))) curr = curr->prev;
9830 /* Return the defmap entry for sym AT pc.
9831 * If none is found, NULL is returned.
9832 * If more than one entry is found an assertion is triggered. */
9833 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9834 defmap_t *res = NULL;
9836 /* find entries for pc */
9837 while (map && map->pc != pc) map = map->next;
9839 /* find first entry for sym @ pc */
9840 while (map && map->pc == pc && map->sym != sym) map = map->next;
9842 /* no entry found */
9843 if (!map) return NULL;
9845 /* check for more entries */
9848 while (map && map->pc == pc) {
9849 /* more than one entry for sym @ pc found? */
9850 assert (map->sym != sym);
9854 /* return single entry for sym @ pc */
9858 /* Modifies the definition of sym at pCode to newval.
9859 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9861 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9864 /* find definitions of pc */
9865 while (m && m->pc != pc) m = m->next;
9867 /* find definition of sym at pc */
9868 while (m && m->pc == pc && (!m->access.isWrite || (m->sym != sym))) m = m->next;
9870 /* no definition found */
9876 /* update following uses of sym */
9877 while (m && m->pc == pc) m = m->prev;
9879 if (m->sym == sym) {
9881 if (m->access.isWrite) m = NULL;
9889 /* ======================================================================== */
9890 /* === STACK ROUTINES ===================================================== */
9891 /* ======================================================================== */
9893 typedef struct stack_s {
9895 struct stack_s *next;
9898 typedef stackitem_t *stack_t;
9899 static stackitem_t *free_stackitems = NULL;
9901 /* Create a stack with one item. */
9902 static stack_t *newStack () {
9903 stack_t *s = (stack_t *) Safe_malloc (sizeof (stack_t));
9908 /* Remove a stack -- its items are only marked free. */
9909 static void deleteStack (stack_t *s) {
9915 i->next = free_stackitems;
9916 free_stackitems = i;
9921 /* Release all stackitems. */
9922 static void releaseStack () {
9925 while (free_stackitems) {
9926 i = free_stackitems->next;
9927 Safe_free(free_stackitems);
9928 free_stackitems = i;
9932 static void stackPush (stack_t *stack, void *data) {
9935 if (free_stackitems) {
9936 i = free_stackitems;
9937 free_stackitems = free_stackitems->next;
9939 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9946 static void *stackPop (stack_t *stack) {
9950 if (stack && *stack) {
9951 data = (*stack)->data;
9953 *stack = (*stack)->next;
9954 i->next = free_stackitems;
9955 free_stackitems = i;
9963 static int stackContains (stack_t *s, void *data) {
9968 if (i->data == data) return 1;
9977 static int stackIsEmpty (stack_t *s) {
9978 return (*s == NULL);
9987 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9988 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9990 s->lastdef = lastdef;
9994 static void deleteState (state_t *s) {
9998 static int stateIsNew (state_t *state, stack_t *todo, stack_t *done) {
10001 /* scan working list for state */
10005 /* is i == state? -- state not new */
10006 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10014 /* is i == state? -- state not new */
10015 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10020 /* not found -- state is new */
10024 static inline valnum_t newValnum ();
10026 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10029 if (!pb) return "<unknown function>";
10031 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10032 if (pc && isPCF(pc)) return PCF(pc)->fname;
10033 else return "<unknown function>";
10036 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10040 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10042 /* find initial value (assigning pc == NULL) */
10043 map = PCFL(pcfl)->in_vals;
10044 while (map && map->sym != sym) map = map->next;
10046 /* initial value already present? */
10048 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10052 /* create a new initial value */
10053 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10054 PCFL(pcfl)->in_vals = map;
10055 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10059 /* insert map as last item in pcfl's defmap */
10060 if (!prev) prev = PCFL(pcfl)->defmap;
10062 PCFL(pcfl)->defmap = map;
10064 while (prev->next) prev = prev->next;
10073 /* Find all reaching definitions for sym at pc.
10074 * A new (!) list of definitions is returned.
10075 * Returns the number of reaching definitions found.
10076 * The defining defmap entries are returned in *chain.
10078 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10083 pCodeFlowLink *succ;
10085 stack_t *todo; /** stack of state_t */
10086 stack_t *done; /** stack of state_t */
10088 int firstState, n_defs;
10090 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10093 /* initialize return list */
10096 /* wildcard symbol? */
10097 if (!sym) return 0;
10099 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10101 map = PCI(pc)->pcflow->defmap;
10103 res = defmapFindDef (map, sym, pc);
10104 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10106 #define USE_PRECALCED_INVALS 1
10107 #if USE_PRECALCED_INVALS
10108 if (!res && PCI(pc)->pcflow->in_vals) {
10109 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10111 //fprintf (stderr, "found def in init values\n");
10112 df_findall_in_vals++;
10118 // found a single definition (in pc's flow)
10119 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10120 defmapAddCopyIfNew (chain, res);
10121 df_findall_sameflow++;
10125 #if USE_PRECALCED_INVALS
10127 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10133 #define FORWARD_FLOW_ANALYSIS 1
10134 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10135 /* no definition found in pc's flow preceeding pc */
10136 todo = newStack ();
10137 done = newStack ();
10138 n_defs = 0; firstState = 1;
10139 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10141 while (!stackIsEmpty (todo)) {
10142 state = (state_t *) stackPop (todo);
10143 stackPush (done, state);
10144 curr = state->flow;
10145 res = state->lastdef;
10146 //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);
10148 /* there are no definitions BEFORE pc in pc's flow (see above) */
10149 if (curr == PCI(pc)->pcflow) {
10151 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10152 res = pic16_pBlockAddInval (pc->pb, sym);
10153 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10156 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10157 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10161 /* save last definition of sym in this flow as initial def in successors */
10162 res = defmapFindDef (curr->defmap, sym, NULL);
10163 if (!res) res = state->lastdef;
10165 /* add successors to working list */
10166 state = newState (NULL, NULL);
10167 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10169 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10170 state->flow = succ->pcflow;
10171 state->lastdef = res;
10172 if (stateIsNew (state, todo, done)) {
10173 stackPush (todo, state);
10174 state = newState (NULL, NULL);
10176 succ = (pCodeFlowLink *) setNextItem (curr->to);
10178 deleteState (state);
10181 #else // !FORWARD_FLOW_ANALYSIS
10183 /* no definition found in pc's flow preceeding pc */
10184 todo = newStack ();
10185 done = newStack ();
10186 n_defs = 0; firstState = 1;
10187 stackPush (todo, newState (PCI(pc)->pcflow, res));
10189 while (!stackIsEmpty (todo)) {
10190 state = (state_t *) stackPop (todo);
10191 curr = state->flow;
10195 /* only check predecessor flows */
10197 /* get (last) definition of sym in this flow */
10198 res = defmapFindDef (curr->defmap, sym, NULL);
10202 /* definition found */
10203 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10204 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10206 /* no definition found -- check predecessor flows */
10207 state = newState (NULL, NULL);
10208 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10210 /* if no flow predecessor available -- sym might be uninitialized */
10212 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10213 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10214 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10215 deleteDefmap (res); res = NULL;
10219 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10220 state->flow = succ->pcflow;
10221 state->lastdef = res;
10222 if (stateIsNew (state, todo, done)) {
10223 stackPush (todo, state);
10224 state = newState (NULL, NULL);
10226 succ = (pCodeFlowLink *) setNextItem (curr->from);
10228 deleteState (state);
10234 /* clean up done stack */
10235 while (!stackIsEmpty(done)) {
10236 deleteState ((state_t *) stackPop (done));
10238 deleteStack (done);
10240 /* return number of items in result set */
10242 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10243 } else if (n_defs == 1) {
10245 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10246 } else if (n_defs > 0) {
10247 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10251 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10256 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10257 df_findall_otherflow++;
10261 /* ======================================================================== */
10262 /* === VALUE NUMBER HANDLING ============================================== */
10263 /* ======================================================================== */
10265 static valnum_t nextValnum = 0x1000;
10266 static hTab *map_symToValnum = NULL;
10268 /** Return a new value number. */
10269 static inline valnum_t newValnum () {
10270 return (nextValnum += 4);
10273 static valnum_t valnumFromStr (const char *str) {
10278 sym = symFromStr (str);
10280 if (!map_symToValnum) {
10281 map_symToValnum = newHashTable (128);
10284 /* literal already known? */
10285 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10287 /* return existing valnum */
10288 if (res) return (valnum_t) PTR_TO_INT(res);
10290 /* create new valnum */
10292 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10296 /* Create a valnum for a literal. */
10297 static valnum_t valnumFromLit (unsigned int lit) {
10298 return ((valnum_t) 0x100 + (lit & 0x0FF));
10301 /* Return the (positive) literal value represented by val
10302 * or -1 iff val is no known literal's valnum. */
10303 static int litFromValnum (valnum_t val) {
10304 if (val >= 0x100 && val < 0x200) {
10305 /* valnum is a (known) literal */
10306 return val & 0x00FF;
10308 /* valnum is not a known literal */
10314 /* Sanity check - all flows in a block must be reachable from initial flow. */
10315 static int verifyAllFlowsReachable (pBlock *pb) {
10321 pCodeFlowLink *succ;
10324 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10327 flowInBlock = NULL;
10329 /* mark initial flow as reached (and "not needs to be reached") */
10330 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10332 addSetHead (&reached, pc);
10333 addSetHead (&checked, pc);
10335 /* mark all further flows in block as "need to be reached" */
10338 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10339 pc = pic16_findNextInstruction (pc->next);
10342 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10343 /* mark as reached and "not need to be reached" */
10344 deleteSetItem (&reached, pcfl);
10345 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10347 /* flow is no longer considered unreachable */
10348 deleteSetItem (&flowInBlock, pcfl);
10350 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10351 if (!isinSet (checked, succ->pcflow)) {
10352 /* flow has never been reached before */
10353 addSetHead (&reached, succ->pcflow);
10354 addSetHead (&checked, succ->pcflow);
10359 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10361 /* by now every flow should have been reached
10362 * --> flowInBlock should be empty */
10363 res = (flowInBlock == NULL);
10367 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10368 while (flowInBlock) {
10369 pcfl = indexSet (flowInBlock, 0);
10370 fprintf (stderr, "not reached: flow %p\n", pcfl);
10371 deleteSetItem (&flowInBlock, pcfl);
10377 deleteSet (&reached);
10378 deleteSet (&flowInBlock);
10379 deleteSet (&checked);
10381 /* if we reached every flow, succ is NULL by now... */
10382 //assert (res); // will fire on unreachable code...
10387 /* Checks a flow for accesses to sym AFTER pc.
10389 * Returns -1 if the symbol is read in this flow (before redefinition),
10390 * returns 0 if the symbol is redefined in this flow or
10391 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10393 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10394 defmap_t *map, *mappc;
10396 /* find pc or start of definitions */
10397 map = pcfl->defmap;
10398 while (map && (map->pc != pc) && map->next) map = map->next;
10399 /* if we found pc -- ignore it */
10400 while (map && map->pc == pc) map = map->prev;
10402 /* scan list backwards (first definition first) */
10403 while (map && mask) {
10404 // if (map->sym == sym) {
10405 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10407 /* scan list for reads at this pc first */
10408 while (map && map->pc == mappc->pc) {
10409 /* is the symbol (partially) read? */
10410 if ((map->sym == sym) && (map->access.isRead && ((map->access.in_mask & mask) != 0))) {
10411 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10418 while (map && map->pc == mappc->pc) {
10419 /* honor (partial) redefinitions of sym */
10420 if ((map->sym == sym) && (map->access.isWrite)) {
10421 mask &= ~map->access.mask;
10422 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10427 /* map already points to the first defmap for the next pCode */
10428 //map = mappc->prev;
10431 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10432 * is still alive; return the appropriate mask of alive bits */
10436 /* Check whether a symbol is alive (AFTER pc). */
10437 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10440 stack_t *todo, *done;
10443 pCodeFlowLink *succ;
10447 assert (isPCI(pc));
10448 pcfl = PCI(pc)->pcflow;
10449 map = pcfl->defmap;
10451 todo = newStack ();
10452 done = newStack ();
10454 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10455 stackPush (todo, state);
10458 while (!stackIsEmpty (todo)) {
10459 state = (state_t *) stackPop (todo);
10460 pcfl = state->flow;
10461 mask = PTR_TO_INT(state->lastdef);
10462 if (visit) stackPush (done, state); else deleteState(state);
10463 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10464 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10465 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10468 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10469 if (mask == 0) continue;
10471 /* symbol is (partially) read before redefinition in flow */
10472 if (mask == -1) break;
10474 /* symbol is neither read nor completely redefined -- check successor flows */
10475 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10476 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10477 if (stateIsNew (state, todo, done)) {
10478 stackPush (todo, state);
10480 deleteState (state);
10485 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10486 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10488 /* symbol is read in at least one flow -- is alive */
10489 if (mask == -1) return 1;
10491 /* symbol is read in no flow */
10495 /* Returns whether access to the given symbol has side effects. */
10496 static int pic16_symIsSpecial (symbol_t sym) {
10497 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10517 /* no special effects known */
10524 /* Check whether a register should be considered local (to the current function) or not. */
10525 static int pic16_regIsLocal (regs *r) {
10528 sym = symFromStr (r->name);
10531 case SPO_FSR0L: // used in ptrget/ptrput
10532 case SPO_FSR0H: // ... as well
10533 case SPO_FSR1L: // used as stack pointer...
10534 case SPO_FSR1H: // ... as well
10535 case SPO_FSR2L: // used as frame pointer
10536 case SPO_FSR2H: // ... as well
10537 case SPO_PRODL: // used to return values from functions
10538 case SPO_PRODH: // ... as well
10539 /* these registers (and some more...) are considered local */
10543 /* for unknown regs: check is marked local, leave if not */
10547 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10553 /* if in doubt, assume non-local... */
10557 /* Check all symbols touched by pc whether their newly assigned values are read.
10558 * Returns 0 if no symbol is used later on, 1 otherwise. */
10559 static int pic16_pCodeIsAlive (pCode *pc) {
10560 pCodeInstruction *pci;
10561 defmap_t *map, *lastpc;
10564 /* we can only handle PCIs */
10565 if (!isPCI(pc)) return 1;
10567 //pc->print (stderr, pc);
10570 assert (pci && pci->pcflow && pci->pcflow->defmap);
10572 /* NEVER remove instructions with implicit side effects */
10575 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10576 case POC_TBLRD_POSTDEC:
10577 case POC_TBLRD_PREINC:
10578 case POC_TBLWT: /* modify program memory */
10579 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10580 case POC_TBLWT_POSTDEC:
10581 case POC_TBLWT_PREINC:
10582 case POC_CLRWDT: /* clear watchdog timer */
10583 case POC_PUSH: /* should be safe to remove though... */
10584 case POC_POP: /* should be safe to remove though... */
10589 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10593 /* no special instruction */
10597 /* prevent us from removing assignments to non-local variables */
10599 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10600 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10602 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10603 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10604 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10605 //pc->print (stderr, pc);
10608 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10609 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10614 /* OVERKILL: prevent us from removing reads from non-local variables
10615 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10616 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10618 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10619 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10621 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10622 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10623 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10624 //pc->print (stderr, pc);
10627 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10628 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10633 /* now check that the defined symbols are not used */
10634 map = pci->pcflow->defmap;
10636 /* find items for pc */
10637 while (map && map->pc != pc) map = map->next;
10639 /* no entries found? something is fishy with DF analysis... -- play safe */
10640 if (!map) { fprintf (stderr, "%s: defmap not found\n", __FUNCTION__); return 1; }
10642 /* remember first item assigned to pc for later use */
10645 /* check all symbols being modified by pc */
10646 while (map && map->pc == pc) {
10647 if (map->sym == 0) { map = map->next; continue; }
10649 /* keep pc if it references special symbols (like POSTDEC0) */
10653 pic16_pCode2str (buf, 256, pc);
10654 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10657 if (pic16_symIsSpecial (map->sym)) {
10658 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10661 if (map->access.isWrite) {
10662 if (pic16_isAlive (map->sym, pc)) {
10663 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10670 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10674 pic16_pCode2str (buf, 256, pc);
10675 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10681 /* Adds implied operands to the list.
10682 * sym - operand being accessed in the pCode
10683 * list - list to append the operand
10684 * isRead - set to 1 iff sym is read in pCode
10685 * listRead - set to 1 iff all operands being read are to be listed
10687 * Returns 0 for "normal" operands, 1 for special operands.
10689 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10690 /* check whether accessing REG accesses other REGs as well */
10694 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10695 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10696 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10700 /* reads FSR0x and WREG */
10701 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10702 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10703 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10704 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10710 /* reads/modifies FSR0x */
10711 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10712 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10713 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10718 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10719 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10720 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10724 /* reads FSR1x and WREG */
10725 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10726 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10727 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10728 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10734 /* reads/modifies FSR1x */
10735 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10736 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10737 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10742 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10743 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10744 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10748 /* reads FSR2x and WREG */
10749 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10750 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10751 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10752 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10758 /* reads/modifies FSR2x */
10759 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10760 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10761 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10765 /* modifies PCLATH and PCLATU */
10766 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10768 /* reading PCL updates PCLATx */
10769 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10770 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10773 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10774 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10775 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10780 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10781 /* nothing special */
10786 /* has been a special operand */
10790 static symbol_t pic16_fsrsym_idx[][2] = {
10791 {SPO_FSR0L, SPO_FSR0H},
10792 {SPO_FSR1L, SPO_FSR1H},
10793 {SPO_FSR2L, SPO_FSR2H}
10796 /** Prepend list with the reads and definitions performed by pc. */
10797 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10798 pCodeInstruction *pci;
10799 int cond, inCond, outCond;
10800 int mask = 0xff, smask;
10801 int isSpecial, isSpecial2;
10802 symbol_t sym, sym2;
10806 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10807 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10808 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10809 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10812 assert (isPCI(pc));
10815 /* handle bit instructions */
10816 if (pci->isBitInst) {
10817 assert (pci->pcop->type == PO_GPR_BIT);
10818 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10821 /* handle (additional) implicit arguments */
10827 lit = PCOL(pci->pcop)->lit;
10828 assert (lit >= 0 && lit < 3);
10829 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, ((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10830 val = valnumFromStr (((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10831 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10832 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10833 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...
10837 case POC_MOVLB: // BSR
10838 case POC_BANKSEL: // BSR
10839 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10842 case POC_MULWF: // PRODx
10843 case POC_MULLW: // PRODx
10844 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10845 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10848 case POC_POP: // TOS, STKPTR
10849 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10850 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10851 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10852 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10855 case POC_PUSH: // STKPTR
10856 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10857 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10858 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10859 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10862 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10863 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10864 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10865 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10866 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10867 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10870 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10871 /* pseudo read on (possible) return values */
10872 // WREG is handled below via outCond
10873 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10874 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10875 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10878 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10879 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10880 /* pseudo read on (possible) return values */
10881 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10882 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10883 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10884 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10886 /* caller's stack pointers must be restored */
10887 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10888 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10889 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10890 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10894 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10895 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10896 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10897 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10900 case POC_TBLRD_POSTINC:
10901 case POC_TBLRD_POSTDEC:
10902 case POC_TBLRD_PREINC:
10903 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10904 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10905 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10906 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10910 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10911 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10912 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10913 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10916 case POC_TBLWT_POSTINC:
10917 case POC_TBLWT_POSTDEC:
10918 case POC_TBLWT_PREINC:
10919 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10920 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10921 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10922 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10926 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10930 /* handle explicit arguments */
10931 inCond = pci->inCond;
10932 outCond = pci->outCond;
10933 cond = inCond | outCond;
10934 if (cond & PCC_W) {
10935 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10938 /* keep STATUS read BEFORE STATUS write in the list */
10939 if (inCond & PCC_STATUS) {
10941 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10942 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10943 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10944 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10945 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10947 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10948 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10951 if (outCond & PCC_STATUS) {
10953 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10954 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10955 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10956 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10957 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
10959 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
10960 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10963 isSpecial = isSpecial2 = 0;
10965 if (cond & PCC_REGISTER) {
10966 name = pic16_get_op (pci->pcop, NULL, 0);
10967 sym = symFromStr (name);
10968 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
10969 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
10972 if (cond & PCC_REGISTER2) {
10973 name = pic16_get_op2 (pci->pcop, NULL, 0);
10974 sym2 = symFromStr (name);
10975 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
10976 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
10980 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10981 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
10987 static void printDefmap (defmap_t *map) {
10991 fprintf (stderr, "defmap @ %p:\n", curr);
10993 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
10994 curr->access.isRead ? "R" : " ",
10995 curr->access.isWrite ? "W": " ",
10996 curr->in_val, curr->val,
10997 curr->access.in_mask, curr->access.mask,
10998 strFromSym(curr->sym), curr->sym,
11002 fprintf (stderr, "<EOL>\n");
11006 /* Add "additional" definitions to uniq.
11007 * 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.
11008 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11010 * If symbols defined in additional are not present in uniq, a definition is created.
11011 * Otherwise the present definition is altered to reflect the newer assignments.
11013 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11014 * before `------- noted in additional --------' after
11016 * I assume that each symbol occurs AT MOST ONCE in uniq.
11019 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11024 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11025 /* find tail of additional list (holds the first assignment) */
11027 while (curr && curr->next) curr = curr->next;
11031 /* find next assignment in additionals */
11032 while (curr && !curr->access.isWrite) curr = curr->prev;
11036 /* find item in uniq */
11038 //printDefmap (*uniq);
11039 while (old && (old->sym != curr->sym)) old = old->next;
11042 /* definition found -- replace */
11043 if (old->val != curr->val) {
11044 old->val = curr->val;
11048 /* new definition */
11049 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11056 /* return 0 iff uniq remained unchanged */
11060 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11061 * lists of its predecessor flows.
11062 * Initially *combined should be NULL, alt_in will be copied to combined.
11063 * If *combined != NULL, combined will be altered:
11064 * - for symbols defined in *combined but not in alt_in,
11065 * *combined is altered to 0 (value unknown, either *combined or INIT).
11066 * - for symbols defined in alt_in but not in *combined,
11067 * a 0 definition is created (value unknown, either INIT or alt).
11068 * - for symbols defined in both, *combined is:
11069 * > left unchanged if *combined->val == alt_in->val or
11070 * > modified to 0 otherwise (value unknown, either alt or *combined).
11072 * I assume that each symbol occurs AT MOST ONCE in each list!
11074 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11080 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11082 if (!(*combined)) {
11083 return defmapUpdateUniqueSym (combined, alt_in);
11086 /* merge the two */
11089 /* find symbols definition in *combined */
11091 while (old && (old->sym != curr->sym)) old = old->next;
11094 /* definition found */
11095 if (old->val && (old->val != curr->val)) {
11096 old->val = 0; /* value unknown */
11100 /* no definition found -- can be either INIT or alt_in's value */
11101 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11102 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11103 if (val != curr->val) change++;
11109 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11112 if (old->val != 0) {
11113 /* find definition in alt_in */
11115 while (curr && curr->sym != old->sym) curr = curr->next;
11117 /* symbol defined in *combined only -- can be either INIT or *combined */
11118 val = pic16_pBlockAddInval (pb, old->sym)->val;
11119 if (old->val != val) {
11132 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11133 defmap_t *curr1, *curr2;
11136 /* identical maps are equal */
11137 if (map1 == map2) return 0;
11139 if (!map1) return -1;
11140 if (!map2) return 1;
11142 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11147 while (curr1 && curr2) {
11148 curr1 = curr1->next;
11149 curr2 = curr2->next;
11152 /* one of them longer? */
11153 if (curr1) return 1;
11154 if (curr2) return -1;
11156 /* both lists are of equal length -- compare (in O(n^2)) */
11161 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11162 if (!curr2) return 1; // symbol not found in curr2
11163 if (curr2->val != curr1->val) return 1; // values differ
11165 /* compare next symbol */
11166 curr1 = curr1->next;
11169 /* no difference found */
11174 /* Prepare a list of all reaching definitions per flow.
11175 * This is done using a forward dataflow analysis.
11177 static void createReachingDefinitions (pBlock *pb) {
11178 defmap_t *out_vals, *in_vals;
11181 pCodeFlowLink *link;
11185 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11186 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11188 deleteDefmapChain (&PCFL(pc)->in_vals);
11189 deleteDefmapChain (&PCFL(pc)->out_vals);
11190 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11194 pc = pic16_findNextInstruction (pb->pcHead);
11195 todo = NULL; blacklist = NULL;
11196 addSetHead (&todo, PCI(pc)->pcflow);
11198 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11199 while (elementsInSet (todo)) {
11200 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11201 pcfl = PCFL(indexSet (todo, 0));
11202 deleteSetItem (&todo, pcfl);
11203 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11207 if (isinSet (blacklist, pcfl)) {
11208 fprintf (stderr, "ignoring blacklisted flow\n");
11212 /* create in_vals from predecessors out_vals */
11213 link = setFirstItem (pcfl->from);
11215 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11216 link = setNextItem (pcfl->from);
11219 //printDefmap (in_vals);
11220 //printDefmap (pcfl->in_vals);
11222 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11223 //fprintf (stderr, "in_vals changed\n");
11224 /* in_vals changed -- update out_vals */
11225 deleteDefmapChain (&pcfl->in_vals);
11226 pcfl->in_vals = in_vals;
11228 /* create out_val from in_val and defmap */
11230 defmapUpdateUniqueSym (&out_vals, in_vals);
11231 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11233 /* is out_vals different from pcfl->out_vals */
11234 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11235 //fprintf (stderr, "out_vals changed\n");
11236 deleteDefmapChain (&pcfl->out_vals);
11237 pcfl->out_vals = out_vals;
11239 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11240 addSet (&blacklist, pcfl);
11243 /* reschedule all successors */
11244 link = setFirstItem (pcfl->to);
11246 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11247 addSetIfnotP (&todo, link->pcflow);
11248 link = setNextItem (pcfl->to);
11251 deleteDefmapChain (&out_vals);
11254 deleteDefmapChain (&in_vals);
11260 static void showAllDefs (symbol_t sym, pCode *pc) {
11264 assert (isPCI(pc));
11265 count = defmapFindAll (sym, pc, &map);
11267 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11270 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11273 pic16_pCode2str (buf, 256, map->pc);
11274 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11278 deleteDefmapChain (&map);
11282 /* safepCodeUnlink and remove pc from defmap. */
11283 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11284 defmap_t *map, *next, **head;
11288 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11289 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11290 res = pic16_safepCodeUnlink (pc, comment);
11293 /* remove pc from defmap */
11296 if (map->pc == pc) {
11297 if (!map->prev && head) *head = map->next;
11298 deleteDefmap (map);
11307 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11309 /* This breaks the defmap chain's references to pCodes... fix it! */
11310 map = PCI(pc)->pcflow->defmap;
11312 while (map && map->pc != pc) map = map->next;
11314 while (map && map->pc == pc) {
11320 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym) {
11322 if (!isPCI(pc)) return;
11324 map = PCI(pc)->pcflow->defmap;
11326 while (map && map->pc != pc) map = map->next;
11327 while (map && map->pc == pc) {
11328 if (map->sym == sym) map->sym = newsym;
11333 /* Assign "better" valnums to results. */
11334 static void assignValnums (pCode *pc) {
11335 pCodeInstruction *pci;
11337 symbol_t sym1, sym2;
11338 int cond, isSpecial1, isSpecial2, count, mask, lit;
11339 defmap_t *list, *val, *oldval, *dummy;
11340 regs *reg1 = NULL, *reg2 = NULL;
11343 /* only works for pCodeInstructions... */
11344 if (!isPCI(pc)) return;
11347 cond = pci->inCond | pci->outCond;
11348 list = pci->pcflow->defmap;
11349 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11351 if (cond & PCC_REGISTER) {
11352 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11353 reg1 = pic16_getRegFromInstruction (pc);
11354 isSpecial1 = pic16_symIsSpecial (sym1);
11356 if (cond & PCC_REGISTER2) {
11357 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11358 reg2 = pic16_getRegFromInstruction (pc);
11359 isSpecial2 = pic16_symIsSpecial (sym2);
11362 /* determine input values */
11364 while (val && val->pc != pc) val = val->next;
11365 //list = val; /* might save some time later... */
11366 while (val && val->pc == pc) {
11368 if (val->sym != 0 && (1 || val->access.isRead)) {
11369 /* get valnum for sym */
11370 count = defmapFindAll (val->sym, pc, &oldval);
11371 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11373 if ((val->access.in_mask & oldval->access.mask) == val->access.in_mask) {
11374 val->in_val = oldval->val;
11378 } else if (count == 0) {
11379 /* no definition found */
11382 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11384 dummy = oldval->next;
11385 mask = oldval->access.mask;
11386 val->in_val = oldval->val;
11387 while (dummy && (dummy->val == val->in_val)) {
11388 mask &= dummy->access.mask;
11389 dummy = dummy->next;
11392 /* found other values or to restictive mask */
11393 if (dummy || ((mask & val->access.in_mask) != val->access.in_mask)) {
11397 if (count > 0) deleteDefmapChain (&oldval);
11402 /* handle valnum assignment */
11404 case POC_CLRF: /* modifies STATUS (Z) */
11405 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11406 oldval = defmapCurr (list, sym1, pc);
11407 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11408 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11409 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11411 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11415 case POC_SETF: /* SETF does not touch STATUS */
11416 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11417 oldval = defmapCurr (list, sym1, pc);
11418 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11419 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11420 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11422 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11426 case POC_MOVLW: /* does not touch STATUS */
11427 oldval = defmapCurr (list, SPO_WREG, pc);
11428 if (pci->pcop->type == PO_LITERAL) {
11429 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11430 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11432 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11433 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11435 if (oldval && oldval->in_val == litnum) {
11436 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11437 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11439 defmapUpdate (list, SPO_WREG, pc, litnum);
11442 case POC_ANDLW: /* modifies STATUS (Z,N) */
11443 case POC_IORLW: /* modifies STATUS (Z,N) */
11444 case POC_XORLW: /* modifies STATUS (Z,N) */
11445 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11446 if (pci->pcop->type == PO_LITERAL) {
11447 lit = (unsigned char) PCOL(pci->pcop)->lit;
11449 val = defmapCurr (list, SPO_WREG, pc);
11450 if (val) vallit = litFromValnum (val->in_val);
11451 if (vallit != -1) {
11452 /* xxxLW <literal>, WREG contains a known literal */
11453 fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11454 if (pci->op == POC_ANDLW) {
11456 } else if (pci->op == POC_IORLW) {
11458 } else if (pci->op == POC_XORLW) {
11461 assert (0 && "invalid operation");
11463 if (vallit == lit) {
11464 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11465 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11467 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11474 /* check if old value matches new value */
11477 assert (pci->pcop->type == PO_LITERAL);
11479 lit = PCOL(pci->pcop)->lit;
11481 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11483 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11484 fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11486 /* cannot remove this LFSR */
11490 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11491 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11492 fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11498 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11503 case POC_MOVWF: /* does not touch flags */
11504 /* find value of WREG */
11505 val = defmapCurr (list, SPO_WREG, pc);
11506 oldval = defmapCurr (list, sym1, pc);
11507 if (val) lit = litFromValnum (val->in_val);
11509 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11511 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11512 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11513 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11515 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11517 assert (lit == 0x0ff);
11518 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11520 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11521 pic16_pCodeReplace (pc, newpc);
11522 defmapReplaceSymRef (pc, SPO_WREG, 0);
11523 pic16_fixDefmap (pc, newpc);
11526 /* This breaks the defmap chain's references to pCodes... fix it! */
11527 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11528 deleteDefmap (val); // delete reference to WREG as in value
11530 oldval = PCI(pc)->pcflow->defmap;
11532 if (oldval->pc == pc) oldval->pc = newpc;
11533 oldval = oldval->next;
11535 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11536 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11537 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11539 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11542 case POC_MOVFW: /* modifies STATUS (Z,N) */
11543 /* find value of REG */
11544 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11545 val = defmapCurr (list, sym1, pc);
11546 oldval = defmapCurr (list, SPO_WREG, pc);
11547 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11548 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11549 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11551 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11555 case POC_MOVFF: /* does not touch STATUS */
11556 /* find value of REG */
11557 val = defmapCurr (list, sym1, pc);
11558 oldval = defmapCurr (list, sym2, pc);
11559 if (val) lit = litFromValnum (val->in_val);
11562 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11563 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11565 newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11566 } else if (lit == 0x00ff) {
11567 newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11572 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11573 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11574 pic16_pCodeReplace (pc, newpc);
11575 defmapReplaceSymRef (pc, sym1, 0);
11576 pic16_fixDefmap (pc, newpc);
11578 break; // do not process instruction as MOVFF...
11580 } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) {
11581 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11582 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11583 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11585 if (!pic16_isAlive (sym1, pc)) {
11586 defmap_t *copy = NULL;
11587 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11588 * This should help eliminate
11590 * <do something not changing A or using B>
11592 * <B is not alive anymore>
11594 * <do something not changing A or using B>
11598 /* scan defmap for symbols storing sym1's value */
11599 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11600 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11601 /* unique reaching definition for sym found */
11602 if (copy->val && copy->val == val->in_val) {
11603 //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);
11604 if (copy->sym == SPO_WREG) {
11605 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11607 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11608 // /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop),
11609 pic16_pCodeOpCopy (PCI(copy->pc)->pcop),
11610 pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11612 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11613 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11614 pic16_pCodeReplace (pc, newpc);
11615 assert (val->sym == sym1 && val->access.isRead && !val->access.isWrite);
11616 defmapReplaceSymRef (pc, sym1, copy->sym);
11617 pic16_fixDefmap (pc, newpc);
11621 deleteDefmapChain (©);
11624 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11629 /* cannot optimize */
11634 static void pic16_destructDF (pBlock *pb) {
11637 /* remove old defmaps */
11638 pc = pic16_findNextInstruction (pb->pcHead);
11640 next = pic16_findNextInstruction (pc->next);
11642 assert (isPCI(pc) || isPCAD(pc));
11643 assert (PCI(pc)->pcflow);
11644 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11645 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11646 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11651 if (defmap_free || defmap_free_count) {
11652 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11653 freeDefmap (&defmap_free);
11654 defmap_free_count = 0;
11658 /* Checks whether a pBlock contains ASMDIRs. */
11659 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11662 pc = pic16_findNextInstruction (pb->pcHead);
11664 if (isPCAD(pc)) return 1;
11666 pc = pic16_findNextInstruction (pc->next);
11669 /* no PCADs found */
11674 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11675 static int pic16_removeUnusedRegistersDF () {
11678 regs *reg1, *reg2, *reg3;
11679 set *seenRegs = NULL;
11681 int islocal, change = 0;
11684 if (!the_pFile || !the_pFile->pbHead) return 0;
11686 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11687 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11689 /* find set of using pCodes per register */
11690 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11691 pc = pic16_findNextInstruction(pc->next)) {
11693 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11694 reg1 = reg2 = NULL;
11695 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11696 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11699 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11700 addSetIfnotP (&seenRegs, reg1);
11701 addSetIfnotP (®1->reglives.usedpCodes, pc);
11704 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11705 addSetIfnotP (&seenRegs, reg2);
11706 addSetIfnotP (®2->reglives.usedpCodes, pc);
11710 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11711 /* may not use pic16_regIsLocal() here -- in interrupt routines
11712 * WREG, PRODx, FSR0x must be saved */
11713 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11714 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11716 for (i=0; i < 2; i++) {
11717 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11718 if (!pc2) pc2 = pc;
11719 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11720 reg2 = pic16_getRegFromInstruction (pc);
11721 reg3 = pic16_getRegFromInstruction2 (pc);
11723 || (reg2->rIdx != pic16_stack_preinc->rIdx
11724 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11726 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11727 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11728 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11729 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11733 deleteSet (®1->reglives.usedpCodes);
11736 deleteSet (&seenRegs);
11743 /* Set up pCodeFlow's defmap_ts.
11744 * Needs correctly set up to/from fields. */
11745 static void pic16_createDF (pBlock *pb) {
11749 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11751 pic16_destructDF (pb);
11753 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11754 if (pic16_pBlockHasAsmdirs (pb)) {
11755 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11759 /* integrity check -- we need to reach all flows to guarantee
11760 * correct data flow analysis (reaching definitions, aliveness) */
11762 if (!verifyAllFlowsReachable (pb)) {
11763 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11768 /* establish new defmaps */
11769 pc = pic16_findNextInstruction (pb->pcHead);
11771 next = pic16_findNextInstruction (pc->next);
11773 assert (PCI(pc)->pcflow);
11774 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11779 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11780 createReachingDefinitions (pb);
11783 /* assign better valnums */
11784 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11785 pc = pic16_findNextInstruction (pb->pcHead);
11787 next = pic16_findNextInstruction (pc->next);
11789 assert (PCI(pc)->pcflow);
11790 assignValnums (pc);
11797 /* remove dead pCodes */
11798 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11801 pc = pic16_findNextInstruction (pb->pcHead);
11803 next = pic16_findNextInstruction (pc->next);
11805 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11806 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11816 /* ======================================================================= */
11817 /* === DEPRECATED CONTROL FLOW CREATION ROUTINES ========================= */
11818 /* ======================================================================= */
11822 /* connect pCode f anf t via their to/from pBranches */
11823 static void pic16_pCodeLink (pCode *f, pCode *t) {
11825 pCodeInstruction *_f, *_t;
11827 if (!f || !t) return;
11830 fprintf (stderr, "linking:\n");
11831 f->print(stderr, f);
11832 f->print(stderr, t);
11835 assert (isPCI(f) || isPCAD(f));
11836 assert (isPCI(t) || isPCAD(t));
11840 /* define t to be CF successor of f */
11841 br = Safe_malloc (sizeof (pBranch));
11844 _f->to = pic16_pBranchAppend (_f->to, br);
11846 /* define f to be CF predecessor of t */
11847 br = Safe_malloc (sizeof (pBranch));
11850 _t->from = pic16_pBranchAppend (_t->from, br);
11852 /* also update pcflow information */
11853 if (_f->pcflow && _t->pcflow && _f->pcflow != _t->pcflow) {
11854 //fprintf (stderr, "creating flow %p --> %p\n", _f->pcflow, _t->pcflow);
11855 LinkFlow_pCode (_f, _t);
11859 static void pic16_destructCF (pBlock *pb) {
11863 /* remove old CF information */
11867 while (PCI(pc)->to) {
11868 br = PCI(pc)->to->next;
11869 Safe_free (PCI(pc)->to);
11872 while (PCI(pc)->from) {
11873 br = PCI(pc)->from->next;
11874 Safe_free (PCI(pc)->from);
11875 PCI(pc)->from = br;
11877 } else if (isPCFL(pc)) {
11878 deleteSet (&PCFL(pc)->to);
11879 deleteSet (&PCFL(pc)->from);
11887 /* Set up pCodeInstruction's to and from pBranches. */
11888 static void pic16_createCF (pBlock *pb) {
11890 pCode *next, *dest;
11893 //fprintf (stderr, "creating CF for %p\n", pb);
11895 pic16_destructCF (pb);
11897 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11898 if (pic16_pBlockHasAsmdirs (pb)) {
11899 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11903 pc = pic16_findNextInstruction(pb->pcHead);
11905 next = pic16_findNextInstruction(pc->next);
11906 if (isPCI_SKIP(pc)) {
11907 pic16_pCodeLink(pc, next);
11908 pic16_pCodeLink(pc, pic16_findNextInstruction(next->next));
11909 } else if (isPCI_BRANCH(pc)) {
11910 // Bcc, BRA, CALL, GOTO
11911 if (PCI(pc)->pcop) {
11912 switch (PCI(pc)->pcop->type) {
11914 label = PCOLAB(PCI(pc)->pcop)->pcop.name;
11915 dest = findLabelinpBlock (pc->pb, PCOLAB(PCI(pc)->pcop));
11919 /* needed for GOTO ___irq_handler */
11920 label = PCI(pc)->pcop->name;
11925 assert (0 && "invalid label format");
11933 switch (PCI(pc)->op) {
11936 if (dest != NULL) {
11937 pic16_pCodeLink(pc, dest);
11939 //fprintf (stderr, "jump target \"%s\" not found!\n", label);
11945 pic16_pCodeLink(pc, next);
11955 if (dest != NULL) {
11956 pic16_pCodeLink(pc, dest);
11958 //fprintf (stderr, "jump target \"%s\"not found!\n", label);
11960 pic16_pCodeLink(pc, next);
11963 fprintf (stderr, "BRANCH instruction: %s\n", PCI(pc)->mnemonic);
11964 assert (0 && "unhandled branch instruction");
11968 pic16_pCodeLink (pc, next);
11975 /* ======================================================================== */
11976 /* === VCG DUMPER ROUTINES ================================================ */
11977 /* ======================================================================== */
11978 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11979 hTab *dumpedNodes = NULL;
11981 /** Dump VCG header into of. */
11982 static void pic16_vcg_init (FILE *of) {
11983 /* graph defaults */
11984 fprintf (of, "graph:{\n");
11985 fprintf (of, "title:\"graph1\"\n");
11986 fprintf (of, "label:\"graph1\"\n");
11987 fprintf (of, "color:white\n");
11988 fprintf (of, "textcolor:black\n");
11989 fprintf (of, "bordercolor:black\n");
11990 fprintf (of, "borderwidth:1\n");
11991 fprintf (of, "textmode:center\n");
11993 fprintf (of, "layoutalgorithm:dfs\n");
11994 fprintf (of, "late_edge_labels:yes\n");
11995 fprintf (of, "display_edge_labels:yes\n");
11996 fprintf (of, "dirty_edge_labels:yes\n");
11997 fprintf (of, "finetuning:yes\n");
11998 fprintf (of, "ignoresingles:no\n");
11999 fprintf (of, "straight_phase:yes\n");
12000 fprintf (of, "priority_phase:yes\n");
12001 fprintf (of, "manhattan_edges:yes\n");
12002 fprintf (of, "smanhattan_edges:no\n");
12003 fprintf (of, "nearedges:no\n");
12004 fprintf (of, "node_alignment:center\n"); // bottom|top|center
12005 fprintf (of, "port_sharing:no\n");
12006 fprintf (of, "arrowmode:free\n"); // fixed|free
12007 fprintf (of, "crossingphase2:yes\n");
12008 fprintf (of, "crossingoptimization:yes\n");
12009 fprintf (of, "edges:yes\n");
12010 fprintf (of, "nodes:yes\n");
12011 fprintf (of, "splines:no\n");
12013 /* node defaults */
12014 fprintf (of, "node.color:lightyellow\n");
12015 fprintf (of, "node.textcolor:black\n");
12016 fprintf (of, "node.textmode:center\n");
12017 fprintf (of, "node.shape:box\n");
12018 fprintf (of, "node.bordercolor:black\n");
12019 fprintf (of, "node.borderwidth:1\n");
12021 /* edge defaults */
12022 fprintf (of, "edge.textcolor:black\n");
12023 fprintf (of, "edge.color:black\n");
12024 fprintf (of, "edge.thickness:1\n");
12025 fprintf (of, "edge.arrowcolor:black\n");
12026 fprintf (of, "edge.backarrowcolor:black\n");
12027 fprintf (of, "edge.arrowsize:15\n");
12028 fprintf (of, "edge.backarrowsize:15\n");
12029 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12030 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12031 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12033 fprintf (of, "\n");
12035 /* prepare data structures */
12037 hTabDeleteAll (dumpedNodes);
12038 dumpedNodes = NULL;
12040 dumpedNodes = newHashTable (128);
12043 /** Dump VCG footer into of. */
12044 static void pic16_vcg_close (FILE *of) {
12045 fprintf (of, "}\n");
12048 #define BUF_SIZE 128
12049 #define pcTitle(pc) (snprintf (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12052 static int ptrcmp (const void *p1, const void *p2) {
12057 /** Dump a pCode node as VCG to of. */
12058 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12059 char buf[BUF_SIZE];
12061 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12065 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12066 //fprintf (stderr, "dumping %p\n", pc);
12068 /* only dump pCodeInstructions and Flow nodes */
12069 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12072 fprintf (of, "node:{");
12073 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12074 fprintf (of, "label:\"%s\n", pcTitle(pc));
12076 fprintf (of, "<PCFLOW>");
12077 } else if (isPCI(pc) || isPCAD(pc)) {
12078 pc->print (of, pc);
12080 fprintf (of, "<!PCI>");
12082 fprintf (of, "\" ");
12083 fprintf (of, "}\n");
12085 if (1 && isPCFL(pc)) {
12086 defmap_t *map, *prev;
12088 map = PCFL(pc)->defmap;
12091 if (map->sym != 0) {
12094 /* emit definition node */
12095 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12096 fprintf (of, "label:\"");
12100 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));
12103 } while (map && prev->pc == map->pc);
12106 fprintf (of, "\" ");
12108 fprintf (of, "color:green ");
12109 fprintf (of, "}\n");
12111 /* emit edge to previous definition */
12112 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12114 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12116 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12118 fprintf (of, "color:green ");
12119 fprintf (of, "}\n");
12122 pic16_vcg_dumpnode (map->pc, of);
12123 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12124 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12131 /* emit additional nodes (e.g. operands) */
12134 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12135 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12136 char buf[BUF_SIZE];
12137 pCodeInstruction *pci;
12141 if (1 && isPCFL(pc)) {
12142 /* emit edges to flow successors */
12144 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12145 pcfl = setFirstItem (PCFL(pc)->to);
12147 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12148 pic16_vcg_dumpnode (pc, of);
12149 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12150 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12151 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12152 pcfl = setNextItem (PCFL(pc)->to);
12156 if (!isPCI(pc) && !isPCAD(pc)) return;
12160 /* emit control flow edges (forward only) */
12164 pic16_vcg_dumpnode (curr->pc, of);
12165 fprintf (of, "edge:{");
12166 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12167 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12168 fprintf (of, "color:red ");
12169 fprintf (of, "}\n");
12174 /* dump "flow" edge (link pCode according to pBlock order) */
12177 pcnext = pic16_findNextInstruction (pc->next);
12179 pic16_vcg_dumpnode (pcnext, of);
12180 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12181 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12189 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12190 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12191 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12195 /* emit data flow edges (backward only) */
12196 /* TODO: gather data flow information... */
12199 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12202 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12203 if (pic16_pBlockHasAsmdirs (pb)) {
12204 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12208 for (pc=pb->pcHead; pc; pc = pc->next) {
12209 pic16_vcg_dumpnode (pc, of);
12212 for (pc=pb->pcHead; pc; pc = pc->next) {
12213 pic16_vcg_dumpedges (pc, of);
12217 static void pic16_vcg_dump_default (pBlock *pb) {
12219 char buf[BUF_SIZE];
12222 /* get function name */
12224 while (pc && !isPCF(pc)) pc = pc->next;
12226 snprintf (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12228 snprintf (buf, BUF_SIZE, "pb_%p.vcg", pb);
12231 //fprintf (stderr, "now dumping %s\n", buf);
12232 of = fopen (buf, "w");
12233 pic16_vcg_init (of);
12234 pic16_vcg_dump (of, pb);
12235 pic16_vcg_close (of);
12240 /*** END of helpers for pCode dataflow optimizations ***/