1 /*-------------------------------------------------------------------------
3 pcode.c - post code generation
5 Written By - Scott Dattalo scott@dattalo.com
6 Ported to PIC16 By - Martin Dubuc m.dubuc@rogers.com
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 -------------------------------------------------------------------------*/
25 #include "common.h" // Include everything in the SDCC src directory
31 #include "pcodeflow.h"
35 extern char *pic16_aopGet (struct asmop *aop, int offset, bool bit16, bool dname);
37 #if defined(__BORLANDC__) || defined(_MSC_VER)
41 #define DUMP_DF_GRAPHS 0
43 /****************************************************************/
44 /****************************************************************/
46 static peepCommand peepCommands[] = {
48 {NOTBITSKIP, "_NOTBITSKIP_"},
49 {BITSKIP, "_BITSKIP_"},
50 {INVERTBITSKIP, "_INVERTBITSKIP_"},
57 // Eventually this will go into device dependent files:
58 pCodeOpReg pic16_pc_status = {{PO_STATUS, "STATUS"}, -1, NULL,0,NULL};
59 pCodeOpReg pic16_pc_intcon = {{PO_INTCON, "INTCON"}, -1, NULL,0,NULL};
60 pCodeOpReg pic16_pc_pcl = {{PO_PCL, "PCL"}, -1, NULL,0,NULL};
61 pCodeOpReg pic16_pc_pclath = {{PO_PCLATH, "PCLATH"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_pclatu = {{PO_PCLATU, "PCLATU"}, -1, NULL,0,NULL}; // patch 14
63 pCodeOpReg pic16_pc_wreg = {{PO_WREG, "WREG"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_bsr = {{PO_BSR, "BSR"}, -1, NULL,0,NULL};
66 pCodeOpReg pic16_pc_tosl = {{PO_SFR_REGISTER, "TOSL"}, -1, NULL,0,NULL}; // patch 14
67 pCodeOpReg pic16_pc_tosh = {{PO_SFR_REGISTER, "TOSH"}, -1, NULL,0,NULL}; //
68 pCodeOpReg pic16_pc_tosu = {{PO_SFR_REGISTER, "TOSU"}, -1, NULL,0,NULL}; // patch 14
70 pCodeOpReg pic16_pc_tblptrl = {{PO_SFR_REGISTER, "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
71 pCodeOpReg pic16_pc_tblptrh = {{PO_SFR_REGISTER, "TBLPTRH"}, -1, NULL,0,NULL}; //
72 pCodeOpReg pic16_pc_tblptru = {{PO_SFR_REGISTER, "TBLPTRU"}, -1, NULL,0,NULL}; //
73 pCodeOpReg pic16_pc_tablat = {{PO_SFR_REGISTER, "TABLAT"}, -1, NULL,0,NULL}; // patch 15
75 //pCodeOpReg pic16_pc_fsr0 = {{PO_FSR0, "FSR0"}, -1, NULL,0,NULL}; //deprecated !
77 pCodeOpReg pic16_pc_fsr0l = {{PO_FSR0, "FSR0L"}, -1, NULL, 0, NULL};
78 pCodeOpReg pic16_pc_fsr0h = {{PO_FSR0, "FSR0H"}, -1, NULL, 0, NULL};
79 pCodeOpReg pic16_pc_fsr1l = {{PO_FSR0, "FSR1L"}, -1, NULL, 0, NULL};
80 pCodeOpReg pic16_pc_fsr1h = {{PO_FSR0, "FSR1H"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr2l = {{PO_FSR0, "FSR2L"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr2h = {{PO_FSR0, "FSR2H"}, -1, NULL, 0, NULL};
84 pCodeOpReg pic16_pc_indf0 = {{PO_INDF0, "INDF0"}, -1, NULL,0,NULL};
85 pCodeOpReg pic16_pc_postinc0 = {{PO_INDF0, "POSTINC0"}, -1, NULL, 0, NULL};
86 pCodeOpReg pic16_pc_postdec0 = {{PO_INDF0, "POSTDEC0"}, -1, NULL, 0, NULL};
87 pCodeOpReg pic16_pc_preinc0 = {{PO_INDF0, "PREINC0"}, -1, NULL, 0, NULL};
88 pCodeOpReg pic16_pc_plusw0 = {{PO_INDF0, "PLUSW0"}, -1, NULL, 0, NULL};
90 pCodeOpReg pic16_pc_indf1 = {{PO_INDF0, "INDF1"}, -1, NULL,0,NULL};
91 pCodeOpReg pic16_pc_postinc1 = {{PO_INDF0, "POSTINC1"}, -1, NULL, 0, NULL};
92 pCodeOpReg pic16_pc_postdec1 = {{PO_INDF0, "POSTDEC1"}, -1, NULL, 0, NULL};
93 pCodeOpReg pic16_pc_preinc1 = {{PO_INDF0, "PREINC1"}, -1, NULL, 0, NULL};
94 pCodeOpReg pic16_pc_plusw1 = {{PO_INDF0, "PLUSW1"}, -1, NULL, 0, NULL};
96 pCodeOpReg pic16_pc_indf2 = {{PO_INDF0, "INDF2"}, -1, NULL,0,NULL};
97 pCodeOpReg pic16_pc_postinc2 = {{PO_INDF0, "POSTINC2"}, -1, NULL, 0, NULL};
98 pCodeOpReg pic16_pc_postdec2 = {{PO_INDF0, "POSTDEC2"}, -1, NULL, 0, NULL};
99 pCodeOpReg pic16_pc_preinc2 = {{PO_INDF0, "PREINC2"}, -1, NULL, 0, NULL};
100 pCodeOpReg pic16_pc_plusw2 = {{PO_INDF0, "PLUSW2"}, -1, NULL, 0, NULL};
102 pCodeOpReg pic16_pc_prodl = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_prodh = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
105 /* EEPROM registers */
106 pCodeOpReg pic16_pc_eecon1 = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
107 pCodeOpReg pic16_pc_eecon2 = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
108 pCodeOpReg pic16_pc_eedata = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
109 pCodeOpReg pic16_pc_eeadr = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
111 pCodeOpReg pic16_pc_kzero = {{PO_GPR_REGISTER, "KZ"}, -1, NULL,0,NULL};
112 pCodeOpReg pic16_pc_wsave = {{PO_GPR_REGISTER, "WSAVE"}, -1, NULL,0,NULL};
113 pCodeOpReg pic16_pc_ssave = {{PO_GPR_REGISTER, "SSAVE"}, -1, NULL,0,NULL};
115 pCodeOpReg *pic16_stackpnt_lo;
116 pCodeOpReg *pic16_stackpnt_hi;
117 pCodeOpReg *pic16_stack_postinc;
118 pCodeOpReg *pic16_stack_postdec;
119 pCodeOpReg *pic16_stack_preinc;
120 pCodeOpReg *pic16_stack_plusw;
122 pCodeOpReg *pic16_framepnt_lo;
123 pCodeOpReg *pic16_framepnt_hi;
124 pCodeOpReg *pic16_frame_postinc;
125 pCodeOpReg *pic16_frame_postdec;
126 pCodeOpReg *pic16_frame_preinc;
127 pCodeOpReg *pic16_frame_plusw;
129 pCodeOpReg pic16_pc_gpsimio = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
130 pCodeOpReg pic16_pc_gpsimio2 = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
132 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
133 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
136 static int mnemonics_initialized = 0;
139 static hTab *pic16MnemonicsHash = NULL;
140 static hTab *pic16pCodePeepCommandsHash = NULL;
142 static pFile *the_pFile = NULL;
143 static pBlock *pb_dead_pcodes = NULL;
145 /* Hardcoded flags to change the behavior of the PIC port */
146 static int peepOptimizing = 1; /* run the peephole optimizer if nonzero */
147 static int functionInlining = 1; /* inline functions if nonzero */
148 int pic16_debug_verbose = 0; /* Set true to inundate .asm file */
150 int pic16_pcode_verbose = 0;
152 //static int GpCodeSequenceNumber = 1;
153 static int GpcFlowSeq = 1;
155 extern void pic16_RemoveUnusedRegisters(void);
156 extern void pic16_RegsUnMapLiveRanges(void);
157 extern void pic16_BuildFlowTree(pBlock *pb);
158 extern void pic16_pCodeRegOptimizeRegUsage(int level);
159 extern int mnem2key(unsigned char const *mnem);
161 /****************************************************************/
162 /* Forward declarations */
163 /****************************************************************/
165 void pic16_unlinkpCode(pCode *pc);
167 static void genericAnalyze(pCode *pc);
168 static void AnalyzeGOTO(pCode *pc);
169 static void AnalyzeSKIP(pCode *pc);
170 static void AnalyzeRETURN(pCode *pc);
173 static void genericDestruct(pCode *pc);
174 static void genericPrint(FILE *of,pCode *pc);
176 static void pCodePrintLabel(FILE *of, pCode *pc);
177 static void pCodePrintFunction(FILE *of, pCode *pc);
178 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
179 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
180 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
181 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
182 int pic16_pCodePeepMatchRule(pCode *pc);
183 static void pBlockStats(FILE *of, pBlock *pb);
184 static pBlock *newpBlock(void);
185 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
186 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
187 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
188 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
189 void OptimizeLocalRegs(void);
190 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
192 char *dumpPicOptype(PIC_OPTYPE type);
194 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
195 pCodeOp *pic16_popGetLit(int);
196 pCodeOp *pic16_popGetWithString(char *);
197 extern int inWparamList(char *s);
199 /** data flow optimization helpers **/
200 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
201 static void pic16_vcg_dump (FILE *of, pBlock *pb);
202 static void pic16_vcg_dump_default (pBlock *pb);
204 static int pic16_pCodeIsAlive (pCode *pc);
205 static void pic16_df_stats ();
206 static void pic16_createDF (pBlock *pb);
207 static int pic16_removeUnusedRegistersDF ();
208 static void pic16_destructDF (pBlock *pb);
209 static void releaseStack ();
211 /****************************************************************/
212 /* PIC Instructions */
213 /****************************************************************/
215 pCodeInstruction pic16_pciADDWF = {
216 {PC_OPCODE, NULL, NULL, 0, NULL,
230 1,0, // dest, bit instruction
232 0, // literal operand
234 0, // fast call/return mode select bit
235 0, // second memory operand
236 0, // second literal operand
238 (PCC_W | PCC_REGISTER), // inCond
239 (PCC_REGISTER | PCC_STATUS), // outCond
243 pCodeInstruction pic16_pciADDFW = {
244 {PC_OPCODE, NULL, NULL, 0, NULL,
258 0,0, // dest, bit instruction
260 0, // literal operand
262 0, // fast call/return mode select bit
263 0, // second memory operand
264 0, // second literal operand
266 (PCC_W | PCC_REGISTER), // inCond
267 (PCC_W | PCC_STATUS), // outCond
271 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
272 {PC_OPCODE, NULL, NULL, 0, NULL,
286 1,0, // dest, bit instruction
288 0, // literal operand
290 0, // fast call/return mode select bit
291 0, // second memory operand
292 0, // second literal operand
294 (PCC_W | PCC_REGISTER | PCC_C), // inCond
295 (PCC_REGISTER | PCC_STATUS), // outCond
299 pCodeInstruction pic16_pciADDFWC = {
300 {PC_OPCODE, NULL, NULL, 0, NULL,
314 0,0, // dest, bit instruction
316 0, // literal operand
318 0, // fast call/return mode select bit
319 0, // second memory operand
320 0, // second literal operand
322 (PCC_W | PCC_REGISTER | PCC_C), // inCond
323 (PCC_W | PCC_STATUS), // outCond
327 pCodeInstruction pic16_pciADDLW = {
328 {PC_OPCODE, NULL, NULL, 0, NULL,
342 0,0, // dest, bit instruction
344 1, // literal operand
346 0, // fast call/return mode select bit
347 0, // second memory operand
348 0, // second literal operand
350 (PCC_W | PCC_LITERAL), // inCond
351 (PCC_W | PCC_STATUS), // outCond
355 pCodeInstruction pic16_pciANDLW = {
356 {PC_OPCODE, NULL, NULL, 0, NULL,
370 0,0, // dest, bit instruction
372 1, // literal operand
374 0, // fast call/return mode select bit
375 0, // second memory operand
376 0, // second literal operand
378 (PCC_W | PCC_LITERAL), // inCond
379 (PCC_W | PCC_Z | PCC_N), // outCond
383 pCodeInstruction pic16_pciANDWF = {
384 {PC_OPCODE, NULL, NULL, 0, NULL,
398 1,0, // dest, bit instruction
400 0, // literal operand
402 0, // fast call/return mode select bit
403 0, // second memory operand
404 0, // second literal operand
406 (PCC_W | PCC_REGISTER), // inCond
407 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
411 pCodeInstruction pic16_pciANDFW = {
412 {PC_OPCODE, NULL, NULL, 0, NULL,
426 0,0, // dest, bit instruction
428 0, // literal operand
430 0, // fast call/return mode select bit
431 0, // second memory operand
432 0, // second literal operand
434 (PCC_W | PCC_REGISTER), // inCond
435 (PCC_W | PCC_Z | PCC_N) // outCond
438 pCodeInstruction pic16_pciBC = { // mdubuc - New
439 {PC_OPCODE, NULL, NULL, 0, NULL,
453 0,0, // dest, bit instruction
455 0, // literal operand
457 0, // fast call/return mode select bit
458 0, // second memory operand
459 0, // second literal operand
461 (PCC_REL_ADDR | PCC_C), // inCond
466 pCodeInstruction pic16_pciBCF = {
467 {PC_OPCODE, NULL, NULL, 0, NULL,
481 1,1, // dest, bit instruction
483 0, // literal operand
485 0, // fast call/return mode select bit
486 0, // second memory operand
487 0, // second literal operand
489 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
490 PCC_REGISTER, // outCond
494 pCodeInstruction pic16_pciBN = { // mdubuc - New
495 {PC_OPCODE, NULL, NULL, 0, NULL,
509 0,0, // dest, bit instruction
511 0, // literal operand
513 0, // fast call/return mode select bit
514 0, // second memory operand
515 0, // second literal operand
517 (PCC_REL_ADDR | PCC_N), // inCond
518 PCC_NONE , // outCond
522 pCodeInstruction pic16_pciBNC = { // mdubuc - New
523 {PC_OPCODE, NULL, NULL, 0, NULL,
537 0,0, // dest, bit instruction
539 0, // literal operand
541 0, // fast call/return mode select bit
542 0, // second memory operand
543 0, // second literal operand
545 (PCC_REL_ADDR | PCC_C), // inCond
546 PCC_NONE , // outCond
550 pCodeInstruction pic16_pciBNN = { // mdubuc - New
551 {PC_OPCODE, NULL, NULL, 0, NULL,
565 0,0, // dest, bit instruction
567 0, // literal operand
569 0, // fast call/return mode select bit
570 0, // second memory operand
571 0, // second literal operand
573 (PCC_REL_ADDR | PCC_N), // inCond
574 PCC_NONE , // outCond
578 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
579 {PC_OPCODE, NULL, NULL, 0, NULL,
593 0,0, // dest, bit instruction
595 0, // literal operand
597 0, // fast call/return mode select bit
598 0, // second memory operand
599 0, // second literal operand
601 (PCC_REL_ADDR | PCC_OV), // inCond
602 PCC_NONE , // outCond
606 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
607 {PC_OPCODE, NULL, NULL, 0, NULL,
621 0,0, // dest, bit instruction
623 0, // literal operand
625 0, // fast call/return mode select bit
626 0, // second memory operand
627 0, // second literal operand
629 (PCC_REL_ADDR | PCC_Z), // inCond
630 PCC_NONE , // outCond
634 pCodeInstruction pic16_pciBOV = { // mdubuc - New
635 {PC_OPCODE, NULL, NULL, 0, NULL,
649 0,0, // dest, bit instruction
651 0, // literal operand
653 0, // fast call/return mode select bit
654 0, // second memory operand
655 0, // second literal operand
657 (PCC_REL_ADDR | PCC_OV), // inCond
658 PCC_NONE , // outCond
662 pCodeInstruction pic16_pciBRA = { // mdubuc - New
663 {PC_OPCODE, NULL, NULL, 0, NULL,
677 0,0, // dest, bit instruction
679 0, // literal operand
681 0, // fast call/return mode select bit
682 0, // second memory operand
683 0, // second literal operand
685 PCC_REL_ADDR, // inCond
686 PCC_NONE , // outCond
690 pCodeInstruction pic16_pciBSF = {
691 {PC_OPCODE, NULL, NULL, 0, NULL,
705 1,1, // dest, bit instruction
707 0, // literal operand
709 0, // fast call/return mode select bit
710 0, // second memory operand
711 0, // second literal operand
713 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
714 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
718 pCodeInstruction pic16_pciBTFSC = {
719 {PC_OPCODE, NULL, NULL, 0, NULL,
733 0,1, // dest, bit instruction
735 0, // literal operand
737 0, // fast call/return mode select bit
738 0, // second memory operand
739 0, // second literal operand
741 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
742 PCC_EXAMINE_PCOP, // outCond
746 pCodeInstruction pic16_pciBTFSS = {
747 {PC_OPCODE, NULL, NULL, 0, NULL,
761 0,1, // dest, bit instruction
763 0, // literal operand
765 0, // fast call/return mode select bit
766 0, // second memory operand
767 0, // second literal operand
769 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
770 PCC_EXAMINE_PCOP, // outCond
774 pCodeInstruction pic16_pciBTG = { // mdubuc - New
775 {PC_OPCODE, NULL, NULL, 0, NULL,
789 0,1, // dest, bit instruction
791 0, // literal operand
793 0, // fast call/return mode select bit
794 0, // second memory operand
795 0, // second literal operand
797 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
798 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
802 pCodeInstruction pic16_pciBZ = { // mdubuc - New
803 {PC_OPCODE, NULL, NULL, 0, NULL,
817 0,0, // dest, bit instruction
819 0, // literal operand
821 0, // fast call/return mode select bit
822 0, // second memory operand
823 0, // second literal operand
825 (PCC_REL_ADDR | PCC_Z), // inCond
830 pCodeInstruction pic16_pciCALL = {
831 {PC_OPCODE, NULL, NULL, 0, NULL,
845 0,0, // dest, bit instruction
847 0, // literal operand
849 1, // fast call/return mode select bit
850 0, // second memory operand
851 0, // second literal operand
858 pCodeInstruction pic16_pciCOMF = {
859 {PC_OPCODE, NULL, NULL, 0, NULL,
873 1,0, // dest, bit instruction
875 0, // literal operand
877 0, // fast call/return mode select bit
878 0, // second memory operand
879 0, // second literal operand
881 PCC_REGISTER, // inCond
882 (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
886 pCodeInstruction pic16_pciCOMFW = {
887 {PC_OPCODE, NULL, NULL, 0, NULL,
901 0,0, // dest, bit instruction
903 0, // literal operand
905 0, // fast call/return mode select bit
906 0, // second memory operand
907 0, // second literal operand
909 PCC_REGISTER, // inCond
910 (PCC_W | PCC_Z | PCC_N) , // outCond
914 pCodeInstruction pic16_pciCLRF = {
915 {PC_OPCODE, NULL, NULL, 0, NULL,
929 0,0, // dest, bit instruction
931 0, // literal operand
933 0, // fast call/return mode select bit
934 0, // second memory operand
935 0, // second literal operand
938 (PCC_REGISTER | PCC_Z), // outCond
942 pCodeInstruction pic16_pciCLRWDT = {
943 {PC_OPCODE, NULL, NULL, 0, NULL,
957 0,0, // dest, bit instruction
959 0, // literal operand
961 0, // fast call/return mode select bit
962 0, // second memory operand
963 0, // second literal operand
966 PCC_NONE , // outCond
970 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
971 {PC_OPCODE, NULL, NULL, 0, NULL,
985 0,0, // dest, bit instruction
987 0, // literal operand
989 0, // fast call/return mode select bit
990 0, // second memory operand
991 0, // second literal operand
993 (PCC_W | PCC_REGISTER), // inCond
994 PCC_NONE , // outCond
998 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
999 {PC_OPCODE, NULL, NULL, 0, NULL,
1006 NULL, // from branch
1013 0,0, // dest, bit instruction
1014 1,1, // branch, skip
1015 0, // literal operand
1016 1, // RAM access bit
1017 0, // fast call/return mode select bit
1018 0, // second memory operand
1019 0, // second literal operand
1021 (PCC_W | PCC_REGISTER), // inCond
1022 PCC_NONE , // outCond
1026 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1027 {PC_OPCODE, NULL, NULL, 0, NULL,
1034 NULL, // from branch
1041 1,0, // dest, bit instruction
1042 1,1, // branch, skip
1043 0, // literal operand
1044 1, // RAM access bit
1045 0, // fast call/return mode select bit
1046 0, // second memory operand
1047 0, // second literal operand
1049 (PCC_W | PCC_REGISTER), // inCond
1050 PCC_NONE , // outCond
1054 pCodeInstruction pic16_pciDAW = {
1055 {PC_OPCODE, NULL, NULL, 0, NULL,
1062 NULL, // from branch
1069 0,0, // dest, bit instruction
1070 0,0, // branch, skip
1071 0, // literal operand
1072 0, // RAM access bit
1073 0, // fast call/return mode select bit
1074 0, // second memory operand
1075 0, // second literal operand
1078 (PCC_W | PCC_C), // outCond
1082 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1083 {PC_OPCODE, NULL, NULL, 0, NULL,
1090 NULL, // from branch
1097 1,0, // dest, bit instruction
1098 1,1, // branch, skip
1099 0, // literal operand
1100 1, // RAM access bit
1101 0, // fast call/return mode select bit
1102 0, // second memory operand
1103 0, // second literal operand
1105 PCC_REGISTER, // inCond
1106 PCC_REGISTER , // outCond
1110 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1111 {PC_OPCODE, NULL, NULL, 0, NULL,
1118 NULL, // from branch
1125 0,0, // dest, bit instruction
1126 1,1, // branch, skip
1127 0, // literal operand
1128 1, // RAM access bit
1129 0, // fast call/return mode select bit
1130 0, // second memory operand
1131 0, // second literal operand
1133 PCC_REGISTER, // inCond
1138 pCodeInstruction pic16_pciDECF = {
1139 {PC_OPCODE, NULL, NULL, 0, NULL,
1146 NULL, // from branch
1153 1,0, // dest, bit instruction
1154 0,0, // branch, skip
1155 0, // literal operand
1156 1, // RAM access bit
1157 0, // fast call/return mode select bit
1158 0, // second memory operand
1159 0, // second literal operand
1161 PCC_REGISTER, // inCond
1162 (PCC_REGISTER | PCC_STATUS) , // outCond
1166 pCodeInstruction pic16_pciDECFW = {
1167 {PC_OPCODE, NULL, NULL, 0, NULL,
1174 NULL, // from branch
1181 0,0, // dest, bit instruction
1182 0,0, // branch, skip
1183 0, // literal operand
1184 1, // RAM access bit
1185 0, // fast call/return mode select bit
1186 0, // second memory operand
1187 0, // second literal operand
1189 PCC_REGISTER, // inCond
1190 (PCC_W | PCC_STATUS) , // outCond
1194 pCodeInstruction pic16_pciDECFSZ = {
1195 {PC_OPCODE, NULL, NULL, 0, NULL,
1202 NULL, // from branch
1209 1,0, // dest, bit instruction
1210 1,1, // branch, skip
1211 0, // literal operand
1212 1, // RAM access bit
1213 0, // fast call/return mode select bit
1214 0, // second memory operand
1215 0, // second literal operand
1217 PCC_REGISTER, // inCond
1218 PCC_REGISTER , // outCond
1222 pCodeInstruction pic16_pciDECFSZW = {
1223 {PC_OPCODE, NULL, NULL, 0, NULL,
1230 NULL, // from branch
1237 0,0, // dest, bit instruction
1238 1,1, // branch, skip
1239 0, // literal operand
1240 1, // RAM access bit
1241 0, // fast call/return mode select bit
1242 0, // second memory operand
1243 0, // second literal operand
1245 PCC_REGISTER, // inCond
1250 pCodeInstruction pic16_pciGOTO = {
1251 {PC_OPCODE, NULL, NULL, 0, NULL,
1258 NULL, // from branch
1265 0,0, // dest, bit instruction
1266 1,0, // branch, skip
1267 0, // literal operand
1268 0, // RAM access bit
1269 0, // fast call/return mode select bit
1270 0, // second memory operand
1271 0, // second literal operand
1273 PCC_REL_ADDR, // inCond
1274 PCC_NONE , // outCond
1278 pCodeInstruction pic16_pciINCF = {
1279 {PC_OPCODE, NULL, NULL, 0, NULL,
1286 NULL, // from branch
1293 1,0, // dest, bit instruction
1294 0,0, // branch, skip
1295 0, // literal operand
1296 1, // RAM access bit
1297 0, // fast call/return mode select bit
1298 0, // second memory operand
1299 0, // second literal operand
1301 PCC_REGISTER, // inCond
1302 (PCC_REGISTER | PCC_STATUS), // outCond
1306 pCodeInstruction pic16_pciINCFW = {
1307 {PC_OPCODE, NULL, NULL, 0, NULL,
1314 NULL, // from branch
1321 0,0, // dest, bit instruction
1322 0,0, // branch, skip
1323 0, // literal operand
1324 1, // RAM access bit
1325 0, // fast call/return mode select bit
1326 0, // second memory operand
1327 0, // second literal operand
1329 PCC_REGISTER, // inCond
1330 (PCC_W | PCC_STATUS) , // outCond
1334 pCodeInstruction pic16_pciINCFSZ = {
1335 {PC_OPCODE, NULL, NULL, 0, NULL,
1342 NULL, // from branch
1349 1,0, // dest, bit instruction
1350 1,1, // branch, skip
1351 0, // literal operand
1352 1, // RAM access bit
1353 0, // fast call/return mode select bit
1354 0, // second memory operand
1355 0, // second literal operand
1357 PCC_REGISTER, // inCond
1358 PCC_REGISTER , // outCond
1362 pCodeInstruction pic16_pciINCFSZW = {
1363 {PC_OPCODE, NULL, NULL, 0, NULL,
1370 NULL, // from branch
1377 0,0, // dest, bit instruction
1378 1,1, // branch, skip
1379 0, // literal operand
1380 1, // RAM access bit
1381 0, // fast call/return mode select bit
1382 0, // second memory operand
1383 0, // second literal operand
1385 PCC_REGISTER, // inCond
1390 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1391 {PC_OPCODE, NULL, NULL, 0, NULL,
1398 NULL, // from branch
1405 1,0, // dest, bit instruction
1406 1,1, // branch, skip
1407 0, // literal operand
1408 1, // RAM access bit
1409 0, // fast call/return mode select bit
1410 0, // second memory operand
1411 0, // second literal operand
1413 PCC_REGISTER, // inCond
1414 PCC_REGISTER , // outCond
1418 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1419 {PC_OPCODE, NULL, NULL, 0, NULL,
1426 NULL, // from branch
1433 0,0, // dest, bit instruction
1434 1,1, // branch, skip
1435 0, // literal operand
1436 1, // RAM access bit
1437 0, // fast call/return mode select bit
1438 0, // second memory operand
1439 0, // second literal operand
1441 PCC_REGISTER, // inCond
1446 pCodeInstruction pic16_pciIORWF = {
1447 {PC_OPCODE, NULL, NULL, 0, NULL,
1454 NULL, // from branch
1461 1,0, // dest, bit instruction
1462 0,0, // branch, skip
1463 0, // literal operand
1464 1, // RAM access bit
1465 0, // fast call/return mode select bit
1466 0, // second memory operand
1467 0, // second literal operand
1469 (PCC_W | PCC_REGISTER), // inCond
1470 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1474 pCodeInstruction pic16_pciIORFW = {
1475 {PC_OPCODE, NULL, NULL, 0, NULL,
1482 NULL, // from branch
1489 0,0, // dest, bit instruction
1490 0,0, // branch, skip
1491 0, // literal operand
1492 1, // RAM access bit
1493 0, // fast call/return mode select bit
1494 0, // second memory operand
1495 0, // second literal operand
1497 (PCC_W | PCC_REGISTER), // inCond
1498 (PCC_W | PCC_Z | PCC_N), // outCond
1502 pCodeInstruction pic16_pciIORLW = {
1503 {PC_OPCODE, NULL, NULL, 0, NULL,
1510 NULL, // from branch
1517 0,0, // dest, bit instruction
1518 0,0, // branch, skip
1519 1, // literal operand
1520 0, // RAM access bit
1521 0, // fast call/return mode select bit
1522 0, // second memory operand
1523 0, // second literal operand
1525 (PCC_W | PCC_LITERAL), // inCond
1526 (PCC_W | PCC_Z | PCC_N), // outCond
1530 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1531 {PC_OPCODE, NULL, NULL, 0, NULL,
1538 NULL, // from branch
1545 0,0, // dest, bit instruction
1546 0,0, // branch, skip
1547 1, // literal operand
1548 0, // RAM access bit
1549 0, // fast call/return mode select bit
1550 0, // second memory operand
1551 1, // second literal operand
1553 PCC_LITERAL, // inCond
1554 PCC_NONE, // outCond
1558 pCodeInstruction pic16_pciMOVF = {
1559 {PC_OPCODE, NULL, NULL, 0, NULL,
1566 NULL, // from branch
1573 1,0, // dest, bit instruction
1574 0,0, // branch, skip
1575 0, // literal operand
1576 1, // RAM access bit
1577 0, // fast call/return mode select bit
1578 0, // second memory operand
1579 0, // second literal operand
1581 PCC_REGISTER, // inCond
1582 (PCC_Z | PCC_N), // outCond
1586 pCodeInstruction pic16_pciMOVFW = {
1587 {PC_OPCODE, NULL, NULL, 0, NULL,
1594 NULL, // from branch
1601 0,0, // dest, bit instruction
1602 0,0, // branch, skip
1603 0, // literal operand
1604 1, // RAM access bit
1605 0, // fast call/return mode select bit
1606 0, // second memory operand
1607 0, // second literal operand
1609 PCC_REGISTER, // inCond
1610 (PCC_W | PCC_N | PCC_Z), // outCond
1614 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1615 {PC_OPCODE, NULL, NULL, 0, NULL,
1622 NULL, // from branch
1629 0,0, // dest, bit instruction
1630 0,0, // branch, skip
1631 0, // literal operand
1632 0, // RAM access bit
1633 0, // fast call/return mode select bit
1634 1, // second memory operand
1635 0, // second literal operand
1637 PCC_REGISTER, // inCond
1638 PCC_REGISTER2, // outCond
1642 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1643 {PC_OPCODE, NULL, NULL, 0, NULL,
1649 NULL, // from branch
1656 0,0, // dest, bit instruction
1657 0,0, // branch, skip
1658 1, // literal operand
1659 0, // RAM access bit
1660 0, // fast call/return mode select bit
1661 0, // second memory operand
1662 0, // second literal operand
1664 (PCC_NONE | PCC_LITERAL), // inCond
1665 PCC_REGISTER, // outCond - BSR
1669 pCodeInstruction pic16_pciMOVLW = {
1670 {PC_OPCODE, NULL, NULL, 0, NULL,
1676 NULL, // from branch
1683 0,0, // dest, bit instruction
1684 0,0, // branch, skip
1685 1, // literal operand
1686 0, // RAM access bit
1687 0, // fast call/return mode select bit
1688 0, // second memory operand
1689 0, // second literal operand
1691 (PCC_NONE | PCC_LITERAL), // inCond
1696 pCodeInstruction pic16_pciMOVWF = {
1697 {PC_OPCODE, NULL, NULL, 0, NULL,
1704 NULL, // from branch
1711 0,0, // dest, bit instruction
1712 0,0, // branch, skip
1713 0, // literal operand
1714 1, // RAM access bit
1715 0, // fast call/return mode select bit
1716 0, // second memory operand
1717 0, // second literal operand
1720 PCC_REGISTER, // outCond
1724 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1725 {PC_OPCODE, NULL, NULL, 0, NULL,
1731 NULL, // from branch
1738 0,0, // dest, bit instruction
1739 0,0, // branch, skip
1740 1, // literal operand
1741 0, // RAM access bit
1742 0, // fast call/return mode select bit
1743 0, // second memory operand
1744 0, // second literal operand
1746 (PCC_W | PCC_LITERAL), // inCond
1747 PCC_NONE, // outCond - PROD
1751 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1752 {PC_OPCODE, NULL, NULL, 0, NULL,
1758 NULL, // from branch
1765 0,0, // dest, bit instruction
1766 0,0, // branch, skip
1767 0, // literal operand
1768 1, // RAM access bit
1769 0, // fast call/return mode select bit
1770 0, // second memory operand
1771 0, // second literal operand
1773 (PCC_W | PCC_REGISTER), // inCond
1774 PCC_REGISTER, // outCond - PROD
1778 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1779 {PC_OPCODE, NULL, NULL, 0, NULL,
1785 NULL, // from branch
1792 0,0, // dest, bit instruction
1793 0,0, // branch, skip
1794 0, // literal operand
1795 1, // RAM access bit
1796 0, // fast call/return mode select bit
1797 0, // second memory operand
1798 0, // second literal operand
1800 PCC_REGISTER, // inCond
1801 (PCC_REGISTER | PCC_STATUS), // outCond
1805 pCodeInstruction pic16_pciNOP = {
1806 {PC_OPCODE, NULL, NULL, 0, NULL,
1812 NULL, // from branch
1819 0,0, // dest, bit instruction
1820 0,0, // branch, skip
1821 0, // literal operand
1822 0, // RAM access bit
1823 0, // fast call/return mode select bit
1824 0, // second memory operand
1825 0, // second literal operand
1828 PCC_NONE, // outCond
1832 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1833 {PC_OPCODE, NULL, NULL, 0, NULL,
1839 NULL, // from branch
1846 0,0, // dest, bit instruction
1847 0,0, // branch, skip
1848 0, // literal operand
1849 0, // RAM access bit
1850 0, // fast call/return mode select bit
1851 0, // second memory operand
1852 0, // second literal operand
1855 PCC_NONE , // outCond
1859 pCodeInstruction pic16_pciPUSH = {
1860 {PC_OPCODE, NULL, NULL, 0, NULL,
1866 NULL, // from branch
1873 0,0, // dest, bit instruction
1874 0,0, // branch, skip
1875 0, // literal operand
1876 0, // RAM access bit
1877 0, // fast call/return mode select bit
1878 0, // second memory operand
1879 0, // second literal operand
1882 PCC_NONE , // outCond
1886 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1887 {PC_OPCODE, NULL, NULL, 0, NULL,
1893 NULL, // from branch
1900 0,0, // dest, bit instruction
1901 1,0, // branch, skip
1902 0, // literal operand
1903 0, // RAM access bit
1904 0, // fast call/return mode select bit
1905 0, // second memory operand
1906 0, // second literal operand
1908 PCC_REL_ADDR, // inCond
1909 PCC_NONE , // outCond
1913 pCodeInstruction pic16_pciRETFIE = {
1914 {PC_OPCODE, NULL, NULL, 0, NULL,
1921 NULL, // from branch
1928 0,0, // dest, bit instruction
1929 1,0, // branch, skip
1930 0, // literal operand
1931 0, // RAM access bit
1932 1, // fast call/return mode select bit
1933 0, // second memory operand
1934 0, // second literal operand
1937 PCC_NONE, // outCond (not true... affects the GIE bit too)
1941 pCodeInstruction pic16_pciRETLW = {
1942 {PC_OPCODE, NULL, NULL, 0, NULL,
1949 NULL, // from branch
1956 0,0, // dest, bit instruction
1957 1,0, // branch, skip
1958 1, // literal operand
1959 0, // RAM access bit
1960 0, // fast call/return mode select bit
1961 0, // second memory operand
1962 0, // second literal operand
1964 PCC_LITERAL, // inCond
1969 pCodeInstruction pic16_pciRETURN = {
1970 {PC_OPCODE, NULL, NULL, 0, NULL,
1977 NULL, // from branch
1984 0,0, // dest, bit instruction
1985 1,0, // branch, skip
1986 0, // literal operand
1987 0, // RAM access bit
1988 1, // fast call/return mode select bit
1989 0, // second memory operand
1990 0, // second literal operand
1993 PCC_NONE, // outCond
1996 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
1997 {PC_OPCODE, NULL, NULL, 0, NULL,
2004 NULL, // from branch
2011 1,0, // dest, bit instruction
2012 0,0, // branch, skip
2013 0, // literal operand
2014 1, // RAM access bit
2015 0, // fast call/return mode select bit
2016 0, // second memory operand
2017 0, // second literal operand
2019 (PCC_C | PCC_REGISTER), // inCond
2020 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2024 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2025 {PC_OPCODE, NULL, NULL, 0, NULL,
2032 NULL, // from branch
2039 0,0, // dest, bit instruction
2040 0,0, // branch, skip
2041 0, // literal operand
2042 1, // RAM access bit
2043 0, // fast call/return mode select bit
2044 0, // second memory operand
2045 0, // second literal operand
2047 (PCC_C | PCC_REGISTER), // inCond
2048 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2052 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2053 {PC_OPCODE, NULL, NULL, 0, NULL,
2060 NULL, // from branch
2067 1,0, // dest, bit instruction
2068 0,0, // branch, skip
2069 0, // literal operand
2070 1, // RAM access bit
2071 0, // fast call/return mode select bit
2072 0, // second memory operand
2073 0, // second literal operand
2075 PCC_REGISTER, // inCond
2076 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2079 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2080 {PC_OPCODE, NULL, NULL, 0, NULL,
2087 NULL, // from branch
2094 0,0, // dest, bit instruction
2095 0,0, // branch, skip
2096 0, // literal operand
2097 1, // RAM access bit
2098 0, // fast call/return mode select bit
2099 0, // second memory operand
2100 0, // second literal operand
2102 PCC_REGISTER, // inCond
2103 (PCC_W | PCC_Z | PCC_N), // outCond
2106 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2107 {PC_OPCODE, NULL, NULL, 0, NULL,
2114 NULL, // from branch
2121 1,0, // dest, bit instruction
2122 0,0, // branch, skip
2123 0, // literal operand
2124 1, // RAM access bit
2125 0, // fast call/return mode select bit
2126 0, // second memory operand
2127 0, // second literal operand
2129 (PCC_C | PCC_REGISTER), // inCond
2130 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2133 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2134 {PC_OPCODE, NULL, NULL, 0, NULL,
2141 NULL, // from branch
2148 0,0, // dest, bit instruction
2149 0,0, // branch, skip
2150 0, // literal operand
2151 1, // RAM access bit
2152 0, // fast call/return mode select bit
2153 0, // second memory operand
2154 0, // second literal operand
2156 (PCC_C | PCC_REGISTER), // inCond
2157 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2160 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2161 {PC_OPCODE, NULL, NULL, 0, NULL,
2168 NULL, // from branch
2175 1,0, // dest, bit instruction
2176 0,0, // branch, skip
2177 0, // literal operand
2178 1, // RAM access bit
2179 0, // fast call/return mode select bit
2180 0, // second memory operand
2181 0, // second literal operand
2183 PCC_REGISTER, // inCond
2184 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2188 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2189 {PC_OPCODE, NULL, NULL, 0, NULL,
2196 NULL, // from branch
2203 0,0, // dest, bit instruction
2204 0,0, // branch, skip
2205 0, // literal operand
2206 1, // RAM access bit
2207 0, // fast call/return mode select bit
2208 0, // second memory operand
2209 0, // second literal operand
2211 PCC_REGISTER, // inCond
2212 (PCC_W | PCC_Z | PCC_N), // outCond
2216 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2217 {PC_OPCODE, NULL, NULL, 0, NULL,
2224 NULL, // from branch
2231 0,0, // dest, bit instruction
2232 0,0, // branch, skip
2233 0, // literal operand
2234 1, // RAM access bit
2235 0, // fast call/return mode select bit
2236 0, // second memory operand
2237 0, // second literal operand
2240 PCC_REGISTER , // outCond
2244 pCodeInstruction pic16_pciSUBLW = {
2245 {PC_OPCODE, NULL, NULL, 0, NULL,
2252 NULL, // from branch
2259 0,0, // dest, bit instruction
2260 0,0, // branch, skip
2261 1, // literal operand
2262 0, // RAM access bit
2263 0, // fast call/return mode select bit
2264 0, // second memory operand
2265 0, // second literal operand
2267 (PCC_W | PCC_LITERAL), // inCond
2268 (PCC_W | PCC_STATUS), // outCond
2272 pCodeInstruction pic16_pciSUBFWB = {
2273 {PC_OPCODE, NULL, NULL, 0, NULL,
2280 NULL, // from branch
2287 1,0, // dest, bit instruction
2288 0,0, // branch, skip
2289 0, // literal operand
2290 1, // RAM access bit
2291 0, // fast call/return mode select bit
2292 0, // second memory operand
2293 0, // second literal operand
2295 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2296 (PCC_W | PCC_STATUS), // outCond
2300 pCodeInstruction pic16_pciSUBWF = {
2301 {PC_OPCODE, NULL, NULL, 0, NULL,
2308 NULL, // from branch
2315 1,0, // dest, bit instruction
2316 0,0, // branch, skip
2317 0, // literal operand
2318 1, // RAM access bit
2319 0, // fast call/return mode select bit
2320 0, // second memory operand
2321 0, // second literal operand
2323 (PCC_W | PCC_REGISTER), // inCond
2324 (PCC_REGISTER | PCC_STATUS), // outCond
2328 pCodeInstruction pic16_pciSUBFW = {
2329 {PC_OPCODE, NULL, NULL, 0, NULL,
2336 NULL, // from branch
2343 0,0, // dest, bit instruction
2344 0,0, // branch, skip
2345 0, // literal operand
2346 1, // RAM access bit
2347 0, // fast call/return mode select bit
2348 0, // second memory operand
2349 0, // second literal operand
2351 (PCC_W | PCC_REGISTER), // inCond
2352 (PCC_W | PCC_STATUS), // outCond
2356 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2357 {PC_OPCODE, NULL, NULL, 0, NULL,
2364 NULL, // from branch
2371 1,0, // dest, bit instruction
2372 0,0, // branch, skip
2373 0, // literal operand
2374 1, // RAM access bit
2375 0, // fast call/return mode select bit
2376 0, // second memory operand
2377 0, // second literal operand
2379 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2380 (PCC_REGISTER | PCC_STATUS), // outCond
2384 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2385 {PC_OPCODE, NULL, NULL, 0, NULL,
2392 NULL, // from branch
2399 0,0, // dest, bit instruction
2400 0,0, // branch, skip
2401 0, // literal operand
2402 1, // RAM access bit
2403 0, // fast call/return mode select bit
2404 0, // second memory operand
2405 0, // second literal operand
2407 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2408 (PCC_W | PCC_STATUS), // outCond
2412 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2413 {PC_OPCODE, NULL, NULL, 0, NULL,
2420 NULL, // from branch
2427 1,0, // dest, bit instruction
2428 0,0, // branch, skip
2429 0, // literal operand
2430 1, // RAM access bit
2431 0, // fast call/return mode select bit
2432 0, // second memory operand
2433 0, // second literal operand
2435 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2436 (PCC_REGISTER | PCC_STATUS), // outCond
2440 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2441 {PC_OPCODE, NULL, NULL, 0, NULL,
2448 NULL, // from branch
2455 0,0, // dest, bit instruction
2456 0,0, // branch, skip
2457 0, // literal operand
2458 1, // RAM access bit
2459 0, // fast call/return mode select bit
2460 0, // second memory operand
2461 0, // second literal operand
2463 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2464 (PCC_W | PCC_STATUS), // outCond
2468 pCodeInstruction pic16_pciSWAPF = {
2469 {PC_OPCODE, NULL, NULL, 0, NULL,
2476 NULL, // from branch
2483 1,0, // dest, bit instruction
2484 0,0, // branch, skip
2485 0, // literal operand
2486 1, // RAM access bit
2487 0, // fast call/return mode select bit
2488 0, // second memory operand
2489 0, // second literal operand
2491 (PCC_REGISTER), // inCond
2492 (PCC_REGISTER), // outCond
2496 pCodeInstruction pic16_pciSWAPFW = {
2497 {PC_OPCODE, NULL, NULL, 0, NULL,
2504 NULL, // from branch
2511 0,0, // dest, bit instruction
2512 0,0, // branch, skip
2513 0, // literal operand
2514 1, // RAM access bit
2515 0, // fast call/return mode select bit
2516 0, // second memory operand
2517 0, // second literal operand
2519 (PCC_REGISTER), // inCond
2524 pCodeInstruction pic16_pciTBLRD = { // patch 15
2525 {PC_OPCODE, NULL, NULL, 0, NULL,
2531 NULL, // from branch
2538 0,0, // dest, bit instruction
2539 0,0, // branch, skip
2540 0, // literal operand
2541 0, // RAM access bit
2542 0, // fast call/return mode select bit
2543 0, // second memory operand
2544 0, // second literal operand
2547 PCC_NONE , // outCond
2551 pCodeInstruction pic16_pciTBLRD_POSTINC = { // patch 15
2552 {PC_OPCODE, NULL, NULL, 0, NULL,
2558 NULL, // from branch
2565 0,0, // dest, bit instruction
2566 0,0, // branch, skip
2567 0, // literal operand
2568 0, // RAM access bit
2569 0, // fast call/return mode select bit
2570 0, // second memory operand
2571 0, // second literal operand
2574 PCC_NONE , // outCond
2578 pCodeInstruction pic16_pciTBLRD_POSTDEC = { // patch 15
2579 {PC_OPCODE, NULL, NULL, 0, NULL,
2585 NULL, // from branch
2592 0,0, // dest, bit instruction
2593 0,0, // branch, skip
2594 0, // literal operand
2595 0, // RAM access bit
2596 0, // fast call/return mode select bit
2597 0, // second memory operand
2598 0, // second literal operand
2601 PCC_NONE , // outCond
2605 pCodeInstruction pic16_pciTBLRD_PREINC = { // patch 15
2606 {PC_OPCODE, NULL, NULL, 0, NULL,
2612 NULL, // from branch
2619 0,0, // dest, bit instruction
2620 0,0, // branch, skip
2621 0, // literal operand
2622 0, // RAM access bit
2623 0, // fast call/return mode select bit
2624 0, // second memory operand
2625 0, // second literal operand
2628 PCC_NONE , // outCond
2632 pCodeInstruction pic16_pciTBLWT = { // patch 15
2633 {PC_OPCODE, NULL, NULL, 0, NULL,
2639 NULL, // from branch
2646 0,0, // dest, bit instruction
2647 0,0, // branch, skip
2648 0, // literal operand
2649 0, // RAM access bit
2650 0, // fast call/return mode select bit
2651 0, // second memory operand
2652 0, // second literal operand
2655 PCC_NONE , // outCond
2659 pCodeInstruction pic16_pciTBLWT_POSTINC = { // patch 15
2660 {PC_OPCODE, NULL, NULL, 0, NULL,
2666 NULL, // from branch
2673 0,0, // dest, bit instruction
2674 0,0, // branch, skip
2675 0, // literal operand
2676 0, // RAM access bit
2677 0, // fast call/return mode select bit
2678 0, // second memory operand
2679 0, // second literal operand
2682 PCC_NONE , // outCond
2686 pCodeInstruction pic16_pciTBLWT_POSTDEC = { // patch 15
2687 {PC_OPCODE, NULL, NULL, 0, NULL,
2693 NULL, // from branch
2700 0,0, // dest, bit instruction
2701 0,0, // branch, skip
2702 0, // literal operand
2703 0, // RAM access bit
2704 0, // fast call/return mode select bit
2705 0, // second memory operand
2706 0, // second literal operand
2709 PCC_NONE , // outCond
2713 pCodeInstruction pic16_pciTBLWT_PREINC = { // patch 15
2714 {PC_OPCODE, NULL, NULL, 0, NULL,
2720 NULL, // from branch
2727 0,0, // dest, bit instruction
2728 0,0, // branch, skip
2729 0, // literal operand
2730 0, // RAM access bit
2731 0, // fast call/return mode select bit
2732 0, // second memory operand
2733 0, // second literal operand
2736 PCC_NONE , // outCond
2740 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2741 {PC_OPCODE, NULL, NULL, 0, NULL,
2748 NULL, // from branch
2755 0,0, // dest, bit instruction
2756 1,1, // branch, skip
2757 0, // literal operand
2758 1, // RAM access bit
2759 0, // fast call/return mode select bit
2760 0, // second memory operand
2761 0, // second literal operand
2763 PCC_REGISTER, // inCond
2764 PCC_NONE, // outCond
2768 pCodeInstruction pic16_pciXORWF = {
2769 {PC_OPCODE, NULL, NULL, 0, NULL,
2776 NULL, // from branch
2783 1,0, // dest, bit instruction
2784 0,0, // branch, skip
2785 0, // literal operand
2786 1, // RAM access bit
2787 0, // fast call/return mode select bit
2788 0, // second memory operand
2789 0, // second literal operand
2791 (PCC_W | PCC_REGISTER), // inCond
2792 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2796 pCodeInstruction pic16_pciXORFW = {
2797 {PC_OPCODE, NULL, NULL, 0, NULL,
2804 NULL, // from branch
2811 0,0, // dest, bit instruction
2812 0,0, // branch, skip
2813 0, // literal operand
2814 1, // RAM access bit
2815 0, // fast call/return mode select bit
2816 0, // second memory operand
2817 0, // second literal operand
2819 (PCC_W | PCC_REGISTER), // inCond
2820 (PCC_W | PCC_Z | PCC_N), // outCond
2824 pCodeInstruction pic16_pciXORLW = {
2825 {PC_OPCODE, NULL, NULL, 0, NULL,
2832 NULL, // from branch
2839 0,0, // dest, bit instruction
2840 0,0, // branch, skip
2841 1, // literal operand
2842 1, // RAM access bit
2843 0, // fast call/return mode select bit
2844 0, // second memory operand
2845 0, // second literal operand
2847 (PCC_W | PCC_LITERAL), // inCond
2848 (PCC_W | PCC_Z | PCC_N), // outCond
2853 pCodeInstruction pic16_pciBANKSEL = {
2854 {PC_OPCODE, NULL, NULL, 0, NULL,
2860 NULL, // from branch
2867 0,0, // dest, bit instruction
2868 0,0, // branch, skip
2869 0, // literal operand
2870 0, // RAM access bit
2871 0, // fast call/return mode select bit
2872 0, // second memory operand
2873 0, // second literal operand
2876 PCC_NONE, // outCond
2881 #define MAX_PIC16MNEMONICS 100
2882 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2884 extern set *externs;
2885 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2886 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2888 void pic16_pCodeInitRegisters(void)
2890 static int initialized=0;
2897 pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2898 pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2899 pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2900 pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2901 pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2902 pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2903 pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2905 pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2906 pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2907 pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2909 pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2910 pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2911 pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2912 pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2914 pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2915 pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2916 pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2917 pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2918 pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2919 pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2921 pic16_stackpnt_lo = &pic16_pc_fsr1l;
2922 pic16_stackpnt_hi = &pic16_pc_fsr1h;
2923 pic16_stack_postdec = &pic16_pc_postdec1;
2924 pic16_stack_postinc = &pic16_pc_postinc1;
2925 pic16_stack_preinc = &pic16_pc_preinc1;
2926 pic16_stack_plusw = &pic16_pc_plusw1;
2928 pic16_framepnt_lo = &pic16_pc_fsr2l;
2929 pic16_framepnt_hi = &pic16_pc_fsr2h;
2930 pic16_frame_postdec = &pic16_pc_postdec2;
2931 pic16_frame_postinc = &pic16_pc_postinc2;
2932 pic16_frame_preinc = &pic16_pc_preinc2;
2933 pic16_frame_plusw = &pic16_pc_plusw2;
2935 pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
2936 pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
2937 pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
2938 pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
2939 pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
2941 pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
2942 pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
2943 pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
2944 pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
2945 pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
2947 pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
2948 pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
2949 pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
2950 pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
2951 pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
2953 pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
2954 pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
2957 pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
2958 pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
2959 pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
2960 pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
2963 pic16_pc_status.rIdx = IDX_STATUS;
2964 pic16_pc_intcon.rIdx = IDX_INTCON;
2965 pic16_pc_pcl.rIdx = IDX_PCL;
2966 pic16_pc_pclath.rIdx = IDX_PCLATH;
2967 pic16_pc_pclatu.rIdx = IDX_PCLATU;
2968 pic16_pc_wreg.rIdx = IDX_WREG;
2969 pic16_pc_bsr.rIdx = IDX_BSR;
2971 pic16_pc_tosl.rIdx = IDX_TOSL;
2972 pic16_pc_tosh.rIdx = IDX_TOSH;
2973 pic16_pc_tosu.rIdx = IDX_TOSU;
2975 pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
2976 pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
2977 pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
2978 pic16_pc_tablat.rIdx = IDX_TABLAT;
2980 pic16_pc_fsr0l.rIdx = IDX_FSR0L;
2981 pic16_pc_fsr0h.rIdx = IDX_FSR0H;
2982 pic16_pc_fsr1l.rIdx = IDX_FSR1L;
2983 pic16_pc_fsr1h.rIdx = IDX_FSR1H;
2984 pic16_pc_fsr2l.rIdx = IDX_FSR2L;
2985 pic16_pc_fsr2h.rIdx = IDX_FSR2H;
2986 pic16_pc_indf0.rIdx = IDX_INDF0;
2987 pic16_pc_postinc0.rIdx = IDX_POSTINC0;
2988 pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
2989 pic16_pc_preinc0.rIdx = IDX_PREINC0;
2990 pic16_pc_plusw0.rIdx = IDX_PLUSW0;
2991 pic16_pc_indf1.rIdx = IDX_INDF1;
2992 pic16_pc_postinc1.rIdx = IDX_POSTINC1;
2993 pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
2994 pic16_pc_preinc1.rIdx = IDX_PREINC1;
2995 pic16_pc_plusw1.rIdx = IDX_PLUSW1;
2996 pic16_pc_indf2.rIdx = IDX_INDF2;
2997 pic16_pc_postinc2.rIdx = IDX_POSTINC2;
2998 pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
2999 pic16_pc_preinc2.rIdx = IDX_PREINC2;
3000 pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3001 pic16_pc_prodl.rIdx = IDX_PRODL;
3002 pic16_pc_prodh.rIdx = IDX_PRODH;
3004 pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3005 pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3006 pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3008 pic16_pc_kzero.rIdx = IDX_KZ;
3009 pic16_pc_wsave.rIdx = IDX_WSAVE;
3010 pic16_pc_ssave.rIdx = IDX_SSAVE;
3012 pic16_pc_eecon1.rIdx = IDX_EECON1;
3013 pic16_pc_eecon2.rIdx = IDX_EECON2;
3014 pic16_pc_eedata.rIdx = IDX_EEDATA;
3015 pic16_pc_eeadr.rIdx = IDX_EEADR;
3018 pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3019 pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3021 pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3022 pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3024 /* probably should put this in a separate initialization routine */
3025 pb_dead_pcodes = newpBlock();
3030 /*-----------------------------------------------------------------*/
3031 /* mnem2key - convert a pic mnemonic into a hash key */
3032 /* (BTW - this spreads the mnemonics quite well) */
3034 /*-----------------------------------------------------------------*/
3036 int mnem2key(unsigned char const *mnem)
3045 key += toupper(*mnem++) +1;
3049 return (key & 0x1f);
3054 void pic16initMnemonics(void)
3059 pCodeInstruction *pci;
3061 if(mnemonics_initialized)
3064 // NULL out the array before making the assignments
3065 // since we check the array contents below this initialization.
3067 for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3068 pic16Mnemonics[i] = NULL;
3071 pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3072 pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3073 pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3074 pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3075 pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3076 pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3077 pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3078 pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3079 pic16Mnemonics[POC_BC] = &pic16_pciBC;
3080 pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3081 pic16Mnemonics[POC_BN] = &pic16_pciBN;
3082 pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3083 pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3084 pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3085 pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3086 pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3087 pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3088 pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3089 pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3090 pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3091 pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3092 pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3093 pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3094 pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3095 pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3096 pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3097 pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3098 pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3099 pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3100 pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3101 pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3102 pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3103 pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3104 pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3105 pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3106 pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3107 pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3108 pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3109 pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3110 pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3111 pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3112 pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3113 pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3114 pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3115 pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3116 pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3117 pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3118 pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3119 pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3120 pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3121 pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3122 pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3123 pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3124 pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3125 pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3126 pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3127 pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3128 pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3129 pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3130 pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3131 pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3132 pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3133 pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3134 pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3135 pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3136 pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3137 pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3138 pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3139 pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3140 pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3141 pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3142 pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3143 pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3144 pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3145 pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3146 pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3147 pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3148 pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3149 pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3150 pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3151 pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3152 pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3153 pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3154 pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3155 pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3156 pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3157 pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3158 pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3159 pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3160 pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3161 pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3162 pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3163 pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3164 pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3166 for(i=0; i<MAX_PIC16MNEMONICS; i++)
3167 if(pic16Mnemonics[i])
3168 hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3169 pci = hTabFirstItem(pic16MnemonicsHash, &key);
3172 DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3173 pci = hTabNextItem(pic16MnemonicsHash, &key);
3176 mnemonics_initialized = 1;
3179 int pic16_getpCodePeepCommand(char *cmd);
3181 int pic16_getpCode(char *mnem,unsigned dest)
3184 pCodeInstruction *pci;
3185 int key = mnem2key((unsigned char *)mnem);
3187 if(!mnemonics_initialized)
3188 pic16initMnemonics();
3190 pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3194 if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3195 if((pci->num_ops <= 1)
3196 || (pci->isModReg == dest)
3198 || (pci->num_ops <= 2 && pci->isAccess)
3199 || (pci->num_ops <= 2 && pci->isFastCall)
3200 || (pci->num_ops <= 2 && pci->is2MemOp)
3201 || (pci->num_ops <= 2 && pci->is2LitOp) )
3205 pci = hTabNextItemWK (pic16MnemonicsHash);
3212 /*-----------------------------------------------------------------*
3213 * pic16initpCodePeepCommands
3215 *-----------------------------------------------------------------*/
3216 void pic16initpCodePeepCommands(void)
3224 hTabAddItem(&pic16pCodePeepCommandsHash,
3225 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3227 } while (peepCommands[i].cmd);
3229 pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3232 //fprintf(stderr, "peep command %s key %d\n",pcmd->cmd,pcmd->id);
3233 pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3238 /*-----------------------------------------------------------------
3241 *-----------------------------------------------------------------*/
3243 int pic16_getpCodePeepCommand(char *cmd)
3247 int key = mnem2key((unsigned char *)cmd);
3250 pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3253 // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3254 if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3258 pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3265 static char getpBlock_dbName(pBlock *pb)
3271 return pb->cmemmap->dbName;
3275 void pic16_pBlockConvert2ISR(pBlock *pb)
3279 if(pb->cmemmap)pb->cmemmap = NULL;
3283 if(pic16_pcode_verbose)
3284 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3287 void pic16_pBlockConvert2Absolute(pBlock *pb)
3290 if(pb->cmemmap)pb->cmemmap = NULL;
3294 if(pic16_pcode_verbose)
3295 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3298 /*-----------------------------------------------------------------*/
3299 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all */
3300 /* instances to the front of the doubly linked */
3301 /* list of pBlocks */
3302 /*-----------------------------------------------------------------*/
3304 void pic16_movepBlock2Head(char dbName)
3309 /* this can happen in sources without code,
3310 * only variable definitions */
3311 if(!the_pFile)return;
3313 pb = the_pFile->pbHead;
3317 if(getpBlock_dbName(pb) == dbName) {
3318 pBlock *pbn = pb->next;
3319 pb->next = the_pFile->pbHead;
3320 the_pFile->pbHead->prev = pb;
3321 the_pFile->pbHead = pb;
3324 pb->prev->next = pbn;
3326 // If the pBlock that we just moved was the last
3327 // one in the link of all of the pBlocks, then we
3328 // need to point the tail to the block just before
3329 // the one we moved.
3330 // Note: if pb->next is NULL, then pb must have
3331 // been the last pBlock in the chain.
3334 pbn->prev = pb->prev;
3336 the_pFile->pbTail = pb->prev;
3347 void pic16_copypCode(FILE *of, char dbName)
3351 if(!of || !the_pFile)
3354 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3355 if(getpBlock_dbName(pb) == dbName) {
3356 // fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3358 pic16_printpBlock(of,pb);
3363 void pic16_pcode_test(void)
3366 DFPRINTF((stderr,"pcode is alive!\n"));
3376 /* create the file name */
3377 strcpy(buffer,dstFileName);
3378 strcat(buffer,".p");
3380 if( !(pFile = fopen(buffer, "w" ))) {
3381 werror(E_FILE_OPEN_ERR,buffer);
3385 fprintf(pFile,"pcode dump\n\n");
3387 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3388 fprintf(pFile,"\n\tNew pBlock\n\n");
3390 fprintf(pFile,"%s",pb->cmemmap->sname);
3392 fprintf(pFile,"internal pblock");
3394 fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3395 pic16_printpBlock(pFile,pb);
3401 unsigned long pic16_countInstructions(void)
3405 unsigned long isize=0;
3407 if(!the_pFile)return -1;
3409 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3410 for(pc = pb->pcHead; pc; pc = pc->next) {
3411 if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3418 /*-----------------------------------------------------------------*/
3419 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg- */
3420 /* ister, RegCond will return the bit being referenced. */
3422 /* fixme - why not just OR in the pcop bit field */
3423 /*-----------------------------------------------------------------*/
3425 static int RegCond(pCodeOp *pcop)
3431 if(!pcop->name)return 0;
3433 if(pcop->type == PO_GPR_BIT && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3434 switch(PCORB(pcop)->bit) {
3449 /*-----------------------------------------------------------------*/
3450 /* pic16_newpCode - create and return a newly initialized pCode */
3452 /* fixme - rename this */
3454 /* The purpose of this routine is to create a new Instruction */
3455 /* pCode. This is called by gen.c while the assembly code is being */
3459 /* PIC_OPCODE op - the assembly instruction we wish to create. */
3460 /* (note that the op is analogous to but not the */
3461 /* same thing as the opcode of the instruction.) */
3462 /* pCdoeOp *pcop - pointer to the operand of the instruction. */
3465 /* a pointer to the new malloc'd pCode is returned. */
3469 /*-----------------------------------------------------------------*/
3470 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3472 pCodeInstruction *pci ;
3474 if(!mnemonics_initialized)
3475 pic16initMnemonics();
3477 pci = Safe_calloc(1, sizeof(pCodeInstruction));
3479 if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3480 memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3483 if(pci->inCond & PCC_EXAMINE_PCOP)
3484 pci->inCond |= RegCond(pcop);
3486 if(pci->outCond & PCC_EXAMINE_PCOP)
3487 pci->outCond |= RegCond(pcop);
3489 pci->pc.prev = pci->pc.next = NULL;
3490 return (pCode *)pci;
3493 fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3499 /*-----------------------------------------------------------------*/
3500 /* pic16_newpCodeWild - create a "wild" as in wild card pCode */
3502 /* Wild pcodes are used during the peep hole optimizer to serve */
3503 /* as place holders for any instruction. When a snippet of code is */
3504 /* compared to a peep hole rule, the wild card opcode will match */
3505 /* any instruction. However, the optional operand and label are */
3506 /* additional qualifiers that must also be matched before the */
3507 /* line (of assembly code) is declared matched. Note that the */
3508 /* operand may be wild too. */
3510 /* Note, a wild instruction is specified just like a wild var: */
3511 /* %4 ; A wild instruction, */
3512 /* See the peeph.def file for additional examples */
3514 /*-----------------------------------------------------------------*/
3516 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3521 pcw = Safe_calloc(1,sizeof(pCodeWild));
3523 pcw->pci.pc.type = PC_WILD;
3524 pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3525 pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3526 pcw->pci.pc.pb = NULL;
3528 // pcw->pci.pc.analyze = genericAnalyze;
3529 pcw->pci.pc.destruct = genericDestruct;
3530 pcw->pci.pc.print = genericPrint;
3532 pcw->id = pCodeID; // this is the 'n' in %n
3533 pcw->operand = optional_operand;
3534 pcw->label = optional_label;
3536 pcw->mustBeBitSkipInst = 0;
3537 pcw->mustNotBeBitSkipInst = 0;
3538 pcw->invertBitSkipInst = 0;
3540 return ( (pCode *)pcw);
3544 /*-----------------------------------------------------------------*/
3545 /* newPcodeInlineP - create a new pCode from a char string */
3546 /*-----------------------------------------------------------------*/
3549 pCode *pic16_newpCodeInlineP(char *cP)
3554 pcc = Safe_calloc(1,sizeof(pCodeComment));
3556 pcc->pc.type = PC_INLINE;
3557 pcc->pc.prev = pcc->pc.next = NULL;
3558 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3561 // pcc->pc.analyze = genericAnalyze;
3562 pcc->pc.destruct = genericDestruct;
3563 pcc->pc.print = genericPrint;
3566 pcc->comment = Safe_strdup(cP);
3568 pcc->comment = NULL;
3570 return ( (pCode *)pcc);
3574 /*-----------------------------------------------------------------*/
3575 /* newPcodeCharP - create a new pCode from a char string */
3576 /*-----------------------------------------------------------------*/
3578 pCode *pic16_newpCodeCharP(char *cP)
3583 pcc = Safe_calloc(1,sizeof(pCodeComment));
3585 pcc->pc.type = PC_COMMENT;
3586 pcc->pc.prev = pcc->pc.next = NULL;
3587 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3590 // pcc->pc.analyze = genericAnalyze;
3591 pcc->pc.destruct = genericDestruct;
3592 pcc->pc.print = genericPrint;
3595 pcc->comment = Safe_strdup(cP);
3597 pcc->comment = NULL;
3599 return ( (pCode *)pcc);
3603 /*-----------------------------------------------------------------*/
3604 /* pic16_newpCodeFunction - */
3605 /*-----------------------------------------------------------------*/
3608 pCode *pic16_newpCodeFunction(char *mod,char *f)
3612 pcf = Safe_calloc(1,sizeof(pCodeFunction));
3614 pcf->pc.type = PC_FUNCTION;
3615 pcf->pc.prev = pcf->pc.next = NULL;
3616 //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3619 // pcf->pc.analyze = genericAnalyze;
3620 pcf->pc.destruct = genericDestruct;
3621 pcf->pc.print = pCodePrintFunction;
3627 pcf->modname = Safe_calloc(1,strlen(mod)+1);
3628 strcpy(pcf->modname,mod);
3630 pcf->modname = NULL;
3633 pcf->fname = Safe_calloc(1,strlen(f)+1);
3634 strcpy(pcf->fname,f);
3638 pcf->stackusage = 0;
3640 return ( (pCode *)pcf);
3643 /*-----------------------------------------------------------------*/
3644 /* pic16_newpCodeFlow */
3645 /*-----------------------------------------------------------------*/
3646 static void destructpCodeFlow(pCode *pc)
3648 if(!pc || !isPCFL(pc))
3655 pic16_unlinkpCode(pc);
3657 deleteSet(&PCFL(pc)->registers);
3658 deleteSet(&PCFL(pc)->from);
3659 deleteSet(&PCFL(pc)->to);
3661 /* Instead of deleting the memory used by this pCode, mark
3662 * the object as bad so that if there's a pointer to this pCode
3663 * dangling around somewhere then (hopefully) when the type is
3664 * checked we'll catch it.
3668 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3674 pCode *pic16_newpCodeFlow(void )
3678 //_ALLOC(pcflow,sizeof(pCodeFlow));
3679 pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3681 pcflow->pc.type = PC_FLOW;
3682 pcflow->pc.prev = pcflow->pc.next = NULL;
3683 pcflow->pc.pb = NULL;
3685 // pcflow->pc.analyze = genericAnalyze;
3686 pcflow->pc.destruct = destructpCodeFlow;
3687 pcflow->pc.print = genericPrint;
3689 pcflow->pc.seq = GpcFlowSeq++;
3691 pcflow->from = pcflow->to = NULL;
3693 pcflow->inCond = PCC_NONE;
3694 pcflow->outCond = PCC_NONE;
3696 pcflow->firstBank = -1;
3697 pcflow->lastBank = -1;
3699 pcflow->FromConflicts = 0;
3700 pcflow->ToConflicts = 0;
3704 pcflow->registers = newSet();
3706 return ( (pCode *)pcflow);
3710 /*-----------------------------------------------------------------*/
3711 /*-----------------------------------------------------------------*/
3712 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3714 pCodeFlowLink *pcflowLink;
3716 pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3718 pcflowLink->pcflow = pcflow;
3719 pcflowLink->bank_conflict = 0;
3724 /*-----------------------------------------------------------------*/
3725 /* pic16_newpCodeCSource - create a new pCode Source Symbol */
3726 /*-----------------------------------------------------------------*/
3728 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3733 pccs = Safe_calloc(1,sizeof(pCodeCSource));
3735 pccs->pc.type = PC_CSOURCE;
3736 pccs->pc.prev = pccs->pc.next = NULL;
3739 pccs->pc.destruct = genericDestruct;
3740 pccs->pc.print = genericPrint;
3742 pccs->line_number = ln;
3744 pccs->line = Safe_strdup(l);
3749 pccs->file_name = Safe_strdup(f);
3751 pccs->file_name = NULL;
3753 return ( (pCode *)pccs);
3758 /*******************************************************************/
3759 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive */
3760 /* added by VR 6-Jun-2003 */
3761 /*******************************************************************/
3763 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3770 pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3771 pcad->pci.pc.type = PC_ASMDIR;
3772 pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3773 pcad->pci.pc.pb = NULL;
3774 pcad->pci.isize = 2;
3775 pcad->pci.pc.destruct = genericDestruct;
3776 pcad->pci.pc.print = genericPrint;
3778 if(asdir && *asdir) {
3780 while(isspace((unsigned char)*asdir))asdir++; // strip any white space from the beginning
3782 pcad->directive = Safe_strdup( asdir );
3785 va_start(ap, argfmt);
3787 memset(buffer, 0, sizeof(buffer));
3788 if(argfmt && *argfmt)
3789 vsprintf(buffer, argfmt, ap);
3793 while(isspace((unsigned char)*lbp))lbp++;
3796 pcad->arg = Safe_strdup( lbp );
3798 return ((pCode *)pcad);
3801 /*-----------------------------------------------------------------*/
3802 /* pCodeLabelDestruct - free memory used by a label. */
3803 /*-----------------------------------------------------------------*/
3804 static void pCodeLabelDestruct(pCode *pc)
3810 // if((pc->type == PC_LABEL) && PCL(pc)->label)
3811 // Safe_free(PCL(pc)->label);
3813 /* Instead of deleting the memory used by this pCode, mark
3814 * the object as bad so that if there's a pointer to this pCode
3815 * dangling around somewhere then (hopefully) when the type is
3816 * checked we'll catch it.
3820 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3826 pCode *pic16_newpCodeLabel(char *name, int key)
3832 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3834 pcl->pc.type = PC_LABEL;
3835 pcl->pc.prev = pcl->pc.next = NULL;
3836 //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3839 // pcl->pc.analyze = genericAnalyze;
3840 pcl->pc.destruct = pCodeLabelDestruct;
3841 pcl->pc.print = pCodePrintLabel;
3848 sprintf(s,"_%05d_DS_",key);
3853 pcl->label = Safe_strdup(s);
3855 // if(pic16_pcode_verbose)
3856 // fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3859 return ( (pCode *)pcl);
3863 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3865 pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3869 return ( (pCode *)pcl );
3872 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3876 pci = Safe_calloc(1, sizeof(pCodeInfo));
3877 pci->pci.pc.type = PC_INFO;
3878 pci->pci.pc.prev = pci->pci.pc.next = NULL;
3879 pci->pci.pc.pb = NULL;
3880 pci->pci.label = NULL;
3882 pci->pci.pc.destruct = genericDestruct;
3883 pci->pci.pc.print = genericPrint;
3888 return ((pCode *)pci);
3892 /*-----------------------------------------------------------------*/
3893 /* newpBlock - create and return a pointer to a new pBlock */
3894 /*-----------------------------------------------------------------*/
3895 static pBlock *newpBlock(void)
3900 PpB = Safe_calloc(1,sizeof(pBlock) );
3901 PpB->next = PpB->prev = NULL;
3903 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3904 PpB->tregisters = NULL;
3906 PpB->FlowTree = NULL;
3912 /*-----------------------------------------------------------------*/
3913 /* pic16_newpCodeChain - create a new chain of pCodes */
3914 /*-----------------------------------------------------------------*
3916 * This function will create a new pBlock and the pointer to the
3917 * pCode that is passed in will be the first pCode in the block.
3918 *-----------------------------------------------------------------*/
3921 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3924 pBlock *pB = newpBlock();
3926 pB->pcHead = pB->pcTail = pc;
3935 /*-----------------------------------------------------------------*/
3936 /* pic16_newpCodeOpLabel - Create a new label given the key */
3937 /* Note, a negative key means that the label is part of wild card */
3938 /* (and hence a wild card label) used in the pCodePeep */
3939 /* optimizations). */
3940 /*-----------------------------------------------------------------*/
3942 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
3945 static int label_key=-1;
3949 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
3950 pcop->type = PO_LABEL;
3955 sprintf(s=buffer,"_%05d_DS_",key);
3957 s = name, key = label_key--;
3960 pcop->name = Safe_strdup(s);
3962 ((pCodeOpLabel *)pcop)->key = key;
3964 //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
3968 /*-----------------------------------------------------------------*/
3969 /*-----------------------------------------------------------------*/
3970 pCodeOp *pic16_newpCodeOpLit(int lit)
3976 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
3977 pcop->type = PO_LITERAL;
3981 sprintf(s,"0x%02hhx", (unsigned char)lit);
3983 // sprintf(s, "%i", lit);
3986 pcop->name = Safe_strdup(s);
3988 ((pCodeOpLit *)pcop)->lit = lit;
3993 /* Allow for 12 bit literals, required for LFSR */
3994 pCodeOp *pic16_newpCodeOpLit12(int lit)
4000 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4001 pcop->type = PO_LITERAL;
4005 sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4007 // sprintf(s, "%i", lit);
4010 pcop->name = Safe_strdup(s);
4012 ((pCodeOpLit *)pcop)->lit = lit;
4017 /*-----------------------------------------------------------------*/
4018 /*-----------------------------------------------------------------*/
4019 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4021 char *s = buffer, tbuf[256], *tb=tbuf;
4025 tb = pic16_get_op(arg2, NULL, 0);
4026 pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4027 pcop->type = PO_LITERAL;
4031 sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4033 pcop->name = Safe_strdup(s);
4036 ((pCodeOpLit2 *)pcop)->lit = lit;
4037 ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4042 /*-----------------------------------------------------------------*/
4043 /*-----------------------------------------------------------------*/
4044 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4048 pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4049 pcop->type = PO_IMMEDIATE;
4051 regs *r = pic16_dirregWithName(name);
4052 pcop->name = Safe_strdup(name);
4056 // fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4057 PCOI(pcop)->rIdx = r->rIdx;
4059 // fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4060 PCOI(pcop)->rIdx = -1;
4062 // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4065 PCOI(pcop)->rIdx = -1;
4068 PCOI(pcop)->index = index;
4069 PCOI(pcop)->offset = offset;
4070 PCOI(pcop)->_const = code_space;
4075 /*-----------------------------------------------------------------*/
4076 /*-----------------------------------------------------------------*/
4077 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4083 if(!pcwb || !subtype) {
4084 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4088 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4089 pcop->type = PO_WILD;
4090 sprintf(s,"%%%d",id);
4091 pcop->name = Safe_strdup(s);
4093 PCOW(pcop)->id = id;
4094 PCOW(pcop)->pcwb = pcwb;
4095 PCOW(pcop)->subtype = subtype;
4096 PCOW(pcop)->matched = NULL;
4098 PCOW(pcop)->pcop2 = NULL;
4103 /*-----------------------------------------------------------------*/
4104 /*-----------------------------------------------------------------*/
4105 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4111 if(!pcwb || !subtype || !subtype2) {
4112 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4116 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4117 pcop->type = PO_WILD;
4118 sprintf(s,"%%%d",id);
4119 pcop->name = Safe_strdup(s);
4121 PCOW(pcop)->id = id;
4122 PCOW(pcop)->pcwb = pcwb;
4123 PCOW(pcop)->subtype = subtype;
4124 PCOW(pcop)->matched = NULL;
4126 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4128 if(!subtype2->name) {
4129 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4130 PCOW2(pcop)->pcop.type = PO_WILD;
4131 sprintf(s, "%%%d", id2);
4132 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4133 PCOW2(pcop)->id = id2;
4134 PCOW2(pcop)->subtype = subtype2;
4136 // fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4137 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4139 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4141 // fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4142 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4151 /*-----------------------------------------------------------------*/
4152 /*-----------------------------------------------------------------*/
4153 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4157 pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4158 pcop->type = PO_GPR_BIT;
4160 pcop->name = Safe_strdup(s);
4164 PCORB(pcop)->bit = bit;
4165 PCORB(pcop)->inBitSpace = inBitSpace;
4166 PCORB(pcop)->subtype = subt;
4168 /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4169 PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4170 // fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4171 // PCOR(pcop)->rIdx = 0;
4175 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4177 return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4178 bit, 0, PO_GPR_REGISTER);
4182 /*-----------------------------------------------------------------*
4183 * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4185 * If rIdx >=0 then a specific register from the set of registers
4186 * will be selected. If rIdx <0, then a new register will be searched
4188 *-----------------------------------------------------------------*/
4190 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4195 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4200 r = pic16_regWithIdx(rIdx);
4202 r = pic16_allocWithIdx(rIdx);
4204 r = pic16_findFreeReg(REG_GPR);
4207 fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4208 __FUNCTION__, __LINE__);
4213 PCOR(pcop)->rIdx = rIdx;
4215 pcop->type = PCOR(pcop)->r->pc_type;
4220 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4225 pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4228 r = pic16_findFreeReg(REG_GPR);
4231 if(!bitVectBitValue(bv, r->rIdx)) {
4233 PCOR(pcop)->rIdx = r->rIdx;
4234 pcop->type = r->pc_type;
4238 r = pic16_findFreeRegNext(REG_GPR, r);
4246 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4251 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4252 PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4253 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4254 pcop->type = PCOR(pcop)->r->pc_type;
4255 pcop->name = PCOR(pcop)->r->name;
4257 // if(pic16_pcode_verbose) {
4258 // fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4259 // __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4265 /*-----------------------------------------------------------------*/
4266 /*-----------------------------------------------------------------*/
4267 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4271 pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4274 pcop->key = Safe_strdup( key );
4276 return (PCOP(pcop));
4279 /*-----------------------------------------------------------------*/
4280 /*-----------------------------------------------------------------*/
4281 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4283 pCodeOpLocalReg *pcop;
4285 pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4289 return (PCOP(pcop));
4293 /*-----------------------------------------------------------------*/
4294 /*-----------------------------------------------------------------*/
4296 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4303 pcop = pic16_newpCodeOpBit(name, -1,0, type);
4307 pcop = pic16_newpCodeOpLit(-1);
4311 pcop = pic16_newpCodeOpLabel(NULL,-1);
4314 pcop = pic16_newpCodeOpReg(-1);
4317 case PO_GPR_REGISTER:
4319 pcop = pic16_newpCodeOpRegFromStr(name);
4321 pcop = pic16_newpCodeOpReg(-1);
4325 assert( !"Cannot create PO_TWO_OPS from string!" );
4330 pcop = Safe_calloc(1,sizeof(pCodeOp) );
4333 pcop->name = Safe_strdup(name);
4341 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4343 pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4344 pcop2->pcop.type = PO_TWO_OPS;
4350 /* This is a multiple of two as gpasm pads DB directives to even length,
4351 * thus the data would be interleaved with \0 bytes...
4352 * This is a multiple of three in order to have arrays of 3-byte pointers
4353 * continuously in memory (without 0-padding at the lines' end).
4354 * This is rather 12 than 6 in order not to split up 4-byte data types
4355 * in arrays right in the middle of a 4-byte word. */
4356 #define DB_ITEMS_PER_LINE 12
4358 typedef struct DBdata
4365 static int DBd_init = -1;
4367 /*-----------------------------------------------------------------*/
4368 /* Initialiase "DB" data buffer */
4369 /*-----------------------------------------------------------------*/
4370 void pic16_initDB(void)
4376 /*-----------------------------------------------------------------*/
4377 /* Flush pending "DB" data to a pBlock */
4379 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4380 /*-----------------------------------------------------------------*/
4381 void pic16_flushDB(char ptype, void *p)
4385 pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4388 fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4391 fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4395 DBd.buffer[0] = '\0';
4400 /*-----------------------------------------------------------------*/
4401 /* Add "DB" directives to a pBlock */
4402 /*-----------------------------------------------------------------*/
4403 void pic16_emitDB(int c, char ptype, void *p)
4408 // we need to initialize
4411 DBd.buffer[0] = '\0';
4414 l = strlen(DBd.buffer);
4415 sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4417 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4420 if (DBd.count>= DB_ITEMS_PER_LINE)
4421 pic16_flushDB(ptype, p);
4424 void pic16_emitDS(char *s, char ptype, void *p)
4429 // we need to initialize
4432 DBd.buffer[0] = '\0';
4435 l = strlen(DBd.buffer);
4436 sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4438 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4440 DBd.count++; //=strlen(s);
4441 if (DBd.count>=DB_ITEMS_PER_LINE)
4442 pic16_flushDB(ptype, p);
4446 /*-----------------------------------------------------------------*/
4447 /*-----------------------------------------------------------------*/
4448 void pic16_pCodeConstString(char *name, char *value, unsigned length)
4452 static set *emittedSymbols = NULL;
4457 /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4458 if (emittedSymbols) {
4459 /* scan set for name */
4460 for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4462 if (!strcmp (item,name)) {
4463 //fprintf (stderr, "%s already emitted\n", name);
4468 addSet (&emittedSymbols, Safe_strdup (name));
4470 //fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value);
4472 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4474 pic16_addpBlock(pb);
4476 // sprintf(buffer,"; %s = ", name);
4477 // strcat(buffer, value);
4478 // fputs(buffer, stderr);
4480 // pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4481 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4484 pic16_emitDB(*value++, 'p', (void *)pb);
4486 pic16_flushDB('p', (void *)pb);
4489 /*-----------------------------------------------------------------*/
4490 /*-----------------------------------------------------------------*/
4492 static void pCodeReadCodeTable(void)
4496 fprintf(stderr, " %s\n",__FUNCTION__);
4498 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4500 pic16_addpBlock(pb);
4502 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4503 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4504 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4505 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4507 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4508 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4509 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4510 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4515 /*-----------------------------------------------------------------*/
4516 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */
4517 /*-----------------------------------------------------------------*/
4518 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4525 /* If this is the first pcode to be added to a block that
4526 * was initialized with a NULL pcode, then go ahead and
4527 * make this pcode the head and tail */
4528 pb->pcHead = pb->pcTail = pc;
4531 pb->pcTail->next = pc;
4533 pc->prev = pb->pcTail;
4540 /*-----------------------------------------------------------------*/
4541 /* pic16_addpBlock - place a pBlock into the pFile */
4542 /*-----------------------------------------------------------------*/
4543 void pic16_addpBlock(pBlock *pb)
4545 // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4548 /* First time called, we'll pass through here. */
4549 //_ALLOC(the_pFile,sizeof(pFile));
4550 the_pFile = Safe_calloc(1,sizeof(pFile));
4551 the_pFile->pbHead = the_pFile->pbTail = pb;
4552 the_pFile->functions = NULL;
4556 the_pFile->pbTail->next = pb;
4557 pb->prev = the_pFile->pbTail;
4559 the_pFile->pbTail = pb;
4562 /*-----------------------------------------------------------------*/
4563 /* removepBlock - remove a pBlock from the pFile */
4564 /*-----------------------------------------------------------------*/
4565 static void removepBlock(pBlock *pb)
4573 //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4575 for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4578 if(pbs == the_pFile->pbHead)
4579 the_pFile->pbHead = pbs->next;
4581 if (pbs == the_pFile->pbTail)
4582 the_pFile->pbTail = pbs->prev;
4585 pbs->next->prev = pbs->prev;
4588 pbs->prev->next = pbs->next;
4595 fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4599 /*-----------------------------------------------------------------*/
4600 /* printpCode - write the contents of a pCode to a file */
4601 /*-----------------------------------------------------------------*/
4602 static void printpCode(FILE *of, pCode *pc)
4613 fprintf(of,"warning - unable to print pCode\n");
4616 /*-----------------------------------------------------------------*/
4617 /* pic16_printpBlock - write the contents of a pBlock to a file */
4618 /*-----------------------------------------------------------------*/
4619 void pic16_printpBlock(FILE *of, pBlock *pb)
4627 for(pc = pb->pcHead; pc; pc = pc->next) {
4628 if(isPCF(pc) && PCF(pc)->fname) {
4629 fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4630 if(pb->dbName == 'A') {
4632 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4633 // fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4634 if(!strcmp(ab->name, PCF(pc)->fname)) {
4635 // fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4636 if(ab->address != -1)
4637 fprintf(of, "\t0X%06X", ab->address);
4648 /*-----------------------------------------------------------------*/
4650 /* pCode processing */
4654 /*-----------------------------------------------------------------*/
4655 pCode * pic16_findNextInstruction(pCode *pci);
4656 pCode * pic16_findPrevInstruction(pCode *pci);
4658 void pic16_unlinkpCode(pCode *pc)
4664 fprintf(stderr,"Unlinking: ");
4665 printpCode(stderr, pc);
4668 pc->prev->next = pc->next;
4670 pc->next->prev = pc->prev;
4672 /* move C source line down (or up) */
4673 if (isPCI(pc) && PCI(pc)->cline) {
4674 prev = pic16_findNextInstruction (pc->next);
4675 if (prev && isPCI(prev) && !PCI(prev)->cline) {
4676 PCI(prev)->cline = PCI(pc)->cline;
4678 prev = pic16_findPrevInstruction (pc->prev);
4679 if (prev && isPCI(prev) && !PCI(prev)->cline)
4680 PCI(prev)->cline = PCI(pc)->cline;
4683 pc->prev = pc->next = NULL;
4687 /*-----------------------------------------------------------------*/
4688 /*-----------------------------------------------------------------*/
4690 static void genericDestruct(pCode *pc)
4693 pic16_unlinkpCode(pc);
4696 /* For instructions, tell the register (if there's one used)
4697 * that it's no longer needed */
4698 regs *reg = pic16_getRegFromInstruction(pc);
4700 deleteSetItem (&(reg->reglives.usedpCodes),pc);
4702 if(PCI(pc)->is2MemOp) {
4703 reg = pic16_getRegFromInstruction2(pc);
4705 deleteSetItem(&(reg->reglives.usedpCodes), pc);
4709 /* Instead of deleting the memory used by this pCode, mark
4710 * the object as bad so that if there's a pointer to this pCode
4711 * dangling around somewhere then (hopefully) when the type is
4712 * checked we'll catch it.
4716 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4722 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4723 /*-----------------------------------------------------------------*/
4724 /*-----------------------------------------------------------------*/
4725 /* modifiers for constant immediate */
4726 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4728 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4733 int use_buffer = 1; // copy the string to the passed buffer pointer
4738 use_buffer = 0; // Don't bother copying the string to the buffer.
4743 switch(pcop->type) {
4751 SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
4754 return (PCOR(pcop)->r->name);
4757 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4759 SNPRINTF(buffer,size,"%s",r->name);
4767 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4768 if(PCOI(pcop)->index) {
4769 SNPRINTF(s,size, "%s(%s + %d)",
4770 immdmod[ PCOI(pcop)->offset ],
4774 SNPRINTF(s,size,"%s(%s)",
4775 immdmod[ PCOI(pcop)->offset ],
4779 if(PCOI(pcop)->index) {
4780 SNPRINTF(s,size, "%s(%s + %d)",
4785 SNPRINTF(s,size, "%s(%s)",
4793 case PO_GPR_REGISTER:
4796 //size = sizeof(buffer);
4797 if( PCOR(pcop)->instance) {
4798 SNPRINTF(s,size,"(%s + %d)",
4800 PCOR(pcop)->instance );
4802 SNPRINTF(s,size,"%s",pcop->name);
4809 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4810 SNPRINTF(s, size, "%s", pcop->name);
4812 if(PCORB(pcop)->pcor.instance)
4813 SNPRINTF(s, size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4815 SNPRINTF(s, size, "%s", pcop->name);
4821 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4827 SNPRINTF(buffer,size,"%s",pcop->name);
4830 return (pcop->name);
4834 return ("unhandled type for op1");
4837 return ("NO operand1");
4840 /*-----------------------------------------------------------------*/
4841 /* pic16_get_op2 - variant to support two memory operand commands */
4842 /*-----------------------------------------------------------------*/
4843 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4846 if(pcop && pcop->type == PO_TWO_OPS) {
4847 return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4850 return "NO operand2";
4853 /*-----------------------------------------------------------------*/
4854 /*-----------------------------------------------------------------*/
4855 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4859 return pic16_get_op(pcc->pcop,NULL,0);
4861 /* gcc 3.2: warning: concatenation of string literals with __FUNCTION__ is deprecated
4862 * return ("ERROR Null: "__FUNCTION__);
4864 return ("ERROR Null: pic16_get_op_from_instruction");
4868 /*-----------------------------------------------------------------*/
4869 /*-----------------------------------------------------------------*/
4870 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4873 fprintf(of,"pcodeopprint- not implemented\n");
4876 /*-----------------------------------------------------------------*/
4877 /* pic16_pCode2str - convert a pCode instruction to string */
4878 /*-----------------------------------------------------------------*/
4879 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4885 if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4886 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4887 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4888 // exit(EXIT_FAILURE);
4895 SNPRINTF(s, size, "\t%s\t", PCI(pc)->mnemonic);
4899 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4901 if (PCI(pc)->pcop->type == PO_TWO_OPS)
4903 /* split into two phases due to static buffer in pic16_get_op() */
4904 SNPRINTF(s, size, "%s",
4905 pic16_get_op((PCI(pc)->pcop), NULL, 0));
4908 SNPRINTF(s, size, ", %s",
4909 pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4913 if(PCI(pc)->is2LitOp) {
4914 SNPRINTF(s,size, "%s", PCOP(PCI(pc)->pcop)->name);
4918 if(PCI(pc)->isBitInst) {
4919 if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4920 if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4921 SNPRINTF(s,size,"(%s >> 3), (%s & 7)",
4922 PCI(pc)->pcop->name ,
4923 PCI(pc)->pcop->name );
4925 SNPRINTF(s,size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4926 (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4928 } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4929 SNPRINTF(s,size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
4931 SNPRINTF(s,size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
4934 if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4935 if( PCI(pc)->num_ops == 3)
4936 SNPRINTF(s,size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
4938 SNPRINTF(s,size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
4940 SNPRINTF(s,size,"%s", pic16_get_op_from_instruction(PCI(pc)));
4944 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
4947 if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst) {
4948 SNPRINTF(s,size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
4953 r = pic16_getRegFromInstruction(pc);
4955 if(PCI(pc)->isAccess) {
4956 static char *bank_spec[2][2] = {
4957 { "", ", ACCESS" }, /* gpasm uses access bank by default */
4958 { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
4961 SNPRINTF(s,size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
4968 /* assuming that comment ends with a \n */
4969 SNPRINTF(s,size,";%s", ((pCodeComment *)pc)->comment);
4973 SNPRINTF(s,size,"; info ==>");
4976 switch( PCINF(pc)->type ) {
4977 case INF_OPTIMIZATION:
4978 SNPRINTF(s,size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
4981 SNPRINTF(s,size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
4986 /* assuming that inline code ends with a \n */
4987 SNPRINTF(s,size,"%s", ((pCodeComment *)pc)->comment);
4991 SNPRINTF(s,size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
4994 SNPRINTF(s,size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
4997 SNPRINTF(s,size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5000 SNPRINTF(s,size,";\t--FLOW change\n");
5003 SNPRINTF(s,size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5004 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5007 if(PCAD(pc)->directive) {
5008 SNPRINTF(s,size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5011 /* special case to handle inline labels without a tab */
5012 SNPRINTF(s,size,"%s\n", PCAD(pc)->arg);
5017 SNPRINTF(s,size,";A bad pCode is being used\n");
5024 /*-----------------------------------------------------------------*/
5025 /* genericPrint - the contents of a pCode to a file */
5026 /*-----------------------------------------------------------------*/
5027 static void genericPrint(FILE *of, pCode *pc)
5035 // fputs(((pCodeComment *)pc)->comment, of);
5036 fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5041 pBranch *pbl = PCI(pc)->label;
5042 while(pbl && pbl->pc) {
5043 if(pbl->pc->type == PC_LABEL)
5044 pCodePrintLabel(of, pbl->pc);
5049 if(pic16_pcode_verbose) {
5050 fprintf(of, "; info ==>");
5051 switch(((pCodeInfo *)pc)->type) {
5052 case INF_OPTIMIZATION:
5053 fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5056 fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5064 fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5068 // If the opcode has a label, print that first
5070 pBranch *pbl = PCI(pc)->label;
5071 while(pbl && pbl->pc) {
5072 if(pbl->pc->type == PC_LABEL)
5073 pCodePrintLabel(of, pbl->pc);
5079 genericPrint(of,PCODE(PCI(pc)->cline));
5084 pic16_pCode2str(str, 256, pc);
5086 fprintf(of,"%s",str);
5088 if(pic16_debug_verbose) {
5089 fprintf(of, "\t;key=%03x",pc->seq);
5091 fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5098 fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5099 if(PCW(pc)->pci.label)
5100 pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5102 if(PCW(pc)->operand) {
5103 fprintf(of,";\toperand ");
5104 pCodeOpPrint(of,PCW(pc)->operand );
5109 if(pic16_debug_verbose) {
5110 fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5111 if(PCFL(pc)->ancestor)
5112 fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5119 // fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5120 fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5121 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5127 pBranch *pbl = PCAD(pc)->pci.label;
5128 while(pbl && pbl->pc) {
5129 if(pbl->pc->type == PC_LABEL)
5130 pCodePrintLabel(of, pbl->pc);
5134 if(PCAD(pc)->directive) {
5135 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5138 /* special case to handle inline labels without tab */
5139 fprintf(of, "%s\n", PCAD(pc)->arg);
5145 fprintf(of,"unknown pCode type %d\n",pc->type);
5150 /*-----------------------------------------------------------------*/
5151 /* pCodePrintFunction - prints function begin/end */
5152 /*-----------------------------------------------------------------*/
5154 static void pCodePrintFunction(FILE *of, pCode *pc)
5161 if( ((pCodeFunction *)pc)->modname)
5162 fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5165 if(!PCF(pc)->absblock) {
5166 if(PCF(pc)->fname) {
5167 pBranch *exits = PCF(pc)->to;
5170 fprintf(of,"%s:", PCF(pc)->fname);
5172 if(pic16_pcode_verbose)
5173 fprintf(of, "\t;Function start");
5179 exits = exits->next;
5183 if(pic16_pcode_verbose)
5184 fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5187 if((PCF(pc)->from &&
5188 PCF(pc)->from->pc->type == PC_FUNCTION &&
5189 PCF(PCF(pc)->from->pc)->fname) ) {
5191 if(pic16_pcode_verbose)
5192 fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5194 if(pic16_pcode_verbose)
5195 fprintf(of,"; exit point [can't find entry point]\n");
5201 /*-----------------------------------------------------------------*/
5202 /* pCodePrintLabel - prints label */
5203 /*-----------------------------------------------------------------*/
5205 static void pCodePrintLabel(FILE *of, pCode *pc)
5212 fprintf(of,"%s:\n",PCL(pc)->label);
5213 else if (PCL(pc)->key >=0)
5214 fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5216 fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5219 /*-----------------------------------------------------------------*/
5220 /* unlinkpCodeFromBranch - Search for a label in a pBranch and */
5221 /* remove it if it is found. */
5222 /*-----------------------------------------------------------------*/
5223 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5230 if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5231 b = PCI(pcl)->label;
5233 fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5238 //fprintf (stderr, "%s \n",__FUNCTION__);
5239 //pcl->print(stderr,pcl);
5240 //pc->print(stderr,pc);
5243 //fprintf (stderr, "found label\n");
5244 //pc->print(stderr, pc);
5248 bprev->next = b->next; /* Not first pCode in chain */
5252 PCI(pcl)->label = b->next; /* First pCode in chain */
5255 return; /* A label can't occur more than once */
5263 /*-----------------------------------------------------------------*/
5264 /*-----------------------------------------------------------------*/
5265 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5284 /*-----------------------------------------------------------------*/
5285 /* pBranchLink - given two pcodes, this function will link them */
5286 /* together through their pBranches */
5287 /*-----------------------------------------------------------------*/
5288 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5292 // Declare a new branch object for the 'from' pCode.
5294 //_ALLOC(b,sizeof(pBranch));
5295 b = Safe_calloc(1,sizeof(pBranch));
5296 b->pc = PCODE(t); // The link to the 'to' pCode.
5299 f->to = pic16_pBranchAppend(f->to,b);
5301 // Now do the same for the 'to' pCode.
5303 //_ALLOC(b,sizeof(pBranch));
5304 b = Safe_calloc(1,sizeof(pBranch));
5308 t->from = pic16_pBranchAppend(t->from,b);
5313 /*-----------------------------------------------------------------*/
5314 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5316 /*-----------------------------------------------------------------*/
5317 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5330 /*-----------------------------------------------------------------*/
5331 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain. */
5332 /*-----------------------------------------------------------------*/
5333 void pic16_pCodeUnlink(pCode *pc)
5338 if(!pc->prev || !pc->next) {
5339 fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5343 /* move C source line down (or up) */
5344 if (isPCI(pc) && PCI(pc)->cline) {
5345 pc1 = pic16_findNextInstruction (pc->next);
5346 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5347 PCI(pc1)->cline = PCI(pc)->cline;
5349 pc1 = pic16_findPrevInstruction (pc->prev);
5350 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5351 PCI(pc1)->cline = PCI(pc)->cline;
5355 /* first remove the pCode from the chain */
5356 pc->prev->next = pc->next;
5357 pc->next->prev = pc->prev;
5359 pc->prev = pc->next = NULL;
5361 /* Now for the hard part... */
5363 /* Remove the branches */
5365 pb1 = PCI(pc)->from;
5367 pc1 = pb1->pc; /* Get the pCode that branches to the
5368 * one we're unlinking */
5370 /* search for the link back to this pCode (the one we're
5372 if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5373 pb2->pc = PCI(pc)->to->pc; // make the replacement
5375 /* if the pCode we're unlinking contains multiple 'to'
5376 * branches (e.g. this a skip instruction) then we need
5377 * to copy these extra branches to the chain. */
5378 if(PCI(pc)->to->next)
5379 pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5388 /*-----------------------------------------------------------------*/
5389 /*-----------------------------------------------------------------*/
5391 static void genericAnalyze(pCode *pc)
5401 // Go through the pCodes that are in pCode chain and link
5402 // them together through the pBranches. Note, the pCodes
5403 // are linked together as a contiguous stream like the
5404 // assembly source code lines. The linking here mimics this
5405 // except that comments are not linked in.
5407 pCode *npc = pc->next;
5409 if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5410 pBranchLink(pc,npc);
5415 /* reached the end of the pcode chain without finding
5416 * an instruction we could link to. */
5420 fprintf(stderr,"analyze PC_FLOW\n");
5424 fprintf(stderr,,";A bad pCode is being used\n");
5430 /*-----------------------------------------------------------------*/
5431 /*-----------------------------------------------------------------*/
5432 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5436 if(pc->type == PC_LABEL) {
5437 if( ((pCodeLabel *)pc)->key == pcop_label->key)
5440 if((pc->type == PC_OPCODE)
5441 || (pc->type == PC_ASMDIR)
5443 pbr = PCI(pc)->label;
5445 if(pbr->pc->type == PC_LABEL) {
5446 if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
5456 /*-----------------------------------------------------------------*/
5457 /*-----------------------------------------------------------------*/
5458 static int checkLabel(pCode *pc)
5462 if(pc && isPCI(pc)) {
5463 pbr = PCI(pc)->label;
5465 if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5475 /*-----------------------------------------------------------------*/
5476 /* findLabelinpBlock - Search the pCode for a particular label */
5477 /*-----------------------------------------------------------------*/
5478 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5485 for(pc = pb->pcHead; pc; pc = pc->next)
5486 if(compareLabel(pc,pcop_label))
5492 /*-----------------------------------------------------------------*/
5493 /* findLabel - Search the pCode for a particular label */
5494 /*-----------------------------------------------------------------*/
5495 static pCode * findLabel(pCodeOpLabel *pcop_label)
5503 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5504 if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5508 fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5512 /*-----------------------------------------------------------------*/
5513 /* pic16_findNextpCode - given a pCode, find the next of type 'pct' */
5514 /* in the linked list */
5515 /*-----------------------------------------------------------------*/
5516 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5529 /*-----------------------------------------------------------------*/
5530 /* findPrevpCode - given a pCode, find the previous of type 'pct' */
5531 /* in the linked list */
5532 /*-----------------------------------------------------------------*/
5533 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5547 //#define PCODE_DEBUG
5548 /*-----------------------------------------------------------------*/
5549 /* pic16_findNextInstruction - given a pCode, find the next instruction */
5550 /* in the linked list */
5551 /*-----------------------------------------------------------------*/
5552 pCode * pic16_findNextInstruction(pCode *pci)
5557 if((pc->type == PC_OPCODE)
5558 || (pc->type == PC_WILD)
5559 || (pc->type == PC_ASMDIR)
5564 fprintf(stderr,"pic16_findNextInstruction: ");
5565 printpCode(stderr, pc);
5570 //fprintf(stderr,"Couldn't find instruction\n");
5574 /*-----------------------------------------------------------------*/
5575 /* pic16_findPrevInstruction - given a pCode, find the next instruction */
5576 /* in the linked list */
5577 /*-----------------------------------------------------------------*/
5578 pCode * pic16_findPrevInstruction(pCode *pci)
5584 if((pc->type == PC_OPCODE)
5585 || (pc->type == PC_WILD)
5586 || (pc->type == PC_ASMDIR)
5592 fprintf(stderr,"pic16_findPrevInstruction: ");
5593 printpCode(stderr, pc);
5598 //fprintf(stderr,"Couldn't find instruction\n");
5605 /*-----------------------------------------------------------------*/
5606 /* findFunctionEnd - given a pCode find the end of the function */
5607 /* that contains it */
5608 /*-----------------------------------------------------------------*/
5609 static pCode * findFunctionEnd(pCode *pc)
5613 if(pc->type == PC_FUNCTION && !(PCF(pc)->fname))
5619 fprintf(stderr,"Couldn't find function end\n");
5624 /*-----------------------------------------------------------------*/
5625 /* AnalyzeLabel - if the pCode is a label, then merge it with the */
5626 /* instruction with which it is associated. */
5627 /*-----------------------------------------------------------------*/
5628 static void AnalyzeLabel(pCode *pc)
5631 pic16_pCodeUnlink(pc);
5637 static void AnalyzeGOTO(pCode *pc)
5640 pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5644 static void AnalyzeSKIP(pCode *pc)
5647 pBranchLink(pc,pic16_findNextInstruction(pc->next));
5648 pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5652 static void AnalyzeRETURN(pCode *pc)
5655 // branch_link(pc,findFunctionEnd(pc->next));
5661 /*-------------------------------------------------------------------*/
5662 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp */
5663 /* if one is present. This is the common */
5664 /* part of pic16_getRegFromInstruction(2) */
5665 /*-------------------------------------------------------------------*/
5667 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5668 if (!pcop) return NULL;
5670 switch(pcop->type) {
5683 return PCOR(pcop)->r;
5685 case PO_SFR_REGISTER:
5686 //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5687 return PCOR(pcop)->r;
5691 // fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5692 return PCOR(pcop)->r;
5695 // return pic16_dirregWithName(PCOI(pcop)->r->name);
5698 return (PCOI(pcop)->r);
5703 return PCOR(pcop)->r;
5705 case PO_GPR_REGISTER:
5707 // fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5708 return PCOR(pcop)->r;
5711 //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5716 //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5721 /* this should never turn up */
5722 //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5729 return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5733 fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5741 /*-----------------------------------------------------------------*/
5742 /*-----------------------------------------------------------------*/
5743 regs * pic16_getRegFromInstruction(pCode *pc)
5748 PCI(pc)->num_ops == 0 ||
5749 (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5753 fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5754 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5757 return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5760 /*-------------------------------------------------------------------------------*/
5761 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5762 /*-------------------------------------------------------------------------------*/
5763 regs * pic16_getRegFromInstruction2(pCode *pc)
5769 PCI(pc)->num_ops == 0 ||
5770 (PCI(pc)->num_ops == 1)) // accept only 2 operand commands
5773 if (PCI(pc)->pcop->type != PO_TWO_OPS)
5777 fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5778 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5781 return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5784 /*-----------------------------------------------------------------*/
5785 /*-----------------------------------------------------------------*/
5787 static void AnalyzepBlock(pBlock *pb)
5794 /* Find all of the registers used in this pBlock
5795 * by looking at each instruction and examining it's
5798 for(pc = pb->pcHead; pc; pc = pc->next) {
5800 /* Is this an instruction with operands? */
5801 if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5803 if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5805 /* Loop through all of the registers declared so far in
5806 this block and see if we find this one there */
5808 regs *r = setFirstItem(pb->tregisters);
5811 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5812 PCOR(PCI(pc)->pcop)->r = r;
5815 r = setNextItem(pb->tregisters);
5819 /* register wasn't found */
5820 //r = Safe_calloc(1, sizeof(regs));
5821 //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5822 //addSet(&pb->tregisters, r);
5823 addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5824 //PCOR(PCI(pc)->pcop)->r = r;
5825 //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5827 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5830 if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5831 if(PCOR(PCI(pc)->pcop)->r) {
5832 pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx); /* FIXME! - VR */
5833 DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5835 if(PCI(pc)->pcop->name)
5836 fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5838 fprintf(stderr,"ERROR: NULL register\n");
5847 /*-----------------------------------------------------------------*/
5849 /*-----------------------------------------------------------------*/
5850 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5852 static void InsertpFlow(pCode *pc, pCode **pflow)
5855 PCFL(*pflow)->end = pc;
5857 if(!pc || !pc->next)
5860 *pflow = pic16_newpCodeFlow();
5861 pic16_pCodeInsertAfter(pc, *pflow);
5864 /*-----------------------------------------------------------------*/
5865 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5866 /* the flow blocks. */
5868 * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5869 * point the instruction flow changes.
5871 /*-----------------------------------------------------------------*/
5872 void pic16_BuildFlow(pBlock *pb)
5875 pCode *last_pci=NULL;
5882 //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq);
5883 /* Insert a pCodeFlow object at the beginning of a pBlock */
5885 InsertpFlow(pb->pcHead, &pflow);
5887 //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */
5888 //pflow->next = pb->pcHead; /* Make the current head the next object */
5889 //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */
5890 //pb->pcHead = pflow; /* Make the Flow object the head */
5893 for( pc = pic16_findNextInstruction(pb->pcHead);
5895 pc=pic16_findNextInstruction(pc)) {
5898 PCI(pc)->pcflow = PCFL(pflow);
5900 //fprintf(stderr," build: ");
5901 //pflow->print(stderr,pflow);
5903 if (checkLabel(pc)) {
5905 /* This instruction marks the beginning of a
5906 * new flow segment */
5911 /* If the previous pCode is not a flow object, then
5912 * insert a new flow object. (This check prevents
5913 * two consecutive flow objects from being insert in
5914 * the case where a skip instruction preceeds an
5915 * instruction containing a label.) */
5917 if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5918 InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5920 PCI(pc)->pcflow = PCFL(pflow);
5924 if( PCI(pc)->isSkip) {
5926 /* The two instructions immediately following this one
5927 * mark the beginning of a new flow segment */
5929 while(pc && PCI(pc)->isSkip) {
5931 PCI(pc)->pcflow = PCFL(pflow);
5935 InsertpFlow(pc, &pflow);
5936 pc=pic16_findNextInstruction(pc->next);
5944 PCI(pc)->pcflow = PCFL(pflow);
5946 InsertpFlow(pc, &pflow);
5948 } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) {
5950 InsertpFlow(pc, &pflow);
5958 //fprintf (stderr,",end seq %d",GpcFlowSeq);
5960 PCFL(pflow)->end = pb->pcTail;
5963 /*-------------------------------------------------------------------*/
5964 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5965 /* the flow blocks. */
5967 * unBuildFlow removes pCodeFlow objects from a pCode chain
5969 /*-----------------------------------------------------------------*/
5970 static void unBuildFlow(pBlock *pb)
5985 if(PCI(pc)->pcflow) {
5986 //Safe_free(PCI(pc)->pcflow);
5987 PCI(pc)->pcflow = NULL;
5990 } else if(isPCFL(pc) )
5999 /*-----------------------------------------------------------------*/
6000 /*-----------------------------------------------------------------*/
6001 static void dumpCond(int cond)
6004 static char *pcc_str[] = {
6018 int ncond = sizeof(pcc_str) / sizeof(char *);
6021 fprintf(stderr, "0x%04X\n",cond);
6023 for(i=0,j=1; i<ncond; i++, j<<=1)
6025 fprintf(stderr, " %s\n",pcc_str[i]);
6031 /*-----------------------------------------------------------------*/
6032 /*-----------------------------------------------------------------*/
6033 static void FlowStats(pCodeFlow *pcflow)
6041 fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6043 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6046 fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6051 fprintf(stderr, " FlowStats inCond: ");
6052 dumpCond(pcflow->inCond);
6053 fprintf(stderr, " FlowStats outCond: ");
6054 dumpCond(pcflow->outCond);
6058 /*-----------------------------------------------------------------*
6059 * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6060 * if it affects the banking bits.
6062 * return: -1 == Banking bits are unaffected by this pCode.
6064 * return: > 0 == Banking bits are affected.
6066 * If the banking bits are affected, then the returned value describes
6067 * which bits are affected and how they're affected. The lower half
6068 * of the integer maps to the bits that are affected, the upper half
6069 * to whether they're set or cleared.
6071 *-----------------------------------------------------------------*/
6073 static int isBankInstruction(pCode *pc)
6081 if( PCI(pc)->op == POC_MOVLB ||
6082 (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6083 bank = PCOL(pc)->lit;
6090 /*-----------------------------------------------------------------*/
6091 /*-----------------------------------------------------------------*/
6092 static void FillFlow(pCodeFlow *pcflow)
6101 // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6103 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6106 //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6113 isBankInstruction(pc);
6115 } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6119 fprintf(stderr, " FillFlow - Bad end of flow\n");
6121 fprintf(stderr, " FillFlow - Ending flow with\n ");
6122 pc->print(stderr,pc);
6125 fprintf(stderr, " FillFlow inCond: ");
6126 dumpCond(pcflow->inCond);
6127 fprintf(stderr, " FillFlow outCond: ");
6128 dumpCond(pcflow->outCond);
6132 /*-----------------------------------------------------------------*/
6133 /*-----------------------------------------------------------------*/
6134 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6136 pCodeFlowLink *fromLink, *toLink;
6138 if(!from || !to || !to->pcflow || !from->pcflow)
6141 fromLink = pic16_newpCodeFlowLink(from->pcflow);
6142 toLink = pic16_newpCodeFlowLink(to->pcflow);
6144 addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
6145 addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6149 pCode *pic16_getJumptabpCode (pCode *pc) {
6152 //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6153 //pc->print (stderr, pc);
6156 if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6157 if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6158 switch (PCOO(PCINF(pcinf)->oper1)->type) {
6159 case OPT_JUMPTABLE_BEGIN:
6160 /* leading begin of jump table -- in one */
6161 pcinf = pic16_findPrevInstruction (pcinf);
6165 case OPT_JUMPTABLE_END:
6166 /* leading end of jumptable -- not in one */
6171 /* ignore all other PCInfos */
6175 pcinf = pcinf->prev;
6178 /* no PCInfo found -- not in a jumptable */
6182 /*-----------------------------------------------------------------*
6183 * void LinkFlow(pBlock *pb)
6185 * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6186 * non-branching segments. In LinkFlow, we determine the execution
6187 * order of these segments. For example, if one of the segments ends
6188 * with a skip, then we know that there are two possible flow segments
6189 * to which control may be passed.
6190 *-----------------------------------------------------------------*/
6191 static void LinkFlow(pBlock *pb)
6196 pCode *jumptab_pre = NULL;
6198 //fprintf(stderr,"linkflow \n");
6200 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6202 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6205 fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6207 //fprintf(stderr," link: ");
6208 //pcflow->print(stderr,pcflow);
6210 //FillFlow(PCFL(pcflow));
6212 pc = PCFL(pcflow)->end;
6214 //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6215 if(isPCI_SKIP(pc)) {
6216 // fprintf(stderr, "ends with skip\n");
6217 // pc->print(stderr,pc);
6219 pct=pic16_findNextInstruction(pc->next);
6220 LinkFlow_pCode(PCI(pc),PCI(pct));
6221 pct=pic16_findNextInstruction(pct->next);
6222 LinkFlow_pCode(PCI(pc),PCI(pct));
6226 if(isPCI_BRANCH(pc)) {
6227 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6229 /* handle GOTOs in jumptables */
6230 if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6231 /* link to previous flow */
6232 //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6233 LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6236 switch (PCI(pc)->op) {
6242 /* unconditional branches -- do not link to next instruction */
6243 //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6248 /* unconditional calls -- link to next instruction */
6249 //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6250 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6261 /* conditional branches -- also link to next instruction */
6262 //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6263 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6267 fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6268 assert (0 && "unhandled branching instruction");
6272 //fprintf(stderr, "ends with branch\n ");
6273 //pc->print(stderr,pc);
6275 if(!(pcol && isPCOLAB(pcol))) {
6276 if((PCI(pc)->op != POC_RETLW)
6277 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6279 /* continue if label is '$' which assembler knows how to parse */
6280 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6282 if(pic16_pcode_verbose) {
6283 pc->print(stderr,pc);
6284 fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6290 if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6291 LinkFlow_pCode(PCI(pc),PCI(pct));
6293 fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6294 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6296 // fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6302 //fprintf(stderr, "ends with non-branching instruction:\n");
6303 //pc->print(stderr,pc);
6305 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6311 //fprintf(stderr, "ends with unknown\n");
6312 //pc->print(stderr,pc);
6316 //fprintf(stderr, "ends with nothing: ERROR\n");
6320 /*-----------------------------------------------------------------*/
6321 /*-----------------------------------------------------------------*/
6323 /*-----------------------------------------------------------------*/
6324 /*-----------------------------------------------------------------*/
6325 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6331 if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6334 if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6344 /*-----------------------------------------------------------------*/
6345 /* insertBankSwitch - inserts a bank switch statement in the */
6346 /* assembly listing */
6348 /* position == 0: insert before */
6349 /* position == 1: insert after pc */
6350 /* position == 2: like 0 but previous was a skip instruction */
6351 /*-----------------------------------------------------------------*/
6352 pCodeOp *pic16_popGetLabel(unsigned int key);
6353 extern int pic16_labelOffset;
6355 static void insertBankSwitch(unsigned char position, pCode *pc)
6362 /* emit BANKSEL [symbol] */
6365 new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6367 // position = 0; // position is always before (sanity check!)
6370 fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6371 pc->print(stderr, pc);
6376 /* insert the bank switch after this pc instruction */
6377 pCode *pcnext = pic16_findNextInstruction(pc);
6379 pic16_pCodeInsertAfter(pc, new_pc);
6380 if(pcnext)pc = pcnext;
6384 /* insert the bank switch BEFORE this pc instruction */
6385 pic16_pCodeInsertAfter(pc->prev, new_pc);
6390 pCode *pcnext, *pcprev, *npci, *ppc;
6392 int ofs1=0, ofs2=0, len=0;
6394 /* just like 0, but previous was a skip instruction,
6395 * so some care should be taken */
6397 pic16_labelOffset += 10000;
6398 tlbl = newiTempLabel(NULL);
6400 /* invert skip instruction */
6401 pcprev = pic16_findPrevInstruction(pc->prev);
6402 ipci = PCI(pcprev)->inverted_op;
6403 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6405 // fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6407 /* copy info from old pCode */
6408 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6409 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6410 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6411 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6412 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6413 PCI(npci)->op = PCI(pcprev)->inverted_op;
6415 /* unlink old pCode */
6417 ppc->next = pcprev->next;
6418 pcprev->next->prev = ppc;
6419 pic16_pCodeInsertAfter(ppc, npci);
6421 /* extra instructions to handle invertion */
6422 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6423 pic16_pCodeInsertAfter(npci, pcnext);
6424 pic16_pCodeInsertAfter(pc->prev, new_pc);
6426 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6427 pic16_pCodeInsertAfter(pc, pcnext);
6432 /* Move the label, if there is one */
6433 if(PCI(pc)->label) {
6434 // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6435 // __FILE__, __LINE__, pc, new_pc);
6436 PCAD(new_pc)->pci.label = PCI(pc)->label;
6437 PCI(pc)->label = NULL;
6442 /*-----------------------------------------------------------------*/
6443 /*int compareBankFlow - compare the banking requirements between */
6445 /*-----------------------------------------------------------------*/
6446 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6449 if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6452 if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6455 if(pcflow->firstBank == -1)
6459 if(pcflowLink->pcflow->firstBank == -1) {
6460 pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6461 pcflowLink->pcflow->to :
6462 pcflowLink->pcflow->from);
6463 return compareBankFlow(pcflow, pctl, toORfrom);
6467 if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6470 pcflowLink->bank_conflict++;
6471 pcflowLink->pcflow->FromConflicts++;
6472 pcflow->ToConflicts++;
6475 if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6478 pcflowLink->bank_conflict++;
6479 pcflowLink->pcflow->ToConflicts++;
6480 pcflow->FromConflicts++;
6484 fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6485 pcflowLink->pcflow->pc.seq,
6486 pcflowLink->pcflow->FromConflicts,
6487 pcflowLink->pcflow->ToConflicts);
6494 /*-----------------------------------------------------------------*/
6495 /*-----------------------------------------------------------------*/
6496 static void DumpFlow(pBlock *pb)
6500 pCodeFlowLink *pcfl;
6503 fprintf(stderr,"Dump flow \n");
6504 pb->pcHead->print(stderr, pb->pcHead);
6506 pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6507 pcflow->print(stderr,pcflow);
6509 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6511 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6513 if(!isPCFL(pcflow)) {
6514 fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6517 fprintf(stderr,"dumping: ");
6518 pcflow->print(stderr,pcflow);
6519 FlowStats(PCFL(pcflow));
6521 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6523 pc = PCODE(pcfl->pcflow);
6525 fprintf(stderr, " from seq %d:\n",pc->seq);
6527 fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6528 pc->print(stderr,pc);
6533 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6535 pc = PCODE(pcfl->pcflow);
6537 fprintf(stderr, " to seq %d:\n",pc->seq);
6539 fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6540 pc->print(stderr,pc);
6549 /*-----------------------------------------------------------------*/
6550 /*-----------------------------------------------------------------*/
6551 static int OptimizepBlock(pBlock *pb)
6556 if(!pb || !peepOptimizing)
6559 DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6561 for(pc = pb->pcHead; pc; pc = pc->next)
6562 matches += pic16_pCodePeepMatchRule(pc);
6565 pc = pic16_findNextInstruction(pb->pcHead);
6573 if(pic16_pCodePeepMatchRule(pc)) {
6578 pc = pic16_findNextInstruction(pcprev->next);
6580 pc = pic16_findNextInstruction(pb->pcHead);
6582 pc = pic16_findNextInstruction(pc->next);
6586 DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6591 /*-----------------------------------------------------------------*/
6592 /*-----------------------------------------------------------------*/
6593 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6597 for(pc = pcs; pc; pc = pc->next) {
6599 if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6601 (PCI(pc)->pcop->type == PO_LABEL) &&
6602 (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6610 /*-----------------------------------------------------------------*/
6611 /*-----------------------------------------------------------------*/
6612 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6619 (PCI(pc)->pcop->type == PO_LABEL)) {
6621 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6623 // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6624 // if(pcol->pcop.name)
6625 // Safe_free(pcol->pcop.name);
6627 /* If the key is negative, then we (probably) have a label to
6628 * a function and the name is already defined */
6631 sprintf(s=buffer,"_%05d_DS_",pcl->key);
6635 //sprintf(buffer,"_%05d_DS_",pcl->key);
6637 fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6639 pcol->pcop.name = Safe_strdup(s);
6640 pcol->key = pcl->key;
6641 //pc->print(stderr,pc);
6648 /*-----------------------------------------------------------------*/
6649 /* pBlockRemoveUnusedLabels - remove the pCode labels from the */
6650 /* pCode chain if they're not used. */
6651 /*-----------------------------------------------------------------*/
6652 static void pBlockRemoveUnusedLabels(pBlock *pb)
6654 pCode *pc; pCodeLabel *pcl;
6656 if(!pb || !pb->pcHead)
6659 for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6661 pBranch *pbr = PCI(pc)->label;
6662 if(pbr && pbr->next) {
6663 pCode *pcd = pb->pcHead;
6665 // fprintf(stderr, "multiple labels\n");
6666 // pc->print(stderr,pc);
6671 while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6672 //fprintf(stderr,"Used by:\n");
6673 //pcd->print(stderr,pcd);
6675 exchangeLabels(PCL(pbr->pc),pcd);
6684 for(pc = pb->pcHead; pc; pc = pc->next) {
6686 if(isPCL(pc)) // pc->type == PC_LABEL)
6688 else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6689 pcl = PCL(PCI(pc)->label->pc);
6692 // fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6694 /* This pCode is a label, so search the pBlock to see if anyone
6697 if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6699 //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6700 /* Couldn't find an instruction that refers to this label
6701 * So, unlink the pCode label from it's pCode chain
6702 * and destroy the label */
6703 // fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6705 DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6706 if(pc->type == PC_LABEL) {
6707 pic16_unlinkpCode(pc);
6708 pCodeLabelDestruct(pc);
6710 unlinkpCodeFromBranch(pc, PCODE(pcl));
6711 /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6712 Safe_free(pc->label);
6722 /*-----------------------------------------------------------------*/
6723 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */
6724 /* chain and put them into pBranches that are */
6725 /* associated with the appropriate pCode */
6727 /*-----------------------------------------------------------------*/
6728 void pic16_pBlockMergeLabels(pBlock *pb)
6731 pCode *pc, *pcnext=NULL;
6736 /* First, Try to remove any unused labels */
6737 //pBlockRemoveUnusedLabels(pb);
6739 /* Now loop through the pBlock and merge the labels with the opcodes */
6742 // for(pc = pb->pcHead; pc; pc = pc->next) {
6745 pCode *pcn = pc->next;
6747 if(pc->type == PC_LABEL) {
6749 // fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6750 // fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6752 if((pcnext = pic16_findNextInstruction(pc) )) {
6754 // pcnext->print(stderr, pcnext);
6756 // Unlink the pCode label from it's pCode chain
6757 pic16_unlinkpCode(pc);
6759 // fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6760 // And link it into the instruction's pBranch labels. (Note, since
6761 // it's possible to have multiple labels associated with one instruction
6762 // we must provide a means to accomodate the additional labels. Thus
6763 // the labels are placed into the singly-linked list "label" as
6764 // opposed to being a single member of the pCodeInstruction.)
6766 //_ALLOC(pbr,sizeof(pBranch));
6768 pbr = Safe_calloc(1,sizeof(pBranch));
6772 PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6775 if(pic16_pcode_verbose)
6776 fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6778 } else if(pc->type == PC_CSOURCE) {
6780 /* merge the source line symbolic info into the next instruction */
6781 if((pcnext = pic16_findNextInstruction(pc) )) {
6783 // Unlink the pCode label from it's pCode chain
6784 pic16_unlinkpCode(pc);
6785 PCI(pcnext)->cline = PCCS(pc);
6786 //fprintf(stderr, "merging CSRC\n");
6787 //genericPrint(stderr,pcnext);
6793 pBlockRemoveUnusedLabels(pb);
6797 /*-----------------------------------------------------------------*/
6798 /*-----------------------------------------------------------------*/
6799 static int OptimizepCode(char dbName)
6801 #define MAX_PASSES 4
6810 DFPRINTF((stderr," Optimizing pCode\n"));
6814 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6815 if('*' == dbName || getpBlock_dbName(pb) == dbName)
6816 matches += OptimizepBlock(pb);
6819 while(matches && ++passes < MAX_PASSES);
6826 const char *pic16_pCodeOpType(pCodeOp *pcop);
6827 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6830 /*-----------------------------------------------------------------*/
6831 /* pic16_popCopyGPR2Bit - copy a pcode operator */
6832 /*-----------------------------------------------------------------*/
6834 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6838 // fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6841 pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6843 if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6846 assert(pcop != NULL);
6848 if( !( (pcop->type == PO_LABEL) ||
6849 (pcop->type == PO_LITERAL) ||
6850 (pcop->type == PO_STR) ))
6851 PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */
6852 PCOR(pcop)->r->wasUsed = 1;
6853 PCOR(pcop)->instance = PCOR(pc)->instance;
6859 /*----------------------------------------------------------------------*
6860 * pic16_areRegsSame - check to see if the names of two registers match *
6861 *----------------------------------------------------------------------*/
6862 int pic16_areRegsSame(regs *r1, regs *r2)
6864 if(!strcmp(r1->name, r2->name))return 1;
6870 /*-----------------------------------------------------------------*/
6871 /*-----------------------------------------------------------------*/
6872 static void pic16_FixRegisterBanking(pBlock *pb)
6876 regs *reg, *prevreg;
6877 unsigned char flag=0;
6882 pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6885 /* loop through all of the flow blocks with in one pblock */
6887 // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6891 /* at this point, pc should point to a PC_FLOW object */
6892 /* for each flow block, determine the register banking
6896 /* if label, then might come from other point, force banksel */
6897 if(isPCL(pc))prevreg = NULL;
6899 if(!isPCI(pc))goto loop;
6901 if(PCI(pc)->label)prevreg = NULL;
6903 if(PCI(pc)->is2MemOp)goto loop;
6905 /* if goto, then force banksel */
6906 // if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6908 reg = pic16_getRegFromInstruction(pc);
6911 pc->print(stderr, pc);
6912 fprintf(stderr, "reg = %p\n", reg);
6915 fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6916 fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6917 reg->address,reg->isBitField, reg->isFixed);
6921 /* now make some tests to make sure that instruction needs bank switch */
6923 /* if no register exists, and if not a bit opcode goto loop */
6925 if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6928 if(isPCI_SKIP(pc)) {
6929 // fprintf(stderr, "instruction is SKIP instruction\n");
6932 if(reg && isACCESS_BANK(reg))goto loop;
6934 if(!isBankInstruction(pc))goto loop;
6936 if(isPCI_LIT(pc))goto loop;
6938 if(PCI(pc)->op == POC_CALL)goto loop;
6940 /* Examine the instruction before this one to make sure it is
6941 * not a skip type instruction */
6942 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
6944 flag = 0; /* add before this instruction */
6946 /* if previous instruction is a skip one, then set flag
6947 * to 2 and call insertBankSwitch */
6948 if(pcprev && isPCI_SKIP(pcprev)) {
6953 if(pic16_options.opt_banksel>0) {
6954 char op1[128], op2[128];
6957 strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
6958 strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
6959 if(!strcmp(op1, op2))goto loop;
6963 insertBankSwitch(flag, pc);
6965 // fprintf(stderr, "BANK SWITCH inserted\n");
6973 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
6975 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
6976 int instrSize (pCode *pc)
6981 if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
6982 return 4; // assumes only regular instructions using <= 4 bytes
6985 if (isPCI(pc)) return PCI(pc)->isize;
6990 /* Returns 1 if pc is referenced by the given label (either
6991 * pc is the label itself or is an instruction with an attached
6993 * Returns 0 if pc is not preceeded by the specified label.
6995 int isLabel (pCode *pc, char *label)
6999 // label attached to the pCode?
7000 if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7001 pBranch *lab = NULL;
7002 lab = PCI(pc)->label;
7005 if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7012 // is inline assembly label?
7013 if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7014 // do not compare trailing ':'
7015 if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7022 if (strcmp(PCL(pc)->label,label) == 0) {
7027 // no label/no label attached/wrong label(s)
7031 /* Returns the distance to the given label in terms of words.
7032 * Labels are searched only within -max .. max words from pc.
7033 * Returns max if the label could not be found or
7034 * its distance from pc in (-max..+max).
7036 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7037 int dist = instrSize(pc);
7041 while (dist < max && curr && !isLabel (curr, label)) {
7043 dist += instrSize(curr); // sizeof (instruction)
7045 if (curr && dist < max) {
7046 if (target != NULL) *target = curr;
7051 curr = pic16_findNextInstruction (pc->next);
7053 while (dist < max && curr && !isLabel (curr, label)) {
7054 dist += instrSize(curr); // sizeof (instruction)
7057 if (curr && dist < max) {
7058 if (target != NULL) *target = curr;
7062 if (target != NULL) *target = NULL;
7066 /* Returns -1 if pc does NOT denote an instruction like
7068 * Otherwise we return
7069 * (a) 0x10 + i for BTFSS
7070 * (b) 0x00 + i for BTFSC
7072 int isSkipOnStatus (pCode *pc)
7076 if (!pc || !isPCI(pc)) return -1;
7077 if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7078 else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7081 pcop = PCI(pc)->pcop;
7083 if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7084 return res + ((pCodeOpRegBit *)pcop)->bit;
7090 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7091 * returns 0 otherwise. */
7092 int isConditionalBranch (pCode *pc)
7094 if (!pc || !isPCI_BRANCH(pc)) return 0;
7096 switch (PCI(pc)->op) {
7114 /* Returns 1 if pc has a label attached to it.
7115 * This can be either a label stored in the pCode itself (.label)
7116 * or a label making up its own pCode preceding this pc.
7117 * Returns 0 if pc cannot be reached directly via a label.
7119 int hasNoLabel (pCode *pc)
7124 // are there any label pCodes between pc and the previous instruction?
7125 prev = pic16_findPrevInstruction (pc->prev);
7126 while (pc && pc != prev) {
7127 // pCode with attached label?
7128 if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7129 && PCI(pc)->label) {
7132 // is inline assembly label?
7133 if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7134 if (isPCW(pc) && PCW(pc)->label) return 0;
7137 if (isPCL(pc)) return 0;
7146 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7151 vsprintf (buf, fmt, va);
7154 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7157 /* Replaces the old pCode with the new one, moving the labels,
7158 * C source line and probably flow information to the new pCode.
7160 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7161 if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7164 /* first move all labels from old to new */
7165 PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7166 PCI(oldPC)->label = NULL;
7169 /* move C source line (if possible) */
7170 if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7171 PCI(newPC)->cline = PCI(oldPC)->cline;
7174 /* keep flow information intact */
7175 newPC->seq = oldPC->seq;
7176 PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7177 if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7178 PCI(newPC)->pcflow->end = newPC;
7181 /* insert a comment stating which pCode has been replaced */
7183 if (pic16_pcode_verbose || pic16_debug_verbose) {
7185 pic16_pCode2str (pc_str, 256, oldPC);
7186 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7190 /* insert new pCode into pBlock */
7191 pic16_pCodeInsertAfter (oldPC, newPC);
7192 pic16_unlinkpCode (oldPC);
7194 /* destruct replaced pCode */
7195 oldPC->destruct (oldPC);
7198 /* Returns the inverted conditional branch (if any) or NULL.
7199 * pcop must be set to the new jump target.
7201 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7205 if (!bcc || !isPCI(bcc)) return NULL;
7207 switch (PCI(bcc)->op) {
7208 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7209 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7210 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7211 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7212 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7213 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7214 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7215 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7222 #define MAX_DIST_GOTO 0x7FFFFFFF
7223 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7224 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7225 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7226 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7228 /* Follows GOTO/BRA instructions to their target instructions, stores the
7229 * final destination (not a GOTO or BRA instruction) in target and returns
7230 * the distance from the original pc to *target.
7232 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7235 pCodeOp *lastPCOP = NULL;
7239 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7241 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7242 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7243 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7245 lastPCOP = PCI(curr)->pcop;
7246 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7247 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7250 if (target) *target = last;
7251 if (pcop) *pcop = lastPCOP;
7255 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7256 * Otherwise the first pCode after the jumptable (after
7257 * the OPT_JUMPTABLE_END tag) is returned.
7259 pCode *skipJumptables (pCode *pc, int *isJumptable)
7262 if (!pc) return NULL;
7264 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7266 //fprintf (stderr, "SKIPPING jumptable\n");
7268 //pc->print(stderr, pc);
7270 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7271 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7272 //fprintf (stderr, "<<JUMPTAB:\n");
7273 // skip OPT_END as well
7274 if (pc) pc = pc->next;
7280 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7284 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7285 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7286 pc = skipJumptables (pc, &isJumptab);
7288 // pc is the first pCode after the jumptable
7291 // pc has not been changed by skipJumptables()
7299 /* Turn GOTOs into BRAs if distance between GOTO and label
7300 * is less than 1024 bytes.
7302 * This method is especially useful if GOTOs after BTFS[SC]
7303 * can be turned into BRAs as GOTO would cost another NOP
7306 void pic16_OptimizeJumps ()
7309 pCode *pc_prev = NULL;
7310 pCode *pc_next = NULL;
7313 int change, iteration, isJumptab;
7316 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7318 if (!the_pFile) return;
7320 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7322 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7323 int matchedInvertRule = 1;
7326 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7328 pc = pic16_findNextInstruction (pb->pcHead);
7331 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7333 // skip jumptable, i.e. start over with no pc_prev!
7339 /* (1) resolve chained jumps
7340 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7341 * (a) leave dead code in and
7342 * (b) skip over the dead code with an (unneccessary) jump.
7344 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7345 pCodeOp *lastTargetOp = NULL;
7346 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7347 int maxDist = MAX_DIST_BCC;
7348 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7349 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7351 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7352 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7353 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7354 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7355 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7356 PCI(pc)->pcop->name = lastTargetOp->name;
7365 int condBraType = isSkipOnStatus(pc_prev);
7366 label = PCI(pc)->pcop->name;
7367 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7368 if (dist < 0) dist = -dist;
7369 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7373 /* (2) remove "GOTO label; label:" */
7374 if (isLabel (pc_next, label)) {
7375 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7376 // first remove all preceeding SKIP instructions
7377 while (pc_prev && isPCI_SKIP(pc_prev)) {
7378 // attach labels on this instruction to pc_next
7379 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7380 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7381 PCI(pc_prev)->label = NULL;
7382 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7383 pic16_unlinkpCode (pc_prev);
7384 pc_prev = pic16_findPrevInstruction (pc);
7386 // now remove the redundant goto itself
7387 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7388 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7389 pic16_unlinkpCode (pc);
7390 pc = pic16_findPrevInstruction(pc_next->prev);
7391 isHandled = 1; // do not perform further optimizations
7397 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7398 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7399 if (dist < MAX_DIST_BCC) {
7401 switch (condBraType) {
7402 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7403 // no BDC on DIGIT CARRY available
7404 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7405 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7406 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7407 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7408 // no BNDC on DIGIT CARRY available
7409 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7410 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7411 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7413 // no replacement possible
7418 // ATTENTION: keep labels attached to BTFSx!
7419 // HINT: GOTO is label free (checked above)
7420 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7421 isHandled = 1; // do not perform further optimizations
7422 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7423 pic16_pCodeReplace (pc_prev, bcc);
7430 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7436 // (4) eliminate the following (common) tripel:
7438 // labels1: Bcc label2;
7439 // GOTO somewhere; ; <-- instruction referenced by pc
7441 // and replace it by
7442 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7444 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7445 // to <cont.> instead
7446 // ATTENTION: This optimization is only valid if <pred.> is
7447 // not a skip operation!
7448 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7449 // ATTENTION: no label may be attached to the GOTO instruction!
7450 if (isConditionalBranch(pc_prev)
7451 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7452 && (dist < MAX_DIST_BCC)
7453 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7454 && hasNoLabel(pc)) {
7455 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7458 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7459 isHandled = 1; // do not perform further optimizations
7460 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7461 pic16_pCodeReplace (pc_prev, newBcc);
7466 matchedInvertRule++;
7471 /* (5) now just turn GOTO into BRA */
7472 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7473 if (dist < MAX_DIST_BRA) {
7474 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7475 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7476 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7477 pic16_pCodeReplace (pc, newBra);
7482 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7485 } // if (!isHandled)
7492 pBlockRemoveUnusedLabels (pb);
7494 // This line enables goto chain resolution!
7495 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7498 } while (change); /* fixpoint iteration per pBlock */
7501 // emit some statistics concerning goto-optimization
7503 if (pic16_debug_verbose || pic16_pcode_verbose) {
7504 fprintf (stderr, "optimize-goto:\n"
7505 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7506 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7507 "\t%5d conditional \"skipping\" jumps inverted\n"
7508 "\t%5d GOTOs to next instruction removed\n"
7509 "\t%5d chained GOTOs resolved\n",
7510 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7513 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7517 #undef MAX_JUMPCHAIN_DEPTH
7518 #undef MAX_DIST_GOTO
7522 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7524 static void pBlockDestruct(pBlock *pb)
7535 /*-----------------------------------------------------------------*/
7536 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7537 /* name dbName and combine them */
7538 /* into one block */
7539 /*-----------------------------------------------------------------*/
7540 static void mergepBlocks(char dbName)
7543 pBlock *pb, *pbmerged = NULL,*pbn;
7545 pb = the_pFile->pbHead;
7547 //fprintf(stderr," merging blocks named %c\n",dbName);
7551 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7552 if( getpBlock_dbName(pb) == dbName) {
7554 //fprintf(stderr," merged block %c\n",dbName);
7559 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7560 /* pic16_addpCode2pBlock doesn't handle the tail: */
7561 pbmerged->pcTail = pb->pcTail;
7563 pb->prev->next = pbn;
7565 pbn->prev = pb->prev;
7570 //pic16_printpBlock(stderr, pbmerged);
7577 /*-----------------------------------------------------------------*/
7578 /* AnalyzeFlow - Examine the flow of the code and optimize */
7580 /* level 0 == minimal optimization */
7581 /* optimize registers that are used only by two instructions */
7582 /* level 1 == maximal optimization */
7583 /* optimize by looking at pairs of instructions that use the */
7585 /*-----------------------------------------------------------------*/
7587 static void AnalyzeFlow(int level)
7589 static int times_called=0;
7593 /* remove unused allocated registers before exiting */
7594 pic16_RemoveUnusedRegisters();
7599 /* if this is not the first time this function has been called,
7600 * then clean up old flow information */
7601 if(times_called++) {
7602 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7604 pic16_RegsUnMapLiveRanges();
7608 /* Phase 2 - Flow Analysis - Register Banking
7610 * In this phase, the individual flow blocks are examined
7611 * and register banking is fixed.
7615 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7616 pic16_FixRegisterBanking(pb);
7619 /* Phase 2 - Flow Analysis
7621 * In this phase, the pCode is partition into pCodeFlow
7622 * blocks. The flow blocks mark the points where a continuous
7623 * stream of instructions changes flow (e.g. because of
7624 * a call or goto or whatever).
7627 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7628 pic16_BuildFlow(pb);
7631 /* Phase 2 - Flow Analysis - linking flow blocks
7633 * In this phase, the individual flow blocks are examined
7634 * to determine their order of excution.
7637 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7641 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7642 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7643 pic16_createDF (pb);
7644 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7645 pic16_vcg_dump_default (pb);
7647 //pic16_destructDF (pb);
7651 if (0) releaseStack (); // releasing is costly...
7655 /* Phase 3 - Flow Analysis - Flow Tree
7657 * In this phase, the individual flow blocks are examined
7658 * to determine their order of execution.
7661 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7662 pic16_BuildFlowTree(pb);
7665 /* Phase x - Flow Analysis - Used Banks
7667 * In this phase, the individual flow blocks are examined
7668 * to determine the Register Banks they use
7672 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7677 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7678 pic16_pCodeRegMapLiveRanges(pb);
7680 pic16_RemoveUnusedRegisters();
7681 pic16_removeUnusedRegistersDF ();
7683 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7684 pic16_pCodeRegOptimizeRegUsage(level);
7693 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7698 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7701 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7702 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7703 pcflow = pcflow->next) {
7704 FillFlow(PCFL(pcflow));
7709 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7712 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7713 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7714 pcflow = pcflow->next) {
7715 FlowStats(PCFL(pcflow));
7721 /* VR -- no need to analyze banking in flow, but left here :
7722 * 1. because it may be used in the future for other purposes
7723 * 2. because if omitted we'll miss some optimization done here
7725 * Perhaps I should rename it to something else
7728 /*-----------------------------------------------------------------*/
7729 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7730 /* assigned to the registers. */
7732 /*-----------------------------------------------------------------*/
7734 void pic16_AnalyzeBanking(void)
7738 /* Phase x - Flow Analysis - Used Banks
7740 * In this phase, the individual flow blocks are examined
7741 * to determine the Register Banks they use
7751 if(!the_pFile)return;
7753 if(!pic16_options.no_banksel) {
7754 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7755 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7756 pic16_FixRegisterBanking(pb);
7761 /*-----------------------------------------------------------------*/
7762 /* buildCallTree - Look at the flow and extract all of the calls. */
7763 /*-----------------------------------------------------------------*/
7764 static set *register_usage(pBlock *pb);
7766 static void buildCallTree(void )
7778 /* Now build the call tree.
7779 First we examine all of the pCodes for functions.
7780 Keep in mind that the function boundaries coincide
7781 with pBlock boundaries.
7783 The algorithm goes something like this:
7784 We have two nested loops. The outer loop iterates
7785 through all of the pBlocks/functions. The inner
7786 loop iterates through all of the pCodes for
7787 a given pBlock. When we begin iterating through
7788 a pBlock, the variable pc_fstart, pCode of the start
7789 of a function, is cleared. We then search for pCodes
7790 of type PC_FUNCTION. When one is encountered, we
7791 initialize pc_fstart to this and at the same time
7792 associate a new pBranch object that signifies a
7793 branch entry. If a return is found, then this signifies
7794 a function exit point. We'll link the pCodes of these
7795 returns to the matching pc_fstart.
7797 When we're done, a doubly linked list of pBranches
7798 will exist. The head of this list is stored in
7799 `the_pFile', which is the meta structure for all
7800 of the pCode. Look at the pic16_printCallTree function
7801 on how the pBranches are linked together.
7804 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7805 pCode *pc_fstart=NULL;
7806 for(pc = pb->pcHead; pc; pc = pc->next) {
7808 if(isPCI(pc) && pc_fstart) {
7809 if(PCI(pc)->is2MemOp) {
7810 r = pic16_getRegFromInstruction2(pc);
7811 if(r && !strcmp(r->name, "POSTDEC1"))
7812 PCF(pc_fstart)->stackusage++;
7814 r = pic16_getRegFromInstruction(pc);
7815 if(r && !strcmp(r->name, "PREINC1"))
7816 PCF(pc_fstart)->stackusage--;
7821 if (PCF(pc)->fname) {
7824 sprintf(buf, "%smain", port->fun_prefix);
7825 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7826 //fprintf(stderr," found main \n");
7827 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7831 pbr = Safe_calloc(1,sizeof(pBranch));
7832 pbr->pc = pc_fstart = pc;
7835 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7837 // Here's a better way of doing the same:
7838 addSet(&pb->function_entries, pc);
7841 // Found an exit point in a function, e.g. return
7842 // (Note, there may be more than one return per function)
7844 pBranchLink(PCF(pc_fstart), PCF(pc));
7846 addSet(&pb->function_exits, pc);
7848 } else if(isCALL(pc)) {
7849 addSet(&pb->function_calls,pc);
7856 /* This is not needed because currently all register used
7857 * by a function are stored in stack -- VR */
7859 /* Re-allocate the registers so that there are no collisions
7860 * between local variables when one function call another */
7863 // pic16_deallocateAllRegs();
7865 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7873 /*-----------------------------------------------------------------*/
7874 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7875 /* all of the logical connections. */
7877 /* Essentially what's done here is that the pCode flow is */
7879 /*-----------------------------------------------------------------*/
7881 void pic16_AnalyzepCode(char dbName)
7892 /* Phase 1 - Register allocation and peep hole optimization
7894 * The first part of the analysis is to determine the registers
7895 * that are used in the pCode. Once that is done, the peep rules
7896 * are applied to the code. We continue to loop until no more
7897 * peep rule optimizations are found (or until we exceed the
7898 * MAX_PASSES threshold).
7900 * When done, the required registers will be determined.
7906 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7907 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7909 /* First, merge the labels with the instructions */
7910 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7911 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7913 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7914 //fprintf(stderr," analyze and merging block %c\n",dbName);
7915 pic16_pBlockMergeLabels(pb);
7918 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7923 changes = OptimizepCode(dbName);
7926 } while(changes && (i++ < MAX_PASSES));
7933 /* convert a series of movff's of local regs to stack, with a single call to
7934 * a support functions which does the same thing via loop */
7935 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
7939 char *fname[]={"__lr_store", "__lr_restore"};
7941 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
7943 pct = pic16_findNextInstruction(pcstart->next);
7946 pct = pc->next; //pic16_findNextInstruction(pc->next);
7947 // pc->print(stderr, pc);
7948 if(isPCI(pc) && PCI(pc)->label) {
7949 pbr = PCI(pc)->label;
7950 while(pbr && pbr->pc) {
7951 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
7955 // pc->print(stderr, pc);
7957 pc->prev->next = pct;
7958 pct->prev = pc->prev;
7962 } while ((pc) && (pc != pcend));
7964 /* unlink movff instructions */
7965 pcstart->next = pcend;
7966 pcend->prev = pcstart;
7970 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7971 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
7974 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
7975 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
7976 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
7979 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7980 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
7987 sym = newSymbol( fname[ entry?0:1 ], 0 );
7988 strcpy(sym->rname, fname[ entry?0:1 ]);
7989 checkAddSym(&externs, sym);
7991 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
7996 /*-----------------------------------------------------------------*/
7997 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
7998 /* local registers to a support function call */
7999 /*-----------------------------------------------------------------*/
8000 void pic16_OptimizeLocalRegs(void)
8005 pCodeOpLocalReg *pclr;
8008 regs *r, *lastr=NULL, *firstr=NULL;
8009 pCode *pcstart=NULL, *pcend=NULL;
8014 * local_regs begin mark
8015 * MOVFF r0x01, POSTDEC1
8016 * MOVFF r0x02, POSTDEC1
8019 * MOVFF r0x0n, POSTDEC1
8020 * local_regs end mark
8022 * convert the above to the below:
8023 * MOVLW starting_register_index
8025 * MOVLW register_count
8026 * call __save_registers_in_stack
8032 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8033 inRegCount = regCount = 0;
8034 firstr = lastr = NULL;
8035 for(pc = pb->pcHead; pc; pc = pc->next) {
8037 /* hold current function name */
8038 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8040 if(pc && (pc->type == PC_INFO)) {
8043 if(pci->type == INF_LOCALREGS) {
8044 pclr = PCOLR(pci->oper1);
8046 if((pclr->type == LR_ENTRY_BEGIN)
8047 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8050 switch(pclr->type) {
8051 case LR_ENTRY_BEGIN:
8053 inRegCount = 1; regCount = 0;
8054 pcstart = pc; //pic16_findNextInstruction(pc->next);
8055 firstr = lastr = NULL;
8061 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8064 if(curFunc && inWparamList(curFunc+1)) {
8065 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8069 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8074 firstr = lastr = NULL;
8078 if(inRegCount == -1) {
8079 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8085 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8087 r = pic16_getRegFromInstruction(pc);
8089 r = pic16_getRegFromInstruction2(pc);
8090 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8091 if(!firstr)firstr = r;
8093 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8105 /*-----------------------------------------------------------------*/
8106 /* ispCodeFunction - returns true if *pc is the pCode of a */
8108 /*-----------------------------------------------------------------*/
8109 static bool ispCodeFunction(pCode *pc)
8112 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8118 /*-----------------------------------------------------------------*/
8119 /* findFunction - Search for a function by name (given the name) */
8120 /* in the set of all functions that are in a pBlock */
8121 /* (note - I expect this to change because I'm planning to limit */
8122 /* pBlock's to just one function declaration */
8123 /*-----------------------------------------------------------------*/
8124 static pCode *findFunction(char *fname)
8131 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8133 pc = setFirstItem(pb->function_entries);
8136 if((pc->type == PC_FUNCTION) &&
8138 (strcmp(fname, PCF(pc)->fname)==0))
8141 pc = setNextItem(pb->function_entries);
8149 static void MarkUsedRegisters(set *regset)
8154 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8155 // fprintf(stderr, "marking register = %s\t", r1->name);
8156 r2 = pic16_regWithIdx(r1->rIdx);
8157 // fprintf(stderr, "to register = %s\n", r2->name);
8163 static void pBlockStats(FILE *of, pBlock *pb)
8169 if(!pic16_pcode_verbose)return;
8171 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8173 // for now just print the first element of each set
8174 pc = setFirstItem(pb->function_entries);
8176 fprintf(of,";entry: ");
8179 pc = setFirstItem(pb->function_exits);
8181 fprintf(of,";has an exit\n");
8185 pc = setFirstItem(pb->function_calls);
8187 fprintf(of,";functions called:\n");
8190 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8191 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8193 pc = setNextItem(pb->function_calls);
8197 r = setFirstItem(pb->tregisters);
8199 int n = elementsInSet(pb->tregisters);
8201 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8204 fprintf(of, "; %s\n",r->name);
8205 r = setNextItem(pb->tregisters);
8209 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8212 /*-----------------------------------------------------------------*/
8213 /*-----------------------------------------------------------------*/
8215 static void sequencepCode(void)
8221 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8223 pb->seq = GpCodeSequenceNumber+1;
8225 for( pc = pb->pcHead; pc; pc = pc->next)
8226 pc->seq = ++GpCodeSequenceNumber;
8232 /*-----------------------------------------------------------------*/
8233 /*-----------------------------------------------------------------*/
8234 static set *register_usage(pBlock *pb)
8237 set *registers=NULL;
8238 set *registersInCallPath = NULL;
8240 /* check recursion */
8242 pc = setFirstItem(pb->function_entries);
8249 if(pc->type != PC_FUNCTION)
8250 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8252 pc = setFirstItem(pb->function_calls);
8253 for( ; pc; pc = setNextItem(pb->function_calls)) {
8255 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8256 char *dest = pic16_get_op_from_instruction(PCI(pc));
8258 pcn = findFunction(dest);
8260 registersInCallPath = register_usage(pcn->pb);
8262 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8267 pBlockStats(stderr,pb); // debug
8270 // Mark the registers in this block as used.
8272 MarkUsedRegisters(pb->tregisters);
8273 if(registersInCallPath) {
8274 /* registers were used in the functions this pBlock has called */
8275 /* so now, we need to see if these collide with the ones we are */
8278 regs *r1,*r2, *newreg;
8280 DFPRINTF((stderr,"comparing registers\n"));
8282 r1 = setFirstItem(registersInCallPath);
8285 r2 = setFirstItem(pb->tregisters);
8287 while(r2 && (r1->type != REG_STK)) {
8289 if(r2->rIdx == r1->rIdx) {
8290 newreg = pic16_findFreeReg(REG_GPR);
8294 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8298 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8299 r1->rIdx, newreg->rIdx));
8300 r2->rIdx = newreg->rIdx;
8301 //if(r2->name) Safe_free(r2->name);
8303 r2->name = Safe_strdup(newreg->name);
8307 newreg->wasUsed = 1;
8309 r2 = setNextItem(pb->tregisters);
8312 r1 = setNextItem(registersInCallPath);
8315 /* Collisions have been resolved. Now free the registers in the call path */
8316 r1 = setFirstItem(registersInCallPath);
8318 if(r1->type != REG_STK) {
8319 newreg = pic16_regWithIdx(r1->rIdx);
8322 r1 = setNextItem(registersInCallPath);
8326 // MarkUsedRegisters(pb->registers);
8328 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8331 DFPRINTF((stderr,"returning regs\n"));
8333 DFPRINTF((stderr,"not returning regs\n"));
8335 DFPRINTF((stderr,"pBlock after register optim.\n"));
8336 pBlockStats(stderr,pb); // debug
8342 /*-----------------------------------------------------------------*/
8343 /* pct2 - writes the call tree to a file */
8345 /*-----------------------------------------------------------------*/
8346 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8350 // set *registersInCallPath = NULL;
8356 fprintf(of, "recursive function\n");
8357 return; //recursion ?
8360 pc = setFirstItem(pb->function_entries);
8367 for(i=0;i<indent;i++) // Indentation
8371 if(pc->type == PC_FUNCTION) {
8372 usedstack += PCF(pc)->stackusage;
8373 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8374 } else return; // ???
8377 pc = setFirstItem(pb->function_calls);
8378 for( ; pc; pc = setNextItem(pb->function_calls)) {
8380 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8381 char *dest = pic16_get_op_from_instruction(PCI(pc));
8383 pcn = findFunction(dest);
8385 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8387 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8395 /*-----------------------------------------------------------------*/
8396 /* pic16_printCallTree - writes the call tree to a file */
8398 /*-----------------------------------------------------------------*/
8400 void pic16_printCallTree(FILE *of)
8412 fprintf(of, "\npBlock statistics\n");
8413 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8417 fprintf(of,"Call Tree\n");
8418 pbr = the_pFile->functions;
8422 if(!ispCodeFunction(pc))
8423 fprintf(of,"bug in call tree");
8426 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8428 while(pc->next && !ispCodeFunction(pc->next)) {
8430 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8431 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8439 fprintf(of,"\n**************\n\na better call tree\n");
8440 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8445 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8446 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8452 /*-----------------------------------------------------------------*/
8454 /*-----------------------------------------------------------------*/
8456 static void InlineFunction(pBlock *pb)
8464 pc = setFirstItem(pb->function_calls);
8466 for( ; pc; pc = setNextItem(pb->function_calls)) {
8469 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8475 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8477 //fprintf(stderr,"Cool can inline:\n");
8478 //pcn->print(stderr,pcn);
8480 //fprintf(stderr,"recursive call Inline\n");
8481 InlineFunction(pcn->pb);
8482 //fprintf(stderr,"return from recursive call Inline\n");
8485 At this point, *pc points to a CALL mnemonic, and
8486 *pcn points to the function that is being called.
8488 To in-line this call, we need to remove the CALL
8489 and RETURN(s), and link the function pCode in with
8495 /* Remove the CALL */
8499 /* remove callee pBlock from the pBlock linked list */
8500 removepBlock(pcn->pb);
8508 /* Remove the Function pCode */
8509 pct = pic16_findNextInstruction(pcn->next);
8511 /* Link the function with the callee */
8512 pc->next = pcn->next;
8513 pcn->next->prev = pc;
8515 /* Convert the function name into a label */
8517 pbr = Safe_calloc(1,sizeof(pBranch));
8518 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8520 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8521 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8523 /* turn all of the return's except the last into goto's */
8524 /* check case for 2 instruction pBlocks */
8525 pce = pic16_findNextInstruction(pcn->next);
8527 pCode *pce_next = pic16_findNextInstruction(pce->next);
8529 if(pce_next == NULL) {
8530 /* found the last return */
8531 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8533 //fprintf(stderr,"found last return\n");
8534 //pce->print(stderr,pce);
8535 pce->prev->next = pc_call->next;
8536 pc_call->next->prev = pce->prev;
8537 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8547 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8553 /*-----------------------------------------------------------------*/
8555 /*-----------------------------------------------------------------*/
8557 void pic16_InlinepCode(void)
8566 if(!functionInlining)
8569 /* Loop through all of the function definitions and count the
8570 * number of times each one is called */
8571 //fprintf(stderr,"inlining %d\n",__LINE__);
8573 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8575 pc = setFirstItem(pb->function_calls);
8577 for( ; pc; pc = setNextItem(pb->function_calls)) {
8580 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8581 if(pcn && isPCF(pcn)) {
8582 PCF(pcn)->ncalled++;
8585 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8590 //fprintf(stderr,"inlining %d\n",__LINE__);
8592 /* Now, Loop through the function definitions again, but this
8593 * time inline those functions that have only been called once. */
8595 InlineFunction(the_pFile->pbHead);
8596 //fprintf(stderr,"inlining %d\n",__LINE__);
8598 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8603 char *pic_optype_names[]={
8604 "PO_NONE", // No operand e.g. NOP
8605 "PO_W", // The working register (as a destination)
8606 "PO_WREG", // The working register (as a file register)
8607 "PO_STATUS", // The 'STATUS' register
8608 "PO_BSR", // The 'BSR' register
8609 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8611 "PO_INDF0", // The Indirect register
8612 "PO_INTCON", // Interrupt Control register
8613 "PO_GPR_REGISTER", // A general purpose register
8614 "PO_GPR_BIT", // A bit of a general purpose register
8615 "PO_GPR_TEMP", // A general purpose temporary register
8616 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8617 "PO_PCL", // Program counter Low register
8618 "PO_PCLATH", // Program counter Latch high register
8619 "PO_PCLATU", // Program counter Latch upper register
8620 "PO_PRODL", // Product Register Low
8621 "PO_PRODH", // Product Register High
8622 "PO_LITERAL", // A constant
8623 "PO_REL_ADDR", // A relative address
8624 "PO_IMMEDIATE", // (8051 legacy)
8625 "PO_DIR", // Direct memory (8051 legacy)
8626 "PO_CRY", // bit memory (8051 legacy)
8627 "PO_BIT", // bit operand.
8628 "PO_STR", // (8051 legacy)
8630 "PO_WILD", // Wild card operand in peep optimizer
8631 "PO_TWO_OPS" // combine two operands
8635 char *dumpPicOptype(PIC_OPTYPE type)
8637 assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8638 return (pic_optype_names[ type ]);
8642 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8645 #define MAX_COMMON_BANK_SIZE 32
8646 #define FIRST_PSEUDO_BANK_NR 1000
8648 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8649 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8650 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8653 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8656 pseudoBankNr bank; // number assigned to this pseudoBank
8657 unsigned int size; // number of operands assigned to this bank
8658 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8661 /*----------------------------------------------------------------------*/
8662 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8663 /*----------------------------------------------------------------------*/
8664 unsigned int hashSymbol (const char *str)
8666 unsigned int res = 0;
8671 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8678 /*-----------------------------------------------------------------------*/
8679 /* compareSymbol - return 1 iff sym1 equals sym2 */
8680 /*-----------------------------------------------------------------------*/
8681 int compareSymbol (const void *sym1, const void *sym2)
8683 char *s1 = (char*) sym1;
8684 char *s2 = (char*) sym2;
8686 return (strcmp (s1,s2) == 0);
8689 /*-----------------------------------------------------------------------*/
8690 /* comparePre - return 1 iff p1 == p2 */
8691 /*-----------------------------------------------------------------------*/
8692 int comparePtr (const void *p1, const void *p2)
8697 /*----------------------------------------------------------*/
8698 /* getSymbolFromOperand - return a pointer to the symbol in */
8699 /* the given operand and its length */
8700 /*----------------------------------------------------------*/
8701 char *getSymbolFromOperand (char *op, int *len)
8706 if (!op) return NULL;
8708 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8710 if (*sym == '(') sym++;
8713 while (((*curr >= 'A') && (*curr <= 'Z'))
8714 || ((*curr >= 'a') && (*curr <= 'z'))
8715 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8716 || (*curr == '_')) {
8717 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8725 /*--------------------------------------------------------------------------*/
8726 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8727 /*--------------------------------------------------------------------------*/
8728 char *getSymFromBank (pseudoBankNr bank)
8732 if (bank < 0) return "<INVALID BANK NR>";
8733 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8736 /*-----------------------------------------------------------------------*/
8737 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8738 /* bank number (uses hTab sym2bank), if the */
8739 /* symbol is not yet assigned a pseudo bank it */
8740 /* is assigned one here */
8741 /*-----------------------------------------------------------------------*/
8742 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8744 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8750 hash = hashSymbol (op) % sym2bank->size;
8751 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8752 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8754 if (bank == UNKNOWN_BANK) {
8755 // create a pseudo bank for the operand
8757 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8758 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8759 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8760 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8762 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8770 /*--------------------------------------------------------------------*/
8771 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8772 /*--------------------------------------------------------------------*/
8773 int isBanksel (pCode *pc)
8777 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8778 // BANKSEL <variablename> or MOVLB <banknr>
8779 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8783 // check for inline assembler BANKSELs
8784 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8785 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8786 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8790 // assume pc is no BANKSEL instruction
8794 /*---------------------------------------------------------------------------------*/
8795 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8796 /* This method can not guarantee to find all modifications of the */
8797 /* BSR (e.g. via INDirection registers) but covers all compiler */
8798 /* generated plus some cases. */
8799 /*---------------------------------------------------------------------------------*/
8800 int invalidatesBSR(pCode *pc)
8802 // assembler directives invalidate BSR (well, they might, we don't know)
8803 if (isPCAD(pc)) return 1;
8805 // only ASMDIRs and pCodeInstructions can invalidate BSR
8806 if (!isPCI(pc)) return 0;
8808 // we have a pCodeInstruction
8810 // check for BSR modifying instructions
8811 switch (PCI(pc)->op) {
8815 case POC_RETFIE: // might be used as CALL replacement
8816 case POC_RETLW: // might be used as CALL replacement
8817 case POC_RETURN: // might be used as CALL replacement
8822 default: // other instruction do not change BSR unless BSR is an explicit operand!
8823 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8827 // no change of BSR possible/probable
8831 /*------------------------------------------------------------*/
8832 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8833 /* the symbol referenced in this BANKSEL */
8834 /*------------------------------------------------------------*/
8835 pseudoBankNr getBankFromBanksel (pCode *pc)
8840 if (!pc) return INVALID_BANK;
8842 if (isPCAD(pc) && PCAD(pc)->directive) {
8843 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8844 // get symbolname from PCAD(pc)->arg
8845 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8846 sym = PCAD(pc)->arg;
8847 data = getPseudoBankNrFromOperand (sym);
8848 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8849 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8850 // get (literal) bank number from PCAD(pc)->arg
8851 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8852 assert (0 && "not yet implemented - turn off banksel optimization for now");
8854 } else if (isPCI(pc)) {
8855 if (PCI(pc)->op == POC_BANKSEL) {
8856 // get symbolname from PCI(pc)->pcop->name (?)
8857 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8858 sym = PCI(pc)->pcop->name;
8859 data = getPseudoBankNrFromOperand (sym);
8860 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8861 } else if (PCI(pc)->op == POC_MOVLB) {
8862 // get (literal) bank number from PCI(pc)->pcop->name
8863 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8864 assert (0 && "not yet implemented - turn off banksel optimization for now");
8869 // no assigned bank could be found
8870 return UNKNOWN_BANK;
8875 /*------------------------------------------------------------------------------*/
8876 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8877 /*------------------------------------------------------------------------------*/
8878 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8882 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8885 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8886 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8888 if (data->bank != bank)
8895 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8899 /*------------------------------------------------------------------*/
8900 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8901 /* bank is selected at a given pCode */
8902 /*------------------------------------------------------------------*/
8904 /* Create a graph with pseudo banks as its nodes and switches between
8905 * these as edges (with the edge weight representing the absolute
8906 * number of BANKSELs from one to the other).
8907 * Removes redundand BANKSELs instead iff mod == 1.
8908 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8909 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8911 * TODO: check ALL instructions operands if they modify BSR directly...
8913 * pb - the pBlock to annotate
8914 * mod - select either graph creation (0) or BANKSEL removal (1)
8916 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8918 pCode *pc, *pc_next;
8919 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8920 int isBankselect = 0;
8921 unsigned int banksels=0;
8925 pc = pic16_findNextInstruction(pb->pcHead);
8927 isBankselect = isBanksel (pc);
8928 pc_next = pic16_findNextInstruction (pc->next);
8930 if (!hasNoLabel (pc)) {
8931 // we don't know our predecessors -- assume different BSRs
8932 prevBSR = UNKNOWN_BANK;
8933 pseudoBSR = UNKNOWN_BANK;
8934 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8937 // check if this is a BANKSEL instruction
8939 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
8940 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
8942 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
8943 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
8944 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
8945 pic16_unlinkpCode (pc);
8949 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
8954 if (!isBankselect && invalidatesBSR(pc)) {
8955 // check if this instruction invalidates the pseudoBSR
8956 pseudoBSR = UNKNOWN_BANK;
8957 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
8960 prevBSR = pseudoBSR;
8967 /*------------------------------------------------------------------------------------*/
8968 /* assignToSameBank - returns 0 on success or an error code */
8969 /* 1 - common bank would be too large */
8970 /* 2 - assignment to fixed (absolute) bank not performed */
8972 /* This functions assumes that unsplittable operands are already assigned to the same */
8973 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
8974 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
8975 /* TODO: Symbols with an abslute address must be handled specially! */
8976 /*------------------------------------------------------------------------------------*/
8977 int assignToSameBank (int bank0, int bank1, int doAbs)
8979 int eff0, eff1, dummy;
8980 pseudoBank *pbank0, *pbank1;
8983 eff0 = getEffectiveBank (bank0);
8984 eff1 = getEffectiveBank (bank1);
8986 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
8988 // nothing to do if already same bank
8989 if (eff0 == eff1) return 0;
8991 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
8994 // ensure eff0 < eff1
8996 // swap eff0 and eff1
9005 // now assign bank eff1 to bank eff0
9006 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9008 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9009 pbank0->bank = eff0;
9012 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9016 hitem = hTabSearch (coerce, eff1 % coerce->size);
9017 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9018 hitem = hitem->next;
9020 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9023 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9024 pbank0->bank, pbank0->size,
9025 getSymFromBank (eff0), getSymFromBank (eff1));
9029 if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9031 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9032 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9033 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9034 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9038 pbank0->size += pbank1->size;
9040 if (pbank1->ref == 0) Safe_free (pbank1);
9046 hitem->item = pbank0;
9048 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9051 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9056 /*----------------------------------------------------------------*/
9057 /* mergeGraphNodes - combines two nodes into one and modifies all */
9058 /* edges to and from the nodes accordingly */
9059 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9060 /* then also (B,A) must be an edge (possibly with weight 0). */
9061 /*----------------------------------------------------------------*/
9062 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9064 GraphEdge *edge, *backedge, *nextedge;
9068 assert (node1 && node2);
9069 assert (node1 != node2);
9071 // add all edges starting at node2 to node1
9074 nextedge = edge->next;
9076 backedge = getGEdge (node, node2);
9078 backweight = backedge->weight;
9081 // insert edges (node1,node) and (node,node1)
9082 addGEdge2 (node1, node, edge->weight, backweight);
9083 // remove edges (node, node2) and (node2, node)
9084 remGEdge (node2, node);
9085 remGEdge (node, node2);
9089 // now node2 should not be referenced by any other GraphNode...
9090 //remGNode (adj, node2->data, node2->hash);
9093 /*----------------------------------------------------------------*/
9094 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9095 /*----------------------------------------------------------------*/
9096 void showGraph (Graph *g)
9100 pseudoBankNr bankNr;
9107 bankNr = getEffectiveBank (node->hash);
9108 assert (bankNr >= 0);
9109 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9111 bankNr = pbank->bank;
9117 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9120 if (edge->weight > 0)
9121 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9128 /*---------------------------------------------------------------*/
9129 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9130 /*---------------------------------------------------------------*/
9131 void pic16_OptimizeBanksel ()
9133 GraphNode *node, *node1, *node1next;
9136 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9137 GraphEdge *edge, *backedge;
9139 int maxWeight, weight, mergeMore, absMaxWeight;
9140 pseudoBankNr curr0, curr1;
9143 pseudoBankNr bankNr;
9144 char *base_symbol0, *base_symbol1;
9149 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9151 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9153 if (!the_pFile || !the_pFile->pbHead) return;
9155 adj = newGraph (NULL);
9156 sym2bank = newHashTable ( 255 );
9157 bank2sym = newHashTable ( 255 );
9158 coerce = newHashTable ( 255 );
9160 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9161 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9162 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9166 // assign symbols with absolute addresses to their respective bank nrs
9167 set = pic16_fix_udata;
9168 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9169 bankNr = reg->address >> 8;
9170 node = getOrAddGNode (adj, NULL, bankNr);
9171 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9172 assignToSameBank (node->hash, bankNr, 1);
9174 assert (bankNr >= 0);
9175 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9177 pbank = Safe_calloc (1, sizeof (pseudoBank));
9178 pbank->bank = reg->address >> 8; //FIXED_BANK;
9181 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9183 assert (pbank->bank == (reg->address >> 8));
9184 pbank->bank = reg->address >> 8; //FIXED_BANK;
9186 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9191 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9192 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9195 if (node->hash < 0) { node = node->next; continue; }
9196 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9199 if (node1->hash < 0) { node1 = node1->next; continue; }
9200 node1next = node1->next;
9201 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9202 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9203 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9204 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9205 if (assignToSameBank (node->hash, node1->hash, 0)) {
9206 fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9207 assert (0 && "Could not assign a symbol to a bank!");
9209 mergeGraphNodes (node, node1);
9211 if (node->hash < node1->hash)
9212 mergeGraphNodes (node, node1);
9214 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9224 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9225 // assign tightly coupled operands to the same (pseudo) bank
9226 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9234 curr0 = getEffectiveBank (node->hash);
9235 if (curr0 < 0) { node = node->next; continue; }
9238 assert (edge->src == node);
9239 backedge = getGEdge (edge->node, edge->src);
9240 weight = edge->weight + (backedge ? backedge->weight : 0);
9241 curr1 = getEffectiveBank (edge->node->hash);
9242 if (curr1 < 0) { edge = edge->next; continue; }
9244 // merging is only useful if the items are not assigned to the same bank already...
9245 if (curr0 != curr1 && weight > maxWeight) {
9246 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9255 if (maxWeight > 0) {
9257 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9258 max->src->hash, getSymFromBank (max->src->hash),
9259 max->node->hash, getSymFromBank (max->node->hash));
9262 node = getGNode (adj, max->src->data, max->src->hash);
9263 node1 = getGNode (adj, max->node->data, max->node->hash);
9265 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9266 if (max->src->hash < max->node->hash)
9267 mergeGraphNodes (node, node1);
9269 mergeGraphNodes (node1, node);
9271 remGEdge (node, node1);
9272 remGEdge (node1, node);
9283 // remove redundant BANKSELs
9284 //fprintf (stderr, "removing redundant BANKSELs\n");
9285 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9286 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9291 fprintf (stderr, "display graph\n");
9296 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9299 /*** END of stuff belonging to the BANKSEL optimization ***/
9303 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9305 typedef unsigned int symbol_t;
9306 typedef unsigned int valnum_t;
9307 //typedef unsigned int hash_t;
9310 #define INT_TO_PTR(x) (((char *) 0) + (x))
9314 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9317 static int pic16_regIsLocal (regs *r);
9318 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9321 static unsigned int pic16_df_removed_pcodes = 0;
9322 static unsigned int pic16_df_saved_bytes = 0;
9323 static unsigned int df_findall_sameflow = 0;
9324 static unsigned int df_findall_otherflow = 0;
9325 static unsigned int df_findall_in_vals = 0;
9327 static void pic16_df_stats () {
9329 if (pic16_debug_verbose || pic16_pcode_verbose) {
9330 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9331 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9332 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9336 /* Remove a pCode iff possible:
9337 * - previous pCode is no SKIP
9339 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9340 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9341 pCode *pcprev, *pcnext;
9342 char buf[256], *total=NULL;
9345 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9347 pcprev = pic16_findPrevInstruction (pc->prev);
9348 pcnext = pic16_findNextInstruction (pc->next);
9350 /* move labels to next instruction (if possible) */
9351 if (PCI(pc)->label && !pcnext) return 0;
9353 /* if this is a SKIP with side-effects -- do not remove */
9354 /* XXX: might try to replace this one with the side-effect only version */
9356 && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9359 switch (PCI(pc)->op)
9363 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9364 pic16_pCodeReplace( pc, newpc );
9368 newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9369 pic16_pCodeReplace( pc, newpc );
9374 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9375 pic16_pCodeReplace( pc, newpc );
9379 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9380 pic16_pCodeReplace( pc, newpc );
9389 /* if previous instruction is a skip -- do not remove */
9390 if (pcprev && isPCI_SKIP(pcprev)) {
9391 if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9392 /* preceeding SKIP could not be removed -- keep this instruction! */
9397 if (PCI(pc)->label) {
9398 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9399 //pc->print (stderr, pc);
9400 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9401 PCI(pc)->label = NULL;
9404 /* update statistics */
9405 pic16_df_removed_pcodes++;
9406 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9408 /* remove the pCode */
9409 pic16_pCode2str (buf, 256, pc);
9410 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9411 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9412 len = strlen (buf) + strlen (comment) + 10;
9413 total = (char *) Safe_malloc (len);
9414 SNPRINTF (total, len, "%s: %s", comment, buf);
9415 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9419 /* actually unlink it from the pBlock -- also remove from to/from lists */
9420 pic16_pCodeUnlink (pc);
9422 /* remove the pCode -- release registers */
9425 /* report success */
9430 /* ======================================================================== */
9431 /* === SYMBOL HANDLING ==================================================== */
9432 /* ======================================================================== */
9434 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9435 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9436 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9438 /** Calculate a hash for a given string.
9439 * If len == 0 the string is assumed to be NUL terminated. */
9440 static hash_t symbolHash (const char *str, unsigned int len) {
9444 hash = (hash << 2) ^ *str;
9449 hash = (hash << 2) ^ *str;
9456 /** Return 1 iff strings v1 and v2 are identical. */
9457 static int symcmp (const void *v1, const void *v2) {
9458 return !strcmp ((const char *) v1, (const char *) v2);
9461 /** Return 1 iff pointers v1 and v2 are identical. */
9462 static int ptrcmp (const void *v1, const void *v2) {
9466 enum { SPO_WREG=0x1000,
9506 /* Return the unique symbol_t for the given string. */
9507 static symbol_t symFromStr (const char *str) {
9512 if (!map_symToStr) {
9514 struct { char *name; symbol_t sym; } predefsyms[] = {
9516 {"STATUS", SPO_STATUS},
9517 {"PRODL", SPO_PRODL},
9518 {"PRODH", SPO_PRODH},
9519 {"INDF0", SPO_INDF0},
9520 {"POSTDEC0", SPO_POSTDEC0},
9521 {"POSTINC0", SPO_POSTINC0},
9522 {"PREINC0", SPO_PREINC0},
9523 {"PLUSW0", SPO_PLUSW0},
9524 {"INDF1", SPO_INDF1},
9525 {"POSTDEC1", SPO_POSTDEC1},
9526 {"POSTINC1", SPO_POSTINC1},
9527 {"PREINC1", SPO_PREINC1},
9528 {"PLUSW1", SPO_PLUSW1},
9529 {"INDF2", SPO_INDF2},
9530 {"POSTDEC2", SPO_POSTDEC2},
9531 {"POSTINC2", SPO_POSTINC2},
9532 {"PREINC2", SPO_PREINC2},
9533 {"PLUSW2", SPO_PLUSW2},
9534 {"STKPTR", SPO_STKPTR},
9539 {"FSR0L", SPO_FSR0L},
9540 {"FSR0H", SPO_FSR0H},
9541 {"FSR1L", SPO_FSR1L},
9542 {"FSR1H", SPO_FSR1H},
9543 {"FSR2L", SPO_FSR2L},
9544 {"FSR2H", SPO_FSR2H},
9546 {"PCLATH", SPO_PCLATH},
9547 {"PCLATU", SPO_PCLATU},
9548 {"TABLAT", SPO_TABLAT},
9549 {"TBLPTRL", SPO_TBLPTRL},
9550 {"TBLPTRH", SPO_TBLPTRH},
9551 {"TBLPTRU", SPO_TBLPTRU},
9555 map_strToSym = newHashTable (128);
9556 map_symToStr = newHashTable (128);
9558 for (i=0; predefsyms[i].name; i++) {
9561 /* enter new symbol */
9562 sym = predefsyms[i].sym;
9563 name = predefsyms[i].name;
9564 res = Safe_strdup (name);
9565 hash = symbolHash (name, 0);
9567 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9568 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9572 hash = symbolHash (str, 0) % map_strToSym->size;
9574 /* find symbol in table */
9575 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9577 //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9581 /* enter new symbol */
9583 res = Safe_strdup (str);
9585 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9586 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9588 //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9594 static const char *strFromSym (symbol_t sym) {
9595 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9599 /* ======================================================================== */
9600 /* === DEFINITION MAP HANDLING ============================================ */
9601 /* ======================================================================== */
9603 /* A defmap provides information about which symbol is defined by which pCode.
9604 * The most recent definitions are prepended to the list, so that the most
9605 * recent definition can be found by forward scanning the list.
9606 * pc2: MOVFF r0x00, r0x01
9608 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9610 * We attach one defmap to each flow object, and each pCode will occur at
9611 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9612 * used to find definitions for a pCode in its own defmap that precede pCode.
9615 typedef struct defmap_s {
9616 symbol_t sym; /** symbol this item refers to */
9619 unsigned int in_mask:8; /** mask leaving in accessed bits */
9620 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9621 int isRead:1; /** sym/mask is read */
9622 int isWrite:1; /** sym/mask is written */
9626 pCode *pc; /** pCode this symbol is refrenced at */
9627 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9628 valnum_t val; /** new unique number for this value (if isWrite) */
9629 struct defmap_s *prev, *next; /** link to previous an next definition */
9632 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9633 static int defmap_free_count = 0; /** number of released defmap items */
9635 /* Returns a defmap_t with the specified data; this will be the new list head.
9636 * next - pointer to the current list head */
9637 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9642 defmap_free = map->next;
9643 --defmap_free_count;
9645 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9648 map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9649 map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9650 map->acc.access.isRead = (isRead != 0);
9651 map->acc.access.isWrite = (isWrite != 0);
9654 map->val = (isWrite ? val : 0);
9657 if (next) next->prev = map;
9662 /* Returns a copy of the single defmap item. */
9663 static defmap_t *copyDefmap (defmap_t *map) {
9664 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9665 memcpy (res, map, sizeof (defmap_t));
9671 /* Insert a defmap item after the specified one. */
9672 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9673 if (!ref || !newItem) return 1;
9675 newItem->next = ref->next;
9676 newItem->prev = ref;
9677 ref->next = newItem;
9678 if (newItem->next) newItem->next->prev = newItem;
9683 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9684 * item is copied before insertion into chain and therefore left untouched.
9685 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9686 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9689 while (dummy && (dummy->sym != item->sym
9690 || dummy->pc != item->pc
9691 || dummy->acc.accessmethod != item->acc.accessmethod
9692 || dummy->val != item->val
9693 || dummy->in_val != item->in_val)) {
9694 dummy = dummy->next;
9697 /* item already present? */
9698 if (dummy) return 0;
9700 /* otherwise: insert copy of item */
9701 dummy = copyDefmap (item);
9702 dummy->next = *head;
9703 if (*head) (*head)->prev = dummy;
9709 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9710 static void deleteDefmap (defmap_t *map) {
9713 /* unlink from chain -- fails for the first item (head is not updated!) */
9714 if (map->next) map->next->prev = map->prev;
9715 if (map->prev) map->prev->next = map->next;
9718 memset (map, 0, sizeof (defmap_t));
9720 /* save for future use */
9721 map->next = defmap_free;
9723 ++defmap_free_count;
9726 /* Release all defmaps referenced from map. */
9727 static void deleteDefmapChain (defmap_t **_map) {
9728 defmap_t *map, *next;
9734 /* find list head */
9735 while (map && map->prev) map = map->prev;
9737 /* delete all items */
9747 /* Free all defmap items. */
9748 static void freeDefmap (defmap_t **_map) {
9756 /* find list head */
9757 while (map->prev) map = map->prev;
9759 /* release all items */
9769 /* Returns the most recent definition for the given symbol preceeding pc.
9770 * If no definition is found, NULL is returned.
9771 * If pc == NULL the whole list is scanned. */
9772 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9773 defmap_t *curr = map;
9776 /* skip all definitions up to pc */
9777 while (curr && (curr->pc != pc)) curr = curr->next;
9779 /* pc not in the list -- scan the whole list for definitions */
9781 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9784 /* skip all definitions performed by pc */
9785 while (curr && (curr->pc == pc)) curr = curr->next;
9789 /* find definition for sym */
9790 while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9798 /* Returns the first use (read) of the given symbol AFTER pc.
9799 * If no such use is found, NULL is returned.
9800 * If pc == NULL the whole list is scanned. */
9801 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9802 defmap_t *curr = map, *prev = NULL;
9805 /* skip all definitions up to pc */
9806 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9808 /* pc not in the list -- scan the whole list for definitions */
9810 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9814 /* find end of list */
9815 while (curr && curr->next) curr = curr->next;
9818 /* find use of sym (scan list backwards) */
9819 while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9825 /* Return the defmap entry for sym AT pc.
9826 * If none is found, NULL is returned.
9827 * If more than one entry is found an assertion is triggered. */
9828 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9829 defmap_t *res = NULL;
9831 /* find entries for pc */
9832 while (map && map->pc != pc) map = map->next;
9834 /* find first entry for sym @ pc */
9835 while (map && map->pc == pc && map->sym != sym) map = map->next;
9837 /* no entry found */
9838 if (!map) return NULL;
9840 /* check for more entries */
9843 while (map && map->pc == pc) {
9844 /* more than one entry for sym @ pc found? */
9845 assert (map->sym != sym);
9849 /* return single entry for sym @ pc */
9853 /* Modifies the definition of sym at pCode to newval.
9854 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9856 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9859 /* find definitions of pc */
9860 while (m && m->pc != pc) m = m->next;
9862 /* find definition of sym at pc */
9863 while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9865 /* no definition found */
9871 /* update following uses of sym */
9872 while (m && m->pc == pc) m = m->prev;
9874 if (m->sym == sym) {
9876 if (m->acc.access.isWrite) m = NULL;
9884 /* ======================================================================== */
9885 /* === STACK ROUTINES ===================================================== */
9886 /* ======================================================================== */
9888 typedef struct stack_s {
9890 struct stack_s *next;
9893 typedef stackitem_t *dynstack_t;
9894 static stackitem_t *free_stackitems = NULL;
9896 /* Create a stack with one item. */
9897 static dynstack_t *newStack () {
9898 dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9903 /* Remove a stack -- its items are only marked free. */
9904 static void deleteStack (dynstack_t *s) {
9910 i->next = free_stackitems;
9911 free_stackitems = i;
9916 /* Release all stackitems. */
9917 static void releaseStack () {
9920 while (free_stackitems) {
9921 i = free_stackitems->next;
9922 Safe_free(free_stackitems);
9923 free_stackitems = i;
9927 static void stackPush (dynstack_t *stack, void *data) {
9930 if (free_stackitems) {
9931 i = free_stackitems;
9932 free_stackitems = free_stackitems->next;
9934 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9941 static void *stackPop (dynstack_t *stack) {
9945 if (stack && *stack) {
9946 data = (*stack)->data;
9948 *stack = (*stack)->next;
9949 i->next = free_stackitems;
9950 free_stackitems = i;
9958 static int stackContains (dynstack_t *s, void *data) {
9963 if (i->data == data) return 1;
9972 static int stackIsEmpty (dynstack_t *s) {
9973 return (*s == NULL);
9982 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9983 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9985 s->lastdef = lastdef;
9989 static void deleteState (state_t *s) {
9993 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
9996 /* scan working list for state */
10000 /* is i == state? -- state not new */
10001 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10009 /* is i == state? -- state not new */
10010 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10015 /* not found -- state is new */
10019 static inline valnum_t newValnum ();
10021 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10024 if (!pb) return "<unknown function>";
10026 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10027 if (pc && isPCF(pc)) return PCF(pc)->fname;
10028 else return "<unknown function>";
10031 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10037 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10039 /* find initial value (assigning pc == NULL) */
10040 map = PCFL(pcfl)->in_vals;
10041 while (map && map->sym != sym) map = map->next;
10043 /* initial value already present? */
10045 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10049 /* create a new initial value */
10050 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10051 PCFL(pcfl)->in_vals = map;
10052 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10056 /* insert map as last item in pcfl's defmap */
10057 if (!prev) prev = PCFL(pcfl)->defmap;
10059 PCFL(pcfl)->defmap = map;
10061 while (prev->next) prev = prev->next;
10070 /* Find all reaching definitions for sym at pc.
10071 * A new (!) list of definitions is returned.
10072 * Returns the number of reaching definitions found.
10073 * The defining defmap entries are returned in *chain.
10075 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10080 pCodeFlowLink *succ;
10082 dynstack_t *todo; /** stack of state_t */
10083 dynstack_t *done; /** stack of state_t */
10085 int firstState, n_defs;
10087 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10090 /* initialize return list */
10093 /* wildcard symbol? */
10094 if (!sym) return 0;
10096 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10098 map = PCI(pc)->pcflow->defmap;
10100 res = defmapFindDef (map, sym, pc);
10101 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10103 #define USE_PRECALCED_INVALS 1
10104 #if USE_PRECALCED_INVALS
10105 if (!res && PCI(pc)->pcflow->in_vals) {
10106 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10108 //fprintf (stderr, "found def in init values\n");
10109 df_findall_in_vals++;
10115 // found a single definition (in pc's flow)
10116 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10117 defmapAddCopyIfNew (chain, res);
10118 df_findall_sameflow++;
10122 #if USE_PRECALCED_INVALS
10124 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10130 #define FORWARD_FLOW_ANALYSIS 1
10131 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10132 /* no definition found in pc's flow preceeding pc */
10133 todo = newStack ();
10134 done = newStack ();
10135 n_defs = 0; firstState = 1;
10136 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10138 while (!stackIsEmpty (todo)) {
10139 state = (state_t *) stackPop (todo);
10140 stackPush (done, state);
10141 curr = state->flow;
10142 res = state->lastdef;
10143 //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);
10145 /* there are no definitions BEFORE pc in pc's flow (see above) */
10146 if (curr == PCI(pc)->pcflow) {
10148 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10149 res = pic16_pBlockAddInval (pc->pb, sym);
10150 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10153 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10154 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10158 /* save last definition of sym in this flow as initial def in successors */
10159 res = defmapFindDef (curr->defmap, sym, NULL);
10160 if (!res) res = state->lastdef;
10162 /* add successors to working list */
10163 state = newState (NULL, NULL);
10164 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10166 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10167 state->flow = succ->pcflow;
10168 state->lastdef = res;
10169 if (stateIsNew (state, todo, done)) {
10170 stackPush (todo, state);
10171 state = newState (NULL, NULL);
10173 succ = (pCodeFlowLink *) setNextItem (curr->to);
10175 deleteState (state);
10178 #else // !FORWARD_FLOW_ANALYSIS
10180 /* no definition found in pc's flow preceeding pc */
10181 todo = newStack ();
10182 done = newStack ();
10183 n_defs = 0; firstState = 1;
10184 stackPush (todo, newState (PCI(pc)->pcflow, res));
10186 while (!stackIsEmpty (todo)) {
10187 state = (state_t *) stackPop (todo);
10188 curr = state->flow;
10192 /* only check predecessor flows */
10194 /* get (last) definition of sym in this flow */
10195 res = defmapFindDef (curr->defmap, sym, NULL);
10199 /* definition found */
10200 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10201 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10203 /* no definition found -- check predecessor flows */
10204 state = newState (NULL, NULL);
10205 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10207 /* if no flow predecessor available -- sym might be uninitialized */
10209 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10210 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10211 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10212 deleteDefmap (res); res = NULL;
10216 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10217 state->flow = succ->pcflow;
10218 state->lastdef = res;
10219 if (stateIsNew (state, todo, done)) {
10220 stackPush (todo, state);
10221 state = newState (NULL, NULL);
10223 succ = (pCodeFlowLink *) setNextItem (curr->from);
10225 deleteState (state);
10231 /* clean up done stack */
10232 while (!stackIsEmpty(done)) {
10233 deleteState ((state_t *) stackPop (done));
10235 deleteStack (done);
10237 /* return number of items in result set */
10239 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10240 } else if (n_defs == 1) {
10242 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10243 } else if (n_defs > 0) {
10244 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10248 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10253 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10254 df_findall_otherflow++;
10258 /* ======================================================================== */
10259 /* === VALUE NUMBER HANDLING ============================================== */
10260 /* ======================================================================== */
10262 static valnum_t nextValnum = 0x1000;
10263 static hTab *map_symToValnum = NULL;
10265 /** Return a new value number. */
10266 static inline valnum_t newValnum () {
10267 return (nextValnum += 4);
10270 static valnum_t valnumFromStr (const char *str) {
10275 sym = symFromStr (str);
10277 if (!map_symToValnum) {
10278 map_symToValnum = newHashTable (128);
10281 /* literal already known? */
10282 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10284 /* return existing valnum */
10285 if (res) return (valnum_t) PTR_TO_INT(res);
10287 /* create new valnum */
10289 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10290 //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10294 /* Create a valnum for a literal. */
10295 static valnum_t valnumFromLit (unsigned int lit) {
10296 return ((valnum_t) 0x100 + (lit & 0x0FF));
10299 /* Return the (positive) literal value represented by val
10300 * or -1 iff val is no known literal's valnum. */
10301 static int litFromValnum (valnum_t val) {
10302 if (val >= 0x100 && val < 0x200) {
10303 /* valnum is a (known) literal */
10304 return val & 0x00FF;
10306 /* valnum is not a known literal */
10312 /* Sanity check - all flows in a block must be reachable from initial flow. */
10313 static int verifyAllFlowsReachable (pBlock *pb) {
10319 pCodeFlowLink *succ;
10322 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10325 flowInBlock = NULL;
10327 /* mark initial flow as reached (and "not needs to be reached") */
10328 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10330 addSetHead (&reached, pc);
10331 addSetHead (&checked, pc);
10333 /* mark all further flows in block as "need to be reached" */
10336 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10337 pc = pic16_findNextInstruction (pc->next);
10340 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10341 /* mark as reached and "not need to be reached" */
10342 deleteSetItem (&reached, pcfl);
10343 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10345 /* flow is no longer considered unreachable */
10346 deleteSetItem (&flowInBlock, pcfl);
10348 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10349 if (!isinSet (checked, succ->pcflow)) {
10350 /* flow has never been reached before */
10351 addSetHead (&reached, succ->pcflow);
10352 addSetHead (&checked, succ->pcflow);
10357 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10359 /* by now every flow should have been reached
10360 * --> flowInBlock should be empty */
10361 res = (flowInBlock == NULL);
10365 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10366 while (flowInBlock) {
10367 pcfl = indexSet (flowInBlock, 0);
10368 fprintf (stderr, "not reached: flow %p\n", pcfl);
10369 deleteSetItem (&flowInBlock, pcfl);
10375 deleteSet (&reached);
10376 deleteSet (&flowInBlock);
10377 deleteSet (&checked);
10379 /* if we reached every flow, succ is NULL by now... */
10380 //assert (res); // will fire on unreachable code...
10385 /* Checks a flow for accesses to sym AFTER pc.
10387 * Returns -1 if the symbol is read in this flow (before redefinition),
10388 * returns 0 if the symbol is redefined in this flow or
10389 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10391 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10392 defmap_t *map, *mappc;
10394 /* find pc or start of definitions */
10395 map = pcfl->defmap;
10396 while (map && (map->pc != pc) && map->next) map = map->next;
10397 /* if we found pc -- ignore it */
10398 while (map && map->pc == pc) map = map->prev;
10400 /* scan list backwards (first definition first) */
10401 while (map && mask) {
10402 // if (map->sym == sym) {
10403 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10405 /* scan list for reads at this pc first */
10406 while (map && map->pc == mappc->pc) {
10407 /* is the symbol (partially) read? */
10408 if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10409 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10416 while (map && map->pc == mappc->pc) {
10417 /* honor (partial) redefinitions of sym */
10418 if ((map->sym == sym) && (map->acc.access.isWrite)) {
10419 mask &= ~map->acc.access.mask;
10420 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10425 /* map already points to the first defmap for the next pCode */
10426 //map = mappc->prev;
10429 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10430 * is still alive; return the appropriate mask of alive bits */
10434 /* Check whether a symbol is alive (AFTER pc). */
10435 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10438 dynstack_t *todo, *done;
10441 pCodeFlowLink *succ;
10445 assert (isPCI(pc));
10446 pcfl = PCI(pc)->pcflow;
10447 map = pcfl->defmap;
10449 todo = newStack ();
10450 done = newStack ();
10452 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10453 stackPush (todo, state);
10456 while (!stackIsEmpty (todo)) {
10457 state = (state_t *) stackPop (todo);
10458 pcfl = state->flow;
10459 mask = PTR_TO_INT(state->lastdef);
10460 if (visit) stackPush (done, state); else deleteState(state);
10461 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10462 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10463 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10466 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10467 if (mask == 0) continue;
10469 /* symbol is (partially) read before redefinition in flow */
10470 if (mask == -1) break;
10472 /* symbol is neither read nor completely redefined -- check successor flows */
10473 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10474 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10475 if (stateIsNew (state, todo, done)) {
10476 stackPush (todo, state);
10478 deleteState (state);
10483 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10484 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10486 /* symbol is read in at least one flow -- is alive */
10487 if (mask == -1) return 1;
10489 /* symbol is read in no flow */
10493 /* Returns whether access to the given symbol has side effects. */
10494 static int pic16_symIsSpecial (symbol_t sym) {
10495 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10515 /* no special effects known */
10522 /* Check whether a register should be considered local (to the current function) or not. */
10523 static int pic16_regIsLocal (regs *r) {
10526 if (r->type == REG_TMP) return 1;
10528 sym = symFromStr (r->name);
10531 case SPO_FSR0L: // used in ptrget/ptrput
10532 case SPO_FSR0H: // ... as well
10533 case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10534 case SPO_FSR1H: // ... as well
10535 case SPO_FSR2L: // used as frame pointer
10536 case SPO_FSR2H: // ... as well
10537 case SPO_PRODL: // used to return values from functions
10538 case SPO_PRODH: // ... as well
10539 /* these registers (and some more...) are considered local */
10543 /* for unknown regs: check is marked local, leave if not */
10547 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10553 /* if in doubt, assume non-local... */
10557 /* Check all symbols touched by pc whether their newly assigned values are read.
10558 * Returns 0 if no symbol is used later on, 1 otherwise. */
10559 static int pic16_pCodeIsAlive (pCode *pc) {
10560 pCodeInstruction *pci;
10561 defmap_t *map, *lastpc;
10564 /* we can only handle PCIs */
10565 if (!isPCI(pc)) return 1;
10567 //pc->print (stderr, pc);
10570 assert (pci && pci->pcflow && pci->pcflow->defmap);
10572 /* NEVER remove instructions with implicit side effects */
10575 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10576 case POC_TBLRD_POSTDEC:
10577 case POC_TBLRD_PREINC:
10578 case POC_TBLWT: /* modify program memory */
10579 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10580 case POC_TBLWT_POSTDEC:
10581 case POC_TBLWT_PREINC:
10582 case POC_CLRWDT: /* clear watchdog timer */
10583 case POC_PUSH: /* should be safe to remove though... */
10584 case POC_POP: /* should be safe to remove though... */
10589 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10593 /* no special instruction */
10597 /* prevent us from removing assignments to non-local variables */
10599 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10600 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10602 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10603 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10604 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10605 //pc->print (stderr, pc);
10608 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10609 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10614 /* OVERKILL: prevent us from removing reads from non-local variables
10615 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10616 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10618 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10619 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10621 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10622 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10623 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10624 //pc->print (stderr, pc);
10627 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10628 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10633 /* now check that the defined symbols are not used */
10634 map = pci->pcflow->defmap;
10636 /* find items for pc */
10637 while (map && map->pc != pc) map = map->next;
10639 /* no entries found? something is fishy with DF analysis... -- play safe */
10641 if (pic16_pcode_verbose) {
10642 fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10647 /* remember first item assigned to pc for later use */
10650 /* check all symbols being modified by pc */
10651 while (map && map->pc == pc) {
10652 if (map->sym == 0) { map = map->next; continue; }
10654 /* keep pc if it references special symbols (like POSTDEC0) */
10658 pic16_pCode2str (buf, 256, pc);
10659 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10662 if (pic16_symIsSpecial (map->sym)) {
10663 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10666 if (map->acc.access.isWrite) {
10667 if (pic16_isAlive (map->sym, pc)) {
10668 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10675 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10679 pic16_pCode2str (buf, 256, pc);
10680 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10686 /* Adds implied operands to the list.
10687 * sym - operand being accessed in the pCode
10688 * list - list to append the operand
10689 * isRead - set to 1 iff sym is read in pCode
10690 * listRead - set to 1 iff all operands being read are to be listed
10692 * Returns 0 for "normal" operands, 1 for special operands.
10694 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10695 /* check whether accessing REG accesses other REGs as well */
10699 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10700 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10701 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10705 /* reads FSR0x and WREG */
10706 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10707 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10708 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10709 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10715 /* reads/modifies FSR0x */
10716 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10717 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10718 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10723 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10724 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10725 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10729 /* reads FSR1x and WREG */
10730 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10731 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10732 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10733 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10739 /* reads/modifies FSR1x */
10740 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10741 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10742 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10747 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10748 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10749 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10753 /* reads FSR2x and WREG */
10754 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10755 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10756 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10757 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10763 /* reads/modifies FSR2x */
10764 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10765 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10766 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10770 /* modifies PCLATH and PCLATU */
10771 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10773 /* reading PCL updates PCLATx */
10774 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10775 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10778 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10779 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10780 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10785 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10786 /* nothing special */
10791 /* has been a special operand */
10795 static symbol_t pic16_fsrsym_idx[][2] = {
10796 {SPO_FSR0L, SPO_FSR0H},
10797 {SPO_FSR1L, SPO_FSR1H},
10798 {SPO_FSR2L, SPO_FSR2H}
10801 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10802 static void mergeDefmapSymbols (defmap_t *list) {
10803 defmap_t *ref, *curr, *temp;
10805 /* now make sure that each symbol occurs at most once per pc */
10807 while (ref && (ref->pc == list->pc)) {
10809 while (curr && (curr->pc == list->pc)) {
10810 if (curr->sym == ref->sym) {
10811 //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10812 /* found a symbol occuring twice... merge the two */
10813 if (curr->acc.access.isRead) {
10814 //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10815 ref->acc.access.isRead = 1;
10816 ref->acc.access.in_mask |= curr->acc.access.in_mask;
10818 if (curr->acc.access.isWrite) {
10819 //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10820 ref->acc.access.isWrite = 1;
10821 ref->acc.access.mask |= curr->acc.access.mask;
10825 deleteDefmap (temp);
10826 continue; // do not skip curr!
10834 /** Prepend list with the reads and definitions performed by pc. */
10835 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10836 pCodeInstruction *pci;
10837 int cond, inCond, outCond;
10838 int mask = 0xff, smask;
10839 int isSpecial, isSpecial2;
10840 symbol_t sym, sym2;
10844 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10845 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10846 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10847 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10850 assert (isPCI(pc));
10853 /* handle bit instructions */
10854 if (pci->isBitInst) {
10855 assert (pci->pcop->type == PO_GPR_BIT);
10856 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10859 /* handle (additional) implicit arguments */
10865 lit = PCOL(pci->pcop)->lit;
10866 assert (lit >= 0 && lit < 3);
10867 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10868 val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10869 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10870 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10871 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...
10875 case POC_MOVLB: // BSR
10876 case POC_BANKSEL: // BSR
10877 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10880 case POC_MULWF: // PRODx
10881 case POC_MULLW: // PRODx
10882 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10883 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10886 case POC_POP: // TOS, STKPTR
10887 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10888 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10889 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10890 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10893 case POC_PUSH: // STKPTR
10894 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10895 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10896 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10897 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10900 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10901 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10902 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10903 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10904 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10905 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10907 /* needs correctly set-up stack pointer */
10908 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10909 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10912 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10913 /* pseudo read on (possible) return values */
10914 // WREG is handled below via outCond
10915 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10916 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10917 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10919 /* caller's stack pointers must be restored */
10920 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10921 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10922 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10923 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10926 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10927 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10928 /* pseudo read on (possible) return values */
10929 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10930 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10931 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10932 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10934 /* caller's stack pointers must be restored */
10935 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10936 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10937 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10938 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10942 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10943 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10944 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10945 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10948 case POC_TBLRD_POSTINC:
10949 case POC_TBLRD_POSTDEC:
10950 case POC_TBLRD_PREINC:
10951 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10952 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10953 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10954 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10958 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10959 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10960 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10961 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10964 case POC_TBLWT_POSTINC:
10965 case POC_TBLWT_POSTDEC:
10966 case POC_TBLWT_PREINC:
10967 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10968 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10969 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10970 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10974 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10978 /* handle explicit arguments */
10979 inCond = pci->inCond;
10980 outCond = pci->outCond;
10981 cond = inCond | outCond;
10982 if (cond & PCC_W) {
10983 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10986 /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
10987 if (inCond & PCC_STATUS) {
10989 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10990 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10991 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10992 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10993 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10995 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10996 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10999 if (outCond & PCC_STATUS) {
11001 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11002 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11003 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11004 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11005 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11007 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11008 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11011 isSpecial = isSpecial2 = 0;
11013 if (cond & PCC_REGISTER) {
11014 name = pic16_get_op (pci->pcop, NULL, 0);
11015 sym = symFromStr (name);
11016 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11017 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11020 if (cond & PCC_REGISTER2) {
11021 name = pic16_get_op2 (pci->pcop, NULL, 0);
11022 sym2 = symFromStr (name);
11023 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11024 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11028 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11029 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11031 mergeDefmapSymbols (list);
11037 static void printDefmap (defmap_t *map) {
11041 fprintf (stderr, "defmap @ %p:\n", curr);
11043 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11044 curr->acc.access.isRead ? "R" : " ",
11045 curr->acc.access.isWrite ? "W": " ",
11046 curr->in_val, curr->val,
11047 curr->acc.access.in_mask, curr->acc.access.mask,
11048 strFromSym(curr->sym), curr->sym,
11052 fprintf (stderr, "<EOL>\n");
11056 /* Add "additional" definitions to uniq.
11057 * 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.
11058 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11060 * If symbols defined in additional are not present in uniq, a definition is created.
11061 * Otherwise the present definition is altered to reflect the newer assignments.
11063 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11064 * before `------- noted in additional --------' after
11066 * I assume that each symbol occurs AT MOST ONCE in uniq.
11069 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11074 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11075 /* find tail of additional list (holds the first assignment) */
11077 while (curr && curr->next) curr = curr->next;
11081 /* find next assignment in additionals */
11082 while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11086 /* find item in uniq */
11088 //printDefmap (*uniq);
11089 while (old && (old->sym != curr->sym)) old = old->next;
11092 /* definition found -- replace */
11093 if (old->val != curr->val) {
11094 old->val = curr->val;
11098 /* new definition */
11099 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11106 /* return 0 iff uniq remained unchanged */
11110 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11111 * lists of its predecessor flows.
11112 * Initially *combined should be NULL, alt_in will be copied to combined.
11113 * If *combined != NULL, combined will be altered:
11114 * - for symbols defined in *combined but not in alt_in,
11115 * *combined is altered to 0 (value unknown, either *combined or INIT).
11116 * - for symbols defined in alt_in but not in *combined,
11117 * a 0 definition is created (value unknown, either INIT or alt).
11118 * - for symbols defined in both, *combined is:
11119 * > left unchanged if *combined->val == alt_in->val or
11120 * > modified to 0 otherwise (value unknown, either alt or *combined).
11122 * I assume that each symbol occurs AT MOST ONCE in each list!
11124 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11130 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11132 if (!(*combined)) {
11133 return defmapUpdateUniqueSym (combined, alt_in);
11136 /* merge the two */
11139 /* find symbols definition in *combined */
11141 while (old && (old->sym != curr->sym)) old = old->next;
11144 /* definition found */
11145 if (old->val && (old->val != curr->val)) {
11146 old->val = 0; /* value unknown */
11150 /* no definition found -- can be either INIT or alt_in's value */
11151 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11152 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11153 if (val != curr->val) change++;
11159 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11162 if (old->val != 0) {
11163 /* find definition in alt_in */
11165 while (curr && curr->sym != old->sym) curr = curr->next;
11167 /* symbol defined in *combined only -- can be either INIT or *combined */
11168 val = pic16_pBlockAddInval (pb, old->sym)->val;
11169 if (old->val != val) {
11182 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11183 defmap_t *curr1, *curr2;
11186 /* identical maps are equal */
11187 if (map1 == map2) return 0;
11189 if (!map1) return -1;
11190 if (!map2) return 1;
11192 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11197 while (curr1 && curr2) {
11198 curr1 = curr1->next;
11199 curr2 = curr2->next;
11202 /* one of them longer? */
11203 if (curr1) return 1;
11204 if (curr2) return -1;
11206 /* both lists are of equal length -- compare (in O(n^2)) */
11211 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11212 if (!curr2) return 1; // symbol not found in curr2
11213 if (curr2->val != curr1->val) return 1; // values differ
11215 /* compare next symbol */
11216 curr1 = curr1->next;
11219 /* no difference found */
11224 /* Prepare a list of all reaching definitions per flow.
11225 * This is done using a forward dataflow analysis.
11227 static void createReachingDefinitions (pBlock *pb) {
11228 defmap_t *out_vals, *in_vals;
11231 pCodeFlowLink *link;
11237 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11238 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11240 deleteDefmapChain (&PCFL(pc)->in_vals);
11241 deleteDefmapChain (&PCFL(pc)->out_vals);
11242 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11246 pc = pic16_findNextInstruction (pb->pcHead);
11247 todo = NULL; blacklist = NULL;
11248 addSetHead (&todo, PCI(pc)->pcflow);
11250 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11251 while (elementsInSet (todo)) {
11252 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11253 pcfl = PCFL(indexSet (todo, 0));
11254 deleteSetItem (&todo, pcfl);
11255 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11259 if (isinSet (blacklist, pcfl)) {
11260 fprintf (stderr, "ignoring blacklisted flow\n");
11264 /* create in_vals from predecessors out_vals */
11265 link = setFirstItem (pcfl->from);
11267 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11268 link = setNextItem (pcfl->from);
11271 //printDefmap (in_vals);
11272 //printDefmap (pcfl->in_vals);
11274 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11275 //fprintf (stderr, "in_vals changed\n");
11276 /* in_vals changed -- update out_vals */
11277 deleteDefmapChain (&pcfl->in_vals);
11278 pcfl->in_vals = in_vals;
11280 /* create out_val from in_val and defmap */
11282 defmapUpdateUniqueSym (&out_vals, in_vals);
11283 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11285 /* is out_vals different from pcfl->out_vals */
11286 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11287 //fprintf (stderr, "out_vals changed\n");
11288 deleteDefmapChain (&pcfl->out_vals);
11289 pcfl->out_vals = out_vals;
11291 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11292 addSet (&blacklist, pcfl);
11295 /* reschedule all successors */
11296 link = setFirstItem (pcfl->to);
11298 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11299 addSetIfnotP (&todo, link->pcflow);
11300 link = setNextItem (pcfl->to);
11303 deleteDefmapChain (&out_vals);
11306 deleteDefmapChain (&in_vals);
11312 static void showAllDefs (symbol_t sym, pCode *pc) {
11316 assert (isPCI(pc));
11317 count = defmapFindAll (sym, pc, &map);
11319 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11322 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11325 pic16_pCode2str (buf, 256, map->pc);
11326 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11330 deleteDefmapChain (&map);
11334 /* safepCodeUnlink and remove pc from defmap. */
11335 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11336 defmap_t *map, *next, **head;
11340 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11341 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11342 res = pic16_safepCodeUnlink (pc, comment);
11345 /* remove pc from defmap */
11348 if (map->pc == pc) {
11349 if (!map->prev && head) *head = map->next;
11350 deleteDefmap (map);
11359 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11361 /* This breaks the defmap chain's references to pCodes... fix it! */
11362 map = PCI(pc)->pcflow->defmap;
11364 while (map && map->pc != pc) map = map->next;
11366 while (map && map->pc == pc) {
11372 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11373 * write accesses (isRead == 0). */
11374 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11375 defmap_t *map, *map_start;
11377 if (!isPCI(pc)) return;
11378 if (sym == newsym) return;
11380 map = PCI(pc)->pcflow->defmap;
11382 while (map && map->pc != pc) map = map->next;
11384 while (map && map->pc == pc) {
11385 if (map->sym == sym) {
11386 assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11387 if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11388 /* only one kind of access handled... this is easy */
11391 /* must copy defmap entry before replacing symbol... */
11392 copy = copyDefmap (map);
11394 map->acc.access.isRead = 0;
11395 copy->acc.access.isWrite = 0;
11397 map->acc.access.isWrite = 0;
11398 copy->acc.access.isRead = 0;
11400 copy->sym = newsym;
11401 /* insert copy into defmap chain */
11402 defmapInsertAfter (map, copy);
11408 /* as this might introduce multiple defmap entries for newsym... */
11409 mergeDefmapSymbols (map_start);
11412 /* Assign "better" valnums to results. */
11413 static void assignValnums (pCode *pc) {
11414 pCodeInstruction *pci;
11416 symbol_t sym1, sym2;
11417 int cond, isSpecial1, isSpecial2, count, mask, lit;
11418 defmap_t *list, *val, *oldval, *dummy;
11419 regs *reg1 = NULL, *reg2 = NULL;
11422 /* only works for pCodeInstructions... */
11423 if (!isPCI(pc)) return;
11426 cond = pci->inCond | pci->outCond;
11427 list = pci->pcflow->defmap;
11428 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11430 if (cond & PCC_REGISTER) {
11431 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11432 reg1 = pic16_getRegFromInstruction (pc);
11433 isSpecial1 = pic16_symIsSpecial (sym1);
11435 if (cond & PCC_REGISTER2) {
11436 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11437 reg2 = pic16_getRegFromInstruction (pc);
11438 isSpecial2 = pic16_symIsSpecial (sym2);
11441 /* determine input values */
11443 while (val && val->pc != pc) val = val->next;
11444 //list = val; /* might save some time later... */
11445 while (val && val->pc == pc) {
11447 if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11448 /* get valnum for sym */
11449 count = defmapFindAll (val->sym, pc, &oldval);
11450 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11452 if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11453 val->in_val = oldval->val;
11457 } else if (count == 0) {
11458 /* no definition found */
11461 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11463 dummy = oldval->next;
11464 mask = oldval->acc.access.mask;
11465 val->in_val = oldval->val;
11466 while (dummy && (dummy->val == val->in_val)) {
11467 mask &= dummy->acc.access.mask;
11468 dummy = dummy->next;
11471 /* found other values or to restictive mask */
11472 if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11476 if (count > 0) deleteDefmapChain (&oldval);
11481 /* handle valnum assignment */
11483 case POC_CLRF: /* modifies STATUS (Z) */
11484 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11485 oldval = defmapCurr (list, sym1, pc);
11486 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11487 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11488 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11490 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11494 case POC_SETF: /* SETF does not touch STATUS */
11495 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11496 oldval = defmapCurr (list, sym1, pc);
11497 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11498 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11499 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11501 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11505 case POC_MOVLW: /* does not touch STATUS */
11506 oldval = defmapCurr (list, SPO_WREG, pc);
11507 if (pci->pcop->type == PO_LITERAL) {
11508 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11509 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11511 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11512 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11514 if (oldval && oldval->in_val == litnum) {
11515 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11516 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11518 defmapUpdate (list, SPO_WREG, pc, litnum);
11521 case POC_ANDLW: /* modifies STATUS (Z,N) */
11522 case POC_IORLW: /* modifies STATUS (Z,N) */
11523 case POC_XORLW: /* modifies STATUS (Z,N) */
11524 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11525 if (pci->pcop->type == PO_LITERAL) {
11527 lit = (unsigned char) PCOL(pci->pcop)->lit;
11528 val = defmapCurr (list, SPO_WREG, pc);
11529 if (val) vallit = litFromValnum (val->in_val);
11530 if (vallit != -1) {
11531 /* xxxLW <literal>, WREG contains a known literal */
11532 //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11533 if (pci->op == POC_ANDLW) {
11535 } else if (pci->op == POC_IORLW) {
11537 } else if (pci->op == POC_XORLW) {
11540 assert (0 && "invalid operation");
11542 if (vallit == lit) {
11543 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11544 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11546 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11553 /* check if old value matches new value */
11556 assert (pci->pcop->type == PO_LITERAL);
11558 lit = PCOL(pci->pcop)->lit;
11560 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11562 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11563 //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11565 /* cannot remove this LFSR */
11569 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11570 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11571 //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11577 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11582 case POC_MOVWF: /* does not touch flags */
11583 /* find value of WREG */
11584 val = defmapCurr (list, SPO_WREG, pc);
11585 oldval = defmapCurr (list, sym1, pc);
11586 if (val) lit = litFromValnum (val->in_val);
11588 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11590 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11591 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11592 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11594 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11596 assert (lit == 0x0ff);
11597 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11599 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11600 pic16_pCodeReplace (pc, newpc);
11601 defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11602 pic16_fixDefmap (pc, newpc);
11605 /* This breaks the defmap chain's references to pCodes... fix it! */
11606 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11607 if (!val->acc.access.isWrite) {
11608 deleteDefmap (val); // delete reference to WREG as in value
11611 val->acc.access.isRead = 0; // delete reference to WREG as in value
11613 oldval = PCI(pc)->pcflow->defmap;
11615 if (oldval->pc == pc) oldval->pc = newpc;
11616 oldval = oldval->next;
11618 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11619 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11620 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11622 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11625 case POC_MOVFW: /* modifies STATUS (Z,N) */
11626 /* find value of REG */
11627 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11628 val = defmapCurr (list, sym1, pc);
11629 oldval = defmapCurr (list, SPO_WREG, pc);
11630 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11631 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11632 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11634 defmap_t *pred, *predpred;
11635 /* Optimize MOVLW immd; MOVWF reg1; [...]; MOVFW reg1
11636 * into MOVLW immd; MOVWF reg1; [...]; MOVLW immd
11637 * This might allow removal of the first two assignments. */
11638 pred = defmapFindDef (list, sym1, pc);
11639 predpred = pred ? defmapFindDef (list, SPO_WREG, pred->pc) : NULL;
11640 if (pred && predpred && (PCI(pred->pc)->op == POC_MOVWF) && (PCI(predpred->pc)->op == POC_MOVLW)
11641 && !pic16_isAlive (SPO_STATUS, pc))
11643 newpc = pic16_newpCode (POC_MOVLW, pic16_pCodeOpCopy (PCI(predpred->pc)->pcop));
11645 if (pic16_debug_verbose || pic16_pcode_verbose) {
11646 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFW: replaced last of MOVLW;MOVWF;MOVFW by MOVLW");
11648 pic16_pCodeReplace (pc, newpc);
11649 defmapReplaceSymRef (pc, sym1, 0, 1);
11650 pic16_fixDefmap (pc, newpc);
11653 /* This breaks the defmap chain's references to pCodes... fix it! */
11654 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11655 if (!val->acc.access.isWrite) {
11656 deleteDefmap (val); // delete reference to reg1 as in value
11659 val->acc.access.isRead = 0; // delete reference to reg1 as in value
11661 oldval = PCI(pc)->pcflow->defmap;
11663 if (oldval->pc == pc) oldval->pc = newpc;
11664 oldval = oldval->next;
11668 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11672 case POC_MOVFF: /* does not touch STATUS */
11673 /* find value of REG */
11674 val = defmapCurr (list, sym1, pc);
11675 oldval = defmapCurr (list, sym2, pc);
11676 if (val) lit = litFromValnum (val->in_val);
11679 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11680 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11682 newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11683 } else if (lit == 0x00ff) {
11684 newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11689 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11690 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11691 pic16_pCodeReplace (pc, newpc);
11692 defmapReplaceSymRef (pc, sym1, 0, 1);
11693 pic16_fixDefmap (pc, newpc);
11695 break; // do not process instruction as MOVFF...
11697 } else if (!isSpecial1 && !isSpecial2
11698 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11699 && val && oldval && (val->in_val != 0)) {
11700 if (val->in_val == oldval->in_val) {
11701 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11702 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11704 if (!pic16_isAlive (sym1, pc)) {
11705 defmap_t *copy = NULL;
11706 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11707 * This should help eliminate
11709 * <do something not changing A or using B>
11711 * <B is not alive anymore>
11713 * <do something not changing A or using B>
11717 /* scan defmap for symbols storing sym1's value */
11718 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11719 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11720 /* unique reaching definition for sym found */
11721 if (copy->val && copy->val == val->in_val) {
11722 //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);
11723 if (copy->sym == SPO_WREG) {
11724 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11726 pCodeOp *pcop = NULL;
11727 /* the code below fails if we try to replace
11728 * MOVFF PRODL, r0x03
11729 * MOVFF r0x03, PCLATU
11731 * MOVFF PRODL, PCLATU
11732 * as copy(PRODL) contains has pc==NULL, by name fails...
11734 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11736 if (copy->pc && PCI(copy->pc)->pcop)
11737 pcop = PCI(copy->pc)->pcop;
11739 /* This code is broken--see above. */
11742 const char *symname = strFromSym(copy->sym);
11745 pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11746 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11747 //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11751 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11753 pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11755 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11756 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11757 pic16_pCodeReplace (pc, newpc);
11758 assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11759 defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11760 pic16_fixDefmap (pc, newpc);
11764 deleteDefmapChain (©);
11767 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11772 /* cannot optimize */
11777 static void pic16_destructDF (pBlock *pb) {
11782 /* remove old defmaps */
11783 pc = pic16_findNextInstruction (pb->pcHead);
11785 next = pic16_findNextInstruction (pc->next);
11787 assert (isPCI(pc) || isPCAD(pc));
11788 assert (PCI(pc)->pcflow);
11789 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11790 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11791 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11796 if (defmap_free || defmap_free_count) {
11797 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11798 freeDefmap (&defmap_free);
11799 defmap_free_count = 0;
11803 /* Checks whether a pBlock contains ASMDIRs. */
11804 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11809 pc = pic16_findNextInstruction (pb->pcHead);
11811 if (isPCAD(pc)) return 1;
11813 pc = pic16_findNextInstruction (pc->next);
11816 /* no PCADs found */
11821 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11822 static int pic16_removeUnusedRegistersDF () {
11825 regs *reg1, *reg2, *reg3;
11826 set *seenRegs = NULL;
11828 int islocal, change = 0;
11831 if (!the_pFile || !the_pFile->pbHead) return 0;
11833 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11834 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11836 /* find set of using pCodes per register */
11837 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11838 pc = pic16_findNextInstruction(pc->next)) {
11840 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11841 reg1 = reg2 = NULL;
11842 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11843 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11846 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11847 addSetIfnotP (&seenRegs, reg1);
11848 addSetIfnotP (®1->reglives.usedpCodes, pc);
11851 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11852 addSetIfnotP (&seenRegs, reg2);
11853 addSetIfnotP (®2->reglives.usedpCodes, pc);
11857 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11858 /* may not use pic16_regIsLocal() here -- in interrupt routines
11859 * WREG, PRODx, FSR0x must be saved */
11860 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11861 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11863 for (i=0; i < 2; i++) {
11864 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11865 if (!pc2) pc2 = pc;
11866 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11867 reg2 = pic16_getRegFromInstruction (pc);
11868 reg3 = pic16_getRegFromInstruction2 (pc);
11870 || (reg2->rIdx != pic16_stack_preinc->rIdx
11871 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11873 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11874 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11875 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11876 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11880 deleteSet (®1->reglives.usedpCodes);
11883 deleteSet (&seenRegs);
11890 /* Set up pCodeFlow's defmap_ts.
11891 * Needs correctly set up to/from fields. */
11892 static void pic16_createDF (pBlock *pb) {
11898 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11900 pic16_destructDF (pb);
11902 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11903 if (pic16_pBlockHasAsmdirs (pb)) {
11904 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11908 /* integrity check -- we need to reach all flows to guarantee
11909 * correct data flow analysis (reaching definitions, aliveness) */
11911 if (!verifyAllFlowsReachable (pb)) {
11912 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11917 /* establish new defmaps */
11918 pc = pic16_findNextInstruction (pb->pcHead);
11920 next = pic16_findNextInstruction (pc->next);
11922 assert (PCI(pc)->pcflow);
11923 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11928 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11929 createReachingDefinitions (pb);
11932 /* assign better valnums */
11933 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11934 pc = pic16_findNextInstruction (pb->pcHead);
11936 next = pic16_findNextInstruction (pc->next);
11938 assert (PCI(pc)->pcflow);
11939 assignValnums (pc);
11946 /* remove dead pCodes */
11947 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11950 pc = pic16_findNextInstruction (pb->pcHead);
11952 next = pic16_findNextInstruction (pc->next);
11954 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11955 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11964 /* ======================================================================== */
11965 /* === VCG DUMPER ROUTINES ================================================ */
11966 /* ======================================================================== */
11967 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11968 hTab *dumpedNodes = NULL;
11970 /** Dump VCG header into of. */
11971 static void pic16_vcg_init (FILE *of) {
11972 /* graph defaults */
11973 fprintf (of, "graph:{\n");
11974 fprintf (of, "title:\"graph1\"\n");
11975 fprintf (of, "label:\"graph1\"\n");
11976 fprintf (of, "color:white\n");
11977 fprintf (of, "textcolor:black\n");
11978 fprintf (of, "bordercolor:black\n");
11979 fprintf (of, "borderwidth:1\n");
11980 fprintf (of, "textmode:center\n");
11982 fprintf (of, "layoutalgorithm:dfs\n");
11983 fprintf (of, "late_edge_labels:yes\n");
11984 fprintf (of, "display_edge_labels:yes\n");
11985 fprintf (of, "dirty_edge_labels:yes\n");
11986 fprintf (of, "finetuning:yes\n");
11987 fprintf (of, "ignoresingles:no\n");
11988 fprintf (of, "straight_phase:yes\n");
11989 fprintf (of, "priority_phase:yes\n");
11990 fprintf (of, "manhattan_edges:yes\n");
11991 fprintf (of, "smanhattan_edges:no\n");
11992 fprintf (of, "nearedges:no\n");
11993 fprintf (of, "node_alignment:center\n"); // bottom|top|center
11994 fprintf (of, "port_sharing:no\n");
11995 fprintf (of, "arrowmode:free\n"); // fixed|free
11996 fprintf (of, "crossingphase2:yes\n");
11997 fprintf (of, "crossingoptimization:yes\n");
11998 fprintf (of, "edges:yes\n");
11999 fprintf (of, "nodes:yes\n");
12000 fprintf (of, "splines:no\n");
12002 /* node defaults */
12003 fprintf (of, "node.color:lightyellow\n");
12004 fprintf (of, "node.textcolor:black\n");
12005 fprintf (of, "node.textmode:center\n");
12006 fprintf (of, "node.shape:box\n");
12007 fprintf (of, "node.bordercolor:black\n");
12008 fprintf (of, "node.borderwidth:1\n");
12010 /* edge defaults */
12011 fprintf (of, "edge.textcolor:black\n");
12012 fprintf (of, "edge.color:black\n");
12013 fprintf (of, "edge.thickness:1\n");
12014 fprintf (of, "edge.arrowcolor:black\n");
12015 fprintf (of, "edge.backarrowcolor:black\n");
12016 fprintf (of, "edge.arrowsize:15\n");
12017 fprintf (of, "edge.backarrowsize:15\n");
12018 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12019 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12020 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12022 fprintf (of, "\n");
12024 /* prepare data structures */
12026 hTabDeleteAll (dumpedNodes);
12027 dumpedNodes = NULL;
12029 dumpedNodes = newHashTable (128);
12032 /** Dump VCG footer into of. */
12033 static void pic16_vcg_close (FILE *of) {
12034 fprintf (of, "}\n");
12037 #define BUF_SIZE 128
12038 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12041 static int ptrcmp (const void *p1, const void *p2) {
12046 /** Dump a pCode node as VCG to of. */
12047 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12048 char buf[BUF_SIZE];
12050 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12054 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12055 //fprintf (stderr, "dumping %p\n", pc);
12057 /* only dump pCodeInstructions and Flow nodes */
12058 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12061 fprintf (of, "node:{");
12062 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12063 fprintf (of, "label:\"%s\n", pcTitle(pc));
12065 fprintf (of, "<PCFLOW>");
12066 } else if (isPCI(pc) || isPCAD(pc)) {
12067 pc->print (of, pc);
12069 fprintf (of, "<!PCI>");
12071 fprintf (of, "\" ");
12072 fprintf (of, "}\n");
12074 if (1 && isPCFL(pc)) {
12075 defmap_t *map, *prev;
12077 map = PCFL(pc)->defmap;
12080 if (map->sym != 0) {
12083 /* emit definition node */
12084 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12085 fprintf (of, "label:\"");
12089 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));
12092 } while (map && prev->pc == map->pc);
12095 fprintf (of, "\" ");
12097 fprintf (of, "color:green ");
12098 fprintf (of, "}\n");
12100 /* emit edge to previous definition */
12101 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12103 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12105 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12107 fprintf (of, "color:green ");
12108 fprintf (of, "}\n");
12111 pic16_vcg_dumpnode (map->pc, of);
12112 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12113 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12120 /* emit additional nodes (e.g. operands) */
12123 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12124 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12125 char buf[BUF_SIZE];
12126 pCodeInstruction *pci;
12130 if (1 && isPCFL(pc)) {
12131 /* emit edges to flow successors */
12133 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12134 pcfl = setFirstItem (PCFL(pc)->to);
12136 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12137 pic16_vcg_dumpnode (pc, of);
12138 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12139 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12140 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12141 pcfl = setNextItem (PCFL(pc)->to);
12145 if (!isPCI(pc) && !isPCAD(pc)) return;
12149 /* emit control flow edges (forward only) */
12153 pic16_vcg_dumpnode (curr->pc, of);
12154 fprintf (of, "edge:{");
12155 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12156 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12157 fprintf (of, "color:red ");
12158 fprintf (of, "}\n");
12163 /* dump "flow" edge (link pCode according to pBlock order) */
12166 pcnext = pic16_findNextInstruction (pc->next);
12168 pic16_vcg_dumpnode (pcnext, of);
12169 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12170 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12178 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12179 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12180 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12184 /* emit data flow edges (backward only) */
12185 /* TODO: gather data flow information... */
12188 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12193 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12194 if (pic16_pBlockHasAsmdirs (pb)) {
12195 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12199 for (pc=pb->pcHead; pc; pc = pc->next) {
12200 pic16_vcg_dumpnode (pc, of);
12203 for (pc=pb->pcHead; pc; pc = pc->next) {
12204 pic16_vcg_dumpedges (pc, of);
12208 static void pic16_vcg_dump_default (pBlock *pb) {
12210 char buf[BUF_SIZE];
12215 /* get function name */
12217 while (pc && !isPCF(pc)) pc = pc->next;
12219 SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12221 SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12224 //fprintf (stderr, "now dumping %s\n", buf);
12225 of = fopen (buf, "w");
12226 pic16_vcg_init (of);
12227 pic16_vcg_dump (of, pb);
12228 pic16_vcg_close (of);
12233 /*** END of helpers for pCode dataflow optimizations ***/