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)
38 #define STRCASECMP stricmp
41 #define STRCASECMP strcasecmp
44 #define DUMP_DF_GRAPHS 0
46 /****************************************************************/
47 /****************************************************************/
49 static peepCommand peepCommands[] = {
51 {NOTBITSKIP, "_NOTBITSKIP_"},
52 {BITSKIP, "_BITSKIP_"},
53 {INVERTBITSKIP, "_INVERTBITSKIP_"},
60 // Eventually this will go into device dependent files:
61 pCodeOpReg pic16_pc_status = {{PO_STATUS, "STATUS"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_intcon = {{PO_INTCON, "INTCON"}, -1, NULL,0,NULL};
63 pCodeOpReg pic16_pc_pcl = {{PO_PCL, "PCL"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_pclath = {{PO_PCLATH, "PCLATH"}, -1, NULL,0,NULL};
65 pCodeOpReg pic16_pc_pclatu = {{PO_PCLATU, "PCLATU"}, -1, NULL,0,NULL}; // patch 14
66 pCodeOpReg pic16_pc_wreg = {{PO_WREG, "WREG"}, -1, NULL,0,NULL};
67 pCodeOpReg pic16_pc_bsr = {{PO_BSR, "BSR"}, -1, NULL,0,NULL};
69 pCodeOpReg pic16_pc_tosl = {{PO_SFR_REGISTER, "TOSL"}, -1, NULL,0,NULL}; // patch 14
70 pCodeOpReg pic16_pc_tosh = {{PO_SFR_REGISTER, "TOSH"}, -1, NULL,0,NULL}; //
71 pCodeOpReg pic16_pc_tosu = {{PO_SFR_REGISTER, "TOSU"}, -1, NULL,0,NULL}; // patch 14
73 pCodeOpReg pic16_pc_tblptrl = {{PO_SFR_REGISTER, "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
74 pCodeOpReg pic16_pc_tblptrh = {{PO_SFR_REGISTER, "TBLPTRH"}, -1, NULL,0,NULL}; //
75 pCodeOpReg pic16_pc_tblptru = {{PO_SFR_REGISTER, "TBLPTRU"}, -1, NULL,0,NULL}; //
76 pCodeOpReg pic16_pc_tablat = {{PO_SFR_REGISTER, "TABLAT"}, -1, NULL,0,NULL}; // patch 15
78 //pCodeOpReg pic16_pc_fsr0 = {{PO_FSR0, "FSR0"}, -1, NULL,0,NULL}; //deprecated !
80 pCodeOpReg pic16_pc_fsr0l = {{PO_FSR0, "FSR0L"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr0h = {{PO_FSR0, "FSR0H"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr1l = {{PO_FSR0, "FSR1L"}, -1, NULL, 0, NULL};
83 pCodeOpReg pic16_pc_fsr1h = {{PO_FSR0, "FSR1H"}, -1, NULL, 0, NULL};
84 pCodeOpReg pic16_pc_fsr2l = {{PO_FSR0, "FSR2L"}, -1, NULL, 0, NULL};
85 pCodeOpReg pic16_pc_fsr2h = {{PO_FSR0, "FSR2H"}, -1, NULL, 0, NULL};
87 pCodeOpReg pic16_pc_indf0 = {{PO_INDF0, "INDF0"}, -1, NULL,0,NULL};
88 pCodeOpReg pic16_pc_postinc0 = {{PO_INDF0, "POSTINC0"}, -1, NULL, 0, NULL};
89 pCodeOpReg pic16_pc_postdec0 = {{PO_INDF0, "POSTDEC0"}, -1, NULL, 0, NULL};
90 pCodeOpReg pic16_pc_preinc0 = {{PO_INDF0, "PREINC0"}, -1, NULL, 0, NULL};
91 pCodeOpReg pic16_pc_plusw0 = {{PO_INDF0, "PLUSW0"}, -1, NULL, 0, NULL};
93 pCodeOpReg pic16_pc_indf1 = {{PO_INDF0, "INDF1"}, -1, NULL,0,NULL};
94 pCodeOpReg pic16_pc_postinc1 = {{PO_INDF0, "POSTINC1"}, -1, NULL, 0, NULL};
95 pCodeOpReg pic16_pc_postdec1 = {{PO_INDF0, "POSTDEC1"}, -1, NULL, 0, NULL};
96 pCodeOpReg pic16_pc_preinc1 = {{PO_INDF0, "PREINC1"}, -1, NULL, 0, NULL};
97 pCodeOpReg pic16_pc_plusw1 = {{PO_INDF0, "PLUSW1"}, -1, NULL, 0, NULL};
99 pCodeOpReg pic16_pc_indf2 = {{PO_INDF0, "INDF2"}, -1, NULL,0,NULL};
100 pCodeOpReg pic16_pc_postinc2 = {{PO_INDF0, "POSTINC2"}, -1, NULL, 0, NULL};
101 pCodeOpReg pic16_pc_postdec2 = {{PO_INDF0, "POSTDEC2"}, -1, NULL, 0, NULL};
102 pCodeOpReg pic16_pc_preinc2 = {{PO_INDF0, "PREINC2"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_plusw2 = {{PO_INDF0, "PLUSW2"}, -1, NULL, 0, NULL};
105 pCodeOpReg pic16_pc_prodl = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
106 pCodeOpReg pic16_pc_prodh = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
108 /* EEPROM registers */
109 pCodeOpReg pic16_pc_eecon1 = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
110 pCodeOpReg pic16_pc_eecon2 = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
111 pCodeOpReg pic16_pc_eedata = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
112 pCodeOpReg pic16_pc_eeadr = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
114 pCodeOpReg pic16_pc_kzero = {{PO_GPR_REGISTER, "KZ"}, -1, NULL,0,NULL};
115 pCodeOpReg pic16_pc_wsave = {{PO_GPR_REGISTER, "WSAVE"}, -1, NULL,0,NULL};
116 pCodeOpReg pic16_pc_ssave = {{PO_GPR_REGISTER, "SSAVE"}, -1, NULL,0,NULL};
118 pCodeOpReg *pic16_stackpnt_lo;
119 pCodeOpReg *pic16_stackpnt_hi;
120 pCodeOpReg *pic16_stack_postinc;
121 pCodeOpReg *pic16_stack_postdec;
122 pCodeOpReg *pic16_stack_preinc;
123 pCodeOpReg *pic16_stack_plusw;
125 pCodeOpReg *pic16_framepnt_lo;
126 pCodeOpReg *pic16_framepnt_hi;
127 pCodeOpReg *pic16_frame_postinc;
128 pCodeOpReg *pic16_frame_postdec;
129 pCodeOpReg *pic16_frame_preinc;
130 pCodeOpReg *pic16_frame_plusw;
132 pCodeOpReg pic16_pc_gpsimio = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
133 pCodeOpReg pic16_pc_gpsimio2 = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
135 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
136 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
139 static int mnemonics_initialized = 0;
142 static hTab *pic16MnemonicsHash = NULL;
143 static hTab *pic16pCodePeepCommandsHash = NULL;
145 static pFile *the_pFile = NULL;
146 static pBlock *pb_dead_pcodes = NULL;
148 /* Hardcoded flags to change the behavior of the PIC port */
149 static int peepOptimizing = 1; /* run the peephole optimizer if nonzero */
150 static int functionInlining = 1; /* inline functions if nonzero */
151 int pic16_debug_verbose = 0; /* Set true to inundate .asm file */
153 int pic16_pcode_verbose = 0;
155 //static int GpCodeSequenceNumber = 1;
156 static int GpcFlowSeq = 1;
158 extern void pic16_RemoveUnusedRegisters(void);
159 extern void pic16_RegsUnMapLiveRanges(void);
160 extern void pic16_BuildFlowTree(pBlock *pb);
161 extern void pic16_pCodeRegOptimizeRegUsage(int level);
162 extern int pic16_picIsInitialized(void);
163 extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
164 extern int mnem2key(unsigned char const *mnem);
166 /****************************************************************/
167 /* Forward declarations */
168 /****************************************************************/
170 void pic16_unlinkpCode(pCode *pc);
172 static void genericAnalyze(pCode *pc);
173 static void AnalyzeGOTO(pCode *pc);
174 static void AnalyzeSKIP(pCode *pc);
175 static void AnalyzeRETURN(pCode *pc);
178 static void genericDestruct(pCode *pc);
179 static void genericPrint(FILE *of,pCode *pc);
181 static void pCodePrintLabel(FILE *of, pCode *pc);
182 static void pCodePrintFunction(FILE *of, pCode *pc);
183 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
184 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
185 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
186 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
187 int pic16_pCodePeepMatchRule(pCode *pc);
188 static void pBlockStats(FILE *of, pBlock *pb);
189 static pBlock *newpBlock(void);
190 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
191 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
192 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
193 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
194 void OptimizeLocalRegs(void);
195 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
197 char *dumpPicOptype(PIC_OPTYPE type);
199 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
200 pCodeOp *pic16_popGetLit(int);
201 pCodeOp *pic16_popGetWithString(char *);
202 extern int inWparamList(char *s);
204 /** data flow optimization helpers **/
205 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
206 static void pic16_vcg_dump (FILE *of, pBlock *pb);
207 static void pic16_vcg_dump_default (pBlock *pb);
209 static int pic16_pCodeIsAlive (pCode *pc);
210 static void pic16_df_stats ();
211 static void pic16_createDF (pBlock *pb);
212 static int pic16_removeUnusedRegistersDF ();
213 static void pic16_destructDF (pBlock *pb);
214 static void releaseStack ();
216 /****************************************************************/
217 /* PIC Instructions */
218 /****************************************************************/
220 pCodeInstruction pic16_pciADDWF = {
221 {PC_OPCODE, NULL, NULL, 0, NULL,
235 1,0, // dest, bit instruction
237 0, // literal operand
239 0, // fast call/return mode select bit
240 0, // second memory operand
241 0, // second literal operand
243 (PCC_W | PCC_REGISTER), // inCond
244 (PCC_REGISTER | PCC_STATUS), // outCond
248 pCodeInstruction pic16_pciADDFW = {
249 {PC_OPCODE, NULL, NULL, 0, NULL,
263 0,0, // dest, bit instruction
265 0, // literal operand
267 0, // fast call/return mode select bit
268 0, // second memory operand
269 0, // second literal operand
271 (PCC_W | PCC_REGISTER), // inCond
272 (PCC_W | PCC_STATUS), // outCond
276 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
277 {PC_OPCODE, NULL, NULL, 0, NULL,
291 1,0, // dest, bit instruction
293 0, // literal operand
295 0, // fast call/return mode select bit
296 0, // second memory operand
297 0, // second literal operand
299 (PCC_W | PCC_REGISTER | PCC_C), // inCond
300 (PCC_REGISTER | PCC_STATUS), // outCond
304 pCodeInstruction pic16_pciADDFWC = {
305 {PC_OPCODE, NULL, NULL, 0, NULL,
319 0,0, // dest, bit instruction
321 0, // literal operand
323 0, // fast call/return mode select bit
324 0, // second memory operand
325 0, // second literal operand
327 (PCC_W | PCC_REGISTER | PCC_C), // inCond
328 (PCC_W | PCC_STATUS), // outCond
332 pCodeInstruction pic16_pciADDLW = {
333 {PC_OPCODE, NULL, NULL, 0, NULL,
347 0,0, // dest, bit instruction
349 1, // literal operand
351 0, // fast call/return mode select bit
352 0, // second memory operand
353 0, // second literal operand
355 (PCC_W | PCC_LITERAL), // inCond
356 (PCC_W | PCC_STATUS), // outCond
360 pCodeInstruction pic16_pciANDLW = {
361 {PC_OPCODE, NULL, NULL, 0, NULL,
375 0,0, // dest, bit instruction
377 1, // literal operand
379 0, // fast call/return mode select bit
380 0, // second memory operand
381 0, // second literal operand
383 (PCC_W | PCC_LITERAL), // inCond
384 (PCC_W | PCC_Z | PCC_N), // outCond
388 pCodeInstruction pic16_pciANDWF = {
389 {PC_OPCODE, NULL, NULL, 0, NULL,
403 1,0, // dest, bit instruction
405 0, // literal operand
407 0, // fast call/return mode select bit
408 0, // second memory operand
409 0, // second literal operand
411 (PCC_W | PCC_REGISTER), // inCond
412 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
416 pCodeInstruction pic16_pciANDFW = {
417 {PC_OPCODE, NULL, NULL, 0, NULL,
431 0,0, // dest, bit instruction
433 0, // literal operand
435 0, // fast call/return mode select bit
436 0, // second memory operand
437 0, // second literal operand
439 (PCC_W | PCC_REGISTER), // inCond
440 (PCC_W | PCC_Z | PCC_N) // outCond
443 pCodeInstruction pic16_pciBC = { // mdubuc - New
444 {PC_OPCODE, NULL, NULL, 0, NULL,
458 0,0, // dest, bit instruction
460 0, // literal operand
462 0, // fast call/return mode select bit
463 0, // second memory operand
464 0, // second literal operand
466 (PCC_REL_ADDR | PCC_C), // inCond
471 pCodeInstruction pic16_pciBCF = {
472 {PC_OPCODE, NULL, NULL, 0, NULL,
486 1,1, // dest, bit instruction
488 0, // literal operand
490 0, // fast call/return mode select bit
491 0, // second memory operand
492 0, // second literal operand
494 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
495 PCC_REGISTER, // outCond
499 pCodeInstruction pic16_pciBN = { // mdubuc - New
500 {PC_OPCODE, NULL, NULL, 0, NULL,
514 0,0, // dest, bit instruction
516 0, // literal operand
518 0, // fast call/return mode select bit
519 0, // second memory operand
520 0, // second literal operand
522 (PCC_REL_ADDR | PCC_N), // inCond
523 PCC_NONE , // outCond
527 pCodeInstruction pic16_pciBNC = { // mdubuc - New
528 {PC_OPCODE, NULL, NULL, 0, NULL,
542 0,0, // dest, bit instruction
544 0, // literal operand
546 0, // fast call/return mode select bit
547 0, // second memory operand
548 0, // second literal operand
550 (PCC_REL_ADDR | PCC_C), // inCond
551 PCC_NONE , // outCond
555 pCodeInstruction pic16_pciBNN = { // mdubuc - New
556 {PC_OPCODE, NULL, NULL, 0, NULL,
570 0,0, // dest, bit instruction
572 0, // literal operand
574 0, // fast call/return mode select bit
575 0, // second memory operand
576 0, // second literal operand
578 (PCC_REL_ADDR | PCC_N), // inCond
579 PCC_NONE , // outCond
583 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
584 {PC_OPCODE, NULL, NULL, 0, NULL,
598 0,0, // dest, bit instruction
600 0, // literal operand
602 0, // fast call/return mode select bit
603 0, // second memory operand
604 0, // second literal operand
606 (PCC_REL_ADDR | PCC_OV), // inCond
607 PCC_NONE , // outCond
611 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
612 {PC_OPCODE, NULL, NULL, 0, NULL,
626 0,0, // dest, bit instruction
628 0, // literal operand
630 0, // fast call/return mode select bit
631 0, // second memory operand
632 0, // second literal operand
634 (PCC_REL_ADDR | PCC_Z), // inCond
635 PCC_NONE , // outCond
639 pCodeInstruction pic16_pciBOV = { // mdubuc - New
640 {PC_OPCODE, NULL, NULL, 0, NULL,
654 0,0, // dest, bit instruction
656 0, // literal operand
658 0, // fast call/return mode select bit
659 0, // second memory operand
660 0, // second literal operand
662 (PCC_REL_ADDR | PCC_OV), // inCond
663 PCC_NONE , // outCond
667 pCodeInstruction pic16_pciBRA = { // mdubuc - New
668 {PC_OPCODE, NULL, NULL, 0, NULL,
682 0,0, // dest, bit instruction
684 0, // literal operand
686 0, // fast call/return mode select bit
687 0, // second memory operand
688 0, // second literal operand
690 PCC_REL_ADDR, // inCond
691 PCC_NONE , // outCond
695 pCodeInstruction pic16_pciBSF = {
696 {PC_OPCODE, NULL, NULL, 0, NULL,
710 1,1, // dest, bit instruction
712 0, // literal operand
714 0, // fast call/return mode select bit
715 0, // second memory operand
716 0, // second literal operand
718 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
719 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
723 pCodeInstruction pic16_pciBTFSC = {
724 {PC_OPCODE, NULL, NULL, 0, NULL,
738 0,1, // dest, bit instruction
740 0, // literal operand
742 0, // fast call/return mode select bit
743 0, // second memory operand
744 0, // second literal operand
746 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
747 PCC_EXAMINE_PCOP, // outCond
751 pCodeInstruction pic16_pciBTFSS = {
752 {PC_OPCODE, NULL, NULL, 0, NULL,
766 0,1, // dest, bit instruction
768 0, // literal operand
770 0, // fast call/return mode select bit
771 0, // second memory operand
772 0, // second literal operand
774 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
775 PCC_EXAMINE_PCOP, // outCond
779 pCodeInstruction pic16_pciBTG = { // mdubuc - New
780 {PC_OPCODE, NULL, NULL, 0, NULL,
794 0,1, // dest, bit instruction
796 0, // literal operand
798 0, // fast call/return mode select bit
799 0, // second memory operand
800 0, // second literal operand
802 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
803 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
807 pCodeInstruction pic16_pciBZ = { // mdubuc - New
808 {PC_OPCODE, NULL, NULL, 0, NULL,
822 0,0, // dest, bit instruction
824 0, // literal operand
826 0, // fast call/return mode select bit
827 0, // second memory operand
828 0, // second literal operand
830 (PCC_REL_ADDR | PCC_Z), // inCond
835 pCodeInstruction pic16_pciCALL = {
836 {PC_OPCODE, NULL, NULL, 0, NULL,
850 0,0, // dest, bit instruction
852 0, // literal operand
854 1, // fast call/return mode select bit
855 0, // second memory operand
856 0, // second literal operand
863 pCodeInstruction pic16_pciCOMF = {
864 {PC_OPCODE, NULL, NULL, 0, NULL,
878 1,0, // dest, bit instruction
880 0, // literal operand
882 0, // fast call/return mode select bit
883 0, // second memory operand
884 0, // second literal operand
886 PCC_REGISTER, // inCond
887 (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
891 pCodeInstruction pic16_pciCOMFW = {
892 {PC_OPCODE, NULL, NULL, 0, NULL,
906 0,0, // dest, bit instruction
908 0, // literal operand
910 0, // fast call/return mode select bit
911 0, // second memory operand
912 0, // second literal operand
914 PCC_REGISTER, // inCond
915 (PCC_W | PCC_Z | PCC_N) , // outCond
919 pCodeInstruction pic16_pciCLRF = {
920 {PC_OPCODE, NULL, NULL, 0, NULL,
934 0,0, // dest, bit instruction
936 0, // literal operand
938 0, // fast call/return mode select bit
939 0, // second memory operand
940 0, // second literal operand
943 (PCC_REGISTER | PCC_Z), // outCond
947 pCodeInstruction pic16_pciCLRWDT = {
948 {PC_OPCODE, NULL, NULL, 0, NULL,
962 0,0, // dest, bit instruction
964 0, // literal operand
966 0, // fast call/return mode select bit
967 0, // second memory operand
968 0, // second literal operand
971 PCC_NONE , // outCond
975 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
976 {PC_OPCODE, NULL, NULL, 0, NULL,
990 0,0, // dest, bit instruction
992 0, // literal operand
994 0, // fast call/return mode select bit
995 0, // second memory operand
996 0, // second literal operand
998 (PCC_W | PCC_REGISTER), // inCond
999 PCC_NONE , // outCond
1003 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1004 {PC_OPCODE, NULL, NULL, 0, NULL,
1011 NULL, // from branch
1018 0,0, // dest, bit instruction
1019 1,1, // branch, skip
1020 0, // literal operand
1021 1, // RAM access bit
1022 0, // fast call/return mode select bit
1023 0, // second memory operand
1024 0, // second literal operand
1026 (PCC_W | PCC_REGISTER), // inCond
1027 PCC_NONE , // outCond
1031 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1032 {PC_OPCODE, NULL, NULL, 0, NULL,
1039 NULL, // from branch
1046 1,0, // dest, bit instruction
1047 1,1, // branch, skip
1048 0, // literal operand
1049 1, // RAM access bit
1050 0, // fast call/return mode select bit
1051 0, // second memory operand
1052 0, // second literal operand
1054 (PCC_W | PCC_REGISTER), // inCond
1055 PCC_NONE , // outCond
1059 pCodeInstruction pic16_pciDAW = {
1060 {PC_OPCODE, NULL, NULL, 0, NULL,
1067 NULL, // from branch
1074 0,0, // dest, bit instruction
1075 0,0, // branch, skip
1076 0, // literal operand
1077 0, // RAM access bit
1078 0, // fast call/return mode select bit
1079 0, // second memory operand
1080 0, // second literal operand
1083 (PCC_W | PCC_C), // outCond
1087 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1088 {PC_OPCODE, NULL, NULL, 0, NULL,
1095 NULL, // from branch
1102 1,0, // dest, bit instruction
1103 1,1, // branch, skip
1104 0, // literal operand
1105 1, // RAM access bit
1106 0, // fast call/return mode select bit
1107 0, // second memory operand
1108 0, // second literal operand
1110 PCC_REGISTER, // inCond
1111 PCC_REGISTER , // outCond
1115 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1116 {PC_OPCODE, NULL, NULL, 0, NULL,
1123 NULL, // from branch
1130 0,0, // dest, bit instruction
1131 1,1, // branch, skip
1132 0, // literal operand
1133 1, // RAM access bit
1134 0, // fast call/return mode select bit
1135 0, // second memory operand
1136 0, // second literal operand
1138 PCC_REGISTER, // inCond
1143 pCodeInstruction pic16_pciDECF = {
1144 {PC_OPCODE, NULL, NULL, 0, NULL,
1151 NULL, // from branch
1158 1,0, // dest, bit instruction
1159 0,0, // branch, skip
1160 0, // literal operand
1161 1, // RAM access bit
1162 0, // fast call/return mode select bit
1163 0, // second memory operand
1164 0, // second literal operand
1166 PCC_REGISTER, // inCond
1167 (PCC_REGISTER | PCC_STATUS) , // outCond
1171 pCodeInstruction pic16_pciDECFW = {
1172 {PC_OPCODE, NULL, NULL, 0, NULL,
1179 NULL, // from branch
1186 0,0, // dest, bit instruction
1187 0,0, // branch, skip
1188 0, // literal operand
1189 1, // RAM access bit
1190 0, // fast call/return mode select bit
1191 0, // second memory operand
1192 0, // second literal operand
1194 PCC_REGISTER, // inCond
1195 (PCC_W | PCC_STATUS) , // outCond
1199 pCodeInstruction pic16_pciDECFSZ = {
1200 {PC_OPCODE, NULL, NULL, 0, NULL,
1207 NULL, // from branch
1214 1,0, // dest, bit instruction
1215 1,1, // branch, skip
1216 0, // literal operand
1217 1, // RAM access bit
1218 0, // fast call/return mode select bit
1219 0, // second memory operand
1220 0, // second literal operand
1222 PCC_REGISTER, // inCond
1223 PCC_REGISTER , // outCond
1227 pCodeInstruction pic16_pciDECFSZW = {
1228 {PC_OPCODE, NULL, NULL, 0, NULL,
1235 NULL, // from branch
1242 0,0, // dest, bit instruction
1243 1,1, // branch, skip
1244 0, // literal operand
1245 1, // RAM access bit
1246 0, // fast call/return mode select bit
1247 0, // second memory operand
1248 0, // second literal operand
1250 PCC_REGISTER, // inCond
1255 pCodeInstruction pic16_pciGOTO = {
1256 {PC_OPCODE, NULL, NULL, 0, NULL,
1263 NULL, // from branch
1270 0,0, // dest, bit instruction
1271 1,0, // branch, skip
1272 0, // literal operand
1273 0, // RAM access bit
1274 0, // fast call/return mode select bit
1275 0, // second memory operand
1276 0, // second literal operand
1278 PCC_REL_ADDR, // inCond
1279 PCC_NONE , // outCond
1283 pCodeInstruction pic16_pciINCF = {
1284 {PC_OPCODE, NULL, NULL, 0, NULL,
1291 NULL, // from branch
1298 1,0, // dest, bit instruction
1299 0,0, // branch, skip
1300 0, // literal operand
1301 1, // RAM access bit
1302 0, // fast call/return mode select bit
1303 0, // second memory operand
1304 0, // second literal operand
1306 PCC_REGISTER, // inCond
1307 (PCC_REGISTER | PCC_STATUS), // outCond
1311 pCodeInstruction pic16_pciINCFW = {
1312 {PC_OPCODE, NULL, NULL, 0, NULL,
1319 NULL, // from branch
1326 0,0, // dest, bit instruction
1327 0,0, // branch, skip
1328 0, // literal operand
1329 1, // RAM access bit
1330 0, // fast call/return mode select bit
1331 0, // second memory operand
1332 0, // second literal operand
1334 PCC_REGISTER, // inCond
1335 (PCC_W | PCC_STATUS) , // outCond
1339 pCodeInstruction pic16_pciINCFSZ = {
1340 {PC_OPCODE, NULL, NULL, 0, NULL,
1347 NULL, // from branch
1354 1,0, // dest, bit instruction
1355 1,1, // branch, skip
1356 0, // literal operand
1357 1, // RAM access bit
1358 0, // fast call/return mode select bit
1359 0, // second memory operand
1360 0, // second literal operand
1362 PCC_REGISTER, // inCond
1363 PCC_REGISTER , // outCond
1367 pCodeInstruction pic16_pciINCFSZW = {
1368 {PC_OPCODE, NULL, NULL, 0, NULL,
1375 NULL, // from branch
1382 0,0, // dest, bit instruction
1383 1,1, // branch, skip
1384 0, // literal operand
1385 1, // RAM access bit
1386 0, // fast call/return mode select bit
1387 0, // second memory operand
1388 0, // second literal operand
1390 PCC_REGISTER, // inCond
1395 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1396 {PC_OPCODE, NULL, NULL, 0, NULL,
1403 NULL, // from branch
1410 1,0, // dest, bit instruction
1411 1,1, // branch, skip
1412 0, // literal operand
1413 1, // RAM access bit
1414 0, // fast call/return mode select bit
1415 0, // second memory operand
1416 0, // second literal operand
1418 PCC_REGISTER, // inCond
1419 PCC_REGISTER , // outCond
1423 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1424 {PC_OPCODE, NULL, NULL, 0, NULL,
1431 NULL, // from branch
1438 0,0, // dest, bit instruction
1439 1,1, // branch, skip
1440 0, // literal operand
1441 1, // RAM access bit
1442 0, // fast call/return mode select bit
1443 0, // second memory operand
1444 0, // second literal operand
1446 PCC_REGISTER, // inCond
1451 pCodeInstruction pic16_pciIORWF = {
1452 {PC_OPCODE, NULL, NULL, 0, NULL,
1459 NULL, // from branch
1466 1,0, // dest, bit instruction
1467 0,0, // branch, skip
1468 0, // literal operand
1469 1, // RAM access bit
1470 0, // fast call/return mode select bit
1471 0, // second memory operand
1472 0, // second literal operand
1474 (PCC_W | PCC_REGISTER), // inCond
1475 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1479 pCodeInstruction pic16_pciIORFW = {
1480 {PC_OPCODE, NULL, NULL, 0, NULL,
1487 NULL, // from branch
1494 0,0, // dest, bit instruction
1495 0,0, // branch, skip
1496 0, // literal operand
1497 1, // RAM access bit
1498 0, // fast call/return mode select bit
1499 0, // second memory operand
1500 0, // second literal operand
1502 (PCC_W | PCC_REGISTER), // inCond
1503 (PCC_W | PCC_Z | PCC_N), // outCond
1507 pCodeInstruction pic16_pciIORLW = {
1508 {PC_OPCODE, NULL, NULL, 0, NULL,
1515 NULL, // from branch
1522 0,0, // dest, bit instruction
1523 0,0, // branch, skip
1524 1, // literal operand
1525 0, // RAM access bit
1526 0, // fast call/return mode select bit
1527 0, // second memory operand
1528 0, // second literal operand
1530 (PCC_W | PCC_LITERAL), // inCond
1531 (PCC_W | PCC_Z | PCC_N), // outCond
1535 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1536 {PC_OPCODE, NULL, NULL, 0, NULL,
1543 NULL, // from branch
1550 0,0, // dest, bit instruction
1551 0,0, // branch, skip
1552 1, // literal operand
1553 0, // RAM access bit
1554 0, // fast call/return mode select bit
1555 0, // second memory operand
1556 1, // second literal operand
1558 PCC_LITERAL, // inCond
1559 PCC_NONE, // outCond
1563 pCodeInstruction pic16_pciMOVF = {
1564 {PC_OPCODE, NULL, NULL, 0, NULL,
1571 NULL, // from branch
1578 1,0, // dest, bit instruction
1579 0,0, // branch, skip
1580 0, // literal operand
1581 1, // RAM access bit
1582 0, // fast call/return mode select bit
1583 0, // second memory operand
1584 0, // second literal operand
1586 PCC_REGISTER, // inCond
1587 (PCC_Z | PCC_N), // outCond
1591 pCodeInstruction pic16_pciMOVFW = {
1592 {PC_OPCODE, NULL, NULL, 0, NULL,
1599 NULL, // from branch
1606 0,0, // dest, bit instruction
1607 0,0, // branch, skip
1608 0, // literal operand
1609 1, // RAM access bit
1610 0, // fast call/return mode select bit
1611 0, // second memory operand
1612 0, // second literal operand
1614 PCC_REGISTER, // inCond
1615 (PCC_W | PCC_N | PCC_Z), // outCond
1619 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1620 {PC_OPCODE, NULL, NULL, 0, NULL,
1627 NULL, // from branch
1634 0,0, // dest, bit instruction
1635 0,0, // branch, skip
1636 0, // literal operand
1637 0, // RAM access bit
1638 0, // fast call/return mode select bit
1639 1, // second memory operand
1640 0, // second literal operand
1642 PCC_REGISTER, // inCond
1643 PCC_REGISTER2, // outCond
1647 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1648 {PC_OPCODE, NULL, NULL, 0, NULL,
1654 NULL, // from branch
1661 0,0, // dest, bit instruction
1662 0,0, // branch, skip
1663 1, // literal operand
1664 0, // RAM access bit
1665 0, // fast call/return mode select bit
1666 0, // second memory operand
1667 0, // second literal operand
1669 (PCC_NONE | PCC_LITERAL), // inCond
1670 PCC_REGISTER, // outCond - BSR
1674 pCodeInstruction pic16_pciMOVLW = {
1675 {PC_OPCODE, NULL, NULL, 0, NULL,
1681 NULL, // from branch
1688 0,0, // dest, bit instruction
1689 0,0, // branch, skip
1690 1, // literal operand
1691 0, // RAM access bit
1692 0, // fast call/return mode select bit
1693 0, // second memory operand
1694 0, // second literal operand
1696 (PCC_NONE | PCC_LITERAL), // inCond
1701 pCodeInstruction pic16_pciMOVWF = {
1702 {PC_OPCODE, NULL, NULL, 0, NULL,
1709 NULL, // from branch
1716 0,0, // dest, bit instruction
1717 0,0, // branch, skip
1718 0, // literal operand
1719 1, // RAM access bit
1720 0, // fast call/return mode select bit
1721 0, // second memory operand
1722 0, // second literal operand
1725 PCC_REGISTER, // outCond
1729 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1730 {PC_OPCODE, NULL, NULL, 0, NULL,
1736 NULL, // from branch
1743 0,0, // dest, bit instruction
1744 0,0, // branch, skip
1745 1, // literal operand
1746 0, // RAM access bit
1747 0, // fast call/return mode select bit
1748 0, // second memory operand
1749 0, // second literal operand
1751 (PCC_W | PCC_LITERAL), // inCond
1752 PCC_NONE, // outCond - PROD
1756 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1757 {PC_OPCODE, NULL, NULL, 0, NULL,
1763 NULL, // from branch
1770 0,0, // dest, bit instruction
1771 0,0, // branch, skip
1772 0, // literal operand
1773 1, // RAM access bit
1774 0, // fast call/return mode select bit
1775 0, // second memory operand
1776 0, // second literal operand
1778 (PCC_W | PCC_REGISTER), // inCond
1779 PCC_REGISTER, // outCond - PROD
1783 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1784 {PC_OPCODE, NULL, NULL, 0, NULL,
1790 NULL, // from branch
1797 0,0, // dest, bit instruction
1798 0,0, // branch, skip
1799 0, // literal operand
1800 1, // RAM access bit
1801 0, // fast call/return mode select bit
1802 0, // second memory operand
1803 0, // second literal operand
1805 PCC_REGISTER, // inCond
1806 (PCC_REGISTER | PCC_STATUS), // outCond
1810 pCodeInstruction pic16_pciNOP = {
1811 {PC_OPCODE, NULL, NULL, 0, NULL,
1817 NULL, // from branch
1824 0,0, // dest, bit instruction
1825 0,0, // branch, skip
1826 0, // literal operand
1827 0, // RAM access bit
1828 0, // fast call/return mode select bit
1829 0, // second memory operand
1830 0, // second literal operand
1833 PCC_NONE, // outCond
1837 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1838 {PC_OPCODE, NULL, NULL, 0, NULL,
1844 NULL, // from branch
1851 0,0, // dest, bit instruction
1852 0,0, // branch, skip
1853 0, // literal operand
1854 0, // RAM access bit
1855 0, // fast call/return mode select bit
1856 0, // second memory operand
1857 0, // second literal operand
1860 PCC_NONE , // outCond
1864 pCodeInstruction pic16_pciPUSH = {
1865 {PC_OPCODE, NULL, NULL, 0, NULL,
1871 NULL, // from branch
1878 0,0, // dest, bit instruction
1879 0,0, // branch, skip
1880 0, // literal operand
1881 0, // RAM access bit
1882 0, // fast call/return mode select bit
1883 0, // second memory operand
1884 0, // second literal operand
1887 PCC_NONE , // outCond
1891 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1892 {PC_OPCODE, NULL, NULL, 0, NULL,
1898 NULL, // from branch
1905 0,0, // dest, bit instruction
1906 1,0, // branch, skip
1907 0, // literal operand
1908 0, // RAM access bit
1909 0, // fast call/return mode select bit
1910 0, // second memory operand
1911 0, // second literal operand
1913 PCC_REL_ADDR, // inCond
1914 PCC_NONE , // outCond
1918 pCodeInstruction pic16_pciRETFIE = {
1919 {PC_OPCODE, NULL, NULL, 0, NULL,
1926 NULL, // from branch
1933 0,0, // dest, bit instruction
1934 1,0, // branch, skip
1935 0, // literal operand
1936 0, // RAM access bit
1937 1, // fast call/return mode select bit
1938 0, // second memory operand
1939 0, // second literal operand
1942 PCC_NONE, // outCond (not true... affects the GIE bit too)
1946 pCodeInstruction pic16_pciRETLW = {
1947 {PC_OPCODE, NULL, NULL, 0, NULL,
1954 NULL, // from branch
1961 0,0, // dest, bit instruction
1962 1,0, // branch, skip
1963 1, // literal operand
1964 0, // RAM access bit
1965 0, // fast call/return mode select bit
1966 0, // second memory operand
1967 0, // second literal operand
1969 PCC_LITERAL, // inCond
1974 pCodeInstruction pic16_pciRETURN = {
1975 {PC_OPCODE, NULL, NULL, 0, NULL,
1982 NULL, // from branch
1989 0,0, // dest, bit instruction
1990 1,0, // branch, skip
1991 0, // literal operand
1992 0, // RAM access bit
1993 1, // fast call/return mode select bit
1994 0, // second memory operand
1995 0, // second literal operand
1998 PCC_NONE, // outCond
2001 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
2002 {PC_OPCODE, NULL, NULL, 0, NULL,
2009 NULL, // from branch
2016 1,0, // dest, bit instruction
2017 0,0, // branch, skip
2018 0, // literal operand
2019 1, // RAM access bit
2020 0, // fast call/return mode select bit
2021 0, // second memory operand
2022 0, // second literal operand
2024 (PCC_C | PCC_REGISTER), // inCond
2025 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2029 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2030 {PC_OPCODE, NULL, NULL, 0, NULL,
2037 NULL, // from branch
2044 0,0, // dest, bit instruction
2045 0,0, // branch, skip
2046 0, // literal operand
2047 1, // RAM access bit
2048 0, // fast call/return mode select bit
2049 0, // second memory operand
2050 0, // second literal operand
2052 (PCC_C | PCC_REGISTER), // inCond
2053 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2057 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2058 {PC_OPCODE, NULL, NULL, 0, NULL,
2065 NULL, // from branch
2072 1,0, // dest, bit instruction
2073 0,0, // branch, skip
2074 0, // literal operand
2075 1, // RAM access bit
2076 0, // fast call/return mode select bit
2077 0, // second memory operand
2078 0, // second literal operand
2080 PCC_REGISTER, // inCond
2081 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2084 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2085 {PC_OPCODE, NULL, NULL, 0, NULL,
2092 NULL, // from branch
2099 0,0, // dest, bit instruction
2100 0,0, // branch, skip
2101 0, // literal operand
2102 1, // RAM access bit
2103 0, // fast call/return mode select bit
2104 0, // second memory operand
2105 0, // second literal operand
2107 PCC_REGISTER, // inCond
2108 (PCC_W | PCC_Z | PCC_N), // outCond
2111 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2112 {PC_OPCODE, NULL, NULL, 0, NULL,
2119 NULL, // from branch
2126 1,0, // dest, bit instruction
2127 0,0, // branch, skip
2128 0, // literal operand
2129 1, // RAM access bit
2130 0, // fast call/return mode select bit
2131 0, // second memory operand
2132 0, // second literal operand
2134 (PCC_C | PCC_REGISTER), // inCond
2135 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2138 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2139 {PC_OPCODE, NULL, NULL, 0, NULL,
2146 NULL, // from branch
2153 0,0, // dest, bit instruction
2154 0,0, // branch, skip
2155 0, // literal operand
2156 1, // RAM access bit
2157 0, // fast call/return mode select bit
2158 0, // second memory operand
2159 0, // second literal operand
2161 (PCC_C | PCC_REGISTER), // inCond
2162 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2165 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2166 {PC_OPCODE, NULL, NULL, 0, NULL,
2173 NULL, // from branch
2180 1,0, // dest, bit instruction
2181 0,0, // branch, skip
2182 0, // literal operand
2183 1, // RAM access bit
2184 0, // fast call/return mode select bit
2185 0, // second memory operand
2186 0, // second literal operand
2188 PCC_REGISTER, // inCond
2189 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2193 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2194 {PC_OPCODE, NULL, NULL, 0, NULL,
2201 NULL, // from branch
2208 0,0, // dest, bit instruction
2209 0,0, // branch, skip
2210 0, // literal operand
2211 1, // RAM access bit
2212 0, // fast call/return mode select bit
2213 0, // second memory operand
2214 0, // second literal operand
2216 PCC_REGISTER, // inCond
2217 (PCC_W | PCC_Z | PCC_N), // outCond
2221 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2222 {PC_OPCODE, NULL, NULL, 0, NULL,
2229 NULL, // from branch
2236 0,0, // dest, bit instruction
2237 0,0, // branch, skip
2238 0, // literal operand
2239 1, // RAM access bit
2240 0, // fast call/return mode select bit
2241 0, // second memory operand
2242 0, // second literal operand
2245 PCC_REGISTER , // outCond
2249 pCodeInstruction pic16_pciSUBLW = {
2250 {PC_OPCODE, NULL, NULL, 0, NULL,
2257 NULL, // from branch
2264 0,0, // dest, bit instruction
2265 0,0, // branch, skip
2266 1, // literal operand
2267 0, // RAM access bit
2268 0, // fast call/return mode select bit
2269 0, // second memory operand
2270 0, // second literal operand
2272 (PCC_W | PCC_LITERAL), // inCond
2273 (PCC_W | PCC_STATUS), // outCond
2277 pCodeInstruction pic16_pciSUBFWB = {
2278 {PC_OPCODE, NULL, NULL, 0, NULL,
2285 NULL, // from branch
2292 1,0, // dest, bit instruction
2293 0,0, // branch, skip
2294 0, // literal operand
2295 1, // RAM access bit
2296 0, // fast call/return mode select bit
2297 0, // second memory operand
2298 0, // second literal operand
2300 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2301 (PCC_W | PCC_STATUS), // outCond
2305 pCodeInstruction pic16_pciSUBWF = {
2306 {PC_OPCODE, NULL, NULL, 0, NULL,
2313 NULL, // from branch
2320 1,0, // dest, bit instruction
2321 0,0, // branch, skip
2322 0, // literal operand
2323 1, // RAM access bit
2324 0, // fast call/return mode select bit
2325 0, // second memory operand
2326 0, // second literal operand
2328 (PCC_W | PCC_REGISTER), // inCond
2329 (PCC_REGISTER | PCC_STATUS), // outCond
2333 pCodeInstruction pic16_pciSUBFW = {
2334 {PC_OPCODE, NULL, NULL, 0, NULL,
2341 NULL, // from branch
2348 0,0, // dest, bit instruction
2349 0,0, // branch, skip
2350 0, // literal operand
2351 1, // RAM access bit
2352 0, // fast call/return mode select bit
2353 0, // second memory operand
2354 0, // second literal operand
2356 (PCC_W | PCC_REGISTER), // inCond
2357 (PCC_W | PCC_STATUS), // outCond
2361 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2362 {PC_OPCODE, NULL, NULL, 0, NULL,
2369 NULL, // from branch
2376 1,0, // dest, bit instruction
2377 0,0, // branch, skip
2378 0, // literal operand
2379 1, // RAM access bit
2380 0, // fast call/return mode select bit
2381 0, // second memory operand
2382 0, // second literal operand
2384 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2385 (PCC_REGISTER | PCC_STATUS), // outCond
2389 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2390 {PC_OPCODE, NULL, NULL, 0, NULL,
2397 NULL, // from branch
2404 0,0, // dest, bit instruction
2405 0,0, // branch, skip
2406 0, // literal operand
2407 1, // RAM access bit
2408 0, // fast call/return mode select bit
2409 0, // second memory operand
2410 0, // second literal operand
2412 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2413 (PCC_W | PCC_STATUS), // outCond
2417 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2418 {PC_OPCODE, NULL, NULL, 0, NULL,
2425 NULL, // from branch
2432 1,0, // dest, bit instruction
2433 0,0, // branch, skip
2434 0, // literal operand
2435 1, // RAM access bit
2436 0, // fast call/return mode select bit
2437 0, // second memory operand
2438 0, // second literal operand
2440 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2441 (PCC_REGISTER | PCC_STATUS), // outCond
2445 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2446 {PC_OPCODE, NULL, NULL, 0, NULL,
2453 NULL, // from branch
2460 0,0, // dest, bit instruction
2461 0,0, // branch, skip
2462 0, // literal operand
2463 1, // RAM access bit
2464 0, // fast call/return mode select bit
2465 0, // second memory operand
2466 0, // second literal operand
2468 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2469 (PCC_W | PCC_STATUS), // outCond
2473 pCodeInstruction pic16_pciSWAPF = {
2474 {PC_OPCODE, NULL, NULL, 0, NULL,
2481 NULL, // from branch
2488 1,0, // dest, bit instruction
2489 0,0, // branch, skip
2490 0, // literal operand
2491 1, // RAM access bit
2492 0, // fast call/return mode select bit
2493 0, // second memory operand
2494 0, // second literal operand
2496 (PCC_REGISTER), // inCond
2497 (PCC_REGISTER), // outCond
2501 pCodeInstruction pic16_pciSWAPFW = {
2502 {PC_OPCODE, NULL, NULL, 0, NULL,
2509 NULL, // from branch
2516 0,0, // dest, bit instruction
2517 0,0, // branch, skip
2518 0, // literal operand
2519 1, // RAM access bit
2520 0, // fast call/return mode select bit
2521 0, // second memory operand
2522 0, // second literal operand
2524 (PCC_REGISTER), // inCond
2529 pCodeInstruction pic16_pciTBLRD = { // patch 15
2530 {PC_OPCODE, NULL, NULL, 0, NULL,
2536 NULL, // from branch
2543 0,0, // dest, bit instruction
2544 0,0, // branch, skip
2545 0, // literal operand
2546 0, // RAM access bit
2547 0, // fast call/return mode select bit
2548 0, // second memory operand
2549 0, // second literal operand
2552 PCC_NONE , // outCond
2556 pCodeInstruction pic16_pciTBLRD_POSTINC = { // patch 15
2557 {PC_OPCODE, NULL, NULL, 0, NULL,
2563 NULL, // from branch
2570 0,0, // dest, bit instruction
2571 0,0, // branch, skip
2572 0, // literal operand
2573 0, // RAM access bit
2574 0, // fast call/return mode select bit
2575 0, // second memory operand
2576 0, // second literal operand
2579 PCC_NONE , // outCond
2583 pCodeInstruction pic16_pciTBLRD_POSTDEC = { // patch 15
2584 {PC_OPCODE, NULL, NULL, 0, NULL,
2590 NULL, // from branch
2597 0,0, // dest, bit instruction
2598 0,0, // branch, skip
2599 0, // literal operand
2600 0, // RAM access bit
2601 0, // fast call/return mode select bit
2602 0, // second memory operand
2603 0, // second literal operand
2606 PCC_NONE , // outCond
2610 pCodeInstruction pic16_pciTBLRD_PREINC = { // patch 15
2611 {PC_OPCODE, NULL, NULL, 0, NULL,
2617 NULL, // from branch
2624 0,0, // dest, bit instruction
2625 0,0, // branch, skip
2626 0, // literal operand
2627 0, // RAM access bit
2628 0, // fast call/return mode select bit
2629 0, // second memory operand
2630 0, // second literal operand
2633 PCC_NONE , // outCond
2637 pCodeInstruction pic16_pciTBLWT = { // patch 15
2638 {PC_OPCODE, NULL, NULL, 0, NULL,
2644 NULL, // from branch
2651 0,0, // dest, bit instruction
2652 0,0, // branch, skip
2653 0, // literal operand
2654 0, // RAM access bit
2655 0, // fast call/return mode select bit
2656 0, // second memory operand
2657 0, // second literal operand
2660 PCC_NONE , // outCond
2664 pCodeInstruction pic16_pciTBLWT_POSTINC = { // patch 15
2665 {PC_OPCODE, NULL, NULL, 0, NULL,
2671 NULL, // from branch
2678 0,0, // dest, bit instruction
2679 0,0, // branch, skip
2680 0, // literal operand
2681 0, // RAM access bit
2682 0, // fast call/return mode select bit
2683 0, // second memory operand
2684 0, // second literal operand
2687 PCC_NONE , // outCond
2691 pCodeInstruction pic16_pciTBLWT_POSTDEC = { // patch 15
2692 {PC_OPCODE, NULL, NULL, 0, NULL,
2698 NULL, // from branch
2705 0,0, // dest, bit instruction
2706 0,0, // branch, skip
2707 0, // literal operand
2708 0, // RAM access bit
2709 0, // fast call/return mode select bit
2710 0, // second memory operand
2711 0, // second literal operand
2714 PCC_NONE , // outCond
2718 pCodeInstruction pic16_pciTBLWT_PREINC = { // patch 15
2719 {PC_OPCODE, NULL, NULL, 0, NULL,
2725 NULL, // from branch
2732 0,0, // dest, bit instruction
2733 0,0, // branch, skip
2734 0, // literal operand
2735 0, // RAM access bit
2736 0, // fast call/return mode select bit
2737 0, // second memory operand
2738 0, // second literal operand
2741 PCC_NONE , // outCond
2745 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2746 {PC_OPCODE, NULL, NULL, 0, NULL,
2753 NULL, // from branch
2760 0,0, // dest, bit instruction
2761 1,1, // branch, skip
2762 0, // literal operand
2763 1, // RAM access bit
2764 0, // fast call/return mode select bit
2765 0, // second memory operand
2766 0, // second literal operand
2768 PCC_REGISTER, // inCond
2769 PCC_NONE, // outCond
2773 pCodeInstruction pic16_pciXORWF = {
2774 {PC_OPCODE, NULL, NULL, 0, NULL,
2781 NULL, // from branch
2788 1,0, // dest, bit instruction
2789 0,0, // branch, skip
2790 0, // literal operand
2791 1, // RAM access bit
2792 0, // fast call/return mode select bit
2793 0, // second memory operand
2794 0, // second literal operand
2796 (PCC_W | PCC_REGISTER), // inCond
2797 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2801 pCodeInstruction pic16_pciXORFW = {
2802 {PC_OPCODE, NULL, NULL, 0, NULL,
2809 NULL, // from branch
2816 0,0, // dest, bit instruction
2817 0,0, // branch, skip
2818 0, // literal operand
2819 1, // RAM access bit
2820 0, // fast call/return mode select bit
2821 0, // second memory operand
2822 0, // second literal operand
2824 (PCC_W | PCC_REGISTER), // inCond
2825 (PCC_W | PCC_Z | PCC_N), // outCond
2829 pCodeInstruction pic16_pciXORLW = {
2830 {PC_OPCODE, NULL, NULL, 0, NULL,
2837 NULL, // from branch
2844 0,0, // dest, bit instruction
2845 0,0, // branch, skip
2846 1, // literal operand
2847 1, // RAM access bit
2848 0, // fast call/return mode select bit
2849 0, // second memory operand
2850 0, // second literal operand
2852 (PCC_W | PCC_LITERAL), // inCond
2853 (PCC_W | PCC_Z | PCC_N), // outCond
2858 pCodeInstruction pic16_pciBANKSEL = {
2859 {PC_OPCODE, NULL, NULL, 0, NULL,
2865 NULL, // from branch
2872 0,0, // dest, bit instruction
2873 0,0, // branch, skip
2874 0, // literal operand
2875 0, // RAM access bit
2876 0, // fast call/return mode select bit
2877 0, // second memory operand
2878 0, // second literal operand
2881 PCC_NONE, // outCond
2886 #define MAX_PIC16MNEMONICS 100
2887 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2889 //#define USE_VSNPRINTF
2892 #ifdef USE_VSNPRINTF
2893 // Alas, vsnprintf is not ANSI standard, and does not exist
2894 // on Solaris (and probably other non-Gnu flavored Unixes).
2896 /*-----------------------------------------------------------------*/
2897 /* SAFE_snprintf - like snprintf except the string pointer is */
2898 /* after the string has been printed to. This is */
2899 /* useful for printing to string as though if it */
2900 /* were a stream. */
2901 /*-----------------------------------------------------------------*/
2902 void SAFE_snprintf(char **str, size_t *size, const char *format, ...)
2910 va_start(val, format);
2912 vsnprintf(*str, *size, format, val);
2918 fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2919 fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2928 // This version is *not* safe, despite the name.
2930 void SAFE_snprintf(char **str, size_t *size, const char *format, ...)
2934 static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2939 va_start(val, format);
2941 vsprintf(buffer, format, val);
2944 len = strlen(buffer);
2946 fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2947 fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2950 strcpy(*str, buffer);
2956 #endif // USE_VSNPRINTF
2959 extern set *externs;
2960 extern void pic16_initStack(int base_address, int size);
2961 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2962 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2963 extern void pic16_init_pic(char *);
2965 void pic16_pCodeInitRegisters(void)
2967 static int initialized=0;
2974 // pic16_initStack(0xfff, 8);
2975 pic16_init_pic(port->processor);
2977 pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2978 pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2979 pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2980 pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2981 pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2982 pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2983 pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2985 pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2986 pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2987 pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2989 pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2990 pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2991 pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2992 pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2994 pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2995 pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2996 pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2997 pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2998 pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2999 pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
3001 pic16_stackpnt_lo = &pic16_pc_fsr1l;
3002 pic16_stackpnt_hi = &pic16_pc_fsr1h;
3003 pic16_stack_postdec = &pic16_pc_postdec1;
3004 pic16_stack_postinc = &pic16_pc_postinc1;
3005 pic16_stack_preinc = &pic16_pc_preinc1;
3006 pic16_stack_plusw = &pic16_pc_plusw1;
3008 pic16_framepnt_lo = &pic16_pc_fsr2l;
3009 pic16_framepnt_hi = &pic16_pc_fsr2h;
3010 pic16_frame_postdec = &pic16_pc_postdec2;
3011 pic16_frame_postinc = &pic16_pc_postinc2;
3012 pic16_frame_preinc = &pic16_pc_preinc2;
3013 pic16_frame_plusw = &pic16_pc_plusw2;
3015 pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3016 pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3017 pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3018 pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3019 pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3021 pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3022 pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3023 pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3024 pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3025 pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3027 pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3028 pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3029 pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3030 pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3031 pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3033 pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3034 pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3037 pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3038 pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3039 pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3040 pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3043 pic16_pc_status.rIdx = IDX_STATUS;
3044 pic16_pc_intcon.rIdx = IDX_INTCON;
3045 pic16_pc_pcl.rIdx = IDX_PCL;
3046 pic16_pc_pclath.rIdx = IDX_PCLATH;
3047 pic16_pc_pclatu.rIdx = IDX_PCLATU;
3048 pic16_pc_wreg.rIdx = IDX_WREG;
3049 pic16_pc_bsr.rIdx = IDX_BSR;
3051 pic16_pc_tosl.rIdx = IDX_TOSL;
3052 pic16_pc_tosh.rIdx = IDX_TOSH;
3053 pic16_pc_tosu.rIdx = IDX_TOSU;
3055 pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3056 pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3057 pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3058 pic16_pc_tablat.rIdx = IDX_TABLAT;
3060 pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3061 pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3062 pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3063 pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3064 pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3065 pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3066 pic16_pc_indf0.rIdx = IDX_INDF0;
3067 pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3068 pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3069 pic16_pc_preinc0.rIdx = IDX_PREINC0;
3070 pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3071 pic16_pc_indf1.rIdx = IDX_INDF1;
3072 pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3073 pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3074 pic16_pc_preinc1.rIdx = IDX_PREINC1;
3075 pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3076 pic16_pc_indf2.rIdx = IDX_INDF2;
3077 pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3078 pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3079 pic16_pc_preinc2.rIdx = IDX_PREINC2;
3080 pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3081 pic16_pc_prodl.rIdx = IDX_PRODL;
3082 pic16_pc_prodh.rIdx = IDX_PRODH;
3084 pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3085 pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3086 pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3088 pic16_pc_kzero.rIdx = IDX_KZ;
3089 pic16_pc_wsave.rIdx = IDX_WSAVE;
3090 pic16_pc_ssave.rIdx = IDX_SSAVE;
3092 pic16_pc_eecon1.rIdx = IDX_EECON1;
3093 pic16_pc_eecon2.rIdx = IDX_EECON2;
3094 pic16_pc_eedata.rIdx = IDX_EEDATA;
3095 pic16_pc_eeadr.rIdx = IDX_EEADR;
3098 pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3099 pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3101 pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3102 pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3104 /* probably should put this in a separate initialization routine */
3105 pb_dead_pcodes = newpBlock();
3110 /*-----------------------------------------------------------------*/
3111 /* mnem2key - convert a pic mnemonic into a hash key */
3112 /* (BTW - this spreads the mnemonics quite well) */
3114 /*-----------------------------------------------------------------*/
3116 int mnem2key(unsigned char const *mnem)
3125 key += toupper(*mnem++) +1;
3129 return (key & 0x1f);
3134 void pic16initMnemonics(void)
3139 pCodeInstruction *pci;
3141 if(mnemonics_initialized)
3144 // NULL out the array before making the assignments
3145 // since we check the array contents below this initialization.
3147 for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3148 pic16Mnemonics[i] = NULL;
3151 pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3152 pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3153 pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3154 pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3155 pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3156 pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3157 pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3158 pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3159 pic16Mnemonics[POC_BC] = &pic16_pciBC;
3160 pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3161 pic16Mnemonics[POC_BN] = &pic16_pciBN;
3162 pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3163 pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3164 pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3165 pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3166 pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3167 pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3168 pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3169 pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3170 pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3171 pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3172 pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3173 pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3174 pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3175 pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3176 pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3177 pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3178 pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3179 pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3180 pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3181 pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3182 pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3183 pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3184 pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3185 pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3186 pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3187 pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3188 pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3189 pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3190 pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3191 pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3192 pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3193 pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3194 pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3195 pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3196 pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3197 pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3198 pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3199 pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3200 pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3201 pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3202 pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3203 pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3204 pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3205 pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3206 pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3207 pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3208 pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3209 pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3210 pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3211 pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3212 pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3213 pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3214 pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3215 pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3216 pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3217 pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3218 pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3219 pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3220 pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3221 pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3222 pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3223 pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3224 pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3225 pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3226 pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3227 pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3228 pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3229 pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3230 pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3231 pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3232 pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3233 pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3234 pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3235 pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3236 pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3237 pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3238 pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3239 pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3240 pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3241 pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3242 pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3243 pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3244 pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3246 for(i=0; i<MAX_PIC16MNEMONICS; i++)
3247 if(pic16Mnemonics[i])
3248 hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3249 pci = hTabFirstItem(pic16MnemonicsHash, &key);
3252 DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3253 pci = hTabNextItem(pic16MnemonicsHash, &key);
3256 mnemonics_initialized = 1;
3259 int pic16_getpCodePeepCommand(char *cmd);
3261 int pic16_getpCode(char *mnem,unsigned dest)
3264 pCodeInstruction *pci;
3265 int key = mnem2key((unsigned char *)mnem);
3267 if(!mnemonics_initialized)
3268 pic16initMnemonics();
3270 pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3274 if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3275 if((pci->num_ops <= 1)
3276 || (pci->isModReg == dest)
3278 || (pci->num_ops <= 2 && pci->isAccess)
3279 || (pci->num_ops <= 2 && pci->isFastCall)
3280 || (pci->num_ops <= 2 && pci->is2MemOp)
3281 || (pci->num_ops <= 2 && pci->is2LitOp) )
3285 pci = hTabNextItemWK (pic16MnemonicsHash);
3292 /*-----------------------------------------------------------------*
3293 * pic16initpCodePeepCommands
3295 *-----------------------------------------------------------------*/
3296 void pic16initpCodePeepCommands(void)
3304 hTabAddItem(&pic16pCodePeepCommandsHash,
3305 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3307 } while (peepCommands[i].cmd);
3309 pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3312 //fprintf(stderr, "peep command %s key %d\n",pcmd->cmd,pcmd->id);
3313 pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3318 /*-----------------------------------------------------------------
3321 *-----------------------------------------------------------------*/
3323 int pic16_getpCodePeepCommand(char *cmd)
3327 int key = mnem2key((unsigned char *)cmd);
3330 pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3333 // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3334 if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3338 pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3345 static char getpBlock_dbName(pBlock *pb)
3351 return pb->cmemmap->dbName;
3355 void pic16_pBlockConvert2ISR(pBlock *pb)
3359 if(pb->cmemmap)pb->cmemmap = NULL;
3363 if(pic16_pcode_verbose)
3364 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3367 void pic16_pBlockConvert2Absolute(pBlock *pb)
3370 if(pb->cmemmap)pb->cmemmap = NULL;
3374 if(pic16_pcode_verbose)
3375 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3378 /*-----------------------------------------------------------------*/
3379 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all */
3380 /* instances to the front of the doubly linked */
3381 /* list of pBlocks */
3382 /*-----------------------------------------------------------------*/
3384 void pic16_movepBlock2Head(char dbName)
3389 /* this can happen in sources without code,
3390 * only variable definitions */
3391 if(!the_pFile)return;
3393 pb = the_pFile->pbHead;
3397 if(getpBlock_dbName(pb) == dbName) {
3398 pBlock *pbn = pb->next;
3399 pb->next = the_pFile->pbHead;
3400 the_pFile->pbHead->prev = pb;
3401 the_pFile->pbHead = pb;
3404 pb->prev->next = pbn;
3406 // If the pBlock that we just moved was the last
3407 // one in the link of all of the pBlocks, then we
3408 // need to point the tail to the block just before
3409 // the one we moved.
3410 // Note: if pb->next is NULL, then pb must have
3411 // been the last pBlock in the chain.
3414 pbn->prev = pb->prev;
3416 the_pFile->pbTail = pb->prev;
3427 void pic16_copypCode(FILE *of, char dbName)
3431 if(!of || !the_pFile)
3434 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3435 if(getpBlock_dbName(pb) == dbName) {
3436 // fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3438 pic16_printpBlock(of,pb);
3443 void pic16_pcode_test(void)
3446 DFPRINTF((stderr,"pcode is alive!\n"));
3456 /* create the file name */
3457 strcpy(buffer,dstFileName);
3458 strcat(buffer,".p");
3460 if( !(pFile = fopen(buffer, "w" ))) {
3461 werror(E_FILE_OPEN_ERR,buffer);
3465 fprintf(pFile,"pcode dump\n\n");
3467 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3468 fprintf(pFile,"\n\tNew pBlock\n\n");
3470 fprintf(pFile,"%s",pb->cmemmap->sname);
3472 fprintf(pFile,"internal pblock");
3474 fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3475 pic16_printpBlock(pFile,pb);
3481 unsigned long pic16_countInstructions(void)
3485 unsigned long isize=0;
3487 if(!the_pFile)return -1;
3489 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3490 for(pc = pb->pcHead; pc; pc = pc->next) {
3491 if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3498 /*-----------------------------------------------------------------*/
3499 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg- */
3500 /* ister, RegCond will return the bit being referenced. */
3502 /* fixme - why not just OR in the pcop bit field */
3503 /*-----------------------------------------------------------------*/
3505 static int RegCond(pCodeOp *pcop)
3511 if(!pcop->name)return 0;
3513 if(pcop->type == PO_GPR_BIT && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3514 switch(PCORB(pcop)->bit) {
3529 /*-----------------------------------------------------------------*/
3530 /* pic16_newpCode - create and return a newly initialized pCode */
3532 /* fixme - rename this */
3534 /* The purpose of this routine is to create a new Instruction */
3535 /* pCode. This is called by gen.c while the assembly code is being */
3539 /* PIC_OPCODE op - the assembly instruction we wish to create. */
3540 /* (note that the op is analogous to but not the */
3541 /* same thing as the opcode of the instruction.) */
3542 /* pCdoeOp *pcop - pointer to the operand of the instruction. */
3545 /* a pointer to the new malloc'd pCode is returned. */
3549 /*-----------------------------------------------------------------*/
3550 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3552 pCodeInstruction *pci ;
3554 if(!mnemonics_initialized)
3555 pic16initMnemonics();
3557 pci = Safe_calloc(1, sizeof(pCodeInstruction));
3559 if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3560 memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3563 if(pci->inCond & PCC_EXAMINE_PCOP)
3564 pci->inCond |= RegCond(pcop);
3566 if(pci->outCond & PCC_EXAMINE_PCOP)
3567 pci->outCond |= RegCond(pcop);
3569 pci->pc.prev = pci->pc.next = NULL;
3570 return (pCode *)pci;
3573 fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3579 /*-----------------------------------------------------------------*/
3580 /* pic16_newpCodeWild - create a "wild" as in wild card pCode */
3582 /* Wild pcodes are used during the peep hole optimizer to serve */
3583 /* as place holders for any instruction. When a snippet of code is */
3584 /* compared to a peep hole rule, the wild card opcode will match */
3585 /* any instruction. However, the optional operand and label are */
3586 /* additional qualifiers that must also be matched before the */
3587 /* line (of assembly code) is declared matched. Note that the */
3588 /* operand may be wild too. */
3590 /* Note, a wild instruction is specified just like a wild var: */
3591 /* %4 ; A wild instruction, */
3592 /* See the peeph.def file for additional examples */
3594 /*-----------------------------------------------------------------*/
3596 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3601 pcw = Safe_calloc(1,sizeof(pCodeWild));
3603 pcw->pci.pc.type = PC_WILD;
3604 pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3605 pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3606 pcw->pci.pc.pb = NULL;
3608 // pcw->pci.pc.analyze = genericAnalyze;
3609 pcw->pci.pc.destruct = genericDestruct;
3610 pcw->pci.pc.print = genericPrint;
3612 pcw->id = pCodeID; // this is the 'n' in %n
3613 pcw->operand = optional_operand;
3614 pcw->label = optional_label;
3616 pcw->mustBeBitSkipInst = 0;
3617 pcw->mustNotBeBitSkipInst = 0;
3618 pcw->invertBitSkipInst = 0;
3620 return ( (pCode *)pcw);
3624 /*-----------------------------------------------------------------*/
3625 /* newPcodeInlineP - create a new pCode from a char string */
3626 /*-----------------------------------------------------------------*/
3629 pCode *pic16_newpCodeInlineP(char *cP)
3634 pcc = Safe_calloc(1,sizeof(pCodeComment));
3636 pcc->pc.type = PC_INLINE;
3637 pcc->pc.prev = pcc->pc.next = NULL;
3638 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3641 // pcc->pc.analyze = genericAnalyze;
3642 pcc->pc.destruct = genericDestruct;
3643 pcc->pc.print = genericPrint;
3646 pcc->comment = Safe_strdup(cP);
3648 pcc->comment = NULL;
3650 return ( (pCode *)pcc);
3654 /*-----------------------------------------------------------------*/
3655 /* newPcodeCharP - create a new pCode from a char string */
3656 /*-----------------------------------------------------------------*/
3658 pCode *pic16_newpCodeCharP(char *cP)
3663 pcc = Safe_calloc(1,sizeof(pCodeComment));
3665 pcc->pc.type = PC_COMMENT;
3666 pcc->pc.prev = pcc->pc.next = NULL;
3667 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3670 // pcc->pc.analyze = genericAnalyze;
3671 pcc->pc.destruct = genericDestruct;
3672 pcc->pc.print = genericPrint;
3675 pcc->comment = Safe_strdup(cP);
3677 pcc->comment = NULL;
3679 return ( (pCode *)pcc);
3683 /*-----------------------------------------------------------------*/
3684 /* pic16_newpCodeFunction - */
3685 /*-----------------------------------------------------------------*/
3688 pCode *pic16_newpCodeFunction(char *mod,char *f)
3692 pcf = Safe_calloc(1,sizeof(pCodeFunction));
3694 pcf->pc.type = PC_FUNCTION;
3695 pcf->pc.prev = pcf->pc.next = NULL;
3696 //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3699 // pcf->pc.analyze = genericAnalyze;
3700 pcf->pc.destruct = genericDestruct;
3701 pcf->pc.print = pCodePrintFunction;
3707 pcf->modname = Safe_calloc(1,strlen(mod)+1);
3708 strcpy(pcf->modname,mod);
3710 pcf->modname = NULL;
3713 pcf->fname = Safe_calloc(1,strlen(f)+1);
3714 strcpy(pcf->fname,f);
3718 pcf->stackusage = 0;
3720 return ( (pCode *)pcf);
3723 /*-----------------------------------------------------------------*/
3724 /* pic16_newpCodeFlow */
3725 /*-----------------------------------------------------------------*/
3726 static void destructpCodeFlow(pCode *pc)
3728 if(!pc || !isPCFL(pc))
3735 pic16_unlinkpCode(pc);
3737 deleteSet(&PCFL(pc)->registers);
3738 deleteSet(&PCFL(pc)->from);
3739 deleteSet(&PCFL(pc)->to);
3741 /* Instead of deleting the memory used by this pCode, mark
3742 * the object as bad so that if there's a pointer to this pCode
3743 * dangling around somewhere then (hopefully) when the type is
3744 * checked we'll catch it.
3748 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3754 pCode *pic16_newpCodeFlow(void )
3758 //_ALLOC(pcflow,sizeof(pCodeFlow));
3759 pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3761 pcflow->pc.type = PC_FLOW;
3762 pcflow->pc.prev = pcflow->pc.next = NULL;
3763 pcflow->pc.pb = NULL;
3765 // pcflow->pc.analyze = genericAnalyze;
3766 pcflow->pc.destruct = destructpCodeFlow;
3767 pcflow->pc.print = genericPrint;
3769 pcflow->pc.seq = GpcFlowSeq++;
3771 pcflow->from = pcflow->to = NULL;
3773 pcflow->inCond = PCC_NONE;
3774 pcflow->outCond = PCC_NONE;
3776 pcflow->firstBank = -1;
3777 pcflow->lastBank = -1;
3779 pcflow->FromConflicts = 0;
3780 pcflow->ToConflicts = 0;
3784 pcflow->registers = newSet();
3786 return ( (pCode *)pcflow);
3790 /*-----------------------------------------------------------------*/
3791 /*-----------------------------------------------------------------*/
3792 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3794 pCodeFlowLink *pcflowLink;
3796 pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3798 pcflowLink->pcflow = pcflow;
3799 pcflowLink->bank_conflict = 0;
3804 /*-----------------------------------------------------------------*/
3805 /* pic16_newpCodeCSource - create a new pCode Source Symbol */
3806 /*-----------------------------------------------------------------*/
3808 pCode *pic16_newpCodeCSource(int ln, char *f, char *l)
3813 pccs = Safe_calloc(1,sizeof(pCodeCSource));
3815 pccs->pc.type = PC_CSOURCE;
3816 pccs->pc.prev = pccs->pc.next = NULL;
3819 pccs->pc.destruct = genericDestruct;
3820 pccs->pc.print = genericPrint;
3822 pccs->line_number = ln;
3824 pccs->line = Safe_strdup(l);
3829 pccs->file_name = Safe_strdup(f);
3831 pccs->file_name = NULL;
3833 return ( (pCode *)pccs);
3838 /*******************************************************************/
3839 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive */
3840 /* added by VR 6-Jun-2003 */
3841 /*******************************************************************/
3843 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3850 pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3851 pcad->pci.pc.type = PC_ASMDIR;
3852 pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3853 pcad->pci.pc.pb = NULL;
3854 pcad->pci.isize = 2;
3855 pcad->pci.pc.destruct = genericDestruct;
3856 pcad->pci.pc.print = genericPrint;
3858 if(asdir && *asdir) {
3860 while(isspace((unsigned char)*asdir))asdir++; // strip any white space from the beginning
3862 pcad->directive = Safe_strdup( asdir );
3865 va_start(ap, argfmt);
3867 memset(buffer, 0, sizeof(buffer));
3868 if(argfmt && *argfmt)
3869 vsprintf(buffer, argfmt, ap);
3873 while(isspace((unsigned char)*lbp))lbp++;
3876 pcad->arg = Safe_strdup( lbp );
3878 return ((pCode *)pcad);
3881 /*-----------------------------------------------------------------*/
3882 /* pCodeLabelDestruct - free memory used by a label. */
3883 /*-----------------------------------------------------------------*/
3884 static void pCodeLabelDestruct(pCode *pc)
3890 // if((pc->type == PC_LABEL) && PCL(pc)->label)
3891 // Safe_free(PCL(pc)->label);
3893 /* Instead of deleting the memory used by this pCode, mark
3894 * the object as bad so that if there's a pointer to this pCode
3895 * dangling around somewhere then (hopefully) when the type is
3896 * checked we'll catch it.
3900 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3906 pCode *pic16_newpCodeLabel(char *name, int key)
3912 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3914 pcl->pc.type = PC_LABEL;
3915 pcl->pc.prev = pcl->pc.next = NULL;
3916 //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3919 // pcl->pc.analyze = genericAnalyze;
3920 pcl->pc.destruct = pCodeLabelDestruct;
3921 pcl->pc.print = pCodePrintLabel;
3928 sprintf(s,"_%05d_DS_",key);
3933 pcl->label = Safe_strdup(s);
3935 // if(pic16_pcode_verbose)
3936 // fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3939 return ( (pCode *)pcl);
3943 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3945 pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3949 return ( (pCode *)pcl );
3952 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3956 pci = Safe_calloc(1, sizeof(pCodeInfo));
3957 pci->pci.pc.type = PC_INFO;
3958 pci->pci.pc.prev = pci->pci.pc.next = NULL;
3959 pci->pci.pc.pb = NULL;
3960 pci->pci.label = NULL;
3962 pci->pci.pc.destruct = genericDestruct;
3963 pci->pci.pc.print = genericPrint;
3968 return ((pCode *)pci);
3972 /*-----------------------------------------------------------------*/
3973 /* newpBlock - create and return a pointer to a new pBlock */
3974 /*-----------------------------------------------------------------*/
3975 static pBlock *newpBlock(void)
3980 PpB = Safe_calloc(1,sizeof(pBlock) );
3981 PpB->next = PpB->prev = NULL;
3983 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3984 PpB->tregisters = NULL;
3986 PpB->FlowTree = NULL;
3992 /*-----------------------------------------------------------------*/
3993 /* pic16_newpCodeChain - create a new chain of pCodes */
3994 /*-----------------------------------------------------------------*
3996 * This function will create a new pBlock and the pointer to the
3997 * pCode that is passed in will be the first pCode in the block.
3998 *-----------------------------------------------------------------*/
4001 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
4004 pBlock *pB = newpBlock();
4006 pB->pcHead = pB->pcTail = pc;
4015 /*-----------------------------------------------------------------*/
4016 /* pic16_newpCodeOpLabel - Create a new label given the key */
4017 /* Note, a negative key means that the label is part of wild card */
4018 /* (and hence a wild card label) used in the pCodePeep */
4019 /* optimizations). */
4020 /*-----------------------------------------------------------------*/
4022 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4025 static int label_key=-1;
4029 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4030 pcop->type = PO_LABEL;
4035 sprintf(s=buffer,"_%05d_DS_",key);
4037 s = name, key = label_key--;
4040 pcop->name = Safe_strdup(s);
4042 ((pCodeOpLabel *)pcop)->key = key;
4044 //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4048 /*-----------------------------------------------------------------*/
4049 /*-----------------------------------------------------------------*/
4050 pCodeOp *pic16_newpCodeOpLit(int lit)
4056 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4057 pcop->type = PO_LITERAL;
4061 sprintf(s,"0x%02hhx", (unsigned char)lit);
4063 // sprintf(s, "%i", lit);
4066 pcop->name = Safe_strdup(s);
4068 ((pCodeOpLit *)pcop)->lit = lit;
4073 /* Allow for 12 bit literals, required for LFSR */
4074 pCodeOp *pic16_newpCodeOpLit12(int lit)
4080 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4081 pcop->type = PO_LITERAL;
4085 sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4087 // sprintf(s, "%i", lit);
4090 pcop->name = Safe_strdup(s);
4092 ((pCodeOpLit *)pcop)->lit = lit;
4097 /*-----------------------------------------------------------------*/
4098 /*-----------------------------------------------------------------*/
4099 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4101 char *s = buffer, tbuf[256], *tb=tbuf;
4105 tb = pic16_get_op(arg2, NULL, 0);
4106 pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4107 pcop->type = PO_LITERAL;
4111 sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4113 pcop->name = Safe_strdup(s);
4116 ((pCodeOpLit2 *)pcop)->lit = lit;
4117 ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4122 /*-----------------------------------------------------------------*/
4123 /*-----------------------------------------------------------------*/
4124 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4128 pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4129 pcop->type = PO_IMMEDIATE;
4131 regs *r = pic16_dirregWithName(name);
4132 pcop->name = Safe_strdup(name);
4136 // fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4137 PCOI(pcop)->rIdx = r->rIdx;
4139 // fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4140 PCOI(pcop)->rIdx = -1;
4142 // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4145 PCOI(pcop)->rIdx = -1;
4148 PCOI(pcop)->index = index;
4149 PCOI(pcop)->offset = offset;
4150 PCOI(pcop)->_const = code_space;
4155 /*-----------------------------------------------------------------*/
4156 /*-----------------------------------------------------------------*/
4157 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4163 if(!pcwb || !subtype) {
4164 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4168 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4169 pcop->type = PO_WILD;
4170 sprintf(s,"%%%d",id);
4171 pcop->name = Safe_strdup(s);
4173 PCOW(pcop)->id = id;
4174 PCOW(pcop)->pcwb = pcwb;
4175 PCOW(pcop)->subtype = subtype;
4176 PCOW(pcop)->matched = NULL;
4178 PCOW(pcop)->pcop2 = NULL;
4183 /*-----------------------------------------------------------------*/
4184 /*-----------------------------------------------------------------*/
4185 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4191 if(!pcwb || !subtype || !subtype2) {
4192 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4196 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4197 pcop->type = PO_WILD;
4198 sprintf(s,"%%%d",id);
4199 pcop->name = Safe_strdup(s);
4201 PCOW(pcop)->id = id;
4202 PCOW(pcop)->pcwb = pcwb;
4203 PCOW(pcop)->subtype = subtype;
4204 PCOW(pcop)->matched = NULL;
4206 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4208 if(!subtype2->name) {
4209 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4210 PCOW2(pcop)->pcop.type = PO_WILD;
4211 sprintf(s, "%%%d", id2);
4212 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4213 PCOW2(pcop)->id = id2;
4214 PCOW2(pcop)->subtype = subtype2;
4216 // fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4217 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4219 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4221 // fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4222 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4231 /*-----------------------------------------------------------------*/
4232 /*-----------------------------------------------------------------*/
4233 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4237 pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4238 pcop->type = PO_GPR_BIT;
4240 pcop->name = Safe_strdup(s);
4244 PCORB(pcop)->bit = bit;
4245 PCORB(pcop)->inBitSpace = inBitSpace;
4246 PCORB(pcop)->subtype = subt;
4248 /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4249 PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4250 // fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4251 // PCOR(pcop)->rIdx = 0;
4255 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4257 return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4258 bit, 0, PO_GPR_REGISTER);
4262 /*-----------------------------------------------------------------*
4263 * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4265 * If rIdx >=0 then a specific register from the set of registers
4266 * will be selected. If rIdx <0, then a new register will be searched
4268 *-----------------------------------------------------------------*/
4270 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4275 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4280 r = pic16_regWithIdx(rIdx);
4282 r = pic16_allocWithIdx(rIdx);
4284 r = pic16_findFreeReg(REG_GPR);
4287 fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4288 __FUNCTION__, __LINE__);
4293 PCOR(pcop)->rIdx = rIdx;
4295 pcop->type = PCOR(pcop)->r->pc_type;
4300 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4305 pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4308 r = pic16_findFreeReg(REG_GPR);
4311 if(!bitVectBitValue(bv, r->rIdx)) {
4313 PCOR(pcop)->rIdx = r->rIdx;
4314 pcop->type = r->pc_type;
4318 r = pic16_findFreeRegNext(REG_GPR, r);
4326 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4331 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4332 PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4333 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4334 pcop->type = PCOR(pcop)->r->pc_type;
4335 pcop->name = PCOR(pcop)->r->name;
4337 // if(pic16_pcode_verbose) {
4338 // fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4339 // __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4345 /*-----------------------------------------------------------------*/
4346 /*-----------------------------------------------------------------*/
4347 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4351 pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4354 pcop->key = Safe_strdup( key );
4356 return (PCOP(pcop));
4359 /*-----------------------------------------------------------------*/
4360 /*-----------------------------------------------------------------*/
4361 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4363 pCodeOpLocalReg *pcop;
4365 pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4369 return (PCOP(pcop));
4373 /*-----------------------------------------------------------------*/
4374 /*-----------------------------------------------------------------*/
4376 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4383 pcop = pic16_newpCodeOpBit(name, -1,0, type);
4387 pcop = pic16_newpCodeOpLit(-1);
4391 pcop = pic16_newpCodeOpLabel(NULL,-1);
4394 pcop = pic16_newpCodeOpReg(-1);
4397 case PO_GPR_REGISTER:
4399 pcop = pic16_newpCodeOpRegFromStr(name);
4401 pcop = pic16_newpCodeOpReg(-1);
4405 assert( !"Cannot create PO_TWO_OPS from string!" );
4410 pcop = Safe_calloc(1,sizeof(pCodeOp) );
4413 pcop->name = Safe_strdup(name);
4421 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4423 pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4424 pcop2->pcop.type = PO_TWO_OPS;
4430 /* This is a multiple of two as gpasm pads DB directives to even length,
4431 * thus the data would be interleaved with \0 bytes...
4432 * This is a multiple of three in order to have arrays of 3-byte pointers
4433 * continuously in memory (without 0-padding at the lines' end).
4434 * This is rather 12 than 6 in order not to split up 4-byte data types
4435 * in arrays right in the middle of a 4-byte word. */
4436 #define DB_ITEMS_PER_LINE 12
4438 typedef struct DBdata
4445 static int DBd_init = -1;
4447 /*-----------------------------------------------------------------*/
4448 /* Initialiase "DB" data buffer */
4449 /*-----------------------------------------------------------------*/
4450 void pic16_initDB(void)
4456 /*-----------------------------------------------------------------*/
4457 /* Flush pending "DB" data to a pBlock */
4459 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4460 /*-----------------------------------------------------------------*/
4461 void pic16_flushDB(char ptype, void *p)
4465 pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4468 fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4471 fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4475 DBd.buffer[0] = '\0';
4480 /*-----------------------------------------------------------------*/
4481 /* Add "DB" directives to a pBlock */
4482 /*-----------------------------------------------------------------*/
4483 void pic16_emitDB(int c, char ptype, void *p)
4488 // we need to initialize
4491 DBd.buffer[0] = '\0';
4494 l = strlen(DBd.buffer);
4495 sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4497 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4500 if (DBd.count>= DB_ITEMS_PER_LINE)
4501 pic16_flushDB(ptype, p);
4504 void pic16_emitDS(char *s, char ptype, void *p)
4509 // we need to initialize
4512 DBd.buffer[0] = '\0';
4515 l = strlen(DBd.buffer);
4516 sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4518 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4520 DBd.count++; //=strlen(s);
4521 if (DBd.count>=DB_ITEMS_PER_LINE)
4522 pic16_flushDB(ptype, p);
4526 /*-----------------------------------------------------------------*/
4527 /*-----------------------------------------------------------------*/
4528 void pic16_pCodeConstString(char *name, char *value)
4532 static set *emittedSymbols = NULL;
4537 /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4538 if (emittedSymbols) {
4539 /* scan set for name */
4540 for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4542 if (!strcmp (item,name)) {
4543 //fprintf (stderr, "%s already emitted\n", name);
4548 addSet (&emittedSymbols, Safe_strdup (name));
4550 //fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value);
4552 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4554 pic16_addpBlock(pb);
4556 // sprintf(buffer,"; %s = ", name);
4557 // strcat(buffer, value);
4558 // fputs(buffer, stderr);
4560 // pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4561 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4564 pic16_emitDB(*value, 'p', (void *)pb);
4566 pic16_flushDB('p', (void *)pb);
4569 /*-----------------------------------------------------------------*/
4570 /*-----------------------------------------------------------------*/
4572 static void pCodeReadCodeTable(void)
4576 fprintf(stderr, " %s\n",__FUNCTION__);
4578 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4580 pic16_addpBlock(pb);
4582 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4583 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4584 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4585 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4587 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4588 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4589 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4590 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4595 /*-----------------------------------------------------------------*/
4596 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */
4597 /*-----------------------------------------------------------------*/
4598 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4605 /* If this is the first pcode to be added to a block that
4606 * was initialized with a NULL pcode, then go ahead and
4607 * make this pcode the head and tail */
4608 pb->pcHead = pb->pcTail = pc;
4611 pb->pcTail->next = pc;
4613 pc->prev = pb->pcTail;
4620 /*-----------------------------------------------------------------*/
4621 /* pic16_addpBlock - place a pBlock into the pFile */
4622 /*-----------------------------------------------------------------*/
4623 void pic16_addpBlock(pBlock *pb)
4625 // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4628 /* First time called, we'll pass through here. */
4629 //_ALLOC(the_pFile,sizeof(pFile));
4630 the_pFile = Safe_calloc(1,sizeof(pFile));
4631 the_pFile->pbHead = the_pFile->pbTail = pb;
4632 the_pFile->functions = NULL;
4636 the_pFile->pbTail->next = pb;
4637 pb->prev = the_pFile->pbTail;
4639 the_pFile->pbTail = pb;
4642 /*-----------------------------------------------------------------*/
4643 /* removepBlock - remove a pBlock from the pFile */
4644 /*-----------------------------------------------------------------*/
4645 static void removepBlock(pBlock *pb)
4653 //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4655 for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4658 if(pbs == the_pFile->pbHead)
4659 the_pFile->pbHead = pbs->next;
4661 if (pbs == the_pFile->pbTail)
4662 the_pFile->pbTail = pbs->prev;
4665 pbs->next->prev = pbs->prev;
4668 pbs->prev->next = pbs->next;
4675 fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4679 /*-----------------------------------------------------------------*/
4680 /* printpCode - write the contents of a pCode to a file */
4681 /*-----------------------------------------------------------------*/
4682 static void printpCode(FILE *of, pCode *pc)
4693 fprintf(of,"warning - unable to print pCode\n");
4696 /*-----------------------------------------------------------------*/
4697 /* pic16_printpBlock - write the contents of a pBlock to a file */
4698 /*-----------------------------------------------------------------*/
4699 void pic16_printpBlock(FILE *of, pBlock *pb)
4707 for(pc = pb->pcHead; pc; pc = pc->next) {
4708 if(isPCF(pc) && PCF(pc)->fname) {
4709 fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4710 if(pb->dbName == 'A') {
4712 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4713 // fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4714 if(!strcmp(ab->name, PCF(pc)->fname)) {
4715 // fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4716 if(ab->address != -1)
4717 fprintf(of, "\t0X%06X", ab->address);
4728 /*-----------------------------------------------------------------*/
4730 /* pCode processing */
4734 /*-----------------------------------------------------------------*/
4735 pCode * pic16_findNextInstruction(pCode *pci);
4736 pCode * pic16_findPrevInstruction(pCode *pci);
4738 void pic16_unlinkpCode(pCode *pc)
4744 fprintf(stderr,"Unlinking: ");
4745 printpCode(stderr, pc);
4748 pc->prev->next = pc->next;
4750 pc->next->prev = pc->prev;
4752 /* move C source line down (or up) */
4753 if (isPCI(pc) && PCI(pc)->cline) {
4754 prev = pic16_findNextInstruction (pc->next);
4755 if (prev && isPCI(prev) && !PCI(prev)->cline) {
4756 PCI(prev)->cline = PCI(pc)->cline;
4758 prev = pic16_findPrevInstruction (pc->prev);
4759 if (prev && isPCI(prev) && !PCI(prev)->cline)
4760 PCI(prev)->cline = PCI(pc)->cline;
4763 pc->prev = pc->next = NULL;
4767 /*-----------------------------------------------------------------*/
4768 /*-----------------------------------------------------------------*/
4770 static void genericDestruct(pCode *pc)
4773 pic16_unlinkpCode(pc);
4776 /* For instructions, tell the register (if there's one used)
4777 * that it's no longer needed */
4778 regs *reg = pic16_getRegFromInstruction(pc);
4780 deleteSetItem (&(reg->reglives.usedpCodes),pc);
4782 if(PCI(pc)->is2MemOp) {
4783 reg = pic16_getRegFromInstruction2(pc);
4785 deleteSetItem(&(reg->reglives.usedpCodes), pc);
4789 /* Instead of deleting the memory used by this pCode, mark
4790 * the object as bad so that if there's a pointer to this pCode
4791 * dangling around somewhere then (hopefully) when the type is
4792 * checked we'll catch it.
4796 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4802 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4803 /*-----------------------------------------------------------------*/
4804 /*-----------------------------------------------------------------*/
4805 /* modifiers for constant immediate */
4806 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4808 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4813 int use_buffer = 1; // copy the string to the passed buffer pointer
4818 use_buffer = 0; // Don't bother copying the string to the buffer.
4823 switch(pcop->type) {
4831 SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4834 return (PCOR(pcop)->r->name);
4837 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4839 SAFE_snprintf(&buffer,&size,"%s",r->name);
4846 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4847 if(PCOI(pcop)->index) {
4848 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4849 immdmod[ PCOI(pcop)->offset ],
4853 SAFE_snprintf(&s,&size,"%s(%s)",
4854 immdmod[ PCOI(pcop)->offset ],
4858 if(PCOI(pcop)->index) {
4859 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4864 SAFE_snprintf(&s,&size, "%s(%s)",
4871 case PO_GPR_REGISTER:
4874 // size = sizeof(buffer);
4875 if( PCOR(pcop)->instance) {
4876 SAFE_snprintf(&s,&size,"(%s + %d)",
4878 PCOR(pcop)->instance );
4880 SAFE_snprintf(&s,&size,"%s",pcop->name);
4885 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4886 SAFE_snprintf(&s, &size, "%s", pcop->name);
4888 if(PCORB(pcop)->pcor.instance)
4889 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4891 SAFE_snprintf(&s, &size, "%s", pcop->name);
4896 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4901 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4904 return (pcop->name);
4908 return ("unhandled type for op1");
4911 return ("NO operand1");
4914 /*-----------------------------------------------------------------*/
4915 /* pic16_get_op2 - variant to support two memory operand commands */
4916 /*-----------------------------------------------------------------*/
4917 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4920 if(pcop && pcop->type == PO_TWO_OPS) {
4921 return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4924 return "NO operand2";
4927 /*-----------------------------------------------------------------*/
4928 /*-----------------------------------------------------------------*/
4929 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4933 return pic16_get_op(pcc->pcop,NULL,0);
4935 /* gcc 3.2: warning: concatenation of string literals with __FUNCTION__ is deprecated
4936 * return ("ERROR Null: "__FUNCTION__);
4938 return ("ERROR Null: pic16_get_op_from_instruction");
4942 /*-----------------------------------------------------------------*/
4943 /*-----------------------------------------------------------------*/
4944 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4947 fprintf(of,"pcodeopprint- not implemented\n");
4950 /*-----------------------------------------------------------------*/
4951 /* pic16_pCode2str - convert a pCode instruction to string */
4952 /*-----------------------------------------------------------------*/
4953 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4959 if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4960 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4961 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4962 // exit(EXIT_FAILURE);
4969 SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4971 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4973 //if(PCI(pc)->is2MemOp)
4974 if (PCI(pc)->pcop->type == PO_TWO_OPS)
4976 /* split into two phases due to static buffer in pic16_get_op() */
4977 SAFE_snprintf(&s,&size, "%s",
4978 pic16_get_op((PCI(pc)->pcop), NULL, 0));
4979 SAFE_snprintf(&s, &size, ", %s",
4980 pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4984 if(PCI(pc)->is2LitOp) {
4985 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4989 if(PCI(pc)->isBitInst) {
4990 if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4991 if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4992 SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)",
4993 PCI(pc)->pcop->name ,
4994 PCI(pc)->pcop->name );
4996 SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4997 // (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
4998 (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
5000 } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5001 SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5003 SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5004 //PCI(pc)->pcop->t.bit );
5007 if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5008 if( PCI(pc)->num_ops == 3)
5009 SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5011 SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5016 SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5019 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5020 if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5021 SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5023 r = pic16_getRegFromInstruction(pc);
5024 // fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5025 // __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?r->accessBank:-1);
5027 if(PCI(pc)->isAccess) {
5028 static char *bank_spec[2][2] = {
5029 { "", ", ACCESS" }, /* gpasm uses access bank by default */
5030 { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5033 SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !r->accessBank) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
5042 /* assuming that comment ends with a \n */
5043 SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5047 SAFE_snprintf(&s,&size,"; info ==>");
5048 switch( PCINF(pc)->type ) {
5049 case INF_OPTIMIZATION:
5050 SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5053 SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5058 /* assuming that inline code ends with a \n */
5059 SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5063 SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5066 SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5069 SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5072 SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5075 // SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5076 SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5077 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5080 if(PCAD(pc)->directive) {
5081 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5084 /* special case to handle inline labels without a tab */
5085 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5090 SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5098 /*-----------------------------------------------------------------*/
5099 /* genericPrint - the contents of a pCode to a file */
5100 /*-----------------------------------------------------------------*/
5101 static void genericPrint(FILE *of, pCode *pc)
5109 // fputs(((pCodeComment *)pc)->comment, of);
5110 fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5115 pBranch *pbl = PCI(pc)->label;
5116 while(pbl && pbl->pc) {
5117 if(pbl->pc->type == PC_LABEL)
5118 pCodePrintLabel(of, pbl->pc);
5123 if(pic16_pcode_verbose) {
5124 fprintf(of, "; info ==>");
5125 switch(((pCodeInfo *)pc)->type) {
5126 case INF_OPTIMIZATION:
5127 fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5130 fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5138 fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5142 // If the opcode has a label, print that first
5144 pBranch *pbl = PCI(pc)->label;
5145 while(pbl && pbl->pc) {
5146 if(pbl->pc->type == PC_LABEL)
5147 pCodePrintLabel(of, pbl->pc);
5153 genericPrint(of,PCODE(PCI(pc)->cline));
5158 pic16_pCode2str(str, 256, pc);
5160 fprintf(of,"%s",str);
5162 if(pic16_debug_verbose) {
5163 fprintf(of, "\t;key=%03x",pc->seq);
5165 fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5172 fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5173 if(PCW(pc)->pci.label)
5174 pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5176 if(PCW(pc)->operand) {
5177 fprintf(of,";\toperand ");
5178 pCodeOpPrint(of,PCW(pc)->operand );
5183 if(pic16_debug_verbose) {
5184 fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5185 if(PCFL(pc)->ancestor)
5186 fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5193 // fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5194 fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5195 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5201 pBranch *pbl = PCAD(pc)->pci.label;
5202 while(pbl && pbl->pc) {
5203 if(pbl->pc->type == PC_LABEL)
5204 pCodePrintLabel(of, pbl->pc);
5208 if(PCAD(pc)->directive) {
5209 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5212 /* special case to handle inline labels without tab */
5213 fprintf(of, "%s\n", PCAD(pc)->arg);
5219 fprintf(of,"unknown pCode type %d\n",pc->type);
5224 /*-----------------------------------------------------------------*/
5225 /* pCodePrintFunction - prints function begin/end */
5226 /*-----------------------------------------------------------------*/
5228 static void pCodePrintFunction(FILE *of, pCode *pc)
5235 if( ((pCodeFunction *)pc)->modname)
5236 fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5239 if(!PCF(pc)->absblock) {
5240 if(PCF(pc)->fname) {
5241 pBranch *exits = PCF(pc)->to;
5244 fprintf(of,"%s:", PCF(pc)->fname);
5246 if(pic16_pcode_verbose)
5247 fprintf(of, "\t;Function start");
5253 exits = exits->next;
5257 if(pic16_pcode_verbose)
5258 fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5261 if((PCF(pc)->from &&
5262 PCF(pc)->from->pc->type == PC_FUNCTION &&
5263 PCF(PCF(pc)->from->pc)->fname) ) {
5265 if(pic16_pcode_verbose)
5266 fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5268 if(pic16_pcode_verbose)
5269 fprintf(of,"; exit point [can't find entry point]\n");
5275 /*-----------------------------------------------------------------*/
5276 /* pCodePrintLabel - prints label */
5277 /*-----------------------------------------------------------------*/
5279 static void pCodePrintLabel(FILE *of, pCode *pc)
5286 fprintf(of,"%s:\n",PCL(pc)->label);
5287 else if (PCL(pc)->key >=0)
5288 fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5290 fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5293 /*-----------------------------------------------------------------*/
5294 /* unlinkpCodeFromBranch - Search for a label in a pBranch and */
5295 /* remove it if it is found. */
5296 /*-----------------------------------------------------------------*/
5297 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5304 if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5305 b = PCI(pcl)->label;
5307 fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5312 //fprintf (stderr, "%s \n",__FUNCTION__);
5313 //pcl->print(stderr,pcl);
5314 //pc->print(stderr,pc);
5317 //fprintf (stderr, "found label\n");
5318 //pc->print(stderr, pc);
5322 bprev->next = b->next; /* Not first pCode in chain */
5326 PCI(pcl)->label = b->next; /* First pCode in chain */
5329 return; /* A label can't occur more than once */
5337 /*-----------------------------------------------------------------*/
5338 /*-----------------------------------------------------------------*/
5339 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5358 /*-----------------------------------------------------------------*/
5359 /* pBranchLink - given two pcodes, this function will link them */
5360 /* together through their pBranches */
5361 /*-----------------------------------------------------------------*/
5362 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5366 // Declare a new branch object for the 'from' pCode.
5368 //_ALLOC(b,sizeof(pBranch));
5369 b = Safe_calloc(1,sizeof(pBranch));
5370 b->pc = PCODE(t); // The link to the 'to' pCode.
5373 f->to = pic16_pBranchAppend(f->to,b);
5375 // Now do the same for the 'to' pCode.
5377 //_ALLOC(b,sizeof(pBranch));
5378 b = Safe_calloc(1,sizeof(pBranch));
5382 t->from = pic16_pBranchAppend(t->from,b);
5387 /*-----------------------------------------------------------------*/
5388 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5390 /*-----------------------------------------------------------------*/
5391 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5404 /*-----------------------------------------------------------------*/
5405 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain. */
5406 /*-----------------------------------------------------------------*/
5407 void pic16_pCodeUnlink(pCode *pc)
5412 if(!pc->prev || !pc->next) {
5413 fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5417 /* move C source line down (or up) */
5418 if (isPCI(pc) && PCI(pc)->cline) {
5419 pc1 = pic16_findNextInstruction (pc->next);
5420 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5421 PCI(pc1)->cline = PCI(pc)->cline;
5423 pc1 = pic16_findPrevInstruction (pc->prev);
5424 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5425 PCI(pc1)->cline = PCI(pc)->cline;
5429 /* first remove the pCode from the chain */
5430 pc->prev->next = pc->next;
5431 pc->next->prev = pc->prev;
5433 pc->prev = pc->next = NULL;
5435 /* Now for the hard part... */
5437 /* Remove the branches */
5439 pb1 = PCI(pc)->from;
5441 pc1 = pb1->pc; /* Get the pCode that branches to the
5442 * one we're unlinking */
5444 /* search for the link back to this pCode (the one we're
5446 if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5447 pb2->pc = PCI(pc)->to->pc; // make the replacement
5449 /* if the pCode we're unlinking contains multiple 'to'
5450 * branches (e.g. this a skip instruction) then we need
5451 * to copy these extra branches to the chain. */
5452 if(PCI(pc)->to->next)
5453 pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5462 /*-----------------------------------------------------------------*/
5463 /*-----------------------------------------------------------------*/
5465 static void genericAnalyze(pCode *pc)
5475 // Go through the pCodes that are in pCode chain and link
5476 // them together through the pBranches. Note, the pCodes
5477 // are linked together as a contiguous stream like the
5478 // assembly source code lines. The linking here mimics this
5479 // except that comments are not linked in.
5481 pCode *npc = pc->next;
5483 if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5484 pBranchLink(pc,npc);
5489 /* reached the end of the pcode chain without finding
5490 * an instruction we could link to. */
5494 fprintf(stderr,"analyze PC_FLOW\n");
5498 fprintf(stderr,,";A bad pCode is being used\n");
5504 /*-----------------------------------------------------------------*/
5505 /*-----------------------------------------------------------------*/
5506 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5510 if(pc->type == PC_LABEL) {
5511 if( ((pCodeLabel *)pc)->key == pcop_label->key)
5514 if((pc->type == PC_OPCODE)
5515 || (pc->type == PC_ASMDIR)
5517 pbr = PCI(pc)->label;
5519 if(pbr->pc->type == PC_LABEL) {
5520 if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
5530 /*-----------------------------------------------------------------*/
5531 /*-----------------------------------------------------------------*/
5532 static int checkLabel(pCode *pc)
5536 if(pc && isPCI(pc)) {
5537 pbr = PCI(pc)->label;
5539 if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5549 /*-----------------------------------------------------------------*/
5550 /* findLabelinpBlock - Search the pCode for a particular label */
5551 /*-----------------------------------------------------------------*/
5552 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5559 for(pc = pb->pcHead; pc; pc = pc->next)
5560 if(compareLabel(pc,pcop_label))
5566 /*-----------------------------------------------------------------*/
5567 /* findLabel - Search the pCode for a particular label */
5568 /*-----------------------------------------------------------------*/
5569 static pCode * findLabel(pCodeOpLabel *pcop_label)
5577 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5578 if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5582 fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5586 /*-----------------------------------------------------------------*/
5587 /* pic16_findNextpCode - given a pCode, find the next of type 'pct' */
5588 /* in the linked list */
5589 /*-----------------------------------------------------------------*/
5590 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5603 /*-----------------------------------------------------------------*/
5604 /* findPrevpCode - given a pCode, find the previous of type 'pct' */
5605 /* in the linked list */
5606 /*-----------------------------------------------------------------*/
5607 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5621 //#define PCODE_DEBUG
5622 /*-----------------------------------------------------------------*/
5623 /* pic16_findNextInstruction - given a pCode, find the next instruction */
5624 /* in the linked list */
5625 /*-----------------------------------------------------------------*/
5626 pCode * pic16_findNextInstruction(pCode *pci)
5631 if((pc->type == PC_OPCODE)
5632 || (pc->type == PC_WILD)
5633 || (pc->type == PC_ASMDIR)
5638 fprintf(stderr,"pic16_findNextInstruction: ");
5639 printpCode(stderr, pc);
5644 //fprintf(stderr,"Couldn't find instruction\n");
5648 /*-----------------------------------------------------------------*/
5649 /* pic16_findPrevInstruction - given a pCode, find the next instruction */
5650 /* in the linked list */
5651 /*-----------------------------------------------------------------*/
5652 pCode * pic16_findPrevInstruction(pCode *pci)
5658 if((pc->type == PC_OPCODE)
5659 || (pc->type == PC_WILD)
5660 || (pc->type == PC_ASMDIR)
5666 fprintf(stderr,"pic16_findPrevInstruction: ");
5667 printpCode(stderr, pc);
5672 //fprintf(stderr,"Couldn't find instruction\n");
5679 /*-----------------------------------------------------------------*/
5680 /* findFunctionEnd - given a pCode find the end of the function */
5681 /* that contains it */
5682 /*-----------------------------------------------------------------*/
5683 static pCode * findFunctionEnd(pCode *pc)
5687 if(pc->type == PC_FUNCTION && !(PCF(pc)->fname))
5693 fprintf(stderr,"Couldn't find function end\n");
5698 /*-----------------------------------------------------------------*/
5699 /* AnalyzeLabel - if the pCode is a label, then merge it with the */
5700 /* instruction with which it is associated. */
5701 /*-----------------------------------------------------------------*/
5702 static void AnalyzeLabel(pCode *pc)
5705 pic16_pCodeUnlink(pc);
5711 static void AnalyzeGOTO(pCode *pc)
5714 pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5718 static void AnalyzeSKIP(pCode *pc)
5721 pBranchLink(pc,pic16_findNextInstruction(pc->next));
5722 pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5726 static void AnalyzeRETURN(pCode *pc)
5729 // branch_link(pc,findFunctionEnd(pc->next));
5735 /*-------------------------------------------------------------------*/
5736 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp */
5737 /* if one is present. This is the common */
5738 /* part of pic16_getRegFromInstruction(2) */
5739 /*-------------------------------------------------------------------*/
5741 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5742 if (!pcop) return NULL;
5744 switch(pcop->type) {
5757 return PCOR(pcop)->r;
5759 case PO_SFR_REGISTER:
5760 //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5761 return PCOR(pcop)->r;
5765 // fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5766 return PCOR(pcop)->r;
5769 // return pic16_dirregWithName(PCOI(pcop)->r->name);
5772 return (PCOI(pcop)->r);
5777 return PCOR(pcop)->r;
5779 case PO_GPR_REGISTER:
5781 // fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5782 return PCOR(pcop)->r;
5785 //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5790 //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5795 /* this should never turn up */
5796 //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5803 return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5807 fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5815 /*-----------------------------------------------------------------*/
5816 /*-----------------------------------------------------------------*/
5817 regs * pic16_getRegFromInstruction(pCode *pc)
5822 PCI(pc)->num_ops == 0 ||
5823 (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5827 fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5828 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5831 return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5834 /*-------------------------------------------------------------------------------*/
5835 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5836 /*-------------------------------------------------------------------------------*/
5837 regs * pic16_getRegFromInstruction2(pCode *pc)
5843 PCI(pc)->num_ops == 0 ||
5844 (PCI(pc)->num_ops == 1)) // accept only 2 operand commands
5847 if (PCI(pc)->pcop->type != PO_TWO_OPS)
5851 fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5852 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5855 return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5858 /*-----------------------------------------------------------------*/
5859 /*-----------------------------------------------------------------*/
5861 static void AnalyzepBlock(pBlock *pb)
5868 /* Find all of the registers used in this pBlock
5869 * by looking at each instruction and examining it's
5872 for(pc = pb->pcHead; pc; pc = pc->next) {
5874 /* Is this an instruction with operands? */
5875 if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5877 if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5879 /* Loop through all of the registers declared so far in
5880 this block and see if we find this one there */
5882 regs *r = setFirstItem(pb->tregisters);
5885 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5886 PCOR(PCI(pc)->pcop)->r = r;
5889 r = setNextItem(pb->tregisters);
5893 /* register wasn't found */
5894 //r = Safe_calloc(1, sizeof(regs));
5895 //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5896 //addSet(&pb->tregisters, r);
5897 addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5898 //PCOR(PCI(pc)->pcop)->r = r;
5899 //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5901 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5904 if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5905 if(PCOR(PCI(pc)->pcop)->r) {
5906 pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx); /* FIXME! - VR */
5907 DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5909 if(PCI(pc)->pcop->name)
5910 fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5912 fprintf(stderr,"ERROR: NULL register\n");
5921 /*-----------------------------------------------------------------*/
5923 /*-----------------------------------------------------------------*/
5924 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5926 static void InsertpFlow(pCode *pc, pCode **pflow)
5929 PCFL(*pflow)->end = pc;
5931 if(!pc || !pc->next)
5934 *pflow = pic16_newpCodeFlow();
5935 pic16_pCodeInsertAfter(pc, *pflow);
5938 /*-----------------------------------------------------------------*/
5939 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5940 /* the flow blocks. */
5942 * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5943 * point the instruction flow changes.
5945 /*-----------------------------------------------------------------*/
5946 void pic16_BuildFlow(pBlock *pb)
5949 pCode *last_pci=NULL;
5956 //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq);
5957 /* Insert a pCodeFlow object at the beginning of a pBlock */
5959 InsertpFlow(pb->pcHead, &pflow);
5961 //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */
5962 //pflow->next = pb->pcHead; /* Make the current head the next object */
5963 //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */
5964 //pb->pcHead = pflow; /* Make the Flow object the head */
5967 for( pc = pic16_findNextInstruction(pb->pcHead);
5969 pc=pic16_findNextInstruction(pc)) {
5972 PCI(pc)->pcflow = PCFL(pflow);
5974 //fprintf(stderr," build: ");
5975 //pflow->print(stderr,pflow);
5977 if (checkLabel(pc)) {
5979 /* This instruction marks the beginning of a
5980 * new flow segment */
5985 /* If the previous pCode is not a flow object, then
5986 * insert a new flow object. (This check prevents
5987 * two consecutive flow objects from being insert in
5988 * the case where a skip instruction preceeds an
5989 * instruction containing a label.) */
5991 if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5992 InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5994 PCI(pc)->pcflow = PCFL(pflow);
5998 if( PCI(pc)->isSkip) {
6000 /* The two instructions immediately following this one
6001 * mark the beginning of a new flow segment */
6003 while(pc && PCI(pc)->isSkip) {
6005 PCI(pc)->pcflow = PCFL(pflow);
6009 InsertpFlow(pc, &pflow);
6010 pc=pic16_findNextInstruction(pc->next);
6018 PCI(pc)->pcflow = PCFL(pflow);
6020 InsertpFlow(pc, &pflow);
6022 } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) {
6024 InsertpFlow(pc, &pflow);
6032 //fprintf (stderr,",end seq %d",GpcFlowSeq);
6034 PCFL(pflow)->end = pb->pcTail;
6037 /*-------------------------------------------------------------------*/
6038 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */
6039 /* the flow blocks. */
6041 * unBuildFlow removes pCodeFlow objects from a pCode chain
6043 /*-----------------------------------------------------------------*/
6044 static void unBuildFlow(pBlock *pb)
6059 if(PCI(pc)->pcflow) {
6060 //Safe_free(PCI(pc)->pcflow);
6061 PCI(pc)->pcflow = NULL;
6064 } else if(isPCFL(pc) )
6073 /*-----------------------------------------------------------------*/
6074 /*-----------------------------------------------------------------*/
6075 static void dumpCond(int cond)
6078 static char *pcc_str[] = {
6092 int ncond = sizeof(pcc_str) / sizeof(char *);
6095 fprintf(stderr, "0x%04X\n",cond);
6097 for(i=0,j=1; i<ncond; i++, j<<=1)
6099 fprintf(stderr, " %s\n",pcc_str[i]);
6105 /*-----------------------------------------------------------------*/
6106 /*-----------------------------------------------------------------*/
6107 static void FlowStats(pCodeFlow *pcflow)
6115 fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6117 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6120 fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6125 fprintf(stderr, " FlowStats inCond: ");
6126 dumpCond(pcflow->inCond);
6127 fprintf(stderr, " FlowStats outCond: ");
6128 dumpCond(pcflow->outCond);
6132 /*-----------------------------------------------------------------*
6133 * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6134 * if it affects the banking bits.
6136 * return: -1 == Banking bits are unaffected by this pCode.
6138 * return: > 0 == Banking bits are affected.
6140 * If the banking bits are affected, then the returned value describes
6141 * which bits are affected and how they're affected. The lower half
6142 * of the integer maps to the bits that are affected, the upper half
6143 * to whether they're set or cleared.
6145 *-----------------------------------------------------------------*/
6147 static int isBankInstruction(pCode *pc)
6155 if( PCI(pc)->op == POC_MOVLB ||
6156 (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6157 bank = PCOL(pc)->lit;
6164 /*-----------------------------------------------------------------*/
6165 /*-----------------------------------------------------------------*/
6166 static void FillFlow(pCodeFlow *pcflow)
6175 // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6177 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6180 //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6187 isBankInstruction(pc);
6189 } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6193 fprintf(stderr, " FillFlow - Bad end of flow\n");
6195 fprintf(stderr, " FillFlow - Ending flow with\n ");
6196 pc->print(stderr,pc);
6199 fprintf(stderr, " FillFlow inCond: ");
6200 dumpCond(pcflow->inCond);
6201 fprintf(stderr, " FillFlow outCond: ");
6202 dumpCond(pcflow->outCond);
6206 /*-----------------------------------------------------------------*/
6207 /*-----------------------------------------------------------------*/
6208 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6210 pCodeFlowLink *fromLink, *toLink;
6212 if(!from || !to || !to->pcflow || !from->pcflow)
6215 fromLink = pic16_newpCodeFlowLink(from->pcflow);
6216 toLink = pic16_newpCodeFlowLink(to->pcflow);
6218 addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
6219 addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6223 pCode *pic16_getJumptabpCode (pCode *pc) {
6226 //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6227 //pc->print (stderr, pc);
6230 if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6231 if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6232 switch (PCOO(PCINF(pcinf)->oper1)->type) {
6233 case OPT_JUMPTABLE_BEGIN:
6234 /* leading begin of jump table -- in one */
6235 pcinf = pic16_findPrevInstruction (pcinf);
6239 case OPT_JUMPTABLE_END:
6240 /* leading end of jumptable -- not in one */
6245 /* ignore all other PCInfos */
6249 pcinf = pcinf->prev;
6252 /* no PCInfo found -- not in a jumptable */
6256 /*-----------------------------------------------------------------*
6257 * void LinkFlow(pBlock *pb)
6259 * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6260 * non-branching segments. In LinkFlow, we determine the execution
6261 * order of these segments. For example, if one of the segments ends
6262 * with a skip, then we know that there are two possible flow segments
6263 * to which control may be passed.
6264 *-----------------------------------------------------------------*/
6265 static void LinkFlow(pBlock *pb)
6270 pCode *jumptab_pre = NULL;
6272 //fprintf(stderr,"linkflow \n");
6274 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6276 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6279 fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6281 //fprintf(stderr," link: ");
6282 //pcflow->print(stderr,pcflow);
6284 //FillFlow(PCFL(pcflow));
6286 pc = PCFL(pcflow)->end;
6288 //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6289 if(isPCI_SKIP(pc)) {
6290 // fprintf(stderr, "ends with skip\n");
6291 // pc->print(stderr,pc);
6293 pct=pic16_findNextInstruction(pc->next);
6294 LinkFlow_pCode(PCI(pc),PCI(pct));
6295 pct=pic16_findNextInstruction(pct->next);
6296 LinkFlow_pCode(PCI(pc),PCI(pct));
6300 if(isPCI_BRANCH(pc)) {
6301 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6303 /* handle GOTOs in jumptables */
6304 if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6305 /* link to previous flow */
6306 //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6307 LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6310 switch (PCI(pc)->op) {
6316 /* unconditional branches -- do not link to next instruction */
6317 //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6322 /* unconditional calls -- link to next instruction */
6323 //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6324 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6335 /* conditional branches -- also link to next instruction */
6336 //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6337 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6341 fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6342 assert (0 && "unhandled branching instruction");
6346 //fprintf(stderr, "ends with branch\n ");
6347 //pc->print(stderr,pc);
6349 if(!(pcol && isPCOLAB(pcol))) {
6350 if((PCI(pc)->op != POC_RETLW)
6351 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6353 /* continue if label is '$' which assembler knows how to parse */
6354 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6356 if(pic16_pcode_verbose) {
6357 pc->print(stderr,pc);
6358 fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6364 if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6365 LinkFlow_pCode(PCI(pc),PCI(pct));
6367 fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6368 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6370 // fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6376 //fprintf(stderr, "ends with non-branching instruction:\n");
6377 //pc->print(stderr,pc);
6379 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6385 //fprintf(stderr, "ends with unknown\n");
6386 //pc->print(stderr,pc);
6390 //fprintf(stderr, "ends with nothing: ERROR\n");
6394 /*-----------------------------------------------------------------*/
6395 /*-----------------------------------------------------------------*/
6397 /*-----------------------------------------------------------------*/
6398 /*-----------------------------------------------------------------*/
6399 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6405 if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6408 if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6418 /*-----------------------------------------------------------------*/
6419 /* insertBankSwitch - inserts a bank switch statement in the */
6420 /* assembly listing */
6422 /* position == 0: insert before */
6423 /* position == 1: insert after pc */
6424 /* position == 2: like 0 but previous was a skip instruction */
6425 /*-----------------------------------------------------------------*/
6426 pCodeOp *pic16_popGetLabel(unsigned int key);
6427 extern int pic16_labelOffset;
6429 static void insertBankSwitch(unsigned char position, pCode *pc)
6436 /* emit BANKSEL [symbol] */
6439 new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6441 // position = 0; // position is always before (sanity check!)
6444 fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6445 pc->print(stderr, pc);
6450 /* insert the bank switch after this pc instruction */
6451 pCode *pcnext = pic16_findNextInstruction(pc);
6453 pic16_pCodeInsertAfter(pc, new_pc);
6454 if(pcnext)pc = pcnext;
6458 /* insert the bank switch BEFORE this pc instruction */
6459 pic16_pCodeInsertAfter(pc->prev, new_pc);
6464 pCode *pcnext, *pcprev, *npci, *ppc;
6466 int ofs1=0, ofs2=0, len=0;
6468 /* just like 0, but previous was a skip instruction,
6469 * so some care should be taken */
6471 pic16_labelOffset += 10000;
6472 tlbl = newiTempLabel(NULL);
6474 /* invert skip instruction */
6475 pcprev = pic16_findPrevInstruction(pc->prev);
6476 ipci = PCI(pcprev)->inverted_op;
6477 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6479 // fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6481 /* copy info from old pCode */
6482 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6483 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6484 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6485 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6486 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6487 PCI(npci)->op = PCI(pcprev)->inverted_op;
6489 /* unlink old pCode */
6491 ppc->next = pcprev->next;
6492 pcprev->next->prev = ppc;
6493 pic16_pCodeInsertAfter(ppc, npci);
6495 /* extra instructions to handle invertion */
6496 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6497 pic16_pCodeInsertAfter(npci, pcnext);
6498 pic16_pCodeInsertAfter(pc->prev, new_pc);
6500 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6501 pic16_pCodeInsertAfter(pc, pcnext);
6506 /* Move the label, if there is one */
6507 if(PCI(pc)->label) {
6508 // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6509 // __FILE__, __LINE__, pc, new_pc);
6510 PCAD(new_pc)->pci.label = PCI(pc)->label;
6511 PCI(pc)->label = NULL;
6516 /*-----------------------------------------------------------------*/
6517 /*int compareBankFlow - compare the banking requirements between */
6519 /*-----------------------------------------------------------------*/
6520 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6523 if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6526 if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6529 if(pcflow->firstBank == -1)
6533 if(pcflowLink->pcflow->firstBank == -1) {
6534 pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6535 pcflowLink->pcflow->to :
6536 pcflowLink->pcflow->from);
6537 return compareBankFlow(pcflow, pctl, toORfrom);
6541 if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6544 pcflowLink->bank_conflict++;
6545 pcflowLink->pcflow->FromConflicts++;
6546 pcflow->ToConflicts++;
6549 if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6552 pcflowLink->bank_conflict++;
6553 pcflowLink->pcflow->ToConflicts++;
6554 pcflow->FromConflicts++;
6558 fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6559 pcflowLink->pcflow->pc.seq,
6560 pcflowLink->pcflow->FromConflicts,
6561 pcflowLink->pcflow->ToConflicts);
6568 /*-----------------------------------------------------------------*/
6569 /*-----------------------------------------------------------------*/
6570 static void DumpFlow(pBlock *pb)
6574 pCodeFlowLink *pcfl;
6577 fprintf(stderr,"Dump flow \n");
6578 pb->pcHead->print(stderr, pb->pcHead);
6580 pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6581 pcflow->print(stderr,pcflow);
6583 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6585 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6587 if(!isPCFL(pcflow)) {
6588 fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6591 fprintf(stderr,"dumping: ");
6592 pcflow->print(stderr,pcflow);
6593 FlowStats(PCFL(pcflow));
6595 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6597 pc = PCODE(pcfl->pcflow);
6599 fprintf(stderr, " from seq %d:\n",pc->seq);
6601 fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6602 pc->print(stderr,pc);
6607 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6609 pc = PCODE(pcfl->pcflow);
6611 fprintf(stderr, " to seq %d:\n",pc->seq);
6613 fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6614 pc->print(stderr,pc);
6623 /*-----------------------------------------------------------------*/
6624 /*-----------------------------------------------------------------*/
6625 static int OptimizepBlock(pBlock *pb)
6630 if(!pb || !peepOptimizing)
6633 DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6635 for(pc = pb->pcHead; pc; pc = pc->next)
6636 matches += pic16_pCodePeepMatchRule(pc);
6639 pc = pic16_findNextInstruction(pb->pcHead);
6647 if(pic16_pCodePeepMatchRule(pc)) {
6652 pc = pic16_findNextInstruction(pcprev->next);
6654 pc = pic16_findNextInstruction(pb->pcHead);
6656 pc = pic16_findNextInstruction(pc->next);
6660 DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6665 /*-----------------------------------------------------------------*/
6666 /*-----------------------------------------------------------------*/
6667 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6671 for(pc = pcs; pc; pc = pc->next) {
6673 if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6675 (PCI(pc)->pcop->type == PO_LABEL) &&
6676 (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6684 /*-----------------------------------------------------------------*/
6685 /*-----------------------------------------------------------------*/
6686 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6693 (PCI(pc)->pcop->type == PO_LABEL)) {
6695 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6697 // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6698 // if(pcol->pcop.name)
6699 // Safe_free(pcol->pcop.name);
6701 /* If the key is negative, then we (probably) have a label to
6702 * a function and the name is already defined */
6705 sprintf(s=buffer,"_%05d_DS_",pcl->key);
6709 //sprintf(buffer,"_%05d_DS_",pcl->key);
6711 fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6713 pcol->pcop.name = Safe_strdup(s);
6714 pcol->key = pcl->key;
6715 //pc->print(stderr,pc);
6722 /*-----------------------------------------------------------------*/
6723 /* pBlockRemoveUnusedLabels - remove the pCode labels from the */
6724 /* pCode chain if they're not used. */
6725 /*-----------------------------------------------------------------*/
6726 static void pBlockRemoveUnusedLabels(pBlock *pb)
6728 pCode *pc; pCodeLabel *pcl;
6733 for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6735 pBranch *pbr = PCI(pc)->label;
6736 if(pbr && pbr->next) {
6737 pCode *pcd = pb->pcHead;
6739 // fprintf(stderr, "multiple labels\n");
6740 // pc->print(stderr,pc);
6745 while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6746 //fprintf(stderr,"Used by:\n");
6747 //pcd->print(stderr,pcd);
6749 exchangeLabels(PCL(pbr->pc),pcd);
6758 for(pc = pb->pcHead; pc; pc = pc->next) {
6760 if(isPCL(pc)) // pc->type == PC_LABEL)
6762 else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6763 pcl = PCL(PCI(pc)->label->pc);
6766 // fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6768 /* This pCode is a label, so search the pBlock to see if anyone
6771 if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6773 //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6774 /* Couldn't find an instruction that refers to this label
6775 * So, unlink the pCode label from it's pCode chain
6776 * and destroy the label */
6777 // fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6779 DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6780 if(pc->type == PC_LABEL) {
6781 pic16_unlinkpCode(pc);
6782 pCodeLabelDestruct(pc);
6784 unlinkpCodeFromBranch(pc, PCODE(pcl));
6785 /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6786 Safe_free(pc->label);
6796 /*-----------------------------------------------------------------*/
6797 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */
6798 /* chain and put them into pBranches that are */
6799 /* associated with the appropriate pCode */
6801 /*-----------------------------------------------------------------*/
6802 void pic16_pBlockMergeLabels(pBlock *pb)
6805 pCode *pc, *pcnext=NULL;
6810 /* First, Try to remove any unused labels */
6811 //pBlockRemoveUnusedLabels(pb);
6813 /* Now loop through the pBlock and merge the labels with the opcodes */
6816 // for(pc = pb->pcHead; pc; pc = pc->next) {
6819 pCode *pcn = pc->next;
6821 if(pc->type == PC_LABEL) {
6823 // fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6824 // fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6826 if((pcnext = pic16_findNextInstruction(pc) )) {
6828 // pcnext->print(stderr, pcnext);
6830 // Unlink the pCode label from it's pCode chain
6831 pic16_unlinkpCode(pc);
6833 // fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6834 // And link it into the instruction's pBranch labels. (Note, since
6835 // it's possible to have multiple labels associated with one instruction
6836 // we must provide a means to accomodate the additional labels. Thus
6837 // the labels are placed into the singly-linked list "label" as
6838 // opposed to being a single member of the pCodeInstruction.)
6840 //_ALLOC(pbr,sizeof(pBranch));
6842 pbr = Safe_calloc(1,sizeof(pBranch));
6846 PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6849 if(pic16_pcode_verbose)
6850 fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6852 } else if(pc->type == PC_CSOURCE) {
6854 /* merge the source line symbolic info into the next instruction */
6855 if((pcnext = pic16_findNextInstruction(pc) )) {
6857 // Unlink the pCode label from it's pCode chain
6858 pic16_unlinkpCode(pc);
6859 PCI(pcnext)->cline = PCCS(pc);
6860 //fprintf(stderr, "merging CSRC\n");
6861 //genericPrint(stderr,pcnext);
6867 pBlockRemoveUnusedLabels(pb);
6871 /*-----------------------------------------------------------------*/
6872 /*-----------------------------------------------------------------*/
6873 static int OptimizepCode(char dbName)
6875 #define MAX_PASSES 4
6884 DFPRINTF((stderr," Optimizing pCode\n"));
6888 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6889 if('*' == dbName || getpBlock_dbName(pb) == dbName)
6890 matches += OptimizepBlock(pb);
6893 while(matches && ++passes < MAX_PASSES);
6900 const char *pic16_pCodeOpType(pCodeOp *pcop);
6901 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6904 /*-----------------------------------------------------------------*/
6905 /* pic16_popCopyGPR2Bit - copy a pcode operator */
6906 /*-----------------------------------------------------------------*/
6908 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6912 // fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6915 pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6917 if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6920 assert(pcop != NULL);
6922 if( !( (pcop->type == PO_LABEL) ||
6923 (pcop->type == PO_LITERAL) ||
6924 (pcop->type == PO_STR) ))
6925 PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */
6926 PCOR(pcop)->r->wasUsed = 1;
6927 PCOR(pcop)->instance = PCOR(pc)->instance;
6933 /*----------------------------------------------------------------------*
6934 * pic16_areRegsSame - check to see if the names of two registers match *
6935 *----------------------------------------------------------------------*/
6936 int pic16_areRegsSame(regs *r1, regs *r2)
6938 if(!strcmp(r1->name, r2->name))return 1;
6944 /*-----------------------------------------------------------------*/
6945 /*-----------------------------------------------------------------*/
6946 static void pic16_FixRegisterBanking(pBlock *pb)
6950 regs *reg, *prevreg;
6951 unsigned char flag=0;
6956 pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6959 /* loop through all of the flow blocks with in one pblock */
6961 // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6965 /* at this point, pc should point to a PC_FLOW object */
6966 /* for each flow block, determine the register banking
6970 /* if label, then might come from other point, force banksel */
6971 if(isPCL(pc))prevreg = NULL;
6973 if(!isPCI(pc))goto loop;
6975 if(PCI(pc)->label)prevreg = NULL;
6977 if(PCI(pc)->is2MemOp)goto loop;
6979 /* if goto, then force banksel */
6980 // if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6982 reg = pic16_getRegFromInstruction(pc);
6985 pc->print(stderr, pc);
6986 fprintf(stderr, "reg = %p\n", reg);
6989 fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6990 fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6991 reg->address,reg->isBitField, reg->isFixed);
6995 /* now make some tests to make sure that instruction needs bank switch */
6997 /* if no register exists, and if not a bit opcode goto loop */
6999 if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
7002 if(isPCI_SKIP(pc)) {
7003 // fprintf(stderr, "instruction is SKIP instruction\n");
7006 if(reg && isACCESS_BANK(reg))goto loop;
7008 if(!isBankInstruction(pc))goto loop;
7010 if(isPCI_LIT(pc))goto loop;
7012 if(PCI(pc)->op == POC_CALL)goto loop;
7014 /* Examine the instruction before this one to make sure it is
7015 * not a skip type instruction */
7016 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7018 flag = 0; /* add before this instruction */
7020 /* if previous instruction is a skip one, then set flag
7021 * to 2 and call insertBankSwitch */
7022 if(pcprev && isPCI_SKIP(pcprev)) {
7027 if(pic16_options.opt_banksel>0) {
7028 char op1[128], op2[128];
7031 strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7032 strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7033 if(!strcmp(op1, op2))goto loop;
7037 insertBankSwitch(flag, pc);
7039 // fprintf(stderr, "BANK SWITCH inserted\n");
7047 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7049 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7050 int instrSize (pCode *pc)
7055 if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7056 return 4; // assumes only regular instructions using <= 4 bytes
7059 if (isPCI(pc)) return PCI(pc)->isize;
7064 /* Returns 1 if pc is referenced by the given label (either
7065 * pc is the label itself or is an instruction with an attached
7067 * Returns 0 if pc is not preceeded by the specified label.
7069 int isLabel (pCode *pc, char *label)
7073 // label attached to the pCode?
7074 if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7075 pBranch *lab = NULL;
7076 lab = PCI(pc)->label;
7079 if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7086 // is inline assembly label?
7087 if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7088 // do not compare trailing ':'
7089 if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7096 if (strcmp(PCL(pc)->label,label) == 0) {
7101 // no label/no label attached/wrong label(s)
7105 /* Returns the distance to the given label in terms of words.
7106 * Labels are searched only within -max .. max words from pc.
7107 * Returns max if the label could not be found or
7108 * its distance from pc in (-max..+max).
7110 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7111 int dist = instrSize(pc);
7115 while (dist < max && curr && !isLabel (curr, label)) {
7117 dist += instrSize(curr); // sizeof (instruction)
7119 if (curr && dist < max) {
7120 if (target != NULL) *target = curr;
7125 curr = pic16_findNextInstruction (pc->next);
7127 while (dist < max && curr && !isLabel (curr, label)) {
7128 dist += instrSize(curr); // sizeof (instruction)
7131 if (curr && dist < max) {
7132 if (target != NULL) *target = curr;
7136 if (target != NULL) *target = NULL;
7140 /* Returns -1 if pc does NOT denote an instruction like
7142 * Otherwise we return
7143 * (a) 0x10 + i for BTFSS
7144 * (b) 0x00 + i for BTFSC
7146 int isSkipOnStatus (pCode *pc)
7150 if (!pc || !isPCI(pc)) return -1;
7151 if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7152 else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7155 pcop = PCI(pc)->pcop;
7157 if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7158 return res + ((pCodeOpRegBit *)pcop)->bit;
7164 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7165 * returns 0 otherwise. */
7166 int isConditionalBranch (pCode *pc)
7168 if (!pc || !isPCI_BRANCH(pc)) return 0;
7170 switch (PCI(pc)->op) {
7188 /* Returns 1 if pc has a label attached to it.
7189 * This can be either a label stored in the pCode itself (.label)
7190 * or a label making up its own pCode preceding this pc.
7191 * Returns 0 if pc cannot be reached directly via a label.
7193 int hasNoLabel (pCode *pc)
7198 // are there any label pCodes between pc and the previous instruction?
7199 prev = pic16_findPrevInstruction (pc->prev);
7200 while (pc && pc != prev) {
7201 // pCode with attached label?
7202 if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7203 && PCI(pc)->label) {
7206 // is inline assembly label?
7207 if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7208 if (isPCW(pc) && PCW(pc)->label) return 0;
7211 if (isPCL(pc)) return 0;
7220 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7225 vsprintf (buf, fmt, va);
7228 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7231 /* Replaces the old pCode with the new one, moving the labels,
7232 * C source line and probably flow information to the new pCode.
7234 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7235 if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7238 /* first move all labels from old to new */
7239 PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7240 PCI(oldPC)->label = NULL;
7243 /* move C source line (if possible) */
7244 if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7245 PCI(newPC)->cline = PCI(oldPC)->cline;
7248 /* keep flow information intact */
7249 newPC->seq = oldPC->seq;
7250 PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7251 if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7252 PCI(newPC)->pcflow->end = newPC;
7255 /* insert a comment stating which pCode has been replaced */
7257 if (pic16_pcode_verbose || pic16_debug_verbose) {
7259 pic16_pCode2str (pc_str, 256, oldPC);
7260 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7264 /* insert new pCode into pBlock */
7265 pic16_pCodeInsertAfter (oldPC, newPC);
7266 pic16_unlinkpCode (oldPC);
7268 /* destruct replaced pCode */
7269 oldPC->destruct (oldPC);
7272 /* Returns the inverted conditional branch (if any) or NULL.
7273 * pcop must be set to the new jump target.
7275 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7279 if (!bcc || !isPCI(bcc)) return NULL;
7281 switch (PCI(bcc)->op) {
7282 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7283 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7284 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7285 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7286 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7287 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7288 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7289 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7296 #define MAX_DIST_GOTO 0x7FFFFFFF
7297 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7298 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7299 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7300 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7302 /* Follows GOTO/BRA instructions to their target instructions, stores the
7303 * final destination (not a GOTO or BRA instruction) in target and returns
7304 * the distance from the original pc to *target.
7306 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7309 pCodeOp *lastPCOP = NULL;
7313 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7315 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7316 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7317 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7319 lastPCOP = PCI(curr)->pcop;
7320 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7321 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7324 if (target) *target = last;
7325 if (pcop) *pcop = lastPCOP;
7329 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7330 * Otherwise the first pCode after the jumptable (after
7331 * the OPT_JUMPTABLE_END tag) is returned.
7333 pCode *skipJumptables (pCode *pc, int *isJumptable)
7336 if (!pc) return NULL;
7338 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7340 //fprintf (stderr, "SKIPPING jumptable\n");
7342 //pc->print(stderr, pc);
7344 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7345 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7346 //fprintf (stderr, "<<JUMPTAB:\n");
7347 // skip OPT_END as well
7348 if (pc) pc = pc->next;
7354 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7358 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7359 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7360 pc = skipJumptables (pc, &isJumptab);
7362 // pc is the first pCode after the jumptable
7365 // pc has not been changed by skipJumptables()
7373 /* Turn GOTOs into BRAs if distance between GOTO and label
7374 * is less than 1024 bytes.
7376 * This method is especially useful if GOTOs after BTFS[SC]
7377 * can be turned into BRAs as GOTO would cost another NOP
7380 void pic16_OptimizeJumps ()
7383 pCode *pc_prev = NULL;
7384 pCode *pc_next = NULL;
7387 int change, iteration, isJumptab;
7390 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7392 if (!the_pFile) return;
7394 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7396 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7397 int matchedInvertRule = 1;
7400 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7402 pc = pic16_findNextInstruction (pb->pcHead);
7405 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7407 // skip jumptable, i.e. start over with no pc_prev!
7413 /* (1) resolve chained jumps
7414 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7415 * (a) leave dead code in and
7416 * (b) skip over the dead code with an (unneccessary) jump.
7418 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7419 pCodeOp *lastTargetOp = NULL;
7420 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7421 int maxDist = MAX_DIST_BCC;
7422 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7423 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7425 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7426 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7427 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7428 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7429 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7430 PCI(pc)->pcop->name = lastTargetOp->name;
7439 int condBraType = isSkipOnStatus(pc_prev);
7440 label = PCI(pc)->pcop->name;
7441 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7442 if (dist < 0) dist = -dist;
7443 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7447 /* (2) remove "GOTO label; label:" */
7448 if (isLabel (pc_next, label)) {
7449 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7450 // first remove all preceeding SKIP instructions
7451 while (pc_prev && isPCI_SKIP(pc_prev)) {
7452 // attach labels on this instruction to pc_next
7453 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7454 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7455 PCI(pc_prev)->label = NULL;
7456 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7457 pic16_unlinkpCode (pc_prev);
7458 pc_prev = pic16_findPrevInstruction (pc);
7460 // now remove the redundant goto itself
7461 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7462 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7463 pic16_unlinkpCode (pc);
7464 pc = pic16_findPrevInstruction(pc_next->prev);
7465 isHandled = 1; // do not perform further optimizations
7471 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7472 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7473 if (dist < MAX_DIST_BCC) {
7475 switch (condBraType) {
7476 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7477 // no BDC on DIGIT CARRY available
7478 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7479 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7480 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7481 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7482 // no BNDC on DIGIT CARRY available
7483 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7484 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7485 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7487 // no replacement possible
7492 // ATTENTION: keep labels attached to BTFSx!
7493 // HINT: GOTO is label free (checked above)
7494 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7495 isHandled = 1; // do not perform further optimizations
7496 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7497 pic16_pCodeReplace (pc_prev, bcc);
7504 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7510 // (4) eliminate the following (common) tripel:
7512 // labels1: Bcc label2;
7513 // GOTO somewhere; ; <-- instruction referenced by pc
7515 // and replace it by
7516 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7518 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7519 // to <cont.> instead
7520 // ATTENTION: This optimization is only valid if <pred.> is
7521 // not a skip operation!
7522 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7523 // ATTENTION: no label may be attached to the GOTO instruction!
7524 if (isConditionalBranch(pc_prev)
7525 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7526 && (dist < MAX_DIST_BCC)
7527 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7528 && hasNoLabel(pc)) {
7529 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7532 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7533 isHandled = 1; // do not perform further optimizations
7534 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7535 pic16_pCodeReplace (pc_prev, newBcc);
7540 matchedInvertRule++;
7545 /* (5) now just turn GOTO into BRA */
7546 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7547 if (dist < MAX_DIST_BRA) {
7548 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7549 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7550 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7551 pic16_pCodeReplace (pc, newBra);
7556 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7559 } // if (!isHandled)
7566 pBlockRemoveUnusedLabels (pb);
7568 // This line enables goto chain resolution!
7569 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7572 } while (change); /* fixpoint iteration per pBlock */
7575 // emit some statistics concerning goto-optimization
7577 if (pic16_debug_verbose || pic16_pcode_verbose) {
7578 fprintf (stderr, "optimize-goto:\n"
7579 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7580 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7581 "\t%5d conditional \"skipping\" jumps inverted\n"
7582 "\t%5d GOTOs to next instruction removed\n"
7583 "\t%5d chained GOTOs resolved\n",
7584 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7587 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7591 #undef MAX_JUMPCHAIN_DEPTH
7592 #undef MAX_DIST_GOTO
7596 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7598 static void pBlockDestruct(pBlock *pb)
7609 /*-----------------------------------------------------------------*/
7610 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7611 /* name dbName and combine them */
7612 /* into one block */
7613 /*-----------------------------------------------------------------*/
7614 static void mergepBlocks(char dbName)
7617 pBlock *pb, *pbmerged = NULL,*pbn;
7619 pb = the_pFile->pbHead;
7621 //fprintf(stderr," merging blocks named %c\n",dbName);
7625 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7626 if( getpBlock_dbName(pb) == dbName) {
7628 //fprintf(stderr," merged block %c\n",dbName);
7633 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7634 /* pic16_addpCode2pBlock doesn't handle the tail: */
7635 pbmerged->pcTail = pb->pcTail;
7637 pb->prev->next = pbn;
7639 pbn->prev = pb->prev;
7644 //pic16_printpBlock(stderr, pbmerged);
7651 /*-----------------------------------------------------------------*/
7652 /* AnalyzeFlow - Examine the flow of the code and optimize */
7654 /* level 0 == minimal optimization */
7655 /* optimize registers that are used only by two instructions */
7656 /* level 1 == maximal optimization */
7657 /* optimize by looking at pairs of instructions that use the */
7659 /*-----------------------------------------------------------------*/
7661 static void AnalyzeFlow(int level)
7663 static int times_called=0;
7667 /* remove unused allocated registers before exiting */
7668 pic16_RemoveUnusedRegisters();
7673 /* if this is not the first time this function has been called,
7674 * then clean up old flow information */
7675 if(times_called++) {
7676 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7678 pic16_RegsUnMapLiveRanges();
7682 /* Phase 2 - Flow Analysis - Register Banking
7684 * In this phase, the individual flow blocks are examined
7685 * and register banking is fixed.
7689 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7690 pic16_FixRegisterBanking(pb);
7693 /* Phase 2 - Flow Analysis
7695 * In this phase, the pCode is partition into pCodeFlow
7696 * blocks. The flow blocks mark the points where a continuous
7697 * stream of instructions changes flow (e.g. because of
7698 * a call or goto or whatever).
7701 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7702 pic16_BuildFlow(pb);
7705 /* Phase 2 - Flow Analysis - linking flow blocks
7707 * In this phase, the individual flow blocks are examined
7708 * to determine their order of excution.
7711 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7715 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7716 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7717 pic16_createDF (pb);
7718 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7719 pic16_vcg_dump_default (pb);
7721 //pic16_destructDF (pb);
7725 if (0) releaseStack (); // releasing is costly...
7729 /* Phase 3 - Flow Analysis - Flow Tree
7731 * In this phase, the individual flow blocks are examined
7732 * to determine their order of execution.
7735 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7736 pic16_BuildFlowTree(pb);
7739 /* Phase x - Flow Analysis - Used Banks
7741 * In this phase, the individual flow blocks are examined
7742 * to determine the Register Banks they use
7746 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7751 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7752 pic16_pCodeRegMapLiveRanges(pb);
7754 pic16_RemoveUnusedRegisters();
7755 pic16_removeUnusedRegistersDF ();
7757 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7758 pic16_pCodeRegOptimizeRegUsage(level);
7767 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7772 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7775 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7776 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7777 pcflow = pcflow->next) {
7778 FillFlow(PCFL(pcflow));
7783 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7786 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7787 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7788 pcflow = pcflow->next) {
7789 FlowStats(PCFL(pcflow));
7795 /* VR -- no need to analyze banking in flow, but left here :
7796 * 1. because it may be used in the future for other purposes
7797 * 2. because if omitted we'll miss some optimization done here
7799 * Perhaps I should rename it to something else
7802 /*-----------------------------------------------------------------*/
7803 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7804 /* assigned to the registers. */
7806 /*-----------------------------------------------------------------*/
7808 void pic16_AnalyzeBanking(void)
7812 /* Phase x - Flow Analysis - Used Banks
7814 * In this phase, the individual flow blocks are examined
7815 * to determine the Register Banks they use
7825 if(!the_pFile)return;
7827 if(!pic16_options.no_banksel) {
7828 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7829 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7830 pic16_FixRegisterBanking(pb);
7835 /*-----------------------------------------------------------------*/
7836 /* buildCallTree - Look at the flow and extract all of the calls. */
7837 /*-----------------------------------------------------------------*/
7838 static set *register_usage(pBlock *pb);
7840 static void buildCallTree(void )
7852 /* Now build the call tree.
7853 First we examine all of the pCodes for functions.
7854 Keep in mind that the function boundaries coincide
7855 with pBlock boundaries.
7857 The algorithm goes something like this:
7858 We have two nested loops. The outer loop iterates
7859 through all of the pBlocks/functions. The inner
7860 loop iterates through all of the pCodes for
7861 a given pBlock. When we begin iterating through
7862 a pBlock, the variable pc_fstart, pCode of the start
7863 of a function, is cleared. We then search for pCodes
7864 of type PC_FUNCTION. When one is encountered, we
7865 initialize pc_fstart to this and at the same time
7866 associate a new pBranch object that signifies a
7867 branch entry. If a return is found, then this signifies
7868 a function exit point. We'll link the pCodes of these
7869 returns to the matching pc_fstart.
7871 When we're done, a doubly linked list of pBranches
7872 will exist. The head of this list is stored in
7873 `the_pFile', which is the meta structure for all
7874 of the pCode. Look at the pic16_printCallTree function
7875 on how the pBranches are linked together.
7878 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7879 pCode *pc_fstart=NULL;
7880 for(pc = pb->pcHead; pc; pc = pc->next) {
7882 if(isPCI(pc) && pc_fstart) {
7883 if(PCI(pc)->is2MemOp) {
7884 r = pic16_getRegFromInstruction2(pc);
7885 if(r && !strcmp(r->name, "POSTDEC1"))
7886 PCF(pc_fstart)->stackusage++;
7888 r = pic16_getRegFromInstruction(pc);
7889 if(r && !strcmp(r->name, "PREINC1"))
7890 PCF(pc_fstart)->stackusage--;
7895 if (PCF(pc)->fname) {
7898 sprintf(buf, "%smain", port->fun_prefix);
7899 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7900 //fprintf(stderr," found main \n");
7901 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7905 pbr = Safe_calloc(1,sizeof(pBranch));
7906 pbr->pc = pc_fstart = pc;
7909 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7911 // Here's a better way of doing the same:
7912 addSet(&pb->function_entries, pc);
7915 // Found an exit point in a function, e.g. return
7916 // (Note, there may be more than one return per function)
7918 pBranchLink(PCF(pc_fstart), PCF(pc));
7920 addSet(&pb->function_exits, pc);
7922 } else if(isCALL(pc)) {
7923 addSet(&pb->function_calls,pc);
7930 /* This is not needed because currently all register used
7931 * by a function are stored in stack -- VR */
7933 /* Re-allocate the registers so that there are no collisions
7934 * between local variables when one function call another */
7937 // pic16_deallocateAllRegs();
7939 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7947 /*-----------------------------------------------------------------*/
7948 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7949 /* all of the logical connections. */
7951 /* Essentially what's done here is that the pCode flow is */
7953 /*-----------------------------------------------------------------*/
7955 void pic16_AnalyzepCode(char dbName)
7966 /* Phase 1 - Register allocation and peep hole optimization
7968 * The first part of the analysis is to determine the registers
7969 * that are used in the pCode. Once that is done, the peep rules
7970 * are applied to the code. We continue to loop until no more
7971 * peep rule optimizations are found (or until we exceed the
7972 * MAX_PASSES threshold).
7974 * When done, the required registers will be determined.
7980 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7981 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7983 /* First, merge the labels with the instructions */
7984 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7985 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7987 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7988 //fprintf(stderr," analyze and merging block %c\n",dbName);
7989 pic16_pBlockMergeLabels(pb);
7992 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7997 changes = OptimizepCode(dbName);
8000 } while(changes && (i++ < MAX_PASSES));
8007 /* convert a series of movff's of local regs to stack, with a single call to
8008 * a support functions which does the same thing via loop */
8009 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8013 char *fname[]={"__lr_store", "__lr_restore"};
8015 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8017 pct = pic16_findNextInstruction(pcstart->next);
8020 pct = pc->next; //pic16_findNextInstruction(pc->next);
8021 // pc->print(stderr, pc);
8022 if(isPCI(pc) && PCI(pc)->label) {
8023 pbr = PCI(pc)->label;
8024 while(pbr && pbr->pc) {
8025 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8029 // pc->print(stderr, pc);
8031 pc->prev->next = pct;
8032 pct->prev = pc->prev;
8036 } while ((pc) && (pc != pcend));
8038 /* unlink movff instructions */
8039 pcstart->next = pcend;
8040 pcend->prev = pcstart;
8044 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8045 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8048 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8049 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8050 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8053 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8054 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8061 sym = newSymbol( fname[ entry?0:1 ], 0 );
8062 strcpy(sym->rname, fname[ entry?0:1 ]);
8063 checkAddSym(&externs, sym);
8065 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8070 /*-----------------------------------------------------------------*/
8071 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
8072 /* local registers to a support function call */
8073 /*-----------------------------------------------------------------*/
8074 void pic16_OptimizeLocalRegs(void)
8079 pCodeOpLocalReg *pclr;
8082 regs *r, *lastr=NULL, *firstr=NULL;
8083 pCode *pcstart=NULL, *pcend=NULL;
8088 * local_regs begin mark
8089 * MOVFF r0x01, POSTDEC1
8090 * MOVFF r0x02, POSTDEC1
8093 * MOVFF r0x0n, POSTDEC1
8094 * local_regs end mark
8096 * convert the above to the below:
8097 * MOVLW starting_register_index
8099 * MOVLW register_count
8100 * call __save_registers_in_stack
8106 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8107 inRegCount = regCount = 0;
8108 firstr = lastr = NULL;
8109 for(pc = pb->pcHead; pc; pc = pc->next) {
8111 /* hold current function name */
8112 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8114 if(pc && (pc->type == PC_INFO)) {
8117 if(pci->type == INF_LOCALREGS) {
8118 pclr = PCOLR(pci->oper1);
8120 if((pclr->type == LR_ENTRY_BEGIN)
8121 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8124 switch(pclr->type) {
8125 case LR_ENTRY_BEGIN:
8127 inRegCount = 1; regCount = 0;
8128 pcstart = pc; //pic16_findNextInstruction(pc->next);
8129 firstr = lastr = NULL;
8135 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8138 if(curFunc && inWparamList(curFunc+1)) {
8139 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8143 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8148 firstr = lastr = NULL;
8152 if(inRegCount == -1) {
8153 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8159 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8161 r = pic16_getRegFromInstruction(pc);
8163 r = pic16_getRegFromInstruction2(pc);
8164 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8165 if(!firstr)firstr = r;
8167 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8179 /*-----------------------------------------------------------------*/
8180 /* ispCodeFunction - returns true if *pc is the pCode of a */
8182 /*-----------------------------------------------------------------*/
8183 static bool ispCodeFunction(pCode *pc)
8186 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8192 /*-----------------------------------------------------------------*/
8193 /* findFunction - Search for a function by name (given the name) */
8194 /* in the set of all functions that are in a pBlock */
8195 /* (note - I expect this to change because I'm planning to limit */
8196 /* pBlock's to just one function declaration */
8197 /*-----------------------------------------------------------------*/
8198 static pCode *findFunction(char *fname)
8205 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8207 pc = setFirstItem(pb->function_entries);
8210 if((pc->type == PC_FUNCTION) &&
8212 (strcmp(fname, PCF(pc)->fname)==0))
8215 pc = setNextItem(pb->function_entries);
8223 static void MarkUsedRegisters(set *regset)
8228 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8229 // fprintf(stderr, "marking register = %s\t", r1->name);
8230 r2 = pic16_regWithIdx(r1->rIdx);
8231 // fprintf(stderr, "to register = %s\n", r2->name);
8237 static void pBlockStats(FILE *of, pBlock *pb)
8243 if(!pic16_pcode_verbose)return;
8245 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8247 // for now just print the first element of each set
8248 pc = setFirstItem(pb->function_entries);
8250 fprintf(of,";entry: ");
8253 pc = setFirstItem(pb->function_exits);
8255 fprintf(of,";has an exit\n");
8259 pc = setFirstItem(pb->function_calls);
8261 fprintf(of,";functions called:\n");
8264 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8265 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8267 pc = setNextItem(pb->function_calls);
8271 r = setFirstItem(pb->tregisters);
8273 int n = elementsInSet(pb->tregisters);
8275 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8278 fprintf(of, "; %s\n",r->name);
8279 r = setNextItem(pb->tregisters);
8283 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8286 /*-----------------------------------------------------------------*/
8287 /*-----------------------------------------------------------------*/
8289 static void sequencepCode(void)
8295 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8297 pb->seq = GpCodeSequenceNumber+1;
8299 for( pc = pb->pcHead; pc; pc = pc->next)
8300 pc->seq = ++GpCodeSequenceNumber;
8306 /*-----------------------------------------------------------------*/
8307 /*-----------------------------------------------------------------*/
8308 static set *register_usage(pBlock *pb)
8311 set *registers=NULL;
8312 set *registersInCallPath = NULL;
8314 /* check recursion */
8316 pc = setFirstItem(pb->function_entries);
8323 if(pc->type != PC_FUNCTION)
8324 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8326 pc = setFirstItem(pb->function_calls);
8327 for( ; pc; pc = setNextItem(pb->function_calls)) {
8329 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8330 char *dest = pic16_get_op_from_instruction(PCI(pc));
8332 pcn = findFunction(dest);
8334 registersInCallPath = register_usage(pcn->pb);
8336 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8341 pBlockStats(stderr,pb); // debug
8344 // Mark the registers in this block as used.
8346 MarkUsedRegisters(pb->tregisters);
8347 if(registersInCallPath) {
8348 /* registers were used in the functions this pBlock has called */
8349 /* so now, we need to see if these collide with the ones we are */
8352 regs *r1,*r2, *newreg;
8354 DFPRINTF((stderr,"comparing registers\n"));
8356 r1 = setFirstItem(registersInCallPath);
8359 r2 = setFirstItem(pb->tregisters);
8361 while(r2 && (r1->type != REG_STK)) {
8363 if(r2->rIdx == r1->rIdx) {
8364 newreg = pic16_findFreeReg(REG_GPR);
8368 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8372 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8373 r1->rIdx, newreg->rIdx));
8374 r2->rIdx = newreg->rIdx;
8375 //if(r2->name) Safe_free(r2->name);
8377 r2->name = Safe_strdup(newreg->name);
8381 newreg->wasUsed = 1;
8383 r2 = setNextItem(pb->tregisters);
8386 r1 = setNextItem(registersInCallPath);
8389 /* Collisions have been resolved. Now free the registers in the call path */
8390 r1 = setFirstItem(registersInCallPath);
8392 if(r1->type != REG_STK) {
8393 newreg = pic16_regWithIdx(r1->rIdx);
8396 r1 = setNextItem(registersInCallPath);
8400 // MarkUsedRegisters(pb->registers);
8402 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8405 DFPRINTF((stderr,"returning regs\n"));
8407 DFPRINTF((stderr,"not returning regs\n"));
8409 DFPRINTF((stderr,"pBlock after register optim.\n"));
8410 pBlockStats(stderr,pb); // debug
8416 /*-----------------------------------------------------------------*/
8417 /* pct2 - writes the call tree to a file */
8419 /*-----------------------------------------------------------------*/
8420 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8424 // set *registersInCallPath = NULL;
8430 fprintf(of, "recursive function\n");
8431 return; //recursion ?
8434 pc = setFirstItem(pb->function_entries);
8441 for(i=0;i<indent;i++) // Indentation
8445 if(pc->type == PC_FUNCTION) {
8446 usedstack += PCF(pc)->stackusage;
8447 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8448 } else return; // ???
8451 pc = setFirstItem(pb->function_calls);
8452 for( ; pc; pc = setNextItem(pb->function_calls)) {
8454 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8455 char *dest = pic16_get_op_from_instruction(PCI(pc));
8457 pcn = findFunction(dest);
8459 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8461 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8469 /*-----------------------------------------------------------------*/
8470 /* pic16_printCallTree - writes the call tree to a file */
8472 /*-----------------------------------------------------------------*/
8474 void pic16_printCallTree(FILE *of)
8486 fprintf(of, "\npBlock statistics\n");
8487 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8491 fprintf(of,"Call Tree\n");
8492 pbr = the_pFile->functions;
8496 if(!ispCodeFunction(pc))
8497 fprintf(of,"bug in call tree");
8500 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8502 while(pc->next && !ispCodeFunction(pc->next)) {
8504 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8505 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8513 fprintf(of,"\n**************\n\na better call tree\n");
8514 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8519 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8520 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8526 /*-----------------------------------------------------------------*/
8528 /*-----------------------------------------------------------------*/
8530 static void InlineFunction(pBlock *pb)
8538 pc = setFirstItem(pb->function_calls);
8540 for( ; pc; pc = setNextItem(pb->function_calls)) {
8543 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8549 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8551 //fprintf(stderr,"Cool can inline:\n");
8552 //pcn->print(stderr,pcn);
8554 //fprintf(stderr,"recursive call Inline\n");
8555 InlineFunction(pcn->pb);
8556 //fprintf(stderr,"return from recursive call Inline\n");
8559 At this point, *pc points to a CALL mnemonic, and
8560 *pcn points to the function that is being called.
8562 To in-line this call, we need to remove the CALL
8563 and RETURN(s), and link the function pCode in with
8569 /* Remove the CALL */
8573 /* remove callee pBlock from the pBlock linked list */
8574 removepBlock(pcn->pb);
8582 /* Remove the Function pCode */
8583 pct = pic16_findNextInstruction(pcn->next);
8585 /* Link the function with the callee */
8586 pc->next = pcn->next;
8587 pcn->next->prev = pc;
8589 /* Convert the function name into a label */
8591 pbr = Safe_calloc(1,sizeof(pBranch));
8592 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8594 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8595 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8597 /* turn all of the return's except the last into goto's */
8598 /* check case for 2 instruction pBlocks */
8599 pce = pic16_findNextInstruction(pcn->next);
8601 pCode *pce_next = pic16_findNextInstruction(pce->next);
8603 if(pce_next == NULL) {
8604 /* found the last return */
8605 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8607 //fprintf(stderr,"found last return\n");
8608 //pce->print(stderr,pce);
8609 pce->prev->next = pc_call->next;
8610 pc_call->next->prev = pce->prev;
8611 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8621 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8627 /*-----------------------------------------------------------------*/
8629 /*-----------------------------------------------------------------*/
8631 void pic16_InlinepCode(void)
8640 if(!functionInlining)
8643 /* Loop through all of the function definitions and count the
8644 * number of times each one is called */
8645 //fprintf(stderr,"inlining %d\n",__LINE__);
8647 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8649 pc = setFirstItem(pb->function_calls);
8651 for( ; pc; pc = setNextItem(pb->function_calls)) {
8654 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8655 if(pcn && isPCF(pcn)) {
8656 PCF(pcn)->ncalled++;
8659 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8664 //fprintf(stderr,"inlining %d\n",__LINE__);
8666 /* Now, Loop through the function definitions again, but this
8667 * time inline those functions that have only been called once. */
8669 InlineFunction(the_pFile->pbHead);
8670 //fprintf(stderr,"inlining %d\n",__LINE__);
8672 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8677 char *pic_optype_names[]={
8678 "PO_NONE", // No operand e.g. NOP
8679 "PO_W", // The working register (as a destination)
8680 "PO_WREG", // The working register (as a file register)
8681 "PO_STATUS", // The 'STATUS' register
8682 "PO_BSR", // The 'BSR' register
8683 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8685 "PO_INDF0", // The Indirect register
8686 "PO_INTCON", // Interrupt Control register
8687 "PO_GPR_REGISTER", // A general purpose register
8688 "PO_GPR_BIT", // A bit of a general purpose register
8689 "PO_GPR_TEMP", // A general purpose temporary register
8690 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8691 "PO_PCL", // Program counter Low register
8692 "PO_PCLATH", // Program counter Latch high register
8693 "PO_PCLATU", // Program counter Latch upper register
8694 "PO_PRODL", // Product Register Low
8695 "PO_PRODH", // Product Register High
8696 "PO_LITERAL", // A constant
8697 "PO_REL_ADDR", // A relative address
8698 "PO_IMMEDIATE", // (8051 legacy)
8699 "PO_DIR", // Direct memory (8051 legacy)
8700 "PO_CRY", // bit memory (8051 legacy)
8701 "PO_BIT", // bit operand.
8702 "PO_STR", // (8051 legacy)
8704 "PO_WILD", // Wild card operand in peep optimizer
8705 "PO_TWO_OPS" // combine two operands
8709 char *dumpPicOptype(PIC_OPTYPE type)
8711 assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8712 return (pic_optype_names[ type ]);
8716 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8719 #define MAX_COMMON_BANK_SIZE 32
8720 #define FIRST_PSEUDO_BANK_NR 1000
8722 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8723 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8724 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8727 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8730 pseudoBankNr bank; // number assigned to this pseudoBank
8731 unsigned int size; // number of operands assigned to this bank
8732 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8735 /*----------------------------------------------------------------------*/
8736 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8737 /*----------------------------------------------------------------------*/
8738 unsigned int hashSymbol (const char *str)
8740 unsigned int res = 0;
8745 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8752 /*-----------------------------------------------------------------------*/
8753 /* compareSymbol - return 1 iff sym1 equals sym2 */
8754 /*-----------------------------------------------------------------------*/
8755 int compareSymbol (const void *sym1, const void *sym2)
8757 char *s1 = (char*) sym1;
8758 char *s2 = (char*) sym2;
8760 return (strcmp (s1,s2) == 0);
8763 /*-----------------------------------------------------------------------*/
8764 /* comparePre - return 1 iff p1 == p2 */
8765 /*-----------------------------------------------------------------------*/
8766 int comparePtr (const void *p1, const void *p2)
8771 /*----------------------------------------------------------*/
8772 /* getSymbolFromOperand - return a pointer to the symbol in */
8773 /* the given operand and its length */
8774 /*----------------------------------------------------------*/
8775 char *getSymbolFromOperand (char *op, int *len)
8780 if (!op) return NULL;
8782 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8784 if (*sym == '(') sym++;
8787 while (((*curr >= 'A') && (*curr <= 'Z'))
8788 || ((*curr >= 'a') && (*curr <= 'z'))
8789 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8790 || (*curr == '_')) {
8791 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8799 /*--------------------------------------------------------------------------*/
8800 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8801 /*--------------------------------------------------------------------------*/
8802 char *getSymFromBank (pseudoBankNr bank)
8806 if (bank < 0) return "<INVALID BANK NR>";
8807 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8810 /*-----------------------------------------------------------------------*/
8811 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8812 /* bank number (uses hTab sym2bank), if the */
8813 /* symbol is not yet assigned a pseudo bank it */
8814 /* is assigned one here */
8815 /*-----------------------------------------------------------------------*/
8816 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8818 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8824 hash = hashSymbol (op) % sym2bank->size;
8825 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8826 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8828 if (bank == UNKNOWN_BANK) {
8829 // create a pseudo bank for the operand
8831 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8832 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8833 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8834 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8836 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8844 /*--------------------------------------------------------------------*/
8845 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8846 /*--------------------------------------------------------------------*/
8847 int isBanksel (pCode *pc)
8851 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8852 // BANKSEL <variablename> or MOVLB <banknr>
8853 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8857 // check for inline assembler BANKSELs
8858 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8859 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8860 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8864 // assume pc is no BANKSEL instruction
8868 /*---------------------------------------------------------------------------------*/
8869 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8870 /* This method can not guarantee to find all modifications of the */
8871 /* BSR (e.g. via INDirection registers) but covers all compiler */
8872 /* generated plus some cases. */
8873 /*---------------------------------------------------------------------------------*/
8874 int invalidatesBSR(pCode *pc)
8876 // assembler directives invalidate BSR (well, they might, we don't know)
8877 if (isPCAD(pc)) return 1;
8879 // only ASMDIRs and pCodeInstructions can invalidate BSR
8880 if (!isPCI(pc)) return 0;
8882 // we have a pCodeInstruction
8884 // check for BSR modifying instructions
8885 switch (PCI(pc)->op) {
8889 case POC_RETFIE: // might be used as CALL replacement
8890 case POC_RETLW: // might be used as CALL replacement
8891 case POC_RETURN: // might be used as CALL replacement
8896 default: // other instruction do not change BSR unless BSR is an explicit operand!
8897 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8901 // no change of BSR possible/probable
8905 /*------------------------------------------------------------*/
8906 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8907 /* the symbol referenced in this BANKSEL */
8908 /*------------------------------------------------------------*/
8909 pseudoBankNr getBankFromBanksel (pCode *pc)
8912 int data = (int)NULL;
8914 if (!pc) return INVALID_BANK;
8916 if (isPCAD(pc) && PCAD(pc)->directive) {
8917 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8918 // get symbolname from PCAD(pc)->arg
8919 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8920 sym = PCAD(pc)->arg;
8921 data = getPseudoBankNrFromOperand (sym);
8922 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8923 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8924 // get (literal) bank number from PCAD(pc)->arg
8925 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8926 assert (0 && "not yet implemented - turn off banksel optimization for now");
8928 } else if (isPCI(pc)) {
8929 if (PCI(pc)->op == POC_BANKSEL) {
8930 // get symbolname from PCI(pc)->pcop->name (?)
8931 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8932 sym = PCI(pc)->pcop->name;
8933 data = getPseudoBankNrFromOperand (sym);
8934 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8935 } else if (PCI(pc)->op == POC_MOVLB) {
8936 // get (literal) bank number from PCI(pc)->pcop->name
8937 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8938 assert (0 && "not yet implemented - turn off banksel optimization for now");
8943 // no assigned bank could be found
8944 return UNKNOWN_BANK;
8949 /*------------------------------------------------------------------------------*/
8950 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8951 /*------------------------------------------------------------------------------*/
8952 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8956 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8959 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8960 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8962 if (data->bank != bank)
8969 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8973 /*------------------------------------------------------------------*/
8974 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8975 /* bank is selected at a given pCode */
8976 /*------------------------------------------------------------------*/
8978 /* Create a graph with pseudo banks as its nodes and switches between
8979 * these as edges (with the edge weight representing the absolute
8980 * number of BANKSELs from one to the other).
8981 * Removes redundand BANKSELs instead iff mod == 1.
8982 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8983 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8985 * TODO: check ALL instructions operands if they modify BSR directly...
8987 * pb - the pBlock to annotate
8988 * mod - select either graph creation (0) or BANKSEL removal (1)
8990 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8992 pCode *pc, *pc_next;
8993 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8994 int isBankselect = 0;
8995 unsigned int banksels=0;
8999 pc = pic16_findNextInstruction(pb->pcHead);
9001 isBankselect = isBanksel (pc);
9002 pc_next = pic16_findNextInstruction (pc->next);
9004 if (!hasNoLabel (pc)) {
9005 // we don't know our predecessors -- assume different BSRs
9006 prevBSR = UNKNOWN_BANK;
9007 pseudoBSR = UNKNOWN_BANK;
9008 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9011 // check if this is a BANKSEL instruction
9013 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9014 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9016 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9017 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9018 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9019 pic16_unlinkpCode (pc);
9023 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9028 if (!isBankselect && invalidatesBSR(pc)) {
9029 // check if this instruction invalidates the pseudoBSR
9030 pseudoBSR = UNKNOWN_BANK;
9031 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9034 prevBSR = pseudoBSR;
9041 /*------------------------------------------------------------------------------------*/
9042 /* assignToSameBank - returns 0 on success or an error code */
9043 /* 1 - common bank would be too large */
9044 /* 2 - assignment to fixed (absolute) bank not performed */
9046 /* This functions assumes that unsplittable operands are already assigned to the same */
9047 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
9048 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
9049 /* TODO: Symbols with an abslute address must be handled specially! */
9050 /*------------------------------------------------------------------------------------*/
9051 int assignToSameBank (int bank0, int bank1, int doAbs)
9053 int eff0, eff1, dummy;
9054 pseudoBank *pbank0, *pbank1;
9057 eff0 = getEffectiveBank (bank0);
9058 eff1 = getEffectiveBank (bank1);
9060 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9062 // nothing to do if already same bank
9063 if (eff0 == eff1) return 0;
9065 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9068 // ensure eff0 < eff1
9070 // swap eff0 and eff1
9079 // now assign bank eff1 to bank eff0
9080 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9082 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9083 pbank0->bank = eff0;
9086 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9090 hitem = hTabSearch (coerce, eff1 % coerce->size);
9091 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9092 hitem = hitem->next;
9094 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9097 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9098 pbank0->bank, pbank0->size,
9099 getSymFromBank (eff0), getSymFromBank (eff1));
9103 if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9105 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9106 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9107 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9108 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9112 pbank0->size += pbank1->size;
9114 if (pbank1->ref == 0) Safe_free (pbank1);
9120 hitem->item = pbank0;
9122 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9125 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9130 /*----------------------------------------------------------------*/
9131 /* mergeGraphNodes - combines two nodes into one and modifies all */
9132 /* edges to and from the nodes accordingly */
9133 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9134 /* then also (B,A) must be an edge (possibly with weight 0). */
9135 /*----------------------------------------------------------------*/
9136 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9138 GraphEdge *edge, *backedge, *nextedge;
9142 assert (node1 && node2);
9143 assert (node1 != node2);
9145 // add all edges starting at node2 to node1
9148 nextedge = edge->next;
9150 backedge = getGEdge (node, node2);
9152 backweight = backedge->weight;
9155 // insert edges (node1,node) and (node,node1)
9156 addGEdge2 (node1, node, edge->weight, backweight);
9157 // remove edges (node, node2) and (node2, node)
9158 remGEdge (node2, node);
9159 remGEdge (node, node2);
9163 // now node2 should not be referenced by any other GraphNode...
9164 //remGNode (adj, node2->data, node2->hash);
9167 /*----------------------------------------------------------------*/
9168 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9169 /*----------------------------------------------------------------*/
9170 void showGraph (Graph *g)
9174 pseudoBankNr bankNr;
9181 bankNr = getEffectiveBank (node->hash);
9182 assert (bankNr >= 0);
9183 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9185 bankNr = pbank->bank;
9191 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9194 if (edge->weight > 0)
9195 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9202 /*---------------------------------------------------------------*/
9203 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9204 /*---------------------------------------------------------------*/
9205 void pic16_OptimizeBanksel ()
9207 GraphNode *node, *node1, *node1next;
9210 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9211 GraphEdge *edge, *backedge;
9213 int maxWeight, weight, mergeMore, absMaxWeight;
9214 pseudoBankNr curr0, curr1;
9217 pseudoBankNr bankNr;
9218 char *base_symbol0, *base_symbol1;
9223 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9225 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9227 if (!the_pFile || !the_pFile->pbHead) return;
9229 adj = newGraph (NULL);
9230 sym2bank = newHashTable ( 255 );
9231 bank2sym = newHashTable ( 255 );
9232 coerce = newHashTable ( 255 );
9234 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9235 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9236 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9240 // assign symbols with absolute addresses to their respective bank nrs
9241 set = pic16_fix_udata;
9242 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9243 bankNr = reg->address >> 8;
9244 node = getOrAddGNode (adj, NULL, bankNr);
9245 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9246 assignToSameBank (node->hash, bankNr, 1);
9248 assert (bankNr >= 0);
9249 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9251 pbank = Safe_calloc (1, sizeof (pseudoBank));
9252 pbank->bank = reg->address >> 8; //FIXED_BANK;
9255 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9257 assert (pbank->bank == (reg->address >> 8));
9258 pbank->bank = reg->address >> 8; //FIXED_BANK;
9260 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9265 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9266 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9269 if (node->hash < 0) { node = node->next; continue; }
9270 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9273 if (node1->hash < 0) { node1 = node1->next; continue; }
9274 node1next = node1->next;
9275 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9276 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9277 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9278 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9279 if (assignToSameBank (node->hash, node1->hash, 0)) {
9280 fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9281 assert (0 && "Could not assign a symbol to a bank!");
9283 mergeGraphNodes (node, node1);
9285 if (node->hash < node1->hash)
9286 mergeGraphNodes (node, node1);
9288 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9298 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9299 // assign tightly coupled operands to the same (pseudo) bank
9300 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9308 curr0 = getEffectiveBank (node->hash);
9309 if (curr0 < 0) { node = node->next; continue; }
9312 assert (edge->src == node);
9313 backedge = getGEdge (edge->node, edge->src);
9314 weight = edge->weight + (backedge ? backedge->weight : 0);
9315 curr1 = getEffectiveBank (edge->node->hash);
9316 if (curr1 < 0) { edge = edge->next; continue; }
9318 // merging is only useful if the items are not assigned to the same bank already...
9319 if (curr0 != curr1 && weight > maxWeight) {
9320 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9329 if (maxWeight > 0) {
9331 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9332 max->src->hash, getSymFromBank (max->src->hash),
9333 max->node->hash, getSymFromBank (max->node->hash));
9336 node = getGNode (adj, max->src->data, max->src->hash);
9337 node1 = getGNode (adj, max->node->data, max->node->hash);
9339 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9340 if (max->src->hash < max->node->hash)
9341 mergeGraphNodes (node, node1);
9343 mergeGraphNodes (node1, node);
9345 remGEdge (node, node1);
9346 remGEdge (node1, node);
9357 // remove redundant BANKSELs
9358 //fprintf (stderr, "removing redundant BANKSELs\n");
9359 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9360 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9365 fprintf (stderr, "display graph\n");
9370 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9373 /*** END of stuff belonging to the BANKSEL optimization ***/
9377 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9379 typedef unsigned int symbol_t;
9380 typedef unsigned int valnum_t;
9381 //typedef unsigned int hash_t;
9384 #define INT_TO_PTR(x) (((char *) 0) + (x))
9388 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9391 static int pic16_regIsLocal (regs *r);
9392 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9395 static unsigned int pic16_df_removed_pcodes = 0;
9396 static unsigned int pic16_df_saved_bytes = 0;
9397 static unsigned int df_findall_sameflow = 0;
9398 static unsigned int df_findall_otherflow = 0;
9399 static unsigned int df_findall_in_vals = 0;
9401 static void pic16_df_stats () {
9403 if (pic16_debug_verbose || pic16_pcode_verbose) {
9404 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9405 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9406 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9410 /* Remove a pCode iff possible:
9411 * - previous pCode is no SKIP
9413 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9414 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9415 pCode *pcprev, *pcnext;
9416 char buf[256], *total=NULL;
9419 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9421 pcprev = pic16_findPrevInstruction (pc->prev);
9422 pcnext = pic16_findNextInstruction (pc->next);
9424 /* move labels to next instruction (if possible) */
9425 if (PCI(pc)->label && !pcnext) return 0;
9427 /* if this is a SKIP with side-effects -- do not remove */
9428 /* XXX: might try to replace this one with the side-effect only version */
9430 && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9433 switch (PCI(pc)->op)
9437 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9438 pic16_pCodeReplace( pc, newpc );
9442 newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9443 pic16_pCodeReplace( pc, newpc );
9448 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9449 pic16_pCodeReplace( pc, newpc );
9453 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9454 pic16_pCodeReplace( pc, newpc );
9463 /* if previous instruction is a skip -- do not remove */
9464 if (pcprev && isPCI_SKIP(pcprev)) {
9465 if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9466 /* preceeding SKIP could not be removed -- keep this instruction! */
9471 if (PCI(pc)->label) {
9472 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9473 //pc->print (stderr, pc);
9474 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9475 PCI(pc)->label = NULL;
9478 /* update statistics */
9479 pic16_df_removed_pcodes++;
9480 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9482 /* remove the pCode */
9483 pic16_pCode2str (buf, 256, pc);
9484 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9485 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9486 len = strlen (buf) + strlen (comment) + 10;
9487 total = (char *) Safe_malloc (len);
9488 SNPRINTF (total, len, "%s: %s", comment, buf);
9489 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9493 /* actually unlink it from the pBlock -- also remove from to/from lists */
9494 pic16_pCodeUnlink (pc);
9496 /* remove the pCode -- release registers */
9499 /* report success */
9504 /* ======================================================================== */
9505 /* === SYMBOL HANDLING ==================================================== */
9506 /* ======================================================================== */
9508 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9509 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9510 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9512 /** Calculate a hash for a given string.
9513 * If len == 0 the string is assumed to be NUL terminated. */
9514 static hash_t symbolHash (const char *str, unsigned int len) {
9518 hash = (hash << 2) ^ *str;
9523 hash = (hash << 2) ^ *str;
9530 /** Return 1 iff strings v1 and v2 are identical. */
9531 static int symcmp (const void *v1, const void *v2) {
9532 return !strcmp ((const char *) v1, (const char *) v2);
9535 /** Return 1 iff pointers v1 and v2 are identical. */
9536 static int ptrcmp (const void *v1, const void *v2) {
9540 enum { SPO_WREG=0x1000,
9580 /* Return the unique symbol_t for the given string. */
9581 static symbol_t symFromStr (const char *str) {
9586 if (!map_symToStr) {
9588 struct { char *name; symbol_t sym; } predefsyms[] = {
9590 {"STATUS", SPO_STATUS},
9591 {"PRODL", SPO_PRODL},
9592 {"PRODH", SPO_PRODH},
9593 {"INDF0", SPO_INDF0},
9594 {"POSTDEC0", SPO_POSTDEC0},
9595 {"POSTINC0", SPO_POSTINC0},
9596 {"PREINC0", SPO_PREINC0},
9597 {"PLUSW0", SPO_PLUSW0},
9598 {"INDF1", SPO_INDF1},
9599 {"POSTDEC1", SPO_POSTDEC1},
9600 {"POSTINC1", SPO_POSTINC1},
9601 {"PREINC1", SPO_PREINC1},
9602 {"PLUSW1", SPO_PLUSW1},
9603 {"INDF2", SPO_INDF2},
9604 {"POSTDEC2", SPO_POSTDEC2},
9605 {"POSTINC2", SPO_POSTINC2},
9606 {"PREINC2", SPO_PREINC2},
9607 {"PLUSW2", SPO_PLUSW2},
9608 {"STKPTR", SPO_STKPTR},
9613 {"FSR0L", SPO_FSR0L},
9614 {"FSR0H", SPO_FSR0H},
9615 {"FSR1L", SPO_FSR1L},
9616 {"FSR1H", SPO_FSR1H},
9617 {"FSR2L", SPO_FSR2L},
9618 {"FSR2H", SPO_FSR2H},
9620 {"PCLATH", SPO_PCLATH},
9621 {"PCLATU", SPO_PCLATU},
9622 {"TABLAT", SPO_TABLAT},
9623 {"TBLPTRL", SPO_TBLPTRL},
9624 {"TBLPTRH", SPO_TBLPTRH},
9625 {"TBLPTRU", SPO_TBLPTRU},
9629 map_strToSym = newHashTable (128);
9630 map_symToStr = newHashTable (128);
9632 for (i=0; predefsyms[i].name; i++) {
9635 /* enter new symbol */
9636 sym = predefsyms[i].sym;
9637 name = predefsyms[i].name;
9638 res = Safe_strdup (name);
9639 hash = symbolHash (name, 0);
9641 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9642 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9646 hash = symbolHash (str, 0) % map_strToSym->size;
9648 /* find symbol in table */
9649 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9651 //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9655 /* enter new symbol */
9657 res = Safe_strdup (str);
9659 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9660 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9662 //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9668 static const char *strFromSym (symbol_t sym) {
9669 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9673 /* ======================================================================== */
9674 /* === DEFINITION MAP HANDLING ============================================ */
9675 /* ======================================================================== */
9677 /* A defmap provides information about which symbol is defined by which pCode.
9678 * The most recent definitions are prepended to the list, so that the most
9679 * recent definition can be found by forward scanning the list.
9680 * pc2: MOVFF r0x00, r0x01
9682 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9684 * We attach one defmap to each flow object, and each pCode will occur at
9685 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9686 * used to find definitions for a pCode in its own defmap that precede pCode.
9689 typedef struct defmap_s {
9690 symbol_t sym; /** symbol this item refers to */
9693 unsigned int in_mask:8; /** mask leaving in accessed bits */
9694 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9695 int isRead:1; /** sym/mask is read */
9696 int isWrite:1; /** sym/mask is written */
9700 pCode *pc; /** pCode this symbol is refrenced at */
9701 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9702 valnum_t val; /** new unique number for this value (if isWrite) */
9703 struct defmap_s *prev, *next; /** link to previous an next definition */
9706 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9707 static int defmap_free_count = 0; /** number of released defmap items */
9709 /* Returns a defmap_t with the specified data; this will be the new list head.
9710 * next - pointer to the current list head */
9711 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9716 defmap_free = map->next;
9717 --defmap_free_count;
9719 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9722 map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9723 map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9724 map->acc.access.isRead = (isRead != 0);
9725 map->acc.access.isWrite = (isWrite != 0);
9728 map->val = (isWrite ? val : 0);
9731 if (next) next->prev = map;
9736 /* Returns a copy of the single defmap item. */
9737 static defmap_t *copyDefmap (defmap_t *map) {
9738 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9739 memcpy (res, map, sizeof (defmap_t));
9745 /* Insert a defmap item after the specified one. */
9746 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9747 if (!ref || !newItem) return 1;
9749 newItem->next = ref->next;
9750 newItem->prev = ref;
9751 ref->next = newItem;
9752 if (newItem->next) newItem->next->prev = newItem;
9757 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9758 * item is copied before insertion into chain and therefore left untouched.
9759 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9760 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9763 while (dummy && (dummy->sym != item->sym
9764 || dummy->pc != item->pc
9765 || dummy->acc.accessmethod != item->acc.accessmethod
9766 || dummy->val != item->val
9767 || dummy->in_val != item->in_val)) {
9768 dummy = dummy->next;
9771 /* item already present? */
9772 if (dummy) return 0;
9774 /* otherwise: insert copy of item */
9775 dummy = copyDefmap (item);
9776 dummy->next = *head;
9777 if (*head) (*head)->prev = dummy;
9783 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9784 static void deleteDefmap (defmap_t *map) {
9787 /* unlink from chain -- fails for the first item (head is not updated!) */
9788 if (map->next) map->next->prev = map->prev;
9789 if (map->prev) map->prev->next = map->next;
9792 memset (map, 0, sizeof (defmap_t));
9794 /* save for future use */
9795 map->next = defmap_free;
9797 ++defmap_free_count;
9800 /* Release all defmaps referenced from map. */
9801 static void deleteDefmapChain (defmap_t **_map) {
9802 defmap_t *map, *next;
9808 /* find list head */
9809 while (map && map->prev) map = map->prev;
9811 /* delete all items */
9821 /* Free all defmap items. */
9822 static void freeDefmap (defmap_t **_map) {
9830 /* find list head */
9831 while (map->prev) map = map->prev;
9833 /* release all items */
9843 /* Returns the most recent definition for the given symbol preceeding pc.
9844 * If no definition is found, NULL is returned.
9845 * If pc == NULL the whole list is scanned. */
9846 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9847 defmap_t *curr = map;
9850 /* skip all definitions up to pc */
9851 while (curr && (curr->pc != pc)) curr = curr->next;
9853 /* pc not in the list -- scan the whole list for definitions */
9855 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9858 /* skip all definitions performed by pc */
9859 while (curr && (curr->pc == pc)) curr = curr->next;
9863 /* find definition for sym */
9864 while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9872 /* Returns the first use (read) of the given symbol AFTER pc.
9873 * If no such use is found, NULL is returned.
9874 * If pc == NULL the whole list is scanned. */
9875 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9876 defmap_t *curr = map, *prev = NULL;
9879 /* skip all definitions up to pc */
9880 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9882 /* pc not in the list -- scan the whole list for definitions */
9884 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9888 /* find end of list */
9889 while (curr && curr->next) curr = curr->next;
9892 /* find use of sym (scan list backwards) */
9893 while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9899 /* Return the defmap entry for sym AT pc.
9900 * If none is found, NULL is returned.
9901 * If more than one entry is found an assertion is triggered. */
9902 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9903 defmap_t *res = NULL;
9905 /* find entries for pc */
9906 while (map && map->pc != pc) map = map->next;
9908 /* find first entry for sym @ pc */
9909 while (map && map->pc == pc && map->sym != sym) map = map->next;
9911 /* no entry found */
9912 if (!map) return NULL;
9914 /* check for more entries */
9917 while (map && map->pc == pc) {
9918 /* more than one entry for sym @ pc found? */
9919 assert (map->sym != sym);
9923 /* return single entry for sym @ pc */
9927 /* Modifies the definition of sym at pCode to newval.
9928 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9930 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9933 /* find definitions of pc */
9934 while (m && m->pc != pc) m = m->next;
9936 /* find definition of sym at pc */
9937 while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9939 /* no definition found */
9945 /* update following uses of sym */
9946 while (m && m->pc == pc) m = m->prev;
9948 if (m->sym == sym) {
9950 if (m->acc.access.isWrite) m = NULL;
9958 /* ======================================================================== */
9959 /* === STACK ROUTINES ===================================================== */
9960 /* ======================================================================== */
9962 typedef struct stack_s {
9964 struct stack_s *next;
9967 typedef stackitem_t *dynstack_t;
9968 static stackitem_t *free_stackitems = NULL;
9970 /* Create a stack with one item. */
9971 static dynstack_t *newStack () {
9972 dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9977 /* Remove a stack -- its items are only marked free. */
9978 static void deleteStack (dynstack_t *s) {
9984 i->next = free_stackitems;
9985 free_stackitems = i;
9990 /* Release all stackitems. */
9991 static void releaseStack () {
9994 while (free_stackitems) {
9995 i = free_stackitems->next;
9996 Safe_free(free_stackitems);
9997 free_stackitems = i;
10001 static void stackPush (dynstack_t *stack, void *data) {
10004 if (free_stackitems) {
10005 i = free_stackitems;
10006 free_stackitems = free_stackitems->next;
10008 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
10015 static void *stackPop (dynstack_t *stack) {
10019 if (stack && *stack) {
10020 data = (*stack)->data;
10022 *stack = (*stack)->next;
10023 i->next = free_stackitems;
10024 free_stackitems = i;
10032 static int stackContains (dynstack_t *s, void *data) {
10037 if (i->data == data) return 1;
10046 static int stackIsEmpty (dynstack_t *s) {
10047 return (*s == NULL);
10056 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10057 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10059 s->lastdef = lastdef;
10063 static void deleteState (state_t *s) {
10067 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10070 /* scan working list for state */
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;
10083 /* is i == state? -- state not new */
10084 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10089 /* not found -- state is new */
10093 static inline valnum_t newValnum ();
10095 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10098 if (!pb) return "<unknown function>";
10100 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10101 if (pc && isPCF(pc)) return PCF(pc)->fname;
10102 else return "<unknown function>";
10105 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10109 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10111 /* find initial value (assigning pc == NULL) */
10112 map = PCFL(pcfl)->in_vals;
10113 while (map && map->sym != sym) map = map->next;
10115 /* initial value already present? */
10117 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10121 /* create a new initial value */
10122 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10123 PCFL(pcfl)->in_vals = map;
10124 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10128 /* insert map as last item in pcfl's defmap */
10129 if (!prev) prev = PCFL(pcfl)->defmap;
10131 PCFL(pcfl)->defmap = map;
10133 while (prev->next) prev = prev->next;
10142 /* Find all reaching definitions for sym at pc.
10143 * A new (!) list of definitions is returned.
10144 * Returns the number of reaching definitions found.
10145 * The defining defmap entries are returned in *chain.
10147 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10152 pCodeFlowLink *succ;
10154 dynstack_t *todo; /** stack of state_t */
10155 dynstack_t *done; /** stack of state_t */
10157 int firstState, n_defs;
10159 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10162 /* initialize return list */
10165 /* wildcard symbol? */
10166 if (!sym) return 0;
10168 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10170 map = PCI(pc)->pcflow->defmap;
10172 res = defmapFindDef (map, sym, pc);
10173 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10175 #define USE_PRECALCED_INVALS 1
10176 #if USE_PRECALCED_INVALS
10177 if (!res && PCI(pc)->pcflow->in_vals) {
10178 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10180 //fprintf (stderr, "found def in init values\n");
10181 df_findall_in_vals++;
10187 // found a single definition (in pc's flow)
10188 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10189 defmapAddCopyIfNew (chain, res);
10190 df_findall_sameflow++;
10194 #if USE_PRECALCED_INVALS
10196 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10202 #define FORWARD_FLOW_ANALYSIS 1
10203 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10204 /* no definition found in pc's flow preceeding pc */
10205 todo = newStack ();
10206 done = newStack ();
10207 n_defs = 0; firstState = 1;
10208 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10210 while (!stackIsEmpty (todo)) {
10211 state = (state_t *) stackPop (todo);
10212 stackPush (done, state);
10213 curr = state->flow;
10214 res = state->lastdef;
10215 //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);
10217 /* there are no definitions BEFORE pc in pc's flow (see above) */
10218 if (curr == PCI(pc)->pcflow) {
10220 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10221 res = pic16_pBlockAddInval (pc->pb, sym);
10222 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10225 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10226 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10230 /* save last definition of sym in this flow as initial def in successors */
10231 res = defmapFindDef (curr->defmap, sym, NULL);
10232 if (!res) res = state->lastdef;
10234 /* add successors to working list */
10235 state = newState (NULL, NULL);
10236 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10238 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10239 state->flow = succ->pcflow;
10240 state->lastdef = res;
10241 if (stateIsNew (state, todo, done)) {
10242 stackPush (todo, state);
10243 state = newState (NULL, NULL);
10245 succ = (pCodeFlowLink *) setNextItem (curr->to);
10247 deleteState (state);
10250 #else // !FORWARD_FLOW_ANALYSIS
10252 /* no definition found in pc's flow preceeding pc */
10253 todo = newStack ();
10254 done = newStack ();
10255 n_defs = 0; firstState = 1;
10256 stackPush (todo, newState (PCI(pc)->pcflow, res));
10258 while (!stackIsEmpty (todo)) {
10259 state = (state_t *) stackPop (todo);
10260 curr = state->flow;
10264 /* only check predecessor flows */
10266 /* get (last) definition of sym in this flow */
10267 res = defmapFindDef (curr->defmap, sym, NULL);
10271 /* definition found */
10272 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10273 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10275 /* no definition found -- check predecessor flows */
10276 state = newState (NULL, NULL);
10277 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10279 /* if no flow predecessor available -- sym might be uninitialized */
10281 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10282 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10283 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10284 deleteDefmap (res); res = NULL;
10288 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10289 state->flow = succ->pcflow;
10290 state->lastdef = res;
10291 if (stateIsNew (state, todo, done)) {
10292 stackPush (todo, state);
10293 state = newState (NULL, NULL);
10295 succ = (pCodeFlowLink *) setNextItem (curr->from);
10297 deleteState (state);
10303 /* clean up done stack */
10304 while (!stackIsEmpty(done)) {
10305 deleteState ((state_t *) stackPop (done));
10307 deleteStack (done);
10309 /* return number of items in result set */
10311 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10312 } else if (n_defs == 1) {
10314 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10315 } else if (n_defs > 0) {
10316 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10320 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10325 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10326 df_findall_otherflow++;
10330 /* ======================================================================== */
10331 /* === VALUE NUMBER HANDLING ============================================== */
10332 /* ======================================================================== */
10334 static valnum_t nextValnum = 0x1000;
10335 static hTab *map_symToValnum = NULL;
10337 /** Return a new value number. */
10338 static inline valnum_t newValnum () {
10339 return (nextValnum += 4);
10342 static valnum_t valnumFromStr (const char *str) {
10347 sym = symFromStr (str);
10349 if (!map_symToValnum) {
10350 map_symToValnum = newHashTable (128);
10353 /* literal already known? */
10354 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10356 /* return existing valnum */
10357 if (res) return (valnum_t) PTR_TO_INT(res);
10359 /* create new valnum */
10361 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10362 //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10366 /* Create a valnum for a literal. */
10367 static valnum_t valnumFromLit (unsigned int lit) {
10368 return ((valnum_t) 0x100 + (lit & 0x0FF));
10371 /* Return the (positive) literal value represented by val
10372 * or -1 iff val is no known literal's valnum. */
10373 static int litFromValnum (valnum_t val) {
10374 if (val >= 0x100 && val < 0x200) {
10375 /* valnum is a (known) literal */
10376 return val & 0x00FF;
10378 /* valnum is not a known literal */
10384 /* Sanity check - all flows in a block must be reachable from initial flow. */
10385 static int verifyAllFlowsReachable (pBlock *pb) {
10391 pCodeFlowLink *succ;
10394 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10397 flowInBlock = NULL;
10399 /* mark initial flow as reached (and "not needs to be reached") */
10400 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10402 addSetHead (&reached, pc);
10403 addSetHead (&checked, pc);
10405 /* mark all further flows in block as "need to be reached" */
10408 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10409 pc = pic16_findNextInstruction (pc->next);
10412 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10413 /* mark as reached and "not need to be reached" */
10414 deleteSetItem (&reached, pcfl);
10415 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10417 /* flow is no longer considered unreachable */
10418 deleteSetItem (&flowInBlock, pcfl);
10420 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10421 if (!isinSet (checked, succ->pcflow)) {
10422 /* flow has never been reached before */
10423 addSetHead (&reached, succ->pcflow);
10424 addSetHead (&checked, succ->pcflow);
10429 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10431 /* by now every flow should have been reached
10432 * --> flowInBlock should be empty */
10433 res = (flowInBlock == NULL);
10437 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10438 while (flowInBlock) {
10439 pcfl = indexSet (flowInBlock, 0);
10440 fprintf (stderr, "not reached: flow %p\n", pcfl);
10441 deleteSetItem (&flowInBlock, pcfl);
10447 deleteSet (&reached);
10448 deleteSet (&flowInBlock);
10449 deleteSet (&checked);
10451 /* if we reached every flow, succ is NULL by now... */
10452 //assert (res); // will fire on unreachable code...
10457 /* Checks a flow for accesses to sym AFTER pc.
10459 * Returns -1 if the symbol is read in this flow (before redefinition),
10460 * returns 0 if the symbol is redefined in this flow or
10461 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10463 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10464 defmap_t *map, *mappc;
10466 /* find pc or start of definitions */
10467 map = pcfl->defmap;
10468 while (map && (map->pc != pc) && map->next) map = map->next;
10469 /* if we found pc -- ignore it */
10470 while (map && map->pc == pc) map = map->prev;
10472 /* scan list backwards (first definition first) */
10473 while (map && mask) {
10474 // if (map->sym == sym) {
10475 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10477 /* scan list for reads at this pc first */
10478 while (map && map->pc == mappc->pc) {
10479 /* is the symbol (partially) read? */
10480 if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10481 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10488 while (map && map->pc == mappc->pc) {
10489 /* honor (partial) redefinitions of sym */
10490 if ((map->sym == sym) && (map->acc.access.isWrite)) {
10491 mask &= ~map->acc.access.mask;
10492 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10497 /* map already points to the first defmap for the next pCode */
10498 //map = mappc->prev;
10501 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10502 * is still alive; return the appropriate mask of alive bits */
10506 /* Check whether a symbol is alive (AFTER pc). */
10507 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10510 dynstack_t *todo, *done;
10513 pCodeFlowLink *succ;
10517 assert (isPCI(pc));
10518 pcfl = PCI(pc)->pcflow;
10519 map = pcfl->defmap;
10521 todo = newStack ();
10522 done = newStack ();
10524 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10525 stackPush (todo, state);
10528 while (!stackIsEmpty (todo)) {
10529 state = (state_t *) stackPop (todo);
10530 pcfl = state->flow;
10531 mask = PTR_TO_INT(state->lastdef);
10532 if (visit) stackPush (done, state); else deleteState(state);
10533 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10534 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10535 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10538 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10539 if (mask == 0) continue;
10541 /* symbol is (partially) read before redefinition in flow */
10542 if (mask == -1) break;
10544 /* symbol is neither read nor completely redefined -- check successor flows */
10545 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10546 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10547 if (stateIsNew (state, todo, done)) {
10548 stackPush (todo, state);
10550 deleteState (state);
10555 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10556 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10558 /* symbol is read in at least one flow -- is alive */
10559 if (mask == -1) return 1;
10561 /* symbol is read in no flow */
10565 /* Returns whether access to the given symbol has side effects. */
10566 static int pic16_symIsSpecial (symbol_t sym) {
10567 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10587 /* no special effects known */
10594 /* Check whether a register should be considered local (to the current function) or not. */
10595 static int pic16_regIsLocal (regs *r) {
10598 if (r->type == REG_TMP) return 1;
10600 sym = symFromStr (r->name);
10603 case SPO_FSR0L: // used in ptrget/ptrput
10604 case SPO_FSR0H: // ... as well
10605 case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10606 case SPO_FSR1H: // ... as well
10607 case SPO_FSR2L: // used as frame pointer
10608 case SPO_FSR2H: // ... as well
10609 case SPO_PRODL: // used to return values from functions
10610 case SPO_PRODH: // ... as well
10611 /* these registers (and some more...) are considered local */
10615 /* for unknown regs: check is marked local, leave if not */
10619 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10625 /* if in doubt, assume non-local... */
10629 /* Check all symbols touched by pc whether their newly assigned values are read.
10630 * Returns 0 if no symbol is used later on, 1 otherwise. */
10631 static int pic16_pCodeIsAlive (pCode *pc) {
10632 pCodeInstruction *pci;
10633 defmap_t *map, *lastpc;
10636 /* we can only handle PCIs */
10637 if (!isPCI(pc)) return 1;
10639 //pc->print (stderr, pc);
10642 assert (pci && pci->pcflow && pci->pcflow->defmap);
10644 /* NEVER remove instructions with implicit side effects */
10647 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10648 case POC_TBLRD_POSTDEC:
10649 case POC_TBLRD_PREINC:
10650 case POC_TBLWT: /* modify program memory */
10651 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10652 case POC_TBLWT_POSTDEC:
10653 case POC_TBLWT_PREINC:
10654 case POC_CLRWDT: /* clear watchdog timer */
10655 case POC_PUSH: /* should be safe to remove though... */
10656 case POC_POP: /* should be safe to remove though... */
10661 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10665 /* no special instruction */
10669 /* prevent us from removing assignments to non-local variables */
10671 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10672 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10674 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10675 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10676 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10677 //pc->print (stderr, pc);
10680 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10681 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10686 /* OVERKILL: prevent us from removing reads from non-local variables
10687 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10688 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10690 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10691 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10693 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10694 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10695 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10696 //pc->print (stderr, pc);
10699 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10700 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10705 /* now check that the defined symbols are not used */
10706 map = pci->pcflow->defmap;
10708 /* find items for pc */
10709 while (map && map->pc != pc) map = map->next;
10711 /* no entries found? something is fishy with DF analysis... -- play safe */
10713 if (pic16_pcode_verbose) {
10714 fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10719 /* remember first item assigned to pc for later use */
10722 /* check all symbols being modified by pc */
10723 while (map && map->pc == pc) {
10724 if (map->sym == 0) { map = map->next; continue; }
10726 /* keep pc if it references special symbols (like POSTDEC0) */
10730 pic16_pCode2str (buf, 256, pc);
10731 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10734 if (pic16_symIsSpecial (map->sym)) {
10735 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10738 if (map->acc.access.isWrite) {
10739 if (pic16_isAlive (map->sym, pc)) {
10740 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10747 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10751 pic16_pCode2str (buf, 256, pc);
10752 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10758 /* Adds implied operands to the list.
10759 * sym - operand being accessed in the pCode
10760 * list - list to append the operand
10761 * isRead - set to 1 iff sym is read in pCode
10762 * listRead - set to 1 iff all operands being read are to be listed
10764 * Returns 0 for "normal" operands, 1 for special operands.
10766 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10767 /* check whether accessing REG accesses other REGs as well */
10771 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10772 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10773 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10777 /* reads FSR0x and WREG */
10778 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10779 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10780 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10781 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10787 /* reads/modifies FSR0x */
10788 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10789 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10790 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10795 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10796 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10797 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10801 /* reads FSR1x and WREG */
10802 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10803 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10804 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10805 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10811 /* reads/modifies FSR1x */
10812 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10813 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10814 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10819 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10820 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10821 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10825 /* reads FSR2x and WREG */
10826 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10827 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10828 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10829 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10835 /* reads/modifies FSR2x */
10836 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10837 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10838 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10842 /* modifies PCLATH and PCLATU */
10843 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10845 /* reading PCL updates PCLATx */
10846 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10847 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10850 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10851 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10852 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10857 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10858 /* nothing special */
10863 /* has been a special operand */
10867 static symbol_t pic16_fsrsym_idx[][2] = {
10868 {SPO_FSR0L, SPO_FSR0H},
10869 {SPO_FSR1L, SPO_FSR1H},
10870 {SPO_FSR2L, SPO_FSR2H}
10873 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10874 static void mergeDefmapSymbols (defmap_t *list) {
10875 defmap_t *ref, *curr, *temp;
10877 /* now make sure that each symbol occurs at most once per pc */
10879 while (ref && (ref->pc == list->pc)) {
10881 while (curr && (curr->pc == list->pc)) {
10882 if (curr->sym == ref->sym) {
10883 //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10884 /* found a symbol occuring twice... merge the two */
10885 if (curr->acc.access.isRead) {
10886 //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10887 ref->acc.access.isRead = 1;
10888 ref->acc.access.in_mask |= curr->acc.access.in_mask;
10890 if (curr->acc.access.isWrite) {
10891 //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10892 ref->acc.access.isWrite = 1;
10893 ref->acc.access.mask |= curr->acc.access.mask;
10897 deleteDefmap (temp);
10898 continue; // do not skip curr!
10906 /** Prepend list with the reads and definitions performed by pc. */
10907 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10908 pCodeInstruction *pci;
10909 int cond, inCond, outCond;
10910 int mask = 0xff, smask;
10911 int isSpecial, isSpecial2;
10912 symbol_t sym, sym2;
10916 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10917 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10918 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10919 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10922 assert (isPCI(pc));
10925 /* handle bit instructions */
10926 if (pci->isBitInst) {
10927 assert (pci->pcop->type == PO_GPR_BIT);
10928 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10931 /* handle (additional) implicit arguments */
10937 lit = PCOL(pci->pcop)->lit;
10938 assert (lit >= 0 && lit < 3);
10939 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10940 val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10941 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10942 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10943 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...
10947 case POC_MOVLB: // BSR
10948 case POC_BANKSEL: // BSR
10949 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10952 case POC_MULWF: // PRODx
10953 case POC_MULLW: // PRODx
10954 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10955 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10958 case POC_POP: // TOS, STKPTR
10959 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10960 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10961 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10962 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10965 case POC_PUSH: // STKPTR
10966 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10967 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10968 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10969 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10972 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10973 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10974 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10975 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10976 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10977 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10979 /* needs correctly set-up stack pointer */
10980 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10981 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10984 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10985 /* pseudo read on (possible) return values */
10986 // WREG is handled below via outCond
10987 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10988 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10989 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10991 /* caller's stack pointers must be restored */
10992 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10993 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10994 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10995 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10998 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10999 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
11000 /* pseudo read on (possible) return values */
11001 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
11002 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
11003 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
11004 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
11006 /* caller's stack pointers must be restored */
11007 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11008 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11009 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
11010 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
11014 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11015 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11016 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11017 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11020 case POC_TBLRD_POSTINC:
11021 case POC_TBLRD_POSTDEC:
11022 case POC_TBLRD_PREINC:
11023 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11024 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11025 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11026 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11030 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11031 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11032 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11033 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11036 case POC_TBLWT_POSTINC:
11037 case POC_TBLWT_POSTDEC:
11038 case POC_TBLWT_PREINC:
11039 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11040 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11041 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11042 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11046 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11050 /* handle explicit arguments */
11051 inCond = pci->inCond;
11052 outCond = pci->outCond;
11053 cond = inCond | outCond;
11054 if (cond & PCC_W) {
11055 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11058 /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11059 if (inCond & PCC_STATUS) {
11061 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11062 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11063 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11064 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11065 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11067 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11068 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11071 if (outCond & PCC_STATUS) {
11073 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11074 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11075 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11076 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11077 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11079 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11080 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11083 isSpecial = isSpecial2 = 0;
11085 if (cond & PCC_REGISTER) {
11086 name = pic16_get_op (pci->pcop, NULL, 0);
11087 sym = symFromStr (name);
11088 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11089 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11092 if (cond & PCC_REGISTER2) {
11093 name = pic16_get_op2 (pci->pcop, NULL, 0);
11094 sym2 = symFromStr (name);
11095 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11096 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11100 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11101 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11103 mergeDefmapSymbols (list);
11109 static void printDefmap (defmap_t *map) {
11113 fprintf (stderr, "defmap @ %p:\n", curr);
11115 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11116 curr->acc.access.isRead ? "R" : " ",
11117 curr->acc.access.isWrite ? "W": " ",
11118 curr->in_val, curr->val,
11119 curr->acc.access.in_mask, curr->acc.access.mask,
11120 strFromSym(curr->sym), curr->sym,
11124 fprintf (stderr, "<EOL>\n");
11128 /* Add "additional" definitions to uniq.
11129 * 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.
11130 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11132 * If symbols defined in additional are not present in uniq, a definition is created.
11133 * Otherwise the present definition is altered to reflect the newer assignments.
11135 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11136 * before `------- noted in additional --------' after
11138 * I assume that each symbol occurs AT MOST ONCE in uniq.
11141 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11146 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11147 /* find tail of additional list (holds the first assignment) */
11149 while (curr && curr->next) curr = curr->next;
11153 /* find next assignment in additionals */
11154 while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11158 /* find item in uniq */
11160 //printDefmap (*uniq);
11161 while (old && (old->sym != curr->sym)) old = old->next;
11164 /* definition found -- replace */
11165 if (old->val != curr->val) {
11166 old->val = curr->val;
11170 /* new definition */
11171 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11178 /* return 0 iff uniq remained unchanged */
11182 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11183 * lists of its predecessor flows.
11184 * Initially *combined should be NULL, alt_in will be copied to combined.
11185 * If *combined != NULL, combined will be altered:
11186 * - for symbols defined in *combined but not in alt_in,
11187 * *combined is altered to 0 (value unknown, either *combined or INIT).
11188 * - for symbols defined in alt_in but not in *combined,
11189 * a 0 definition is created (value unknown, either INIT or alt).
11190 * - for symbols defined in both, *combined is:
11191 * > left unchanged if *combined->val == alt_in->val or
11192 * > modified to 0 otherwise (value unknown, either alt or *combined).
11194 * I assume that each symbol occurs AT MOST ONCE in each list!
11196 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11202 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11204 if (!(*combined)) {
11205 return defmapUpdateUniqueSym (combined, alt_in);
11208 /* merge the two */
11211 /* find symbols definition in *combined */
11213 while (old && (old->sym != curr->sym)) old = old->next;
11216 /* definition found */
11217 if (old->val && (old->val != curr->val)) {
11218 old->val = 0; /* value unknown */
11222 /* no definition found -- can be either INIT or alt_in's value */
11223 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11224 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11225 if (val != curr->val) change++;
11231 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11234 if (old->val != 0) {
11235 /* find definition in alt_in */
11237 while (curr && curr->sym != old->sym) curr = curr->next;
11239 /* symbol defined in *combined only -- can be either INIT or *combined */
11240 val = pic16_pBlockAddInval (pb, old->sym)->val;
11241 if (old->val != val) {
11254 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11255 defmap_t *curr1, *curr2;
11258 /* identical maps are equal */
11259 if (map1 == map2) return 0;
11261 if (!map1) return -1;
11262 if (!map2) return 1;
11264 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11269 while (curr1 && curr2) {
11270 curr1 = curr1->next;
11271 curr2 = curr2->next;
11274 /* one of them longer? */
11275 if (curr1) return 1;
11276 if (curr2) return -1;
11278 /* both lists are of equal length -- compare (in O(n^2)) */
11283 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11284 if (!curr2) return 1; // symbol not found in curr2
11285 if (curr2->val != curr1->val) return 1; // values differ
11287 /* compare next symbol */
11288 curr1 = curr1->next;
11291 /* no difference found */
11296 /* Prepare a list of all reaching definitions per flow.
11297 * This is done using a forward dataflow analysis.
11299 static void createReachingDefinitions (pBlock *pb) {
11300 defmap_t *out_vals, *in_vals;
11303 pCodeFlowLink *link;
11307 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11308 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11310 deleteDefmapChain (&PCFL(pc)->in_vals);
11311 deleteDefmapChain (&PCFL(pc)->out_vals);
11312 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11316 pc = pic16_findNextInstruction (pb->pcHead);
11317 todo = NULL; blacklist = NULL;
11318 addSetHead (&todo, PCI(pc)->pcflow);
11320 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11321 while (elementsInSet (todo)) {
11322 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11323 pcfl = PCFL(indexSet (todo, 0));
11324 deleteSetItem (&todo, pcfl);
11325 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11329 if (isinSet (blacklist, pcfl)) {
11330 fprintf (stderr, "ignoring blacklisted flow\n");
11334 /* create in_vals from predecessors out_vals */
11335 link = setFirstItem (pcfl->from);
11337 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11338 link = setNextItem (pcfl->from);
11341 //printDefmap (in_vals);
11342 //printDefmap (pcfl->in_vals);
11344 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11345 //fprintf (stderr, "in_vals changed\n");
11346 /* in_vals changed -- update out_vals */
11347 deleteDefmapChain (&pcfl->in_vals);
11348 pcfl->in_vals = in_vals;
11350 /* create out_val from in_val and defmap */
11352 defmapUpdateUniqueSym (&out_vals, in_vals);
11353 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11355 /* is out_vals different from pcfl->out_vals */
11356 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11357 //fprintf (stderr, "out_vals changed\n");
11358 deleteDefmapChain (&pcfl->out_vals);
11359 pcfl->out_vals = out_vals;
11361 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11362 addSet (&blacklist, pcfl);
11365 /* reschedule all successors */
11366 link = setFirstItem (pcfl->to);
11368 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11369 addSetIfnotP (&todo, link->pcflow);
11370 link = setNextItem (pcfl->to);
11373 deleteDefmapChain (&out_vals);
11376 deleteDefmapChain (&in_vals);
11382 static void showAllDefs (symbol_t sym, pCode *pc) {
11386 assert (isPCI(pc));
11387 count = defmapFindAll (sym, pc, &map);
11389 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11392 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11395 pic16_pCode2str (buf, 256, map->pc);
11396 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11400 deleteDefmapChain (&map);
11404 /* safepCodeUnlink and remove pc from defmap. */
11405 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11406 defmap_t *map, *next, **head;
11410 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11411 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11412 res = pic16_safepCodeUnlink (pc, comment);
11415 /* remove pc from defmap */
11418 if (map->pc == pc) {
11419 if (!map->prev && head) *head = map->next;
11420 deleteDefmap (map);
11429 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11431 /* This breaks the defmap chain's references to pCodes... fix it! */
11432 map = PCI(pc)->pcflow->defmap;
11434 while (map && map->pc != pc) map = map->next;
11436 while (map && map->pc == pc) {
11442 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11443 * write accesses (isRead == 0). */
11444 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11445 defmap_t *map, *map_start;
11447 if (!isPCI(pc)) return;
11448 if (sym == newsym) return;
11450 map = PCI(pc)->pcflow->defmap;
11452 while (map && map->pc != pc) map = map->next;
11454 while (map && map->pc == pc) {
11455 if (map->sym == sym) {
11456 assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11457 if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11458 /* only one kind of access handled... this is easy */
11461 /* must copy defmap entry before replacing symbol... */
11462 copy = copyDefmap (map);
11464 map->acc.access.isRead = 0;
11465 copy->acc.access.isWrite = 0;
11467 map->acc.access.isWrite = 0;
11468 copy->acc.access.isRead = 0;
11470 copy->sym = newsym;
11471 /* insert copy into defmap chain */
11472 defmapInsertAfter (map, copy);
11478 /* as this might introduce multiple defmap entries for newsym... */
11479 mergeDefmapSymbols (map_start);
11482 /* Assign "better" valnums to results. */
11483 static void assignValnums (pCode *pc) {
11484 pCodeInstruction *pci;
11486 symbol_t sym1, sym2;
11487 int cond, isSpecial1, isSpecial2, count, mask, lit;
11488 defmap_t *list, *val, *oldval, *dummy;
11489 regs *reg1 = NULL, *reg2 = NULL;
11492 /* only works for pCodeInstructions... */
11493 if (!isPCI(pc)) return;
11496 cond = pci->inCond | pci->outCond;
11497 list = pci->pcflow->defmap;
11498 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11500 if (cond & PCC_REGISTER) {
11501 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11502 reg1 = pic16_getRegFromInstruction (pc);
11503 isSpecial1 = pic16_symIsSpecial (sym1);
11505 if (cond & PCC_REGISTER2) {
11506 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11507 reg2 = pic16_getRegFromInstruction (pc);
11508 isSpecial2 = pic16_symIsSpecial (sym2);
11511 /* determine input values */
11513 while (val && val->pc != pc) val = val->next;
11514 //list = val; /* might save some time later... */
11515 while (val && val->pc == pc) {
11517 if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11518 /* get valnum for sym */
11519 count = defmapFindAll (val->sym, pc, &oldval);
11520 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11522 if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11523 val->in_val = oldval->val;
11527 } else if (count == 0) {
11528 /* no definition found */
11531 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11533 dummy = oldval->next;
11534 mask = oldval->acc.access.mask;
11535 val->in_val = oldval->val;
11536 while (dummy && (dummy->val == val->in_val)) {
11537 mask &= dummy->acc.access.mask;
11538 dummy = dummy->next;
11541 /* found other values or to restictive mask */
11542 if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11546 if (count > 0) deleteDefmapChain (&oldval);
11551 /* handle valnum assignment */
11553 case POC_CLRF: /* modifies STATUS (Z) */
11554 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11555 oldval = defmapCurr (list, sym1, pc);
11556 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11557 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11558 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11560 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11564 case POC_SETF: /* SETF does not touch STATUS */
11565 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11566 oldval = defmapCurr (list, sym1, pc);
11567 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11568 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11569 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11571 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11575 case POC_MOVLW: /* does not touch STATUS */
11576 oldval = defmapCurr (list, SPO_WREG, pc);
11577 if (pci->pcop->type == PO_LITERAL) {
11578 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11579 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11581 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11582 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11584 if (oldval && oldval->in_val == litnum) {
11585 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11586 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11588 defmapUpdate (list, SPO_WREG, pc, litnum);
11591 case POC_ANDLW: /* modifies STATUS (Z,N) */
11592 case POC_IORLW: /* modifies STATUS (Z,N) */
11593 case POC_XORLW: /* modifies STATUS (Z,N) */
11594 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11595 if (pci->pcop->type == PO_LITERAL) {
11597 lit = (unsigned char) PCOL(pci->pcop)->lit;
11598 val = defmapCurr (list, SPO_WREG, pc);
11599 if (val) vallit = litFromValnum (val->in_val);
11600 if (vallit != -1) {
11601 /* xxxLW <literal>, WREG contains a known literal */
11602 //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11603 if (pci->op == POC_ANDLW) {
11605 } else if (pci->op == POC_IORLW) {
11607 } else if (pci->op == POC_XORLW) {
11610 assert (0 && "invalid operation");
11612 if (vallit == lit) {
11613 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11614 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11616 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11623 /* check if old value matches new value */
11626 assert (pci->pcop->type == PO_LITERAL);
11628 lit = PCOL(pci->pcop)->lit;
11630 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11632 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11633 //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11635 /* cannot remove this LFSR */
11639 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11640 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11641 //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11647 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11652 case POC_MOVWF: /* does not touch flags */
11653 /* find value of WREG */
11654 val = defmapCurr (list, SPO_WREG, pc);
11655 oldval = defmapCurr (list, sym1, pc);
11656 if (val) lit = litFromValnum (val->in_val);
11658 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11660 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11661 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11662 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11664 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11666 assert (lit == 0x0ff);
11667 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11669 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11670 pic16_pCodeReplace (pc, newpc);
11671 defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11672 pic16_fixDefmap (pc, newpc);
11675 /* This breaks the defmap chain's references to pCodes... fix it! */
11676 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11677 if (!val->acc.access.isWrite) {
11678 deleteDefmap (val); // delete reference to WREG as in value
11681 val->acc.access.isRead = 0; // delete reference to WREG as in value
11683 oldval = PCI(pc)->pcflow->defmap;
11685 if (oldval->pc == pc) oldval->pc = newpc;
11686 oldval = oldval->next;
11688 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11689 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11690 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11692 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11695 case POC_MOVFW: /* modifies STATUS (Z,N) */
11696 /* find value of REG */
11697 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11698 val = defmapCurr (list, sym1, pc);
11699 oldval = defmapCurr (list, SPO_WREG, pc);
11700 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11701 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11702 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11704 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11708 case POC_MOVFF: /* does not touch STATUS */
11709 /* find value of REG */
11710 val = defmapCurr (list, sym1, pc);
11711 oldval = defmapCurr (list, sym2, pc);
11712 if (val) lit = litFromValnum (val->in_val);
11715 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11716 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11718 newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11719 } else if (lit == 0x00ff) {
11720 newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11725 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11726 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11727 pic16_pCodeReplace (pc, newpc);
11728 defmapReplaceSymRef (pc, sym1, 0, 1);
11729 pic16_fixDefmap (pc, newpc);
11731 break; // do not process instruction as MOVFF...
11733 } else if (!isSpecial1 && !isSpecial2
11734 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11735 && val && oldval && (val->in_val != 0)) {
11736 if (val->in_val == oldval->in_val) {
11737 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11738 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11740 if (!pic16_isAlive (sym1, pc)) {
11741 defmap_t *copy = NULL;
11742 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11743 * This should help eliminate
11745 * <do something not changing A or using B>
11747 * <B is not alive anymore>
11749 * <do something not changing A or using B>
11753 /* scan defmap for symbols storing sym1's value */
11754 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11755 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11756 /* unique reaching definition for sym found */
11757 if (copy->val && copy->val == val->in_val) {
11758 //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);
11759 if (copy->sym == SPO_WREG) {
11760 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11762 pCodeOp *pcop = NULL;
11763 /* the code below fails if we try to replace
11764 * MOVFF PRODL, r0x03
11765 * MOVFF r0x03, PCLATU
11767 * MOVFF PRODL, PCLATU
11768 * as copy(PRODL) contains has pc==NULL, by name fails...
11770 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11772 if (copy->pc && PCI(copy->pc)->pcop)
11773 pcop = PCI(copy->pc)->pcop;
11775 /* This code is broken--see above. */
11778 const char *symname = strFromSym(copy->sym);
11781 pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11782 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11783 //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11787 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11789 pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11791 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11792 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11793 pic16_pCodeReplace (pc, newpc);
11794 assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11795 defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11796 pic16_fixDefmap (pc, newpc);
11800 deleteDefmapChain (©);
11803 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11808 /* cannot optimize */
11813 static void pic16_destructDF (pBlock *pb) {
11816 /* remove old defmaps */
11817 pc = pic16_findNextInstruction (pb->pcHead);
11819 next = pic16_findNextInstruction (pc->next);
11821 assert (isPCI(pc) || isPCAD(pc));
11822 assert (PCI(pc)->pcflow);
11823 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11824 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11825 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11830 if (defmap_free || defmap_free_count) {
11831 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11832 freeDefmap (&defmap_free);
11833 defmap_free_count = 0;
11837 /* Checks whether a pBlock contains ASMDIRs. */
11838 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11841 pc = pic16_findNextInstruction (pb->pcHead);
11843 if (isPCAD(pc)) return 1;
11845 pc = pic16_findNextInstruction (pc->next);
11848 /* no PCADs found */
11853 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11854 static int pic16_removeUnusedRegistersDF () {
11857 regs *reg1, *reg2, *reg3;
11858 set *seenRegs = NULL;
11860 int islocal, change = 0;
11863 if (!the_pFile || !the_pFile->pbHead) return 0;
11865 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11866 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11868 /* find set of using pCodes per register */
11869 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11870 pc = pic16_findNextInstruction(pc->next)) {
11872 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11873 reg1 = reg2 = NULL;
11874 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11875 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11878 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11879 addSetIfnotP (&seenRegs, reg1);
11880 addSetIfnotP (®1->reglives.usedpCodes, pc);
11883 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11884 addSetIfnotP (&seenRegs, reg2);
11885 addSetIfnotP (®2->reglives.usedpCodes, pc);
11889 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11890 /* may not use pic16_regIsLocal() here -- in interrupt routines
11891 * WREG, PRODx, FSR0x must be saved */
11892 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11893 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11895 for (i=0; i < 2; i++) {
11896 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11897 if (!pc2) pc2 = pc;
11898 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11899 reg2 = pic16_getRegFromInstruction (pc);
11900 reg3 = pic16_getRegFromInstruction2 (pc);
11902 || (reg2->rIdx != pic16_stack_preinc->rIdx
11903 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11905 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11906 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11907 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11908 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11912 deleteSet (®1->reglives.usedpCodes);
11915 deleteSet (&seenRegs);
11922 /* Set up pCodeFlow's defmap_ts.
11923 * Needs correctly set up to/from fields. */
11924 static void pic16_createDF (pBlock *pb) {
11928 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11930 pic16_destructDF (pb);
11932 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11933 if (pic16_pBlockHasAsmdirs (pb)) {
11934 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11938 /* integrity check -- we need to reach all flows to guarantee
11939 * correct data flow analysis (reaching definitions, aliveness) */
11941 if (!verifyAllFlowsReachable (pb)) {
11942 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11947 /* establish new defmaps */
11948 pc = pic16_findNextInstruction (pb->pcHead);
11950 next = pic16_findNextInstruction (pc->next);
11952 assert (PCI(pc)->pcflow);
11953 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11958 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11959 createReachingDefinitions (pb);
11962 /* assign better valnums */
11963 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11964 pc = pic16_findNextInstruction (pb->pcHead);
11966 next = pic16_findNextInstruction (pc->next);
11968 assert (PCI(pc)->pcflow);
11969 assignValnums (pc);
11976 /* remove dead pCodes */
11977 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11980 pc = pic16_findNextInstruction (pb->pcHead);
11982 next = pic16_findNextInstruction (pc->next);
11984 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11985 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11994 /* ======================================================================== */
11995 /* === VCG DUMPER ROUTINES ================================================ */
11996 /* ======================================================================== */
11997 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11998 hTab *dumpedNodes = NULL;
12000 /** Dump VCG header into of. */
12001 static void pic16_vcg_init (FILE *of) {
12002 /* graph defaults */
12003 fprintf (of, "graph:{\n");
12004 fprintf (of, "title:\"graph1\"\n");
12005 fprintf (of, "label:\"graph1\"\n");
12006 fprintf (of, "color:white\n");
12007 fprintf (of, "textcolor:black\n");
12008 fprintf (of, "bordercolor:black\n");
12009 fprintf (of, "borderwidth:1\n");
12010 fprintf (of, "textmode:center\n");
12012 fprintf (of, "layoutalgorithm:dfs\n");
12013 fprintf (of, "late_edge_labels:yes\n");
12014 fprintf (of, "display_edge_labels:yes\n");
12015 fprintf (of, "dirty_edge_labels:yes\n");
12016 fprintf (of, "finetuning:yes\n");
12017 fprintf (of, "ignoresingles:no\n");
12018 fprintf (of, "straight_phase:yes\n");
12019 fprintf (of, "priority_phase:yes\n");
12020 fprintf (of, "manhattan_edges:yes\n");
12021 fprintf (of, "smanhattan_edges:no\n");
12022 fprintf (of, "nearedges:no\n");
12023 fprintf (of, "node_alignment:center\n"); // bottom|top|center
12024 fprintf (of, "port_sharing:no\n");
12025 fprintf (of, "arrowmode:free\n"); // fixed|free
12026 fprintf (of, "crossingphase2:yes\n");
12027 fprintf (of, "crossingoptimization:yes\n");
12028 fprintf (of, "edges:yes\n");
12029 fprintf (of, "nodes:yes\n");
12030 fprintf (of, "splines:no\n");
12032 /* node defaults */
12033 fprintf (of, "node.color:lightyellow\n");
12034 fprintf (of, "node.textcolor:black\n");
12035 fprintf (of, "node.textmode:center\n");
12036 fprintf (of, "node.shape:box\n");
12037 fprintf (of, "node.bordercolor:black\n");
12038 fprintf (of, "node.borderwidth:1\n");
12040 /* edge defaults */
12041 fprintf (of, "edge.textcolor:black\n");
12042 fprintf (of, "edge.color:black\n");
12043 fprintf (of, "edge.thickness:1\n");
12044 fprintf (of, "edge.arrowcolor:black\n");
12045 fprintf (of, "edge.backarrowcolor:black\n");
12046 fprintf (of, "edge.arrowsize:15\n");
12047 fprintf (of, "edge.backarrowsize:15\n");
12048 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12049 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12050 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12052 fprintf (of, "\n");
12054 /* prepare data structures */
12056 hTabDeleteAll (dumpedNodes);
12057 dumpedNodes = NULL;
12059 dumpedNodes = newHashTable (128);
12062 /** Dump VCG footer into of. */
12063 static void pic16_vcg_close (FILE *of) {
12064 fprintf (of, "}\n");
12067 #define BUF_SIZE 128
12068 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12071 static int ptrcmp (const void *p1, const void *p2) {
12076 /** Dump a pCode node as VCG to of. */
12077 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12078 char buf[BUF_SIZE];
12080 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12084 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12085 //fprintf (stderr, "dumping %p\n", pc);
12087 /* only dump pCodeInstructions and Flow nodes */
12088 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12091 fprintf (of, "node:{");
12092 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12093 fprintf (of, "label:\"%s\n", pcTitle(pc));
12095 fprintf (of, "<PCFLOW>");
12096 } else if (isPCI(pc) || isPCAD(pc)) {
12097 pc->print (of, pc);
12099 fprintf (of, "<!PCI>");
12101 fprintf (of, "\" ");
12102 fprintf (of, "}\n");
12104 if (1 && isPCFL(pc)) {
12105 defmap_t *map, *prev;
12107 map = PCFL(pc)->defmap;
12110 if (map->sym != 0) {
12113 /* emit definition node */
12114 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12115 fprintf (of, "label:\"");
12119 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));
12122 } while (map && prev->pc == map->pc);
12125 fprintf (of, "\" ");
12127 fprintf (of, "color:green ");
12128 fprintf (of, "}\n");
12130 /* emit edge to previous definition */
12131 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12133 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12135 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12137 fprintf (of, "color:green ");
12138 fprintf (of, "}\n");
12141 pic16_vcg_dumpnode (map->pc, of);
12142 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12143 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12150 /* emit additional nodes (e.g. operands) */
12153 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12154 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12155 char buf[BUF_SIZE];
12156 pCodeInstruction *pci;
12160 if (1 && isPCFL(pc)) {
12161 /* emit edges to flow successors */
12163 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12164 pcfl = setFirstItem (PCFL(pc)->to);
12166 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12167 pic16_vcg_dumpnode (pc, of);
12168 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12169 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12170 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12171 pcfl = setNextItem (PCFL(pc)->to);
12175 if (!isPCI(pc) && !isPCAD(pc)) return;
12179 /* emit control flow edges (forward only) */
12183 pic16_vcg_dumpnode (curr->pc, of);
12184 fprintf (of, "edge:{");
12185 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12186 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12187 fprintf (of, "color:red ");
12188 fprintf (of, "}\n");
12193 /* dump "flow" edge (link pCode according to pBlock order) */
12196 pcnext = pic16_findNextInstruction (pc->next);
12198 pic16_vcg_dumpnode (pcnext, of);
12199 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12200 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12208 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12209 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12210 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12214 /* emit data flow edges (backward only) */
12215 /* TODO: gather data flow information... */
12218 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12221 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12222 if (pic16_pBlockHasAsmdirs (pb)) {
12223 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12227 for (pc=pb->pcHead; pc; pc = pc->next) {
12228 pic16_vcg_dumpnode (pc, of);
12231 for (pc=pb->pcHead; pc; pc = pc->next) {
12232 pic16_vcg_dumpedges (pc, of);
12236 static void pic16_vcg_dump_default (pBlock *pb) {
12238 char buf[BUF_SIZE];
12241 /* get function name */
12243 while (pc && !isPCF(pc)) pc = pc->next;
12245 SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12247 SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12250 //fprintf (stderr, "now dumping %s\n", buf);
12251 of = fopen (buf, "w");
12252 pic16_vcg_init (of);
12253 pic16_vcg_dump (of, pb);
12254 pic16_vcg_close (of);
12259 /*** END of helpers for pCode dataflow optimizations ***/