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 extern char *pic16_aopGet (struct asmop *aop, int offset, bool bit16, bool dname);
37 #if defined(__BORLANDC__) || defined(_MSC_VER)
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(unsigned 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(unsigned 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((const unsigned char *)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((unsigned char *)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((const unsigned char *)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((unsigned char *)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) {
3526 /*-----------------------------------------------------------------*/
3527 /* pic16_newpCode - create and return a newly initialized pCode */
3529 /* fixme - rename this */
3531 /* The purpose of this routine is to create a new Instruction */
3532 /* pCode. This is called by gen.c while the assembly code is being */
3536 /* PIC_OPCODE op - the assembly instruction we wish to create. */
3537 /* (note that the op is analogous to but not the */
3538 /* same thing as the opcode of the instruction.) */
3539 /* pCdoeOp *pcop - pointer to the operand of the instruction. */
3542 /* a pointer to the new malloc'd pCode is returned. */
3546 /*-----------------------------------------------------------------*/
3547 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3549 pCodeInstruction *pci ;
3551 if(!mnemonics_initialized)
3552 pic16initMnemonics();
3554 pci = Safe_calloc(1, sizeof(pCodeInstruction));
3556 if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3557 memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3560 if(pci->inCond & PCC_EXAMINE_PCOP)
3561 pci->inCond |= RegCond(pcop);
3563 if(pci->outCond & PCC_EXAMINE_PCOP)
3564 pci->outCond |= RegCond(pcop);
3566 pci->pc.prev = pci->pc.next = NULL;
3567 return (pCode *)pci;
3570 fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3576 /*-----------------------------------------------------------------*/
3577 /* pic16_newpCodeWild - create a "wild" as in wild card pCode */
3579 /* Wild pcodes are used during the peep hole optimizer to serve */
3580 /* as place holders for any instruction. When a snippet of code is */
3581 /* compared to a peep hole rule, the wild card opcode will match */
3582 /* any instruction. However, the optional operand and label are */
3583 /* additional qualifiers that must also be matched before the */
3584 /* line (of assembly code) is declared matched. Note that the */
3585 /* operand may be wild too. */
3587 /* Note, a wild instruction is specified just like a wild var: */
3588 /* %4 ; A wild instruction, */
3589 /* See the peeph.def file for additional examples */
3591 /*-----------------------------------------------------------------*/
3593 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3598 pcw = Safe_calloc(1,sizeof(pCodeWild));
3600 pcw->pci.pc.type = PC_WILD;
3601 pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3602 pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3603 pcw->pci.pc.pb = NULL;
3605 // pcw->pci.pc.analyze = genericAnalyze;
3606 pcw->pci.pc.destruct = genericDestruct;
3607 pcw->pci.pc.print = genericPrint;
3609 pcw->id = pCodeID; // this is the 'n' in %n
3610 pcw->operand = optional_operand;
3611 pcw->label = optional_label;
3613 pcw->mustBeBitSkipInst = 0;
3614 pcw->mustNotBeBitSkipInst = 0;
3615 pcw->invertBitSkipInst = 0;
3617 return ( (pCode *)pcw);
3621 /*-----------------------------------------------------------------*/
3622 /* newPcodeInlineP - create a new pCode from a char string */
3623 /*-----------------------------------------------------------------*/
3626 pCode *pic16_newpCodeInlineP(char *cP)
3631 pcc = Safe_calloc(1,sizeof(pCodeComment));
3633 pcc->pc.type = PC_INLINE;
3634 pcc->pc.prev = pcc->pc.next = NULL;
3635 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3638 // pcc->pc.analyze = genericAnalyze;
3639 pcc->pc.destruct = genericDestruct;
3640 pcc->pc.print = genericPrint;
3643 pcc->comment = Safe_strdup(cP);
3645 pcc->comment = NULL;
3647 return ( (pCode *)pcc);
3651 /*-----------------------------------------------------------------*/
3652 /* newPcodeCharP - create a new pCode from a char string */
3653 /*-----------------------------------------------------------------*/
3655 pCode *pic16_newpCodeCharP(char *cP)
3660 pcc = Safe_calloc(1,sizeof(pCodeComment));
3662 pcc->pc.type = PC_COMMENT;
3663 pcc->pc.prev = pcc->pc.next = NULL;
3664 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3667 // pcc->pc.analyze = genericAnalyze;
3668 pcc->pc.destruct = genericDestruct;
3669 pcc->pc.print = genericPrint;
3672 pcc->comment = Safe_strdup(cP);
3674 pcc->comment = NULL;
3676 return ( (pCode *)pcc);
3680 /*-----------------------------------------------------------------*/
3681 /* pic16_newpCodeFunction - */
3682 /*-----------------------------------------------------------------*/
3685 pCode *pic16_newpCodeFunction(char *mod,char *f)
3689 pcf = Safe_calloc(1,sizeof(pCodeFunction));
3691 pcf->pc.type = PC_FUNCTION;
3692 pcf->pc.prev = pcf->pc.next = NULL;
3693 //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3696 // pcf->pc.analyze = genericAnalyze;
3697 pcf->pc.destruct = genericDestruct;
3698 pcf->pc.print = pCodePrintFunction;
3704 pcf->modname = Safe_calloc(1,strlen(mod)+1);
3705 strcpy(pcf->modname,mod);
3707 pcf->modname = NULL;
3710 pcf->fname = Safe_calloc(1,strlen(f)+1);
3711 strcpy(pcf->fname,f);
3715 pcf->stackusage = 0;
3717 return ( (pCode *)pcf);
3720 /*-----------------------------------------------------------------*/
3721 /* pic16_newpCodeFlow */
3722 /*-----------------------------------------------------------------*/
3723 static void destructpCodeFlow(pCode *pc)
3725 if(!pc || !isPCFL(pc))
3732 pic16_unlinkpCode(pc);
3734 deleteSet(&PCFL(pc)->registers);
3735 deleteSet(&PCFL(pc)->from);
3736 deleteSet(&PCFL(pc)->to);
3738 /* Instead of deleting the memory used by this pCode, mark
3739 * the object as bad so that if there's a pointer to this pCode
3740 * dangling around somewhere then (hopefully) when the type is
3741 * checked we'll catch it.
3745 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3751 pCode *pic16_newpCodeFlow(void )
3755 //_ALLOC(pcflow,sizeof(pCodeFlow));
3756 pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3758 pcflow->pc.type = PC_FLOW;
3759 pcflow->pc.prev = pcflow->pc.next = NULL;
3760 pcflow->pc.pb = NULL;
3762 // pcflow->pc.analyze = genericAnalyze;
3763 pcflow->pc.destruct = destructpCodeFlow;
3764 pcflow->pc.print = genericPrint;
3766 pcflow->pc.seq = GpcFlowSeq++;
3768 pcflow->from = pcflow->to = NULL;
3770 pcflow->inCond = PCC_NONE;
3771 pcflow->outCond = PCC_NONE;
3773 pcflow->firstBank = -1;
3774 pcflow->lastBank = -1;
3776 pcflow->FromConflicts = 0;
3777 pcflow->ToConflicts = 0;
3781 pcflow->registers = newSet();
3783 return ( (pCode *)pcflow);
3787 /*-----------------------------------------------------------------*/
3788 /*-----------------------------------------------------------------*/
3789 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3791 pCodeFlowLink *pcflowLink;
3793 pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3795 pcflowLink->pcflow = pcflow;
3796 pcflowLink->bank_conflict = 0;
3801 /*-----------------------------------------------------------------*/
3802 /* pic16_newpCodeCSource - create a new pCode Source Symbol */
3803 /*-----------------------------------------------------------------*/
3805 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3810 pccs = Safe_calloc(1,sizeof(pCodeCSource));
3812 pccs->pc.type = PC_CSOURCE;
3813 pccs->pc.prev = pccs->pc.next = NULL;
3816 pccs->pc.destruct = genericDestruct;
3817 pccs->pc.print = genericPrint;
3819 pccs->line_number = ln;
3821 pccs->line = Safe_strdup(l);
3826 pccs->file_name = Safe_strdup(f);
3828 pccs->file_name = NULL;
3830 return ( (pCode *)pccs);
3835 /*******************************************************************/
3836 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive */
3837 /* added by VR 6-Jun-2003 */
3838 /*******************************************************************/
3840 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3847 pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3848 pcad->pci.pc.type = PC_ASMDIR;
3849 pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3850 pcad->pci.pc.pb = NULL;
3851 pcad->pci.isize = 2;
3852 pcad->pci.pc.destruct = genericDestruct;
3853 pcad->pci.pc.print = genericPrint;
3855 if(asdir && *asdir) {
3857 while(isspace((unsigned char)*asdir))asdir++; // strip any white space from the beginning
3859 pcad->directive = Safe_strdup( asdir );
3862 va_start(ap, argfmt);
3864 memset(buffer, 0, sizeof(buffer));
3865 if(argfmt && *argfmt)
3866 vsprintf(buffer, argfmt, ap);
3870 while(isspace((unsigned char)*lbp))lbp++;
3873 pcad->arg = Safe_strdup( lbp );
3875 return ((pCode *)pcad);
3878 /*-----------------------------------------------------------------*/
3879 /* pCodeLabelDestruct - free memory used by a label. */
3880 /*-----------------------------------------------------------------*/
3881 static void pCodeLabelDestruct(pCode *pc)
3887 // if((pc->type == PC_LABEL) && PCL(pc)->label)
3888 // Safe_free(PCL(pc)->label);
3890 /* Instead of deleting the memory used by this pCode, mark
3891 * the object as bad so that if there's a pointer to this pCode
3892 * dangling around somewhere then (hopefully) when the type is
3893 * checked we'll catch it.
3897 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3903 pCode *pic16_newpCodeLabel(char *name, int key)
3909 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3911 pcl->pc.type = PC_LABEL;
3912 pcl->pc.prev = pcl->pc.next = NULL;
3913 //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3916 // pcl->pc.analyze = genericAnalyze;
3917 pcl->pc.destruct = pCodeLabelDestruct;
3918 pcl->pc.print = pCodePrintLabel;
3925 sprintf(s,"_%05d_DS_",key);
3930 pcl->label = Safe_strdup(s);
3932 // if(pic16_pcode_verbose)
3933 // fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3936 return ( (pCode *)pcl);
3940 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3942 pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3946 return ( (pCode *)pcl );
3949 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3953 pci = Safe_calloc(1, sizeof(pCodeInfo));
3954 pci->pci.pc.type = PC_INFO;
3955 pci->pci.pc.prev = pci->pci.pc.next = NULL;
3956 pci->pci.pc.pb = NULL;
3957 pci->pci.label = NULL;
3959 pci->pci.pc.destruct = genericDestruct;
3960 pci->pci.pc.print = genericPrint;
3965 return ((pCode *)pci);
3969 /*-----------------------------------------------------------------*/
3970 /* newpBlock - create and return a pointer to a new pBlock */
3971 /*-----------------------------------------------------------------*/
3972 static pBlock *newpBlock(void)
3977 PpB = Safe_calloc(1,sizeof(pBlock) );
3978 PpB->next = PpB->prev = NULL;
3980 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3981 PpB->tregisters = NULL;
3983 PpB->FlowTree = NULL;
3989 /*-----------------------------------------------------------------*/
3990 /* pic16_newpCodeChain - create a new chain of pCodes */
3991 /*-----------------------------------------------------------------*
3993 * This function will create a new pBlock and the pointer to the
3994 * pCode that is passed in will be the first pCode in the block.
3995 *-----------------------------------------------------------------*/
3998 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
4001 pBlock *pB = newpBlock();
4003 pB->pcHead = pB->pcTail = pc;
4012 /*-----------------------------------------------------------------*/
4013 /* pic16_newpCodeOpLabel - Create a new label given the key */
4014 /* Note, a negative key means that the label is part of wild card */
4015 /* (and hence a wild card label) used in the pCodePeep */
4016 /* optimizations). */
4017 /*-----------------------------------------------------------------*/
4019 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4022 static int label_key=-1;
4026 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4027 pcop->type = PO_LABEL;
4032 sprintf(s=buffer,"_%05d_DS_",key);
4034 s = name, key = label_key--;
4037 pcop->name = Safe_strdup(s);
4039 ((pCodeOpLabel *)pcop)->key = key;
4041 //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4045 /*-----------------------------------------------------------------*/
4046 /*-----------------------------------------------------------------*/
4047 pCodeOp *pic16_newpCodeOpLit(int lit)
4053 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4054 pcop->type = PO_LITERAL;
4058 sprintf(s,"0x%02hhx", (unsigned char)lit);
4060 // sprintf(s, "%i", lit);
4063 pcop->name = Safe_strdup(s);
4065 ((pCodeOpLit *)pcop)->lit = lit;
4070 /* Allow for 12 bit literals, required for LFSR */
4071 pCodeOp *pic16_newpCodeOpLit12(int lit)
4077 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4078 pcop->type = PO_LITERAL;
4082 sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4084 // sprintf(s, "%i", lit);
4087 pcop->name = Safe_strdup(s);
4089 ((pCodeOpLit *)pcop)->lit = lit;
4094 /*-----------------------------------------------------------------*/
4095 /*-----------------------------------------------------------------*/
4096 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4098 char *s = buffer, tbuf[256], *tb=tbuf;
4102 tb = pic16_get_op(arg2, NULL, 0);
4103 pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4104 pcop->type = PO_LITERAL;
4108 sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4110 pcop->name = Safe_strdup(s);
4113 ((pCodeOpLit2 *)pcop)->lit = lit;
4114 ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4119 /*-----------------------------------------------------------------*/
4120 /*-----------------------------------------------------------------*/
4121 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4125 pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4126 pcop->type = PO_IMMEDIATE;
4128 regs *r = pic16_dirregWithName(name);
4129 pcop->name = Safe_strdup(name);
4133 // fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4134 PCOI(pcop)->rIdx = r->rIdx;
4136 // fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4137 PCOI(pcop)->rIdx = -1;
4139 // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4142 PCOI(pcop)->rIdx = -1;
4145 PCOI(pcop)->index = index;
4146 PCOI(pcop)->offset = offset;
4147 PCOI(pcop)->_const = code_space;
4152 /*-----------------------------------------------------------------*/
4153 /*-----------------------------------------------------------------*/
4154 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4160 if(!pcwb || !subtype) {
4161 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4165 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4166 pcop->type = PO_WILD;
4167 sprintf(s,"%%%d",id);
4168 pcop->name = Safe_strdup(s);
4170 PCOW(pcop)->id = id;
4171 PCOW(pcop)->pcwb = pcwb;
4172 PCOW(pcop)->subtype = subtype;
4173 PCOW(pcop)->matched = NULL;
4175 PCOW(pcop)->pcop2 = NULL;
4180 /*-----------------------------------------------------------------*/
4181 /*-----------------------------------------------------------------*/
4182 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4188 if(!pcwb || !subtype || !subtype2) {
4189 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4193 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4194 pcop->type = PO_WILD;
4195 sprintf(s,"%%%d",id);
4196 pcop->name = Safe_strdup(s);
4198 PCOW(pcop)->id = id;
4199 PCOW(pcop)->pcwb = pcwb;
4200 PCOW(pcop)->subtype = subtype;
4201 PCOW(pcop)->matched = NULL;
4203 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4205 if(!subtype2->name) {
4206 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4207 PCOW2(pcop)->pcop.type = PO_WILD;
4208 sprintf(s, "%%%d", id2);
4209 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4210 PCOW2(pcop)->id = id2;
4211 PCOW2(pcop)->subtype = subtype2;
4213 // fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4214 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4216 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4218 // fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4219 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4228 /*-----------------------------------------------------------------*/
4229 /*-----------------------------------------------------------------*/
4230 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4234 pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4235 pcop->type = PO_GPR_BIT;
4237 pcop->name = Safe_strdup(s);
4241 PCORB(pcop)->bit = bit;
4242 PCORB(pcop)->inBitSpace = inBitSpace;
4243 PCORB(pcop)->subtype = subt;
4245 /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4246 PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4247 // fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4248 // PCOR(pcop)->rIdx = 0;
4252 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4254 return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4255 bit, 0, PO_GPR_REGISTER);
4259 /*-----------------------------------------------------------------*
4260 * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4262 * If rIdx >=0 then a specific register from the set of registers
4263 * will be selected. If rIdx <0, then a new register will be searched
4265 *-----------------------------------------------------------------*/
4267 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4272 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4277 r = pic16_regWithIdx(rIdx);
4279 r = pic16_allocWithIdx(rIdx);
4281 r = pic16_findFreeReg(REG_GPR);
4284 fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4285 __FUNCTION__, __LINE__);
4290 PCOR(pcop)->rIdx = rIdx;
4292 pcop->type = PCOR(pcop)->r->pc_type;
4297 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4302 pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4305 r = pic16_findFreeReg(REG_GPR);
4308 if(!bitVectBitValue(bv, r->rIdx)) {
4310 PCOR(pcop)->rIdx = r->rIdx;
4311 pcop->type = r->pc_type;
4315 r = pic16_findFreeRegNext(REG_GPR, r);
4323 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4328 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4329 PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4330 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4331 pcop->type = PCOR(pcop)->r->pc_type;
4332 pcop->name = PCOR(pcop)->r->name;
4334 // if(pic16_pcode_verbose) {
4335 // fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4336 // __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4342 /*-----------------------------------------------------------------*/
4343 /*-----------------------------------------------------------------*/
4344 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4348 pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4351 pcop->key = Safe_strdup( key );
4353 return (PCOP(pcop));
4356 /*-----------------------------------------------------------------*/
4357 /*-----------------------------------------------------------------*/
4358 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4360 pCodeOpLocalReg *pcop;
4362 pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4366 return (PCOP(pcop));
4370 /*-----------------------------------------------------------------*/
4371 /*-----------------------------------------------------------------*/
4373 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4380 pcop = pic16_newpCodeOpBit(name, -1,0, type);
4384 pcop = pic16_newpCodeOpLit(-1);
4388 pcop = pic16_newpCodeOpLabel(NULL,-1);
4391 pcop = pic16_newpCodeOpReg(-1);
4394 case PO_GPR_REGISTER:
4396 pcop = pic16_newpCodeOpRegFromStr(name);
4398 pcop = pic16_newpCodeOpReg(-1);
4402 assert( !"Cannot create PO_TWO_OPS from string!" );
4407 pcop = Safe_calloc(1,sizeof(pCodeOp) );
4410 pcop->name = Safe_strdup(name);
4418 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4420 pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4421 pcop2->pcop.type = PO_TWO_OPS;
4427 /* This is a multiple of two as gpasm pads DB directives to even length,
4428 * thus the data would be interleaved with \0 bytes...
4429 * This is a multiple of three in order to have arrays of 3-byte pointers
4430 * continuously in memory (without 0-padding at the lines' end).
4431 * This is rather 12 than 6 in order not to split up 4-byte data types
4432 * in arrays right in the middle of a 4-byte word. */
4433 #define DB_ITEMS_PER_LINE 12
4435 typedef struct DBdata
4442 static int DBd_init = -1;
4444 /*-----------------------------------------------------------------*/
4445 /* Initialiase "DB" data buffer */
4446 /*-----------------------------------------------------------------*/
4447 void pic16_initDB(void)
4453 /*-----------------------------------------------------------------*/
4454 /* Flush pending "DB" data to a pBlock */
4456 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4457 /*-----------------------------------------------------------------*/
4458 void pic16_flushDB(char ptype, void *p)
4462 pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4465 fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4468 fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4472 DBd.buffer[0] = '\0';
4477 /*-----------------------------------------------------------------*/
4478 /* Add "DB" directives to a pBlock */
4479 /*-----------------------------------------------------------------*/
4480 void pic16_emitDB(int c, char ptype, void *p)
4485 // we need to initialize
4488 DBd.buffer[0] = '\0';
4491 l = strlen(DBd.buffer);
4492 sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4494 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4497 if (DBd.count>= DB_ITEMS_PER_LINE)
4498 pic16_flushDB(ptype, p);
4501 void pic16_emitDS(char *s, char ptype, void *p)
4506 // we need to initialize
4509 DBd.buffer[0] = '\0';
4512 l = strlen(DBd.buffer);
4513 sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4515 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4517 DBd.count++; //=strlen(s);
4518 if (DBd.count>=DB_ITEMS_PER_LINE)
4519 pic16_flushDB(ptype, p);
4523 /*-----------------------------------------------------------------*/
4524 /*-----------------------------------------------------------------*/
4525 void pic16_pCodeConstString(char *name, char *value)
4529 static set *emittedSymbols = NULL;
4534 /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4535 if (emittedSymbols) {
4536 /* scan set for name */
4537 for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4539 if (!strcmp (item,name)) {
4540 //fprintf (stderr, "%s already emitted\n", name);
4545 addSet (&emittedSymbols, Safe_strdup (name));
4547 //fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value);
4549 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4551 pic16_addpBlock(pb);
4553 // sprintf(buffer,"; %s = ", name);
4554 // strcat(buffer, value);
4555 // fputs(buffer, stderr);
4557 // pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4558 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4561 pic16_emitDB(*value, 'p', (void *)pb);
4563 pic16_flushDB('p', (void *)pb);
4566 /*-----------------------------------------------------------------*/
4567 /*-----------------------------------------------------------------*/
4569 static void pCodeReadCodeTable(void)
4573 fprintf(stderr, " %s\n",__FUNCTION__);
4575 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4577 pic16_addpBlock(pb);
4579 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4580 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4581 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4582 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4584 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4585 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4586 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4587 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4592 /*-----------------------------------------------------------------*/
4593 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */
4594 /*-----------------------------------------------------------------*/
4595 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4602 /* If this is the first pcode to be added to a block that
4603 * was initialized with a NULL pcode, then go ahead and
4604 * make this pcode the head and tail */
4605 pb->pcHead = pb->pcTail = pc;
4608 pb->pcTail->next = pc;
4610 pc->prev = pb->pcTail;
4617 /*-----------------------------------------------------------------*/
4618 /* pic16_addpBlock - place a pBlock into the pFile */
4619 /*-----------------------------------------------------------------*/
4620 void pic16_addpBlock(pBlock *pb)
4622 // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4625 /* First time called, we'll pass through here. */
4626 //_ALLOC(the_pFile,sizeof(pFile));
4627 the_pFile = Safe_calloc(1,sizeof(pFile));
4628 the_pFile->pbHead = the_pFile->pbTail = pb;
4629 the_pFile->functions = NULL;
4633 the_pFile->pbTail->next = pb;
4634 pb->prev = the_pFile->pbTail;
4636 the_pFile->pbTail = pb;
4639 /*-----------------------------------------------------------------*/
4640 /* removepBlock - remove a pBlock from the pFile */
4641 /*-----------------------------------------------------------------*/
4642 static void removepBlock(pBlock *pb)
4650 //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4652 for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4655 if(pbs == the_pFile->pbHead)
4656 the_pFile->pbHead = pbs->next;
4658 if (pbs == the_pFile->pbTail)
4659 the_pFile->pbTail = pbs->prev;
4662 pbs->next->prev = pbs->prev;
4665 pbs->prev->next = pbs->next;
4672 fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4676 /*-----------------------------------------------------------------*/
4677 /* printpCode - write the contents of a pCode to a file */
4678 /*-----------------------------------------------------------------*/
4679 static void printpCode(FILE *of, pCode *pc)
4690 fprintf(of,"warning - unable to print pCode\n");
4693 /*-----------------------------------------------------------------*/
4694 /* pic16_printpBlock - write the contents of a pBlock to a file */
4695 /*-----------------------------------------------------------------*/
4696 void pic16_printpBlock(FILE *of, pBlock *pb)
4704 for(pc = pb->pcHead; pc; pc = pc->next) {
4705 if(isPCF(pc) && PCF(pc)->fname) {
4706 fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4707 if(pb->dbName == 'A') {
4709 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4710 // fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4711 if(!strcmp(ab->name, PCF(pc)->fname)) {
4712 // fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4713 if(ab->address != -1)
4714 fprintf(of, "\t0X%06X", ab->address);
4725 /*-----------------------------------------------------------------*/
4727 /* pCode processing */
4731 /*-----------------------------------------------------------------*/
4732 pCode * pic16_findNextInstruction(pCode *pci);
4733 pCode * pic16_findPrevInstruction(pCode *pci);
4735 void pic16_unlinkpCode(pCode *pc)
4741 fprintf(stderr,"Unlinking: ");
4742 printpCode(stderr, pc);
4745 pc->prev->next = pc->next;
4747 pc->next->prev = pc->prev;
4749 /* move C source line down (or up) */
4750 if (isPCI(pc) && PCI(pc)->cline) {
4751 prev = pic16_findNextInstruction (pc->next);
4752 if (prev && isPCI(prev) && !PCI(prev)->cline) {
4753 PCI(prev)->cline = PCI(pc)->cline;
4755 prev = pic16_findPrevInstruction (pc->prev);
4756 if (prev && isPCI(prev) && !PCI(prev)->cline)
4757 PCI(prev)->cline = PCI(pc)->cline;
4760 pc->prev = pc->next = NULL;
4764 /*-----------------------------------------------------------------*/
4765 /*-----------------------------------------------------------------*/
4767 static void genericDestruct(pCode *pc)
4770 pic16_unlinkpCode(pc);
4773 /* For instructions, tell the register (if there's one used)
4774 * that it's no longer needed */
4775 regs *reg = pic16_getRegFromInstruction(pc);
4777 deleteSetItem (&(reg->reglives.usedpCodes),pc);
4779 if(PCI(pc)->is2MemOp) {
4780 reg = pic16_getRegFromInstruction2(pc);
4782 deleteSetItem(&(reg->reglives.usedpCodes), pc);
4786 /* Instead of deleting the memory used by this pCode, mark
4787 * the object as bad so that if there's a pointer to this pCode
4788 * dangling around somewhere then (hopefully) when the type is
4789 * checked we'll catch it.
4793 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4799 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4800 /*-----------------------------------------------------------------*/
4801 /*-----------------------------------------------------------------*/
4802 /* modifiers for constant immediate */
4803 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4805 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4810 int use_buffer = 1; // copy the string to the passed buffer pointer
4815 use_buffer = 0; // Don't bother copying the string to the buffer.
4820 switch(pcop->type) {
4828 SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4831 return (PCOR(pcop)->r->name);
4834 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4836 SAFE_snprintf(&buffer,&size,"%s",r->name);
4843 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4844 if(PCOI(pcop)->index) {
4845 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4846 immdmod[ PCOI(pcop)->offset ],
4850 SAFE_snprintf(&s,&size,"%s(%s)",
4851 immdmod[ PCOI(pcop)->offset ],
4855 if(PCOI(pcop)->index) {
4856 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4861 SAFE_snprintf(&s,&size, "%s(%s)",
4868 case PO_GPR_REGISTER:
4871 // size = sizeof(buffer);
4872 if( PCOR(pcop)->instance) {
4873 SAFE_snprintf(&s,&size,"(%s + %d)",
4875 PCOR(pcop)->instance );
4877 SAFE_snprintf(&s,&size,"%s",pcop->name);
4882 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4883 SAFE_snprintf(&s, &size, "%s", pcop->name);
4885 if(PCORB(pcop)->pcor.instance)
4886 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4888 SAFE_snprintf(&s, &size, "%s", pcop->name);
4893 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4898 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4901 return (pcop->name);
4905 return ("unhandled type for op1");
4908 return ("NO operand1");
4911 /*-----------------------------------------------------------------*/
4912 /* pic16_get_op2 - variant to support two memory operand commands */
4913 /*-----------------------------------------------------------------*/
4914 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4917 if(pcop && pcop->type == PO_TWO_OPS) {
4918 return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4921 return "NO operand2";
4924 /*-----------------------------------------------------------------*/
4925 /*-----------------------------------------------------------------*/
4926 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4930 return pic16_get_op(pcc->pcop,NULL,0);
4932 /* gcc 3.2: warning: concatenation of string literals with __FUNCTION__ is deprecated
4933 * return ("ERROR Null: "__FUNCTION__);
4935 return ("ERROR Null: pic16_get_op_from_instruction");
4939 /*-----------------------------------------------------------------*/
4940 /*-----------------------------------------------------------------*/
4941 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4944 fprintf(of,"pcodeopprint- not implemented\n");
4947 /*-----------------------------------------------------------------*/
4948 /* pic16_pCode2str - convert a pCode instruction to string */
4949 /*-----------------------------------------------------------------*/
4950 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4956 if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4957 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4958 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4959 // exit(EXIT_FAILURE);
4966 SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4968 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4970 //if(PCI(pc)->is2MemOp)
4971 if (PCI(pc)->pcop->type == PO_TWO_OPS)
4973 /* split into two phases due to static buffer in pic16_get_op() */
4974 SAFE_snprintf(&s,&size, "%s",
4975 pic16_get_op((PCI(pc)->pcop), NULL, 0));
4976 SAFE_snprintf(&s, &size, ", %s",
4977 pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4981 if(PCI(pc)->is2LitOp) {
4982 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4986 if(PCI(pc)->isBitInst) {
4987 if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4988 if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4989 SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)",
4990 PCI(pc)->pcop->name ,
4991 PCI(pc)->pcop->name );
4993 SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4994 // (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
4995 (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4997 } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4998 SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5000 SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5001 //PCI(pc)->pcop->t.bit );
5004 if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5005 if( PCI(pc)->num_ops == 3)
5006 SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5008 SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5013 SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5016 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5017 if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5018 SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5020 r = pic16_getRegFromInstruction(pc);
5021 // fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5022 // __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?isACCESS_BANK(r):-1);
5024 if(PCI(pc)->isAccess) {
5025 static char *bank_spec[2][2] = {
5026 { "", ", ACCESS" }, /* gpasm uses access bank by default */
5027 { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5030 SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
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 return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5804 fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5812 /*-----------------------------------------------------------------*/
5813 /*-----------------------------------------------------------------*/
5814 regs * pic16_getRegFromInstruction(pCode *pc)
5819 PCI(pc)->num_ops == 0 ||
5820 (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5824 fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5825 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5828 return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5831 /*-------------------------------------------------------------------------------*/
5832 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5833 /*-------------------------------------------------------------------------------*/
5834 regs * pic16_getRegFromInstruction2(pCode *pc)
5840 PCI(pc)->num_ops == 0 ||
5841 (PCI(pc)->num_ops == 1)) // accept only 2 operand commands
5844 if (PCI(pc)->pcop->type != PO_TWO_OPS)
5848 fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5849 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5852 return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5855 /*-----------------------------------------------------------------*/
5856 /*-----------------------------------------------------------------*/
5858 static void AnalyzepBlock(pBlock *pb)
5865 /* Find all of the registers used in this pBlock
5866 * by looking at each instruction and examining it's
5869 for(pc = pb->pcHead; pc; pc = pc->next) {
5871 /* Is this an instruction with operands? */
5872 if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5874 if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5876 /* Loop through all of the registers declared so far in
5877 this block and see if we find this one there */
5879 regs *r = setFirstItem(pb->tregisters);
5882 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5883 PCOR(PCI(pc)->pcop)->r = r;
5886 r = setNextItem(pb->tregisters);
5890 /* register wasn't found */
5891 //r = Safe_calloc(1, sizeof(regs));
5892 //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5893 //addSet(&pb->tregisters, r);
5894 addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5895 //PCOR(PCI(pc)->pcop)->r = r;
5896 //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5898 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5901 if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5902 if(PCOR(PCI(pc)->pcop)->r) {
5903 pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx); /* FIXME! - VR */
5904 DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5906 if(PCI(pc)->pcop->name)
5907 fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5909 fprintf(stderr,"ERROR: NULL register\n");
5918 /*-----------------------------------------------------------------*/
5920 /*-----------------------------------------------------------------*/
5921 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5923 static void InsertpFlow(pCode *pc, pCode **pflow)
5926 PCFL(*pflow)->end = pc;
5928 if(!pc || !pc->next)
5931 *pflow = pic16_newpCodeFlow();
5932 pic16_pCodeInsertAfter(pc, *pflow);
5935 /*-----------------------------------------------------------------*/
5936 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5937 /* the flow blocks. */
5939 * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5940 * point the instruction flow changes.
5942 /*-----------------------------------------------------------------*/
5943 void pic16_BuildFlow(pBlock *pb)
5946 pCode *last_pci=NULL;
5953 //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq);
5954 /* Insert a pCodeFlow object at the beginning of a pBlock */
5956 InsertpFlow(pb->pcHead, &pflow);
5958 //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */
5959 //pflow->next = pb->pcHead; /* Make the current head the next object */
5960 //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */
5961 //pb->pcHead = pflow; /* Make the Flow object the head */
5964 for( pc = pic16_findNextInstruction(pb->pcHead);
5966 pc=pic16_findNextInstruction(pc)) {
5969 PCI(pc)->pcflow = PCFL(pflow);
5971 //fprintf(stderr," build: ");
5972 //pflow->print(stderr,pflow);
5974 if (checkLabel(pc)) {
5976 /* This instruction marks the beginning of a
5977 * new flow segment */
5982 /* If the previous pCode is not a flow object, then
5983 * insert a new flow object. (This check prevents
5984 * two consecutive flow objects from being insert in
5985 * the case where a skip instruction preceeds an
5986 * instruction containing a label.) */
5988 if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5989 InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5991 PCI(pc)->pcflow = PCFL(pflow);
5995 if( PCI(pc)->isSkip) {
5997 /* The two instructions immediately following this one
5998 * mark the beginning of a new flow segment */
6000 while(pc && PCI(pc)->isSkip) {
6002 PCI(pc)->pcflow = PCFL(pflow);
6006 InsertpFlow(pc, &pflow);
6007 pc=pic16_findNextInstruction(pc->next);
6015 PCI(pc)->pcflow = PCFL(pflow);
6017 InsertpFlow(pc, &pflow);
6019 } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) {
6021 InsertpFlow(pc, &pflow);
6029 //fprintf (stderr,",end seq %d",GpcFlowSeq);
6031 PCFL(pflow)->end = pb->pcTail;
6034 /*-------------------------------------------------------------------*/
6035 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */
6036 /* the flow blocks. */
6038 * unBuildFlow removes pCodeFlow objects from a pCode chain
6040 /*-----------------------------------------------------------------*/
6041 static void unBuildFlow(pBlock *pb)
6056 if(PCI(pc)->pcflow) {
6057 //Safe_free(PCI(pc)->pcflow);
6058 PCI(pc)->pcflow = NULL;
6061 } else if(isPCFL(pc) )
6070 /*-----------------------------------------------------------------*/
6071 /*-----------------------------------------------------------------*/
6072 static void dumpCond(int cond)
6075 static char *pcc_str[] = {
6089 int ncond = sizeof(pcc_str) / sizeof(char *);
6092 fprintf(stderr, "0x%04X\n",cond);
6094 for(i=0,j=1; i<ncond; i++, j<<=1)
6096 fprintf(stderr, " %s\n",pcc_str[i]);
6102 /*-----------------------------------------------------------------*/
6103 /*-----------------------------------------------------------------*/
6104 static void FlowStats(pCodeFlow *pcflow)
6112 fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6114 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6117 fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6122 fprintf(stderr, " FlowStats inCond: ");
6123 dumpCond(pcflow->inCond);
6124 fprintf(stderr, " FlowStats outCond: ");
6125 dumpCond(pcflow->outCond);
6129 /*-----------------------------------------------------------------*
6130 * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6131 * if it affects the banking bits.
6133 * return: -1 == Banking bits are unaffected by this pCode.
6135 * return: > 0 == Banking bits are affected.
6137 * If the banking bits are affected, then the returned value describes
6138 * which bits are affected and how they're affected. The lower half
6139 * of the integer maps to the bits that are affected, the upper half
6140 * to whether they're set or cleared.
6142 *-----------------------------------------------------------------*/
6144 static int isBankInstruction(pCode *pc)
6152 if( PCI(pc)->op == POC_MOVLB ||
6153 (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6154 bank = PCOL(pc)->lit;
6161 /*-----------------------------------------------------------------*/
6162 /*-----------------------------------------------------------------*/
6163 static void FillFlow(pCodeFlow *pcflow)
6172 // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6174 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6177 //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6184 isBankInstruction(pc);
6186 } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6190 fprintf(stderr, " FillFlow - Bad end of flow\n");
6192 fprintf(stderr, " FillFlow - Ending flow with\n ");
6193 pc->print(stderr,pc);
6196 fprintf(stderr, " FillFlow inCond: ");
6197 dumpCond(pcflow->inCond);
6198 fprintf(stderr, " FillFlow outCond: ");
6199 dumpCond(pcflow->outCond);
6203 /*-----------------------------------------------------------------*/
6204 /*-----------------------------------------------------------------*/
6205 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6207 pCodeFlowLink *fromLink, *toLink;
6209 if(!from || !to || !to->pcflow || !from->pcflow)
6212 fromLink = pic16_newpCodeFlowLink(from->pcflow);
6213 toLink = pic16_newpCodeFlowLink(to->pcflow);
6215 addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
6216 addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6220 pCode *pic16_getJumptabpCode (pCode *pc) {
6223 //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6224 //pc->print (stderr, pc);
6227 if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6228 if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6229 switch (PCOO(PCINF(pcinf)->oper1)->type) {
6230 case OPT_JUMPTABLE_BEGIN:
6231 /* leading begin of jump table -- in one */
6232 pcinf = pic16_findPrevInstruction (pcinf);
6236 case OPT_JUMPTABLE_END:
6237 /* leading end of jumptable -- not in one */
6242 /* ignore all other PCInfos */
6246 pcinf = pcinf->prev;
6249 /* no PCInfo found -- not in a jumptable */
6253 /*-----------------------------------------------------------------*
6254 * void LinkFlow(pBlock *pb)
6256 * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6257 * non-branching segments. In LinkFlow, we determine the execution
6258 * order of these segments. For example, if one of the segments ends
6259 * with a skip, then we know that there are two possible flow segments
6260 * to which control may be passed.
6261 *-----------------------------------------------------------------*/
6262 static void LinkFlow(pBlock *pb)
6267 pCode *jumptab_pre = NULL;
6269 //fprintf(stderr,"linkflow \n");
6271 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6273 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6276 fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6278 //fprintf(stderr," link: ");
6279 //pcflow->print(stderr,pcflow);
6281 //FillFlow(PCFL(pcflow));
6283 pc = PCFL(pcflow)->end;
6285 //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6286 if(isPCI_SKIP(pc)) {
6287 // fprintf(stderr, "ends with skip\n");
6288 // pc->print(stderr,pc);
6290 pct=pic16_findNextInstruction(pc->next);
6291 LinkFlow_pCode(PCI(pc),PCI(pct));
6292 pct=pic16_findNextInstruction(pct->next);
6293 LinkFlow_pCode(PCI(pc),PCI(pct));
6297 if(isPCI_BRANCH(pc)) {
6298 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6300 /* handle GOTOs in jumptables */
6301 if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6302 /* link to previous flow */
6303 //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6304 LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6307 switch (PCI(pc)->op) {
6313 /* unconditional branches -- do not link to next instruction */
6314 //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6319 /* unconditional calls -- link to next instruction */
6320 //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6321 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6332 /* conditional branches -- also link to next instruction */
6333 //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6334 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6338 fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6339 assert (0 && "unhandled branching instruction");
6343 //fprintf(stderr, "ends with branch\n ");
6344 //pc->print(stderr,pc);
6346 if(!(pcol && isPCOLAB(pcol))) {
6347 if((PCI(pc)->op != POC_RETLW)
6348 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6350 /* continue if label is '$' which assembler knows how to parse */
6351 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6353 if(pic16_pcode_verbose) {
6354 pc->print(stderr,pc);
6355 fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6361 if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6362 LinkFlow_pCode(PCI(pc),PCI(pct));
6364 fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6365 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6367 // fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6373 //fprintf(stderr, "ends with non-branching instruction:\n");
6374 //pc->print(stderr,pc);
6376 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6382 //fprintf(stderr, "ends with unknown\n");
6383 //pc->print(stderr,pc);
6387 //fprintf(stderr, "ends with nothing: ERROR\n");
6391 /*-----------------------------------------------------------------*/
6392 /*-----------------------------------------------------------------*/
6394 /*-----------------------------------------------------------------*/
6395 /*-----------------------------------------------------------------*/
6396 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6402 if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6405 if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6415 /*-----------------------------------------------------------------*/
6416 /* insertBankSwitch - inserts a bank switch statement in the */
6417 /* assembly listing */
6419 /* position == 0: insert before */
6420 /* position == 1: insert after pc */
6421 /* position == 2: like 0 but previous was a skip instruction */
6422 /*-----------------------------------------------------------------*/
6423 pCodeOp *pic16_popGetLabel(unsigned int key);
6424 extern int pic16_labelOffset;
6426 static void insertBankSwitch(unsigned char position, pCode *pc)
6433 /* emit BANKSEL [symbol] */
6436 new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6438 // position = 0; // position is always before (sanity check!)
6441 fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6442 pc->print(stderr, pc);
6447 /* insert the bank switch after this pc instruction */
6448 pCode *pcnext = pic16_findNextInstruction(pc);
6450 pic16_pCodeInsertAfter(pc, new_pc);
6451 if(pcnext)pc = pcnext;
6455 /* insert the bank switch BEFORE this pc instruction */
6456 pic16_pCodeInsertAfter(pc->prev, new_pc);
6461 pCode *pcnext, *pcprev, *npci, *ppc;
6463 int ofs1=0, ofs2=0, len=0;
6465 /* just like 0, but previous was a skip instruction,
6466 * so some care should be taken */
6468 pic16_labelOffset += 10000;
6469 tlbl = newiTempLabel(NULL);
6471 /* invert skip instruction */
6472 pcprev = pic16_findPrevInstruction(pc->prev);
6473 ipci = PCI(pcprev)->inverted_op;
6474 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6476 // fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6478 /* copy info from old pCode */
6479 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6480 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6481 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6482 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6483 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6484 PCI(npci)->op = PCI(pcprev)->inverted_op;
6486 /* unlink old pCode */
6488 ppc->next = pcprev->next;
6489 pcprev->next->prev = ppc;
6490 pic16_pCodeInsertAfter(ppc, npci);
6492 /* extra instructions to handle invertion */
6493 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6494 pic16_pCodeInsertAfter(npci, pcnext);
6495 pic16_pCodeInsertAfter(pc->prev, new_pc);
6497 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6498 pic16_pCodeInsertAfter(pc, pcnext);
6503 /* Move the label, if there is one */
6504 if(PCI(pc)->label) {
6505 // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6506 // __FILE__, __LINE__, pc, new_pc);
6507 PCAD(new_pc)->pci.label = PCI(pc)->label;
6508 PCI(pc)->label = NULL;
6513 /*-----------------------------------------------------------------*/
6514 /*int compareBankFlow - compare the banking requirements between */
6516 /*-----------------------------------------------------------------*/
6517 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6520 if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6523 if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6526 if(pcflow->firstBank == -1)
6530 if(pcflowLink->pcflow->firstBank == -1) {
6531 pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6532 pcflowLink->pcflow->to :
6533 pcflowLink->pcflow->from);
6534 return compareBankFlow(pcflow, pctl, toORfrom);
6538 if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6541 pcflowLink->bank_conflict++;
6542 pcflowLink->pcflow->FromConflicts++;
6543 pcflow->ToConflicts++;
6546 if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6549 pcflowLink->bank_conflict++;
6550 pcflowLink->pcflow->ToConflicts++;
6551 pcflow->FromConflicts++;
6555 fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6556 pcflowLink->pcflow->pc.seq,
6557 pcflowLink->pcflow->FromConflicts,
6558 pcflowLink->pcflow->ToConflicts);
6565 /*-----------------------------------------------------------------*/
6566 /*-----------------------------------------------------------------*/
6567 static void DumpFlow(pBlock *pb)
6571 pCodeFlowLink *pcfl;
6574 fprintf(stderr,"Dump flow \n");
6575 pb->pcHead->print(stderr, pb->pcHead);
6577 pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6578 pcflow->print(stderr,pcflow);
6580 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6582 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6584 if(!isPCFL(pcflow)) {
6585 fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6588 fprintf(stderr,"dumping: ");
6589 pcflow->print(stderr,pcflow);
6590 FlowStats(PCFL(pcflow));
6592 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6594 pc = PCODE(pcfl->pcflow);
6596 fprintf(stderr, " from seq %d:\n",pc->seq);
6598 fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6599 pc->print(stderr,pc);
6604 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6606 pc = PCODE(pcfl->pcflow);
6608 fprintf(stderr, " to seq %d:\n",pc->seq);
6610 fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6611 pc->print(stderr,pc);
6620 /*-----------------------------------------------------------------*/
6621 /*-----------------------------------------------------------------*/
6622 static int OptimizepBlock(pBlock *pb)
6627 if(!pb || !peepOptimizing)
6630 DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6632 for(pc = pb->pcHead; pc; pc = pc->next)
6633 matches += pic16_pCodePeepMatchRule(pc);
6636 pc = pic16_findNextInstruction(pb->pcHead);
6644 if(pic16_pCodePeepMatchRule(pc)) {
6649 pc = pic16_findNextInstruction(pcprev->next);
6651 pc = pic16_findNextInstruction(pb->pcHead);
6653 pc = pic16_findNextInstruction(pc->next);
6657 DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6662 /*-----------------------------------------------------------------*/
6663 /*-----------------------------------------------------------------*/
6664 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6668 for(pc = pcs; pc; pc = pc->next) {
6670 if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6672 (PCI(pc)->pcop->type == PO_LABEL) &&
6673 (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6681 /*-----------------------------------------------------------------*/
6682 /*-----------------------------------------------------------------*/
6683 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6690 (PCI(pc)->pcop->type == PO_LABEL)) {
6692 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6694 // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6695 // if(pcol->pcop.name)
6696 // Safe_free(pcol->pcop.name);
6698 /* If the key is negative, then we (probably) have a label to
6699 * a function and the name is already defined */
6702 sprintf(s=buffer,"_%05d_DS_",pcl->key);
6706 //sprintf(buffer,"_%05d_DS_",pcl->key);
6708 fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6710 pcol->pcop.name = Safe_strdup(s);
6711 pcol->key = pcl->key;
6712 //pc->print(stderr,pc);
6719 /*-----------------------------------------------------------------*/
6720 /* pBlockRemoveUnusedLabels - remove the pCode labels from the */
6721 /* pCode chain if they're not used. */
6722 /*-----------------------------------------------------------------*/
6723 static void pBlockRemoveUnusedLabels(pBlock *pb)
6725 pCode *pc; pCodeLabel *pcl;
6727 if(!pb || !pb->pcHead)
6730 for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6732 pBranch *pbr = PCI(pc)->label;
6733 if(pbr && pbr->next) {
6734 pCode *pcd = pb->pcHead;
6736 // fprintf(stderr, "multiple labels\n");
6737 // pc->print(stderr,pc);
6742 while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6743 //fprintf(stderr,"Used by:\n");
6744 //pcd->print(stderr,pcd);
6746 exchangeLabels(PCL(pbr->pc),pcd);
6755 for(pc = pb->pcHead; pc; pc = pc->next) {
6757 if(isPCL(pc)) // pc->type == PC_LABEL)
6759 else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6760 pcl = PCL(PCI(pc)->label->pc);
6763 // fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6765 /* This pCode is a label, so search the pBlock to see if anyone
6768 if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6770 //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6771 /* Couldn't find an instruction that refers to this label
6772 * So, unlink the pCode label from it's pCode chain
6773 * and destroy the label */
6774 // fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6776 DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6777 if(pc->type == PC_LABEL) {
6778 pic16_unlinkpCode(pc);
6779 pCodeLabelDestruct(pc);
6781 unlinkpCodeFromBranch(pc, PCODE(pcl));
6782 /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6783 Safe_free(pc->label);
6793 /*-----------------------------------------------------------------*/
6794 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */
6795 /* chain and put them into pBranches that are */
6796 /* associated with the appropriate pCode */
6798 /*-----------------------------------------------------------------*/
6799 void pic16_pBlockMergeLabels(pBlock *pb)
6802 pCode *pc, *pcnext=NULL;
6807 /* First, Try to remove any unused labels */
6808 //pBlockRemoveUnusedLabels(pb);
6810 /* Now loop through the pBlock and merge the labels with the opcodes */
6813 // for(pc = pb->pcHead; pc; pc = pc->next) {
6816 pCode *pcn = pc->next;
6818 if(pc->type == PC_LABEL) {
6820 // fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6821 // fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6823 if((pcnext = pic16_findNextInstruction(pc) )) {
6825 // pcnext->print(stderr, pcnext);
6827 // Unlink the pCode label from it's pCode chain
6828 pic16_unlinkpCode(pc);
6830 // fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6831 // And link it into the instruction's pBranch labels. (Note, since
6832 // it's possible to have multiple labels associated with one instruction
6833 // we must provide a means to accomodate the additional labels. Thus
6834 // the labels are placed into the singly-linked list "label" as
6835 // opposed to being a single member of the pCodeInstruction.)
6837 //_ALLOC(pbr,sizeof(pBranch));
6839 pbr = Safe_calloc(1,sizeof(pBranch));
6843 PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6846 if(pic16_pcode_verbose)
6847 fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6849 } else if(pc->type == PC_CSOURCE) {
6851 /* merge the source line symbolic info into the next instruction */
6852 if((pcnext = pic16_findNextInstruction(pc) )) {
6854 // Unlink the pCode label from it's pCode chain
6855 pic16_unlinkpCode(pc);
6856 PCI(pcnext)->cline = PCCS(pc);
6857 //fprintf(stderr, "merging CSRC\n");
6858 //genericPrint(stderr,pcnext);
6864 pBlockRemoveUnusedLabels(pb);
6868 /*-----------------------------------------------------------------*/
6869 /*-----------------------------------------------------------------*/
6870 static int OptimizepCode(char dbName)
6872 #define MAX_PASSES 4
6881 DFPRINTF((stderr," Optimizing pCode\n"));
6885 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6886 if('*' == dbName || getpBlock_dbName(pb) == dbName)
6887 matches += OptimizepBlock(pb);
6890 while(matches && ++passes < MAX_PASSES);
6897 const char *pic16_pCodeOpType(pCodeOp *pcop);
6898 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6901 /*-----------------------------------------------------------------*/
6902 /* pic16_popCopyGPR2Bit - copy a pcode operator */
6903 /*-----------------------------------------------------------------*/
6905 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6909 // fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6912 pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6914 if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6917 assert(pcop != NULL);
6919 if( !( (pcop->type == PO_LABEL) ||
6920 (pcop->type == PO_LITERAL) ||
6921 (pcop->type == PO_STR) ))
6922 PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */
6923 PCOR(pcop)->r->wasUsed = 1;
6924 PCOR(pcop)->instance = PCOR(pc)->instance;
6930 /*----------------------------------------------------------------------*
6931 * pic16_areRegsSame - check to see if the names of two registers match *
6932 *----------------------------------------------------------------------*/
6933 int pic16_areRegsSame(regs *r1, regs *r2)
6935 if(!strcmp(r1->name, r2->name))return 1;
6941 /*-----------------------------------------------------------------*/
6942 /*-----------------------------------------------------------------*/
6943 static void pic16_FixRegisterBanking(pBlock *pb)
6947 regs *reg, *prevreg;
6948 unsigned char flag=0;
6953 pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6956 /* loop through all of the flow blocks with in one pblock */
6958 // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6962 /* at this point, pc should point to a PC_FLOW object */
6963 /* for each flow block, determine the register banking
6967 /* if label, then might come from other point, force banksel */
6968 if(isPCL(pc))prevreg = NULL;
6970 if(!isPCI(pc))goto loop;
6972 if(PCI(pc)->label)prevreg = NULL;
6974 if(PCI(pc)->is2MemOp)goto loop;
6976 /* if goto, then force banksel */
6977 // if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6979 reg = pic16_getRegFromInstruction(pc);
6982 pc->print(stderr, pc);
6983 fprintf(stderr, "reg = %p\n", reg);
6986 fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6987 fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6988 reg->address,reg->isBitField, reg->isFixed);
6992 /* now make some tests to make sure that instruction needs bank switch */
6994 /* if no register exists, and if not a bit opcode goto loop */
6996 if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6999 if(isPCI_SKIP(pc)) {
7000 // fprintf(stderr, "instruction is SKIP instruction\n");
7003 if(reg && isACCESS_BANK(reg))goto loop;
7005 if(!isBankInstruction(pc))goto loop;
7007 if(isPCI_LIT(pc))goto loop;
7009 if(PCI(pc)->op == POC_CALL)goto loop;
7011 /* Examine the instruction before this one to make sure it is
7012 * not a skip type instruction */
7013 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7015 flag = 0; /* add before this instruction */
7017 /* if previous instruction is a skip one, then set flag
7018 * to 2 and call insertBankSwitch */
7019 if(pcprev && isPCI_SKIP(pcprev)) {
7024 if(pic16_options.opt_banksel>0) {
7025 char op1[128], op2[128];
7028 strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7029 strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7030 if(!strcmp(op1, op2))goto loop;
7034 insertBankSwitch(flag, pc);
7036 // fprintf(stderr, "BANK SWITCH inserted\n");
7044 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7046 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7047 int instrSize (pCode *pc)
7052 if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7053 return 4; // assumes only regular instructions using <= 4 bytes
7056 if (isPCI(pc)) return PCI(pc)->isize;
7061 /* Returns 1 if pc is referenced by the given label (either
7062 * pc is the label itself or is an instruction with an attached
7064 * Returns 0 if pc is not preceeded by the specified label.
7066 int isLabel (pCode *pc, char *label)
7070 // label attached to the pCode?
7071 if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7072 pBranch *lab = NULL;
7073 lab = PCI(pc)->label;
7076 if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7083 // is inline assembly label?
7084 if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7085 // do not compare trailing ':'
7086 if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7093 if (strcmp(PCL(pc)->label,label) == 0) {
7098 // no label/no label attached/wrong label(s)
7102 /* Returns the distance to the given label in terms of words.
7103 * Labels are searched only within -max .. max words from pc.
7104 * Returns max if the label could not be found or
7105 * its distance from pc in (-max..+max).
7107 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7108 int dist = instrSize(pc);
7112 while (dist < max && curr && !isLabel (curr, label)) {
7114 dist += instrSize(curr); // sizeof (instruction)
7116 if (curr && dist < max) {
7117 if (target != NULL) *target = curr;
7122 curr = pic16_findNextInstruction (pc->next);
7124 while (dist < max && curr && !isLabel (curr, label)) {
7125 dist += instrSize(curr); // sizeof (instruction)
7128 if (curr && dist < max) {
7129 if (target != NULL) *target = curr;
7133 if (target != NULL) *target = NULL;
7137 /* Returns -1 if pc does NOT denote an instruction like
7139 * Otherwise we return
7140 * (a) 0x10 + i for BTFSS
7141 * (b) 0x00 + i for BTFSC
7143 int isSkipOnStatus (pCode *pc)
7147 if (!pc || !isPCI(pc)) return -1;
7148 if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7149 else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7152 pcop = PCI(pc)->pcop;
7154 if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7155 return res + ((pCodeOpRegBit *)pcop)->bit;
7161 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7162 * returns 0 otherwise. */
7163 int isConditionalBranch (pCode *pc)
7165 if (!pc || !isPCI_BRANCH(pc)) return 0;
7167 switch (PCI(pc)->op) {
7185 /* Returns 1 if pc has a label attached to it.
7186 * This can be either a label stored in the pCode itself (.label)
7187 * or a label making up its own pCode preceding this pc.
7188 * Returns 0 if pc cannot be reached directly via a label.
7190 int hasNoLabel (pCode *pc)
7195 // are there any label pCodes between pc and the previous instruction?
7196 prev = pic16_findPrevInstruction (pc->prev);
7197 while (pc && pc != prev) {
7198 // pCode with attached label?
7199 if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7200 && PCI(pc)->label) {
7203 // is inline assembly label?
7204 if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7205 if (isPCW(pc) && PCW(pc)->label) return 0;
7208 if (isPCL(pc)) return 0;
7217 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7222 vsprintf (buf, fmt, va);
7225 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7228 /* Replaces the old pCode with the new one, moving the labels,
7229 * C source line and probably flow information to the new pCode.
7231 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7232 if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7235 /* first move all labels from old to new */
7236 PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7237 PCI(oldPC)->label = NULL;
7240 /* move C source line (if possible) */
7241 if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7242 PCI(newPC)->cline = PCI(oldPC)->cline;
7245 /* keep flow information intact */
7246 newPC->seq = oldPC->seq;
7247 PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7248 if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7249 PCI(newPC)->pcflow->end = newPC;
7252 /* insert a comment stating which pCode has been replaced */
7254 if (pic16_pcode_verbose || pic16_debug_verbose) {
7256 pic16_pCode2str (pc_str, 256, oldPC);
7257 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7261 /* insert new pCode into pBlock */
7262 pic16_pCodeInsertAfter (oldPC, newPC);
7263 pic16_unlinkpCode (oldPC);
7265 /* destruct replaced pCode */
7266 oldPC->destruct (oldPC);
7269 /* Returns the inverted conditional branch (if any) or NULL.
7270 * pcop must be set to the new jump target.
7272 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7276 if (!bcc || !isPCI(bcc)) return NULL;
7278 switch (PCI(bcc)->op) {
7279 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7280 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7281 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7282 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7283 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7284 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7285 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7286 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7293 #define MAX_DIST_GOTO 0x7FFFFFFF
7294 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7295 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7296 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7297 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7299 /* Follows GOTO/BRA instructions to their target instructions, stores the
7300 * final destination (not a GOTO or BRA instruction) in target and returns
7301 * the distance from the original pc to *target.
7303 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7306 pCodeOp *lastPCOP = NULL;
7310 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7312 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7313 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7314 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7316 lastPCOP = PCI(curr)->pcop;
7317 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7318 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7321 if (target) *target = last;
7322 if (pcop) *pcop = lastPCOP;
7326 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7327 * Otherwise the first pCode after the jumptable (after
7328 * the OPT_JUMPTABLE_END tag) is returned.
7330 pCode *skipJumptables (pCode *pc, int *isJumptable)
7333 if (!pc) return NULL;
7335 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7337 //fprintf (stderr, "SKIPPING jumptable\n");
7339 //pc->print(stderr, pc);
7341 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7342 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7343 //fprintf (stderr, "<<JUMPTAB:\n");
7344 // skip OPT_END as well
7345 if (pc) pc = pc->next;
7351 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7355 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7356 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7357 pc = skipJumptables (pc, &isJumptab);
7359 // pc is the first pCode after the jumptable
7362 // pc has not been changed by skipJumptables()
7370 /* Turn GOTOs into BRAs if distance between GOTO and label
7371 * is less than 1024 bytes.
7373 * This method is especially useful if GOTOs after BTFS[SC]
7374 * can be turned into BRAs as GOTO would cost another NOP
7377 void pic16_OptimizeJumps ()
7380 pCode *pc_prev = NULL;
7381 pCode *pc_next = NULL;
7384 int change, iteration, isJumptab;
7387 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7389 if (!the_pFile) return;
7391 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7393 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7394 int matchedInvertRule = 1;
7397 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7399 pc = pic16_findNextInstruction (pb->pcHead);
7402 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7404 // skip jumptable, i.e. start over with no pc_prev!
7410 /* (1) resolve chained jumps
7411 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7412 * (a) leave dead code in and
7413 * (b) skip over the dead code with an (unneccessary) jump.
7415 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7416 pCodeOp *lastTargetOp = NULL;
7417 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7418 int maxDist = MAX_DIST_BCC;
7419 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7420 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7422 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7423 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7424 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7425 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7426 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7427 PCI(pc)->pcop->name = lastTargetOp->name;
7436 int condBraType = isSkipOnStatus(pc_prev);
7437 label = PCI(pc)->pcop->name;
7438 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7439 if (dist < 0) dist = -dist;
7440 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7444 /* (2) remove "GOTO label; label:" */
7445 if (isLabel (pc_next, label)) {
7446 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7447 // first remove all preceeding SKIP instructions
7448 while (pc_prev && isPCI_SKIP(pc_prev)) {
7449 // attach labels on this instruction to pc_next
7450 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7451 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7452 PCI(pc_prev)->label = NULL;
7453 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7454 pic16_unlinkpCode (pc_prev);
7455 pc_prev = pic16_findPrevInstruction (pc);
7457 // now remove the redundant goto itself
7458 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7459 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7460 pic16_unlinkpCode (pc);
7461 pc = pic16_findPrevInstruction(pc_next->prev);
7462 isHandled = 1; // do not perform further optimizations
7468 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7469 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7470 if (dist < MAX_DIST_BCC) {
7472 switch (condBraType) {
7473 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7474 // no BDC on DIGIT CARRY available
7475 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7476 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7477 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7478 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7479 // no BNDC on DIGIT CARRY available
7480 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7481 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7482 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7484 // no replacement possible
7489 // ATTENTION: keep labels attached to BTFSx!
7490 // HINT: GOTO is label free (checked above)
7491 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7492 isHandled = 1; // do not perform further optimizations
7493 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7494 pic16_pCodeReplace (pc_prev, bcc);
7501 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7507 // (4) eliminate the following (common) tripel:
7509 // labels1: Bcc label2;
7510 // GOTO somewhere; ; <-- instruction referenced by pc
7512 // and replace it by
7513 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7515 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7516 // to <cont.> instead
7517 // ATTENTION: This optimization is only valid if <pred.> is
7518 // not a skip operation!
7519 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7520 // ATTENTION: no label may be attached to the GOTO instruction!
7521 if (isConditionalBranch(pc_prev)
7522 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7523 && (dist < MAX_DIST_BCC)
7524 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7525 && hasNoLabel(pc)) {
7526 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7529 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7530 isHandled = 1; // do not perform further optimizations
7531 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7532 pic16_pCodeReplace (pc_prev, newBcc);
7537 matchedInvertRule++;
7542 /* (5) now just turn GOTO into BRA */
7543 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7544 if (dist < MAX_DIST_BRA) {
7545 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7546 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7547 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7548 pic16_pCodeReplace (pc, newBra);
7553 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7556 } // if (!isHandled)
7563 pBlockRemoveUnusedLabels (pb);
7565 // This line enables goto chain resolution!
7566 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7569 } while (change); /* fixpoint iteration per pBlock */
7572 // emit some statistics concerning goto-optimization
7574 if (pic16_debug_verbose || pic16_pcode_verbose) {
7575 fprintf (stderr, "optimize-goto:\n"
7576 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7577 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7578 "\t%5d conditional \"skipping\" jumps inverted\n"
7579 "\t%5d GOTOs to next instruction removed\n"
7580 "\t%5d chained GOTOs resolved\n",
7581 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7584 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7588 #undef MAX_JUMPCHAIN_DEPTH
7589 #undef MAX_DIST_GOTO
7593 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7595 static void pBlockDestruct(pBlock *pb)
7606 /*-----------------------------------------------------------------*/
7607 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7608 /* name dbName and combine them */
7609 /* into one block */
7610 /*-----------------------------------------------------------------*/
7611 static void mergepBlocks(char dbName)
7614 pBlock *pb, *pbmerged = NULL,*pbn;
7616 pb = the_pFile->pbHead;
7618 //fprintf(stderr," merging blocks named %c\n",dbName);
7622 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7623 if( getpBlock_dbName(pb) == dbName) {
7625 //fprintf(stderr," merged block %c\n",dbName);
7630 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7631 /* pic16_addpCode2pBlock doesn't handle the tail: */
7632 pbmerged->pcTail = pb->pcTail;
7634 pb->prev->next = pbn;
7636 pbn->prev = pb->prev;
7641 //pic16_printpBlock(stderr, pbmerged);
7648 /*-----------------------------------------------------------------*/
7649 /* AnalyzeFlow - Examine the flow of the code and optimize */
7651 /* level 0 == minimal optimization */
7652 /* optimize registers that are used only by two instructions */
7653 /* level 1 == maximal optimization */
7654 /* optimize by looking at pairs of instructions that use the */
7656 /*-----------------------------------------------------------------*/
7658 static void AnalyzeFlow(int level)
7660 static int times_called=0;
7664 /* remove unused allocated registers before exiting */
7665 pic16_RemoveUnusedRegisters();
7670 /* if this is not the first time this function has been called,
7671 * then clean up old flow information */
7672 if(times_called++) {
7673 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7675 pic16_RegsUnMapLiveRanges();
7679 /* Phase 2 - Flow Analysis - Register Banking
7681 * In this phase, the individual flow blocks are examined
7682 * and register banking is fixed.
7686 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7687 pic16_FixRegisterBanking(pb);
7690 /* Phase 2 - Flow Analysis
7692 * In this phase, the pCode is partition into pCodeFlow
7693 * blocks. The flow blocks mark the points where a continuous
7694 * stream of instructions changes flow (e.g. because of
7695 * a call or goto or whatever).
7698 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7699 pic16_BuildFlow(pb);
7702 /* Phase 2 - Flow Analysis - linking flow blocks
7704 * In this phase, the individual flow blocks are examined
7705 * to determine their order of excution.
7708 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7712 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7713 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7714 pic16_createDF (pb);
7715 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7716 pic16_vcg_dump_default (pb);
7718 //pic16_destructDF (pb);
7722 if (0) releaseStack (); // releasing is costly...
7726 /* Phase 3 - Flow Analysis - Flow Tree
7728 * In this phase, the individual flow blocks are examined
7729 * to determine their order of execution.
7732 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7733 pic16_BuildFlowTree(pb);
7736 /* Phase x - Flow Analysis - Used Banks
7738 * In this phase, the individual flow blocks are examined
7739 * to determine the Register Banks they use
7743 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7748 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7749 pic16_pCodeRegMapLiveRanges(pb);
7751 pic16_RemoveUnusedRegisters();
7752 pic16_removeUnusedRegistersDF ();
7754 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7755 pic16_pCodeRegOptimizeRegUsage(level);
7764 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7769 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7772 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7773 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7774 pcflow = pcflow->next) {
7775 FillFlow(PCFL(pcflow));
7780 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7783 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7784 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7785 pcflow = pcflow->next) {
7786 FlowStats(PCFL(pcflow));
7792 /* VR -- no need to analyze banking in flow, but left here :
7793 * 1. because it may be used in the future for other purposes
7794 * 2. because if omitted we'll miss some optimization done here
7796 * Perhaps I should rename it to something else
7799 /*-----------------------------------------------------------------*/
7800 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7801 /* assigned to the registers. */
7803 /*-----------------------------------------------------------------*/
7805 void pic16_AnalyzeBanking(void)
7809 /* Phase x - Flow Analysis - Used Banks
7811 * In this phase, the individual flow blocks are examined
7812 * to determine the Register Banks they use
7822 if(!the_pFile)return;
7824 if(!pic16_options.no_banksel) {
7825 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7826 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7827 pic16_FixRegisterBanking(pb);
7832 /*-----------------------------------------------------------------*/
7833 /* buildCallTree - Look at the flow and extract all of the calls. */
7834 /*-----------------------------------------------------------------*/
7835 static set *register_usage(pBlock *pb);
7837 static void buildCallTree(void )
7849 /* Now build the call tree.
7850 First we examine all of the pCodes for functions.
7851 Keep in mind that the function boundaries coincide
7852 with pBlock boundaries.
7854 The algorithm goes something like this:
7855 We have two nested loops. The outer loop iterates
7856 through all of the pBlocks/functions. The inner
7857 loop iterates through all of the pCodes for
7858 a given pBlock. When we begin iterating through
7859 a pBlock, the variable pc_fstart, pCode of the start
7860 of a function, is cleared. We then search for pCodes
7861 of type PC_FUNCTION. When one is encountered, we
7862 initialize pc_fstart to this and at the same time
7863 associate a new pBranch object that signifies a
7864 branch entry. If a return is found, then this signifies
7865 a function exit point. We'll link the pCodes of these
7866 returns to the matching pc_fstart.
7868 When we're done, a doubly linked list of pBranches
7869 will exist. The head of this list is stored in
7870 `the_pFile', which is the meta structure for all
7871 of the pCode. Look at the pic16_printCallTree function
7872 on how the pBranches are linked together.
7875 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7876 pCode *pc_fstart=NULL;
7877 for(pc = pb->pcHead; pc; pc = pc->next) {
7879 if(isPCI(pc) && pc_fstart) {
7880 if(PCI(pc)->is2MemOp) {
7881 r = pic16_getRegFromInstruction2(pc);
7882 if(r && !strcmp(r->name, "POSTDEC1"))
7883 PCF(pc_fstart)->stackusage++;
7885 r = pic16_getRegFromInstruction(pc);
7886 if(r && !strcmp(r->name, "PREINC1"))
7887 PCF(pc_fstart)->stackusage--;
7892 if (PCF(pc)->fname) {
7895 sprintf(buf, "%smain", port->fun_prefix);
7896 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7897 //fprintf(stderr," found main \n");
7898 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7902 pbr = Safe_calloc(1,sizeof(pBranch));
7903 pbr->pc = pc_fstart = pc;
7906 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7908 // Here's a better way of doing the same:
7909 addSet(&pb->function_entries, pc);
7912 // Found an exit point in a function, e.g. return
7913 // (Note, there may be more than one return per function)
7915 pBranchLink(PCF(pc_fstart), PCF(pc));
7917 addSet(&pb->function_exits, pc);
7919 } else if(isCALL(pc)) {
7920 addSet(&pb->function_calls,pc);
7927 /* This is not needed because currently all register used
7928 * by a function are stored in stack -- VR */
7930 /* Re-allocate the registers so that there are no collisions
7931 * between local variables when one function call another */
7934 // pic16_deallocateAllRegs();
7936 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7944 /*-----------------------------------------------------------------*/
7945 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7946 /* all of the logical connections. */
7948 /* Essentially what's done here is that the pCode flow is */
7950 /*-----------------------------------------------------------------*/
7952 void pic16_AnalyzepCode(char dbName)
7963 /* Phase 1 - Register allocation and peep hole optimization
7965 * The first part of the analysis is to determine the registers
7966 * that are used in the pCode. Once that is done, the peep rules
7967 * are applied to the code. We continue to loop until no more
7968 * peep rule optimizations are found (or until we exceed the
7969 * MAX_PASSES threshold).
7971 * When done, the required registers will be determined.
7977 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7978 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7980 /* First, merge the labels with the instructions */
7981 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7982 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7984 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7985 //fprintf(stderr," analyze and merging block %c\n",dbName);
7986 pic16_pBlockMergeLabels(pb);
7989 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7994 changes = OptimizepCode(dbName);
7997 } while(changes && (i++ < MAX_PASSES));
8004 /* convert a series of movff's of local regs to stack, with a single call to
8005 * a support functions which does the same thing via loop */
8006 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8010 char *fname[]={"__lr_store", "__lr_restore"};
8012 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8014 pct = pic16_findNextInstruction(pcstart->next);
8017 pct = pc->next; //pic16_findNextInstruction(pc->next);
8018 // pc->print(stderr, pc);
8019 if(isPCI(pc) && PCI(pc)->label) {
8020 pbr = PCI(pc)->label;
8021 while(pbr && pbr->pc) {
8022 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8026 // pc->print(stderr, pc);
8028 pc->prev->next = pct;
8029 pct->prev = pc->prev;
8033 } while ((pc) && (pc != pcend));
8035 /* unlink movff instructions */
8036 pcstart->next = pcend;
8037 pcend->prev = pcstart;
8041 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8042 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8045 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8046 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8047 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8050 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8051 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8058 sym = newSymbol( fname[ entry?0:1 ], 0 );
8059 strcpy(sym->rname, fname[ entry?0:1 ]);
8060 checkAddSym(&externs, sym);
8062 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8067 /*-----------------------------------------------------------------*/
8068 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
8069 /* local registers to a support function call */
8070 /*-----------------------------------------------------------------*/
8071 void pic16_OptimizeLocalRegs(void)
8076 pCodeOpLocalReg *pclr;
8079 regs *r, *lastr=NULL, *firstr=NULL;
8080 pCode *pcstart=NULL, *pcend=NULL;
8085 * local_regs begin mark
8086 * MOVFF r0x01, POSTDEC1
8087 * MOVFF r0x02, POSTDEC1
8090 * MOVFF r0x0n, POSTDEC1
8091 * local_regs end mark
8093 * convert the above to the below:
8094 * MOVLW starting_register_index
8096 * MOVLW register_count
8097 * call __save_registers_in_stack
8103 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8104 inRegCount = regCount = 0;
8105 firstr = lastr = NULL;
8106 for(pc = pb->pcHead; pc; pc = pc->next) {
8108 /* hold current function name */
8109 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8111 if(pc && (pc->type == PC_INFO)) {
8114 if(pci->type == INF_LOCALREGS) {
8115 pclr = PCOLR(pci->oper1);
8117 if((pclr->type == LR_ENTRY_BEGIN)
8118 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8121 switch(pclr->type) {
8122 case LR_ENTRY_BEGIN:
8124 inRegCount = 1; regCount = 0;
8125 pcstart = pc; //pic16_findNextInstruction(pc->next);
8126 firstr = lastr = NULL;
8132 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8135 if(curFunc && inWparamList(curFunc+1)) {
8136 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8140 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8145 firstr = lastr = NULL;
8149 if(inRegCount == -1) {
8150 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8156 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8158 r = pic16_getRegFromInstruction(pc);
8160 r = pic16_getRegFromInstruction2(pc);
8161 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8162 if(!firstr)firstr = r;
8164 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8176 /*-----------------------------------------------------------------*/
8177 /* ispCodeFunction - returns true if *pc is the pCode of a */
8179 /*-----------------------------------------------------------------*/
8180 static bool ispCodeFunction(pCode *pc)
8183 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8189 /*-----------------------------------------------------------------*/
8190 /* findFunction - Search for a function by name (given the name) */
8191 /* in the set of all functions that are in a pBlock */
8192 /* (note - I expect this to change because I'm planning to limit */
8193 /* pBlock's to just one function declaration */
8194 /*-----------------------------------------------------------------*/
8195 static pCode *findFunction(char *fname)
8202 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8204 pc = setFirstItem(pb->function_entries);
8207 if((pc->type == PC_FUNCTION) &&
8209 (strcmp(fname, PCF(pc)->fname)==0))
8212 pc = setNextItem(pb->function_entries);
8220 static void MarkUsedRegisters(set *regset)
8225 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8226 // fprintf(stderr, "marking register = %s\t", r1->name);
8227 r2 = pic16_regWithIdx(r1->rIdx);
8228 // fprintf(stderr, "to register = %s\n", r2->name);
8234 static void pBlockStats(FILE *of, pBlock *pb)
8240 if(!pic16_pcode_verbose)return;
8242 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8244 // for now just print the first element of each set
8245 pc = setFirstItem(pb->function_entries);
8247 fprintf(of,";entry: ");
8250 pc = setFirstItem(pb->function_exits);
8252 fprintf(of,";has an exit\n");
8256 pc = setFirstItem(pb->function_calls);
8258 fprintf(of,";functions called:\n");
8261 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8262 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8264 pc = setNextItem(pb->function_calls);
8268 r = setFirstItem(pb->tregisters);
8270 int n = elementsInSet(pb->tregisters);
8272 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8275 fprintf(of, "; %s\n",r->name);
8276 r = setNextItem(pb->tregisters);
8280 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8283 /*-----------------------------------------------------------------*/
8284 /*-----------------------------------------------------------------*/
8286 static void sequencepCode(void)
8292 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8294 pb->seq = GpCodeSequenceNumber+1;
8296 for( pc = pb->pcHead; pc; pc = pc->next)
8297 pc->seq = ++GpCodeSequenceNumber;
8303 /*-----------------------------------------------------------------*/
8304 /*-----------------------------------------------------------------*/
8305 static set *register_usage(pBlock *pb)
8308 set *registers=NULL;
8309 set *registersInCallPath = NULL;
8311 /* check recursion */
8313 pc = setFirstItem(pb->function_entries);
8320 if(pc->type != PC_FUNCTION)
8321 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8323 pc = setFirstItem(pb->function_calls);
8324 for( ; pc; pc = setNextItem(pb->function_calls)) {
8326 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8327 char *dest = pic16_get_op_from_instruction(PCI(pc));
8329 pcn = findFunction(dest);
8331 registersInCallPath = register_usage(pcn->pb);
8333 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8338 pBlockStats(stderr,pb); // debug
8341 // Mark the registers in this block as used.
8343 MarkUsedRegisters(pb->tregisters);
8344 if(registersInCallPath) {
8345 /* registers were used in the functions this pBlock has called */
8346 /* so now, we need to see if these collide with the ones we are */
8349 regs *r1,*r2, *newreg;
8351 DFPRINTF((stderr,"comparing registers\n"));
8353 r1 = setFirstItem(registersInCallPath);
8356 r2 = setFirstItem(pb->tregisters);
8358 while(r2 && (r1->type != REG_STK)) {
8360 if(r2->rIdx == r1->rIdx) {
8361 newreg = pic16_findFreeReg(REG_GPR);
8365 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8369 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8370 r1->rIdx, newreg->rIdx));
8371 r2->rIdx = newreg->rIdx;
8372 //if(r2->name) Safe_free(r2->name);
8374 r2->name = Safe_strdup(newreg->name);
8378 newreg->wasUsed = 1;
8380 r2 = setNextItem(pb->tregisters);
8383 r1 = setNextItem(registersInCallPath);
8386 /* Collisions have been resolved. Now free the registers in the call path */
8387 r1 = setFirstItem(registersInCallPath);
8389 if(r1->type != REG_STK) {
8390 newreg = pic16_regWithIdx(r1->rIdx);
8393 r1 = setNextItem(registersInCallPath);
8397 // MarkUsedRegisters(pb->registers);
8399 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8402 DFPRINTF((stderr,"returning regs\n"));
8404 DFPRINTF((stderr,"not returning regs\n"));
8406 DFPRINTF((stderr,"pBlock after register optim.\n"));
8407 pBlockStats(stderr,pb); // debug
8413 /*-----------------------------------------------------------------*/
8414 /* pct2 - writes the call tree to a file */
8416 /*-----------------------------------------------------------------*/
8417 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8421 // set *registersInCallPath = NULL;
8427 fprintf(of, "recursive function\n");
8428 return; //recursion ?
8431 pc = setFirstItem(pb->function_entries);
8438 for(i=0;i<indent;i++) // Indentation
8442 if(pc->type == PC_FUNCTION) {
8443 usedstack += PCF(pc)->stackusage;
8444 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8445 } else return; // ???
8448 pc = setFirstItem(pb->function_calls);
8449 for( ; pc; pc = setNextItem(pb->function_calls)) {
8451 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8452 char *dest = pic16_get_op_from_instruction(PCI(pc));
8454 pcn = findFunction(dest);
8456 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8458 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8466 /*-----------------------------------------------------------------*/
8467 /* pic16_printCallTree - writes the call tree to a file */
8469 /*-----------------------------------------------------------------*/
8471 void pic16_printCallTree(FILE *of)
8483 fprintf(of, "\npBlock statistics\n");
8484 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8488 fprintf(of,"Call Tree\n");
8489 pbr = the_pFile->functions;
8493 if(!ispCodeFunction(pc))
8494 fprintf(of,"bug in call tree");
8497 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8499 while(pc->next && !ispCodeFunction(pc->next)) {
8501 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8502 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8510 fprintf(of,"\n**************\n\na better call tree\n");
8511 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8516 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8517 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8523 /*-----------------------------------------------------------------*/
8525 /*-----------------------------------------------------------------*/
8527 static void InlineFunction(pBlock *pb)
8535 pc = setFirstItem(pb->function_calls);
8537 for( ; pc; pc = setNextItem(pb->function_calls)) {
8540 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8546 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8548 //fprintf(stderr,"Cool can inline:\n");
8549 //pcn->print(stderr,pcn);
8551 //fprintf(stderr,"recursive call Inline\n");
8552 InlineFunction(pcn->pb);
8553 //fprintf(stderr,"return from recursive call Inline\n");
8556 At this point, *pc points to a CALL mnemonic, and
8557 *pcn points to the function that is being called.
8559 To in-line this call, we need to remove the CALL
8560 and RETURN(s), and link the function pCode in with
8566 /* Remove the CALL */
8570 /* remove callee pBlock from the pBlock linked list */
8571 removepBlock(pcn->pb);
8579 /* Remove the Function pCode */
8580 pct = pic16_findNextInstruction(pcn->next);
8582 /* Link the function with the callee */
8583 pc->next = pcn->next;
8584 pcn->next->prev = pc;
8586 /* Convert the function name into a label */
8588 pbr = Safe_calloc(1,sizeof(pBranch));
8589 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8591 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8592 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8594 /* turn all of the return's except the last into goto's */
8595 /* check case for 2 instruction pBlocks */
8596 pce = pic16_findNextInstruction(pcn->next);
8598 pCode *pce_next = pic16_findNextInstruction(pce->next);
8600 if(pce_next == NULL) {
8601 /* found the last return */
8602 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8604 //fprintf(stderr,"found last return\n");
8605 //pce->print(stderr,pce);
8606 pce->prev->next = pc_call->next;
8607 pc_call->next->prev = pce->prev;
8608 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8618 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8624 /*-----------------------------------------------------------------*/
8626 /*-----------------------------------------------------------------*/
8628 void pic16_InlinepCode(void)
8637 if(!functionInlining)
8640 /* Loop through all of the function definitions and count the
8641 * number of times each one is called */
8642 //fprintf(stderr,"inlining %d\n",__LINE__);
8644 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8646 pc = setFirstItem(pb->function_calls);
8648 for( ; pc; pc = setNextItem(pb->function_calls)) {
8651 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8652 if(pcn && isPCF(pcn)) {
8653 PCF(pcn)->ncalled++;
8656 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8661 //fprintf(stderr,"inlining %d\n",__LINE__);
8663 /* Now, Loop through the function definitions again, but this
8664 * time inline those functions that have only been called once. */
8666 InlineFunction(the_pFile->pbHead);
8667 //fprintf(stderr,"inlining %d\n",__LINE__);
8669 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8674 char *pic_optype_names[]={
8675 "PO_NONE", // No operand e.g. NOP
8676 "PO_W", // The working register (as a destination)
8677 "PO_WREG", // The working register (as a file register)
8678 "PO_STATUS", // The 'STATUS' register
8679 "PO_BSR", // The 'BSR' register
8680 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8682 "PO_INDF0", // The Indirect register
8683 "PO_INTCON", // Interrupt Control register
8684 "PO_GPR_REGISTER", // A general purpose register
8685 "PO_GPR_BIT", // A bit of a general purpose register
8686 "PO_GPR_TEMP", // A general purpose temporary register
8687 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8688 "PO_PCL", // Program counter Low register
8689 "PO_PCLATH", // Program counter Latch high register
8690 "PO_PCLATU", // Program counter Latch upper register
8691 "PO_PRODL", // Product Register Low
8692 "PO_PRODH", // Product Register High
8693 "PO_LITERAL", // A constant
8694 "PO_REL_ADDR", // A relative address
8695 "PO_IMMEDIATE", // (8051 legacy)
8696 "PO_DIR", // Direct memory (8051 legacy)
8697 "PO_CRY", // bit memory (8051 legacy)
8698 "PO_BIT", // bit operand.
8699 "PO_STR", // (8051 legacy)
8701 "PO_WILD", // Wild card operand in peep optimizer
8702 "PO_TWO_OPS" // combine two operands
8706 char *dumpPicOptype(PIC_OPTYPE type)
8708 assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8709 return (pic_optype_names[ type ]);
8713 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8716 #define MAX_COMMON_BANK_SIZE 32
8717 #define FIRST_PSEUDO_BANK_NR 1000
8719 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8720 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8721 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8724 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8727 pseudoBankNr bank; // number assigned to this pseudoBank
8728 unsigned int size; // number of operands assigned to this bank
8729 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8732 /*----------------------------------------------------------------------*/
8733 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8734 /*----------------------------------------------------------------------*/
8735 unsigned int hashSymbol (const char *str)
8737 unsigned int res = 0;
8742 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8749 /*-----------------------------------------------------------------------*/
8750 /* compareSymbol - return 1 iff sym1 equals sym2 */
8751 /*-----------------------------------------------------------------------*/
8752 int compareSymbol (const void *sym1, const void *sym2)
8754 char *s1 = (char*) sym1;
8755 char *s2 = (char*) sym2;
8757 return (strcmp (s1,s2) == 0);
8760 /*-----------------------------------------------------------------------*/
8761 /* comparePre - return 1 iff p1 == p2 */
8762 /*-----------------------------------------------------------------------*/
8763 int comparePtr (const void *p1, const void *p2)
8768 /*----------------------------------------------------------*/
8769 /* getSymbolFromOperand - return a pointer to the symbol in */
8770 /* the given operand and its length */
8771 /*----------------------------------------------------------*/
8772 char *getSymbolFromOperand (char *op, int *len)
8777 if (!op) return NULL;
8779 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8781 if (*sym == '(') sym++;
8784 while (((*curr >= 'A') && (*curr <= 'Z'))
8785 || ((*curr >= 'a') && (*curr <= 'z'))
8786 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8787 || (*curr == '_')) {
8788 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8796 /*--------------------------------------------------------------------------*/
8797 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8798 /*--------------------------------------------------------------------------*/
8799 char *getSymFromBank (pseudoBankNr bank)
8803 if (bank < 0) return "<INVALID BANK NR>";
8804 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8807 /*-----------------------------------------------------------------------*/
8808 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8809 /* bank number (uses hTab sym2bank), if the */
8810 /* symbol is not yet assigned a pseudo bank it */
8811 /* is assigned one here */
8812 /*-----------------------------------------------------------------------*/
8813 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8815 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8821 hash = hashSymbol (op) % sym2bank->size;
8822 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8823 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8825 if (bank == UNKNOWN_BANK) {
8826 // create a pseudo bank for the operand
8828 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8829 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8830 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8831 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8833 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8841 /*--------------------------------------------------------------------*/
8842 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8843 /*--------------------------------------------------------------------*/
8844 int isBanksel (pCode *pc)
8848 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8849 // BANKSEL <variablename> or MOVLB <banknr>
8850 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8854 // check for inline assembler BANKSELs
8855 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8856 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8857 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8861 // assume pc is no BANKSEL instruction
8865 /*---------------------------------------------------------------------------------*/
8866 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8867 /* This method can not guarantee to find all modifications of the */
8868 /* BSR (e.g. via INDirection registers) but covers all compiler */
8869 /* generated plus some cases. */
8870 /*---------------------------------------------------------------------------------*/
8871 int invalidatesBSR(pCode *pc)
8873 // assembler directives invalidate BSR (well, they might, we don't know)
8874 if (isPCAD(pc)) return 1;
8876 // only ASMDIRs and pCodeInstructions can invalidate BSR
8877 if (!isPCI(pc)) return 0;
8879 // we have a pCodeInstruction
8881 // check for BSR modifying instructions
8882 switch (PCI(pc)->op) {
8886 case POC_RETFIE: // might be used as CALL replacement
8887 case POC_RETLW: // might be used as CALL replacement
8888 case POC_RETURN: // might be used as CALL replacement
8893 default: // other instruction do not change BSR unless BSR is an explicit operand!
8894 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8898 // no change of BSR possible/probable
8902 /*------------------------------------------------------------*/
8903 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8904 /* the symbol referenced in this BANKSEL */
8905 /*------------------------------------------------------------*/
8906 pseudoBankNr getBankFromBanksel (pCode *pc)
8909 int data = (int)NULL;
8911 if (!pc) return INVALID_BANK;
8913 if (isPCAD(pc) && PCAD(pc)->directive) {
8914 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8915 // get symbolname from PCAD(pc)->arg
8916 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8917 sym = PCAD(pc)->arg;
8918 data = getPseudoBankNrFromOperand (sym);
8919 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8920 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8921 // get (literal) bank number from PCAD(pc)->arg
8922 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8923 assert (0 && "not yet implemented - turn off banksel optimization for now");
8925 } else if (isPCI(pc)) {
8926 if (PCI(pc)->op == POC_BANKSEL) {
8927 // get symbolname from PCI(pc)->pcop->name (?)
8928 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8929 sym = PCI(pc)->pcop->name;
8930 data = getPseudoBankNrFromOperand (sym);
8931 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8932 } else if (PCI(pc)->op == POC_MOVLB) {
8933 // get (literal) bank number from PCI(pc)->pcop->name
8934 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8935 assert (0 && "not yet implemented - turn off banksel optimization for now");
8940 // no assigned bank could be found
8941 return UNKNOWN_BANK;
8946 /*------------------------------------------------------------------------------*/
8947 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8948 /*------------------------------------------------------------------------------*/
8949 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8953 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8956 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8957 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8959 if (data->bank != bank)
8966 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8970 /*------------------------------------------------------------------*/
8971 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8972 /* bank is selected at a given pCode */
8973 /*------------------------------------------------------------------*/
8975 /* Create a graph with pseudo banks as its nodes and switches between
8976 * these as edges (with the edge weight representing the absolute
8977 * number of BANKSELs from one to the other).
8978 * Removes redundand BANKSELs instead iff mod == 1.
8979 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8980 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8982 * TODO: check ALL instructions operands if they modify BSR directly...
8984 * pb - the pBlock to annotate
8985 * mod - select either graph creation (0) or BANKSEL removal (1)
8987 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8989 pCode *pc, *pc_next;
8990 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8991 int isBankselect = 0;
8992 unsigned int banksels=0;
8996 pc = pic16_findNextInstruction(pb->pcHead);
8998 isBankselect = isBanksel (pc);
8999 pc_next = pic16_findNextInstruction (pc->next);
9001 if (!hasNoLabel (pc)) {
9002 // we don't know our predecessors -- assume different BSRs
9003 prevBSR = UNKNOWN_BANK;
9004 pseudoBSR = UNKNOWN_BANK;
9005 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9008 // check if this is a BANKSEL instruction
9010 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9011 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9013 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9014 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9015 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9016 pic16_unlinkpCode (pc);
9020 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9025 if (!isBankselect && invalidatesBSR(pc)) {
9026 // check if this instruction invalidates the pseudoBSR
9027 pseudoBSR = UNKNOWN_BANK;
9028 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9031 prevBSR = pseudoBSR;
9038 /*------------------------------------------------------------------------------------*/
9039 /* assignToSameBank - returns 0 on success or an error code */
9040 /* 1 - common bank would be too large */
9041 /* 2 - assignment to fixed (absolute) bank not performed */
9043 /* This functions assumes that unsplittable operands are already assigned to the same */
9044 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
9045 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
9046 /* TODO: Symbols with an abslute address must be handled specially! */
9047 /*------------------------------------------------------------------------------------*/
9048 int assignToSameBank (int bank0, int bank1, int doAbs)
9050 int eff0, eff1, dummy;
9051 pseudoBank *pbank0, *pbank1;
9054 eff0 = getEffectiveBank (bank0);
9055 eff1 = getEffectiveBank (bank1);
9057 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9059 // nothing to do if already same bank
9060 if (eff0 == eff1) return 0;
9062 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9065 // ensure eff0 < eff1
9067 // swap eff0 and eff1
9076 // now assign bank eff1 to bank eff0
9077 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9079 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9080 pbank0->bank = eff0;
9083 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9087 hitem = hTabSearch (coerce, eff1 % coerce->size);
9088 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9089 hitem = hitem->next;
9091 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9094 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9095 pbank0->bank, pbank0->size,
9096 getSymFromBank (eff0), getSymFromBank (eff1));
9100 if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9102 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9103 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9104 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9105 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9109 pbank0->size += pbank1->size;
9111 if (pbank1->ref == 0) Safe_free (pbank1);
9117 hitem->item = pbank0;
9119 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9122 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9127 /*----------------------------------------------------------------*/
9128 /* mergeGraphNodes - combines two nodes into one and modifies all */
9129 /* edges to and from the nodes accordingly */
9130 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9131 /* then also (B,A) must be an edge (possibly with weight 0). */
9132 /*----------------------------------------------------------------*/
9133 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9135 GraphEdge *edge, *backedge, *nextedge;
9139 assert (node1 && node2);
9140 assert (node1 != node2);
9142 // add all edges starting at node2 to node1
9145 nextedge = edge->next;
9147 backedge = getGEdge (node, node2);
9149 backweight = backedge->weight;
9152 // insert edges (node1,node) and (node,node1)
9153 addGEdge2 (node1, node, edge->weight, backweight);
9154 // remove edges (node, node2) and (node2, node)
9155 remGEdge (node2, node);
9156 remGEdge (node, node2);
9160 // now node2 should not be referenced by any other GraphNode...
9161 //remGNode (adj, node2->data, node2->hash);
9164 /*----------------------------------------------------------------*/
9165 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9166 /*----------------------------------------------------------------*/
9167 void showGraph (Graph *g)
9171 pseudoBankNr bankNr;
9178 bankNr = getEffectiveBank (node->hash);
9179 assert (bankNr >= 0);
9180 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9182 bankNr = pbank->bank;
9188 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9191 if (edge->weight > 0)
9192 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9199 /*---------------------------------------------------------------*/
9200 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9201 /*---------------------------------------------------------------*/
9202 void pic16_OptimizeBanksel ()
9204 GraphNode *node, *node1, *node1next;
9207 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9208 GraphEdge *edge, *backedge;
9210 int maxWeight, weight, mergeMore, absMaxWeight;
9211 pseudoBankNr curr0, curr1;
9214 pseudoBankNr bankNr;
9215 char *base_symbol0, *base_symbol1;
9220 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9222 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9224 if (!the_pFile || !the_pFile->pbHead) return;
9226 adj = newGraph (NULL);
9227 sym2bank = newHashTable ( 255 );
9228 bank2sym = newHashTable ( 255 );
9229 coerce = newHashTable ( 255 );
9231 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9232 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9233 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9237 // assign symbols with absolute addresses to their respective bank nrs
9238 set = pic16_fix_udata;
9239 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9240 bankNr = reg->address >> 8;
9241 node = getOrAddGNode (adj, NULL, bankNr);
9242 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9243 assignToSameBank (node->hash, bankNr, 1);
9245 assert (bankNr >= 0);
9246 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9248 pbank = Safe_calloc (1, sizeof (pseudoBank));
9249 pbank->bank = reg->address >> 8; //FIXED_BANK;
9252 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9254 assert (pbank->bank == (reg->address >> 8));
9255 pbank->bank = reg->address >> 8; //FIXED_BANK;
9257 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9262 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9263 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9266 if (node->hash < 0) { node = node->next; continue; }
9267 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9270 if (node1->hash < 0) { node1 = node1->next; continue; }
9271 node1next = node1->next;
9272 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9273 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9274 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9275 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9276 if (assignToSameBank (node->hash, node1->hash, 0)) {
9277 fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9278 assert (0 && "Could not assign a symbol to a bank!");
9280 mergeGraphNodes (node, node1);
9282 if (node->hash < node1->hash)
9283 mergeGraphNodes (node, node1);
9285 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9295 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9296 // assign tightly coupled operands to the same (pseudo) bank
9297 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9305 curr0 = getEffectiveBank (node->hash);
9306 if (curr0 < 0) { node = node->next; continue; }
9309 assert (edge->src == node);
9310 backedge = getGEdge (edge->node, edge->src);
9311 weight = edge->weight + (backedge ? backedge->weight : 0);
9312 curr1 = getEffectiveBank (edge->node->hash);
9313 if (curr1 < 0) { edge = edge->next; continue; }
9315 // merging is only useful if the items are not assigned to the same bank already...
9316 if (curr0 != curr1 && weight > maxWeight) {
9317 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9326 if (maxWeight > 0) {
9328 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9329 max->src->hash, getSymFromBank (max->src->hash),
9330 max->node->hash, getSymFromBank (max->node->hash));
9333 node = getGNode (adj, max->src->data, max->src->hash);
9334 node1 = getGNode (adj, max->node->data, max->node->hash);
9336 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9337 if (max->src->hash < max->node->hash)
9338 mergeGraphNodes (node, node1);
9340 mergeGraphNodes (node1, node);
9342 remGEdge (node, node1);
9343 remGEdge (node1, node);
9354 // remove redundant BANKSELs
9355 //fprintf (stderr, "removing redundant BANKSELs\n");
9356 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9357 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9362 fprintf (stderr, "display graph\n");
9367 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9370 /*** END of stuff belonging to the BANKSEL optimization ***/
9374 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9376 typedef unsigned int symbol_t;
9377 typedef unsigned int valnum_t;
9378 //typedef unsigned int hash_t;
9381 #define INT_TO_PTR(x) (((char *) 0) + (x))
9385 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9388 static int pic16_regIsLocal (regs *r);
9389 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9392 static unsigned int pic16_df_removed_pcodes = 0;
9393 static unsigned int pic16_df_saved_bytes = 0;
9394 static unsigned int df_findall_sameflow = 0;
9395 static unsigned int df_findall_otherflow = 0;
9396 static unsigned int df_findall_in_vals = 0;
9398 static void pic16_df_stats () {
9400 if (pic16_debug_verbose || pic16_pcode_verbose) {
9401 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9402 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9403 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9407 /* Remove a pCode iff possible:
9408 * - previous pCode is no SKIP
9410 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9411 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9412 pCode *pcprev, *pcnext;
9413 char buf[256], *total=NULL;
9416 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9418 pcprev = pic16_findPrevInstruction (pc->prev);
9419 pcnext = pic16_findNextInstruction (pc->next);
9421 /* move labels to next instruction (if possible) */
9422 if (PCI(pc)->label && !pcnext) return 0;
9424 /* if this is a SKIP with side-effects -- do not remove */
9425 /* XXX: might try to replace this one with the side-effect only version */
9427 && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9430 switch (PCI(pc)->op)
9434 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9435 pic16_pCodeReplace( pc, newpc );
9439 newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9440 pic16_pCodeReplace( pc, newpc );
9445 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9446 pic16_pCodeReplace( pc, newpc );
9450 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9451 pic16_pCodeReplace( pc, newpc );
9460 /* if previous instruction is a skip -- do not remove */
9461 if (pcprev && isPCI_SKIP(pcprev)) {
9462 if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9463 /* preceeding SKIP could not be removed -- keep this instruction! */
9468 if (PCI(pc)->label) {
9469 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9470 //pc->print (stderr, pc);
9471 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9472 PCI(pc)->label = NULL;
9475 /* update statistics */
9476 pic16_df_removed_pcodes++;
9477 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9479 /* remove the pCode */
9480 pic16_pCode2str (buf, 256, pc);
9481 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9482 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9483 len = strlen (buf) + strlen (comment) + 10;
9484 total = (char *) Safe_malloc (len);
9485 SNPRINTF (total, len, "%s: %s", comment, buf);
9486 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9490 /* actually unlink it from the pBlock -- also remove from to/from lists */
9491 pic16_pCodeUnlink (pc);
9493 /* remove the pCode -- release registers */
9496 /* report success */
9501 /* ======================================================================== */
9502 /* === SYMBOL HANDLING ==================================================== */
9503 /* ======================================================================== */
9505 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9506 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9507 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9509 /** Calculate a hash for a given string.
9510 * If len == 0 the string is assumed to be NUL terminated. */
9511 static hash_t symbolHash (const char *str, unsigned int len) {
9515 hash = (hash << 2) ^ *str;
9520 hash = (hash << 2) ^ *str;
9527 /** Return 1 iff strings v1 and v2 are identical. */
9528 static int symcmp (const void *v1, const void *v2) {
9529 return !strcmp ((const char *) v1, (const char *) v2);
9532 /** Return 1 iff pointers v1 and v2 are identical. */
9533 static int ptrcmp (const void *v1, const void *v2) {
9537 enum { SPO_WREG=0x1000,
9577 /* Return the unique symbol_t for the given string. */
9578 static symbol_t symFromStr (const char *str) {
9583 if (!map_symToStr) {
9585 struct { char *name; symbol_t sym; } predefsyms[] = {
9587 {"STATUS", SPO_STATUS},
9588 {"PRODL", SPO_PRODL},
9589 {"PRODH", SPO_PRODH},
9590 {"INDF0", SPO_INDF0},
9591 {"POSTDEC0", SPO_POSTDEC0},
9592 {"POSTINC0", SPO_POSTINC0},
9593 {"PREINC0", SPO_PREINC0},
9594 {"PLUSW0", SPO_PLUSW0},
9595 {"INDF1", SPO_INDF1},
9596 {"POSTDEC1", SPO_POSTDEC1},
9597 {"POSTINC1", SPO_POSTINC1},
9598 {"PREINC1", SPO_PREINC1},
9599 {"PLUSW1", SPO_PLUSW1},
9600 {"INDF2", SPO_INDF2},
9601 {"POSTDEC2", SPO_POSTDEC2},
9602 {"POSTINC2", SPO_POSTINC2},
9603 {"PREINC2", SPO_PREINC2},
9604 {"PLUSW2", SPO_PLUSW2},
9605 {"STKPTR", SPO_STKPTR},
9610 {"FSR0L", SPO_FSR0L},
9611 {"FSR0H", SPO_FSR0H},
9612 {"FSR1L", SPO_FSR1L},
9613 {"FSR1H", SPO_FSR1H},
9614 {"FSR2L", SPO_FSR2L},
9615 {"FSR2H", SPO_FSR2H},
9617 {"PCLATH", SPO_PCLATH},
9618 {"PCLATU", SPO_PCLATU},
9619 {"TABLAT", SPO_TABLAT},
9620 {"TBLPTRL", SPO_TBLPTRL},
9621 {"TBLPTRH", SPO_TBLPTRH},
9622 {"TBLPTRU", SPO_TBLPTRU},
9626 map_strToSym = newHashTable (128);
9627 map_symToStr = newHashTable (128);
9629 for (i=0; predefsyms[i].name; i++) {
9632 /* enter new symbol */
9633 sym = predefsyms[i].sym;
9634 name = predefsyms[i].name;
9635 res = Safe_strdup (name);
9636 hash = symbolHash (name, 0);
9638 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9639 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9643 hash = symbolHash (str, 0) % map_strToSym->size;
9645 /* find symbol in table */
9646 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9648 //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9652 /* enter new symbol */
9654 res = Safe_strdup (str);
9656 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9657 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9659 //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9665 static const char *strFromSym (symbol_t sym) {
9666 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9670 /* ======================================================================== */
9671 /* === DEFINITION MAP HANDLING ============================================ */
9672 /* ======================================================================== */
9674 /* A defmap provides information about which symbol is defined by which pCode.
9675 * The most recent definitions are prepended to the list, so that the most
9676 * recent definition can be found by forward scanning the list.
9677 * pc2: MOVFF r0x00, r0x01
9679 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9681 * We attach one defmap to each flow object, and each pCode will occur at
9682 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9683 * used to find definitions for a pCode in its own defmap that precede pCode.
9686 typedef struct defmap_s {
9687 symbol_t sym; /** symbol this item refers to */
9690 unsigned int in_mask:8; /** mask leaving in accessed bits */
9691 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9692 int isRead:1; /** sym/mask is read */
9693 int isWrite:1; /** sym/mask is written */
9697 pCode *pc; /** pCode this symbol is refrenced at */
9698 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9699 valnum_t val; /** new unique number for this value (if isWrite) */
9700 struct defmap_s *prev, *next; /** link to previous an next definition */
9703 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9704 static int defmap_free_count = 0; /** number of released defmap items */
9706 /* Returns a defmap_t with the specified data; this will be the new list head.
9707 * next - pointer to the current list head */
9708 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9713 defmap_free = map->next;
9714 --defmap_free_count;
9716 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9719 map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9720 map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9721 map->acc.access.isRead = (isRead != 0);
9722 map->acc.access.isWrite = (isWrite != 0);
9725 map->val = (isWrite ? val : 0);
9728 if (next) next->prev = map;
9733 /* Returns a copy of the single defmap item. */
9734 static defmap_t *copyDefmap (defmap_t *map) {
9735 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9736 memcpy (res, map, sizeof (defmap_t));
9742 /* Insert a defmap item after the specified one. */
9743 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9744 if (!ref || !newItem) return 1;
9746 newItem->next = ref->next;
9747 newItem->prev = ref;
9748 ref->next = newItem;
9749 if (newItem->next) newItem->next->prev = newItem;
9754 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9755 * item is copied before insertion into chain and therefore left untouched.
9756 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9757 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9760 while (dummy && (dummy->sym != item->sym
9761 || dummy->pc != item->pc
9762 || dummy->acc.accessmethod != item->acc.accessmethod
9763 || dummy->val != item->val
9764 || dummy->in_val != item->in_val)) {
9765 dummy = dummy->next;
9768 /* item already present? */
9769 if (dummy) return 0;
9771 /* otherwise: insert copy of item */
9772 dummy = copyDefmap (item);
9773 dummy->next = *head;
9774 if (*head) (*head)->prev = dummy;
9780 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9781 static void deleteDefmap (defmap_t *map) {
9784 /* unlink from chain -- fails for the first item (head is not updated!) */
9785 if (map->next) map->next->prev = map->prev;
9786 if (map->prev) map->prev->next = map->next;
9789 memset (map, 0, sizeof (defmap_t));
9791 /* save for future use */
9792 map->next = defmap_free;
9794 ++defmap_free_count;
9797 /* Release all defmaps referenced from map. */
9798 static void deleteDefmapChain (defmap_t **_map) {
9799 defmap_t *map, *next;
9805 /* find list head */
9806 while (map && map->prev) map = map->prev;
9808 /* delete all items */
9818 /* Free all defmap items. */
9819 static void freeDefmap (defmap_t **_map) {
9827 /* find list head */
9828 while (map->prev) map = map->prev;
9830 /* release all items */
9840 /* Returns the most recent definition for the given symbol preceeding pc.
9841 * If no definition is found, NULL is returned.
9842 * If pc == NULL the whole list is scanned. */
9843 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9844 defmap_t *curr = map;
9847 /* skip all definitions up to pc */
9848 while (curr && (curr->pc != pc)) curr = curr->next;
9850 /* pc not in the list -- scan the whole list for definitions */
9852 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9855 /* skip all definitions performed by pc */
9856 while (curr && (curr->pc == pc)) curr = curr->next;
9860 /* find definition for sym */
9861 while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9869 /* Returns the first use (read) of the given symbol AFTER pc.
9870 * If no such use is found, NULL is returned.
9871 * If pc == NULL the whole list is scanned. */
9872 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9873 defmap_t *curr = map, *prev = NULL;
9876 /* skip all definitions up to pc */
9877 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9879 /* pc not in the list -- scan the whole list for definitions */
9881 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9885 /* find end of list */
9886 while (curr && curr->next) curr = curr->next;
9889 /* find use of sym (scan list backwards) */
9890 while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9896 /* Return the defmap entry for sym AT pc.
9897 * If none is found, NULL is returned.
9898 * If more than one entry is found an assertion is triggered. */
9899 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9900 defmap_t *res = NULL;
9902 /* find entries for pc */
9903 while (map && map->pc != pc) map = map->next;
9905 /* find first entry for sym @ pc */
9906 while (map && map->pc == pc && map->sym != sym) map = map->next;
9908 /* no entry found */
9909 if (!map) return NULL;
9911 /* check for more entries */
9914 while (map && map->pc == pc) {
9915 /* more than one entry for sym @ pc found? */
9916 assert (map->sym != sym);
9920 /* return single entry for sym @ pc */
9924 /* Modifies the definition of sym at pCode to newval.
9925 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9927 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9930 /* find definitions of pc */
9931 while (m && m->pc != pc) m = m->next;
9933 /* find definition of sym at pc */
9934 while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9936 /* no definition found */
9942 /* update following uses of sym */
9943 while (m && m->pc == pc) m = m->prev;
9945 if (m->sym == sym) {
9947 if (m->acc.access.isWrite) m = NULL;
9955 /* ======================================================================== */
9956 /* === STACK ROUTINES ===================================================== */
9957 /* ======================================================================== */
9959 typedef struct stack_s {
9961 struct stack_s *next;
9964 typedef stackitem_t *dynstack_t;
9965 static stackitem_t *free_stackitems = NULL;
9967 /* Create a stack with one item. */
9968 static dynstack_t *newStack () {
9969 dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9974 /* Remove a stack -- its items are only marked free. */
9975 static void deleteStack (dynstack_t *s) {
9981 i->next = free_stackitems;
9982 free_stackitems = i;
9987 /* Release all stackitems. */
9988 static void releaseStack () {
9991 while (free_stackitems) {
9992 i = free_stackitems->next;
9993 Safe_free(free_stackitems);
9994 free_stackitems = i;
9998 static void stackPush (dynstack_t *stack, void *data) {
10001 if (free_stackitems) {
10002 i = free_stackitems;
10003 free_stackitems = free_stackitems->next;
10005 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
10012 static void *stackPop (dynstack_t *stack) {
10016 if (stack && *stack) {
10017 data = (*stack)->data;
10019 *stack = (*stack)->next;
10020 i->next = free_stackitems;
10021 free_stackitems = i;
10029 static int stackContains (dynstack_t *s, void *data) {
10034 if (i->data == data) return 1;
10043 static int stackIsEmpty (dynstack_t *s) {
10044 return (*s == NULL);
10053 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10054 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10056 s->lastdef = lastdef;
10060 static void deleteState (state_t *s) {
10064 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10067 /* scan working list for state */
10071 /* is i == state? -- state not new */
10072 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10080 /* is i == state? -- state not new */
10081 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10086 /* not found -- state is new */
10090 static inline valnum_t newValnum ();
10092 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10095 if (!pb) return "<unknown function>";
10097 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10098 if (pc && isPCF(pc)) return PCF(pc)->fname;
10099 else return "<unknown function>";
10102 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10108 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10110 /* find initial value (assigning pc == NULL) */
10111 map = PCFL(pcfl)->in_vals;
10112 while (map && map->sym != sym) map = map->next;
10114 /* initial value already present? */
10116 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10120 /* create a new initial value */
10121 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10122 PCFL(pcfl)->in_vals = map;
10123 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10127 /* insert map as last item in pcfl's defmap */
10128 if (!prev) prev = PCFL(pcfl)->defmap;
10130 PCFL(pcfl)->defmap = map;
10132 while (prev->next) prev = prev->next;
10141 /* Find all reaching definitions for sym at pc.
10142 * A new (!) list of definitions is returned.
10143 * Returns the number of reaching definitions found.
10144 * The defining defmap entries are returned in *chain.
10146 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10151 pCodeFlowLink *succ;
10153 dynstack_t *todo; /** stack of state_t */
10154 dynstack_t *done; /** stack of state_t */
10156 int firstState, n_defs;
10158 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10161 /* initialize return list */
10164 /* wildcard symbol? */
10165 if (!sym) return 0;
10167 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10169 map = PCI(pc)->pcflow->defmap;
10171 res = defmapFindDef (map, sym, pc);
10172 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10174 #define USE_PRECALCED_INVALS 1
10175 #if USE_PRECALCED_INVALS
10176 if (!res && PCI(pc)->pcflow->in_vals) {
10177 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10179 //fprintf (stderr, "found def in init values\n");
10180 df_findall_in_vals++;
10186 // found a single definition (in pc's flow)
10187 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10188 defmapAddCopyIfNew (chain, res);
10189 df_findall_sameflow++;
10193 #if USE_PRECALCED_INVALS
10195 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10201 #define FORWARD_FLOW_ANALYSIS 1
10202 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10203 /* no definition found in pc's flow preceeding pc */
10204 todo = newStack ();
10205 done = newStack ();
10206 n_defs = 0; firstState = 1;
10207 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10209 while (!stackIsEmpty (todo)) {
10210 state = (state_t *) stackPop (todo);
10211 stackPush (done, state);
10212 curr = state->flow;
10213 res = state->lastdef;
10214 //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);
10216 /* there are no definitions BEFORE pc in pc's flow (see above) */
10217 if (curr == PCI(pc)->pcflow) {
10219 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10220 res = pic16_pBlockAddInval (pc->pb, sym);
10221 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10224 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10225 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10229 /* save last definition of sym in this flow as initial def in successors */
10230 res = defmapFindDef (curr->defmap, sym, NULL);
10231 if (!res) res = state->lastdef;
10233 /* add successors to working list */
10234 state = newState (NULL, NULL);
10235 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10237 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10238 state->flow = succ->pcflow;
10239 state->lastdef = res;
10240 if (stateIsNew (state, todo, done)) {
10241 stackPush (todo, state);
10242 state = newState (NULL, NULL);
10244 succ = (pCodeFlowLink *) setNextItem (curr->to);
10246 deleteState (state);
10249 #else // !FORWARD_FLOW_ANALYSIS
10251 /* no definition found in pc's flow preceeding pc */
10252 todo = newStack ();
10253 done = newStack ();
10254 n_defs = 0; firstState = 1;
10255 stackPush (todo, newState (PCI(pc)->pcflow, res));
10257 while (!stackIsEmpty (todo)) {
10258 state = (state_t *) stackPop (todo);
10259 curr = state->flow;
10263 /* only check predecessor flows */
10265 /* get (last) definition of sym in this flow */
10266 res = defmapFindDef (curr->defmap, sym, NULL);
10270 /* definition found */
10271 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10272 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10274 /* no definition found -- check predecessor flows */
10275 state = newState (NULL, NULL);
10276 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10278 /* if no flow predecessor available -- sym might be uninitialized */
10280 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10281 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10282 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10283 deleteDefmap (res); res = NULL;
10287 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10288 state->flow = succ->pcflow;
10289 state->lastdef = res;
10290 if (stateIsNew (state, todo, done)) {
10291 stackPush (todo, state);
10292 state = newState (NULL, NULL);
10294 succ = (pCodeFlowLink *) setNextItem (curr->from);
10296 deleteState (state);
10302 /* clean up done stack */
10303 while (!stackIsEmpty(done)) {
10304 deleteState ((state_t *) stackPop (done));
10306 deleteStack (done);
10308 /* return number of items in result set */
10310 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10311 } else if (n_defs == 1) {
10313 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10314 } else if (n_defs > 0) {
10315 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10319 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10324 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10325 df_findall_otherflow++;
10329 /* ======================================================================== */
10330 /* === VALUE NUMBER HANDLING ============================================== */
10331 /* ======================================================================== */
10333 static valnum_t nextValnum = 0x1000;
10334 static hTab *map_symToValnum = NULL;
10336 /** Return a new value number. */
10337 static inline valnum_t newValnum () {
10338 return (nextValnum += 4);
10341 static valnum_t valnumFromStr (const char *str) {
10346 sym = symFromStr (str);
10348 if (!map_symToValnum) {
10349 map_symToValnum = newHashTable (128);
10352 /* literal already known? */
10353 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10355 /* return existing valnum */
10356 if (res) return (valnum_t) PTR_TO_INT(res);
10358 /* create new valnum */
10360 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10361 //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10365 /* Create a valnum for a literal. */
10366 static valnum_t valnumFromLit (unsigned int lit) {
10367 return ((valnum_t) 0x100 + (lit & 0x0FF));
10370 /* Return the (positive) literal value represented by val
10371 * or -1 iff val is no known literal's valnum. */
10372 static int litFromValnum (valnum_t val) {
10373 if (val >= 0x100 && val < 0x200) {
10374 /* valnum is a (known) literal */
10375 return val & 0x00FF;
10377 /* valnum is not a known literal */
10383 /* Sanity check - all flows in a block must be reachable from initial flow. */
10384 static int verifyAllFlowsReachable (pBlock *pb) {
10390 pCodeFlowLink *succ;
10393 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10396 flowInBlock = NULL;
10398 /* mark initial flow as reached (and "not needs to be reached") */
10399 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10401 addSetHead (&reached, pc);
10402 addSetHead (&checked, pc);
10404 /* mark all further flows in block as "need to be reached" */
10407 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10408 pc = pic16_findNextInstruction (pc->next);
10411 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10412 /* mark as reached and "not need to be reached" */
10413 deleteSetItem (&reached, pcfl);
10414 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10416 /* flow is no longer considered unreachable */
10417 deleteSetItem (&flowInBlock, pcfl);
10419 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10420 if (!isinSet (checked, succ->pcflow)) {
10421 /* flow has never been reached before */
10422 addSetHead (&reached, succ->pcflow);
10423 addSetHead (&checked, succ->pcflow);
10428 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10430 /* by now every flow should have been reached
10431 * --> flowInBlock should be empty */
10432 res = (flowInBlock == NULL);
10436 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10437 while (flowInBlock) {
10438 pcfl = indexSet (flowInBlock, 0);
10439 fprintf (stderr, "not reached: flow %p\n", pcfl);
10440 deleteSetItem (&flowInBlock, pcfl);
10446 deleteSet (&reached);
10447 deleteSet (&flowInBlock);
10448 deleteSet (&checked);
10450 /* if we reached every flow, succ is NULL by now... */
10451 //assert (res); // will fire on unreachable code...
10456 /* Checks a flow for accesses to sym AFTER pc.
10458 * Returns -1 if the symbol is read in this flow (before redefinition),
10459 * returns 0 if the symbol is redefined in this flow or
10460 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10462 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10463 defmap_t *map, *mappc;
10465 /* find pc or start of definitions */
10466 map = pcfl->defmap;
10467 while (map && (map->pc != pc) && map->next) map = map->next;
10468 /* if we found pc -- ignore it */
10469 while (map && map->pc == pc) map = map->prev;
10471 /* scan list backwards (first definition first) */
10472 while (map && mask) {
10473 // if (map->sym == sym) {
10474 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10476 /* scan list for reads at this pc first */
10477 while (map && map->pc == mappc->pc) {
10478 /* is the symbol (partially) read? */
10479 if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10480 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10487 while (map && map->pc == mappc->pc) {
10488 /* honor (partial) redefinitions of sym */
10489 if ((map->sym == sym) && (map->acc.access.isWrite)) {
10490 mask &= ~map->acc.access.mask;
10491 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10496 /* map already points to the first defmap for the next pCode */
10497 //map = mappc->prev;
10500 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10501 * is still alive; return the appropriate mask of alive bits */
10505 /* Check whether a symbol is alive (AFTER pc). */
10506 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10509 dynstack_t *todo, *done;
10512 pCodeFlowLink *succ;
10516 assert (isPCI(pc));
10517 pcfl = PCI(pc)->pcflow;
10518 map = pcfl->defmap;
10520 todo = newStack ();
10521 done = newStack ();
10523 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10524 stackPush (todo, state);
10527 while (!stackIsEmpty (todo)) {
10528 state = (state_t *) stackPop (todo);
10529 pcfl = state->flow;
10530 mask = PTR_TO_INT(state->lastdef);
10531 if (visit) stackPush (done, state); else deleteState(state);
10532 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10533 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10534 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10537 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10538 if (mask == 0) continue;
10540 /* symbol is (partially) read before redefinition in flow */
10541 if (mask == -1) break;
10543 /* symbol is neither read nor completely redefined -- check successor flows */
10544 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10545 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10546 if (stateIsNew (state, todo, done)) {
10547 stackPush (todo, state);
10549 deleteState (state);
10554 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10555 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10557 /* symbol is read in at least one flow -- is alive */
10558 if (mask == -1) return 1;
10560 /* symbol is read in no flow */
10564 /* Returns whether access to the given symbol has side effects. */
10565 static int pic16_symIsSpecial (symbol_t sym) {
10566 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10586 /* no special effects known */
10593 /* Check whether a register should be considered local (to the current function) or not. */
10594 static int pic16_regIsLocal (regs *r) {
10597 if (r->type == REG_TMP) return 1;
10599 sym = symFromStr (r->name);
10602 case SPO_FSR0L: // used in ptrget/ptrput
10603 case SPO_FSR0H: // ... as well
10604 case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10605 case SPO_FSR1H: // ... as well
10606 case SPO_FSR2L: // used as frame pointer
10607 case SPO_FSR2H: // ... as well
10608 case SPO_PRODL: // used to return values from functions
10609 case SPO_PRODH: // ... as well
10610 /* these registers (and some more...) are considered local */
10614 /* for unknown regs: check is marked local, leave if not */
10618 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10624 /* if in doubt, assume non-local... */
10628 /* Check all symbols touched by pc whether their newly assigned values are read.
10629 * Returns 0 if no symbol is used later on, 1 otherwise. */
10630 static int pic16_pCodeIsAlive (pCode *pc) {
10631 pCodeInstruction *pci;
10632 defmap_t *map, *lastpc;
10635 /* we can only handle PCIs */
10636 if (!isPCI(pc)) return 1;
10638 //pc->print (stderr, pc);
10641 assert (pci && pci->pcflow && pci->pcflow->defmap);
10643 /* NEVER remove instructions with implicit side effects */
10646 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10647 case POC_TBLRD_POSTDEC:
10648 case POC_TBLRD_PREINC:
10649 case POC_TBLWT: /* modify program memory */
10650 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10651 case POC_TBLWT_POSTDEC:
10652 case POC_TBLWT_PREINC:
10653 case POC_CLRWDT: /* clear watchdog timer */
10654 case POC_PUSH: /* should be safe to remove though... */
10655 case POC_POP: /* should be safe to remove though... */
10660 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10664 /* no special instruction */
10668 /* prevent us from removing assignments to non-local variables */
10670 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10671 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10673 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10674 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10675 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10676 //pc->print (stderr, pc);
10679 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10680 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10685 /* OVERKILL: prevent us from removing reads from non-local variables
10686 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10687 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10689 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10690 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10692 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10693 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10694 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10695 //pc->print (stderr, pc);
10698 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10699 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10704 /* now check that the defined symbols are not used */
10705 map = pci->pcflow->defmap;
10707 /* find items for pc */
10708 while (map && map->pc != pc) map = map->next;
10710 /* no entries found? something is fishy with DF analysis... -- play safe */
10712 if (pic16_pcode_verbose) {
10713 fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10718 /* remember first item assigned to pc for later use */
10721 /* check all symbols being modified by pc */
10722 while (map && map->pc == pc) {
10723 if (map->sym == 0) { map = map->next; continue; }
10725 /* keep pc if it references special symbols (like POSTDEC0) */
10729 pic16_pCode2str (buf, 256, pc);
10730 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10733 if (pic16_symIsSpecial (map->sym)) {
10734 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10737 if (map->acc.access.isWrite) {
10738 if (pic16_isAlive (map->sym, pc)) {
10739 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10746 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10750 pic16_pCode2str (buf, 256, pc);
10751 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10757 /* Adds implied operands to the list.
10758 * sym - operand being accessed in the pCode
10759 * list - list to append the operand
10760 * isRead - set to 1 iff sym is read in pCode
10761 * listRead - set to 1 iff all operands being read are to be listed
10763 * Returns 0 for "normal" operands, 1 for special operands.
10765 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10766 /* check whether accessing REG accesses other REGs as well */
10770 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10771 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10772 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10776 /* reads FSR0x and WREG */
10777 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10778 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10779 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10780 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10786 /* reads/modifies FSR0x */
10787 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10788 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10789 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10794 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10795 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10796 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10800 /* reads FSR1x and WREG */
10801 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10802 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10803 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10804 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10810 /* reads/modifies FSR1x */
10811 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10812 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10813 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10818 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10819 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10820 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10824 /* reads FSR2x and WREG */
10825 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10826 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10827 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10828 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10834 /* reads/modifies FSR2x */
10835 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10836 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10837 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10841 /* modifies PCLATH and PCLATU */
10842 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10844 /* reading PCL updates PCLATx */
10845 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10846 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10849 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10850 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10851 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10856 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10857 /* nothing special */
10862 /* has been a special operand */
10866 static symbol_t pic16_fsrsym_idx[][2] = {
10867 {SPO_FSR0L, SPO_FSR0H},
10868 {SPO_FSR1L, SPO_FSR1H},
10869 {SPO_FSR2L, SPO_FSR2H}
10872 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10873 static void mergeDefmapSymbols (defmap_t *list) {
10874 defmap_t *ref, *curr, *temp;
10876 /* now make sure that each symbol occurs at most once per pc */
10878 while (ref && (ref->pc == list->pc)) {
10880 while (curr && (curr->pc == list->pc)) {
10881 if (curr->sym == ref->sym) {
10882 //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10883 /* found a symbol occuring twice... merge the two */
10884 if (curr->acc.access.isRead) {
10885 //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10886 ref->acc.access.isRead = 1;
10887 ref->acc.access.in_mask |= curr->acc.access.in_mask;
10889 if (curr->acc.access.isWrite) {
10890 //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10891 ref->acc.access.isWrite = 1;
10892 ref->acc.access.mask |= curr->acc.access.mask;
10896 deleteDefmap (temp);
10897 continue; // do not skip curr!
10905 /** Prepend list with the reads and definitions performed by pc. */
10906 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10907 pCodeInstruction *pci;
10908 int cond, inCond, outCond;
10909 int mask = 0xff, smask;
10910 int isSpecial, isSpecial2;
10911 symbol_t sym, sym2;
10915 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10916 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10917 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10918 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10921 assert (isPCI(pc));
10924 /* handle bit instructions */
10925 if (pci->isBitInst) {
10926 assert (pci->pcop->type == PO_GPR_BIT);
10927 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10930 /* handle (additional) implicit arguments */
10936 lit = PCOL(pci->pcop)->lit;
10937 assert (lit >= 0 && lit < 3);
10938 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10939 val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10940 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10941 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10942 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...
10946 case POC_MOVLB: // BSR
10947 case POC_BANKSEL: // BSR
10948 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10951 case POC_MULWF: // PRODx
10952 case POC_MULLW: // PRODx
10953 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10954 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10957 case POC_POP: // TOS, STKPTR
10958 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10959 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10960 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10961 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10964 case POC_PUSH: // STKPTR
10965 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10966 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10967 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10968 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10971 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10972 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10973 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10974 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10975 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10976 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10978 /* needs correctly set-up stack pointer */
10979 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10980 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10983 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10984 /* pseudo read on (possible) return values */
10985 // WREG is handled below via outCond
10986 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10987 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10988 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10990 /* caller's stack pointers must be restored */
10991 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10992 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10993 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10994 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10997 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10998 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10999 /* pseudo read on (possible) return values */
11000 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
11001 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
11002 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
11003 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
11005 /* caller's stack pointers must be restored */
11006 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11007 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11008 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
11009 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
11013 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11014 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11015 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11016 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11019 case POC_TBLRD_POSTINC:
11020 case POC_TBLRD_POSTDEC:
11021 case POC_TBLRD_PREINC:
11022 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11023 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11024 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11025 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11029 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11030 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11031 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11032 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11035 case POC_TBLWT_POSTINC:
11036 case POC_TBLWT_POSTDEC:
11037 case POC_TBLWT_PREINC:
11038 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11039 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11040 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11041 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11045 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11049 /* handle explicit arguments */
11050 inCond = pci->inCond;
11051 outCond = pci->outCond;
11052 cond = inCond | outCond;
11053 if (cond & PCC_W) {
11054 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11057 /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11058 if (inCond & PCC_STATUS) {
11060 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11061 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11062 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11063 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11064 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11066 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11067 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11070 if (outCond & PCC_STATUS) {
11072 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11073 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11074 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11075 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11076 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11078 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11079 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11082 isSpecial = isSpecial2 = 0;
11084 if (cond & PCC_REGISTER) {
11085 name = pic16_get_op (pci->pcop, NULL, 0);
11086 sym = symFromStr (name);
11087 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11088 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11091 if (cond & PCC_REGISTER2) {
11092 name = pic16_get_op2 (pci->pcop, NULL, 0);
11093 sym2 = symFromStr (name);
11094 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11095 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11099 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11100 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11102 mergeDefmapSymbols (list);
11108 static void printDefmap (defmap_t *map) {
11112 fprintf (stderr, "defmap @ %p:\n", curr);
11114 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11115 curr->acc.access.isRead ? "R" : " ",
11116 curr->acc.access.isWrite ? "W": " ",
11117 curr->in_val, curr->val,
11118 curr->acc.access.in_mask, curr->acc.access.mask,
11119 strFromSym(curr->sym), curr->sym,
11123 fprintf (stderr, "<EOL>\n");
11127 /* Add "additional" definitions to uniq.
11128 * 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.
11129 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11131 * If symbols defined in additional are not present in uniq, a definition is created.
11132 * Otherwise the present definition is altered to reflect the newer assignments.
11134 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11135 * before `------- noted in additional --------' after
11137 * I assume that each symbol occurs AT MOST ONCE in uniq.
11140 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11145 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11146 /* find tail of additional list (holds the first assignment) */
11148 while (curr && curr->next) curr = curr->next;
11152 /* find next assignment in additionals */
11153 while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11157 /* find item in uniq */
11159 //printDefmap (*uniq);
11160 while (old && (old->sym != curr->sym)) old = old->next;
11163 /* definition found -- replace */
11164 if (old->val != curr->val) {
11165 old->val = curr->val;
11169 /* new definition */
11170 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11177 /* return 0 iff uniq remained unchanged */
11181 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11182 * lists of its predecessor flows.
11183 * Initially *combined should be NULL, alt_in will be copied to combined.
11184 * If *combined != NULL, combined will be altered:
11185 * - for symbols defined in *combined but not in alt_in,
11186 * *combined is altered to 0 (value unknown, either *combined or INIT).
11187 * - for symbols defined in alt_in but not in *combined,
11188 * a 0 definition is created (value unknown, either INIT or alt).
11189 * - for symbols defined in both, *combined is:
11190 * > left unchanged if *combined->val == alt_in->val or
11191 * > modified to 0 otherwise (value unknown, either alt or *combined).
11193 * I assume that each symbol occurs AT MOST ONCE in each list!
11195 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11201 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11203 if (!(*combined)) {
11204 return defmapUpdateUniqueSym (combined, alt_in);
11207 /* merge the two */
11210 /* find symbols definition in *combined */
11212 while (old && (old->sym != curr->sym)) old = old->next;
11215 /* definition found */
11216 if (old->val && (old->val != curr->val)) {
11217 old->val = 0; /* value unknown */
11221 /* no definition found -- can be either INIT or alt_in's value */
11222 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11223 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11224 if (val != curr->val) change++;
11230 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11233 if (old->val != 0) {
11234 /* find definition in alt_in */
11236 while (curr && curr->sym != old->sym) curr = curr->next;
11238 /* symbol defined in *combined only -- can be either INIT or *combined */
11239 val = pic16_pBlockAddInval (pb, old->sym)->val;
11240 if (old->val != val) {
11253 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11254 defmap_t *curr1, *curr2;
11257 /* identical maps are equal */
11258 if (map1 == map2) return 0;
11260 if (!map1) return -1;
11261 if (!map2) return 1;
11263 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11268 while (curr1 && curr2) {
11269 curr1 = curr1->next;
11270 curr2 = curr2->next;
11273 /* one of them longer? */
11274 if (curr1) return 1;
11275 if (curr2) return -1;
11277 /* both lists are of equal length -- compare (in O(n^2)) */
11282 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11283 if (!curr2) return 1; // symbol not found in curr2
11284 if (curr2->val != curr1->val) return 1; // values differ
11286 /* compare next symbol */
11287 curr1 = curr1->next;
11290 /* no difference found */
11295 /* Prepare a list of all reaching definitions per flow.
11296 * This is done using a forward dataflow analysis.
11298 static void createReachingDefinitions (pBlock *pb) {
11299 defmap_t *out_vals, *in_vals;
11302 pCodeFlowLink *link;
11308 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11309 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11311 deleteDefmapChain (&PCFL(pc)->in_vals);
11312 deleteDefmapChain (&PCFL(pc)->out_vals);
11313 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11317 pc = pic16_findNextInstruction (pb->pcHead);
11318 todo = NULL; blacklist = NULL;
11319 addSetHead (&todo, PCI(pc)->pcflow);
11321 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11322 while (elementsInSet (todo)) {
11323 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11324 pcfl = PCFL(indexSet (todo, 0));
11325 deleteSetItem (&todo, pcfl);
11326 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11330 if (isinSet (blacklist, pcfl)) {
11331 fprintf (stderr, "ignoring blacklisted flow\n");
11335 /* create in_vals from predecessors out_vals */
11336 link = setFirstItem (pcfl->from);
11338 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11339 link = setNextItem (pcfl->from);
11342 //printDefmap (in_vals);
11343 //printDefmap (pcfl->in_vals);
11345 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11346 //fprintf (stderr, "in_vals changed\n");
11347 /* in_vals changed -- update out_vals */
11348 deleteDefmapChain (&pcfl->in_vals);
11349 pcfl->in_vals = in_vals;
11351 /* create out_val from in_val and defmap */
11353 defmapUpdateUniqueSym (&out_vals, in_vals);
11354 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11356 /* is out_vals different from pcfl->out_vals */
11357 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11358 //fprintf (stderr, "out_vals changed\n");
11359 deleteDefmapChain (&pcfl->out_vals);
11360 pcfl->out_vals = out_vals;
11362 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11363 addSet (&blacklist, pcfl);
11366 /* reschedule all successors */
11367 link = setFirstItem (pcfl->to);
11369 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11370 addSetIfnotP (&todo, link->pcflow);
11371 link = setNextItem (pcfl->to);
11374 deleteDefmapChain (&out_vals);
11377 deleteDefmapChain (&in_vals);
11383 static void showAllDefs (symbol_t sym, pCode *pc) {
11387 assert (isPCI(pc));
11388 count = defmapFindAll (sym, pc, &map);
11390 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11393 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11396 pic16_pCode2str (buf, 256, map->pc);
11397 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11401 deleteDefmapChain (&map);
11405 /* safepCodeUnlink and remove pc from defmap. */
11406 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11407 defmap_t *map, *next, **head;
11411 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11412 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11413 res = pic16_safepCodeUnlink (pc, comment);
11416 /* remove pc from defmap */
11419 if (map->pc == pc) {
11420 if (!map->prev && head) *head = map->next;
11421 deleteDefmap (map);
11430 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11432 /* This breaks the defmap chain's references to pCodes... fix it! */
11433 map = PCI(pc)->pcflow->defmap;
11435 while (map && map->pc != pc) map = map->next;
11437 while (map && map->pc == pc) {
11443 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11444 * write accesses (isRead == 0). */
11445 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11446 defmap_t *map, *map_start;
11448 if (!isPCI(pc)) return;
11449 if (sym == newsym) return;
11451 map = PCI(pc)->pcflow->defmap;
11453 while (map && map->pc != pc) map = map->next;
11455 while (map && map->pc == pc) {
11456 if (map->sym == sym) {
11457 assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11458 if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11459 /* only one kind of access handled... this is easy */
11462 /* must copy defmap entry before replacing symbol... */
11463 copy = copyDefmap (map);
11465 map->acc.access.isRead = 0;
11466 copy->acc.access.isWrite = 0;
11468 map->acc.access.isWrite = 0;
11469 copy->acc.access.isRead = 0;
11471 copy->sym = newsym;
11472 /* insert copy into defmap chain */
11473 defmapInsertAfter (map, copy);
11479 /* as this might introduce multiple defmap entries for newsym... */
11480 mergeDefmapSymbols (map_start);
11483 /* Assign "better" valnums to results. */
11484 static void assignValnums (pCode *pc) {
11485 pCodeInstruction *pci;
11487 symbol_t sym1, sym2;
11488 int cond, isSpecial1, isSpecial2, count, mask, lit;
11489 defmap_t *list, *val, *oldval, *dummy;
11490 regs *reg1 = NULL, *reg2 = NULL;
11493 /* only works for pCodeInstructions... */
11494 if (!isPCI(pc)) return;
11497 cond = pci->inCond | pci->outCond;
11498 list = pci->pcflow->defmap;
11499 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11501 if (cond & PCC_REGISTER) {
11502 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11503 reg1 = pic16_getRegFromInstruction (pc);
11504 isSpecial1 = pic16_symIsSpecial (sym1);
11506 if (cond & PCC_REGISTER2) {
11507 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11508 reg2 = pic16_getRegFromInstruction (pc);
11509 isSpecial2 = pic16_symIsSpecial (sym2);
11512 /* determine input values */
11514 while (val && val->pc != pc) val = val->next;
11515 //list = val; /* might save some time later... */
11516 while (val && val->pc == pc) {
11518 if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11519 /* get valnum for sym */
11520 count = defmapFindAll (val->sym, pc, &oldval);
11521 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11523 if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11524 val->in_val = oldval->val;
11528 } else if (count == 0) {
11529 /* no definition found */
11532 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11534 dummy = oldval->next;
11535 mask = oldval->acc.access.mask;
11536 val->in_val = oldval->val;
11537 while (dummy && (dummy->val == val->in_val)) {
11538 mask &= dummy->acc.access.mask;
11539 dummy = dummy->next;
11542 /* found other values or to restictive mask */
11543 if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11547 if (count > 0) deleteDefmapChain (&oldval);
11552 /* handle valnum assignment */
11554 case POC_CLRF: /* modifies STATUS (Z) */
11555 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11556 oldval = defmapCurr (list, sym1, pc);
11557 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11558 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11559 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11561 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11565 case POC_SETF: /* SETF does not touch STATUS */
11566 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11567 oldval = defmapCurr (list, sym1, pc);
11568 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11569 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11570 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11572 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11576 case POC_MOVLW: /* does not touch STATUS */
11577 oldval = defmapCurr (list, SPO_WREG, pc);
11578 if (pci->pcop->type == PO_LITERAL) {
11579 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11580 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11582 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11583 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11585 if (oldval && oldval->in_val == litnum) {
11586 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11587 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11589 defmapUpdate (list, SPO_WREG, pc, litnum);
11592 case POC_ANDLW: /* modifies STATUS (Z,N) */
11593 case POC_IORLW: /* modifies STATUS (Z,N) */
11594 case POC_XORLW: /* modifies STATUS (Z,N) */
11595 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11596 if (pci->pcop->type == PO_LITERAL) {
11598 lit = (unsigned char) PCOL(pci->pcop)->lit;
11599 val = defmapCurr (list, SPO_WREG, pc);
11600 if (val) vallit = litFromValnum (val->in_val);
11601 if (vallit != -1) {
11602 /* xxxLW <literal>, WREG contains a known literal */
11603 //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11604 if (pci->op == POC_ANDLW) {
11606 } else if (pci->op == POC_IORLW) {
11608 } else if (pci->op == POC_XORLW) {
11611 assert (0 && "invalid operation");
11613 if (vallit == lit) {
11614 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11615 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11617 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11624 /* check if old value matches new value */
11627 assert (pci->pcop->type == PO_LITERAL);
11629 lit = PCOL(pci->pcop)->lit;
11631 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11633 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11634 //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11636 /* cannot remove this LFSR */
11640 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11641 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11642 //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11648 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11653 case POC_MOVWF: /* does not touch flags */
11654 /* find value of WREG */
11655 val = defmapCurr (list, SPO_WREG, pc);
11656 oldval = defmapCurr (list, sym1, pc);
11657 if (val) lit = litFromValnum (val->in_val);
11659 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11661 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11662 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11663 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11665 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11667 assert (lit == 0x0ff);
11668 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11670 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11671 pic16_pCodeReplace (pc, newpc);
11672 defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11673 pic16_fixDefmap (pc, newpc);
11676 /* This breaks the defmap chain's references to pCodes... fix it! */
11677 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11678 if (!val->acc.access.isWrite) {
11679 deleteDefmap (val); // delete reference to WREG as in value
11682 val->acc.access.isRead = 0; // delete reference to WREG as in value
11684 oldval = PCI(pc)->pcflow->defmap;
11686 if (oldval->pc == pc) oldval->pc = newpc;
11687 oldval = oldval->next;
11689 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11690 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11691 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11693 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11696 case POC_MOVFW: /* modifies STATUS (Z,N) */
11697 /* find value of REG */
11698 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11699 val = defmapCurr (list, sym1, pc);
11700 oldval = defmapCurr (list, SPO_WREG, pc);
11701 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11702 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11703 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11705 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11709 case POC_MOVFF: /* does not touch STATUS */
11710 /* find value of REG */
11711 val = defmapCurr (list, sym1, pc);
11712 oldval = defmapCurr (list, sym2, pc);
11713 if (val) lit = litFromValnum (val->in_val);
11716 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11717 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11719 newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11720 } else if (lit == 0x00ff) {
11721 newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11726 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11727 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11728 pic16_pCodeReplace (pc, newpc);
11729 defmapReplaceSymRef (pc, sym1, 0, 1);
11730 pic16_fixDefmap (pc, newpc);
11732 break; // do not process instruction as MOVFF...
11734 } else if (!isSpecial1 && !isSpecial2
11735 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11736 && val && oldval && (val->in_val != 0)) {
11737 if (val->in_val == oldval->in_val) {
11738 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11739 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11741 if (!pic16_isAlive (sym1, pc)) {
11742 defmap_t *copy = NULL;
11743 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11744 * This should help eliminate
11746 * <do something not changing A or using B>
11748 * <B is not alive anymore>
11750 * <do something not changing A or using B>
11754 /* scan defmap for symbols storing sym1's value */
11755 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11756 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11757 /* unique reaching definition for sym found */
11758 if (copy->val && copy->val == val->in_val) {
11759 //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);
11760 if (copy->sym == SPO_WREG) {
11761 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11763 pCodeOp *pcop = NULL;
11764 /* the code below fails if we try to replace
11765 * MOVFF PRODL, r0x03
11766 * MOVFF r0x03, PCLATU
11768 * MOVFF PRODL, PCLATU
11769 * as copy(PRODL) contains has pc==NULL, by name fails...
11771 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11773 if (copy->pc && PCI(copy->pc)->pcop)
11774 pcop = PCI(copy->pc)->pcop;
11776 /* This code is broken--see above. */
11779 const char *symname = strFromSym(copy->sym);
11782 pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11783 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11784 //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11788 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11790 pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11792 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11793 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11794 pic16_pCodeReplace (pc, newpc);
11795 assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11796 defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11797 pic16_fixDefmap (pc, newpc);
11801 deleteDefmapChain (©);
11804 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11809 /* cannot optimize */
11814 static void pic16_destructDF (pBlock *pb) {
11819 /* remove old defmaps */
11820 pc = pic16_findNextInstruction (pb->pcHead);
11822 next = pic16_findNextInstruction (pc->next);
11824 assert (isPCI(pc) || isPCAD(pc));
11825 assert (PCI(pc)->pcflow);
11826 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11827 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11828 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11833 if (defmap_free || defmap_free_count) {
11834 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11835 freeDefmap (&defmap_free);
11836 defmap_free_count = 0;
11840 /* Checks whether a pBlock contains ASMDIRs. */
11841 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11846 pc = pic16_findNextInstruction (pb->pcHead);
11848 if (isPCAD(pc)) return 1;
11850 pc = pic16_findNextInstruction (pc->next);
11853 /* no PCADs found */
11858 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11859 static int pic16_removeUnusedRegistersDF () {
11862 regs *reg1, *reg2, *reg3;
11863 set *seenRegs = NULL;
11865 int islocal, change = 0;
11868 if (!the_pFile || !the_pFile->pbHead) return 0;
11870 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11871 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11873 /* find set of using pCodes per register */
11874 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11875 pc = pic16_findNextInstruction(pc->next)) {
11877 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11878 reg1 = reg2 = NULL;
11879 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11880 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11883 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11884 addSetIfnotP (&seenRegs, reg1);
11885 addSetIfnotP (®1->reglives.usedpCodes, pc);
11888 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11889 addSetIfnotP (&seenRegs, reg2);
11890 addSetIfnotP (®2->reglives.usedpCodes, pc);
11894 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11895 /* may not use pic16_regIsLocal() here -- in interrupt routines
11896 * WREG, PRODx, FSR0x must be saved */
11897 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11898 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11900 for (i=0; i < 2; i++) {
11901 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11902 if (!pc2) pc2 = pc;
11903 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11904 reg2 = pic16_getRegFromInstruction (pc);
11905 reg3 = pic16_getRegFromInstruction2 (pc);
11907 || (reg2->rIdx != pic16_stack_preinc->rIdx
11908 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11910 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11911 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11912 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11913 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11917 deleteSet (®1->reglives.usedpCodes);
11920 deleteSet (&seenRegs);
11927 /* Set up pCodeFlow's defmap_ts.
11928 * Needs correctly set up to/from fields. */
11929 static void pic16_createDF (pBlock *pb) {
11935 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11937 pic16_destructDF (pb);
11939 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11940 if (pic16_pBlockHasAsmdirs (pb)) {
11941 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11945 /* integrity check -- we need to reach all flows to guarantee
11946 * correct data flow analysis (reaching definitions, aliveness) */
11948 if (!verifyAllFlowsReachable (pb)) {
11949 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11954 /* establish new defmaps */
11955 pc = pic16_findNextInstruction (pb->pcHead);
11957 next = pic16_findNextInstruction (pc->next);
11959 assert (PCI(pc)->pcflow);
11960 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11965 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11966 createReachingDefinitions (pb);
11969 /* assign better valnums */
11970 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11971 pc = pic16_findNextInstruction (pb->pcHead);
11973 next = pic16_findNextInstruction (pc->next);
11975 assert (PCI(pc)->pcflow);
11976 assignValnums (pc);
11983 /* remove dead pCodes */
11984 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11987 pc = pic16_findNextInstruction (pb->pcHead);
11989 next = pic16_findNextInstruction (pc->next);
11991 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11992 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
12001 /* ======================================================================== */
12002 /* === VCG DUMPER ROUTINES ================================================ */
12003 /* ======================================================================== */
12004 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
12005 hTab *dumpedNodes = NULL;
12007 /** Dump VCG header into of. */
12008 static void pic16_vcg_init (FILE *of) {
12009 /* graph defaults */
12010 fprintf (of, "graph:{\n");
12011 fprintf (of, "title:\"graph1\"\n");
12012 fprintf (of, "label:\"graph1\"\n");
12013 fprintf (of, "color:white\n");
12014 fprintf (of, "textcolor:black\n");
12015 fprintf (of, "bordercolor:black\n");
12016 fprintf (of, "borderwidth:1\n");
12017 fprintf (of, "textmode:center\n");
12019 fprintf (of, "layoutalgorithm:dfs\n");
12020 fprintf (of, "late_edge_labels:yes\n");
12021 fprintf (of, "display_edge_labels:yes\n");
12022 fprintf (of, "dirty_edge_labels:yes\n");
12023 fprintf (of, "finetuning:yes\n");
12024 fprintf (of, "ignoresingles:no\n");
12025 fprintf (of, "straight_phase:yes\n");
12026 fprintf (of, "priority_phase:yes\n");
12027 fprintf (of, "manhattan_edges:yes\n");
12028 fprintf (of, "smanhattan_edges:no\n");
12029 fprintf (of, "nearedges:no\n");
12030 fprintf (of, "node_alignment:center\n"); // bottom|top|center
12031 fprintf (of, "port_sharing:no\n");
12032 fprintf (of, "arrowmode:free\n"); // fixed|free
12033 fprintf (of, "crossingphase2:yes\n");
12034 fprintf (of, "crossingoptimization:yes\n");
12035 fprintf (of, "edges:yes\n");
12036 fprintf (of, "nodes:yes\n");
12037 fprintf (of, "splines:no\n");
12039 /* node defaults */
12040 fprintf (of, "node.color:lightyellow\n");
12041 fprintf (of, "node.textcolor:black\n");
12042 fprintf (of, "node.textmode:center\n");
12043 fprintf (of, "node.shape:box\n");
12044 fprintf (of, "node.bordercolor:black\n");
12045 fprintf (of, "node.borderwidth:1\n");
12047 /* edge defaults */
12048 fprintf (of, "edge.textcolor:black\n");
12049 fprintf (of, "edge.color:black\n");
12050 fprintf (of, "edge.thickness:1\n");
12051 fprintf (of, "edge.arrowcolor:black\n");
12052 fprintf (of, "edge.backarrowcolor:black\n");
12053 fprintf (of, "edge.arrowsize:15\n");
12054 fprintf (of, "edge.backarrowsize:15\n");
12055 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12056 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12057 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12059 fprintf (of, "\n");
12061 /* prepare data structures */
12063 hTabDeleteAll (dumpedNodes);
12064 dumpedNodes = NULL;
12066 dumpedNodes = newHashTable (128);
12069 /** Dump VCG footer into of. */
12070 static void pic16_vcg_close (FILE *of) {
12071 fprintf (of, "}\n");
12074 #define BUF_SIZE 128
12075 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12078 static int ptrcmp (const void *p1, const void *p2) {
12083 /** Dump a pCode node as VCG to of. */
12084 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12085 char buf[BUF_SIZE];
12087 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12091 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12092 //fprintf (stderr, "dumping %p\n", pc);
12094 /* only dump pCodeInstructions and Flow nodes */
12095 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12098 fprintf (of, "node:{");
12099 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12100 fprintf (of, "label:\"%s\n", pcTitle(pc));
12102 fprintf (of, "<PCFLOW>");
12103 } else if (isPCI(pc) || isPCAD(pc)) {
12104 pc->print (of, pc);
12106 fprintf (of, "<!PCI>");
12108 fprintf (of, "\" ");
12109 fprintf (of, "}\n");
12111 if (1 && isPCFL(pc)) {
12112 defmap_t *map, *prev;
12114 map = PCFL(pc)->defmap;
12117 if (map->sym != 0) {
12120 /* emit definition node */
12121 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12122 fprintf (of, "label:\"");
12126 fprintf (of, "%s%c%c: val %4x|%4x & %02x|%02x, sym %s", (prev == map) ? "" : "\n", map->acc.access.isRead ? 'R' : ' ', map->acc.access.isWrite ? 'W' : ' ', map->in_val, map->val, map->acc.access.in_mask, map->acc.access.mask, strFromSym (map->sym));
12129 } while (map && prev->pc == map->pc);
12132 fprintf (of, "\" ");
12134 fprintf (of, "color:green ");
12135 fprintf (of, "}\n");
12137 /* emit edge to previous definition */
12138 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12140 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12142 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12144 fprintf (of, "color:green ");
12145 fprintf (of, "}\n");
12148 pic16_vcg_dumpnode (map->pc, of);
12149 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12150 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12157 /* emit additional nodes (e.g. operands) */
12160 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12161 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12162 char buf[BUF_SIZE];
12163 pCodeInstruction *pci;
12167 if (1 && isPCFL(pc)) {
12168 /* emit edges to flow successors */
12170 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12171 pcfl = setFirstItem (PCFL(pc)->to);
12173 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12174 pic16_vcg_dumpnode (pc, of);
12175 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12176 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12177 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12178 pcfl = setNextItem (PCFL(pc)->to);
12182 if (!isPCI(pc) && !isPCAD(pc)) return;
12186 /* emit control flow edges (forward only) */
12190 pic16_vcg_dumpnode (curr->pc, of);
12191 fprintf (of, "edge:{");
12192 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12193 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12194 fprintf (of, "color:red ");
12195 fprintf (of, "}\n");
12200 /* dump "flow" edge (link pCode according to pBlock order) */
12203 pcnext = pic16_findNextInstruction (pc->next);
12205 pic16_vcg_dumpnode (pcnext, of);
12206 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12207 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12215 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12216 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12217 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12221 /* emit data flow edges (backward only) */
12222 /* TODO: gather data flow information... */
12225 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12230 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12231 if (pic16_pBlockHasAsmdirs (pb)) {
12232 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12236 for (pc=pb->pcHead; pc; pc = pc->next) {
12237 pic16_vcg_dumpnode (pc, of);
12240 for (pc=pb->pcHead; pc; pc = pc->next) {
12241 pic16_vcg_dumpedges (pc, of);
12245 static void pic16_vcg_dump_default (pBlock *pb) {
12247 char buf[BUF_SIZE];
12252 /* get function name */
12254 while (pc && !isPCF(pc)) pc = pc->next;
12256 SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12258 SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12261 //fprintf (stderr, "now dumping %s\n", buf);
12262 of = fopen (buf, "w");
12263 pic16_vcg_init (of);
12264 pic16_vcg_dump (of, pb);
12265 pic16_vcg_close (of);
12270 /*** END of helpers for pCode dataflow optimizations ***/