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 void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
160 extern int mnem2key(unsigned char const *mnem);
162 /****************************************************************/
163 /* Forward declarations */
164 /****************************************************************/
166 void pic16_unlinkpCode(pCode *pc);
168 static void genericAnalyze(pCode *pc);
169 static void AnalyzeGOTO(pCode *pc);
170 static void AnalyzeSKIP(pCode *pc);
171 static void AnalyzeRETURN(pCode *pc);
174 static void genericDestruct(pCode *pc);
175 static void genericPrint(FILE *of,pCode *pc);
177 static void pCodePrintLabel(FILE *of, pCode *pc);
178 static void pCodePrintFunction(FILE *of, pCode *pc);
179 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
180 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
181 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
182 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
183 int pic16_pCodePeepMatchRule(pCode *pc);
184 static void pBlockStats(FILE *of, pBlock *pb);
185 static pBlock *newpBlock(void);
186 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
187 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
188 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
189 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
190 void OptimizeLocalRegs(void);
191 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
193 char *dumpPicOptype(PIC_OPTYPE type);
195 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
196 pCodeOp *pic16_popGetLit(int);
197 pCodeOp *pic16_popGetWithString(char *);
198 extern int inWparamList(char *s);
200 /** data flow optimization helpers **/
201 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
202 static void pic16_vcg_dump (FILE *of, pBlock *pb);
203 static void pic16_vcg_dump_default (pBlock *pb);
205 static int pic16_pCodeIsAlive (pCode *pc);
206 static void pic16_df_stats ();
207 static void pic16_createDF (pBlock *pb);
208 static int pic16_removeUnusedRegistersDF ();
209 static void pic16_destructDF (pBlock *pb);
210 static void releaseStack ();
212 /****************************************************************/
213 /* PIC Instructions */
214 /****************************************************************/
216 pCodeInstruction pic16_pciADDWF = {
217 {PC_OPCODE, NULL, NULL, 0, NULL,
231 1,0, // dest, bit instruction
233 0, // literal operand
235 0, // fast call/return mode select bit
236 0, // second memory operand
237 0, // second literal operand
239 (PCC_W | PCC_REGISTER), // inCond
240 (PCC_REGISTER | PCC_STATUS), // outCond
244 pCodeInstruction pic16_pciADDFW = {
245 {PC_OPCODE, NULL, NULL, 0, NULL,
259 0,0, // dest, bit instruction
261 0, // literal operand
263 0, // fast call/return mode select bit
264 0, // second memory operand
265 0, // second literal operand
267 (PCC_W | PCC_REGISTER), // inCond
268 (PCC_W | PCC_STATUS), // outCond
272 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
273 {PC_OPCODE, NULL, NULL, 0, NULL,
287 1,0, // dest, bit instruction
289 0, // literal operand
291 0, // fast call/return mode select bit
292 0, // second memory operand
293 0, // second literal operand
295 (PCC_W | PCC_REGISTER | PCC_C), // inCond
296 (PCC_REGISTER | PCC_STATUS), // outCond
300 pCodeInstruction pic16_pciADDFWC = {
301 {PC_OPCODE, NULL, NULL, 0, NULL,
315 0,0, // dest, bit instruction
317 0, // literal operand
319 0, // fast call/return mode select bit
320 0, // second memory operand
321 0, // second literal operand
323 (PCC_W | PCC_REGISTER | PCC_C), // inCond
324 (PCC_W | PCC_STATUS), // outCond
328 pCodeInstruction pic16_pciADDLW = {
329 {PC_OPCODE, NULL, NULL, 0, NULL,
343 0,0, // dest, bit instruction
345 1, // literal operand
347 0, // fast call/return mode select bit
348 0, // second memory operand
349 0, // second literal operand
351 (PCC_W | PCC_LITERAL), // inCond
352 (PCC_W | PCC_STATUS), // outCond
356 pCodeInstruction pic16_pciANDLW = {
357 {PC_OPCODE, NULL, NULL, 0, NULL,
371 0,0, // dest, bit instruction
373 1, // literal operand
375 0, // fast call/return mode select bit
376 0, // second memory operand
377 0, // second literal operand
379 (PCC_W | PCC_LITERAL), // inCond
380 (PCC_W | PCC_Z | PCC_N), // outCond
384 pCodeInstruction pic16_pciANDWF = {
385 {PC_OPCODE, NULL, NULL, 0, NULL,
399 1,0, // dest, bit instruction
401 0, // literal operand
403 0, // fast call/return mode select bit
404 0, // second memory operand
405 0, // second literal operand
407 (PCC_W | PCC_REGISTER), // inCond
408 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
412 pCodeInstruction pic16_pciANDFW = {
413 {PC_OPCODE, NULL, NULL, 0, NULL,
427 0,0, // dest, bit instruction
429 0, // literal operand
431 0, // fast call/return mode select bit
432 0, // second memory operand
433 0, // second literal operand
435 (PCC_W | PCC_REGISTER), // inCond
436 (PCC_W | PCC_Z | PCC_N) // outCond
439 pCodeInstruction pic16_pciBC = { // mdubuc - New
440 {PC_OPCODE, NULL, NULL, 0, NULL,
454 0,0, // dest, bit instruction
456 0, // literal operand
458 0, // fast call/return mode select bit
459 0, // second memory operand
460 0, // second literal operand
462 (PCC_REL_ADDR | PCC_C), // inCond
467 pCodeInstruction pic16_pciBCF = {
468 {PC_OPCODE, NULL, NULL, 0, NULL,
482 1,1, // dest, bit instruction
484 0, // literal operand
486 0, // fast call/return mode select bit
487 0, // second memory operand
488 0, // second literal operand
490 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
491 PCC_REGISTER, // outCond
495 pCodeInstruction pic16_pciBN = { // mdubuc - New
496 {PC_OPCODE, NULL, NULL, 0, NULL,
510 0,0, // dest, bit instruction
512 0, // literal operand
514 0, // fast call/return mode select bit
515 0, // second memory operand
516 0, // second literal operand
518 (PCC_REL_ADDR | PCC_N), // inCond
519 PCC_NONE , // outCond
523 pCodeInstruction pic16_pciBNC = { // mdubuc - New
524 {PC_OPCODE, NULL, NULL, 0, NULL,
538 0,0, // dest, bit instruction
540 0, // literal operand
542 0, // fast call/return mode select bit
543 0, // second memory operand
544 0, // second literal operand
546 (PCC_REL_ADDR | PCC_C), // inCond
547 PCC_NONE , // outCond
551 pCodeInstruction pic16_pciBNN = { // mdubuc - New
552 {PC_OPCODE, NULL, NULL, 0, NULL,
566 0,0, // dest, bit instruction
568 0, // literal operand
570 0, // fast call/return mode select bit
571 0, // second memory operand
572 0, // second literal operand
574 (PCC_REL_ADDR | PCC_N), // inCond
575 PCC_NONE , // outCond
579 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
580 {PC_OPCODE, NULL, NULL, 0, NULL,
594 0,0, // dest, bit instruction
596 0, // literal operand
598 0, // fast call/return mode select bit
599 0, // second memory operand
600 0, // second literal operand
602 (PCC_REL_ADDR | PCC_OV), // inCond
603 PCC_NONE , // outCond
607 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
608 {PC_OPCODE, NULL, NULL, 0, NULL,
622 0,0, // dest, bit instruction
624 0, // literal operand
626 0, // fast call/return mode select bit
627 0, // second memory operand
628 0, // second literal operand
630 (PCC_REL_ADDR | PCC_Z), // inCond
631 PCC_NONE , // outCond
635 pCodeInstruction pic16_pciBOV = { // mdubuc - New
636 {PC_OPCODE, NULL, NULL, 0, NULL,
650 0,0, // dest, bit instruction
652 0, // literal operand
654 0, // fast call/return mode select bit
655 0, // second memory operand
656 0, // second literal operand
658 (PCC_REL_ADDR | PCC_OV), // inCond
659 PCC_NONE , // outCond
663 pCodeInstruction pic16_pciBRA = { // mdubuc - New
664 {PC_OPCODE, NULL, NULL, 0, NULL,
678 0,0, // dest, bit instruction
680 0, // literal operand
682 0, // fast call/return mode select bit
683 0, // second memory operand
684 0, // second literal operand
686 PCC_REL_ADDR, // inCond
687 PCC_NONE , // outCond
691 pCodeInstruction pic16_pciBSF = {
692 {PC_OPCODE, NULL, NULL, 0, NULL,
706 1,1, // dest, bit instruction
708 0, // literal operand
710 0, // fast call/return mode select bit
711 0, // second memory operand
712 0, // second literal operand
714 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
715 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
719 pCodeInstruction pic16_pciBTFSC = {
720 {PC_OPCODE, NULL, NULL, 0, NULL,
734 0,1, // dest, bit instruction
736 0, // literal operand
738 0, // fast call/return mode select bit
739 0, // second memory operand
740 0, // second literal operand
742 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
743 PCC_EXAMINE_PCOP, // outCond
747 pCodeInstruction pic16_pciBTFSS = {
748 {PC_OPCODE, NULL, NULL, 0, NULL,
762 0,1, // dest, bit instruction
764 0, // literal operand
766 0, // fast call/return mode select bit
767 0, // second memory operand
768 0, // second literal operand
770 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
771 PCC_EXAMINE_PCOP, // outCond
775 pCodeInstruction pic16_pciBTG = { // mdubuc - New
776 {PC_OPCODE, NULL, NULL, 0, NULL,
790 0,1, // dest, bit instruction
792 0, // literal operand
794 0, // fast call/return mode select bit
795 0, // second memory operand
796 0, // second literal operand
798 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
799 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
803 pCodeInstruction pic16_pciBZ = { // mdubuc - New
804 {PC_OPCODE, NULL, NULL, 0, NULL,
818 0,0, // dest, bit instruction
820 0, // literal operand
822 0, // fast call/return mode select bit
823 0, // second memory operand
824 0, // second literal operand
826 (PCC_REL_ADDR | PCC_Z), // inCond
831 pCodeInstruction pic16_pciCALL = {
832 {PC_OPCODE, NULL, NULL, 0, NULL,
846 0,0, // dest, bit instruction
848 0, // literal operand
850 1, // fast call/return mode select bit
851 0, // second memory operand
852 0, // second literal operand
859 pCodeInstruction pic16_pciCOMF = {
860 {PC_OPCODE, NULL, NULL, 0, NULL,
874 1,0, // dest, bit instruction
876 0, // literal operand
878 0, // fast call/return mode select bit
879 0, // second memory operand
880 0, // second literal operand
882 PCC_REGISTER, // inCond
883 (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
887 pCodeInstruction pic16_pciCOMFW = {
888 {PC_OPCODE, NULL, NULL, 0, NULL,
902 0,0, // dest, bit instruction
904 0, // literal operand
906 0, // fast call/return mode select bit
907 0, // second memory operand
908 0, // second literal operand
910 PCC_REGISTER, // inCond
911 (PCC_W | PCC_Z | PCC_N) , // outCond
915 pCodeInstruction pic16_pciCLRF = {
916 {PC_OPCODE, NULL, NULL, 0, NULL,
930 0,0, // dest, bit instruction
932 0, // literal operand
934 0, // fast call/return mode select bit
935 0, // second memory operand
936 0, // second literal operand
939 (PCC_REGISTER | PCC_Z), // outCond
943 pCodeInstruction pic16_pciCLRWDT = {
944 {PC_OPCODE, NULL, NULL, 0, NULL,
958 0,0, // dest, bit instruction
960 0, // literal operand
962 0, // fast call/return mode select bit
963 0, // second memory operand
964 0, // second literal operand
967 PCC_NONE , // outCond
971 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
972 {PC_OPCODE, NULL, NULL, 0, NULL,
986 0,0, // dest, bit instruction
988 0, // literal operand
990 0, // fast call/return mode select bit
991 0, // second memory operand
992 0, // second literal operand
994 (PCC_W | PCC_REGISTER), // inCond
995 PCC_NONE , // outCond
999 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1000 {PC_OPCODE, NULL, NULL, 0, NULL,
1007 NULL, // from branch
1014 0,0, // dest, bit instruction
1015 1,1, // branch, skip
1016 0, // literal operand
1017 1, // RAM access bit
1018 0, // fast call/return mode select bit
1019 0, // second memory operand
1020 0, // second literal operand
1022 (PCC_W | PCC_REGISTER), // inCond
1023 PCC_NONE , // outCond
1027 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1028 {PC_OPCODE, NULL, NULL, 0, NULL,
1035 NULL, // from branch
1042 1,0, // dest, bit instruction
1043 1,1, // branch, skip
1044 0, // literal operand
1045 1, // RAM access bit
1046 0, // fast call/return mode select bit
1047 0, // second memory operand
1048 0, // second literal operand
1050 (PCC_W | PCC_REGISTER), // inCond
1051 PCC_NONE , // outCond
1055 pCodeInstruction pic16_pciDAW = {
1056 {PC_OPCODE, NULL, NULL, 0, NULL,
1063 NULL, // from branch
1070 0,0, // dest, bit instruction
1071 0,0, // branch, skip
1072 0, // literal operand
1073 0, // RAM access bit
1074 0, // fast call/return mode select bit
1075 0, // second memory operand
1076 0, // second literal operand
1079 (PCC_W | PCC_C), // outCond
1083 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1084 {PC_OPCODE, NULL, NULL, 0, NULL,
1091 NULL, // from branch
1098 1,0, // dest, bit instruction
1099 1,1, // branch, skip
1100 0, // literal operand
1101 1, // RAM access bit
1102 0, // fast call/return mode select bit
1103 0, // second memory operand
1104 0, // second literal operand
1106 PCC_REGISTER, // inCond
1107 PCC_REGISTER , // outCond
1111 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1112 {PC_OPCODE, NULL, NULL, 0, NULL,
1119 NULL, // from branch
1126 0,0, // dest, bit instruction
1127 1,1, // branch, skip
1128 0, // literal operand
1129 1, // RAM access bit
1130 0, // fast call/return mode select bit
1131 0, // second memory operand
1132 0, // second literal operand
1134 PCC_REGISTER, // inCond
1139 pCodeInstruction pic16_pciDECF = {
1140 {PC_OPCODE, NULL, NULL, 0, NULL,
1147 NULL, // from branch
1154 1,0, // dest, bit instruction
1155 0,0, // branch, skip
1156 0, // literal operand
1157 1, // RAM access bit
1158 0, // fast call/return mode select bit
1159 0, // second memory operand
1160 0, // second literal operand
1162 PCC_REGISTER, // inCond
1163 (PCC_REGISTER | PCC_STATUS) , // outCond
1167 pCodeInstruction pic16_pciDECFW = {
1168 {PC_OPCODE, NULL, NULL, 0, NULL,
1175 NULL, // from branch
1182 0,0, // dest, bit instruction
1183 0,0, // branch, skip
1184 0, // literal operand
1185 1, // RAM access bit
1186 0, // fast call/return mode select bit
1187 0, // second memory operand
1188 0, // second literal operand
1190 PCC_REGISTER, // inCond
1191 (PCC_W | PCC_STATUS) , // outCond
1195 pCodeInstruction pic16_pciDECFSZ = {
1196 {PC_OPCODE, NULL, NULL, 0, NULL,
1203 NULL, // from branch
1210 1,0, // dest, bit instruction
1211 1,1, // branch, skip
1212 0, // literal operand
1213 1, // RAM access bit
1214 0, // fast call/return mode select bit
1215 0, // second memory operand
1216 0, // second literal operand
1218 PCC_REGISTER, // inCond
1219 PCC_REGISTER , // outCond
1223 pCodeInstruction pic16_pciDECFSZW = {
1224 {PC_OPCODE, NULL, NULL, 0, NULL,
1231 NULL, // from branch
1238 0,0, // dest, bit instruction
1239 1,1, // branch, skip
1240 0, // literal operand
1241 1, // RAM access bit
1242 0, // fast call/return mode select bit
1243 0, // second memory operand
1244 0, // second literal operand
1246 PCC_REGISTER, // inCond
1251 pCodeInstruction pic16_pciGOTO = {
1252 {PC_OPCODE, NULL, NULL, 0, NULL,
1259 NULL, // from branch
1266 0,0, // dest, bit instruction
1267 1,0, // branch, skip
1268 0, // literal operand
1269 0, // RAM access bit
1270 0, // fast call/return mode select bit
1271 0, // second memory operand
1272 0, // second literal operand
1274 PCC_REL_ADDR, // inCond
1275 PCC_NONE , // outCond
1279 pCodeInstruction pic16_pciINCF = {
1280 {PC_OPCODE, NULL, NULL, 0, NULL,
1287 NULL, // from branch
1294 1,0, // dest, bit instruction
1295 0,0, // branch, skip
1296 0, // literal operand
1297 1, // RAM access bit
1298 0, // fast call/return mode select bit
1299 0, // second memory operand
1300 0, // second literal operand
1302 PCC_REGISTER, // inCond
1303 (PCC_REGISTER | PCC_STATUS), // outCond
1307 pCodeInstruction pic16_pciINCFW = {
1308 {PC_OPCODE, NULL, NULL, 0, NULL,
1315 NULL, // from branch
1322 0,0, // dest, bit instruction
1323 0,0, // branch, skip
1324 0, // literal operand
1325 1, // RAM access bit
1326 0, // fast call/return mode select bit
1327 0, // second memory operand
1328 0, // second literal operand
1330 PCC_REGISTER, // inCond
1331 (PCC_W | PCC_STATUS) , // outCond
1335 pCodeInstruction pic16_pciINCFSZ = {
1336 {PC_OPCODE, NULL, NULL, 0, NULL,
1343 NULL, // from branch
1350 1,0, // dest, bit instruction
1351 1,1, // branch, skip
1352 0, // literal operand
1353 1, // RAM access bit
1354 0, // fast call/return mode select bit
1355 0, // second memory operand
1356 0, // second literal operand
1358 PCC_REGISTER, // inCond
1359 PCC_REGISTER , // outCond
1363 pCodeInstruction pic16_pciINCFSZW = {
1364 {PC_OPCODE, NULL, NULL, 0, NULL,
1371 NULL, // from branch
1378 0,0, // dest, bit instruction
1379 1,1, // branch, skip
1380 0, // literal operand
1381 1, // RAM access bit
1382 0, // fast call/return mode select bit
1383 0, // second memory operand
1384 0, // second literal operand
1386 PCC_REGISTER, // inCond
1391 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1392 {PC_OPCODE, NULL, NULL, 0, NULL,
1399 NULL, // from branch
1406 1,0, // dest, bit instruction
1407 1,1, // branch, skip
1408 0, // literal operand
1409 1, // RAM access bit
1410 0, // fast call/return mode select bit
1411 0, // second memory operand
1412 0, // second literal operand
1414 PCC_REGISTER, // inCond
1415 PCC_REGISTER , // outCond
1419 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1420 {PC_OPCODE, NULL, NULL, 0, NULL,
1427 NULL, // from branch
1434 0,0, // dest, bit instruction
1435 1,1, // branch, skip
1436 0, // literal operand
1437 1, // RAM access bit
1438 0, // fast call/return mode select bit
1439 0, // second memory operand
1440 0, // second literal operand
1442 PCC_REGISTER, // inCond
1447 pCodeInstruction pic16_pciIORWF = {
1448 {PC_OPCODE, NULL, NULL, 0, NULL,
1455 NULL, // from branch
1462 1,0, // dest, bit instruction
1463 0,0, // branch, skip
1464 0, // literal operand
1465 1, // RAM access bit
1466 0, // fast call/return mode select bit
1467 0, // second memory operand
1468 0, // second literal operand
1470 (PCC_W | PCC_REGISTER), // inCond
1471 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1475 pCodeInstruction pic16_pciIORFW = {
1476 {PC_OPCODE, NULL, NULL, 0, NULL,
1483 NULL, // from branch
1490 0,0, // dest, bit instruction
1491 0,0, // branch, skip
1492 0, // literal operand
1493 1, // RAM access bit
1494 0, // fast call/return mode select bit
1495 0, // second memory operand
1496 0, // second literal operand
1498 (PCC_W | PCC_REGISTER), // inCond
1499 (PCC_W | PCC_Z | PCC_N), // outCond
1503 pCodeInstruction pic16_pciIORLW = {
1504 {PC_OPCODE, NULL, NULL, 0, NULL,
1511 NULL, // from branch
1518 0,0, // dest, bit instruction
1519 0,0, // branch, skip
1520 1, // literal operand
1521 0, // RAM access bit
1522 0, // fast call/return mode select bit
1523 0, // second memory operand
1524 0, // second literal operand
1526 (PCC_W | PCC_LITERAL), // inCond
1527 (PCC_W | PCC_Z | PCC_N), // outCond
1531 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1532 {PC_OPCODE, NULL, NULL, 0, NULL,
1539 NULL, // from branch
1546 0,0, // dest, bit instruction
1547 0,0, // branch, skip
1548 1, // literal operand
1549 0, // RAM access bit
1550 0, // fast call/return mode select bit
1551 0, // second memory operand
1552 1, // second literal operand
1554 PCC_LITERAL, // inCond
1555 PCC_NONE, // outCond
1559 pCodeInstruction pic16_pciMOVF = {
1560 {PC_OPCODE, NULL, NULL, 0, NULL,
1567 NULL, // from branch
1574 1,0, // dest, bit instruction
1575 0,0, // branch, skip
1576 0, // literal operand
1577 1, // RAM access bit
1578 0, // fast call/return mode select bit
1579 0, // second memory operand
1580 0, // second literal operand
1582 PCC_REGISTER, // inCond
1583 (PCC_Z | PCC_N), // outCond
1587 pCodeInstruction pic16_pciMOVFW = {
1588 {PC_OPCODE, NULL, NULL, 0, NULL,
1595 NULL, // from branch
1602 0,0, // dest, bit instruction
1603 0,0, // branch, skip
1604 0, // literal operand
1605 1, // RAM access bit
1606 0, // fast call/return mode select bit
1607 0, // second memory operand
1608 0, // second literal operand
1610 PCC_REGISTER, // inCond
1611 (PCC_W | PCC_N | PCC_Z), // outCond
1615 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1616 {PC_OPCODE, NULL, NULL, 0, NULL,
1623 NULL, // from branch
1630 0,0, // dest, bit instruction
1631 0,0, // branch, skip
1632 0, // literal operand
1633 0, // RAM access bit
1634 0, // fast call/return mode select bit
1635 1, // second memory operand
1636 0, // second literal operand
1638 PCC_REGISTER, // inCond
1639 PCC_REGISTER2, // outCond
1643 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1644 {PC_OPCODE, NULL, NULL, 0, NULL,
1650 NULL, // from branch
1657 0,0, // dest, bit instruction
1658 0,0, // branch, skip
1659 1, // literal operand
1660 0, // RAM access bit
1661 0, // fast call/return mode select bit
1662 0, // second memory operand
1663 0, // second literal operand
1665 (PCC_NONE | PCC_LITERAL), // inCond
1666 PCC_REGISTER, // outCond - BSR
1670 pCodeInstruction pic16_pciMOVLW = {
1671 {PC_OPCODE, NULL, NULL, 0, NULL,
1677 NULL, // from branch
1684 0,0, // dest, bit instruction
1685 0,0, // branch, skip
1686 1, // literal operand
1687 0, // RAM access bit
1688 0, // fast call/return mode select bit
1689 0, // second memory operand
1690 0, // second literal operand
1692 (PCC_NONE | PCC_LITERAL), // inCond
1697 pCodeInstruction pic16_pciMOVWF = {
1698 {PC_OPCODE, NULL, NULL, 0, NULL,
1705 NULL, // from branch
1712 0,0, // dest, bit instruction
1713 0,0, // branch, skip
1714 0, // literal operand
1715 1, // RAM access bit
1716 0, // fast call/return mode select bit
1717 0, // second memory operand
1718 0, // second literal operand
1721 PCC_REGISTER, // outCond
1725 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1726 {PC_OPCODE, NULL, NULL, 0, NULL,
1732 NULL, // from branch
1739 0,0, // dest, bit instruction
1740 0,0, // branch, skip
1741 1, // literal operand
1742 0, // RAM access bit
1743 0, // fast call/return mode select bit
1744 0, // second memory operand
1745 0, // second literal operand
1747 (PCC_W | PCC_LITERAL), // inCond
1748 PCC_NONE, // outCond - PROD
1752 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1753 {PC_OPCODE, NULL, NULL, 0, NULL,
1759 NULL, // from branch
1766 0,0, // dest, bit instruction
1767 0,0, // branch, skip
1768 0, // literal operand
1769 1, // RAM access bit
1770 0, // fast call/return mode select bit
1771 0, // second memory operand
1772 0, // second literal operand
1774 (PCC_W | PCC_REGISTER), // inCond
1775 PCC_REGISTER, // outCond - PROD
1779 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1780 {PC_OPCODE, NULL, NULL, 0, NULL,
1786 NULL, // from branch
1793 0,0, // dest, bit instruction
1794 0,0, // branch, skip
1795 0, // literal operand
1796 1, // RAM access bit
1797 0, // fast call/return mode select bit
1798 0, // second memory operand
1799 0, // second literal operand
1801 PCC_REGISTER, // inCond
1802 (PCC_REGISTER | PCC_STATUS), // outCond
1806 pCodeInstruction pic16_pciNOP = {
1807 {PC_OPCODE, NULL, NULL, 0, NULL,
1813 NULL, // from branch
1820 0,0, // dest, bit instruction
1821 0,0, // branch, skip
1822 0, // literal operand
1823 0, // RAM access bit
1824 0, // fast call/return mode select bit
1825 0, // second memory operand
1826 0, // second literal operand
1829 PCC_NONE, // outCond
1833 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1834 {PC_OPCODE, NULL, NULL, 0, NULL,
1840 NULL, // from branch
1847 0,0, // dest, bit instruction
1848 0,0, // branch, skip
1849 0, // literal operand
1850 0, // RAM access bit
1851 0, // fast call/return mode select bit
1852 0, // second memory operand
1853 0, // second literal operand
1856 PCC_NONE , // outCond
1860 pCodeInstruction pic16_pciPUSH = {
1861 {PC_OPCODE, NULL, NULL, 0, NULL,
1867 NULL, // from branch
1874 0,0, // dest, bit instruction
1875 0,0, // branch, skip
1876 0, // literal operand
1877 0, // RAM access bit
1878 0, // fast call/return mode select bit
1879 0, // second memory operand
1880 0, // second literal operand
1883 PCC_NONE , // outCond
1887 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1888 {PC_OPCODE, NULL, NULL, 0, NULL,
1894 NULL, // from branch
1901 0,0, // dest, bit instruction
1902 1,0, // branch, skip
1903 0, // literal operand
1904 0, // RAM access bit
1905 0, // fast call/return mode select bit
1906 0, // second memory operand
1907 0, // second literal operand
1909 PCC_REL_ADDR, // inCond
1910 PCC_NONE , // outCond
1914 pCodeInstruction pic16_pciRETFIE = {
1915 {PC_OPCODE, NULL, NULL, 0, NULL,
1922 NULL, // from branch
1929 0,0, // dest, bit instruction
1930 1,0, // branch, skip
1931 0, // literal operand
1932 0, // RAM access bit
1933 1, // fast call/return mode select bit
1934 0, // second memory operand
1935 0, // second literal operand
1938 PCC_NONE, // outCond (not true... affects the GIE bit too)
1942 pCodeInstruction pic16_pciRETLW = {
1943 {PC_OPCODE, NULL, NULL, 0, NULL,
1950 NULL, // from branch
1957 0,0, // dest, bit instruction
1958 1,0, // branch, skip
1959 1, // literal operand
1960 0, // RAM access bit
1961 0, // fast call/return mode select bit
1962 0, // second memory operand
1963 0, // second literal operand
1965 PCC_LITERAL, // inCond
1970 pCodeInstruction pic16_pciRETURN = {
1971 {PC_OPCODE, NULL, NULL, 0, NULL,
1978 NULL, // from branch
1985 0,0, // dest, bit instruction
1986 1,0, // branch, skip
1987 0, // literal operand
1988 0, // RAM access bit
1989 1, // fast call/return mode select bit
1990 0, // second memory operand
1991 0, // second literal operand
1994 PCC_NONE, // outCond
1997 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
1998 {PC_OPCODE, NULL, NULL, 0, NULL,
2005 NULL, // from branch
2012 1,0, // dest, bit instruction
2013 0,0, // branch, skip
2014 0, // literal operand
2015 1, // RAM access bit
2016 0, // fast call/return mode select bit
2017 0, // second memory operand
2018 0, // second literal operand
2020 (PCC_C | PCC_REGISTER), // inCond
2021 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2025 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2026 {PC_OPCODE, NULL, NULL, 0, NULL,
2033 NULL, // from branch
2040 0,0, // dest, bit instruction
2041 0,0, // branch, skip
2042 0, // literal operand
2043 1, // RAM access bit
2044 0, // fast call/return mode select bit
2045 0, // second memory operand
2046 0, // second literal operand
2048 (PCC_C | PCC_REGISTER), // inCond
2049 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2053 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2054 {PC_OPCODE, NULL, NULL, 0, NULL,
2061 NULL, // from branch
2068 1,0, // dest, bit instruction
2069 0,0, // branch, skip
2070 0, // literal operand
2071 1, // RAM access bit
2072 0, // fast call/return mode select bit
2073 0, // second memory operand
2074 0, // second literal operand
2076 PCC_REGISTER, // inCond
2077 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2080 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2081 {PC_OPCODE, NULL, NULL, 0, NULL,
2088 NULL, // from branch
2095 0,0, // dest, bit instruction
2096 0,0, // branch, skip
2097 0, // literal operand
2098 1, // RAM access bit
2099 0, // fast call/return mode select bit
2100 0, // second memory operand
2101 0, // second literal operand
2103 PCC_REGISTER, // inCond
2104 (PCC_W | PCC_Z | PCC_N), // outCond
2107 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2108 {PC_OPCODE, NULL, NULL, 0, NULL,
2115 NULL, // from branch
2122 1,0, // dest, bit instruction
2123 0,0, // branch, skip
2124 0, // literal operand
2125 1, // RAM access bit
2126 0, // fast call/return mode select bit
2127 0, // second memory operand
2128 0, // second literal operand
2130 (PCC_C | PCC_REGISTER), // inCond
2131 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2134 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2135 {PC_OPCODE, NULL, NULL, 0, NULL,
2142 NULL, // from branch
2149 0,0, // dest, bit instruction
2150 0,0, // branch, skip
2151 0, // literal operand
2152 1, // RAM access bit
2153 0, // fast call/return mode select bit
2154 0, // second memory operand
2155 0, // second literal operand
2157 (PCC_C | PCC_REGISTER), // inCond
2158 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2161 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2162 {PC_OPCODE, NULL, NULL, 0, NULL,
2169 NULL, // from branch
2176 1,0, // dest, bit instruction
2177 0,0, // branch, skip
2178 0, // literal operand
2179 1, // RAM access bit
2180 0, // fast call/return mode select bit
2181 0, // second memory operand
2182 0, // second literal operand
2184 PCC_REGISTER, // inCond
2185 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2189 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2190 {PC_OPCODE, NULL, NULL, 0, NULL,
2197 NULL, // from branch
2204 0,0, // dest, bit instruction
2205 0,0, // branch, skip
2206 0, // literal operand
2207 1, // RAM access bit
2208 0, // fast call/return mode select bit
2209 0, // second memory operand
2210 0, // second literal operand
2212 PCC_REGISTER, // inCond
2213 (PCC_W | PCC_Z | PCC_N), // outCond
2217 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2218 {PC_OPCODE, NULL, NULL, 0, NULL,
2225 NULL, // from branch
2232 0,0, // dest, bit instruction
2233 0,0, // branch, skip
2234 0, // literal operand
2235 1, // RAM access bit
2236 0, // fast call/return mode select bit
2237 0, // second memory operand
2238 0, // second literal operand
2241 PCC_REGISTER , // outCond
2245 pCodeInstruction pic16_pciSUBLW = {
2246 {PC_OPCODE, NULL, NULL, 0, NULL,
2253 NULL, // from branch
2260 0,0, // dest, bit instruction
2261 0,0, // branch, skip
2262 1, // literal operand
2263 0, // RAM access bit
2264 0, // fast call/return mode select bit
2265 0, // second memory operand
2266 0, // second literal operand
2268 (PCC_W | PCC_LITERAL), // inCond
2269 (PCC_W | PCC_STATUS), // outCond
2273 pCodeInstruction pic16_pciSUBFWB = {
2274 {PC_OPCODE, NULL, NULL, 0, NULL,
2281 NULL, // from branch
2288 1,0, // dest, bit instruction
2289 0,0, // branch, skip
2290 0, // literal operand
2291 1, // RAM access bit
2292 0, // fast call/return mode select bit
2293 0, // second memory operand
2294 0, // second literal operand
2296 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2297 (PCC_W | PCC_STATUS), // outCond
2301 pCodeInstruction pic16_pciSUBWF = {
2302 {PC_OPCODE, NULL, NULL, 0, NULL,
2309 NULL, // from branch
2316 1,0, // dest, bit instruction
2317 0,0, // branch, skip
2318 0, // literal operand
2319 1, // RAM access bit
2320 0, // fast call/return mode select bit
2321 0, // second memory operand
2322 0, // second literal operand
2324 (PCC_W | PCC_REGISTER), // inCond
2325 (PCC_REGISTER | PCC_STATUS), // outCond
2329 pCodeInstruction pic16_pciSUBFW = {
2330 {PC_OPCODE, NULL, NULL, 0, NULL,
2337 NULL, // from branch
2344 0,0, // dest, bit instruction
2345 0,0, // branch, skip
2346 0, // literal operand
2347 1, // RAM access bit
2348 0, // fast call/return mode select bit
2349 0, // second memory operand
2350 0, // second literal operand
2352 (PCC_W | PCC_REGISTER), // inCond
2353 (PCC_W | PCC_STATUS), // outCond
2357 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2358 {PC_OPCODE, NULL, NULL, 0, NULL,
2365 NULL, // from branch
2372 1,0, // dest, bit instruction
2373 0,0, // branch, skip
2374 0, // literal operand
2375 1, // RAM access bit
2376 0, // fast call/return mode select bit
2377 0, // second memory operand
2378 0, // second literal operand
2380 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2381 (PCC_REGISTER | PCC_STATUS), // outCond
2385 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2386 {PC_OPCODE, NULL, NULL, 0, NULL,
2393 NULL, // from branch
2400 0,0, // dest, bit instruction
2401 0,0, // branch, skip
2402 0, // literal operand
2403 1, // RAM access bit
2404 0, // fast call/return mode select bit
2405 0, // second memory operand
2406 0, // second literal operand
2408 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2409 (PCC_W | PCC_STATUS), // outCond
2413 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2414 {PC_OPCODE, NULL, NULL, 0, NULL,
2421 NULL, // from branch
2428 1,0, // dest, bit instruction
2429 0,0, // branch, skip
2430 0, // literal operand
2431 1, // RAM access bit
2432 0, // fast call/return mode select bit
2433 0, // second memory operand
2434 0, // second literal operand
2436 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2437 (PCC_REGISTER | PCC_STATUS), // outCond
2441 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2442 {PC_OPCODE, NULL, NULL, 0, NULL,
2449 NULL, // from branch
2456 0,0, // dest, bit instruction
2457 0,0, // branch, skip
2458 0, // literal operand
2459 1, // RAM access bit
2460 0, // fast call/return mode select bit
2461 0, // second memory operand
2462 0, // second literal operand
2464 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2465 (PCC_W | PCC_STATUS), // outCond
2469 pCodeInstruction pic16_pciSWAPF = {
2470 {PC_OPCODE, NULL, NULL, 0, NULL,
2477 NULL, // from branch
2484 1,0, // dest, bit instruction
2485 0,0, // branch, skip
2486 0, // literal operand
2487 1, // RAM access bit
2488 0, // fast call/return mode select bit
2489 0, // second memory operand
2490 0, // second literal operand
2492 (PCC_REGISTER), // inCond
2493 (PCC_REGISTER), // outCond
2497 pCodeInstruction pic16_pciSWAPFW = {
2498 {PC_OPCODE, NULL, NULL, 0, NULL,
2505 NULL, // from branch
2512 0,0, // dest, bit instruction
2513 0,0, // branch, skip
2514 0, // literal operand
2515 1, // RAM access bit
2516 0, // fast call/return mode select bit
2517 0, // second memory operand
2518 0, // second literal operand
2520 (PCC_REGISTER), // inCond
2525 pCodeInstruction pic16_pciTBLRD = { // patch 15
2526 {PC_OPCODE, NULL, NULL, 0, NULL,
2532 NULL, // from branch
2539 0,0, // dest, bit instruction
2540 0,0, // branch, skip
2541 0, // literal operand
2542 0, // RAM access bit
2543 0, // fast call/return mode select bit
2544 0, // second memory operand
2545 0, // second literal operand
2548 PCC_NONE , // outCond
2552 pCodeInstruction pic16_pciTBLRD_POSTINC = { // patch 15
2553 {PC_OPCODE, NULL, NULL, 0, NULL,
2559 NULL, // from branch
2566 0,0, // dest, bit instruction
2567 0,0, // branch, skip
2568 0, // literal operand
2569 0, // RAM access bit
2570 0, // fast call/return mode select bit
2571 0, // second memory operand
2572 0, // second literal operand
2575 PCC_NONE , // outCond
2579 pCodeInstruction pic16_pciTBLRD_POSTDEC = { // patch 15
2580 {PC_OPCODE, NULL, NULL, 0, NULL,
2586 NULL, // from branch
2593 0,0, // dest, bit instruction
2594 0,0, // branch, skip
2595 0, // literal operand
2596 0, // RAM access bit
2597 0, // fast call/return mode select bit
2598 0, // second memory operand
2599 0, // second literal operand
2602 PCC_NONE , // outCond
2606 pCodeInstruction pic16_pciTBLRD_PREINC = { // patch 15
2607 {PC_OPCODE, NULL, NULL, 0, NULL,
2613 NULL, // from branch
2620 0,0, // dest, bit instruction
2621 0,0, // branch, skip
2622 0, // literal operand
2623 0, // RAM access bit
2624 0, // fast call/return mode select bit
2625 0, // second memory operand
2626 0, // second literal operand
2629 PCC_NONE , // outCond
2633 pCodeInstruction pic16_pciTBLWT = { // patch 15
2634 {PC_OPCODE, NULL, NULL, 0, NULL,
2640 NULL, // from branch
2647 0,0, // dest, bit instruction
2648 0,0, // branch, skip
2649 0, // literal operand
2650 0, // RAM access bit
2651 0, // fast call/return mode select bit
2652 0, // second memory operand
2653 0, // second literal operand
2656 PCC_NONE , // outCond
2660 pCodeInstruction pic16_pciTBLWT_POSTINC = { // patch 15
2661 {PC_OPCODE, NULL, NULL, 0, NULL,
2667 NULL, // from branch
2674 0,0, // dest, bit instruction
2675 0,0, // branch, skip
2676 0, // literal operand
2677 0, // RAM access bit
2678 0, // fast call/return mode select bit
2679 0, // second memory operand
2680 0, // second literal operand
2683 PCC_NONE , // outCond
2687 pCodeInstruction pic16_pciTBLWT_POSTDEC = { // patch 15
2688 {PC_OPCODE, NULL, NULL, 0, NULL,
2694 NULL, // from branch
2701 0,0, // dest, bit instruction
2702 0,0, // branch, skip
2703 0, // literal operand
2704 0, // RAM access bit
2705 0, // fast call/return mode select bit
2706 0, // second memory operand
2707 0, // second literal operand
2710 PCC_NONE , // outCond
2714 pCodeInstruction pic16_pciTBLWT_PREINC = { // patch 15
2715 {PC_OPCODE, NULL, NULL, 0, NULL,
2721 NULL, // from branch
2728 0,0, // dest, bit instruction
2729 0,0, // branch, skip
2730 0, // literal operand
2731 0, // RAM access bit
2732 0, // fast call/return mode select bit
2733 0, // second memory operand
2734 0, // second literal operand
2737 PCC_NONE , // outCond
2741 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2742 {PC_OPCODE, NULL, NULL, 0, NULL,
2749 NULL, // from branch
2756 0,0, // dest, bit instruction
2757 1,1, // branch, skip
2758 0, // literal operand
2759 1, // RAM access bit
2760 0, // fast call/return mode select bit
2761 0, // second memory operand
2762 0, // second literal operand
2764 PCC_REGISTER, // inCond
2765 PCC_NONE, // outCond
2769 pCodeInstruction pic16_pciXORWF = {
2770 {PC_OPCODE, NULL, NULL, 0, NULL,
2777 NULL, // from branch
2784 1,0, // dest, bit instruction
2785 0,0, // branch, skip
2786 0, // literal operand
2787 1, // RAM access bit
2788 0, // fast call/return mode select bit
2789 0, // second memory operand
2790 0, // second literal operand
2792 (PCC_W | PCC_REGISTER), // inCond
2793 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2797 pCodeInstruction pic16_pciXORFW = {
2798 {PC_OPCODE, NULL, NULL, 0, NULL,
2805 NULL, // from branch
2812 0,0, // dest, bit instruction
2813 0,0, // branch, skip
2814 0, // literal operand
2815 1, // RAM access bit
2816 0, // fast call/return mode select bit
2817 0, // second memory operand
2818 0, // second literal operand
2820 (PCC_W | PCC_REGISTER), // inCond
2821 (PCC_W | PCC_Z | PCC_N), // outCond
2825 pCodeInstruction pic16_pciXORLW = {
2826 {PC_OPCODE, NULL, NULL, 0, NULL,
2833 NULL, // from branch
2840 0,0, // dest, bit instruction
2841 0,0, // branch, skip
2842 1, // literal operand
2843 1, // RAM access bit
2844 0, // fast call/return mode select bit
2845 0, // second memory operand
2846 0, // second literal operand
2848 (PCC_W | PCC_LITERAL), // inCond
2849 (PCC_W | PCC_Z | PCC_N), // outCond
2854 pCodeInstruction pic16_pciBANKSEL = {
2855 {PC_OPCODE, NULL, NULL, 0, NULL,
2861 NULL, // from branch
2868 0,0, // dest, bit instruction
2869 0,0, // branch, skip
2870 0, // literal operand
2871 0, // RAM access bit
2872 0, // fast call/return mode select bit
2873 0, // second memory operand
2874 0, // second literal operand
2877 PCC_NONE, // outCond
2882 #define MAX_PIC16MNEMONICS 100
2883 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2885 //#define USE_VSNPRINTF
2888 #ifdef USE_VSNPRINTF
2889 // Alas, vsnprintf is not ANSI standard, and does not exist
2890 // on Solaris (and probably other non-Gnu flavored Unixes).
2892 /*-----------------------------------------------------------------*/
2893 /* SAFE_snprintf - like snprintf except the string pointer is */
2894 /* after the string has been printed to. This is */
2895 /* useful for printing to string as though if it */
2896 /* were a stream. */
2897 /*-----------------------------------------------------------------*/
2898 void SAFE_snprintf(char **str, size_t *size, const char *format, ...)
2906 va_start(val, format);
2908 vsnprintf(*str, *size, format, val);
2914 fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2915 fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2924 // This version is *not* safe, despite the name.
2926 void SAFE_snprintf(char **str, size_t *size, const char *format, ...)
2930 static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2935 va_start(val, format);
2937 vsprintf(buffer, format, val);
2940 len = strlen(buffer);
2942 fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2943 fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2946 strcpy(*str, buffer);
2952 #endif // USE_VSNPRINTF
2955 extern set *externs;
2956 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2957 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2959 void pic16_pCodeInitRegisters(void)
2961 static int initialized=0;
2968 pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2969 pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2970 pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2971 pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2972 pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2973 pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2974 pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2976 pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2977 pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2978 pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2980 pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2981 pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2982 pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2983 pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2985 pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2986 pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2987 pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2988 pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2989 pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2990 pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2992 pic16_stackpnt_lo = &pic16_pc_fsr1l;
2993 pic16_stackpnt_hi = &pic16_pc_fsr1h;
2994 pic16_stack_postdec = &pic16_pc_postdec1;
2995 pic16_stack_postinc = &pic16_pc_postinc1;
2996 pic16_stack_preinc = &pic16_pc_preinc1;
2997 pic16_stack_plusw = &pic16_pc_plusw1;
2999 pic16_framepnt_lo = &pic16_pc_fsr2l;
3000 pic16_framepnt_hi = &pic16_pc_fsr2h;
3001 pic16_frame_postdec = &pic16_pc_postdec2;
3002 pic16_frame_postinc = &pic16_pc_postinc2;
3003 pic16_frame_preinc = &pic16_pc_preinc2;
3004 pic16_frame_plusw = &pic16_pc_plusw2;
3006 pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3007 pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3008 pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3009 pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3010 pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3012 pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3013 pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3014 pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3015 pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3016 pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3018 pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3019 pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3020 pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3021 pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3022 pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3024 pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3025 pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3028 pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3029 pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3030 pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3031 pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3034 pic16_pc_status.rIdx = IDX_STATUS;
3035 pic16_pc_intcon.rIdx = IDX_INTCON;
3036 pic16_pc_pcl.rIdx = IDX_PCL;
3037 pic16_pc_pclath.rIdx = IDX_PCLATH;
3038 pic16_pc_pclatu.rIdx = IDX_PCLATU;
3039 pic16_pc_wreg.rIdx = IDX_WREG;
3040 pic16_pc_bsr.rIdx = IDX_BSR;
3042 pic16_pc_tosl.rIdx = IDX_TOSL;
3043 pic16_pc_tosh.rIdx = IDX_TOSH;
3044 pic16_pc_tosu.rIdx = IDX_TOSU;
3046 pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3047 pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3048 pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3049 pic16_pc_tablat.rIdx = IDX_TABLAT;
3051 pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3052 pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3053 pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3054 pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3055 pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3056 pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3057 pic16_pc_indf0.rIdx = IDX_INDF0;
3058 pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3059 pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3060 pic16_pc_preinc0.rIdx = IDX_PREINC0;
3061 pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3062 pic16_pc_indf1.rIdx = IDX_INDF1;
3063 pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3064 pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3065 pic16_pc_preinc1.rIdx = IDX_PREINC1;
3066 pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3067 pic16_pc_indf2.rIdx = IDX_INDF2;
3068 pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3069 pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3070 pic16_pc_preinc2.rIdx = IDX_PREINC2;
3071 pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3072 pic16_pc_prodl.rIdx = IDX_PRODL;
3073 pic16_pc_prodh.rIdx = IDX_PRODH;
3075 pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3076 pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3077 pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3079 pic16_pc_kzero.rIdx = IDX_KZ;
3080 pic16_pc_wsave.rIdx = IDX_WSAVE;
3081 pic16_pc_ssave.rIdx = IDX_SSAVE;
3083 pic16_pc_eecon1.rIdx = IDX_EECON1;
3084 pic16_pc_eecon2.rIdx = IDX_EECON2;
3085 pic16_pc_eedata.rIdx = IDX_EEDATA;
3086 pic16_pc_eeadr.rIdx = IDX_EEADR;
3089 pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3090 pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3092 pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3093 pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3095 /* probably should put this in a separate initialization routine */
3096 pb_dead_pcodes = newpBlock();
3101 /*-----------------------------------------------------------------*/
3102 /* mnem2key - convert a pic mnemonic into a hash key */
3103 /* (BTW - this spreads the mnemonics quite well) */
3105 /*-----------------------------------------------------------------*/
3107 int mnem2key(unsigned char const *mnem)
3116 key += toupper(*mnem++) +1;
3120 return (key & 0x1f);
3125 void pic16initMnemonics(void)
3130 pCodeInstruction *pci;
3132 if(mnemonics_initialized)
3135 // NULL out the array before making the assignments
3136 // since we check the array contents below this initialization.
3138 for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3139 pic16Mnemonics[i] = NULL;
3142 pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3143 pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3144 pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3145 pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3146 pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3147 pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3148 pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3149 pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3150 pic16Mnemonics[POC_BC] = &pic16_pciBC;
3151 pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3152 pic16Mnemonics[POC_BN] = &pic16_pciBN;
3153 pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3154 pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3155 pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3156 pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3157 pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3158 pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3159 pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3160 pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3161 pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3162 pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3163 pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3164 pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3165 pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3166 pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3167 pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3168 pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3169 pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3170 pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3171 pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3172 pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3173 pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3174 pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3175 pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3176 pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3177 pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3178 pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3179 pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3180 pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3181 pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3182 pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3183 pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3184 pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3185 pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3186 pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3187 pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3188 pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3189 pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3190 pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3191 pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3192 pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3193 pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3194 pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3195 pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3196 pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3197 pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3198 pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3199 pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3200 pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3201 pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3202 pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3203 pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3204 pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3205 pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3206 pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3207 pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3208 pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3209 pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3210 pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3211 pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3212 pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3213 pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3214 pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3215 pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3216 pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3217 pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3218 pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3219 pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3220 pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3221 pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3222 pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3223 pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3224 pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3225 pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3226 pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3227 pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3228 pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3229 pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3230 pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3231 pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3232 pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3233 pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3234 pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3235 pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3237 for(i=0; i<MAX_PIC16MNEMONICS; i++)
3238 if(pic16Mnemonics[i])
3239 hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3240 pci = hTabFirstItem(pic16MnemonicsHash, &key);
3243 DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3244 pci = hTabNextItem(pic16MnemonicsHash, &key);
3247 mnemonics_initialized = 1;
3250 int pic16_getpCodePeepCommand(char *cmd);
3252 int pic16_getpCode(char *mnem,unsigned dest)
3255 pCodeInstruction *pci;
3256 int key = mnem2key((unsigned char *)mnem);
3258 if(!mnemonics_initialized)
3259 pic16initMnemonics();
3261 pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3265 if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3266 if((pci->num_ops <= 1)
3267 || (pci->isModReg == dest)
3269 || (pci->num_ops <= 2 && pci->isAccess)
3270 || (pci->num_ops <= 2 && pci->isFastCall)
3271 || (pci->num_ops <= 2 && pci->is2MemOp)
3272 || (pci->num_ops <= 2 && pci->is2LitOp) )
3276 pci = hTabNextItemWK (pic16MnemonicsHash);
3283 /*-----------------------------------------------------------------*
3284 * pic16initpCodePeepCommands
3286 *-----------------------------------------------------------------*/
3287 void pic16initpCodePeepCommands(void)
3295 hTabAddItem(&pic16pCodePeepCommandsHash,
3296 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3298 } while (peepCommands[i].cmd);
3300 pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3303 //fprintf(stderr, "peep command %s key %d\n",pcmd->cmd,pcmd->id);
3304 pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3309 /*-----------------------------------------------------------------
3312 *-----------------------------------------------------------------*/
3314 int pic16_getpCodePeepCommand(char *cmd)
3318 int key = mnem2key((unsigned char *)cmd);
3321 pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3324 // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3325 if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3329 pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3336 static char getpBlock_dbName(pBlock *pb)
3342 return pb->cmemmap->dbName;
3346 void pic16_pBlockConvert2ISR(pBlock *pb)
3350 if(pb->cmemmap)pb->cmemmap = NULL;
3354 if(pic16_pcode_verbose)
3355 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3358 void pic16_pBlockConvert2Absolute(pBlock *pb)
3361 if(pb->cmemmap)pb->cmemmap = NULL;
3365 if(pic16_pcode_verbose)
3366 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3369 /*-----------------------------------------------------------------*/
3370 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all */
3371 /* instances to the front of the doubly linked */
3372 /* list of pBlocks */
3373 /*-----------------------------------------------------------------*/
3375 void pic16_movepBlock2Head(char dbName)
3380 /* this can happen in sources without code,
3381 * only variable definitions */
3382 if(!the_pFile)return;
3384 pb = the_pFile->pbHead;
3388 if(getpBlock_dbName(pb) == dbName) {
3389 pBlock *pbn = pb->next;
3390 pb->next = the_pFile->pbHead;
3391 the_pFile->pbHead->prev = pb;
3392 the_pFile->pbHead = pb;
3395 pb->prev->next = pbn;
3397 // If the pBlock that we just moved was the last
3398 // one in the link of all of the pBlocks, then we
3399 // need to point the tail to the block just before
3400 // the one we moved.
3401 // Note: if pb->next is NULL, then pb must have
3402 // been the last pBlock in the chain.
3405 pbn->prev = pb->prev;
3407 the_pFile->pbTail = pb->prev;
3418 void pic16_copypCode(FILE *of, char dbName)
3422 if(!of || !the_pFile)
3425 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3426 if(getpBlock_dbName(pb) == dbName) {
3427 // fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3429 pic16_printpBlock(of,pb);
3434 void pic16_pcode_test(void)
3437 DFPRINTF((stderr,"pcode is alive!\n"));
3447 /* create the file name */
3448 strcpy(buffer,dstFileName);
3449 strcat(buffer,".p");
3451 if( !(pFile = fopen(buffer, "w" ))) {
3452 werror(E_FILE_OPEN_ERR,buffer);
3456 fprintf(pFile,"pcode dump\n\n");
3458 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3459 fprintf(pFile,"\n\tNew pBlock\n\n");
3461 fprintf(pFile,"%s",pb->cmemmap->sname);
3463 fprintf(pFile,"internal pblock");
3465 fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3466 pic16_printpBlock(pFile,pb);
3472 unsigned long pic16_countInstructions(void)
3476 unsigned long isize=0;
3478 if(!the_pFile)return -1;
3480 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3481 for(pc = pb->pcHead; pc; pc = pc->next) {
3482 if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3489 /*-----------------------------------------------------------------*/
3490 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg- */
3491 /* ister, RegCond will return the bit being referenced. */
3493 /* fixme - why not just OR in the pcop bit field */
3494 /*-----------------------------------------------------------------*/
3496 static int RegCond(pCodeOp *pcop)
3502 if(!pcop->name)return 0;
3504 if(pcop->type == PO_GPR_BIT && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3505 switch(PCORB(pcop)->bit) {
3520 /*-----------------------------------------------------------------*/
3521 /* pic16_newpCode - create and return a newly initialized pCode */
3523 /* fixme - rename this */
3525 /* The purpose of this routine is to create a new Instruction */
3526 /* pCode. This is called by gen.c while the assembly code is being */
3530 /* PIC_OPCODE op - the assembly instruction we wish to create. */
3531 /* (note that the op is analogous to but not the */
3532 /* same thing as the opcode of the instruction.) */
3533 /* pCdoeOp *pcop - pointer to the operand of the instruction. */
3536 /* a pointer to the new malloc'd pCode is returned. */
3540 /*-----------------------------------------------------------------*/
3541 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3543 pCodeInstruction *pci ;
3545 if(!mnemonics_initialized)
3546 pic16initMnemonics();
3548 pci = Safe_calloc(1, sizeof(pCodeInstruction));
3550 if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3551 memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3554 if(pci->inCond & PCC_EXAMINE_PCOP)
3555 pci->inCond |= RegCond(pcop);
3557 if(pci->outCond & PCC_EXAMINE_PCOP)
3558 pci->outCond |= RegCond(pcop);
3560 pci->pc.prev = pci->pc.next = NULL;
3561 return (pCode *)pci;
3564 fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3570 /*-----------------------------------------------------------------*/
3571 /* pic16_newpCodeWild - create a "wild" as in wild card pCode */
3573 /* Wild pcodes are used during the peep hole optimizer to serve */
3574 /* as place holders for any instruction. When a snippet of code is */
3575 /* compared to a peep hole rule, the wild card opcode will match */
3576 /* any instruction. However, the optional operand and label are */
3577 /* additional qualifiers that must also be matched before the */
3578 /* line (of assembly code) is declared matched. Note that the */
3579 /* operand may be wild too. */
3581 /* Note, a wild instruction is specified just like a wild var: */
3582 /* %4 ; A wild instruction, */
3583 /* See the peeph.def file for additional examples */
3585 /*-----------------------------------------------------------------*/
3587 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3592 pcw = Safe_calloc(1,sizeof(pCodeWild));
3594 pcw->pci.pc.type = PC_WILD;
3595 pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3596 pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3597 pcw->pci.pc.pb = NULL;
3599 // pcw->pci.pc.analyze = genericAnalyze;
3600 pcw->pci.pc.destruct = genericDestruct;
3601 pcw->pci.pc.print = genericPrint;
3603 pcw->id = pCodeID; // this is the 'n' in %n
3604 pcw->operand = optional_operand;
3605 pcw->label = optional_label;
3607 pcw->mustBeBitSkipInst = 0;
3608 pcw->mustNotBeBitSkipInst = 0;
3609 pcw->invertBitSkipInst = 0;
3611 return ( (pCode *)pcw);
3615 /*-----------------------------------------------------------------*/
3616 /* newPcodeInlineP - create a new pCode from a char string */
3617 /*-----------------------------------------------------------------*/
3620 pCode *pic16_newpCodeInlineP(char *cP)
3625 pcc = Safe_calloc(1,sizeof(pCodeComment));
3627 pcc->pc.type = PC_INLINE;
3628 pcc->pc.prev = pcc->pc.next = NULL;
3629 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3632 // pcc->pc.analyze = genericAnalyze;
3633 pcc->pc.destruct = genericDestruct;
3634 pcc->pc.print = genericPrint;
3637 pcc->comment = Safe_strdup(cP);
3639 pcc->comment = NULL;
3641 return ( (pCode *)pcc);
3645 /*-----------------------------------------------------------------*/
3646 /* newPcodeCharP - create a new pCode from a char string */
3647 /*-----------------------------------------------------------------*/
3649 pCode *pic16_newpCodeCharP(char *cP)
3654 pcc = Safe_calloc(1,sizeof(pCodeComment));
3656 pcc->pc.type = PC_COMMENT;
3657 pcc->pc.prev = pcc->pc.next = NULL;
3658 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3661 // pcc->pc.analyze = genericAnalyze;
3662 pcc->pc.destruct = genericDestruct;
3663 pcc->pc.print = genericPrint;
3666 pcc->comment = Safe_strdup(cP);
3668 pcc->comment = NULL;
3670 return ( (pCode *)pcc);
3674 /*-----------------------------------------------------------------*/
3675 /* pic16_newpCodeFunction - */
3676 /*-----------------------------------------------------------------*/
3679 pCode *pic16_newpCodeFunction(char *mod,char *f)
3683 pcf = Safe_calloc(1,sizeof(pCodeFunction));
3685 pcf->pc.type = PC_FUNCTION;
3686 pcf->pc.prev = pcf->pc.next = NULL;
3687 //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3690 // pcf->pc.analyze = genericAnalyze;
3691 pcf->pc.destruct = genericDestruct;
3692 pcf->pc.print = pCodePrintFunction;
3698 pcf->modname = Safe_calloc(1,strlen(mod)+1);
3699 strcpy(pcf->modname,mod);
3701 pcf->modname = NULL;
3704 pcf->fname = Safe_calloc(1,strlen(f)+1);
3705 strcpy(pcf->fname,f);
3709 pcf->stackusage = 0;
3711 return ( (pCode *)pcf);
3714 /*-----------------------------------------------------------------*/
3715 /* pic16_newpCodeFlow */
3716 /*-----------------------------------------------------------------*/
3717 static void destructpCodeFlow(pCode *pc)
3719 if(!pc || !isPCFL(pc))
3726 pic16_unlinkpCode(pc);
3728 deleteSet(&PCFL(pc)->registers);
3729 deleteSet(&PCFL(pc)->from);
3730 deleteSet(&PCFL(pc)->to);
3732 /* Instead of deleting the memory used by this pCode, mark
3733 * the object as bad so that if there's a pointer to this pCode
3734 * dangling around somewhere then (hopefully) when the type is
3735 * checked we'll catch it.
3739 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3745 pCode *pic16_newpCodeFlow(void )
3749 //_ALLOC(pcflow,sizeof(pCodeFlow));
3750 pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3752 pcflow->pc.type = PC_FLOW;
3753 pcflow->pc.prev = pcflow->pc.next = NULL;
3754 pcflow->pc.pb = NULL;
3756 // pcflow->pc.analyze = genericAnalyze;
3757 pcflow->pc.destruct = destructpCodeFlow;
3758 pcflow->pc.print = genericPrint;
3760 pcflow->pc.seq = GpcFlowSeq++;
3762 pcflow->from = pcflow->to = NULL;
3764 pcflow->inCond = PCC_NONE;
3765 pcflow->outCond = PCC_NONE;
3767 pcflow->firstBank = -1;
3768 pcflow->lastBank = -1;
3770 pcflow->FromConflicts = 0;
3771 pcflow->ToConflicts = 0;
3775 pcflow->registers = newSet();
3777 return ( (pCode *)pcflow);
3781 /*-----------------------------------------------------------------*/
3782 /*-----------------------------------------------------------------*/
3783 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3785 pCodeFlowLink *pcflowLink;
3787 pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3789 pcflowLink->pcflow = pcflow;
3790 pcflowLink->bank_conflict = 0;
3795 /*-----------------------------------------------------------------*/
3796 /* pic16_newpCodeCSource - create a new pCode Source Symbol */
3797 /*-----------------------------------------------------------------*/
3799 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3804 pccs = Safe_calloc(1,sizeof(pCodeCSource));
3806 pccs->pc.type = PC_CSOURCE;
3807 pccs->pc.prev = pccs->pc.next = NULL;
3810 pccs->pc.destruct = genericDestruct;
3811 pccs->pc.print = genericPrint;
3813 pccs->line_number = ln;
3815 pccs->line = Safe_strdup(l);
3820 pccs->file_name = Safe_strdup(f);
3822 pccs->file_name = NULL;
3824 return ( (pCode *)pccs);
3829 /*******************************************************************/
3830 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive */
3831 /* added by VR 6-Jun-2003 */
3832 /*******************************************************************/
3834 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3841 pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3842 pcad->pci.pc.type = PC_ASMDIR;
3843 pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3844 pcad->pci.pc.pb = NULL;
3845 pcad->pci.isize = 2;
3846 pcad->pci.pc.destruct = genericDestruct;
3847 pcad->pci.pc.print = genericPrint;
3849 if(asdir && *asdir) {
3851 while(isspace((unsigned char)*asdir))asdir++; // strip any white space from the beginning
3853 pcad->directive = Safe_strdup( asdir );
3856 va_start(ap, argfmt);
3858 memset(buffer, 0, sizeof(buffer));
3859 if(argfmt && *argfmt)
3860 vsprintf(buffer, argfmt, ap);
3864 while(isspace((unsigned char)*lbp))lbp++;
3867 pcad->arg = Safe_strdup( lbp );
3869 return ((pCode *)pcad);
3872 /*-----------------------------------------------------------------*/
3873 /* pCodeLabelDestruct - free memory used by a label. */
3874 /*-----------------------------------------------------------------*/
3875 static void pCodeLabelDestruct(pCode *pc)
3881 // if((pc->type == PC_LABEL) && PCL(pc)->label)
3882 // Safe_free(PCL(pc)->label);
3884 /* Instead of deleting the memory used by this pCode, mark
3885 * the object as bad so that if there's a pointer to this pCode
3886 * dangling around somewhere then (hopefully) when the type is
3887 * checked we'll catch it.
3891 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3897 pCode *pic16_newpCodeLabel(char *name, int key)
3903 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3905 pcl->pc.type = PC_LABEL;
3906 pcl->pc.prev = pcl->pc.next = NULL;
3907 //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3910 // pcl->pc.analyze = genericAnalyze;
3911 pcl->pc.destruct = pCodeLabelDestruct;
3912 pcl->pc.print = pCodePrintLabel;
3919 sprintf(s,"_%05d_DS_",key);
3924 pcl->label = Safe_strdup(s);
3926 // if(pic16_pcode_verbose)
3927 // fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3930 return ( (pCode *)pcl);
3934 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3936 pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3940 return ( (pCode *)pcl );
3943 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3947 pci = Safe_calloc(1, sizeof(pCodeInfo));
3948 pci->pci.pc.type = PC_INFO;
3949 pci->pci.pc.prev = pci->pci.pc.next = NULL;
3950 pci->pci.pc.pb = NULL;
3951 pci->pci.label = NULL;
3953 pci->pci.pc.destruct = genericDestruct;
3954 pci->pci.pc.print = genericPrint;
3959 return ((pCode *)pci);
3963 /*-----------------------------------------------------------------*/
3964 /* newpBlock - create and return a pointer to a new pBlock */
3965 /*-----------------------------------------------------------------*/
3966 static pBlock *newpBlock(void)
3971 PpB = Safe_calloc(1,sizeof(pBlock) );
3972 PpB->next = PpB->prev = NULL;
3974 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3975 PpB->tregisters = NULL;
3977 PpB->FlowTree = NULL;
3983 /*-----------------------------------------------------------------*/
3984 /* pic16_newpCodeChain - create a new chain of pCodes */
3985 /*-----------------------------------------------------------------*
3987 * This function will create a new pBlock and the pointer to the
3988 * pCode that is passed in will be the first pCode in the block.
3989 *-----------------------------------------------------------------*/
3992 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3995 pBlock *pB = newpBlock();
3997 pB->pcHead = pB->pcTail = pc;
4006 /*-----------------------------------------------------------------*/
4007 /* pic16_newpCodeOpLabel - Create a new label given the key */
4008 /* Note, a negative key means that the label is part of wild card */
4009 /* (and hence a wild card label) used in the pCodePeep */
4010 /* optimizations). */
4011 /*-----------------------------------------------------------------*/
4013 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4016 static int label_key=-1;
4020 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4021 pcop->type = PO_LABEL;
4026 sprintf(s=buffer,"_%05d_DS_",key);
4028 s = name, key = label_key--;
4031 pcop->name = Safe_strdup(s);
4033 ((pCodeOpLabel *)pcop)->key = key;
4035 //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4039 /*-----------------------------------------------------------------*/
4040 /*-----------------------------------------------------------------*/
4041 pCodeOp *pic16_newpCodeOpLit(int lit)
4047 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4048 pcop->type = PO_LITERAL;
4052 sprintf(s,"0x%02hhx", (unsigned char)lit);
4054 // sprintf(s, "%i", lit);
4057 pcop->name = Safe_strdup(s);
4059 ((pCodeOpLit *)pcop)->lit = lit;
4064 /* Allow for 12 bit literals, required for LFSR */
4065 pCodeOp *pic16_newpCodeOpLit12(int lit)
4071 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4072 pcop->type = PO_LITERAL;
4076 sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4078 // sprintf(s, "%i", lit);
4081 pcop->name = Safe_strdup(s);
4083 ((pCodeOpLit *)pcop)->lit = lit;
4088 /*-----------------------------------------------------------------*/
4089 /*-----------------------------------------------------------------*/
4090 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4092 char *s = buffer, tbuf[256], *tb=tbuf;
4096 tb = pic16_get_op(arg2, NULL, 0);
4097 pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4098 pcop->type = PO_LITERAL;
4102 sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4104 pcop->name = Safe_strdup(s);
4107 ((pCodeOpLit2 *)pcop)->lit = lit;
4108 ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4113 /*-----------------------------------------------------------------*/
4114 /*-----------------------------------------------------------------*/
4115 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4119 pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4120 pcop->type = PO_IMMEDIATE;
4122 regs *r = pic16_dirregWithName(name);
4123 pcop->name = Safe_strdup(name);
4127 // fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4128 PCOI(pcop)->rIdx = r->rIdx;
4130 // fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4131 PCOI(pcop)->rIdx = -1;
4133 // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4136 PCOI(pcop)->rIdx = -1;
4139 PCOI(pcop)->index = index;
4140 PCOI(pcop)->offset = offset;
4141 PCOI(pcop)->_const = code_space;
4146 /*-----------------------------------------------------------------*/
4147 /*-----------------------------------------------------------------*/
4148 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4154 if(!pcwb || !subtype) {
4155 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4159 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4160 pcop->type = PO_WILD;
4161 sprintf(s,"%%%d",id);
4162 pcop->name = Safe_strdup(s);
4164 PCOW(pcop)->id = id;
4165 PCOW(pcop)->pcwb = pcwb;
4166 PCOW(pcop)->subtype = subtype;
4167 PCOW(pcop)->matched = NULL;
4169 PCOW(pcop)->pcop2 = NULL;
4174 /*-----------------------------------------------------------------*/
4175 /*-----------------------------------------------------------------*/
4176 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4182 if(!pcwb || !subtype || !subtype2) {
4183 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4187 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4188 pcop->type = PO_WILD;
4189 sprintf(s,"%%%d",id);
4190 pcop->name = Safe_strdup(s);
4192 PCOW(pcop)->id = id;
4193 PCOW(pcop)->pcwb = pcwb;
4194 PCOW(pcop)->subtype = subtype;
4195 PCOW(pcop)->matched = NULL;
4197 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4199 if(!subtype2->name) {
4200 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4201 PCOW2(pcop)->pcop.type = PO_WILD;
4202 sprintf(s, "%%%d", id2);
4203 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4204 PCOW2(pcop)->id = id2;
4205 PCOW2(pcop)->subtype = subtype2;
4207 // fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4208 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4210 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4212 // fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4213 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4222 /*-----------------------------------------------------------------*/
4223 /*-----------------------------------------------------------------*/
4224 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4228 pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4229 pcop->type = PO_GPR_BIT;
4231 pcop->name = Safe_strdup(s);
4235 PCORB(pcop)->bit = bit;
4236 PCORB(pcop)->inBitSpace = inBitSpace;
4237 PCORB(pcop)->subtype = subt;
4239 /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4240 PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4241 // fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4242 // PCOR(pcop)->rIdx = 0;
4246 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4248 return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4249 bit, 0, PO_GPR_REGISTER);
4253 /*-----------------------------------------------------------------*
4254 * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4256 * If rIdx >=0 then a specific register from the set of registers
4257 * will be selected. If rIdx <0, then a new register will be searched
4259 *-----------------------------------------------------------------*/
4261 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4266 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4271 r = pic16_regWithIdx(rIdx);
4273 r = pic16_allocWithIdx(rIdx);
4275 r = pic16_findFreeReg(REG_GPR);
4278 fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4279 __FUNCTION__, __LINE__);
4284 PCOR(pcop)->rIdx = rIdx;
4286 pcop->type = PCOR(pcop)->r->pc_type;
4291 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4296 pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4299 r = pic16_findFreeReg(REG_GPR);
4302 if(!bitVectBitValue(bv, r->rIdx)) {
4304 PCOR(pcop)->rIdx = r->rIdx;
4305 pcop->type = r->pc_type;
4309 r = pic16_findFreeRegNext(REG_GPR, r);
4317 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4322 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4323 PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4324 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4325 pcop->type = PCOR(pcop)->r->pc_type;
4326 pcop->name = PCOR(pcop)->r->name;
4328 // if(pic16_pcode_verbose) {
4329 // fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4330 // __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4336 /*-----------------------------------------------------------------*/
4337 /*-----------------------------------------------------------------*/
4338 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4342 pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4345 pcop->key = Safe_strdup( key );
4347 return (PCOP(pcop));
4350 /*-----------------------------------------------------------------*/
4351 /*-----------------------------------------------------------------*/
4352 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4354 pCodeOpLocalReg *pcop;
4356 pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4360 return (PCOP(pcop));
4364 /*-----------------------------------------------------------------*/
4365 /*-----------------------------------------------------------------*/
4367 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4374 pcop = pic16_newpCodeOpBit(name, -1,0, type);
4378 pcop = pic16_newpCodeOpLit(-1);
4382 pcop = pic16_newpCodeOpLabel(NULL,-1);
4385 pcop = pic16_newpCodeOpReg(-1);
4388 case PO_GPR_REGISTER:
4390 pcop = pic16_newpCodeOpRegFromStr(name);
4392 pcop = pic16_newpCodeOpReg(-1);
4396 assert( !"Cannot create PO_TWO_OPS from string!" );
4401 pcop = Safe_calloc(1,sizeof(pCodeOp) );
4404 pcop->name = Safe_strdup(name);
4412 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4414 pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4415 pcop2->pcop.type = PO_TWO_OPS;
4421 /* This is a multiple of two as gpasm pads DB directives to even length,
4422 * thus the data would be interleaved with \0 bytes...
4423 * This is a multiple of three in order to have arrays of 3-byte pointers
4424 * continuously in memory (without 0-padding at the lines' end).
4425 * This is rather 12 than 6 in order not to split up 4-byte data types
4426 * in arrays right in the middle of a 4-byte word. */
4427 #define DB_ITEMS_PER_LINE 12
4429 typedef struct DBdata
4436 static int DBd_init = -1;
4438 /*-----------------------------------------------------------------*/
4439 /* Initialiase "DB" data buffer */
4440 /*-----------------------------------------------------------------*/
4441 void pic16_initDB(void)
4447 /*-----------------------------------------------------------------*/
4448 /* Flush pending "DB" data to a pBlock */
4450 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4451 /*-----------------------------------------------------------------*/
4452 void pic16_flushDB(char ptype, void *p)
4456 pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4459 fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4462 fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4466 DBd.buffer[0] = '\0';
4471 /*-----------------------------------------------------------------*/
4472 /* Add "DB" directives to a pBlock */
4473 /*-----------------------------------------------------------------*/
4474 void pic16_emitDB(int c, char ptype, void *p)
4479 // we need to initialize
4482 DBd.buffer[0] = '\0';
4485 l = strlen(DBd.buffer);
4486 sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4488 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4491 if (DBd.count>= DB_ITEMS_PER_LINE)
4492 pic16_flushDB(ptype, p);
4495 void pic16_emitDS(char *s, char ptype, void *p)
4500 // we need to initialize
4503 DBd.buffer[0] = '\0';
4506 l = strlen(DBd.buffer);
4507 sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4509 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4511 DBd.count++; //=strlen(s);
4512 if (DBd.count>=DB_ITEMS_PER_LINE)
4513 pic16_flushDB(ptype, p);
4517 /*-----------------------------------------------------------------*/
4518 /*-----------------------------------------------------------------*/
4519 void pic16_pCodeConstString(char *name, char *value)
4523 static set *emittedSymbols = NULL;
4528 /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4529 if (emittedSymbols) {
4530 /* scan set for name */
4531 for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4533 if (!strcmp (item,name)) {
4534 //fprintf (stderr, "%s already emitted\n", name);
4539 addSet (&emittedSymbols, Safe_strdup (name));
4541 //fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value);
4543 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4545 pic16_addpBlock(pb);
4547 // sprintf(buffer,"; %s = ", name);
4548 // strcat(buffer, value);
4549 // fputs(buffer, stderr);
4551 // pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4552 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4555 pic16_emitDB(*value, 'p', (void *)pb);
4557 pic16_flushDB('p', (void *)pb);
4560 /*-----------------------------------------------------------------*/
4561 /*-----------------------------------------------------------------*/
4563 static void pCodeReadCodeTable(void)
4567 fprintf(stderr, " %s\n",__FUNCTION__);
4569 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4571 pic16_addpBlock(pb);
4573 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4574 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4575 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4576 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4578 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4579 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4580 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4581 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4586 /*-----------------------------------------------------------------*/
4587 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */
4588 /*-----------------------------------------------------------------*/
4589 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4596 /* If this is the first pcode to be added to a block that
4597 * was initialized with a NULL pcode, then go ahead and
4598 * make this pcode the head and tail */
4599 pb->pcHead = pb->pcTail = pc;
4602 pb->pcTail->next = pc;
4604 pc->prev = pb->pcTail;
4611 /*-----------------------------------------------------------------*/
4612 /* pic16_addpBlock - place a pBlock into the pFile */
4613 /*-----------------------------------------------------------------*/
4614 void pic16_addpBlock(pBlock *pb)
4616 // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4619 /* First time called, we'll pass through here. */
4620 //_ALLOC(the_pFile,sizeof(pFile));
4621 the_pFile = Safe_calloc(1,sizeof(pFile));
4622 the_pFile->pbHead = the_pFile->pbTail = pb;
4623 the_pFile->functions = NULL;
4627 the_pFile->pbTail->next = pb;
4628 pb->prev = the_pFile->pbTail;
4630 the_pFile->pbTail = pb;
4633 /*-----------------------------------------------------------------*/
4634 /* removepBlock - remove a pBlock from the pFile */
4635 /*-----------------------------------------------------------------*/
4636 static void removepBlock(pBlock *pb)
4644 //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4646 for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4649 if(pbs == the_pFile->pbHead)
4650 the_pFile->pbHead = pbs->next;
4652 if (pbs == the_pFile->pbTail)
4653 the_pFile->pbTail = pbs->prev;
4656 pbs->next->prev = pbs->prev;
4659 pbs->prev->next = pbs->next;
4666 fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4670 /*-----------------------------------------------------------------*/
4671 /* printpCode - write the contents of a pCode to a file */
4672 /*-----------------------------------------------------------------*/
4673 static void printpCode(FILE *of, pCode *pc)
4684 fprintf(of,"warning - unable to print pCode\n");
4687 /*-----------------------------------------------------------------*/
4688 /* pic16_printpBlock - write the contents of a pBlock to a file */
4689 /*-----------------------------------------------------------------*/
4690 void pic16_printpBlock(FILE *of, pBlock *pb)
4698 for(pc = pb->pcHead; pc; pc = pc->next) {
4699 if(isPCF(pc) && PCF(pc)->fname) {
4700 fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4701 if(pb->dbName == 'A') {
4703 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4704 // fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4705 if(!strcmp(ab->name, PCF(pc)->fname)) {
4706 // fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4707 if(ab->address != -1)
4708 fprintf(of, "\t0X%06X", ab->address);
4719 /*-----------------------------------------------------------------*/
4721 /* pCode processing */
4725 /*-----------------------------------------------------------------*/
4726 pCode * pic16_findNextInstruction(pCode *pci);
4727 pCode * pic16_findPrevInstruction(pCode *pci);
4729 void pic16_unlinkpCode(pCode *pc)
4735 fprintf(stderr,"Unlinking: ");
4736 printpCode(stderr, pc);
4739 pc->prev->next = pc->next;
4741 pc->next->prev = pc->prev;
4743 /* move C source line down (or up) */
4744 if (isPCI(pc) && PCI(pc)->cline) {
4745 prev = pic16_findNextInstruction (pc->next);
4746 if (prev && isPCI(prev) && !PCI(prev)->cline) {
4747 PCI(prev)->cline = PCI(pc)->cline;
4749 prev = pic16_findPrevInstruction (pc->prev);
4750 if (prev && isPCI(prev) && !PCI(prev)->cline)
4751 PCI(prev)->cline = PCI(pc)->cline;
4754 pc->prev = pc->next = NULL;
4758 /*-----------------------------------------------------------------*/
4759 /*-----------------------------------------------------------------*/
4761 static void genericDestruct(pCode *pc)
4764 pic16_unlinkpCode(pc);
4767 /* For instructions, tell the register (if there's one used)
4768 * that it's no longer needed */
4769 regs *reg = pic16_getRegFromInstruction(pc);
4771 deleteSetItem (&(reg->reglives.usedpCodes),pc);
4773 if(PCI(pc)->is2MemOp) {
4774 reg = pic16_getRegFromInstruction2(pc);
4776 deleteSetItem(&(reg->reglives.usedpCodes), pc);
4780 /* Instead of deleting the memory used by this pCode, mark
4781 * the object as bad so that if there's a pointer to this pCode
4782 * dangling around somewhere then (hopefully) when the type is
4783 * checked we'll catch it.
4787 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4793 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4794 /*-----------------------------------------------------------------*/
4795 /*-----------------------------------------------------------------*/
4796 /* modifiers for constant immediate */
4797 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4799 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4804 int use_buffer = 1; // copy the string to the passed buffer pointer
4809 use_buffer = 0; // Don't bother copying the string to the buffer.
4814 switch(pcop->type) {
4822 SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4825 return (PCOR(pcop)->r->name);
4828 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4830 SAFE_snprintf(&buffer,&size,"%s",r->name);
4837 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4838 if(PCOI(pcop)->index) {
4839 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4840 immdmod[ PCOI(pcop)->offset ],
4844 SAFE_snprintf(&s,&size,"%s(%s)",
4845 immdmod[ PCOI(pcop)->offset ],
4849 if(PCOI(pcop)->index) {
4850 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4855 SAFE_snprintf(&s,&size, "%s(%s)",
4862 case PO_GPR_REGISTER:
4865 // size = sizeof(buffer);
4866 if( PCOR(pcop)->instance) {
4867 SAFE_snprintf(&s,&size,"(%s + %d)",
4869 PCOR(pcop)->instance );
4871 SAFE_snprintf(&s,&size,"%s",pcop->name);
4876 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4877 SAFE_snprintf(&s, &size, "%s", pcop->name);
4879 if(PCORB(pcop)->pcor.instance)
4880 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4882 SAFE_snprintf(&s, &size, "%s", pcop->name);
4887 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4892 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4895 return (pcop->name);
4899 return ("unhandled type for op1");
4902 return ("NO operand1");
4905 /*-----------------------------------------------------------------*/
4906 /* pic16_get_op2 - variant to support two memory operand commands */
4907 /*-----------------------------------------------------------------*/
4908 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4911 if(pcop && pcop->type == PO_TWO_OPS) {
4912 return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4915 return "NO operand2";
4918 /*-----------------------------------------------------------------*/
4919 /*-----------------------------------------------------------------*/
4920 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4924 return pic16_get_op(pcc->pcop,NULL,0);
4926 /* gcc 3.2: warning: concatenation of string literals with __FUNCTION__ is deprecated
4927 * return ("ERROR Null: "__FUNCTION__);
4929 return ("ERROR Null: pic16_get_op_from_instruction");
4933 /*-----------------------------------------------------------------*/
4934 /*-----------------------------------------------------------------*/
4935 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4938 fprintf(of,"pcodeopprint- not implemented\n");
4941 /*-----------------------------------------------------------------*/
4942 /* pic16_pCode2str - convert a pCode instruction to string */
4943 /*-----------------------------------------------------------------*/
4944 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4950 if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4951 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4952 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4953 // exit(EXIT_FAILURE);
4960 SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4962 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4964 //if(PCI(pc)->is2MemOp)
4965 if (PCI(pc)->pcop->type == PO_TWO_OPS)
4967 /* split into two phases due to static buffer in pic16_get_op() */
4968 SAFE_snprintf(&s,&size, "%s",
4969 pic16_get_op((PCI(pc)->pcop), NULL, 0));
4970 SAFE_snprintf(&s, &size, ", %s",
4971 pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4975 if(PCI(pc)->is2LitOp) {
4976 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4980 if(PCI(pc)->isBitInst) {
4981 if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4982 if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4983 SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)",
4984 PCI(pc)->pcop->name ,
4985 PCI(pc)->pcop->name );
4987 SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4988 // (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
4989 (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4991 } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4992 SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
4994 SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
4995 //PCI(pc)->pcop->t.bit );
4998 if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4999 if( PCI(pc)->num_ops == 3)
5000 SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5002 SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5007 SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5010 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5011 if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5012 SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5014 r = pic16_getRegFromInstruction(pc);
5015 // fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5016 // __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?isACCESS_BANK(r):-1);
5018 if(PCI(pc)->isAccess) {
5019 static char *bank_spec[2][2] = {
5020 { "", ", ACCESS" }, /* gpasm uses access bank by default */
5021 { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5024 SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
5033 /* assuming that comment ends with a \n */
5034 SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5038 SAFE_snprintf(&s,&size,"; info ==>");
5039 switch( PCINF(pc)->type ) {
5040 case INF_OPTIMIZATION:
5041 SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5044 SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5049 /* assuming that inline code ends with a \n */
5050 SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5054 SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5057 SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5060 SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5063 SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5066 // SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5067 SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5068 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5071 if(PCAD(pc)->directive) {
5072 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5075 /* special case to handle inline labels without a tab */
5076 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5081 SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5089 /*-----------------------------------------------------------------*/
5090 /* genericPrint - the contents of a pCode to a file */
5091 /*-----------------------------------------------------------------*/
5092 static void genericPrint(FILE *of, pCode *pc)
5100 // fputs(((pCodeComment *)pc)->comment, of);
5101 fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5106 pBranch *pbl = PCI(pc)->label;
5107 while(pbl && pbl->pc) {
5108 if(pbl->pc->type == PC_LABEL)
5109 pCodePrintLabel(of, pbl->pc);
5114 if(pic16_pcode_verbose) {
5115 fprintf(of, "; info ==>");
5116 switch(((pCodeInfo *)pc)->type) {
5117 case INF_OPTIMIZATION:
5118 fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5121 fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5129 fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5133 // If the opcode has a label, print that first
5135 pBranch *pbl = PCI(pc)->label;
5136 while(pbl && pbl->pc) {
5137 if(pbl->pc->type == PC_LABEL)
5138 pCodePrintLabel(of, pbl->pc);
5144 genericPrint(of,PCODE(PCI(pc)->cline));
5149 pic16_pCode2str(str, 256, pc);
5151 fprintf(of,"%s",str);
5153 if(pic16_debug_verbose) {
5154 fprintf(of, "\t;key=%03x",pc->seq);
5156 fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5163 fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5164 if(PCW(pc)->pci.label)
5165 pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5167 if(PCW(pc)->operand) {
5168 fprintf(of,";\toperand ");
5169 pCodeOpPrint(of,PCW(pc)->operand );
5174 if(pic16_debug_verbose) {
5175 fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5176 if(PCFL(pc)->ancestor)
5177 fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5184 // fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5185 fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5186 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5192 pBranch *pbl = PCAD(pc)->pci.label;
5193 while(pbl && pbl->pc) {
5194 if(pbl->pc->type == PC_LABEL)
5195 pCodePrintLabel(of, pbl->pc);
5199 if(PCAD(pc)->directive) {
5200 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5203 /* special case to handle inline labels without tab */
5204 fprintf(of, "%s\n", PCAD(pc)->arg);
5210 fprintf(of,"unknown pCode type %d\n",pc->type);
5215 /*-----------------------------------------------------------------*/
5216 /* pCodePrintFunction - prints function begin/end */
5217 /*-----------------------------------------------------------------*/
5219 static void pCodePrintFunction(FILE *of, pCode *pc)
5226 if( ((pCodeFunction *)pc)->modname)
5227 fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5230 if(!PCF(pc)->absblock) {
5231 if(PCF(pc)->fname) {
5232 pBranch *exits = PCF(pc)->to;
5235 fprintf(of,"%s:", PCF(pc)->fname);
5237 if(pic16_pcode_verbose)
5238 fprintf(of, "\t;Function start");
5244 exits = exits->next;
5248 if(pic16_pcode_verbose)
5249 fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5252 if((PCF(pc)->from &&
5253 PCF(pc)->from->pc->type == PC_FUNCTION &&
5254 PCF(PCF(pc)->from->pc)->fname) ) {
5256 if(pic16_pcode_verbose)
5257 fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5259 if(pic16_pcode_verbose)
5260 fprintf(of,"; exit point [can't find entry point]\n");
5266 /*-----------------------------------------------------------------*/
5267 /* pCodePrintLabel - prints label */
5268 /*-----------------------------------------------------------------*/
5270 static void pCodePrintLabel(FILE *of, pCode *pc)
5277 fprintf(of,"%s:\n",PCL(pc)->label);
5278 else if (PCL(pc)->key >=0)
5279 fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5281 fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5284 /*-----------------------------------------------------------------*/
5285 /* unlinkpCodeFromBranch - Search for a label in a pBranch and */
5286 /* remove it if it is found. */
5287 /*-----------------------------------------------------------------*/
5288 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5295 if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5296 b = PCI(pcl)->label;
5298 fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5303 //fprintf (stderr, "%s \n",__FUNCTION__);
5304 //pcl->print(stderr,pcl);
5305 //pc->print(stderr,pc);
5308 //fprintf (stderr, "found label\n");
5309 //pc->print(stderr, pc);
5313 bprev->next = b->next; /* Not first pCode in chain */
5317 PCI(pcl)->label = b->next; /* First pCode in chain */
5320 return; /* A label can't occur more than once */
5328 /*-----------------------------------------------------------------*/
5329 /*-----------------------------------------------------------------*/
5330 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5349 /*-----------------------------------------------------------------*/
5350 /* pBranchLink - given two pcodes, this function will link them */
5351 /* together through their pBranches */
5352 /*-----------------------------------------------------------------*/
5353 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5357 // Declare a new branch object for the 'from' pCode.
5359 //_ALLOC(b,sizeof(pBranch));
5360 b = Safe_calloc(1,sizeof(pBranch));
5361 b->pc = PCODE(t); // The link to the 'to' pCode.
5364 f->to = pic16_pBranchAppend(f->to,b);
5366 // Now do the same for the 'to' pCode.
5368 //_ALLOC(b,sizeof(pBranch));
5369 b = Safe_calloc(1,sizeof(pBranch));
5373 t->from = pic16_pBranchAppend(t->from,b);
5378 /*-----------------------------------------------------------------*/
5379 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5381 /*-----------------------------------------------------------------*/
5382 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5395 /*-----------------------------------------------------------------*/
5396 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain. */
5397 /*-----------------------------------------------------------------*/
5398 void pic16_pCodeUnlink(pCode *pc)
5403 if(!pc->prev || !pc->next) {
5404 fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5408 /* move C source line down (or up) */
5409 if (isPCI(pc) && PCI(pc)->cline) {
5410 pc1 = pic16_findNextInstruction (pc->next);
5411 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5412 PCI(pc1)->cline = PCI(pc)->cline;
5414 pc1 = pic16_findPrevInstruction (pc->prev);
5415 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5416 PCI(pc1)->cline = PCI(pc)->cline;
5420 /* first remove the pCode from the chain */
5421 pc->prev->next = pc->next;
5422 pc->next->prev = pc->prev;
5424 pc->prev = pc->next = NULL;
5426 /* Now for the hard part... */
5428 /* Remove the branches */
5430 pb1 = PCI(pc)->from;
5432 pc1 = pb1->pc; /* Get the pCode that branches to the
5433 * one we're unlinking */
5435 /* search for the link back to this pCode (the one we're
5437 if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5438 pb2->pc = PCI(pc)->to->pc; // make the replacement
5440 /* if the pCode we're unlinking contains multiple 'to'
5441 * branches (e.g. this a skip instruction) then we need
5442 * to copy these extra branches to the chain. */
5443 if(PCI(pc)->to->next)
5444 pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5453 /*-----------------------------------------------------------------*/
5454 /*-----------------------------------------------------------------*/
5456 static void genericAnalyze(pCode *pc)
5466 // Go through the pCodes that are in pCode chain and link
5467 // them together through the pBranches. Note, the pCodes
5468 // are linked together as a contiguous stream like the
5469 // assembly source code lines. The linking here mimics this
5470 // except that comments are not linked in.
5472 pCode *npc = pc->next;
5474 if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5475 pBranchLink(pc,npc);
5480 /* reached the end of the pcode chain without finding
5481 * an instruction we could link to. */
5485 fprintf(stderr,"analyze PC_FLOW\n");
5489 fprintf(stderr,,";A bad pCode is being used\n");
5495 /*-----------------------------------------------------------------*/
5496 /*-----------------------------------------------------------------*/
5497 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5501 if(pc->type == PC_LABEL) {
5502 if( ((pCodeLabel *)pc)->key == pcop_label->key)
5505 if((pc->type == PC_OPCODE)
5506 || (pc->type == PC_ASMDIR)
5508 pbr = PCI(pc)->label;
5510 if(pbr->pc->type == PC_LABEL) {
5511 if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
5521 /*-----------------------------------------------------------------*/
5522 /*-----------------------------------------------------------------*/
5523 static int checkLabel(pCode *pc)
5527 if(pc && isPCI(pc)) {
5528 pbr = PCI(pc)->label;
5530 if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5540 /*-----------------------------------------------------------------*/
5541 /* findLabelinpBlock - Search the pCode for a particular label */
5542 /*-----------------------------------------------------------------*/
5543 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5550 for(pc = pb->pcHead; pc; pc = pc->next)
5551 if(compareLabel(pc,pcop_label))
5557 /*-----------------------------------------------------------------*/
5558 /* findLabel - Search the pCode for a particular label */
5559 /*-----------------------------------------------------------------*/
5560 static pCode * findLabel(pCodeOpLabel *pcop_label)
5568 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5569 if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5573 fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5577 /*-----------------------------------------------------------------*/
5578 /* pic16_findNextpCode - given a pCode, find the next of type 'pct' */
5579 /* in the linked list */
5580 /*-----------------------------------------------------------------*/
5581 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5594 /*-----------------------------------------------------------------*/
5595 /* findPrevpCode - given a pCode, find the previous of type 'pct' */
5596 /* in the linked list */
5597 /*-----------------------------------------------------------------*/
5598 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5612 //#define PCODE_DEBUG
5613 /*-----------------------------------------------------------------*/
5614 /* pic16_findNextInstruction - given a pCode, find the next instruction */
5615 /* in the linked list */
5616 /*-----------------------------------------------------------------*/
5617 pCode * pic16_findNextInstruction(pCode *pci)
5622 if((pc->type == PC_OPCODE)
5623 || (pc->type == PC_WILD)
5624 || (pc->type == PC_ASMDIR)
5629 fprintf(stderr,"pic16_findNextInstruction: ");
5630 printpCode(stderr, pc);
5635 //fprintf(stderr,"Couldn't find instruction\n");
5639 /*-----------------------------------------------------------------*/
5640 /* pic16_findPrevInstruction - given a pCode, find the next instruction */
5641 /* in the linked list */
5642 /*-----------------------------------------------------------------*/
5643 pCode * pic16_findPrevInstruction(pCode *pci)
5649 if((pc->type == PC_OPCODE)
5650 || (pc->type == PC_WILD)
5651 || (pc->type == PC_ASMDIR)
5657 fprintf(stderr,"pic16_findPrevInstruction: ");
5658 printpCode(stderr, pc);
5663 //fprintf(stderr,"Couldn't find instruction\n");
5670 /*-----------------------------------------------------------------*/
5671 /* findFunctionEnd - given a pCode find the end of the function */
5672 /* that contains it */
5673 /*-----------------------------------------------------------------*/
5674 static pCode * findFunctionEnd(pCode *pc)
5678 if(pc->type == PC_FUNCTION && !(PCF(pc)->fname))
5684 fprintf(stderr,"Couldn't find function end\n");
5689 /*-----------------------------------------------------------------*/
5690 /* AnalyzeLabel - if the pCode is a label, then merge it with the */
5691 /* instruction with which it is associated. */
5692 /*-----------------------------------------------------------------*/
5693 static void AnalyzeLabel(pCode *pc)
5696 pic16_pCodeUnlink(pc);
5702 static void AnalyzeGOTO(pCode *pc)
5705 pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5709 static void AnalyzeSKIP(pCode *pc)
5712 pBranchLink(pc,pic16_findNextInstruction(pc->next));
5713 pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5717 static void AnalyzeRETURN(pCode *pc)
5720 // branch_link(pc,findFunctionEnd(pc->next));
5726 /*-------------------------------------------------------------------*/
5727 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp */
5728 /* if one is present. This is the common */
5729 /* part of pic16_getRegFromInstruction(2) */
5730 /*-------------------------------------------------------------------*/
5732 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5733 if (!pcop) return NULL;
5735 switch(pcop->type) {
5748 return PCOR(pcop)->r;
5750 case PO_SFR_REGISTER:
5751 //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5752 return PCOR(pcop)->r;
5756 // fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5757 return PCOR(pcop)->r;
5760 // return pic16_dirregWithName(PCOI(pcop)->r->name);
5763 return (PCOI(pcop)->r);
5768 return PCOR(pcop)->r;
5770 case PO_GPR_REGISTER:
5772 // fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5773 return PCOR(pcop)->r;
5776 //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5781 //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5786 /* this should never turn up */
5787 //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5794 return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5798 fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5806 /*-----------------------------------------------------------------*/
5807 /*-----------------------------------------------------------------*/
5808 regs * pic16_getRegFromInstruction(pCode *pc)
5813 PCI(pc)->num_ops == 0 ||
5814 (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5818 fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5819 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5822 return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5825 /*-------------------------------------------------------------------------------*/
5826 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5827 /*-------------------------------------------------------------------------------*/
5828 regs * pic16_getRegFromInstruction2(pCode *pc)
5834 PCI(pc)->num_ops == 0 ||
5835 (PCI(pc)->num_ops == 1)) // accept only 2 operand commands
5838 if (PCI(pc)->pcop->type != PO_TWO_OPS)
5842 fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5843 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5846 return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5849 /*-----------------------------------------------------------------*/
5850 /*-----------------------------------------------------------------*/
5852 static void AnalyzepBlock(pBlock *pb)
5859 /* Find all of the registers used in this pBlock
5860 * by looking at each instruction and examining it's
5863 for(pc = pb->pcHead; pc; pc = pc->next) {
5865 /* Is this an instruction with operands? */
5866 if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5868 if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5870 /* Loop through all of the registers declared so far in
5871 this block and see if we find this one there */
5873 regs *r = setFirstItem(pb->tregisters);
5876 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5877 PCOR(PCI(pc)->pcop)->r = r;
5880 r = setNextItem(pb->tregisters);
5884 /* register wasn't found */
5885 //r = Safe_calloc(1, sizeof(regs));
5886 //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5887 //addSet(&pb->tregisters, r);
5888 addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5889 //PCOR(PCI(pc)->pcop)->r = r;
5890 //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5892 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5895 if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5896 if(PCOR(PCI(pc)->pcop)->r) {
5897 pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx); /* FIXME! - VR */
5898 DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5900 if(PCI(pc)->pcop->name)
5901 fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5903 fprintf(stderr,"ERROR: NULL register\n");
5912 /*-----------------------------------------------------------------*/
5914 /*-----------------------------------------------------------------*/
5915 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5917 static void InsertpFlow(pCode *pc, pCode **pflow)
5920 PCFL(*pflow)->end = pc;
5922 if(!pc || !pc->next)
5925 *pflow = pic16_newpCodeFlow();
5926 pic16_pCodeInsertAfter(pc, *pflow);
5929 /*-----------------------------------------------------------------*/
5930 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5931 /* the flow blocks. */
5933 * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5934 * point the instruction flow changes.
5936 /*-----------------------------------------------------------------*/
5937 void pic16_BuildFlow(pBlock *pb)
5940 pCode *last_pci=NULL;
5947 //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq);
5948 /* Insert a pCodeFlow object at the beginning of a pBlock */
5950 InsertpFlow(pb->pcHead, &pflow);
5952 //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */
5953 //pflow->next = pb->pcHead; /* Make the current head the next object */
5954 //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */
5955 //pb->pcHead = pflow; /* Make the Flow object the head */
5958 for( pc = pic16_findNextInstruction(pb->pcHead);
5960 pc=pic16_findNextInstruction(pc)) {
5963 PCI(pc)->pcflow = PCFL(pflow);
5965 //fprintf(stderr," build: ");
5966 //pflow->print(stderr,pflow);
5968 if (checkLabel(pc)) {
5970 /* This instruction marks the beginning of a
5971 * new flow segment */
5976 /* If the previous pCode is not a flow object, then
5977 * insert a new flow object. (This check prevents
5978 * two consecutive flow objects from being insert in
5979 * the case where a skip instruction preceeds an
5980 * instruction containing a label.) */
5982 if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5983 InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5985 PCI(pc)->pcflow = PCFL(pflow);
5989 if( PCI(pc)->isSkip) {
5991 /* The two instructions immediately following this one
5992 * mark the beginning of a new flow segment */
5994 while(pc && PCI(pc)->isSkip) {
5996 PCI(pc)->pcflow = PCFL(pflow);
6000 InsertpFlow(pc, &pflow);
6001 pc=pic16_findNextInstruction(pc->next);
6009 PCI(pc)->pcflow = PCFL(pflow);
6011 InsertpFlow(pc, &pflow);
6013 } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) {
6015 InsertpFlow(pc, &pflow);
6023 //fprintf (stderr,",end seq %d",GpcFlowSeq);
6025 PCFL(pflow)->end = pb->pcTail;
6028 /*-------------------------------------------------------------------*/
6029 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */
6030 /* the flow blocks. */
6032 * unBuildFlow removes pCodeFlow objects from a pCode chain
6034 /*-----------------------------------------------------------------*/
6035 static void unBuildFlow(pBlock *pb)
6050 if(PCI(pc)->pcflow) {
6051 //Safe_free(PCI(pc)->pcflow);
6052 PCI(pc)->pcflow = NULL;
6055 } else if(isPCFL(pc) )
6064 /*-----------------------------------------------------------------*/
6065 /*-----------------------------------------------------------------*/
6066 static void dumpCond(int cond)
6069 static char *pcc_str[] = {
6083 int ncond = sizeof(pcc_str) / sizeof(char *);
6086 fprintf(stderr, "0x%04X\n",cond);
6088 for(i=0,j=1; i<ncond; i++, j<<=1)
6090 fprintf(stderr, " %s\n",pcc_str[i]);
6096 /*-----------------------------------------------------------------*/
6097 /*-----------------------------------------------------------------*/
6098 static void FlowStats(pCodeFlow *pcflow)
6106 fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6108 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6111 fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6116 fprintf(stderr, " FlowStats inCond: ");
6117 dumpCond(pcflow->inCond);
6118 fprintf(stderr, " FlowStats outCond: ");
6119 dumpCond(pcflow->outCond);
6123 /*-----------------------------------------------------------------*
6124 * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6125 * if it affects the banking bits.
6127 * return: -1 == Banking bits are unaffected by this pCode.
6129 * return: > 0 == Banking bits are affected.
6131 * If the banking bits are affected, then the returned value describes
6132 * which bits are affected and how they're affected. The lower half
6133 * of the integer maps to the bits that are affected, the upper half
6134 * to whether they're set or cleared.
6136 *-----------------------------------------------------------------*/
6138 static int isBankInstruction(pCode *pc)
6146 if( PCI(pc)->op == POC_MOVLB ||
6147 (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6148 bank = PCOL(pc)->lit;
6155 /*-----------------------------------------------------------------*/
6156 /*-----------------------------------------------------------------*/
6157 static void FillFlow(pCodeFlow *pcflow)
6166 // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6168 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6171 //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6178 isBankInstruction(pc);
6180 } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6184 fprintf(stderr, " FillFlow - Bad end of flow\n");
6186 fprintf(stderr, " FillFlow - Ending flow with\n ");
6187 pc->print(stderr,pc);
6190 fprintf(stderr, " FillFlow inCond: ");
6191 dumpCond(pcflow->inCond);
6192 fprintf(stderr, " FillFlow outCond: ");
6193 dumpCond(pcflow->outCond);
6197 /*-----------------------------------------------------------------*/
6198 /*-----------------------------------------------------------------*/
6199 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6201 pCodeFlowLink *fromLink, *toLink;
6203 if(!from || !to || !to->pcflow || !from->pcflow)
6206 fromLink = pic16_newpCodeFlowLink(from->pcflow);
6207 toLink = pic16_newpCodeFlowLink(to->pcflow);
6209 addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
6210 addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6214 pCode *pic16_getJumptabpCode (pCode *pc) {
6217 //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6218 //pc->print (stderr, pc);
6221 if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6222 if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6223 switch (PCOO(PCINF(pcinf)->oper1)->type) {
6224 case OPT_JUMPTABLE_BEGIN:
6225 /* leading begin of jump table -- in one */
6226 pcinf = pic16_findPrevInstruction (pcinf);
6230 case OPT_JUMPTABLE_END:
6231 /* leading end of jumptable -- not in one */
6236 /* ignore all other PCInfos */
6240 pcinf = pcinf->prev;
6243 /* no PCInfo found -- not in a jumptable */
6247 /*-----------------------------------------------------------------*
6248 * void LinkFlow(pBlock *pb)
6250 * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6251 * non-branching segments. In LinkFlow, we determine the execution
6252 * order of these segments. For example, if one of the segments ends
6253 * with a skip, then we know that there are two possible flow segments
6254 * to which control may be passed.
6255 *-----------------------------------------------------------------*/
6256 static void LinkFlow(pBlock *pb)
6261 pCode *jumptab_pre = NULL;
6263 //fprintf(stderr,"linkflow \n");
6265 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6267 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6270 fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6272 //fprintf(stderr," link: ");
6273 //pcflow->print(stderr,pcflow);
6275 //FillFlow(PCFL(pcflow));
6277 pc = PCFL(pcflow)->end;
6279 //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6280 if(isPCI_SKIP(pc)) {
6281 // fprintf(stderr, "ends with skip\n");
6282 // pc->print(stderr,pc);
6284 pct=pic16_findNextInstruction(pc->next);
6285 LinkFlow_pCode(PCI(pc),PCI(pct));
6286 pct=pic16_findNextInstruction(pct->next);
6287 LinkFlow_pCode(PCI(pc),PCI(pct));
6291 if(isPCI_BRANCH(pc)) {
6292 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6294 /* handle GOTOs in jumptables */
6295 if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6296 /* link to previous flow */
6297 //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6298 LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6301 switch (PCI(pc)->op) {
6307 /* unconditional branches -- do not link to next instruction */
6308 //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6313 /* unconditional calls -- link to next instruction */
6314 //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6315 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6326 /* conditional branches -- also link to next instruction */
6327 //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6328 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6332 fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6333 assert (0 && "unhandled branching instruction");
6337 //fprintf(stderr, "ends with branch\n ");
6338 //pc->print(stderr,pc);
6340 if(!(pcol && isPCOLAB(pcol))) {
6341 if((PCI(pc)->op != POC_RETLW)
6342 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6344 /* continue if label is '$' which assembler knows how to parse */
6345 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6347 if(pic16_pcode_verbose) {
6348 pc->print(stderr,pc);
6349 fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6355 if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6356 LinkFlow_pCode(PCI(pc),PCI(pct));
6358 fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6359 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6361 // fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6367 //fprintf(stderr, "ends with non-branching instruction:\n");
6368 //pc->print(stderr,pc);
6370 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6376 //fprintf(stderr, "ends with unknown\n");
6377 //pc->print(stderr,pc);
6381 //fprintf(stderr, "ends with nothing: ERROR\n");
6385 /*-----------------------------------------------------------------*/
6386 /*-----------------------------------------------------------------*/
6388 /*-----------------------------------------------------------------*/
6389 /*-----------------------------------------------------------------*/
6390 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6396 if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6399 if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6409 /*-----------------------------------------------------------------*/
6410 /* insertBankSwitch - inserts a bank switch statement in the */
6411 /* assembly listing */
6413 /* position == 0: insert before */
6414 /* position == 1: insert after pc */
6415 /* position == 2: like 0 but previous was a skip instruction */
6416 /*-----------------------------------------------------------------*/
6417 pCodeOp *pic16_popGetLabel(unsigned int key);
6418 extern int pic16_labelOffset;
6420 static void insertBankSwitch(unsigned char position, pCode *pc)
6427 /* emit BANKSEL [symbol] */
6430 new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6432 // position = 0; // position is always before (sanity check!)
6435 fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6436 pc->print(stderr, pc);
6441 /* insert the bank switch after this pc instruction */
6442 pCode *pcnext = pic16_findNextInstruction(pc);
6444 pic16_pCodeInsertAfter(pc, new_pc);
6445 if(pcnext)pc = pcnext;
6449 /* insert the bank switch BEFORE this pc instruction */
6450 pic16_pCodeInsertAfter(pc->prev, new_pc);
6455 pCode *pcnext, *pcprev, *npci, *ppc;
6457 int ofs1=0, ofs2=0, len=0;
6459 /* just like 0, but previous was a skip instruction,
6460 * so some care should be taken */
6462 pic16_labelOffset += 10000;
6463 tlbl = newiTempLabel(NULL);
6465 /* invert skip instruction */
6466 pcprev = pic16_findPrevInstruction(pc->prev);
6467 ipci = PCI(pcprev)->inverted_op;
6468 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6470 // fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6472 /* copy info from old pCode */
6473 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6474 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6475 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6476 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6477 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6478 PCI(npci)->op = PCI(pcprev)->inverted_op;
6480 /* unlink old pCode */
6482 ppc->next = pcprev->next;
6483 pcprev->next->prev = ppc;
6484 pic16_pCodeInsertAfter(ppc, npci);
6486 /* extra instructions to handle invertion */
6487 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6488 pic16_pCodeInsertAfter(npci, pcnext);
6489 pic16_pCodeInsertAfter(pc->prev, new_pc);
6491 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6492 pic16_pCodeInsertAfter(pc, pcnext);
6497 /* Move the label, if there is one */
6498 if(PCI(pc)->label) {
6499 // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6500 // __FILE__, __LINE__, pc, new_pc);
6501 PCAD(new_pc)->pci.label = PCI(pc)->label;
6502 PCI(pc)->label = NULL;
6507 /*-----------------------------------------------------------------*/
6508 /*int compareBankFlow - compare the banking requirements between */
6510 /*-----------------------------------------------------------------*/
6511 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6514 if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6517 if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6520 if(pcflow->firstBank == -1)
6524 if(pcflowLink->pcflow->firstBank == -1) {
6525 pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6526 pcflowLink->pcflow->to :
6527 pcflowLink->pcflow->from);
6528 return compareBankFlow(pcflow, pctl, toORfrom);
6532 if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6535 pcflowLink->bank_conflict++;
6536 pcflowLink->pcflow->FromConflicts++;
6537 pcflow->ToConflicts++;
6540 if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6543 pcflowLink->bank_conflict++;
6544 pcflowLink->pcflow->ToConflicts++;
6545 pcflow->FromConflicts++;
6549 fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6550 pcflowLink->pcflow->pc.seq,
6551 pcflowLink->pcflow->FromConflicts,
6552 pcflowLink->pcflow->ToConflicts);
6559 /*-----------------------------------------------------------------*/
6560 /*-----------------------------------------------------------------*/
6561 static void DumpFlow(pBlock *pb)
6565 pCodeFlowLink *pcfl;
6568 fprintf(stderr,"Dump flow \n");
6569 pb->pcHead->print(stderr, pb->pcHead);
6571 pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6572 pcflow->print(stderr,pcflow);
6574 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6576 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6578 if(!isPCFL(pcflow)) {
6579 fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6582 fprintf(stderr,"dumping: ");
6583 pcflow->print(stderr,pcflow);
6584 FlowStats(PCFL(pcflow));
6586 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6588 pc = PCODE(pcfl->pcflow);
6590 fprintf(stderr, " from seq %d:\n",pc->seq);
6592 fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6593 pc->print(stderr,pc);
6598 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6600 pc = PCODE(pcfl->pcflow);
6602 fprintf(stderr, " to seq %d:\n",pc->seq);
6604 fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6605 pc->print(stderr,pc);
6614 /*-----------------------------------------------------------------*/
6615 /*-----------------------------------------------------------------*/
6616 static int OptimizepBlock(pBlock *pb)
6621 if(!pb || !peepOptimizing)
6624 DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6626 for(pc = pb->pcHead; pc; pc = pc->next)
6627 matches += pic16_pCodePeepMatchRule(pc);
6630 pc = pic16_findNextInstruction(pb->pcHead);
6638 if(pic16_pCodePeepMatchRule(pc)) {
6643 pc = pic16_findNextInstruction(pcprev->next);
6645 pc = pic16_findNextInstruction(pb->pcHead);
6647 pc = pic16_findNextInstruction(pc->next);
6651 DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6656 /*-----------------------------------------------------------------*/
6657 /*-----------------------------------------------------------------*/
6658 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6662 for(pc = pcs; pc; pc = pc->next) {
6664 if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6666 (PCI(pc)->pcop->type == PO_LABEL) &&
6667 (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6675 /*-----------------------------------------------------------------*/
6676 /*-----------------------------------------------------------------*/
6677 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6684 (PCI(pc)->pcop->type == PO_LABEL)) {
6686 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6688 // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6689 // if(pcol->pcop.name)
6690 // Safe_free(pcol->pcop.name);
6692 /* If the key is negative, then we (probably) have a label to
6693 * a function and the name is already defined */
6696 sprintf(s=buffer,"_%05d_DS_",pcl->key);
6700 //sprintf(buffer,"_%05d_DS_",pcl->key);
6702 fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6704 pcol->pcop.name = Safe_strdup(s);
6705 pcol->key = pcl->key;
6706 //pc->print(stderr,pc);
6713 /*-----------------------------------------------------------------*/
6714 /* pBlockRemoveUnusedLabels - remove the pCode labels from the */
6715 /* pCode chain if they're not used. */
6716 /*-----------------------------------------------------------------*/
6717 static void pBlockRemoveUnusedLabels(pBlock *pb)
6719 pCode *pc; pCodeLabel *pcl;
6721 if(!pb || !pb->pcHead)
6724 for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6726 pBranch *pbr = PCI(pc)->label;
6727 if(pbr && pbr->next) {
6728 pCode *pcd = pb->pcHead;
6730 // fprintf(stderr, "multiple labels\n");
6731 // pc->print(stderr,pc);
6736 while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6737 //fprintf(stderr,"Used by:\n");
6738 //pcd->print(stderr,pcd);
6740 exchangeLabels(PCL(pbr->pc),pcd);
6749 for(pc = pb->pcHead; pc; pc = pc->next) {
6751 if(isPCL(pc)) // pc->type == PC_LABEL)
6753 else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6754 pcl = PCL(PCI(pc)->label->pc);
6757 // fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6759 /* This pCode is a label, so search the pBlock to see if anyone
6762 if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6764 //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6765 /* Couldn't find an instruction that refers to this label
6766 * So, unlink the pCode label from it's pCode chain
6767 * and destroy the label */
6768 // fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6770 DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6771 if(pc->type == PC_LABEL) {
6772 pic16_unlinkpCode(pc);
6773 pCodeLabelDestruct(pc);
6775 unlinkpCodeFromBranch(pc, PCODE(pcl));
6776 /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6777 Safe_free(pc->label);
6787 /*-----------------------------------------------------------------*/
6788 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */
6789 /* chain and put them into pBranches that are */
6790 /* associated with the appropriate pCode */
6792 /*-----------------------------------------------------------------*/
6793 void pic16_pBlockMergeLabels(pBlock *pb)
6796 pCode *pc, *pcnext=NULL;
6801 /* First, Try to remove any unused labels */
6802 //pBlockRemoveUnusedLabels(pb);
6804 /* Now loop through the pBlock and merge the labels with the opcodes */
6807 // for(pc = pb->pcHead; pc; pc = pc->next) {
6810 pCode *pcn = pc->next;
6812 if(pc->type == PC_LABEL) {
6814 // fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6815 // fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6817 if((pcnext = pic16_findNextInstruction(pc) )) {
6819 // pcnext->print(stderr, pcnext);
6821 // Unlink the pCode label from it's pCode chain
6822 pic16_unlinkpCode(pc);
6824 // fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6825 // And link it into the instruction's pBranch labels. (Note, since
6826 // it's possible to have multiple labels associated with one instruction
6827 // we must provide a means to accomodate the additional labels. Thus
6828 // the labels are placed into the singly-linked list "label" as
6829 // opposed to being a single member of the pCodeInstruction.)
6831 //_ALLOC(pbr,sizeof(pBranch));
6833 pbr = Safe_calloc(1,sizeof(pBranch));
6837 PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6840 if(pic16_pcode_verbose)
6841 fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6843 } else if(pc->type == PC_CSOURCE) {
6845 /* merge the source line symbolic info into the next instruction */
6846 if((pcnext = pic16_findNextInstruction(pc) )) {
6848 // Unlink the pCode label from it's pCode chain
6849 pic16_unlinkpCode(pc);
6850 PCI(pcnext)->cline = PCCS(pc);
6851 //fprintf(stderr, "merging CSRC\n");
6852 //genericPrint(stderr,pcnext);
6858 pBlockRemoveUnusedLabels(pb);
6862 /*-----------------------------------------------------------------*/
6863 /*-----------------------------------------------------------------*/
6864 static int OptimizepCode(char dbName)
6866 #define MAX_PASSES 4
6875 DFPRINTF((stderr," Optimizing pCode\n"));
6879 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6880 if('*' == dbName || getpBlock_dbName(pb) == dbName)
6881 matches += OptimizepBlock(pb);
6884 while(matches && ++passes < MAX_PASSES);
6891 const char *pic16_pCodeOpType(pCodeOp *pcop);
6892 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6895 /*-----------------------------------------------------------------*/
6896 /* pic16_popCopyGPR2Bit - copy a pcode operator */
6897 /*-----------------------------------------------------------------*/
6899 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6903 // fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6906 pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6908 if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6911 assert(pcop != NULL);
6913 if( !( (pcop->type == PO_LABEL) ||
6914 (pcop->type == PO_LITERAL) ||
6915 (pcop->type == PO_STR) ))
6916 PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */
6917 PCOR(pcop)->r->wasUsed = 1;
6918 PCOR(pcop)->instance = PCOR(pc)->instance;
6924 /*----------------------------------------------------------------------*
6925 * pic16_areRegsSame - check to see if the names of two registers match *
6926 *----------------------------------------------------------------------*/
6927 int pic16_areRegsSame(regs *r1, regs *r2)
6929 if(!strcmp(r1->name, r2->name))return 1;
6935 /*-----------------------------------------------------------------*/
6936 /*-----------------------------------------------------------------*/
6937 static void pic16_FixRegisterBanking(pBlock *pb)
6941 regs *reg, *prevreg;
6942 unsigned char flag=0;
6947 pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6950 /* loop through all of the flow blocks with in one pblock */
6952 // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6956 /* at this point, pc should point to a PC_FLOW object */
6957 /* for each flow block, determine the register banking
6961 /* if label, then might come from other point, force banksel */
6962 if(isPCL(pc))prevreg = NULL;
6964 if(!isPCI(pc))goto loop;
6966 if(PCI(pc)->label)prevreg = NULL;
6968 if(PCI(pc)->is2MemOp)goto loop;
6970 /* if goto, then force banksel */
6971 // if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6973 reg = pic16_getRegFromInstruction(pc);
6976 pc->print(stderr, pc);
6977 fprintf(stderr, "reg = %p\n", reg);
6980 fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6981 fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6982 reg->address,reg->isBitField, reg->isFixed);
6986 /* now make some tests to make sure that instruction needs bank switch */
6988 /* if no register exists, and if not a bit opcode goto loop */
6990 if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6993 if(isPCI_SKIP(pc)) {
6994 // fprintf(stderr, "instruction is SKIP instruction\n");
6997 if(reg && isACCESS_BANK(reg))goto loop;
6999 if(!isBankInstruction(pc))goto loop;
7001 if(isPCI_LIT(pc))goto loop;
7003 if(PCI(pc)->op == POC_CALL)goto loop;
7005 /* Examine the instruction before this one to make sure it is
7006 * not a skip type instruction */
7007 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7009 flag = 0; /* add before this instruction */
7011 /* if previous instruction is a skip one, then set flag
7012 * to 2 and call insertBankSwitch */
7013 if(pcprev && isPCI_SKIP(pcprev)) {
7018 if(pic16_options.opt_banksel>0) {
7019 char op1[128], op2[128];
7022 strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7023 strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7024 if(!strcmp(op1, op2))goto loop;
7028 insertBankSwitch(flag, pc);
7030 // fprintf(stderr, "BANK SWITCH inserted\n");
7038 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7040 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7041 int instrSize (pCode *pc)
7046 if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7047 return 4; // assumes only regular instructions using <= 4 bytes
7050 if (isPCI(pc)) return PCI(pc)->isize;
7055 /* Returns 1 if pc is referenced by the given label (either
7056 * pc is the label itself or is an instruction with an attached
7058 * Returns 0 if pc is not preceeded by the specified label.
7060 int isLabel (pCode *pc, char *label)
7064 // label attached to the pCode?
7065 if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7066 pBranch *lab = NULL;
7067 lab = PCI(pc)->label;
7070 if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7077 // is inline assembly label?
7078 if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7079 // do not compare trailing ':'
7080 if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7087 if (strcmp(PCL(pc)->label,label) == 0) {
7092 // no label/no label attached/wrong label(s)
7096 /* Returns the distance to the given label in terms of words.
7097 * Labels are searched only within -max .. max words from pc.
7098 * Returns max if the label could not be found or
7099 * its distance from pc in (-max..+max).
7101 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7102 int dist = instrSize(pc);
7106 while (dist < max && curr && !isLabel (curr, label)) {
7108 dist += instrSize(curr); // sizeof (instruction)
7110 if (curr && dist < max) {
7111 if (target != NULL) *target = curr;
7116 curr = pic16_findNextInstruction (pc->next);
7118 while (dist < max && curr && !isLabel (curr, label)) {
7119 dist += instrSize(curr); // sizeof (instruction)
7122 if (curr && dist < max) {
7123 if (target != NULL) *target = curr;
7127 if (target != NULL) *target = NULL;
7131 /* Returns -1 if pc does NOT denote an instruction like
7133 * Otherwise we return
7134 * (a) 0x10 + i for BTFSS
7135 * (b) 0x00 + i for BTFSC
7137 int isSkipOnStatus (pCode *pc)
7141 if (!pc || !isPCI(pc)) return -1;
7142 if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7143 else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7146 pcop = PCI(pc)->pcop;
7148 if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7149 return res + ((pCodeOpRegBit *)pcop)->bit;
7155 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7156 * returns 0 otherwise. */
7157 int isConditionalBranch (pCode *pc)
7159 if (!pc || !isPCI_BRANCH(pc)) return 0;
7161 switch (PCI(pc)->op) {
7179 /* Returns 1 if pc has a label attached to it.
7180 * This can be either a label stored in the pCode itself (.label)
7181 * or a label making up its own pCode preceding this pc.
7182 * Returns 0 if pc cannot be reached directly via a label.
7184 int hasNoLabel (pCode *pc)
7189 // are there any label pCodes between pc and the previous instruction?
7190 prev = pic16_findPrevInstruction (pc->prev);
7191 while (pc && pc != prev) {
7192 // pCode with attached label?
7193 if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7194 && PCI(pc)->label) {
7197 // is inline assembly label?
7198 if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7199 if (isPCW(pc) && PCW(pc)->label) return 0;
7202 if (isPCL(pc)) return 0;
7211 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7216 vsprintf (buf, fmt, va);
7219 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7222 /* Replaces the old pCode with the new one, moving the labels,
7223 * C source line and probably flow information to the new pCode.
7225 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7226 if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7229 /* first move all labels from old to new */
7230 PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7231 PCI(oldPC)->label = NULL;
7234 /* move C source line (if possible) */
7235 if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7236 PCI(newPC)->cline = PCI(oldPC)->cline;
7239 /* keep flow information intact */
7240 newPC->seq = oldPC->seq;
7241 PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7242 if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7243 PCI(newPC)->pcflow->end = newPC;
7246 /* insert a comment stating which pCode has been replaced */
7248 if (pic16_pcode_verbose || pic16_debug_verbose) {
7250 pic16_pCode2str (pc_str, 256, oldPC);
7251 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7255 /* insert new pCode into pBlock */
7256 pic16_pCodeInsertAfter (oldPC, newPC);
7257 pic16_unlinkpCode (oldPC);
7259 /* destruct replaced pCode */
7260 oldPC->destruct (oldPC);
7263 /* Returns the inverted conditional branch (if any) or NULL.
7264 * pcop must be set to the new jump target.
7266 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7270 if (!bcc || !isPCI(bcc)) return NULL;
7272 switch (PCI(bcc)->op) {
7273 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7274 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7275 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7276 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7277 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7278 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7279 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7280 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7287 #define MAX_DIST_GOTO 0x7FFFFFFF
7288 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7289 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7290 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7291 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7293 /* Follows GOTO/BRA instructions to their target instructions, stores the
7294 * final destination (not a GOTO or BRA instruction) in target and returns
7295 * the distance from the original pc to *target.
7297 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7300 pCodeOp *lastPCOP = NULL;
7304 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7306 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7307 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7308 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7310 lastPCOP = PCI(curr)->pcop;
7311 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7312 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7315 if (target) *target = last;
7316 if (pcop) *pcop = lastPCOP;
7320 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7321 * Otherwise the first pCode after the jumptable (after
7322 * the OPT_JUMPTABLE_END tag) is returned.
7324 pCode *skipJumptables (pCode *pc, int *isJumptable)
7327 if (!pc) return NULL;
7329 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7331 //fprintf (stderr, "SKIPPING jumptable\n");
7333 //pc->print(stderr, pc);
7335 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7336 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7337 //fprintf (stderr, "<<JUMPTAB:\n");
7338 // skip OPT_END as well
7339 if (pc) pc = pc->next;
7345 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7349 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7350 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7351 pc = skipJumptables (pc, &isJumptab);
7353 // pc is the first pCode after the jumptable
7356 // pc has not been changed by skipJumptables()
7364 /* Turn GOTOs into BRAs if distance between GOTO and label
7365 * is less than 1024 bytes.
7367 * This method is especially useful if GOTOs after BTFS[SC]
7368 * can be turned into BRAs as GOTO would cost another NOP
7371 void pic16_OptimizeJumps ()
7374 pCode *pc_prev = NULL;
7375 pCode *pc_next = NULL;
7378 int change, iteration, isJumptab;
7381 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7383 if (!the_pFile) return;
7385 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7387 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7388 int matchedInvertRule = 1;
7391 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7393 pc = pic16_findNextInstruction (pb->pcHead);
7396 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7398 // skip jumptable, i.e. start over with no pc_prev!
7404 /* (1) resolve chained jumps
7405 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7406 * (a) leave dead code in and
7407 * (b) skip over the dead code with an (unneccessary) jump.
7409 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7410 pCodeOp *lastTargetOp = NULL;
7411 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7412 int maxDist = MAX_DIST_BCC;
7413 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7414 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7416 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7417 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7418 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7419 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7420 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7421 PCI(pc)->pcop->name = lastTargetOp->name;
7430 int condBraType = isSkipOnStatus(pc_prev);
7431 label = PCI(pc)->pcop->name;
7432 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7433 if (dist < 0) dist = -dist;
7434 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7438 /* (2) remove "GOTO label; label:" */
7439 if (isLabel (pc_next, label)) {
7440 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7441 // first remove all preceeding SKIP instructions
7442 while (pc_prev && isPCI_SKIP(pc_prev)) {
7443 // attach labels on this instruction to pc_next
7444 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7445 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7446 PCI(pc_prev)->label = NULL;
7447 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7448 pic16_unlinkpCode (pc_prev);
7449 pc_prev = pic16_findPrevInstruction (pc);
7451 // now remove the redundant goto itself
7452 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7453 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7454 pic16_unlinkpCode (pc);
7455 pc = pic16_findPrevInstruction(pc_next->prev);
7456 isHandled = 1; // do not perform further optimizations
7462 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7463 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7464 if (dist < MAX_DIST_BCC) {
7466 switch (condBraType) {
7467 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7468 // no BDC on DIGIT CARRY available
7469 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7470 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7471 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7472 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7473 // no BNDC on DIGIT CARRY available
7474 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7475 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7476 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7478 // no replacement possible
7483 // ATTENTION: keep labels attached to BTFSx!
7484 // HINT: GOTO is label free (checked above)
7485 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7486 isHandled = 1; // do not perform further optimizations
7487 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7488 pic16_pCodeReplace (pc_prev, bcc);
7495 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7501 // (4) eliminate the following (common) tripel:
7503 // labels1: Bcc label2;
7504 // GOTO somewhere; ; <-- instruction referenced by pc
7506 // and replace it by
7507 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7509 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7510 // to <cont.> instead
7511 // ATTENTION: This optimization is only valid if <pred.> is
7512 // not a skip operation!
7513 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7514 // ATTENTION: no label may be attached to the GOTO instruction!
7515 if (isConditionalBranch(pc_prev)
7516 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7517 && (dist < MAX_DIST_BCC)
7518 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7519 && hasNoLabel(pc)) {
7520 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7523 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7524 isHandled = 1; // do not perform further optimizations
7525 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7526 pic16_pCodeReplace (pc_prev, newBcc);
7531 matchedInvertRule++;
7536 /* (5) now just turn GOTO into BRA */
7537 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7538 if (dist < MAX_DIST_BRA) {
7539 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7540 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7541 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7542 pic16_pCodeReplace (pc, newBra);
7547 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7550 } // if (!isHandled)
7557 pBlockRemoveUnusedLabels (pb);
7559 // This line enables goto chain resolution!
7560 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7563 } while (change); /* fixpoint iteration per pBlock */
7566 // emit some statistics concerning goto-optimization
7568 if (pic16_debug_verbose || pic16_pcode_verbose) {
7569 fprintf (stderr, "optimize-goto:\n"
7570 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7571 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7572 "\t%5d conditional \"skipping\" jumps inverted\n"
7573 "\t%5d GOTOs to next instruction removed\n"
7574 "\t%5d chained GOTOs resolved\n",
7575 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7578 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7582 #undef MAX_JUMPCHAIN_DEPTH
7583 #undef MAX_DIST_GOTO
7587 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7589 static void pBlockDestruct(pBlock *pb)
7600 /*-----------------------------------------------------------------*/
7601 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7602 /* name dbName and combine them */
7603 /* into one block */
7604 /*-----------------------------------------------------------------*/
7605 static void mergepBlocks(char dbName)
7608 pBlock *pb, *pbmerged = NULL,*pbn;
7610 pb = the_pFile->pbHead;
7612 //fprintf(stderr," merging blocks named %c\n",dbName);
7616 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7617 if( getpBlock_dbName(pb) == dbName) {
7619 //fprintf(stderr," merged block %c\n",dbName);
7624 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7625 /* pic16_addpCode2pBlock doesn't handle the tail: */
7626 pbmerged->pcTail = pb->pcTail;
7628 pb->prev->next = pbn;
7630 pbn->prev = pb->prev;
7635 //pic16_printpBlock(stderr, pbmerged);
7642 /*-----------------------------------------------------------------*/
7643 /* AnalyzeFlow - Examine the flow of the code and optimize */
7645 /* level 0 == minimal optimization */
7646 /* optimize registers that are used only by two instructions */
7647 /* level 1 == maximal optimization */
7648 /* optimize by looking at pairs of instructions that use the */
7650 /*-----------------------------------------------------------------*/
7652 static void AnalyzeFlow(int level)
7654 static int times_called=0;
7658 /* remove unused allocated registers before exiting */
7659 pic16_RemoveUnusedRegisters();
7664 /* if this is not the first time this function has been called,
7665 * then clean up old flow information */
7666 if(times_called++) {
7667 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7669 pic16_RegsUnMapLiveRanges();
7673 /* Phase 2 - Flow Analysis - Register Banking
7675 * In this phase, the individual flow blocks are examined
7676 * and register banking is fixed.
7680 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7681 pic16_FixRegisterBanking(pb);
7684 /* Phase 2 - Flow Analysis
7686 * In this phase, the pCode is partition into pCodeFlow
7687 * blocks. The flow blocks mark the points where a continuous
7688 * stream of instructions changes flow (e.g. because of
7689 * a call or goto or whatever).
7692 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7693 pic16_BuildFlow(pb);
7696 /* Phase 2 - Flow Analysis - linking flow blocks
7698 * In this phase, the individual flow blocks are examined
7699 * to determine their order of excution.
7702 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7706 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7707 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7708 pic16_createDF (pb);
7709 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7710 pic16_vcg_dump_default (pb);
7712 //pic16_destructDF (pb);
7716 if (0) releaseStack (); // releasing is costly...
7720 /* Phase 3 - Flow Analysis - Flow Tree
7722 * In this phase, the individual flow blocks are examined
7723 * to determine their order of execution.
7726 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7727 pic16_BuildFlowTree(pb);
7730 /* Phase x - Flow Analysis - Used Banks
7732 * In this phase, the individual flow blocks are examined
7733 * to determine the Register Banks they use
7737 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7742 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7743 pic16_pCodeRegMapLiveRanges(pb);
7745 pic16_RemoveUnusedRegisters();
7746 pic16_removeUnusedRegistersDF ();
7748 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7749 pic16_pCodeRegOptimizeRegUsage(level);
7758 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7763 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7766 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7767 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7768 pcflow = pcflow->next) {
7769 FillFlow(PCFL(pcflow));
7774 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7777 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7778 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7779 pcflow = pcflow->next) {
7780 FlowStats(PCFL(pcflow));
7786 /* VR -- no need to analyze banking in flow, but left here :
7787 * 1. because it may be used in the future for other purposes
7788 * 2. because if omitted we'll miss some optimization done here
7790 * Perhaps I should rename it to something else
7793 /*-----------------------------------------------------------------*/
7794 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7795 /* assigned to the registers. */
7797 /*-----------------------------------------------------------------*/
7799 void pic16_AnalyzeBanking(void)
7803 /* Phase x - Flow Analysis - Used Banks
7805 * In this phase, the individual flow blocks are examined
7806 * to determine the Register Banks they use
7816 if(!the_pFile)return;
7818 if(!pic16_options.no_banksel) {
7819 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7820 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7821 pic16_FixRegisterBanking(pb);
7826 /*-----------------------------------------------------------------*/
7827 /* buildCallTree - Look at the flow and extract all of the calls. */
7828 /*-----------------------------------------------------------------*/
7829 static set *register_usage(pBlock *pb);
7831 static void buildCallTree(void )
7843 /* Now build the call tree.
7844 First we examine all of the pCodes for functions.
7845 Keep in mind that the function boundaries coincide
7846 with pBlock boundaries.
7848 The algorithm goes something like this:
7849 We have two nested loops. The outer loop iterates
7850 through all of the pBlocks/functions. The inner
7851 loop iterates through all of the pCodes for
7852 a given pBlock. When we begin iterating through
7853 a pBlock, the variable pc_fstart, pCode of the start
7854 of a function, is cleared. We then search for pCodes
7855 of type PC_FUNCTION. When one is encountered, we
7856 initialize pc_fstart to this and at the same time
7857 associate a new pBranch object that signifies a
7858 branch entry. If a return is found, then this signifies
7859 a function exit point. We'll link the pCodes of these
7860 returns to the matching pc_fstart.
7862 When we're done, a doubly linked list of pBranches
7863 will exist. The head of this list is stored in
7864 `the_pFile', which is the meta structure for all
7865 of the pCode. Look at the pic16_printCallTree function
7866 on how the pBranches are linked together.
7869 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7870 pCode *pc_fstart=NULL;
7871 for(pc = pb->pcHead; pc; pc = pc->next) {
7873 if(isPCI(pc) && pc_fstart) {
7874 if(PCI(pc)->is2MemOp) {
7875 r = pic16_getRegFromInstruction2(pc);
7876 if(r && !strcmp(r->name, "POSTDEC1"))
7877 PCF(pc_fstart)->stackusage++;
7879 r = pic16_getRegFromInstruction(pc);
7880 if(r && !strcmp(r->name, "PREINC1"))
7881 PCF(pc_fstart)->stackusage--;
7886 if (PCF(pc)->fname) {
7889 sprintf(buf, "%smain", port->fun_prefix);
7890 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7891 //fprintf(stderr," found main \n");
7892 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7896 pbr = Safe_calloc(1,sizeof(pBranch));
7897 pbr->pc = pc_fstart = pc;
7900 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7902 // Here's a better way of doing the same:
7903 addSet(&pb->function_entries, pc);
7906 // Found an exit point in a function, e.g. return
7907 // (Note, there may be more than one return per function)
7909 pBranchLink(PCF(pc_fstart), PCF(pc));
7911 addSet(&pb->function_exits, pc);
7913 } else if(isCALL(pc)) {
7914 addSet(&pb->function_calls,pc);
7921 /* This is not needed because currently all register used
7922 * by a function are stored in stack -- VR */
7924 /* Re-allocate the registers so that there are no collisions
7925 * between local variables when one function call another */
7928 // pic16_deallocateAllRegs();
7930 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7938 /*-----------------------------------------------------------------*/
7939 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7940 /* all of the logical connections. */
7942 /* Essentially what's done here is that the pCode flow is */
7944 /*-----------------------------------------------------------------*/
7946 void pic16_AnalyzepCode(char dbName)
7957 /* Phase 1 - Register allocation and peep hole optimization
7959 * The first part of the analysis is to determine the registers
7960 * that are used in the pCode. Once that is done, the peep rules
7961 * are applied to the code. We continue to loop until no more
7962 * peep rule optimizations are found (or until we exceed the
7963 * MAX_PASSES threshold).
7965 * When done, the required registers will be determined.
7971 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7972 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7974 /* First, merge the labels with the instructions */
7975 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7976 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7978 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7979 //fprintf(stderr," analyze and merging block %c\n",dbName);
7980 pic16_pBlockMergeLabels(pb);
7983 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7988 changes = OptimizepCode(dbName);
7991 } while(changes && (i++ < MAX_PASSES));
7998 /* convert a series of movff's of local regs to stack, with a single call to
7999 * a support functions which does the same thing via loop */
8000 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8004 char *fname[]={"__lr_store", "__lr_restore"};
8006 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8008 pct = pic16_findNextInstruction(pcstart->next);
8011 pct = pc->next; //pic16_findNextInstruction(pc->next);
8012 // pc->print(stderr, pc);
8013 if(isPCI(pc) && PCI(pc)->label) {
8014 pbr = PCI(pc)->label;
8015 while(pbr && pbr->pc) {
8016 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8020 // pc->print(stderr, pc);
8022 pc->prev->next = pct;
8023 pct->prev = pc->prev;
8027 } while ((pc) && (pc != pcend));
8029 /* unlink movff instructions */
8030 pcstart->next = pcend;
8031 pcend->prev = pcstart;
8035 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8036 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8039 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8040 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8041 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8044 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8045 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8052 sym = newSymbol( fname[ entry?0:1 ], 0 );
8053 strcpy(sym->rname, fname[ entry?0:1 ]);
8054 checkAddSym(&externs, sym);
8056 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8061 /*-----------------------------------------------------------------*/
8062 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
8063 /* local registers to a support function call */
8064 /*-----------------------------------------------------------------*/
8065 void pic16_OptimizeLocalRegs(void)
8070 pCodeOpLocalReg *pclr;
8073 regs *r, *lastr=NULL, *firstr=NULL;
8074 pCode *pcstart=NULL, *pcend=NULL;
8079 * local_regs begin mark
8080 * MOVFF r0x01, POSTDEC1
8081 * MOVFF r0x02, POSTDEC1
8084 * MOVFF r0x0n, POSTDEC1
8085 * local_regs end mark
8087 * convert the above to the below:
8088 * MOVLW starting_register_index
8090 * MOVLW register_count
8091 * call __save_registers_in_stack
8097 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8098 inRegCount = regCount = 0;
8099 firstr = lastr = NULL;
8100 for(pc = pb->pcHead; pc; pc = pc->next) {
8102 /* hold current function name */
8103 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8105 if(pc && (pc->type == PC_INFO)) {
8108 if(pci->type == INF_LOCALREGS) {
8109 pclr = PCOLR(pci->oper1);
8111 if((pclr->type == LR_ENTRY_BEGIN)
8112 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8115 switch(pclr->type) {
8116 case LR_ENTRY_BEGIN:
8118 inRegCount = 1; regCount = 0;
8119 pcstart = pc; //pic16_findNextInstruction(pc->next);
8120 firstr = lastr = NULL;
8126 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8129 if(curFunc && inWparamList(curFunc+1)) {
8130 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8134 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8139 firstr = lastr = NULL;
8143 if(inRegCount == -1) {
8144 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8150 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8152 r = pic16_getRegFromInstruction(pc);
8154 r = pic16_getRegFromInstruction2(pc);
8155 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8156 if(!firstr)firstr = r;
8158 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8170 /*-----------------------------------------------------------------*/
8171 /* ispCodeFunction - returns true if *pc is the pCode of a */
8173 /*-----------------------------------------------------------------*/
8174 static bool ispCodeFunction(pCode *pc)
8177 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8183 /*-----------------------------------------------------------------*/
8184 /* findFunction - Search for a function by name (given the name) */
8185 /* in the set of all functions that are in a pBlock */
8186 /* (note - I expect this to change because I'm planning to limit */
8187 /* pBlock's to just one function declaration */
8188 /*-----------------------------------------------------------------*/
8189 static pCode *findFunction(char *fname)
8196 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8198 pc = setFirstItem(pb->function_entries);
8201 if((pc->type == PC_FUNCTION) &&
8203 (strcmp(fname, PCF(pc)->fname)==0))
8206 pc = setNextItem(pb->function_entries);
8214 static void MarkUsedRegisters(set *regset)
8219 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8220 // fprintf(stderr, "marking register = %s\t", r1->name);
8221 r2 = pic16_regWithIdx(r1->rIdx);
8222 // fprintf(stderr, "to register = %s\n", r2->name);
8228 static void pBlockStats(FILE *of, pBlock *pb)
8234 if(!pic16_pcode_verbose)return;
8236 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8238 // for now just print the first element of each set
8239 pc = setFirstItem(pb->function_entries);
8241 fprintf(of,";entry: ");
8244 pc = setFirstItem(pb->function_exits);
8246 fprintf(of,";has an exit\n");
8250 pc = setFirstItem(pb->function_calls);
8252 fprintf(of,";functions called:\n");
8255 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8256 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8258 pc = setNextItem(pb->function_calls);
8262 r = setFirstItem(pb->tregisters);
8264 int n = elementsInSet(pb->tregisters);
8266 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8269 fprintf(of, "; %s\n",r->name);
8270 r = setNextItem(pb->tregisters);
8274 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8277 /*-----------------------------------------------------------------*/
8278 /*-----------------------------------------------------------------*/
8280 static void sequencepCode(void)
8286 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8288 pb->seq = GpCodeSequenceNumber+1;
8290 for( pc = pb->pcHead; pc; pc = pc->next)
8291 pc->seq = ++GpCodeSequenceNumber;
8297 /*-----------------------------------------------------------------*/
8298 /*-----------------------------------------------------------------*/
8299 static set *register_usage(pBlock *pb)
8302 set *registers=NULL;
8303 set *registersInCallPath = NULL;
8305 /* check recursion */
8307 pc = setFirstItem(pb->function_entries);
8314 if(pc->type != PC_FUNCTION)
8315 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8317 pc = setFirstItem(pb->function_calls);
8318 for( ; pc; pc = setNextItem(pb->function_calls)) {
8320 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8321 char *dest = pic16_get_op_from_instruction(PCI(pc));
8323 pcn = findFunction(dest);
8325 registersInCallPath = register_usage(pcn->pb);
8327 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8332 pBlockStats(stderr,pb); // debug
8335 // Mark the registers in this block as used.
8337 MarkUsedRegisters(pb->tregisters);
8338 if(registersInCallPath) {
8339 /* registers were used in the functions this pBlock has called */
8340 /* so now, we need to see if these collide with the ones we are */
8343 regs *r1,*r2, *newreg;
8345 DFPRINTF((stderr,"comparing registers\n"));
8347 r1 = setFirstItem(registersInCallPath);
8350 r2 = setFirstItem(pb->tregisters);
8352 while(r2 && (r1->type != REG_STK)) {
8354 if(r2->rIdx == r1->rIdx) {
8355 newreg = pic16_findFreeReg(REG_GPR);
8359 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8363 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8364 r1->rIdx, newreg->rIdx));
8365 r2->rIdx = newreg->rIdx;
8366 //if(r2->name) Safe_free(r2->name);
8368 r2->name = Safe_strdup(newreg->name);
8372 newreg->wasUsed = 1;
8374 r2 = setNextItem(pb->tregisters);
8377 r1 = setNextItem(registersInCallPath);
8380 /* Collisions have been resolved. Now free the registers in the call path */
8381 r1 = setFirstItem(registersInCallPath);
8383 if(r1->type != REG_STK) {
8384 newreg = pic16_regWithIdx(r1->rIdx);
8387 r1 = setNextItem(registersInCallPath);
8391 // MarkUsedRegisters(pb->registers);
8393 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8396 DFPRINTF((stderr,"returning regs\n"));
8398 DFPRINTF((stderr,"not returning regs\n"));
8400 DFPRINTF((stderr,"pBlock after register optim.\n"));
8401 pBlockStats(stderr,pb); // debug
8407 /*-----------------------------------------------------------------*/
8408 /* pct2 - writes the call tree to a file */
8410 /*-----------------------------------------------------------------*/
8411 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8415 // set *registersInCallPath = NULL;
8421 fprintf(of, "recursive function\n");
8422 return; //recursion ?
8425 pc = setFirstItem(pb->function_entries);
8432 for(i=0;i<indent;i++) // Indentation
8436 if(pc->type == PC_FUNCTION) {
8437 usedstack += PCF(pc)->stackusage;
8438 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8439 } else return; // ???
8442 pc = setFirstItem(pb->function_calls);
8443 for( ; pc; pc = setNextItem(pb->function_calls)) {
8445 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8446 char *dest = pic16_get_op_from_instruction(PCI(pc));
8448 pcn = findFunction(dest);
8450 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8452 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8460 /*-----------------------------------------------------------------*/
8461 /* pic16_printCallTree - writes the call tree to a file */
8463 /*-----------------------------------------------------------------*/
8465 void pic16_printCallTree(FILE *of)
8477 fprintf(of, "\npBlock statistics\n");
8478 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8482 fprintf(of,"Call Tree\n");
8483 pbr = the_pFile->functions;
8487 if(!ispCodeFunction(pc))
8488 fprintf(of,"bug in call tree");
8491 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8493 while(pc->next && !ispCodeFunction(pc->next)) {
8495 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8496 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8504 fprintf(of,"\n**************\n\na better call tree\n");
8505 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8510 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8511 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8517 /*-----------------------------------------------------------------*/
8519 /*-----------------------------------------------------------------*/
8521 static void InlineFunction(pBlock *pb)
8529 pc = setFirstItem(pb->function_calls);
8531 for( ; pc; pc = setNextItem(pb->function_calls)) {
8534 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8540 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8542 //fprintf(stderr,"Cool can inline:\n");
8543 //pcn->print(stderr,pcn);
8545 //fprintf(stderr,"recursive call Inline\n");
8546 InlineFunction(pcn->pb);
8547 //fprintf(stderr,"return from recursive call Inline\n");
8550 At this point, *pc points to a CALL mnemonic, and
8551 *pcn points to the function that is being called.
8553 To in-line this call, we need to remove the CALL
8554 and RETURN(s), and link the function pCode in with
8560 /* Remove the CALL */
8564 /* remove callee pBlock from the pBlock linked list */
8565 removepBlock(pcn->pb);
8573 /* Remove the Function pCode */
8574 pct = pic16_findNextInstruction(pcn->next);
8576 /* Link the function with the callee */
8577 pc->next = pcn->next;
8578 pcn->next->prev = pc;
8580 /* Convert the function name into a label */
8582 pbr = Safe_calloc(1,sizeof(pBranch));
8583 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8585 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8586 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8588 /* turn all of the return's except the last into goto's */
8589 /* check case for 2 instruction pBlocks */
8590 pce = pic16_findNextInstruction(pcn->next);
8592 pCode *pce_next = pic16_findNextInstruction(pce->next);
8594 if(pce_next == NULL) {
8595 /* found the last return */
8596 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8598 //fprintf(stderr,"found last return\n");
8599 //pce->print(stderr,pce);
8600 pce->prev->next = pc_call->next;
8601 pc_call->next->prev = pce->prev;
8602 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8612 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8618 /*-----------------------------------------------------------------*/
8620 /*-----------------------------------------------------------------*/
8622 void pic16_InlinepCode(void)
8631 if(!functionInlining)
8634 /* Loop through all of the function definitions and count the
8635 * number of times each one is called */
8636 //fprintf(stderr,"inlining %d\n",__LINE__);
8638 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8640 pc = setFirstItem(pb->function_calls);
8642 for( ; pc; pc = setNextItem(pb->function_calls)) {
8645 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8646 if(pcn && isPCF(pcn)) {
8647 PCF(pcn)->ncalled++;
8650 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8655 //fprintf(stderr,"inlining %d\n",__LINE__);
8657 /* Now, Loop through the function definitions again, but this
8658 * time inline those functions that have only been called once. */
8660 InlineFunction(the_pFile->pbHead);
8661 //fprintf(stderr,"inlining %d\n",__LINE__);
8663 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8668 char *pic_optype_names[]={
8669 "PO_NONE", // No operand e.g. NOP
8670 "PO_W", // The working register (as a destination)
8671 "PO_WREG", // The working register (as a file register)
8672 "PO_STATUS", // The 'STATUS' register
8673 "PO_BSR", // The 'BSR' register
8674 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8676 "PO_INDF0", // The Indirect register
8677 "PO_INTCON", // Interrupt Control register
8678 "PO_GPR_REGISTER", // A general purpose register
8679 "PO_GPR_BIT", // A bit of a general purpose register
8680 "PO_GPR_TEMP", // A general purpose temporary register
8681 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8682 "PO_PCL", // Program counter Low register
8683 "PO_PCLATH", // Program counter Latch high register
8684 "PO_PCLATU", // Program counter Latch upper register
8685 "PO_PRODL", // Product Register Low
8686 "PO_PRODH", // Product Register High
8687 "PO_LITERAL", // A constant
8688 "PO_REL_ADDR", // A relative address
8689 "PO_IMMEDIATE", // (8051 legacy)
8690 "PO_DIR", // Direct memory (8051 legacy)
8691 "PO_CRY", // bit memory (8051 legacy)
8692 "PO_BIT", // bit operand.
8693 "PO_STR", // (8051 legacy)
8695 "PO_WILD", // Wild card operand in peep optimizer
8696 "PO_TWO_OPS" // combine two operands
8700 char *dumpPicOptype(PIC_OPTYPE type)
8702 assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8703 return (pic_optype_names[ type ]);
8707 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8710 #define MAX_COMMON_BANK_SIZE 32
8711 #define FIRST_PSEUDO_BANK_NR 1000
8713 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8714 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8715 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8718 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8721 pseudoBankNr bank; // number assigned to this pseudoBank
8722 unsigned int size; // number of operands assigned to this bank
8723 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8726 /*----------------------------------------------------------------------*/
8727 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8728 /*----------------------------------------------------------------------*/
8729 unsigned int hashSymbol (const char *str)
8731 unsigned int res = 0;
8736 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8743 /*-----------------------------------------------------------------------*/
8744 /* compareSymbol - return 1 iff sym1 equals sym2 */
8745 /*-----------------------------------------------------------------------*/
8746 int compareSymbol (const void *sym1, const void *sym2)
8748 char *s1 = (char*) sym1;
8749 char *s2 = (char*) sym2;
8751 return (strcmp (s1,s2) == 0);
8754 /*-----------------------------------------------------------------------*/
8755 /* comparePre - return 1 iff p1 == p2 */
8756 /*-----------------------------------------------------------------------*/
8757 int comparePtr (const void *p1, const void *p2)
8762 /*----------------------------------------------------------*/
8763 /* getSymbolFromOperand - return a pointer to the symbol in */
8764 /* the given operand and its length */
8765 /*----------------------------------------------------------*/
8766 char *getSymbolFromOperand (char *op, int *len)
8771 if (!op) return NULL;
8773 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8775 if (*sym == '(') sym++;
8778 while (((*curr >= 'A') && (*curr <= 'Z'))
8779 || ((*curr >= 'a') && (*curr <= 'z'))
8780 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8781 || (*curr == '_')) {
8782 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8790 /*--------------------------------------------------------------------------*/
8791 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8792 /*--------------------------------------------------------------------------*/
8793 char *getSymFromBank (pseudoBankNr bank)
8797 if (bank < 0) return "<INVALID BANK NR>";
8798 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8801 /*-----------------------------------------------------------------------*/
8802 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8803 /* bank number (uses hTab sym2bank), if the */
8804 /* symbol is not yet assigned a pseudo bank it */
8805 /* is assigned one here */
8806 /*-----------------------------------------------------------------------*/
8807 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8809 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8815 hash = hashSymbol (op) % sym2bank->size;
8816 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8817 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8819 if (bank == UNKNOWN_BANK) {
8820 // create a pseudo bank for the operand
8822 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8823 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8824 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8825 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8827 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8835 /*--------------------------------------------------------------------*/
8836 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8837 /*--------------------------------------------------------------------*/
8838 int isBanksel (pCode *pc)
8842 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8843 // BANKSEL <variablename> or MOVLB <banknr>
8844 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8848 // check for inline assembler BANKSELs
8849 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8850 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8851 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8855 // assume pc is no BANKSEL instruction
8859 /*---------------------------------------------------------------------------------*/
8860 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8861 /* This method can not guarantee to find all modifications of the */
8862 /* BSR (e.g. via INDirection registers) but covers all compiler */
8863 /* generated plus some cases. */
8864 /*---------------------------------------------------------------------------------*/
8865 int invalidatesBSR(pCode *pc)
8867 // assembler directives invalidate BSR (well, they might, we don't know)
8868 if (isPCAD(pc)) return 1;
8870 // only ASMDIRs and pCodeInstructions can invalidate BSR
8871 if (!isPCI(pc)) return 0;
8873 // we have a pCodeInstruction
8875 // check for BSR modifying instructions
8876 switch (PCI(pc)->op) {
8880 case POC_RETFIE: // might be used as CALL replacement
8881 case POC_RETLW: // might be used as CALL replacement
8882 case POC_RETURN: // might be used as CALL replacement
8887 default: // other instruction do not change BSR unless BSR is an explicit operand!
8888 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8892 // no change of BSR possible/probable
8896 /*------------------------------------------------------------*/
8897 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8898 /* the symbol referenced in this BANKSEL */
8899 /*------------------------------------------------------------*/
8900 pseudoBankNr getBankFromBanksel (pCode *pc)
8905 if (!pc) return INVALID_BANK;
8907 if (isPCAD(pc) && PCAD(pc)->directive) {
8908 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8909 // get symbolname from PCAD(pc)->arg
8910 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8911 sym = PCAD(pc)->arg;
8912 data = getPseudoBankNrFromOperand (sym);
8913 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8914 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8915 // get (literal) bank number from PCAD(pc)->arg
8916 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8917 assert (0 && "not yet implemented - turn off banksel optimization for now");
8919 } else if (isPCI(pc)) {
8920 if (PCI(pc)->op == POC_BANKSEL) {
8921 // get symbolname from PCI(pc)->pcop->name (?)
8922 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8923 sym = PCI(pc)->pcop->name;
8924 data = getPseudoBankNrFromOperand (sym);
8925 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8926 } else if (PCI(pc)->op == POC_MOVLB) {
8927 // get (literal) bank number from PCI(pc)->pcop->name
8928 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8929 assert (0 && "not yet implemented - turn off banksel optimization for now");
8934 // no assigned bank could be found
8935 return UNKNOWN_BANK;
8940 /*------------------------------------------------------------------------------*/
8941 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8942 /*------------------------------------------------------------------------------*/
8943 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8947 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8950 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8951 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8953 if (data->bank != bank)
8960 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8964 /*------------------------------------------------------------------*/
8965 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8966 /* bank is selected at a given pCode */
8967 /*------------------------------------------------------------------*/
8969 /* Create a graph with pseudo banks as its nodes and switches between
8970 * these as edges (with the edge weight representing the absolute
8971 * number of BANKSELs from one to the other).
8972 * Removes redundand BANKSELs instead iff mod == 1.
8973 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8974 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8976 * TODO: check ALL instructions operands if they modify BSR directly...
8978 * pb - the pBlock to annotate
8979 * mod - select either graph creation (0) or BANKSEL removal (1)
8981 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8983 pCode *pc, *pc_next;
8984 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8985 int isBankselect = 0;
8986 unsigned int banksels=0;
8990 pc = pic16_findNextInstruction(pb->pcHead);
8992 isBankselect = isBanksel (pc);
8993 pc_next = pic16_findNextInstruction (pc->next);
8995 if (!hasNoLabel (pc)) {
8996 // we don't know our predecessors -- assume different BSRs
8997 prevBSR = UNKNOWN_BANK;
8998 pseudoBSR = UNKNOWN_BANK;
8999 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9002 // check if this is a BANKSEL instruction
9004 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9005 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9007 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9008 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9009 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9010 pic16_unlinkpCode (pc);
9014 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9019 if (!isBankselect && invalidatesBSR(pc)) {
9020 // check if this instruction invalidates the pseudoBSR
9021 pseudoBSR = UNKNOWN_BANK;
9022 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9025 prevBSR = pseudoBSR;
9032 /*------------------------------------------------------------------------------------*/
9033 /* assignToSameBank - returns 0 on success or an error code */
9034 /* 1 - common bank would be too large */
9035 /* 2 - assignment to fixed (absolute) bank not performed */
9037 /* This functions assumes that unsplittable operands are already assigned to the same */
9038 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
9039 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
9040 /* TODO: Symbols with an abslute address must be handled specially! */
9041 /*------------------------------------------------------------------------------------*/
9042 int assignToSameBank (int bank0, int bank1, int doAbs)
9044 int eff0, eff1, dummy;
9045 pseudoBank *pbank0, *pbank1;
9048 eff0 = getEffectiveBank (bank0);
9049 eff1 = getEffectiveBank (bank1);
9051 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9053 // nothing to do if already same bank
9054 if (eff0 == eff1) return 0;
9056 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9059 // ensure eff0 < eff1
9061 // swap eff0 and eff1
9070 // now assign bank eff1 to bank eff0
9071 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9073 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9074 pbank0->bank = eff0;
9077 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9081 hitem = hTabSearch (coerce, eff1 % coerce->size);
9082 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9083 hitem = hitem->next;
9085 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9088 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9089 pbank0->bank, pbank0->size,
9090 getSymFromBank (eff0), getSymFromBank (eff1));
9094 if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9096 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9097 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9098 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9099 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9103 pbank0->size += pbank1->size;
9105 if (pbank1->ref == 0) Safe_free (pbank1);
9111 hitem->item = pbank0;
9113 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9116 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9121 /*----------------------------------------------------------------*/
9122 /* mergeGraphNodes - combines two nodes into one and modifies all */
9123 /* edges to and from the nodes accordingly */
9124 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9125 /* then also (B,A) must be an edge (possibly with weight 0). */
9126 /*----------------------------------------------------------------*/
9127 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9129 GraphEdge *edge, *backedge, *nextedge;
9133 assert (node1 && node2);
9134 assert (node1 != node2);
9136 // add all edges starting at node2 to node1
9139 nextedge = edge->next;
9141 backedge = getGEdge (node, node2);
9143 backweight = backedge->weight;
9146 // insert edges (node1,node) and (node,node1)
9147 addGEdge2 (node1, node, edge->weight, backweight);
9148 // remove edges (node, node2) and (node2, node)
9149 remGEdge (node2, node);
9150 remGEdge (node, node2);
9154 // now node2 should not be referenced by any other GraphNode...
9155 //remGNode (adj, node2->data, node2->hash);
9158 /*----------------------------------------------------------------*/
9159 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9160 /*----------------------------------------------------------------*/
9161 void showGraph (Graph *g)
9165 pseudoBankNr bankNr;
9172 bankNr = getEffectiveBank (node->hash);
9173 assert (bankNr >= 0);
9174 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9176 bankNr = pbank->bank;
9182 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9185 if (edge->weight > 0)
9186 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9193 /*---------------------------------------------------------------*/
9194 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9195 /*---------------------------------------------------------------*/
9196 void pic16_OptimizeBanksel ()
9198 GraphNode *node, *node1, *node1next;
9201 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9202 GraphEdge *edge, *backedge;
9204 int maxWeight, weight, mergeMore, absMaxWeight;
9205 pseudoBankNr curr0, curr1;
9208 pseudoBankNr bankNr;
9209 char *base_symbol0, *base_symbol1;
9214 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9216 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9218 if (!the_pFile || !the_pFile->pbHead) return;
9220 adj = newGraph (NULL);
9221 sym2bank = newHashTable ( 255 );
9222 bank2sym = newHashTable ( 255 );
9223 coerce = newHashTable ( 255 );
9225 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9226 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9227 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9231 // assign symbols with absolute addresses to their respective bank nrs
9232 set = pic16_fix_udata;
9233 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9234 bankNr = reg->address >> 8;
9235 node = getOrAddGNode (adj, NULL, bankNr);
9236 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9237 assignToSameBank (node->hash, bankNr, 1);
9239 assert (bankNr >= 0);
9240 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9242 pbank = Safe_calloc (1, sizeof (pseudoBank));
9243 pbank->bank = reg->address >> 8; //FIXED_BANK;
9246 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9248 assert (pbank->bank == (reg->address >> 8));
9249 pbank->bank = reg->address >> 8; //FIXED_BANK;
9251 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9256 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9257 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9260 if (node->hash < 0) { node = node->next; continue; }
9261 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9264 if (node1->hash < 0) { node1 = node1->next; continue; }
9265 node1next = node1->next;
9266 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9267 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9268 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9269 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9270 if (assignToSameBank (node->hash, node1->hash, 0)) {
9271 fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9272 assert (0 && "Could not assign a symbol to a bank!");
9274 mergeGraphNodes (node, node1);
9276 if (node->hash < node1->hash)
9277 mergeGraphNodes (node, node1);
9279 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9289 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9290 // assign tightly coupled operands to the same (pseudo) bank
9291 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9299 curr0 = getEffectiveBank (node->hash);
9300 if (curr0 < 0) { node = node->next; continue; }
9303 assert (edge->src == node);
9304 backedge = getGEdge (edge->node, edge->src);
9305 weight = edge->weight + (backedge ? backedge->weight : 0);
9306 curr1 = getEffectiveBank (edge->node->hash);
9307 if (curr1 < 0) { edge = edge->next; continue; }
9309 // merging is only useful if the items are not assigned to the same bank already...
9310 if (curr0 != curr1 && weight > maxWeight) {
9311 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9320 if (maxWeight > 0) {
9322 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9323 max->src->hash, getSymFromBank (max->src->hash),
9324 max->node->hash, getSymFromBank (max->node->hash));
9327 node = getGNode (adj, max->src->data, max->src->hash);
9328 node1 = getGNode (adj, max->node->data, max->node->hash);
9330 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9331 if (max->src->hash < max->node->hash)
9332 mergeGraphNodes (node, node1);
9334 mergeGraphNodes (node1, node);
9336 remGEdge (node, node1);
9337 remGEdge (node1, node);
9348 // remove redundant BANKSELs
9349 //fprintf (stderr, "removing redundant BANKSELs\n");
9350 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9351 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9356 fprintf (stderr, "display graph\n");
9361 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9364 /*** END of stuff belonging to the BANKSEL optimization ***/
9368 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9370 typedef unsigned int symbol_t;
9371 typedef unsigned int valnum_t;
9372 //typedef unsigned int hash_t;
9375 #define INT_TO_PTR(x) (((char *) 0) + (x))
9379 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9382 static int pic16_regIsLocal (regs *r);
9383 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9386 static unsigned int pic16_df_removed_pcodes = 0;
9387 static unsigned int pic16_df_saved_bytes = 0;
9388 static unsigned int df_findall_sameflow = 0;
9389 static unsigned int df_findall_otherflow = 0;
9390 static unsigned int df_findall_in_vals = 0;
9392 static void pic16_df_stats () {
9394 if (pic16_debug_verbose || pic16_pcode_verbose) {
9395 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9396 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9397 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9401 /* Remove a pCode iff possible:
9402 * - previous pCode is no SKIP
9404 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9405 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9406 pCode *pcprev, *pcnext;
9407 char buf[256], *total=NULL;
9410 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9412 pcprev = pic16_findPrevInstruction (pc->prev);
9413 pcnext = pic16_findNextInstruction (pc->next);
9415 /* move labels to next instruction (if possible) */
9416 if (PCI(pc)->label && !pcnext) return 0;
9418 /* if this is a SKIP with side-effects -- do not remove */
9419 /* XXX: might try to replace this one with the side-effect only version */
9421 && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9424 switch (PCI(pc)->op)
9428 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9429 pic16_pCodeReplace( pc, newpc );
9433 newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9434 pic16_pCodeReplace( pc, newpc );
9439 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9440 pic16_pCodeReplace( pc, newpc );
9444 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9445 pic16_pCodeReplace( pc, newpc );
9454 /* if previous instruction is a skip -- do not remove */
9455 if (pcprev && isPCI_SKIP(pcprev)) {
9456 if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9457 /* preceeding SKIP could not be removed -- keep this instruction! */
9462 if (PCI(pc)->label) {
9463 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9464 //pc->print (stderr, pc);
9465 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9466 PCI(pc)->label = NULL;
9469 /* update statistics */
9470 pic16_df_removed_pcodes++;
9471 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9473 /* remove the pCode */
9474 pic16_pCode2str (buf, 256, pc);
9475 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9476 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9477 len = strlen (buf) + strlen (comment) + 10;
9478 total = (char *) Safe_malloc (len);
9479 SNPRINTF (total, len, "%s: %s", comment, buf);
9480 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9484 /* actually unlink it from the pBlock -- also remove from to/from lists */
9485 pic16_pCodeUnlink (pc);
9487 /* remove the pCode -- release registers */
9490 /* report success */
9495 /* ======================================================================== */
9496 /* === SYMBOL HANDLING ==================================================== */
9497 /* ======================================================================== */
9499 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9500 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9501 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9503 /** Calculate a hash for a given string.
9504 * If len == 0 the string is assumed to be NUL terminated. */
9505 static hash_t symbolHash (const char *str, unsigned int len) {
9509 hash = (hash << 2) ^ *str;
9514 hash = (hash << 2) ^ *str;
9521 /** Return 1 iff strings v1 and v2 are identical. */
9522 static int symcmp (const void *v1, const void *v2) {
9523 return !strcmp ((const char *) v1, (const char *) v2);
9526 /** Return 1 iff pointers v1 and v2 are identical. */
9527 static int ptrcmp (const void *v1, const void *v2) {
9531 enum { SPO_WREG=0x1000,
9571 /* Return the unique symbol_t for the given string. */
9572 static symbol_t symFromStr (const char *str) {
9577 if (!map_symToStr) {
9579 struct { char *name; symbol_t sym; } predefsyms[] = {
9581 {"STATUS", SPO_STATUS},
9582 {"PRODL", SPO_PRODL},
9583 {"PRODH", SPO_PRODH},
9584 {"INDF0", SPO_INDF0},
9585 {"POSTDEC0", SPO_POSTDEC0},
9586 {"POSTINC0", SPO_POSTINC0},
9587 {"PREINC0", SPO_PREINC0},
9588 {"PLUSW0", SPO_PLUSW0},
9589 {"INDF1", SPO_INDF1},
9590 {"POSTDEC1", SPO_POSTDEC1},
9591 {"POSTINC1", SPO_POSTINC1},
9592 {"PREINC1", SPO_PREINC1},
9593 {"PLUSW1", SPO_PLUSW1},
9594 {"INDF2", SPO_INDF2},
9595 {"POSTDEC2", SPO_POSTDEC2},
9596 {"POSTINC2", SPO_POSTINC2},
9597 {"PREINC2", SPO_PREINC2},
9598 {"PLUSW2", SPO_PLUSW2},
9599 {"STKPTR", SPO_STKPTR},
9604 {"FSR0L", SPO_FSR0L},
9605 {"FSR0H", SPO_FSR0H},
9606 {"FSR1L", SPO_FSR1L},
9607 {"FSR1H", SPO_FSR1H},
9608 {"FSR2L", SPO_FSR2L},
9609 {"FSR2H", SPO_FSR2H},
9611 {"PCLATH", SPO_PCLATH},
9612 {"PCLATU", SPO_PCLATU},
9613 {"TABLAT", SPO_TABLAT},
9614 {"TBLPTRL", SPO_TBLPTRL},
9615 {"TBLPTRH", SPO_TBLPTRH},
9616 {"TBLPTRU", SPO_TBLPTRU},
9620 map_strToSym = newHashTable (128);
9621 map_symToStr = newHashTable (128);
9623 for (i=0; predefsyms[i].name; i++) {
9626 /* enter new symbol */
9627 sym = predefsyms[i].sym;
9628 name = predefsyms[i].name;
9629 res = Safe_strdup (name);
9630 hash = symbolHash (name, 0);
9632 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9633 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9637 hash = symbolHash (str, 0) % map_strToSym->size;
9639 /* find symbol in table */
9640 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9642 //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9646 /* enter new symbol */
9648 res = Safe_strdup (str);
9650 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9651 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9653 //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9659 static const char *strFromSym (symbol_t sym) {
9660 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9664 /* ======================================================================== */
9665 /* === DEFINITION MAP HANDLING ============================================ */
9666 /* ======================================================================== */
9668 /* A defmap provides information about which symbol is defined by which pCode.
9669 * The most recent definitions are prepended to the list, so that the most
9670 * recent definition can be found by forward scanning the list.
9671 * pc2: MOVFF r0x00, r0x01
9673 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9675 * We attach one defmap to each flow object, and each pCode will occur at
9676 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9677 * used to find definitions for a pCode in its own defmap that precede pCode.
9680 typedef struct defmap_s {
9681 symbol_t sym; /** symbol this item refers to */
9684 unsigned int in_mask:8; /** mask leaving in accessed bits */
9685 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9686 int isRead:1; /** sym/mask is read */
9687 int isWrite:1; /** sym/mask is written */
9691 pCode *pc; /** pCode this symbol is refrenced at */
9692 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9693 valnum_t val; /** new unique number for this value (if isWrite) */
9694 struct defmap_s *prev, *next; /** link to previous an next definition */
9697 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9698 static int defmap_free_count = 0; /** number of released defmap items */
9700 /* Returns a defmap_t with the specified data; this will be the new list head.
9701 * next - pointer to the current list head */
9702 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9707 defmap_free = map->next;
9708 --defmap_free_count;
9710 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9713 map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9714 map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9715 map->acc.access.isRead = (isRead != 0);
9716 map->acc.access.isWrite = (isWrite != 0);
9719 map->val = (isWrite ? val : 0);
9722 if (next) next->prev = map;
9727 /* Returns a copy of the single defmap item. */
9728 static defmap_t *copyDefmap (defmap_t *map) {
9729 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9730 memcpy (res, map, sizeof (defmap_t));
9736 /* Insert a defmap item after the specified one. */
9737 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9738 if (!ref || !newItem) return 1;
9740 newItem->next = ref->next;
9741 newItem->prev = ref;
9742 ref->next = newItem;
9743 if (newItem->next) newItem->next->prev = newItem;
9748 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9749 * item is copied before insertion into chain and therefore left untouched.
9750 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9751 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9754 while (dummy && (dummy->sym != item->sym
9755 || dummy->pc != item->pc
9756 || dummy->acc.accessmethod != item->acc.accessmethod
9757 || dummy->val != item->val
9758 || dummy->in_val != item->in_val)) {
9759 dummy = dummy->next;
9762 /* item already present? */
9763 if (dummy) return 0;
9765 /* otherwise: insert copy of item */
9766 dummy = copyDefmap (item);
9767 dummy->next = *head;
9768 if (*head) (*head)->prev = dummy;
9774 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9775 static void deleteDefmap (defmap_t *map) {
9778 /* unlink from chain -- fails for the first item (head is not updated!) */
9779 if (map->next) map->next->prev = map->prev;
9780 if (map->prev) map->prev->next = map->next;
9783 memset (map, 0, sizeof (defmap_t));
9785 /* save for future use */
9786 map->next = defmap_free;
9788 ++defmap_free_count;
9791 /* Release all defmaps referenced from map. */
9792 static void deleteDefmapChain (defmap_t **_map) {
9793 defmap_t *map, *next;
9799 /* find list head */
9800 while (map && map->prev) map = map->prev;
9802 /* delete all items */
9812 /* Free all defmap items. */
9813 static void freeDefmap (defmap_t **_map) {
9821 /* find list head */
9822 while (map->prev) map = map->prev;
9824 /* release all items */
9834 /* Returns the most recent definition for the given symbol preceeding pc.
9835 * If no definition is found, NULL is returned.
9836 * If pc == NULL the whole list is scanned. */
9837 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9838 defmap_t *curr = map;
9841 /* skip all definitions up to pc */
9842 while (curr && (curr->pc != pc)) curr = curr->next;
9844 /* pc not in the list -- scan the whole list for definitions */
9846 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9849 /* skip all definitions performed by pc */
9850 while (curr && (curr->pc == pc)) curr = curr->next;
9854 /* find definition for sym */
9855 while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9863 /* Returns the first use (read) of the given symbol AFTER pc.
9864 * If no such use is found, NULL is returned.
9865 * If pc == NULL the whole list is scanned. */
9866 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9867 defmap_t *curr = map, *prev = NULL;
9870 /* skip all definitions up to pc */
9871 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9873 /* pc not in the list -- scan the whole list for definitions */
9875 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9879 /* find end of list */
9880 while (curr && curr->next) curr = curr->next;
9883 /* find use of sym (scan list backwards) */
9884 while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9890 /* Return the defmap entry for sym AT pc.
9891 * If none is found, NULL is returned.
9892 * If more than one entry is found an assertion is triggered. */
9893 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9894 defmap_t *res = NULL;
9896 /* find entries for pc */
9897 while (map && map->pc != pc) map = map->next;
9899 /* find first entry for sym @ pc */
9900 while (map && map->pc == pc && map->sym != sym) map = map->next;
9902 /* no entry found */
9903 if (!map) return NULL;
9905 /* check for more entries */
9908 while (map && map->pc == pc) {
9909 /* more than one entry for sym @ pc found? */
9910 assert (map->sym != sym);
9914 /* return single entry for sym @ pc */
9918 /* Modifies the definition of sym at pCode to newval.
9919 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9921 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9924 /* find definitions of pc */
9925 while (m && m->pc != pc) m = m->next;
9927 /* find definition of sym at pc */
9928 while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9930 /* no definition found */
9936 /* update following uses of sym */
9937 while (m && m->pc == pc) m = m->prev;
9939 if (m->sym == sym) {
9941 if (m->acc.access.isWrite) m = NULL;
9949 /* ======================================================================== */
9950 /* === STACK ROUTINES ===================================================== */
9951 /* ======================================================================== */
9953 typedef struct stack_s {
9955 struct stack_s *next;
9958 typedef stackitem_t *dynstack_t;
9959 static stackitem_t *free_stackitems = NULL;
9961 /* Create a stack with one item. */
9962 static dynstack_t *newStack () {
9963 dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9968 /* Remove a stack -- its items are only marked free. */
9969 static void deleteStack (dynstack_t *s) {
9975 i->next = free_stackitems;
9976 free_stackitems = i;
9981 /* Release all stackitems. */
9982 static void releaseStack () {
9985 while (free_stackitems) {
9986 i = free_stackitems->next;
9987 Safe_free(free_stackitems);
9988 free_stackitems = i;
9992 static void stackPush (dynstack_t *stack, void *data) {
9995 if (free_stackitems) {
9996 i = free_stackitems;
9997 free_stackitems = free_stackitems->next;
9999 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
10006 static void *stackPop (dynstack_t *stack) {
10010 if (stack && *stack) {
10011 data = (*stack)->data;
10013 *stack = (*stack)->next;
10014 i->next = free_stackitems;
10015 free_stackitems = i;
10023 static int stackContains (dynstack_t *s, void *data) {
10028 if (i->data == data) return 1;
10037 static int stackIsEmpty (dynstack_t *s) {
10038 return (*s == NULL);
10047 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10048 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10050 s->lastdef = lastdef;
10054 static void deleteState (state_t *s) {
10058 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10061 /* scan working list for state */
10065 /* is i == state? -- state not new */
10066 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10074 /* is i == state? -- state not new */
10075 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10080 /* not found -- state is new */
10084 static inline valnum_t newValnum ();
10086 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10089 if (!pb) return "<unknown function>";
10091 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10092 if (pc && isPCF(pc)) return PCF(pc)->fname;
10093 else return "<unknown function>";
10096 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10102 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10104 /* find initial value (assigning pc == NULL) */
10105 map = PCFL(pcfl)->in_vals;
10106 while (map && map->sym != sym) map = map->next;
10108 /* initial value already present? */
10110 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10114 /* create a new initial value */
10115 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10116 PCFL(pcfl)->in_vals = map;
10117 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10121 /* insert map as last item in pcfl's defmap */
10122 if (!prev) prev = PCFL(pcfl)->defmap;
10124 PCFL(pcfl)->defmap = map;
10126 while (prev->next) prev = prev->next;
10135 /* Find all reaching definitions for sym at pc.
10136 * A new (!) list of definitions is returned.
10137 * Returns the number of reaching definitions found.
10138 * The defining defmap entries are returned in *chain.
10140 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10145 pCodeFlowLink *succ;
10147 dynstack_t *todo; /** stack of state_t */
10148 dynstack_t *done; /** stack of state_t */
10150 int firstState, n_defs;
10152 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10155 /* initialize return list */
10158 /* wildcard symbol? */
10159 if (!sym) return 0;
10161 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10163 map = PCI(pc)->pcflow->defmap;
10165 res = defmapFindDef (map, sym, pc);
10166 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10168 #define USE_PRECALCED_INVALS 1
10169 #if USE_PRECALCED_INVALS
10170 if (!res && PCI(pc)->pcflow->in_vals) {
10171 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10173 //fprintf (stderr, "found def in init values\n");
10174 df_findall_in_vals++;
10180 // found a single definition (in pc's flow)
10181 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10182 defmapAddCopyIfNew (chain, res);
10183 df_findall_sameflow++;
10187 #if USE_PRECALCED_INVALS
10189 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10195 #define FORWARD_FLOW_ANALYSIS 1
10196 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10197 /* no definition found in pc's flow preceeding pc */
10198 todo = newStack ();
10199 done = newStack ();
10200 n_defs = 0; firstState = 1;
10201 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10203 while (!stackIsEmpty (todo)) {
10204 state = (state_t *) stackPop (todo);
10205 stackPush (done, state);
10206 curr = state->flow;
10207 res = state->lastdef;
10208 //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);
10210 /* there are no definitions BEFORE pc in pc's flow (see above) */
10211 if (curr == PCI(pc)->pcflow) {
10213 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10214 res = pic16_pBlockAddInval (pc->pb, sym);
10215 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10218 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10219 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10223 /* save last definition of sym in this flow as initial def in successors */
10224 res = defmapFindDef (curr->defmap, sym, NULL);
10225 if (!res) res = state->lastdef;
10227 /* add successors to working list */
10228 state = newState (NULL, NULL);
10229 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10231 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10232 state->flow = succ->pcflow;
10233 state->lastdef = res;
10234 if (stateIsNew (state, todo, done)) {
10235 stackPush (todo, state);
10236 state = newState (NULL, NULL);
10238 succ = (pCodeFlowLink *) setNextItem (curr->to);
10240 deleteState (state);
10243 #else // !FORWARD_FLOW_ANALYSIS
10245 /* no definition found in pc's flow preceeding pc */
10246 todo = newStack ();
10247 done = newStack ();
10248 n_defs = 0; firstState = 1;
10249 stackPush (todo, newState (PCI(pc)->pcflow, res));
10251 while (!stackIsEmpty (todo)) {
10252 state = (state_t *) stackPop (todo);
10253 curr = state->flow;
10257 /* only check predecessor flows */
10259 /* get (last) definition of sym in this flow */
10260 res = defmapFindDef (curr->defmap, sym, NULL);
10264 /* definition found */
10265 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10266 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10268 /* no definition found -- check predecessor flows */
10269 state = newState (NULL, NULL);
10270 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10272 /* if no flow predecessor available -- sym might be uninitialized */
10274 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10275 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10276 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10277 deleteDefmap (res); res = NULL;
10281 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10282 state->flow = succ->pcflow;
10283 state->lastdef = res;
10284 if (stateIsNew (state, todo, done)) {
10285 stackPush (todo, state);
10286 state = newState (NULL, NULL);
10288 succ = (pCodeFlowLink *) setNextItem (curr->from);
10290 deleteState (state);
10296 /* clean up done stack */
10297 while (!stackIsEmpty(done)) {
10298 deleteState ((state_t *) stackPop (done));
10300 deleteStack (done);
10302 /* return number of items in result set */
10304 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10305 } else if (n_defs == 1) {
10307 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10308 } else if (n_defs > 0) {
10309 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10313 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10318 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10319 df_findall_otherflow++;
10323 /* ======================================================================== */
10324 /* === VALUE NUMBER HANDLING ============================================== */
10325 /* ======================================================================== */
10327 static valnum_t nextValnum = 0x1000;
10328 static hTab *map_symToValnum = NULL;
10330 /** Return a new value number. */
10331 static inline valnum_t newValnum () {
10332 return (nextValnum += 4);
10335 static valnum_t valnumFromStr (const char *str) {
10340 sym = symFromStr (str);
10342 if (!map_symToValnum) {
10343 map_symToValnum = newHashTable (128);
10346 /* literal already known? */
10347 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10349 /* return existing valnum */
10350 if (res) return (valnum_t) PTR_TO_INT(res);
10352 /* create new valnum */
10354 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10355 //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10359 /* Create a valnum for a literal. */
10360 static valnum_t valnumFromLit (unsigned int lit) {
10361 return ((valnum_t) 0x100 + (lit & 0x0FF));
10364 /* Return the (positive) literal value represented by val
10365 * or -1 iff val is no known literal's valnum. */
10366 static int litFromValnum (valnum_t val) {
10367 if (val >= 0x100 && val < 0x200) {
10368 /* valnum is a (known) literal */
10369 return val & 0x00FF;
10371 /* valnum is not a known literal */
10377 /* Sanity check - all flows in a block must be reachable from initial flow. */
10378 static int verifyAllFlowsReachable (pBlock *pb) {
10384 pCodeFlowLink *succ;
10387 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10390 flowInBlock = NULL;
10392 /* mark initial flow as reached (and "not needs to be reached") */
10393 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10395 addSetHead (&reached, pc);
10396 addSetHead (&checked, pc);
10398 /* mark all further flows in block as "need to be reached" */
10401 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10402 pc = pic16_findNextInstruction (pc->next);
10405 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10406 /* mark as reached and "not need to be reached" */
10407 deleteSetItem (&reached, pcfl);
10408 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10410 /* flow is no longer considered unreachable */
10411 deleteSetItem (&flowInBlock, pcfl);
10413 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10414 if (!isinSet (checked, succ->pcflow)) {
10415 /* flow has never been reached before */
10416 addSetHead (&reached, succ->pcflow);
10417 addSetHead (&checked, succ->pcflow);
10422 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10424 /* by now every flow should have been reached
10425 * --> flowInBlock should be empty */
10426 res = (flowInBlock == NULL);
10430 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10431 while (flowInBlock) {
10432 pcfl = indexSet (flowInBlock, 0);
10433 fprintf (stderr, "not reached: flow %p\n", pcfl);
10434 deleteSetItem (&flowInBlock, pcfl);
10440 deleteSet (&reached);
10441 deleteSet (&flowInBlock);
10442 deleteSet (&checked);
10444 /* if we reached every flow, succ is NULL by now... */
10445 //assert (res); // will fire on unreachable code...
10450 /* Checks a flow for accesses to sym AFTER pc.
10452 * Returns -1 if the symbol is read in this flow (before redefinition),
10453 * returns 0 if the symbol is redefined in this flow or
10454 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10456 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10457 defmap_t *map, *mappc;
10459 /* find pc or start of definitions */
10460 map = pcfl->defmap;
10461 while (map && (map->pc != pc) && map->next) map = map->next;
10462 /* if we found pc -- ignore it */
10463 while (map && map->pc == pc) map = map->prev;
10465 /* scan list backwards (first definition first) */
10466 while (map && mask) {
10467 // if (map->sym == sym) {
10468 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10470 /* scan list for reads at this pc first */
10471 while (map && map->pc == mappc->pc) {
10472 /* is the symbol (partially) read? */
10473 if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10474 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10481 while (map && map->pc == mappc->pc) {
10482 /* honor (partial) redefinitions of sym */
10483 if ((map->sym == sym) && (map->acc.access.isWrite)) {
10484 mask &= ~map->acc.access.mask;
10485 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10490 /* map already points to the first defmap for the next pCode */
10491 //map = mappc->prev;
10494 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10495 * is still alive; return the appropriate mask of alive bits */
10499 /* Check whether a symbol is alive (AFTER pc). */
10500 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10503 dynstack_t *todo, *done;
10506 pCodeFlowLink *succ;
10510 assert (isPCI(pc));
10511 pcfl = PCI(pc)->pcflow;
10512 map = pcfl->defmap;
10514 todo = newStack ();
10515 done = newStack ();
10517 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10518 stackPush (todo, state);
10521 while (!stackIsEmpty (todo)) {
10522 state = (state_t *) stackPop (todo);
10523 pcfl = state->flow;
10524 mask = PTR_TO_INT(state->lastdef);
10525 if (visit) stackPush (done, state); else deleteState(state);
10526 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10527 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10528 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10531 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10532 if (mask == 0) continue;
10534 /* symbol is (partially) read before redefinition in flow */
10535 if (mask == -1) break;
10537 /* symbol is neither read nor completely redefined -- check successor flows */
10538 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10539 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10540 if (stateIsNew (state, todo, done)) {
10541 stackPush (todo, state);
10543 deleteState (state);
10548 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10549 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10551 /* symbol is read in at least one flow -- is alive */
10552 if (mask == -1) return 1;
10554 /* symbol is read in no flow */
10558 /* Returns whether access to the given symbol has side effects. */
10559 static int pic16_symIsSpecial (symbol_t sym) {
10560 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10580 /* no special effects known */
10587 /* Check whether a register should be considered local (to the current function) or not. */
10588 static int pic16_regIsLocal (regs *r) {
10591 if (r->type == REG_TMP) return 1;
10593 sym = symFromStr (r->name);
10596 case SPO_FSR0L: // used in ptrget/ptrput
10597 case SPO_FSR0H: // ... as well
10598 case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10599 case SPO_FSR1H: // ... as well
10600 case SPO_FSR2L: // used as frame pointer
10601 case SPO_FSR2H: // ... as well
10602 case SPO_PRODL: // used to return values from functions
10603 case SPO_PRODH: // ... as well
10604 /* these registers (and some more...) are considered local */
10608 /* for unknown regs: check is marked local, leave if not */
10612 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10618 /* if in doubt, assume non-local... */
10622 /* Check all symbols touched by pc whether their newly assigned values are read.
10623 * Returns 0 if no symbol is used later on, 1 otherwise. */
10624 static int pic16_pCodeIsAlive (pCode *pc) {
10625 pCodeInstruction *pci;
10626 defmap_t *map, *lastpc;
10629 /* we can only handle PCIs */
10630 if (!isPCI(pc)) return 1;
10632 //pc->print (stderr, pc);
10635 assert (pci && pci->pcflow && pci->pcflow->defmap);
10637 /* NEVER remove instructions with implicit side effects */
10640 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10641 case POC_TBLRD_POSTDEC:
10642 case POC_TBLRD_PREINC:
10643 case POC_TBLWT: /* modify program memory */
10644 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10645 case POC_TBLWT_POSTDEC:
10646 case POC_TBLWT_PREINC:
10647 case POC_CLRWDT: /* clear watchdog timer */
10648 case POC_PUSH: /* should be safe to remove though... */
10649 case POC_POP: /* should be safe to remove though... */
10654 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10658 /* no special instruction */
10662 /* prevent us from removing assignments to non-local variables */
10664 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10665 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10667 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10668 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10669 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10670 //pc->print (stderr, pc);
10673 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10674 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10679 /* OVERKILL: prevent us from removing reads from non-local variables
10680 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10681 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10683 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10684 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10686 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10687 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10688 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10689 //pc->print (stderr, pc);
10692 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10693 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10698 /* now check that the defined symbols are not used */
10699 map = pci->pcflow->defmap;
10701 /* find items for pc */
10702 while (map && map->pc != pc) map = map->next;
10704 /* no entries found? something is fishy with DF analysis... -- play safe */
10706 if (pic16_pcode_verbose) {
10707 fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10712 /* remember first item assigned to pc for later use */
10715 /* check all symbols being modified by pc */
10716 while (map && map->pc == pc) {
10717 if (map->sym == 0) { map = map->next; continue; }
10719 /* keep pc if it references special symbols (like POSTDEC0) */
10723 pic16_pCode2str (buf, 256, pc);
10724 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10727 if (pic16_symIsSpecial (map->sym)) {
10728 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10731 if (map->acc.access.isWrite) {
10732 if (pic16_isAlive (map->sym, pc)) {
10733 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10740 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10744 pic16_pCode2str (buf, 256, pc);
10745 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10751 /* Adds implied operands to the list.
10752 * sym - operand being accessed in the pCode
10753 * list - list to append the operand
10754 * isRead - set to 1 iff sym is read in pCode
10755 * listRead - set to 1 iff all operands being read are to be listed
10757 * Returns 0 for "normal" operands, 1 for special operands.
10759 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10760 /* check whether accessing REG accesses other REGs as well */
10764 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10765 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10766 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10770 /* reads FSR0x and WREG */
10771 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10772 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10773 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10774 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10780 /* reads/modifies FSR0x */
10781 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10782 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10783 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10788 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10789 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10790 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10794 /* reads FSR1x and WREG */
10795 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10796 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10797 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10798 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10804 /* reads/modifies FSR1x */
10805 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10806 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10807 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10812 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10813 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10814 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10818 /* reads FSR2x and WREG */
10819 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10820 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10821 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10822 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10828 /* reads/modifies FSR2x */
10829 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10830 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10831 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10835 /* modifies PCLATH and PCLATU */
10836 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10838 /* reading PCL updates PCLATx */
10839 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10840 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10843 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10844 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10845 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10850 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10851 /* nothing special */
10856 /* has been a special operand */
10860 static symbol_t pic16_fsrsym_idx[][2] = {
10861 {SPO_FSR0L, SPO_FSR0H},
10862 {SPO_FSR1L, SPO_FSR1H},
10863 {SPO_FSR2L, SPO_FSR2H}
10866 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10867 static void mergeDefmapSymbols (defmap_t *list) {
10868 defmap_t *ref, *curr, *temp;
10870 /* now make sure that each symbol occurs at most once per pc */
10872 while (ref && (ref->pc == list->pc)) {
10874 while (curr && (curr->pc == list->pc)) {
10875 if (curr->sym == ref->sym) {
10876 //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10877 /* found a symbol occuring twice... merge the two */
10878 if (curr->acc.access.isRead) {
10879 //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10880 ref->acc.access.isRead = 1;
10881 ref->acc.access.in_mask |= curr->acc.access.in_mask;
10883 if (curr->acc.access.isWrite) {
10884 //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10885 ref->acc.access.isWrite = 1;
10886 ref->acc.access.mask |= curr->acc.access.mask;
10890 deleteDefmap (temp);
10891 continue; // do not skip curr!
10899 /** Prepend list with the reads and definitions performed by pc. */
10900 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10901 pCodeInstruction *pci;
10902 int cond, inCond, outCond;
10903 int mask = 0xff, smask;
10904 int isSpecial, isSpecial2;
10905 symbol_t sym, sym2;
10909 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10910 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10911 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10912 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10915 assert (isPCI(pc));
10918 /* handle bit instructions */
10919 if (pci->isBitInst) {
10920 assert (pci->pcop->type == PO_GPR_BIT);
10921 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10924 /* handle (additional) implicit arguments */
10930 lit = PCOL(pci->pcop)->lit;
10931 assert (lit >= 0 && lit < 3);
10932 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10933 val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10934 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10935 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10936 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...
10940 case POC_MOVLB: // BSR
10941 case POC_BANKSEL: // BSR
10942 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10945 case POC_MULWF: // PRODx
10946 case POC_MULLW: // PRODx
10947 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10948 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10951 case POC_POP: // TOS, STKPTR
10952 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10953 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10954 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10955 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10958 case POC_PUSH: // STKPTR
10959 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10960 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10961 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10962 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10965 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10966 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10967 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10968 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10969 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10970 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10972 /* needs correctly set-up stack pointer */
10973 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10974 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10977 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10978 /* pseudo read on (possible) return values */
10979 // WREG is handled below via outCond
10980 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10981 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10982 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10984 /* caller's stack pointers must be restored */
10985 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10986 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10987 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10988 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10991 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10992 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10993 /* pseudo read on (possible) return values */
10994 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10995 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10996 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10997 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10999 /* caller's stack pointers must be restored */
11000 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11001 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11002 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
11003 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
11007 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11008 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11009 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11010 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11013 case POC_TBLRD_POSTINC:
11014 case POC_TBLRD_POSTDEC:
11015 case POC_TBLRD_PREINC:
11016 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11017 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11018 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11019 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11023 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11024 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11025 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11026 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11029 case POC_TBLWT_POSTINC:
11030 case POC_TBLWT_POSTDEC:
11031 case POC_TBLWT_PREINC:
11032 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11033 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11034 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11035 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11039 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11043 /* handle explicit arguments */
11044 inCond = pci->inCond;
11045 outCond = pci->outCond;
11046 cond = inCond | outCond;
11047 if (cond & PCC_W) {
11048 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11051 /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11052 if (inCond & PCC_STATUS) {
11054 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11055 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11056 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11057 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11058 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11060 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11061 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11064 if (outCond & PCC_STATUS) {
11066 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11067 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11068 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11069 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11070 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11072 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11073 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11076 isSpecial = isSpecial2 = 0;
11078 if (cond & PCC_REGISTER) {
11079 name = pic16_get_op (pci->pcop, NULL, 0);
11080 sym = symFromStr (name);
11081 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11082 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11085 if (cond & PCC_REGISTER2) {
11086 name = pic16_get_op2 (pci->pcop, NULL, 0);
11087 sym2 = symFromStr (name);
11088 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11089 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11093 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11094 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11096 mergeDefmapSymbols (list);
11102 static void printDefmap (defmap_t *map) {
11106 fprintf (stderr, "defmap @ %p:\n", curr);
11108 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11109 curr->acc.access.isRead ? "R" : " ",
11110 curr->acc.access.isWrite ? "W": " ",
11111 curr->in_val, curr->val,
11112 curr->acc.access.in_mask, curr->acc.access.mask,
11113 strFromSym(curr->sym), curr->sym,
11117 fprintf (stderr, "<EOL>\n");
11121 /* Add "additional" definitions to uniq.
11122 * 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.
11123 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11125 * If symbols defined in additional are not present in uniq, a definition is created.
11126 * Otherwise the present definition is altered to reflect the newer assignments.
11128 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11129 * before `------- noted in additional --------' after
11131 * I assume that each symbol occurs AT MOST ONCE in uniq.
11134 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11139 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11140 /* find tail of additional list (holds the first assignment) */
11142 while (curr && curr->next) curr = curr->next;
11146 /* find next assignment in additionals */
11147 while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11151 /* find item in uniq */
11153 //printDefmap (*uniq);
11154 while (old && (old->sym != curr->sym)) old = old->next;
11157 /* definition found -- replace */
11158 if (old->val != curr->val) {
11159 old->val = curr->val;
11163 /* new definition */
11164 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11171 /* return 0 iff uniq remained unchanged */
11175 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11176 * lists of its predecessor flows.
11177 * Initially *combined should be NULL, alt_in will be copied to combined.
11178 * If *combined != NULL, combined will be altered:
11179 * - for symbols defined in *combined but not in alt_in,
11180 * *combined is altered to 0 (value unknown, either *combined or INIT).
11181 * - for symbols defined in alt_in but not in *combined,
11182 * a 0 definition is created (value unknown, either INIT or alt).
11183 * - for symbols defined in both, *combined is:
11184 * > left unchanged if *combined->val == alt_in->val or
11185 * > modified to 0 otherwise (value unknown, either alt or *combined).
11187 * I assume that each symbol occurs AT MOST ONCE in each list!
11189 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11195 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11197 if (!(*combined)) {
11198 return defmapUpdateUniqueSym (combined, alt_in);
11201 /* merge the two */
11204 /* find symbols definition in *combined */
11206 while (old && (old->sym != curr->sym)) old = old->next;
11209 /* definition found */
11210 if (old->val && (old->val != curr->val)) {
11211 old->val = 0; /* value unknown */
11215 /* no definition found -- can be either INIT or alt_in's value */
11216 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11217 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11218 if (val != curr->val) change++;
11224 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11227 if (old->val != 0) {
11228 /* find definition in alt_in */
11230 while (curr && curr->sym != old->sym) curr = curr->next;
11232 /* symbol defined in *combined only -- can be either INIT or *combined */
11233 val = pic16_pBlockAddInval (pb, old->sym)->val;
11234 if (old->val != val) {
11247 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11248 defmap_t *curr1, *curr2;
11251 /* identical maps are equal */
11252 if (map1 == map2) return 0;
11254 if (!map1) return -1;
11255 if (!map2) return 1;
11257 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11262 while (curr1 && curr2) {
11263 curr1 = curr1->next;
11264 curr2 = curr2->next;
11267 /* one of them longer? */
11268 if (curr1) return 1;
11269 if (curr2) return -1;
11271 /* both lists are of equal length -- compare (in O(n^2)) */
11276 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11277 if (!curr2) return 1; // symbol not found in curr2
11278 if (curr2->val != curr1->val) return 1; // values differ
11280 /* compare next symbol */
11281 curr1 = curr1->next;
11284 /* no difference found */
11289 /* Prepare a list of all reaching definitions per flow.
11290 * This is done using a forward dataflow analysis.
11292 static void createReachingDefinitions (pBlock *pb) {
11293 defmap_t *out_vals, *in_vals;
11296 pCodeFlowLink *link;
11302 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11303 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11305 deleteDefmapChain (&PCFL(pc)->in_vals);
11306 deleteDefmapChain (&PCFL(pc)->out_vals);
11307 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11311 pc = pic16_findNextInstruction (pb->pcHead);
11312 todo = NULL; blacklist = NULL;
11313 addSetHead (&todo, PCI(pc)->pcflow);
11315 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11316 while (elementsInSet (todo)) {
11317 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11318 pcfl = PCFL(indexSet (todo, 0));
11319 deleteSetItem (&todo, pcfl);
11320 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11324 if (isinSet (blacklist, pcfl)) {
11325 fprintf (stderr, "ignoring blacklisted flow\n");
11329 /* create in_vals from predecessors out_vals */
11330 link = setFirstItem (pcfl->from);
11332 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11333 link = setNextItem (pcfl->from);
11336 //printDefmap (in_vals);
11337 //printDefmap (pcfl->in_vals);
11339 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11340 //fprintf (stderr, "in_vals changed\n");
11341 /* in_vals changed -- update out_vals */
11342 deleteDefmapChain (&pcfl->in_vals);
11343 pcfl->in_vals = in_vals;
11345 /* create out_val from in_val and defmap */
11347 defmapUpdateUniqueSym (&out_vals, in_vals);
11348 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11350 /* is out_vals different from pcfl->out_vals */
11351 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11352 //fprintf (stderr, "out_vals changed\n");
11353 deleteDefmapChain (&pcfl->out_vals);
11354 pcfl->out_vals = out_vals;
11356 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11357 addSet (&blacklist, pcfl);
11360 /* reschedule all successors */
11361 link = setFirstItem (pcfl->to);
11363 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11364 addSetIfnotP (&todo, link->pcflow);
11365 link = setNextItem (pcfl->to);
11368 deleteDefmapChain (&out_vals);
11371 deleteDefmapChain (&in_vals);
11377 static void showAllDefs (symbol_t sym, pCode *pc) {
11381 assert (isPCI(pc));
11382 count = defmapFindAll (sym, pc, &map);
11384 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11387 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11390 pic16_pCode2str (buf, 256, map->pc);
11391 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11395 deleteDefmapChain (&map);
11399 /* safepCodeUnlink and remove pc from defmap. */
11400 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11401 defmap_t *map, *next, **head;
11405 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11406 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11407 res = pic16_safepCodeUnlink (pc, comment);
11410 /* remove pc from defmap */
11413 if (map->pc == pc) {
11414 if (!map->prev && head) *head = map->next;
11415 deleteDefmap (map);
11424 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11426 /* This breaks the defmap chain's references to pCodes... fix it! */
11427 map = PCI(pc)->pcflow->defmap;
11429 while (map && map->pc != pc) map = map->next;
11431 while (map && map->pc == pc) {
11437 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11438 * write accesses (isRead == 0). */
11439 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11440 defmap_t *map, *map_start;
11442 if (!isPCI(pc)) return;
11443 if (sym == newsym) return;
11445 map = PCI(pc)->pcflow->defmap;
11447 while (map && map->pc != pc) map = map->next;
11449 while (map && map->pc == pc) {
11450 if (map->sym == sym) {
11451 assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11452 if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11453 /* only one kind of access handled... this is easy */
11456 /* must copy defmap entry before replacing symbol... */
11457 copy = copyDefmap (map);
11459 map->acc.access.isRead = 0;
11460 copy->acc.access.isWrite = 0;
11462 map->acc.access.isWrite = 0;
11463 copy->acc.access.isRead = 0;
11465 copy->sym = newsym;
11466 /* insert copy into defmap chain */
11467 defmapInsertAfter (map, copy);
11473 /* as this might introduce multiple defmap entries for newsym... */
11474 mergeDefmapSymbols (map_start);
11477 /* Assign "better" valnums to results. */
11478 static void assignValnums (pCode *pc) {
11479 pCodeInstruction *pci;
11481 symbol_t sym1, sym2;
11482 int cond, isSpecial1, isSpecial2, count, mask, lit;
11483 defmap_t *list, *val, *oldval, *dummy;
11484 regs *reg1 = NULL, *reg2 = NULL;
11487 /* only works for pCodeInstructions... */
11488 if (!isPCI(pc)) return;
11491 cond = pci->inCond | pci->outCond;
11492 list = pci->pcflow->defmap;
11493 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11495 if (cond & PCC_REGISTER) {
11496 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11497 reg1 = pic16_getRegFromInstruction (pc);
11498 isSpecial1 = pic16_symIsSpecial (sym1);
11500 if (cond & PCC_REGISTER2) {
11501 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11502 reg2 = pic16_getRegFromInstruction (pc);
11503 isSpecial2 = pic16_symIsSpecial (sym2);
11506 /* determine input values */
11508 while (val && val->pc != pc) val = val->next;
11509 //list = val; /* might save some time later... */
11510 while (val && val->pc == pc) {
11512 if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11513 /* get valnum for sym */
11514 count = defmapFindAll (val->sym, pc, &oldval);
11515 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11517 if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11518 val->in_val = oldval->val;
11522 } else if (count == 0) {
11523 /* no definition found */
11526 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11528 dummy = oldval->next;
11529 mask = oldval->acc.access.mask;
11530 val->in_val = oldval->val;
11531 while (dummy && (dummy->val == val->in_val)) {
11532 mask &= dummy->acc.access.mask;
11533 dummy = dummy->next;
11536 /* found other values or to restictive mask */
11537 if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11541 if (count > 0) deleteDefmapChain (&oldval);
11546 /* handle valnum assignment */
11548 case POC_CLRF: /* modifies STATUS (Z) */
11549 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11550 oldval = defmapCurr (list, sym1, pc);
11551 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11552 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11553 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11555 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11559 case POC_SETF: /* SETF does not touch STATUS */
11560 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11561 oldval = defmapCurr (list, sym1, pc);
11562 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11563 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11564 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11566 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11570 case POC_MOVLW: /* does not touch STATUS */
11571 oldval = defmapCurr (list, SPO_WREG, pc);
11572 if (pci->pcop->type == PO_LITERAL) {
11573 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11574 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11576 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11577 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11579 if (oldval && oldval->in_val == litnum) {
11580 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11581 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11583 defmapUpdate (list, SPO_WREG, pc, litnum);
11586 case POC_ANDLW: /* modifies STATUS (Z,N) */
11587 case POC_IORLW: /* modifies STATUS (Z,N) */
11588 case POC_XORLW: /* modifies STATUS (Z,N) */
11589 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11590 if (pci->pcop->type == PO_LITERAL) {
11592 lit = (unsigned char) PCOL(pci->pcop)->lit;
11593 val = defmapCurr (list, SPO_WREG, pc);
11594 if (val) vallit = litFromValnum (val->in_val);
11595 if (vallit != -1) {
11596 /* xxxLW <literal>, WREG contains a known literal */
11597 //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11598 if (pci->op == POC_ANDLW) {
11600 } else if (pci->op == POC_IORLW) {
11602 } else if (pci->op == POC_XORLW) {
11605 assert (0 && "invalid operation");
11607 if (vallit == lit) {
11608 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11609 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11611 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11618 /* check if old value matches new value */
11621 assert (pci->pcop->type == PO_LITERAL);
11623 lit = PCOL(pci->pcop)->lit;
11625 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11627 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11628 //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11630 /* cannot remove this LFSR */
11634 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11635 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11636 //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11642 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11647 case POC_MOVWF: /* does not touch flags */
11648 /* find value of WREG */
11649 val = defmapCurr (list, SPO_WREG, pc);
11650 oldval = defmapCurr (list, sym1, pc);
11651 if (val) lit = litFromValnum (val->in_val);
11653 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11655 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11656 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11657 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11659 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11661 assert (lit == 0x0ff);
11662 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11664 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11665 pic16_pCodeReplace (pc, newpc);
11666 defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11667 pic16_fixDefmap (pc, newpc);
11670 /* This breaks the defmap chain's references to pCodes... fix it! */
11671 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11672 if (!val->acc.access.isWrite) {
11673 deleteDefmap (val); // delete reference to WREG as in value
11676 val->acc.access.isRead = 0; // delete reference to WREG as in value
11678 oldval = PCI(pc)->pcflow->defmap;
11680 if (oldval->pc == pc) oldval->pc = newpc;
11681 oldval = oldval->next;
11683 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11684 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11685 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11687 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11690 case POC_MOVFW: /* modifies STATUS (Z,N) */
11691 /* find value of REG */
11692 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11693 val = defmapCurr (list, sym1, pc);
11694 oldval = defmapCurr (list, SPO_WREG, pc);
11695 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11696 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11697 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11699 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11703 case POC_MOVFF: /* does not touch STATUS */
11704 /* find value of REG */
11705 val = defmapCurr (list, sym1, pc);
11706 oldval = defmapCurr (list, sym2, pc);
11707 if (val) lit = litFromValnum (val->in_val);
11710 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11711 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11713 newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11714 } else if (lit == 0x00ff) {
11715 newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11720 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11721 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11722 pic16_pCodeReplace (pc, newpc);
11723 defmapReplaceSymRef (pc, sym1, 0, 1);
11724 pic16_fixDefmap (pc, newpc);
11726 break; // do not process instruction as MOVFF...
11728 } else if (!isSpecial1 && !isSpecial2
11729 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11730 && val && oldval && (val->in_val != 0)) {
11731 if (val->in_val == oldval->in_val) {
11732 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11733 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11735 if (!pic16_isAlive (sym1, pc)) {
11736 defmap_t *copy = NULL;
11737 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11738 * This should help eliminate
11740 * <do something not changing A or using B>
11742 * <B is not alive anymore>
11744 * <do something not changing A or using B>
11748 /* scan defmap for symbols storing sym1's value */
11749 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11750 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11751 /* unique reaching definition for sym found */
11752 if (copy->val && copy->val == val->in_val) {
11753 //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);
11754 if (copy->sym == SPO_WREG) {
11755 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11757 pCodeOp *pcop = NULL;
11758 /* the code below fails if we try to replace
11759 * MOVFF PRODL, r0x03
11760 * MOVFF r0x03, PCLATU
11762 * MOVFF PRODL, PCLATU
11763 * as copy(PRODL) contains has pc==NULL, by name fails...
11765 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11767 if (copy->pc && PCI(copy->pc)->pcop)
11768 pcop = PCI(copy->pc)->pcop;
11770 /* This code is broken--see above. */
11773 const char *symname = strFromSym(copy->sym);
11776 pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11777 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11778 //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11782 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11784 pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11786 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11787 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11788 pic16_pCodeReplace (pc, newpc);
11789 assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11790 defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11791 pic16_fixDefmap (pc, newpc);
11795 deleteDefmapChain (©);
11798 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11803 /* cannot optimize */
11808 static void pic16_destructDF (pBlock *pb) {
11813 /* remove old defmaps */
11814 pc = pic16_findNextInstruction (pb->pcHead);
11816 next = pic16_findNextInstruction (pc->next);
11818 assert (isPCI(pc) || isPCAD(pc));
11819 assert (PCI(pc)->pcflow);
11820 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11821 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11822 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11827 if (defmap_free || defmap_free_count) {
11828 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11829 freeDefmap (&defmap_free);
11830 defmap_free_count = 0;
11834 /* Checks whether a pBlock contains ASMDIRs. */
11835 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11840 pc = pic16_findNextInstruction (pb->pcHead);
11842 if (isPCAD(pc)) return 1;
11844 pc = pic16_findNextInstruction (pc->next);
11847 /* no PCADs found */
11852 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11853 static int pic16_removeUnusedRegistersDF () {
11856 regs *reg1, *reg2, *reg3;
11857 set *seenRegs = NULL;
11859 int islocal, change = 0;
11862 if (!the_pFile || !the_pFile->pbHead) return 0;
11864 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11865 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11867 /* find set of using pCodes per register */
11868 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11869 pc = pic16_findNextInstruction(pc->next)) {
11871 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11872 reg1 = reg2 = NULL;
11873 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11874 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11877 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11878 addSetIfnotP (&seenRegs, reg1);
11879 addSetIfnotP (®1->reglives.usedpCodes, pc);
11882 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11883 addSetIfnotP (&seenRegs, reg2);
11884 addSetIfnotP (®2->reglives.usedpCodes, pc);
11888 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11889 /* may not use pic16_regIsLocal() here -- in interrupt routines
11890 * WREG, PRODx, FSR0x must be saved */
11891 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11892 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11894 for (i=0; i < 2; i++) {
11895 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11896 if (!pc2) pc2 = pc;
11897 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11898 reg2 = pic16_getRegFromInstruction (pc);
11899 reg3 = pic16_getRegFromInstruction2 (pc);
11901 || (reg2->rIdx != pic16_stack_preinc->rIdx
11902 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11904 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11905 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11906 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11907 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11911 deleteSet (®1->reglives.usedpCodes);
11914 deleteSet (&seenRegs);
11921 /* Set up pCodeFlow's defmap_ts.
11922 * Needs correctly set up to/from fields. */
11923 static void pic16_createDF (pBlock *pb) {
11929 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11931 pic16_destructDF (pb);
11933 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11934 if (pic16_pBlockHasAsmdirs (pb)) {
11935 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11939 /* integrity check -- we need to reach all flows to guarantee
11940 * correct data flow analysis (reaching definitions, aliveness) */
11942 if (!verifyAllFlowsReachable (pb)) {
11943 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11948 /* establish new defmaps */
11949 pc = pic16_findNextInstruction (pb->pcHead);
11951 next = pic16_findNextInstruction (pc->next);
11953 assert (PCI(pc)->pcflow);
11954 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11959 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11960 createReachingDefinitions (pb);
11963 /* assign better valnums */
11964 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11965 pc = pic16_findNextInstruction (pb->pcHead);
11967 next = pic16_findNextInstruction (pc->next);
11969 assert (PCI(pc)->pcflow);
11970 assignValnums (pc);
11977 /* remove dead pCodes */
11978 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11981 pc = pic16_findNextInstruction (pb->pcHead);
11983 next = pic16_findNextInstruction (pc->next);
11985 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11986 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11995 /* ======================================================================== */
11996 /* === VCG DUMPER ROUTINES ================================================ */
11997 /* ======================================================================== */
11998 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11999 hTab *dumpedNodes = NULL;
12001 /** Dump VCG header into of. */
12002 static void pic16_vcg_init (FILE *of) {
12003 /* graph defaults */
12004 fprintf (of, "graph:{\n");
12005 fprintf (of, "title:\"graph1\"\n");
12006 fprintf (of, "label:\"graph1\"\n");
12007 fprintf (of, "color:white\n");
12008 fprintf (of, "textcolor:black\n");
12009 fprintf (of, "bordercolor:black\n");
12010 fprintf (of, "borderwidth:1\n");
12011 fprintf (of, "textmode:center\n");
12013 fprintf (of, "layoutalgorithm:dfs\n");
12014 fprintf (of, "late_edge_labels:yes\n");
12015 fprintf (of, "display_edge_labels:yes\n");
12016 fprintf (of, "dirty_edge_labels:yes\n");
12017 fprintf (of, "finetuning:yes\n");
12018 fprintf (of, "ignoresingles:no\n");
12019 fprintf (of, "straight_phase:yes\n");
12020 fprintf (of, "priority_phase:yes\n");
12021 fprintf (of, "manhattan_edges:yes\n");
12022 fprintf (of, "smanhattan_edges:no\n");
12023 fprintf (of, "nearedges:no\n");
12024 fprintf (of, "node_alignment:center\n"); // bottom|top|center
12025 fprintf (of, "port_sharing:no\n");
12026 fprintf (of, "arrowmode:free\n"); // fixed|free
12027 fprintf (of, "crossingphase2:yes\n");
12028 fprintf (of, "crossingoptimization:yes\n");
12029 fprintf (of, "edges:yes\n");
12030 fprintf (of, "nodes:yes\n");
12031 fprintf (of, "splines:no\n");
12033 /* node defaults */
12034 fprintf (of, "node.color:lightyellow\n");
12035 fprintf (of, "node.textcolor:black\n");
12036 fprintf (of, "node.textmode:center\n");
12037 fprintf (of, "node.shape:box\n");
12038 fprintf (of, "node.bordercolor:black\n");
12039 fprintf (of, "node.borderwidth:1\n");
12041 /* edge defaults */
12042 fprintf (of, "edge.textcolor:black\n");
12043 fprintf (of, "edge.color:black\n");
12044 fprintf (of, "edge.thickness:1\n");
12045 fprintf (of, "edge.arrowcolor:black\n");
12046 fprintf (of, "edge.backarrowcolor:black\n");
12047 fprintf (of, "edge.arrowsize:15\n");
12048 fprintf (of, "edge.backarrowsize:15\n");
12049 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12050 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12051 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12053 fprintf (of, "\n");
12055 /* prepare data structures */
12057 hTabDeleteAll (dumpedNodes);
12058 dumpedNodes = NULL;
12060 dumpedNodes = newHashTable (128);
12063 /** Dump VCG footer into of. */
12064 static void pic16_vcg_close (FILE *of) {
12065 fprintf (of, "}\n");
12068 #define BUF_SIZE 128
12069 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12072 static int ptrcmp (const void *p1, const void *p2) {
12077 /** Dump a pCode node as VCG to of. */
12078 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12079 char buf[BUF_SIZE];
12081 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12085 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12086 //fprintf (stderr, "dumping %p\n", pc);
12088 /* only dump pCodeInstructions and Flow nodes */
12089 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12092 fprintf (of, "node:{");
12093 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12094 fprintf (of, "label:\"%s\n", pcTitle(pc));
12096 fprintf (of, "<PCFLOW>");
12097 } else if (isPCI(pc) || isPCAD(pc)) {
12098 pc->print (of, pc);
12100 fprintf (of, "<!PCI>");
12102 fprintf (of, "\" ");
12103 fprintf (of, "}\n");
12105 if (1 && isPCFL(pc)) {
12106 defmap_t *map, *prev;
12108 map = PCFL(pc)->defmap;
12111 if (map->sym != 0) {
12114 /* emit definition node */
12115 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12116 fprintf (of, "label:\"");
12120 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));
12123 } while (map && prev->pc == map->pc);
12126 fprintf (of, "\" ");
12128 fprintf (of, "color:green ");
12129 fprintf (of, "}\n");
12131 /* emit edge to previous definition */
12132 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12134 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12136 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12138 fprintf (of, "color:green ");
12139 fprintf (of, "}\n");
12142 pic16_vcg_dumpnode (map->pc, of);
12143 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12144 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12151 /* emit additional nodes (e.g. operands) */
12154 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12155 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12156 char buf[BUF_SIZE];
12157 pCodeInstruction *pci;
12161 if (1 && isPCFL(pc)) {
12162 /* emit edges to flow successors */
12164 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12165 pcfl = setFirstItem (PCFL(pc)->to);
12167 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12168 pic16_vcg_dumpnode (pc, of);
12169 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12170 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12171 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12172 pcfl = setNextItem (PCFL(pc)->to);
12176 if (!isPCI(pc) && !isPCAD(pc)) return;
12180 /* emit control flow edges (forward only) */
12184 pic16_vcg_dumpnode (curr->pc, of);
12185 fprintf (of, "edge:{");
12186 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12187 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12188 fprintf (of, "color:red ");
12189 fprintf (of, "}\n");
12194 /* dump "flow" edge (link pCode according to pBlock order) */
12197 pcnext = pic16_findNextInstruction (pc->next);
12199 pic16_vcg_dumpnode (pcnext, of);
12200 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12201 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12209 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12210 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12211 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12215 /* emit data flow edges (backward only) */
12216 /* TODO: gather data flow information... */
12219 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12224 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12225 if (pic16_pBlockHasAsmdirs (pb)) {
12226 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12230 for (pc=pb->pcHead; pc; pc = pc->next) {
12231 pic16_vcg_dumpnode (pc, of);
12234 for (pc=pb->pcHead; pc; pc = pc->next) {
12235 pic16_vcg_dumpedges (pc, of);
12239 static void pic16_vcg_dump_default (pBlock *pb) {
12241 char buf[BUF_SIZE];
12246 /* get function name */
12248 while (pc && !isPCF(pc)) pc = pc->next;
12250 SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12252 SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12255 //fprintf (stderr, "now dumping %s\n", buf);
12256 of = fopen (buf, "w");
12257 pic16_vcg_init (of);
12258 pic16_vcg_dump (of, pb);
12259 pic16_vcg_close (of);
12264 /*** END of helpers for pCode dataflow optimizations ***/