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);
160 /****************************************************************/
161 /* Forward declarations */
162 /****************************************************************/
164 void pic16_unlinkpCode(pCode *pc);
166 static void genericAnalyze(pCode *pc);
167 static void AnalyzeGOTO(pCode *pc);
168 static void AnalyzeSKIP(pCode *pc);
169 static void AnalyzeRETURN(pCode *pc);
172 static void genericDestruct(pCode *pc);
173 static void genericPrint(FILE *of,pCode *pc);
175 static void pCodePrintLabel(FILE *of, pCode *pc);
176 static void pCodePrintFunction(FILE *of, pCode *pc);
177 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
178 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
179 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
180 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
181 int pic16_pCodePeepMatchRule(pCode *pc);
182 static void pBlockStats(FILE *of, pBlock *pb);
183 static pBlock *newpBlock(void);
184 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
185 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
186 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
187 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
188 void OptimizeLocalRegs(void);
189 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
191 char *dumpPicOptype(PIC_OPTYPE type);
193 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
194 pCodeOp *pic16_popGetLit(int);
195 pCodeOp *pic16_popGetWithString(char *);
196 extern int inWparamList(char *s);
198 /** data flow optimization helpers **/
199 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
200 static void pic16_vcg_dump (FILE *of, pBlock *pb);
201 static void pic16_vcg_dump_default (pBlock *pb);
203 static int pic16_pCodeIsAlive (pCode *pc);
204 static void pic16_df_stats ();
205 static void pic16_createDF (pBlock *pb);
206 static int pic16_removeUnusedRegistersDF ();
207 static void pic16_destructDF (pBlock *pb);
208 static void releaseStack ();
210 /****************************************************************/
211 /* PIC Instructions */
212 /****************************************************************/
214 pCodeInstruction pic16_pciADDWF = {
215 {PC_OPCODE, NULL, NULL, 0, NULL,
229 1,0, // dest, bit instruction
231 0, // literal operand
233 0, // fast call/return mode select bit
234 0, // second memory operand
235 0, // second literal operand
237 (PCC_W | PCC_REGISTER), // inCond
238 (PCC_REGISTER | PCC_STATUS), // outCond
242 pCodeInstruction pic16_pciADDFW = {
243 {PC_OPCODE, NULL, NULL, 0, NULL,
257 0,0, // dest, bit instruction
259 0, // literal operand
261 0, // fast call/return mode select bit
262 0, // second memory operand
263 0, // second literal operand
265 (PCC_W | PCC_REGISTER), // inCond
266 (PCC_W | PCC_STATUS), // outCond
270 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
271 {PC_OPCODE, NULL, NULL, 0, NULL,
285 1,0, // dest, bit instruction
287 0, // literal operand
289 0, // fast call/return mode select bit
290 0, // second memory operand
291 0, // second literal operand
293 (PCC_W | PCC_REGISTER | PCC_C), // inCond
294 (PCC_REGISTER | PCC_STATUS), // outCond
298 pCodeInstruction pic16_pciADDFWC = {
299 {PC_OPCODE, NULL, NULL, 0, NULL,
313 0,0, // dest, bit instruction
315 0, // literal operand
317 0, // fast call/return mode select bit
318 0, // second memory operand
319 0, // second literal operand
321 (PCC_W | PCC_REGISTER | PCC_C), // inCond
322 (PCC_W | PCC_STATUS), // outCond
326 pCodeInstruction pic16_pciADDLW = {
327 {PC_OPCODE, NULL, NULL, 0, NULL,
341 0,0, // dest, bit instruction
343 1, // literal operand
345 0, // fast call/return mode select bit
346 0, // second memory operand
347 0, // second literal operand
349 (PCC_W | PCC_LITERAL), // inCond
350 (PCC_W | PCC_STATUS), // outCond
354 pCodeInstruction pic16_pciANDLW = {
355 {PC_OPCODE, NULL, NULL, 0, NULL,
369 0,0, // dest, bit instruction
371 1, // literal operand
373 0, // fast call/return mode select bit
374 0, // second memory operand
375 0, // second literal operand
377 (PCC_W | PCC_LITERAL), // inCond
378 (PCC_W | PCC_Z | PCC_N), // outCond
382 pCodeInstruction pic16_pciANDWF = {
383 {PC_OPCODE, NULL, NULL, 0, NULL,
397 1,0, // dest, bit instruction
399 0, // literal operand
401 0, // fast call/return mode select bit
402 0, // second memory operand
403 0, // second literal operand
405 (PCC_W | PCC_REGISTER), // inCond
406 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
410 pCodeInstruction pic16_pciANDFW = {
411 {PC_OPCODE, NULL, NULL, 0, NULL,
425 0,0, // dest, bit instruction
427 0, // literal operand
429 0, // fast call/return mode select bit
430 0, // second memory operand
431 0, // second literal operand
433 (PCC_W | PCC_REGISTER), // inCond
434 (PCC_W | PCC_Z | PCC_N) // outCond
437 pCodeInstruction pic16_pciBC = { // mdubuc - New
438 {PC_OPCODE, NULL, NULL, 0, NULL,
452 0,0, // dest, bit instruction
454 0, // literal operand
456 0, // fast call/return mode select bit
457 0, // second memory operand
458 0, // second literal operand
460 (PCC_REL_ADDR | PCC_C), // inCond
465 pCodeInstruction pic16_pciBCF = {
466 {PC_OPCODE, NULL, NULL, 0, NULL,
480 1,1, // dest, bit instruction
482 0, // literal operand
484 0, // fast call/return mode select bit
485 0, // second memory operand
486 0, // second literal operand
488 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
489 PCC_REGISTER, // outCond
493 pCodeInstruction pic16_pciBN = { // mdubuc - New
494 {PC_OPCODE, NULL, NULL, 0, NULL,
508 0,0, // dest, bit instruction
510 0, // literal operand
512 0, // fast call/return mode select bit
513 0, // second memory operand
514 0, // second literal operand
516 (PCC_REL_ADDR | PCC_N), // inCond
517 PCC_NONE , // outCond
521 pCodeInstruction pic16_pciBNC = { // mdubuc - New
522 {PC_OPCODE, NULL, NULL, 0, NULL,
536 0,0, // dest, bit instruction
538 0, // literal operand
540 0, // fast call/return mode select bit
541 0, // second memory operand
542 0, // second literal operand
544 (PCC_REL_ADDR | PCC_C), // inCond
545 PCC_NONE , // outCond
549 pCodeInstruction pic16_pciBNN = { // mdubuc - New
550 {PC_OPCODE, NULL, NULL, 0, NULL,
564 0,0, // dest, bit instruction
566 0, // literal operand
568 0, // fast call/return mode select bit
569 0, // second memory operand
570 0, // second literal operand
572 (PCC_REL_ADDR | PCC_N), // inCond
573 PCC_NONE , // outCond
577 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
578 {PC_OPCODE, NULL, NULL, 0, NULL,
592 0,0, // dest, bit instruction
594 0, // literal operand
596 0, // fast call/return mode select bit
597 0, // second memory operand
598 0, // second literal operand
600 (PCC_REL_ADDR | PCC_OV), // inCond
601 PCC_NONE , // outCond
605 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
606 {PC_OPCODE, NULL, NULL, 0, NULL,
620 0,0, // dest, bit instruction
622 0, // literal operand
624 0, // fast call/return mode select bit
625 0, // second memory operand
626 0, // second literal operand
628 (PCC_REL_ADDR | PCC_Z), // inCond
629 PCC_NONE , // outCond
633 pCodeInstruction pic16_pciBOV = { // mdubuc - New
634 {PC_OPCODE, NULL, NULL, 0, NULL,
648 0,0, // dest, bit instruction
650 0, // literal operand
652 0, // fast call/return mode select bit
653 0, // second memory operand
654 0, // second literal operand
656 (PCC_REL_ADDR | PCC_OV), // inCond
657 PCC_NONE , // outCond
661 pCodeInstruction pic16_pciBRA = { // mdubuc - New
662 {PC_OPCODE, NULL, NULL, 0, NULL,
676 0,0, // dest, bit instruction
678 0, // literal operand
680 0, // fast call/return mode select bit
681 0, // second memory operand
682 0, // second literal operand
684 PCC_REL_ADDR, // inCond
685 PCC_NONE , // outCond
689 pCodeInstruction pic16_pciBSF = {
690 {PC_OPCODE, NULL, NULL, 0, NULL,
704 1,1, // dest, bit instruction
706 0, // literal operand
708 0, // fast call/return mode select bit
709 0, // second memory operand
710 0, // second literal operand
712 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
713 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
717 pCodeInstruction pic16_pciBTFSC = {
718 {PC_OPCODE, NULL, NULL, 0, NULL,
732 0,1, // dest, bit instruction
734 0, // literal operand
736 0, // fast call/return mode select bit
737 0, // second memory operand
738 0, // second literal operand
740 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
741 PCC_EXAMINE_PCOP, // outCond
745 pCodeInstruction pic16_pciBTFSS = {
746 {PC_OPCODE, NULL, NULL, 0, NULL,
760 0,1, // dest, bit instruction
762 0, // literal operand
764 0, // fast call/return mode select bit
765 0, // second memory operand
766 0, // second literal operand
768 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
769 PCC_EXAMINE_PCOP, // outCond
773 pCodeInstruction pic16_pciBTG = { // mdubuc - New
774 {PC_OPCODE, NULL, NULL, 0, NULL,
788 0,1, // dest, bit instruction
790 0, // literal operand
792 0, // fast call/return mode select bit
793 0, // second memory operand
794 0, // second literal operand
796 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
797 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
801 pCodeInstruction pic16_pciBZ = { // mdubuc - New
802 {PC_OPCODE, NULL, NULL, 0, NULL,
816 0,0, // dest, bit instruction
818 0, // literal operand
820 0, // fast call/return mode select bit
821 0, // second memory operand
822 0, // second literal operand
824 (PCC_REL_ADDR | PCC_Z), // inCond
829 pCodeInstruction pic16_pciCALL = {
830 {PC_OPCODE, NULL, NULL, 0, NULL,
844 0,0, // dest, bit instruction
846 0, // literal operand
848 1, // fast call/return mode select bit
849 0, // second memory operand
850 0, // second literal operand
857 pCodeInstruction pic16_pciCOMF = {
858 {PC_OPCODE, NULL, NULL, 0, NULL,
872 1,0, // dest, bit instruction
874 0, // literal operand
876 0, // fast call/return mode select bit
877 0, // second memory operand
878 0, // second literal operand
880 PCC_REGISTER, // inCond
881 (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
885 pCodeInstruction pic16_pciCOMFW = {
886 {PC_OPCODE, NULL, NULL, 0, NULL,
900 0,0, // dest, bit instruction
902 0, // literal operand
904 0, // fast call/return mode select bit
905 0, // second memory operand
906 0, // second literal operand
908 PCC_REGISTER, // inCond
909 (PCC_W | PCC_Z | PCC_N) , // outCond
913 pCodeInstruction pic16_pciCLRF = {
914 {PC_OPCODE, NULL, NULL, 0, NULL,
928 0,0, // dest, bit instruction
930 0, // literal operand
932 0, // fast call/return mode select bit
933 0, // second memory operand
934 0, // second literal operand
937 (PCC_REGISTER | PCC_Z), // outCond
941 pCodeInstruction pic16_pciCLRWDT = {
942 {PC_OPCODE, NULL, NULL, 0, NULL,
956 0,0, // dest, bit instruction
958 0, // literal operand
960 0, // fast call/return mode select bit
961 0, // second memory operand
962 0, // second literal operand
965 PCC_NONE , // outCond
969 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
970 {PC_OPCODE, NULL, NULL, 0, NULL,
984 0,0, // dest, bit instruction
986 0, // literal operand
988 0, // fast call/return mode select bit
989 0, // second memory operand
990 0, // second literal operand
992 (PCC_W | PCC_REGISTER), // inCond
993 PCC_NONE , // outCond
997 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
998 {PC_OPCODE, NULL, NULL, 0, NULL,
1005 NULL, // from branch
1012 0,0, // dest, bit instruction
1013 1,1, // branch, skip
1014 0, // literal operand
1015 1, // RAM access bit
1016 0, // fast call/return mode select bit
1017 0, // second memory operand
1018 0, // second literal operand
1020 (PCC_W | PCC_REGISTER), // inCond
1021 PCC_NONE , // outCond
1025 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1026 {PC_OPCODE, NULL, NULL, 0, NULL,
1033 NULL, // from branch
1040 1,0, // dest, bit instruction
1041 1,1, // branch, skip
1042 0, // literal operand
1043 1, // RAM access bit
1044 0, // fast call/return mode select bit
1045 0, // second memory operand
1046 0, // second literal operand
1048 (PCC_W | PCC_REGISTER), // inCond
1049 PCC_NONE , // outCond
1053 pCodeInstruction pic16_pciDAW = {
1054 {PC_OPCODE, NULL, NULL, 0, NULL,
1061 NULL, // from branch
1068 0,0, // dest, bit instruction
1069 0,0, // branch, skip
1070 0, // literal operand
1071 0, // RAM access bit
1072 0, // fast call/return mode select bit
1073 0, // second memory operand
1074 0, // second literal operand
1077 (PCC_W | PCC_C), // outCond
1081 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1082 {PC_OPCODE, NULL, NULL, 0, NULL,
1089 NULL, // from branch
1096 1,0, // dest, bit instruction
1097 1,1, // branch, skip
1098 0, // literal operand
1099 1, // RAM access bit
1100 0, // fast call/return mode select bit
1101 0, // second memory operand
1102 0, // second literal operand
1104 PCC_REGISTER, // inCond
1105 PCC_REGISTER , // outCond
1109 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1110 {PC_OPCODE, NULL, NULL, 0, NULL,
1117 NULL, // from branch
1124 0,0, // dest, bit instruction
1125 1,1, // branch, skip
1126 0, // literal operand
1127 1, // RAM access bit
1128 0, // fast call/return mode select bit
1129 0, // second memory operand
1130 0, // second literal operand
1132 PCC_REGISTER, // inCond
1137 pCodeInstruction pic16_pciDECF = {
1138 {PC_OPCODE, NULL, NULL, 0, NULL,
1145 NULL, // from branch
1152 1,0, // dest, bit instruction
1153 0,0, // branch, skip
1154 0, // literal operand
1155 1, // RAM access bit
1156 0, // fast call/return mode select bit
1157 0, // second memory operand
1158 0, // second literal operand
1160 PCC_REGISTER, // inCond
1161 (PCC_REGISTER | PCC_STATUS) , // outCond
1165 pCodeInstruction pic16_pciDECFW = {
1166 {PC_OPCODE, NULL, NULL, 0, NULL,
1173 NULL, // from branch
1180 0,0, // dest, bit instruction
1181 0,0, // branch, skip
1182 0, // literal operand
1183 1, // RAM access bit
1184 0, // fast call/return mode select bit
1185 0, // second memory operand
1186 0, // second literal operand
1188 PCC_REGISTER, // inCond
1189 (PCC_W | PCC_STATUS) , // outCond
1193 pCodeInstruction pic16_pciDECFSZ = {
1194 {PC_OPCODE, NULL, NULL, 0, NULL,
1201 NULL, // from branch
1208 1,0, // dest, bit instruction
1209 1,1, // branch, skip
1210 0, // literal operand
1211 1, // RAM access bit
1212 0, // fast call/return mode select bit
1213 0, // second memory operand
1214 0, // second literal operand
1216 PCC_REGISTER, // inCond
1217 PCC_REGISTER , // outCond
1221 pCodeInstruction pic16_pciDECFSZW = {
1222 {PC_OPCODE, NULL, NULL, 0, NULL,
1229 NULL, // from branch
1236 0,0, // dest, bit instruction
1237 1,1, // branch, skip
1238 0, // literal operand
1239 1, // RAM access bit
1240 0, // fast call/return mode select bit
1241 0, // second memory operand
1242 0, // second literal operand
1244 PCC_REGISTER, // inCond
1249 pCodeInstruction pic16_pciGOTO = {
1250 {PC_OPCODE, NULL, NULL, 0, NULL,
1257 NULL, // from branch
1264 0,0, // dest, bit instruction
1265 1,0, // branch, skip
1266 0, // literal operand
1267 0, // RAM access bit
1268 0, // fast call/return mode select bit
1269 0, // second memory operand
1270 0, // second literal operand
1272 PCC_REL_ADDR, // inCond
1273 PCC_NONE , // outCond
1277 pCodeInstruction pic16_pciINCF = {
1278 {PC_OPCODE, NULL, NULL, 0, NULL,
1285 NULL, // from branch
1292 1,0, // dest, bit instruction
1293 0,0, // branch, skip
1294 0, // literal operand
1295 1, // RAM access bit
1296 0, // fast call/return mode select bit
1297 0, // second memory operand
1298 0, // second literal operand
1300 PCC_REGISTER, // inCond
1301 (PCC_REGISTER | PCC_STATUS), // outCond
1305 pCodeInstruction pic16_pciINCFW = {
1306 {PC_OPCODE, NULL, NULL, 0, NULL,
1313 NULL, // from branch
1320 0,0, // dest, bit instruction
1321 0,0, // branch, skip
1322 0, // literal operand
1323 1, // RAM access bit
1324 0, // fast call/return mode select bit
1325 0, // second memory operand
1326 0, // second literal operand
1328 PCC_REGISTER, // inCond
1329 (PCC_W | PCC_STATUS) , // outCond
1333 pCodeInstruction pic16_pciINCFSZ = {
1334 {PC_OPCODE, NULL, NULL, 0, NULL,
1341 NULL, // from branch
1348 1,0, // dest, bit instruction
1349 1,1, // branch, skip
1350 0, // literal operand
1351 1, // RAM access bit
1352 0, // fast call/return mode select bit
1353 0, // second memory operand
1354 0, // second literal operand
1356 PCC_REGISTER, // inCond
1357 PCC_REGISTER , // outCond
1361 pCodeInstruction pic16_pciINCFSZW = {
1362 {PC_OPCODE, NULL, NULL, 0, NULL,
1369 NULL, // from branch
1376 0,0, // dest, bit instruction
1377 1,1, // branch, skip
1378 0, // literal operand
1379 1, // RAM access bit
1380 0, // fast call/return mode select bit
1381 0, // second memory operand
1382 0, // second literal operand
1384 PCC_REGISTER, // inCond
1389 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1390 {PC_OPCODE, NULL, NULL, 0, NULL,
1397 NULL, // from branch
1404 1,0, // dest, bit instruction
1405 1,1, // branch, skip
1406 0, // literal operand
1407 1, // RAM access bit
1408 0, // fast call/return mode select bit
1409 0, // second memory operand
1410 0, // second literal operand
1412 PCC_REGISTER, // inCond
1413 PCC_REGISTER , // outCond
1417 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1418 {PC_OPCODE, NULL, NULL, 0, NULL,
1425 NULL, // from branch
1432 0,0, // dest, bit instruction
1433 1,1, // branch, skip
1434 0, // literal operand
1435 1, // RAM access bit
1436 0, // fast call/return mode select bit
1437 0, // second memory operand
1438 0, // second literal operand
1440 PCC_REGISTER, // inCond
1445 pCodeInstruction pic16_pciIORWF = {
1446 {PC_OPCODE, NULL, NULL, 0, NULL,
1453 NULL, // from branch
1460 1,0, // dest, bit instruction
1461 0,0, // branch, skip
1462 0, // literal operand
1463 1, // RAM access bit
1464 0, // fast call/return mode select bit
1465 0, // second memory operand
1466 0, // second literal operand
1468 (PCC_W | PCC_REGISTER), // inCond
1469 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1473 pCodeInstruction pic16_pciIORFW = {
1474 {PC_OPCODE, NULL, NULL, 0, NULL,
1481 NULL, // from branch
1488 0,0, // dest, bit instruction
1489 0,0, // branch, skip
1490 0, // literal operand
1491 1, // RAM access bit
1492 0, // fast call/return mode select bit
1493 0, // second memory operand
1494 0, // second literal operand
1496 (PCC_W | PCC_REGISTER), // inCond
1497 (PCC_W | PCC_Z | PCC_N), // outCond
1501 pCodeInstruction pic16_pciIORLW = {
1502 {PC_OPCODE, NULL, NULL, 0, NULL,
1509 NULL, // from branch
1516 0,0, // dest, bit instruction
1517 0,0, // branch, skip
1518 1, // literal operand
1519 0, // RAM access bit
1520 0, // fast call/return mode select bit
1521 0, // second memory operand
1522 0, // second literal operand
1524 (PCC_W | PCC_LITERAL), // inCond
1525 (PCC_W | PCC_Z | PCC_N), // outCond
1529 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1530 {PC_OPCODE, NULL, NULL, 0, NULL,
1537 NULL, // from branch
1544 0,0, // dest, bit instruction
1545 0,0, // branch, skip
1546 1, // literal operand
1547 0, // RAM access bit
1548 0, // fast call/return mode select bit
1549 0, // second memory operand
1550 1, // second literal operand
1552 PCC_LITERAL, // inCond
1553 PCC_NONE, // outCond
1557 pCodeInstruction pic16_pciMOVF = {
1558 {PC_OPCODE, NULL, NULL, 0, NULL,
1565 NULL, // from branch
1572 1,0, // dest, bit instruction
1573 0,0, // branch, skip
1574 0, // literal operand
1575 1, // RAM access bit
1576 0, // fast call/return mode select bit
1577 0, // second memory operand
1578 0, // second literal operand
1580 PCC_REGISTER, // inCond
1581 (PCC_Z | PCC_N), // outCond
1585 pCodeInstruction pic16_pciMOVFW = {
1586 {PC_OPCODE, NULL, NULL, 0, NULL,
1593 NULL, // from branch
1600 0,0, // dest, bit instruction
1601 0,0, // branch, skip
1602 0, // literal operand
1603 1, // RAM access bit
1604 0, // fast call/return mode select bit
1605 0, // second memory operand
1606 0, // second literal operand
1608 PCC_REGISTER, // inCond
1609 (PCC_W | PCC_N | PCC_Z), // outCond
1613 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1614 {PC_OPCODE, NULL, NULL, 0, NULL,
1621 NULL, // from branch
1628 0,0, // dest, bit instruction
1629 0,0, // branch, skip
1630 0, // literal operand
1631 0, // RAM access bit
1632 0, // fast call/return mode select bit
1633 1, // second memory operand
1634 0, // second literal operand
1636 PCC_REGISTER, // inCond
1637 PCC_REGISTER2, // outCond
1641 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1642 {PC_OPCODE, NULL, NULL, 0, NULL,
1648 NULL, // from branch
1655 0,0, // dest, bit instruction
1656 0,0, // branch, skip
1657 1, // literal operand
1658 0, // RAM access bit
1659 0, // fast call/return mode select bit
1660 0, // second memory operand
1661 0, // second literal operand
1663 (PCC_NONE | PCC_LITERAL), // inCond
1664 PCC_REGISTER, // outCond - BSR
1668 pCodeInstruction pic16_pciMOVLW = {
1669 {PC_OPCODE, NULL, NULL, 0, NULL,
1675 NULL, // from branch
1682 0,0, // dest, bit instruction
1683 0,0, // branch, skip
1684 1, // literal operand
1685 0, // RAM access bit
1686 0, // fast call/return mode select bit
1687 0, // second memory operand
1688 0, // second literal operand
1690 (PCC_NONE | PCC_LITERAL), // inCond
1695 pCodeInstruction pic16_pciMOVWF = {
1696 {PC_OPCODE, NULL, NULL, 0, NULL,
1703 NULL, // from branch
1710 0,0, // dest, bit instruction
1711 0,0, // branch, skip
1712 0, // literal operand
1713 1, // RAM access bit
1714 0, // fast call/return mode select bit
1715 0, // second memory operand
1716 0, // second literal operand
1719 PCC_REGISTER, // outCond
1723 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1724 {PC_OPCODE, NULL, NULL, 0, NULL,
1730 NULL, // from branch
1737 0,0, // dest, bit instruction
1738 0,0, // branch, skip
1739 1, // literal operand
1740 0, // RAM access bit
1741 0, // fast call/return mode select bit
1742 0, // second memory operand
1743 0, // second literal operand
1745 (PCC_W | PCC_LITERAL), // inCond
1746 PCC_NONE, // outCond - PROD
1750 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1751 {PC_OPCODE, NULL, NULL, 0, NULL,
1757 NULL, // from branch
1764 0,0, // dest, bit instruction
1765 0,0, // branch, skip
1766 0, // literal operand
1767 1, // RAM access bit
1768 0, // fast call/return mode select bit
1769 0, // second memory operand
1770 0, // second literal operand
1772 (PCC_W | PCC_REGISTER), // inCond
1773 PCC_REGISTER, // outCond - PROD
1777 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1778 {PC_OPCODE, NULL, NULL, 0, NULL,
1784 NULL, // from branch
1791 0,0, // dest, bit instruction
1792 0,0, // branch, skip
1793 0, // literal operand
1794 1, // RAM access bit
1795 0, // fast call/return mode select bit
1796 0, // second memory operand
1797 0, // second literal operand
1799 PCC_REGISTER, // inCond
1800 (PCC_REGISTER | PCC_STATUS), // outCond
1804 pCodeInstruction pic16_pciNOP = {
1805 {PC_OPCODE, NULL, NULL, 0, NULL,
1811 NULL, // from branch
1818 0,0, // dest, bit instruction
1819 0,0, // branch, skip
1820 0, // literal operand
1821 0, // RAM access bit
1822 0, // fast call/return mode select bit
1823 0, // second memory operand
1824 0, // second literal operand
1827 PCC_NONE, // outCond
1831 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1832 {PC_OPCODE, NULL, NULL, 0, NULL,
1838 NULL, // from branch
1845 0,0, // dest, bit instruction
1846 0,0, // branch, skip
1847 0, // literal operand
1848 0, // RAM access bit
1849 0, // fast call/return mode select bit
1850 0, // second memory operand
1851 0, // second literal operand
1854 PCC_NONE , // outCond
1858 pCodeInstruction pic16_pciPUSH = {
1859 {PC_OPCODE, NULL, NULL, 0, NULL,
1865 NULL, // from branch
1872 0,0, // dest, bit instruction
1873 0,0, // branch, skip
1874 0, // literal operand
1875 0, // RAM access bit
1876 0, // fast call/return mode select bit
1877 0, // second memory operand
1878 0, // second literal operand
1881 PCC_NONE , // outCond
1885 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1886 {PC_OPCODE, NULL, NULL, 0, NULL,
1892 NULL, // from branch
1899 0,0, // dest, bit instruction
1900 1,0, // branch, skip
1901 0, // literal operand
1902 0, // RAM access bit
1903 0, // fast call/return mode select bit
1904 0, // second memory operand
1905 0, // second literal operand
1907 PCC_REL_ADDR, // inCond
1908 PCC_NONE , // outCond
1912 pCodeInstruction pic16_pciRETFIE = {
1913 {PC_OPCODE, NULL, NULL, 0, NULL,
1920 NULL, // from branch
1927 0,0, // dest, bit instruction
1928 1,0, // branch, skip
1929 0, // literal operand
1930 0, // RAM access bit
1931 1, // fast call/return mode select bit
1932 0, // second memory operand
1933 0, // second literal operand
1936 PCC_NONE, // outCond (not true... affects the GIE bit too)
1940 pCodeInstruction pic16_pciRETLW = {
1941 {PC_OPCODE, NULL, NULL, 0, NULL,
1948 NULL, // from branch
1955 0,0, // dest, bit instruction
1956 1,0, // branch, skip
1957 1, // literal operand
1958 0, // RAM access bit
1959 0, // fast call/return mode select bit
1960 0, // second memory operand
1961 0, // second literal operand
1963 PCC_LITERAL, // inCond
1968 pCodeInstruction pic16_pciRETURN = {
1969 {PC_OPCODE, NULL, NULL, 0, NULL,
1976 NULL, // from branch
1983 0,0, // dest, bit instruction
1984 1,0, // branch, skip
1985 0, // literal operand
1986 0, // RAM access bit
1987 1, // fast call/return mode select bit
1988 0, // second memory operand
1989 0, // second literal operand
1992 PCC_NONE, // outCond
1995 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
1996 {PC_OPCODE, NULL, NULL, 0, NULL,
2003 NULL, // from branch
2010 1,0, // dest, bit instruction
2011 0,0, // branch, skip
2012 0, // literal operand
2013 1, // RAM access bit
2014 0, // fast call/return mode select bit
2015 0, // second memory operand
2016 0, // second literal operand
2018 (PCC_C | PCC_REGISTER), // inCond
2019 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2023 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2024 {PC_OPCODE, NULL, NULL, 0, NULL,
2031 NULL, // from branch
2038 0,0, // dest, bit instruction
2039 0,0, // branch, skip
2040 0, // literal operand
2041 1, // RAM access bit
2042 0, // fast call/return mode select bit
2043 0, // second memory operand
2044 0, // second literal operand
2046 (PCC_C | PCC_REGISTER), // inCond
2047 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2051 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2052 {PC_OPCODE, NULL, NULL, 0, NULL,
2059 NULL, // from branch
2066 1,0, // dest, bit instruction
2067 0,0, // branch, skip
2068 0, // literal operand
2069 1, // RAM access bit
2070 0, // fast call/return mode select bit
2071 0, // second memory operand
2072 0, // second literal operand
2074 PCC_REGISTER, // inCond
2075 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2078 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2079 {PC_OPCODE, NULL, NULL, 0, NULL,
2086 NULL, // from branch
2093 0,0, // dest, bit instruction
2094 0,0, // branch, skip
2095 0, // literal operand
2096 1, // RAM access bit
2097 0, // fast call/return mode select bit
2098 0, // second memory operand
2099 0, // second literal operand
2101 PCC_REGISTER, // inCond
2102 (PCC_W | PCC_Z | PCC_N), // outCond
2105 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2106 {PC_OPCODE, NULL, NULL, 0, NULL,
2113 NULL, // from branch
2120 1,0, // dest, bit instruction
2121 0,0, // branch, skip
2122 0, // literal operand
2123 1, // RAM access bit
2124 0, // fast call/return mode select bit
2125 0, // second memory operand
2126 0, // second literal operand
2128 (PCC_C | PCC_REGISTER), // inCond
2129 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2132 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2133 {PC_OPCODE, NULL, NULL, 0, NULL,
2140 NULL, // from branch
2147 0,0, // dest, bit instruction
2148 0,0, // branch, skip
2149 0, // literal operand
2150 1, // RAM access bit
2151 0, // fast call/return mode select bit
2152 0, // second memory operand
2153 0, // second literal operand
2155 (PCC_C | PCC_REGISTER), // inCond
2156 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2159 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2160 {PC_OPCODE, NULL, NULL, 0, NULL,
2167 NULL, // from branch
2174 1,0, // dest, bit instruction
2175 0,0, // branch, skip
2176 0, // literal operand
2177 1, // RAM access bit
2178 0, // fast call/return mode select bit
2179 0, // second memory operand
2180 0, // second literal operand
2182 PCC_REGISTER, // inCond
2183 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2187 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2188 {PC_OPCODE, NULL, NULL, 0, NULL,
2195 NULL, // from branch
2202 0,0, // dest, bit instruction
2203 0,0, // branch, skip
2204 0, // literal operand
2205 1, // RAM access bit
2206 0, // fast call/return mode select bit
2207 0, // second memory operand
2208 0, // second literal operand
2210 PCC_REGISTER, // inCond
2211 (PCC_W | PCC_Z | PCC_N), // outCond
2215 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2216 {PC_OPCODE, NULL, NULL, 0, NULL,
2223 NULL, // from branch
2230 0,0, // dest, bit instruction
2231 0,0, // branch, skip
2232 0, // literal operand
2233 1, // RAM access bit
2234 0, // fast call/return mode select bit
2235 0, // second memory operand
2236 0, // second literal operand
2239 PCC_REGISTER , // outCond
2243 pCodeInstruction pic16_pciSUBLW = {
2244 {PC_OPCODE, NULL, NULL, 0, NULL,
2251 NULL, // from branch
2258 0,0, // dest, bit instruction
2259 0,0, // branch, skip
2260 1, // literal operand
2261 0, // RAM access bit
2262 0, // fast call/return mode select bit
2263 0, // second memory operand
2264 0, // second literal operand
2266 (PCC_W | PCC_LITERAL), // inCond
2267 (PCC_W | PCC_STATUS), // outCond
2271 pCodeInstruction pic16_pciSUBFWB = {
2272 {PC_OPCODE, NULL, NULL, 0, NULL,
2279 NULL, // from branch
2286 1,0, // dest, bit instruction
2287 0,0, // branch, skip
2288 0, // literal operand
2289 1, // RAM access bit
2290 0, // fast call/return mode select bit
2291 0, // second memory operand
2292 0, // second literal operand
2294 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2295 (PCC_W | PCC_STATUS), // outCond
2299 pCodeInstruction pic16_pciSUBWF = {
2300 {PC_OPCODE, NULL, NULL, 0, NULL,
2307 NULL, // from branch
2314 1,0, // dest, bit instruction
2315 0,0, // branch, skip
2316 0, // literal operand
2317 1, // RAM access bit
2318 0, // fast call/return mode select bit
2319 0, // second memory operand
2320 0, // second literal operand
2322 (PCC_W | PCC_REGISTER), // inCond
2323 (PCC_REGISTER | PCC_STATUS), // outCond
2327 pCodeInstruction pic16_pciSUBFW = {
2328 {PC_OPCODE, NULL, NULL, 0, NULL,
2335 NULL, // from branch
2342 0,0, // dest, bit instruction
2343 0,0, // branch, skip
2344 0, // literal operand
2345 1, // RAM access bit
2346 0, // fast call/return mode select bit
2347 0, // second memory operand
2348 0, // second literal operand
2350 (PCC_W | PCC_REGISTER), // inCond
2351 (PCC_W | PCC_STATUS), // outCond
2355 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2356 {PC_OPCODE, NULL, NULL, 0, NULL,
2363 NULL, // from branch
2370 1,0, // dest, bit instruction
2371 0,0, // branch, skip
2372 0, // literal operand
2373 1, // RAM access bit
2374 0, // fast call/return mode select bit
2375 0, // second memory operand
2376 0, // second literal operand
2378 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2379 (PCC_REGISTER | PCC_STATUS), // outCond
2383 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2384 {PC_OPCODE, NULL, NULL, 0, NULL,
2391 NULL, // from branch
2398 0,0, // dest, bit instruction
2399 0,0, // branch, skip
2400 0, // literal operand
2401 1, // RAM access bit
2402 0, // fast call/return mode select bit
2403 0, // second memory operand
2404 0, // second literal operand
2406 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2407 (PCC_W | PCC_STATUS), // outCond
2411 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2412 {PC_OPCODE, NULL, NULL, 0, NULL,
2419 NULL, // from branch
2426 1,0, // dest, bit instruction
2427 0,0, // branch, skip
2428 0, // literal operand
2429 1, // RAM access bit
2430 0, // fast call/return mode select bit
2431 0, // second memory operand
2432 0, // second literal operand
2434 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2435 (PCC_REGISTER | PCC_STATUS), // outCond
2439 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2440 {PC_OPCODE, NULL, NULL, 0, NULL,
2447 NULL, // from branch
2454 0,0, // dest, bit instruction
2455 0,0, // branch, skip
2456 0, // literal operand
2457 1, // RAM access bit
2458 0, // fast call/return mode select bit
2459 0, // second memory operand
2460 0, // second literal operand
2462 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2463 (PCC_W | PCC_STATUS), // outCond
2467 pCodeInstruction pic16_pciSWAPF = {
2468 {PC_OPCODE, NULL, NULL, 0, NULL,
2475 NULL, // from branch
2482 1,0, // dest, bit instruction
2483 0,0, // branch, skip
2484 0, // literal operand
2485 1, // RAM access bit
2486 0, // fast call/return mode select bit
2487 0, // second memory operand
2488 0, // second literal operand
2490 (PCC_REGISTER), // inCond
2491 (PCC_REGISTER), // outCond
2495 pCodeInstruction pic16_pciSWAPFW = {
2496 {PC_OPCODE, NULL, NULL, 0, NULL,
2503 NULL, // from branch
2510 0,0, // dest, bit instruction
2511 0,0, // branch, skip
2512 0, // literal operand
2513 1, // RAM access bit
2514 0, // fast call/return mode select bit
2515 0, // second memory operand
2516 0, // second literal operand
2518 (PCC_REGISTER), // inCond
2523 pCodeInstruction pic16_pciTBLRD = { // patch 15
2524 {PC_OPCODE, NULL, NULL, 0, NULL,
2530 NULL, // from branch
2537 0,0, // dest, bit instruction
2538 0,0, // branch, skip
2539 0, // literal operand
2540 0, // RAM access bit
2541 0, // fast call/return mode select bit
2542 0, // second memory operand
2543 0, // second literal operand
2546 PCC_NONE , // outCond
2550 pCodeInstruction pic16_pciTBLRD_POSTINC = { // patch 15
2551 {PC_OPCODE, NULL, NULL, 0, NULL,
2557 NULL, // from branch
2564 0,0, // dest, bit instruction
2565 0,0, // branch, skip
2566 0, // literal operand
2567 0, // RAM access bit
2568 0, // fast call/return mode select bit
2569 0, // second memory operand
2570 0, // second literal operand
2573 PCC_NONE , // outCond
2577 pCodeInstruction pic16_pciTBLRD_POSTDEC = { // patch 15
2578 {PC_OPCODE, NULL, NULL, 0, NULL,
2584 NULL, // from branch
2591 0,0, // dest, bit instruction
2592 0,0, // branch, skip
2593 0, // literal operand
2594 0, // RAM access bit
2595 0, // fast call/return mode select bit
2596 0, // second memory operand
2597 0, // second literal operand
2600 PCC_NONE , // outCond
2604 pCodeInstruction pic16_pciTBLRD_PREINC = { // patch 15
2605 {PC_OPCODE, NULL, NULL, 0, NULL,
2611 NULL, // from branch
2618 0,0, // dest, bit instruction
2619 0,0, // branch, skip
2620 0, // literal operand
2621 0, // RAM access bit
2622 0, // fast call/return mode select bit
2623 0, // second memory operand
2624 0, // second literal operand
2627 PCC_NONE , // outCond
2631 pCodeInstruction pic16_pciTBLWT = { // patch 15
2632 {PC_OPCODE, NULL, NULL, 0, NULL,
2638 NULL, // from branch
2645 0,0, // dest, bit instruction
2646 0,0, // branch, skip
2647 0, // literal operand
2648 0, // RAM access bit
2649 0, // fast call/return mode select bit
2650 0, // second memory operand
2651 0, // second literal operand
2654 PCC_NONE , // outCond
2658 pCodeInstruction pic16_pciTBLWT_POSTINC = { // patch 15
2659 {PC_OPCODE, NULL, NULL, 0, NULL,
2665 NULL, // from branch
2672 0,0, // dest, bit instruction
2673 0,0, // branch, skip
2674 0, // literal operand
2675 0, // RAM access bit
2676 0, // fast call/return mode select bit
2677 0, // second memory operand
2678 0, // second literal operand
2681 PCC_NONE , // outCond
2685 pCodeInstruction pic16_pciTBLWT_POSTDEC = { // patch 15
2686 {PC_OPCODE, NULL, NULL, 0, NULL,
2692 NULL, // from branch
2699 0,0, // dest, bit instruction
2700 0,0, // branch, skip
2701 0, // literal operand
2702 0, // RAM access bit
2703 0, // fast call/return mode select bit
2704 0, // second memory operand
2705 0, // second literal operand
2708 PCC_NONE , // outCond
2712 pCodeInstruction pic16_pciTBLWT_PREINC = { // patch 15
2713 {PC_OPCODE, NULL, NULL, 0, NULL,
2719 NULL, // from branch
2726 0,0, // dest, bit instruction
2727 0,0, // branch, skip
2728 0, // literal operand
2729 0, // RAM access bit
2730 0, // fast call/return mode select bit
2731 0, // second memory operand
2732 0, // second literal operand
2735 PCC_NONE , // outCond
2739 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2740 {PC_OPCODE, NULL, NULL, 0, NULL,
2747 NULL, // from branch
2754 0,0, // dest, bit instruction
2755 1,1, // branch, skip
2756 0, // literal operand
2757 1, // RAM access bit
2758 0, // fast call/return mode select bit
2759 0, // second memory operand
2760 0, // second literal operand
2762 PCC_REGISTER, // inCond
2763 PCC_NONE, // outCond
2767 pCodeInstruction pic16_pciXORWF = {
2768 {PC_OPCODE, NULL, NULL, 0, NULL,
2775 NULL, // from branch
2782 1,0, // dest, bit instruction
2783 0,0, // branch, skip
2784 0, // literal operand
2785 1, // RAM access bit
2786 0, // fast call/return mode select bit
2787 0, // second memory operand
2788 0, // second literal operand
2790 (PCC_W | PCC_REGISTER), // inCond
2791 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2795 pCodeInstruction pic16_pciXORFW = {
2796 {PC_OPCODE, NULL, NULL, 0, NULL,
2803 NULL, // from branch
2810 0,0, // dest, bit instruction
2811 0,0, // branch, skip
2812 0, // literal operand
2813 1, // RAM access bit
2814 0, // fast call/return mode select bit
2815 0, // second memory operand
2816 0, // second literal operand
2818 (PCC_W | PCC_REGISTER), // inCond
2819 (PCC_W | PCC_Z | PCC_N), // outCond
2823 pCodeInstruction pic16_pciXORLW = {
2824 {PC_OPCODE, NULL, NULL, 0, NULL,
2831 NULL, // from branch
2838 0,0, // dest, bit instruction
2839 0,0, // branch, skip
2840 1, // literal operand
2841 1, // RAM access bit
2842 0, // fast call/return mode select bit
2843 0, // second memory operand
2844 0, // second literal operand
2846 (PCC_W | PCC_LITERAL), // inCond
2847 (PCC_W | PCC_Z | PCC_N), // outCond
2852 pCodeInstruction pic16_pciBANKSEL = {
2853 {PC_OPCODE, NULL, NULL, 0, NULL,
2859 NULL, // from branch
2866 0,0, // dest, bit instruction
2867 0,0, // branch, skip
2868 0, // literal operand
2869 0, // RAM access bit
2870 0, // fast call/return mode select bit
2871 0, // second memory operand
2872 0, // second literal operand
2875 PCC_NONE, // outCond
2880 #define MAX_PIC16MNEMONICS 100
2881 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2883 extern set *externs;
2884 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2885 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2887 void pic16_pCodeInitRegisters(void)
2889 static int initialized=0;
2896 pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2897 pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2898 pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2899 pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2900 pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2901 pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2902 pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2904 pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2905 pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2906 pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2908 pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2909 pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2910 pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2911 pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2913 pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2914 pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2915 pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2916 pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2917 pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2918 pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2920 pic16_stackpnt_lo = &pic16_pc_fsr1l;
2921 pic16_stackpnt_hi = &pic16_pc_fsr1h;
2922 pic16_stack_postdec = &pic16_pc_postdec1;
2923 pic16_stack_postinc = &pic16_pc_postinc1;
2924 pic16_stack_preinc = &pic16_pc_preinc1;
2925 pic16_stack_plusw = &pic16_pc_plusw1;
2927 pic16_framepnt_lo = &pic16_pc_fsr2l;
2928 pic16_framepnt_hi = &pic16_pc_fsr2h;
2929 pic16_frame_postdec = &pic16_pc_postdec2;
2930 pic16_frame_postinc = &pic16_pc_postinc2;
2931 pic16_frame_preinc = &pic16_pc_preinc2;
2932 pic16_frame_plusw = &pic16_pc_plusw2;
2934 pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
2935 pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
2936 pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
2937 pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
2938 pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
2940 pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
2941 pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
2942 pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
2943 pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
2944 pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
2946 pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
2947 pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
2948 pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
2949 pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
2950 pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
2952 pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
2953 pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
2956 pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
2957 pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
2958 pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
2959 pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
2962 pic16_pc_status.rIdx = IDX_STATUS;
2963 pic16_pc_intcon.rIdx = IDX_INTCON;
2964 pic16_pc_pcl.rIdx = IDX_PCL;
2965 pic16_pc_pclath.rIdx = IDX_PCLATH;
2966 pic16_pc_pclatu.rIdx = IDX_PCLATU;
2967 pic16_pc_wreg.rIdx = IDX_WREG;
2968 pic16_pc_bsr.rIdx = IDX_BSR;
2970 pic16_pc_tosl.rIdx = IDX_TOSL;
2971 pic16_pc_tosh.rIdx = IDX_TOSH;
2972 pic16_pc_tosu.rIdx = IDX_TOSU;
2974 pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
2975 pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
2976 pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
2977 pic16_pc_tablat.rIdx = IDX_TABLAT;
2979 pic16_pc_fsr0l.rIdx = IDX_FSR0L;
2980 pic16_pc_fsr0h.rIdx = IDX_FSR0H;
2981 pic16_pc_fsr1l.rIdx = IDX_FSR1L;
2982 pic16_pc_fsr1h.rIdx = IDX_FSR1H;
2983 pic16_pc_fsr2l.rIdx = IDX_FSR2L;
2984 pic16_pc_fsr2h.rIdx = IDX_FSR2H;
2985 pic16_pc_indf0.rIdx = IDX_INDF0;
2986 pic16_pc_postinc0.rIdx = IDX_POSTINC0;
2987 pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
2988 pic16_pc_preinc0.rIdx = IDX_PREINC0;
2989 pic16_pc_plusw0.rIdx = IDX_PLUSW0;
2990 pic16_pc_indf1.rIdx = IDX_INDF1;
2991 pic16_pc_postinc1.rIdx = IDX_POSTINC1;
2992 pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
2993 pic16_pc_preinc1.rIdx = IDX_PREINC1;
2994 pic16_pc_plusw1.rIdx = IDX_PLUSW1;
2995 pic16_pc_indf2.rIdx = IDX_INDF2;
2996 pic16_pc_postinc2.rIdx = IDX_POSTINC2;
2997 pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
2998 pic16_pc_preinc2.rIdx = IDX_PREINC2;
2999 pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3000 pic16_pc_prodl.rIdx = IDX_PRODL;
3001 pic16_pc_prodh.rIdx = IDX_PRODH;
3003 pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3004 pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3005 pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3007 pic16_pc_kzero.rIdx = IDX_KZ;
3008 pic16_pc_wsave.rIdx = IDX_WSAVE;
3009 pic16_pc_ssave.rIdx = IDX_SSAVE;
3011 pic16_pc_eecon1.rIdx = IDX_EECON1;
3012 pic16_pc_eecon2.rIdx = IDX_EECON2;
3013 pic16_pc_eedata.rIdx = IDX_EEDATA;
3014 pic16_pc_eeadr.rIdx = IDX_EEADR;
3017 pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3018 pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3020 pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3021 pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3023 /* probably should put this in a separate initialization routine */
3024 pb_dead_pcodes = newpBlock();
3028 /*-----------------------------------------------------------------*/
3029 /* mnem2key - convert a pic mnemonic into a hash key */
3030 /* (BTW - this spreads the mnemonics quite well) */
3032 /*-----------------------------------------------------------------*/
3034 static int mnem2key(unsigned char const *mnem)
3043 key += toupper(*mnem++) +1;
3047 return (key & 0x1f);
3051 void pic16initMnemonics(void)
3056 pCodeInstruction *pci;
3058 if(mnemonics_initialized)
3061 // NULL out the array before making the assignments
3062 // since we check the array contents below this initialization.
3064 for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3065 pic16Mnemonics[i] = NULL;
3068 pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3069 pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3070 pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3071 pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3072 pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3073 pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3074 pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3075 pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3076 pic16Mnemonics[POC_BC] = &pic16_pciBC;
3077 pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3078 pic16Mnemonics[POC_BN] = &pic16_pciBN;
3079 pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3080 pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3081 pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3082 pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3083 pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3084 pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3085 pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3086 pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3087 pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3088 pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3089 pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3090 pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3091 pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3092 pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3093 pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3094 pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3095 pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3096 pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3097 pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3098 pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3099 pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3100 pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3101 pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3102 pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3103 pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3104 pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3105 pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3106 pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3107 pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3108 pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3109 pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3110 pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3111 pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3112 pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3113 pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3114 pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3115 pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3116 pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3117 pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3118 pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3119 pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3120 pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3121 pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3122 pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3123 pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3124 pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3125 pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3126 pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3127 pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3128 pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3129 pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3130 pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3131 pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3132 pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3133 pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3134 pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3135 pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3136 pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3137 pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3138 pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3139 pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3140 pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3141 pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3142 pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3143 pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3144 pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3145 pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3146 pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3147 pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3148 pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3149 pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3150 pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3151 pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3152 pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3153 pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3154 pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3155 pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3156 pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3157 pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3158 pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3159 pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3160 pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3161 pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3163 for(i=0; i<MAX_PIC16MNEMONICS; i++)
3164 if(pic16Mnemonics[i])
3165 hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3166 pci = hTabFirstItem(pic16MnemonicsHash, &key);
3169 DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3170 pci = hTabNextItem(pic16MnemonicsHash, &key);
3173 mnemonics_initialized = 1;
3176 int pic16_getpCodePeepCommand(char *cmd);
3178 int pic16_getpCode(char *mnem,unsigned dest)
3181 pCodeInstruction *pci;
3182 int key = mnem2key((unsigned char *)mnem);
3184 if(!mnemonics_initialized)
3185 pic16initMnemonics();
3187 pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3191 if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3192 if((pci->num_ops <= 1)
3193 || (pci->isModReg == dest)
3195 || (pci->num_ops <= 2 && pci->isAccess)
3196 || (pci->num_ops <= 2 && pci->isFastCall)
3197 || (pci->num_ops <= 2 && pci->is2MemOp)
3198 || (pci->num_ops <= 2 && pci->is2LitOp) )
3202 pci = hTabNextItemWK (pic16MnemonicsHash);
3209 /*-----------------------------------------------------------------*
3210 * pic16initpCodePeepCommands
3212 *-----------------------------------------------------------------*/
3213 void pic16initpCodePeepCommands(void)
3221 hTabAddItem(&pic16pCodePeepCommandsHash,
3222 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3224 } while (peepCommands[i].cmd);
3226 pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3229 //fprintf(stderr, "peep command %s key %d\n",pcmd->cmd,pcmd->id);
3230 pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3235 /*-----------------------------------------------------------------
3238 *-----------------------------------------------------------------*/
3240 int pic16_getpCodePeepCommand(char *cmd)
3244 int key = mnem2key((unsigned char *)cmd);
3247 pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3250 // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3251 if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3255 pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3262 static char getpBlock_dbName(pBlock *pb)
3268 return pb->cmemmap->dbName;
3272 void pic16_pBlockConvert2ISR(pBlock *pb)
3276 if(pb->cmemmap)pb->cmemmap = NULL;
3280 if(pic16_pcode_verbose)
3281 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3284 void pic16_pBlockConvert2Absolute(pBlock *pb)
3287 if(pb->cmemmap)pb->cmemmap = NULL;
3291 if(pic16_pcode_verbose)
3292 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3295 /*-----------------------------------------------------------------*/
3296 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all */
3297 /* instances to the front of the doubly linked */
3298 /* list of pBlocks */
3299 /*-----------------------------------------------------------------*/
3301 void pic16_movepBlock2Head(char dbName)
3306 /* this can happen in sources without code,
3307 * only variable definitions */
3308 if(!the_pFile)return;
3310 pb = the_pFile->pbHead;
3314 if(getpBlock_dbName(pb) == dbName) {
3315 pBlock *pbn = pb->next;
3316 pb->next = the_pFile->pbHead;
3317 the_pFile->pbHead->prev = pb;
3318 the_pFile->pbHead = pb;
3321 pb->prev->next = pbn;
3323 // If the pBlock that we just moved was the last
3324 // one in the link of all of the pBlocks, then we
3325 // need to point the tail to the block just before
3326 // the one we moved.
3327 // Note: if pb->next is NULL, then pb must have
3328 // been the last pBlock in the chain.
3331 pbn->prev = pb->prev;
3333 the_pFile->pbTail = pb->prev;
3344 void pic16_copypCode(FILE *of, char dbName)
3348 if(!of || !the_pFile)
3351 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3352 if(getpBlock_dbName(pb) == dbName) {
3353 // fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3355 pic16_printpBlock(of,pb);
3360 void pic16_pcode_test(void)
3363 DFPRINTF((stderr,"pcode is alive!\n"));
3373 /* create the file name */
3374 strcpy(buffer,dstFileName);
3375 strcat(buffer,".p");
3377 if( !(pFile = fopen(buffer, "w" ))) {
3378 werror(E_FILE_OPEN_ERR,buffer);
3382 fprintf(pFile,"pcode dump\n\n");
3384 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3385 fprintf(pFile,"\n\tNew pBlock\n\n");
3387 fprintf(pFile,"%s",pb->cmemmap->sname);
3389 fprintf(pFile,"internal pblock");
3391 fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3392 pic16_printpBlock(pFile,pb);
3398 unsigned long pic16_countInstructions(void)
3402 unsigned long isize=0;
3404 if(!the_pFile)return -1;
3406 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3407 for(pc = pb->pcHead; pc; pc = pc->next) {
3408 if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3415 /*-----------------------------------------------------------------*/
3416 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg- */
3417 /* ister, RegCond will return the bit being referenced. */
3419 /* fixme - why not just OR in the pcop bit field */
3420 /*-----------------------------------------------------------------*/
3422 static int RegCond(pCodeOp *pcop)
3428 if(!pcop->name)return 0;
3430 if(pcop->type == PO_GPR_BIT && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3431 switch(PCORB(pcop)->bit) {
3446 /*-----------------------------------------------------------------*/
3447 /* pic16_newpCode - create and return a newly initialized pCode */
3449 /* fixme - rename this */
3451 /* The purpose of this routine is to create a new Instruction */
3452 /* pCode. This is called by gen.c while the assembly code is being */
3456 /* PIC_OPCODE op - the assembly instruction we wish to create. */
3457 /* (note that the op is analogous to but not the */
3458 /* same thing as the opcode of the instruction.) */
3459 /* pCdoeOp *pcop - pointer to the operand of the instruction. */
3462 /* a pointer to the new malloc'd pCode is returned. */
3466 /*-----------------------------------------------------------------*/
3467 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3469 pCodeInstruction *pci ;
3471 if(!mnemonics_initialized)
3472 pic16initMnemonics();
3474 pci = Safe_calloc(1, sizeof(pCodeInstruction));
3476 if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3477 memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3480 if(pci->inCond & PCC_EXAMINE_PCOP)
3481 pci->inCond |= RegCond(pcop);
3483 if(pci->outCond & PCC_EXAMINE_PCOP)
3484 pci->outCond |= RegCond(pcop);
3486 pci->pc.prev = pci->pc.next = NULL;
3487 return (pCode *)pci;
3490 fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3496 /*-----------------------------------------------------------------*/
3497 /* pic16_newpCodeWild - create a "wild" as in wild card pCode */
3499 /* Wild pcodes are used during the peep hole optimizer to serve */
3500 /* as place holders for any instruction. When a snippet of code is */
3501 /* compared to a peep hole rule, the wild card opcode will match */
3502 /* any instruction. However, the optional operand and label are */
3503 /* additional qualifiers that must also be matched before the */
3504 /* line (of assembly code) is declared matched. Note that the */
3505 /* operand may be wild too. */
3507 /* Note, a wild instruction is specified just like a wild var: */
3508 /* %4 ; A wild instruction, */
3509 /* See the peeph.def file for additional examples */
3511 /*-----------------------------------------------------------------*/
3513 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3518 pcw = Safe_calloc(1,sizeof(pCodeWild));
3520 pcw->pci.pc.type = PC_WILD;
3521 pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3522 pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3523 pcw->pci.pc.pb = NULL;
3525 // pcw->pci.pc.analyze = genericAnalyze;
3526 pcw->pci.pc.destruct = genericDestruct;
3527 pcw->pci.pc.print = genericPrint;
3529 pcw->id = pCodeID; // this is the 'n' in %n
3530 pcw->operand = optional_operand;
3531 pcw->label = optional_label;
3533 pcw->mustBeBitSkipInst = 0;
3534 pcw->mustNotBeBitSkipInst = 0;
3535 pcw->invertBitSkipInst = 0;
3537 return ( (pCode *)pcw);
3541 /*-----------------------------------------------------------------*/
3542 /* newPcodeInlineP - create a new pCode from a char string */
3543 /*-----------------------------------------------------------------*/
3546 pCode *pic16_newpCodeInlineP(char *cP)
3551 pcc = Safe_calloc(1,sizeof(pCodeComment));
3553 pcc->pc.type = PC_INLINE;
3554 pcc->pc.prev = pcc->pc.next = NULL;
3555 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3558 // pcc->pc.analyze = genericAnalyze;
3559 pcc->pc.destruct = genericDestruct;
3560 pcc->pc.print = genericPrint;
3563 pcc->comment = Safe_strdup(cP);
3565 pcc->comment = NULL;
3567 return ( (pCode *)pcc);
3571 /*-----------------------------------------------------------------*/
3572 /* newPcodeCharP - create a new pCode from a char string */
3573 /*-----------------------------------------------------------------*/
3575 pCode *pic16_newpCodeCharP(char *cP)
3580 pcc = Safe_calloc(1,sizeof(pCodeComment));
3582 pcc->pc.type = PC_COMMENT;
3583 pcc->pc.prev = pcc->pc.next = NULL;
3584 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3587 // pcc->pc.analyze = genericAnalyze;
3588 pcc->pc.destruct = genericDestruct;
3589 pcc->pc.print = genericPrint;
3592 pcc->comment = Safe_strdup(cP);
3594 pcc->comment = NULL;
3596 return ( (pCode *)pcc);
3600 /*-----------------------------------------------------------------*/
3601 /* pic16_newpCodeFunction - */
3602 /*-----------------------------------------------------------------*/
3605 pCode *pic16_newpCodeFunction(char *mod,char *f)
3609 pcf = Safe_calloc(1,sizeof(pCodeFunction));
3611 pcf->pc.type = PC_FUNCTION;
3612 pcf->pc.prev = pcf->pc.next = NULL;
3613 //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3616 // pcf->pc.analyze = genericAnalyze;
3617 pcf->pc.destruct = genericDestruct;
3618 pcf->pc.print = pCodePrintFunction;
3624 pcf->modname = Safe_calloc(1,strlen(mod)+1);
3625 strcpy(pcf->modname,mod);
3627 pcf->modname = NULL;
3630 pcf->fname = Safe_calloc(1,strlen(f)+1);
3631 strcpy(pcf->fname,f);
3635 pcf->stackusage = 0;
3637 return ( (pCode *)pcf);
3640 /*-----------------------------------------------------------------*/
3641 /* pic16_newpCodeFlow */
3642 /*-----------------------------------------------------------------*/
3643 static void destructpCodeFlow(pCode *pc)
3645 if(!pc || !isPCFL(pc))
3652 pic16_unlinkpCode(pc);
3654 deleteSet(&PCFL(pc)->registers);
3655 deleteSet(&PCFL(pc)->from);
3656 deleteSet(&PCFL(pc)->to);
3658 /* Instead of deleting the memory used by this pCode, mark
3659 * the object as bad so that if there's a pointer to this pCode
3660 * dangling around somewhere then (hopefully) when the type is
3661 * checked we'll catch it.
3665 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3671 pCode *pic16_newpCodeFlow(void )
3675 //_ALLOC(pcflow,sizeof(pCodeFlow));
3676 pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3678 pcflow->pc.type = PC_FLOW;
3679 pcflow->pc.prev = pcflow->pc.next = NULL;
3680 pcflow->pc.pb = NULL;
3682 // pcflow->pc.analyze = genericAnalyze;
3683 pcflow->pc.destruct = destructpCodeFlow;
3684 pcflow->pc.print = genericPrint;
3686 pcflow->pc.seq = GpcFlowSeq++;
3688 pcflow->from = pcflow->to = NULL;
3690 pcflow->inCond = PCC_NONE;
3691 pcflow->outCond = PCC_NONE;
3693 pcflow->firstBank = -1;
3694 pcflow->lastBank = -1;
3696 pcflow->FromConflicts = 0;
3697 pcflow->ToConflicts = 0;
3701 pcflow->registers = newSet();
3703 return ( (pCode *)pcflow);
3707 /*-----------------------------------------------------------------*/
3708 /*-----------------------------------------------------------------*/
3709 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3711 pCodeFlowLink *pcflowLink;
3713 pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3715 pcflowLink->pcflow = pcflow;
3716 pcflowLink->bank_conflict = 0;
3721 /*-----------------------------------------------------------------*/
3722 /* pic16_newpCodeCSource - create a new pCode Source Symbol */
3723 /*-----------------------------------------------------------------*/
3725 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3730 pccs = Safe_calloc(1,sizeof(pCodeCSource));
3732 pccs->pc.type = PC_CSOURCE;
3733 pccs->pc.prev = pccs->pc.next = NULL;
3736 pccs->pc.destruct = genericDestruct;
3737 pccs->pc.print = genericPrint;
3739 pccs->line_number = ln;
3741 pccs->line = Safe_strdup(l);
3746 pccs->file_name = Safe_strdup(f);
3748 pccs->file_name = NULL;
3750 return ( (pCode *)pccs);
3755 /*******************************************************************/
3756 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive */
3757 /* added by VR 6-Jun-2003 */
3758 /*******************************************************************/
3760 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3767 pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3768 pcad->pci.pc.type = PC_ASMDIR;
3769 pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3770 pcad->pci.pc.pb = NULL;
3771 pcad->pci.isize = 2;
3772 pcad->pci.pc.destruct = genericDestruct;
3773 pcad->pci.pc.print = genericPrint;
3775 if(asdir && *asdir) {
3777 while(isspace((unsigned char)*asdir))asdir++; // strip any white space from the beginning
3779 pcad->directive = Safe_strdup( asdir );
3782 va_start(ap, argfmt);
3784 memset(buffer, 0, sizeof(buffer));
3785 if(argfmt && *argfmt)
3786 vsprintf(buffer, argfmt, ap);
3790 while(isspace((unsigned char)*lbp))lbp++;
3793 pcad->arg = Safe_strdup( lbp );
3795 return ((pCode *)pcad);
3798 /*-----------------------------------------------------------------*/
3799 /* pCodeLabelDestruct - free memory used by a label. */
3800 /*-----------------------------------------------------------------*/
3801 static void pCodeLabelDestruct(pCode *pc)
3807 pic16_unlinkpCode(pc);
3809 // if((pc->type == PC_LABEL) && PCL(pc)->label)
3810 // Safe_free(PCL(pc)->label);
3812 /* Instead of deleting the memory used by this pCode, mark
3813 * the object as bad so that if there's a pointer to this pCode
3814 * dangling around somewhere then (hopefully) when the type is
3815 * checked we'll catch it.
3819 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3825 pCode *pic16_newpCodeLabel(char *name, int key)
3831 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3833 pcl->pc.type = PC_LABEL;
3834 pcl->pc.prev = pcl->pc.next = NULL;
3835 //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3838 // pcl->pc.analyze = genericAnalyze;
3839 pcl->pc.destruct = pCodeLabelDestruct;
3840 pcl->pc.print = pCodePrintLabel;
3847 sprintf(s,"_%05d_DS_",key);
3852 pcl->label = Safe_strdup(s);
3854 // if(pic16_pcode_verbose)
3855 // fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3858 return ( (pCode *)pcl);
3862 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3864 pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3868 return ( (pCode *)pcl );
3871 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3875 pci = Safe_calloc(1, sizeof(pCodeInfo));
3876 pci->pci.pc.type = PC_INFO;
3877 pci->pci.pc.prev = pci->pci.pc.next = NULL;
3878 pci->pci.pc.pb = NULL;
3879 pci->pci.label = NULL;
3881 pci->pci.pc.destruct = genericDestruct;
3882 pci->pci.pc.print = genericPrint;
3887 return ((pCode *)pci);
3891 /*-----------------------------------------------------------------*/
3892 /* newpBlock - create and return a pointer to a new pBlock */
3893 /*-----------------------------------------------------------------*/
3894 static pBlock *newpBlock(void)
3899 PpB = Safe_calloc(1,sizeof(pBlock) );
3900 PpB->next = PpB->prev = NULL;
3902 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3903 PpB->tregisters = NULL;
3905 PpB->FlowTree = NULL;
3911 /*-----------------------------------------------------------------*/
3912 /* pic16_newpCodeChain - create a new chain of pCodes */
3913 /*-----------------------------------------------------------------*
3915 * This function will create a new pBlock and the pointer to the
3916 * pCode that is passed in will be the first pCode in the block.
3917 *-----------------------------------------------------------------*/
3920 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3923 pBlock *pB = newpBlock();
3925 pB->pcHead = pB->pcTail = pc;
3934 /*-----------------------------------------------------------------*/
3935 /* pic16_newpCodeOpLabel - Create a new label given the key */
3936 /* Note, a negative key means that the label is part of wild card */
3937 /* (and hence a wild card label) used in the pCodePeep */
3938 /* optimizations). */
3939 /*-----------------------------------------------------------------*/
3941 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
3944 static int label_key=-1;
3948 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
3949 pcop->type = PO_LABEL;
3954 sprintf(s=buffer,"_%05d_DS_",key);
3956 s = name, key = label_key--;
3959 pcop->name = Safe_strdup(s);
3961 ((pCodeOpLabel *)pcop)->key = key;
3963 //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
3967 /*-----------------------------------------------------------------*/
3968 /*-----------------------------------------------------------------*/
3969 pCodeOp *pic16_newpCodeOpLit(int lit)
3975 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
3976 pcop->type = PO_LITERAL;
3980 sprintf(s,"0x%02hhx", (unsigned char)lit);
3982 // sprintf(s, "%i", lit);
3985 pcop->name = Safe_strdup(s);
3987 ((pCodeOpLit *)pcop)->lit = lit;
3992 /* Allow for 12 bit literals, required for LFSR */
3993 pCodeOp *pic16_newpCodeOpLit12(int lit)
3999 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4000 pcop->type = PO_LITERAL;
4004 sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4006 // sprintf(s, "%i", lit);
4009 pcop->name = Safe_strdup(s);
4011 ((pCodeOpLit *)pcop)->lit = lit;
4016 /*-----------------------------------------------------------------*/
4017 /*-----------------------------------------------------------------*/
4018 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4020 char *s = buffer, tbuf[256], *tb=tbuf;
4024 tb = pic16_get_op(arg2, NULL, 0);
4025 pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4026 pcop->type = PO_LITERAL;
4030 sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4032 pcop->name = Safe_strdup(s);
4035 ((pCodeOpLit2 *)pcop)->lit = lit;
4036 ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4041 /*-----------------------------------------------------------------*/
4042 /*-----------------------------------------------------------------*/
4043 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4047 pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4048 pcop->type = PO_IMMEDIATE;
4050 regs *r = pic16_dirregWithName(name);
4051 pcop->name = Safe_strdup(name);
4055 // fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4056 PCOI(pcop)->rIdx = r->rIdx;
4058 // fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4059 PCOI(pcop)->rIdx = -1;
4061 // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4064 PCOI(pcop)->rIdx = -1;
4067 PCOI(pcop)->index = index;
4068 PCOI(pcop)->offset = offset;
4069 PCOI(pcop)->_const = code_space;
4074 /*-----------------------------------------------------------------*/
4075 /*-----------------------------------------------------------------*/
4076 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4082 if(!pcwb || !subtype) {
4083 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4087 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4088 pcop->type = PO_WILD;
4089 sprintf(s,"%%%d",id);
4090 pcop->name = Safe_strdup(s);
4092 PCOW(pcop)->id = id;
4093 PCOW(pcop)->pcwb = pcwb;
4094 PCOW(pcop)->subtype = subtype;
4095 PCOW(pcop)->matched = NULL;
4097 PCOW(pcop)->pcop2 = NULL;
4102 /*-----------------------------------------------------------------*/
4103 /*-----------------------------------------------------------------*/
4104 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4110 if(!pcwb || !subtype || !subtype2) {
4111 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4115 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4116 pcop->type = PO_WILD;
4117 sprintf(s,"%%%d",id);
4118 pcop->name = Safe_strdup(s);
4120 PCOW(pcop)->id = id;
4121 PCOW(pcop)->pcwb = pcwb;
4122 PCOW(pcop)->subtype = subtype;
4123 PCOW(pcop)->matched = NULL;
4125 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4127 if(!subtype2->name) {
4128 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4129 PCOW2(pcop)->pcop.type = PO_WILD;
4130 sprintf(s, "%%%d", id2);
4131 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4132 PCOW2(pcop)->id = id2;
4133 PCOW2(pcop)->subtype = subtype2;
4135 // fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4136 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4138 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4140 // fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4141 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4150 /*-----------------------------------------------------------------*/
4151 /*-----------------------------------------------------------------*/
4152 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4156 pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4157 pcop->type = PO_GPR_BIT;
4159 pcop->name = Safe_strdup(s);
4163 PCORB(pcop)->bit = bit;
4164 PCORB(pcop)->inBitSpace = inBitSpace;
4165 PCORB(pcop)->subtype = subt;
4167 /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4168 PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4169 // fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4170 // PCOR(pcop)->rIdx = 0;
4174 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4176 return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4177 bit, 0, PO_GPR_REGISTER);
4181 /*-----------------------------------------------------------------*
4182 * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4184 * If rIdx >=0 then a specific register from the set of registers
4185 * will be selected. If rIdx <0, then a new register will be searched
4187 *-----------------------------------------------------------------*/
4189 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4194 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4199 r = pic16_regWithIdx(rIdx);
4201 r = pic16_allocWithIdx(rIdx);
4203 r = pic16_findFreeReg(REG_GPR);
4206 fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4207 __FUNCTION__, __LINE__);
4212 PCOR(pcop)->rIdx = rIdx;
4214 pcop->type = PCOR(pcop)->r->pc_type;
4219 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4224 pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4227 r = pic16_findFreeReg(REG_GPR);
4230 if(!bitVectBitValue(bv, r->rIdx)) {
4232 PCOR(pcop)->rIdx = r->rIdx;
4233 pcop->type = r->pc_type;
4237 r = pic16_findFreeRegNext(REG_GPR, r);
4245 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4250 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4251 PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4252 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4253 pcop->type = PCOR(pcop)->r->pc_type;
4254 pcop->name = PCOR(pcop)->r->name;
4256 // if(pic16_pcode_verbose) {
4257 // fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4258 // __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4264 /*-----------------------------------------------------------------*/
4265 /*-----------------------------------------------------------------*/
4266 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4270 pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4273 pcop->key = Safe_strdup( key );
4275 return (PCOP(pcop));
4278 /*-----------------------------------------------------------------*/
4279 /*-----------------------------------------------------------------*/
4280 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4282 pCodeOpLocalReg *pcop;
4284 pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4288 return (PCOP(pcop));
4292 /*-----------------------------------------------------------------*/
4293 /*-----------------------------------------------------------------*/
4295 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4302 pcop = pic16_newpCodeOpBit(name, -1,0, type);
4306 pcop = pic16_newpCodeOpLit(-1);
4310 pcop = pic16_newpCodeOpLabel(NULL,-1);
4313 pcop = pic16_newpCodeOpReg(-1);
4316 case PO_GPR_REGISTER:
4318 pcop = pic16_newpCodeOpRegFromStr(name);
4320 pcop = pic16_newpCodeOpReg(-1);
4324 assert( !"Cannot create PO_TWO_OPS from string!" );
4329 pcop = Safe_calloc(1,sizeof(pCodeOp) );
4332 pcop->name = Safe_strdup(name);
4340 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4342 pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4343 pcop2->pcop.type = PO_TWO_OPS;
4349 /* This is a multiple of two as gpasm pads DB directives to even length,
4350 * thus the data would be interleaved with \0 bytes...
4351 * This is a multiple of three in order to have arrays of 3-byte pointers
4352 * continuously in memory (without 0-padding at the lines' end).
4353 * This is rather 12 than 6 in order not to split up 4-byte data types
4354 * in arrays right in the middle of a 4-byte word. */
4355 #define DB_ITEMS_PER_LINE 12
4357 typedef struct DBdata
4364 static int DBd_init = -1;
4366 /*-----------------------------------------------------------------*/
4367 /* Initialiase "DB" data buffer */
4368 /*-----------------------------------------------------------------*/
4369 void pic16_initDB(void)
4375 /*-----------------------------------------------------------------*/
4376 /* Flush pending "DB" data to a pBlock */
4378 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4379 /*-----------------------------------------------------------------*/
4380 void pic16_flushDB(char ptype, void *p)
4384 pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4387 fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4390 fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4394 DBd.buffer[0] = '\0';
4399 /*-----------------------------------------------------------------*/
4400 /* Add "DB" directives to a pBlock */
4401 /*-----------------------------------------------------------------*/
4402 void pic16_emitDB(int c, char ptype, void *p)
4407 // we need to initialize
4410 DBd.buffer[0] = '\0';
4413 l = strlen(DBd.buffer);
4414 sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4416 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4419 if (DBd.count>= DB_ITEMS_PER_LINE)
4420 pic16_flushDB(ptype, p);
4423 void pic16_emitDS(char *s, char ptype, void *p)
4428 // we need to initialize
4431 DBd.buffer[0] = '\0';
4434 l = strlen(DBd.buffer);
4435 sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4437 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4439 DBd.count++; //=strlen(s);
4440 if (DBd.count>=DB_ITEMS_PER_LINE)
4441 pic16_flushDB(ptype, p);
4445 /*-----------------------------------------------------------------*/
4446 /*-----------------------------------------------------------------*/
4447 void pic16_pCodeConstString(char *name, char *value, unsigned length)
4451 static set *emittedSymbols = NULL;
4456 /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4457 if (emittedSymbols) {
4458 /* scan set for name */
4459 for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4461 if (!strcmp (item,name)) {
4462 //fprintf (stderr, "%s already emitted\n", name);
4467 addSet (&emittedSymbols, Safe_strdup (name));
4469 //fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value);
4471 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4473 pic16_addpBlock(pb);
4475 // sprintf(buffer,"; %s = ", name);
4476 // strcat(buffer, value);
4477 // fputs(buffer, stderr);
4479 // pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4480 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4483 pic16_emitDB(*value++, 'p', (void *)pb);
4485 pic16_flushDB('p', (void *)pb);
4488 /*-----------------------------------------------------------------*/
4489 /*-----------------------------------------------------------------*/
4491 static void pCodeReadCodeTable(void)
4495 fprintf(stderr, " %s\n",__FUNCTION__);
4497 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4499 pic16_addpBlock(pb);
4501 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4502 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4503 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4504 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4506 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4507 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4508 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4509 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4514 /*-----------------------------------------------------------------*/
4515 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */
4516 /*-----------------------------------------------------------------*/
4517 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4524 /* If this is the first pcode to be added to a block that
4525 * was initialized with a NULL pcode, then go ahead and
4526 * make this pcode the head and tail */
4527 pb->pcHead = pb->pcTail = pc;
4530 pb->pcTail->next = pc;
4532 pc->prev = pb->pcTail;
4539 /*-----------------------------------------------------------------*/
4540 /* pic16_addpBlock - place a pBlock into the pFile */
4541 /*-----------------------------------------------------------------*/
4542 void pic16_addpBlock(pBlock *pb)
4544 // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4547 /* First time called, we'll pass through here. */
4548 //_ALLOC(the_pFile,sizeof(pFile));
4549 the_pFile = Safe_calloc(1,sizeof(pFile));
4550 the_pFile->pbHead = the_pFile->pbTail = pb;
4551 the_pFile->functions = NULL;
4555 the_pFile->pbTail->next = pb;
4556 pb->prev = the_pFile->pbTail;
4558 the_pFile->pbTail = pb;
4561 /*-----------------------------------------------------------------*/
4562 /* removepBlock - remove a pBlock from the pFile */
4563 /*-----------------------------------------------------------------*/
4564 static void removepBlock(pBlock *pb)
4572 //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4574 for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4577 if(pbs == the_pFile->pbHead)
4578 the_pFile->pbHead = pbs->next;
4580 if (pbs == the_pFile->pbTail)
4581 the_pFile->pbTail = pbs->prev;
4584 pbs->next->prev = pbs->prev;
4587 pbs->prev->next = pbs->next;
4594 fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4598 /*-----------------------------------------------------------------*/
4599 /* printpCode - write the contents of a pCode to a file */
4600 /*-----------------------------------------------------------------*/
4601 static void printpCode(FILE *of, pCode *pc)
4612 fprintf(of,"warning - unable to print pCode\n");
4615 /*-----------------------------------------------------------------*/
4616 /* pic16_printpBlock - write the contents of a pBlock to a file */
4617 /*-----------------------------------------------------------------*/
4618 void pic16_printpBlock(FILE *of, pBlock *pb)
4626 for(pc = pb->pcHead; pc; pc = pc->next) {
4627 if(isPCF(pc) && PCF(pc)->fname) {
4628 fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4629 if(pb->dbName == 'A') {
4631 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4632 // fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4633 if(!strcmp(ab->name, PCF(pc)->fname)) {
4634 // fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4635 if(ab->address != -1)
4636 fprintf(of, "\t0X%06X", ab->address);
4647 /*-----------------------------------------------------------------*/
4649 /* pCode processing */
4653 /*-----------------------------------------------------------------*/
4654 pCode * pic16_findNextInstruction(pCode *pci);
4655 pCode * pic16_findPrevInstruction(pCode *pci);
4657 void pic16_unlinkpCode(pCode *pc)
4663 fprintf(stderr,"Unlinking: ");
4664 printpCode(stderr, pc);
4667 pc->prev->next = pc->next;
4668 } else if (pc->pb && (pc->pb->pcHead == pc)) {
4669 pc->pb->pcHead = pc->next;
4672 pc->next->prev = pc->prev;
4673 } else if (pc->pb && (pc->pb->pcTail == pc)) {
4674 pc->pb->pcTail = pc->prev;
4677 /* move C source line down (or up) */
4678 if (isPCI(pc) && PCI(pc)->cline) {
4679 prev = pic16_findNextInstruction (pc->next);
4680 if (prev && isPCI(prev) && !PCI(prev)->cline) {
4681 PCI(prev)->cline = PCI(pc)->cline;
4683 prev = pic16_findPrevInstruction (pc->prev);
4684 if (prev && isPCI(prev) && !PCI(prev)->cline)
4685 PCI(prev)->cline = PCI(pc)->cline;
4688 pc->prev = pc->next = NULL;
4692 /*-----------------------------------------------------------------*/
4693 /*-----------------------------------------------------------------*/
4695 static void genericDestruct(pCode *pc)
4698 pic16_unlinkpCode(pc);
4701 /* For instructions, tell the register (if there's one used)
4702 * that it's no longer needed */
4703 regs *reg = pic16_getRegFromInstruction(pc);
4705 deleteSetItem (&(reg->reglives.usedpCodes),pc);
4707 if(PCI(pc)->is2MemOp) {
4708 reg = pic16_getRegFromInstruction2(pc);
4710 deleteSetItem(&(reg->reglives.usedpCodes), pc);
4714 /* Instead of deleting the memory used by this pCode, mark
4715 * the object as bad so that if there's a pointer to this pCode
4716 * dangling around somewhere then (hopefully) when the type is
4717 * checked we'll catch it.
4721 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4727 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4728 /*-----------------------------------------------------------------*/
4729 /*-----------------------------------------------------------------*/
4730 /* modifiers for constant immediate */
4731 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4733 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4738 int use_buffer = 1; // copy the string to the passed buffer pointer
4743 use_buffer = 0; // Don't bother copying the string to the buffer.
4748 switch(pcop->type) {
4756 SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
4759 return (PCOR(pcop)->r->name);
4762 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4764 SNPRINTF(buffer,size,"%s",r->name);
4772 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4773 if(PCOI(pcop)->index) {
4774 SNPRINTF(s,size, "%s(%s + %d)",
4775 immdmod[ PCOI(pcop)->offset ],
4779 SNPRINTF(s,size,"%s(%s)",
4780 immdmod[ PCOI(pcop)->offset ],
4784 if(PCOI(pcop)->index) {
4785 SNPRINTF(s,size, "%s(%s + %d)",
4790 SNPRINTF(s,size, "%s(%s)",
4798 case PO_GPR_REGISTER:
4801 //size = sizeof(buffer);
4802 if( PCOR(pcop)->instance) {
4803 SNPRINTF(s,size,"(%s + %d)",
4805 PCOR(pcop)->instance );
4807 SNPRINTF(s,size,"%s",pcop->name);
4814 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4815 SNPRINTF(s, size, "%s", pcop->name);
4817 if(PCORB(pcop)->pcor.instance)
4818 SNPRINTF(s, size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4820 SNPRINTF(s, size, "%s", pcop->name);
4826 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4832 SNPRINTF(buffer,size,"%s",pcop->name);
4835 return (pcop->name);
4839 return ("unhandled type for op1");
4842 return ("NO operand1");
4845 /*-----------------------------------------------------------------*/
4846 /* pic16_get_op2 - variant to support two memory operand commands */
4847 /*-----------------------------------------------------------------*/
4848 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4851 if(pcop && pcop->type == PO_TWO_OPS) {
4852 return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4855 return "NO operand2";
4858 /*-----------------------------------------------------------------*/
4859 /*-----------------------------------------------------------------*/
4860 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4864 return pic16_get_op(pcc->pcop,NULL,0);
4866 /* gcc 3.2: warning: concatenation of string literals with __FUNCTION__ is deprecated
4867 * return ("ERROR Null: "__FUNCTION__);
4869 return ("ERROR Null: pic16_get_op_from_instruction");
4873 /*-----------------------------------------------------------------*/
4874 /*-----------------------------------------------------------------*/
4875 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4878 fprintf(of,"pcodeopprint- not implemented\n");
4881 /*-----------------------------------------------------------------*/
4882 /* pic16_pCode2str - convert a pCode instruction to string */
4883 /*-----------------------------------------------------------------*/
4884 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4890 if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4891 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4892 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4893 // exit(EXIT_FAILURE);
4900 SNPRINTF(s, size, "\t%s\t", PCI(pc)->mnemonic);
4904 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4906 if (PCI(pc)->pcop->type == PO_TWO_OPS)
4908 /* split into two phases due to static buffer in pic16_get_op() */
4909 SNPRINTF(s, size, "%s",
4910 pic16_get_op((PCI(pc)->pcop), NULL, 0));
4913 SNPRINTF(s, size, ", %s",
4914 pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4918 if(PCI(pc)->is2LitOp) {
4919 SNPRINTF(s,size, "%s", PCOP(PCI(pc)->pcop)->name);
4923 if(PCI(pc)->isBitInst) {
4924 if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4925 if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4926 SNPRINTF(s,size,"(%s >> 3), (%s & 7)",
4927 PCI(pc)->pcop->name ,
4928 PCI(pc)->pcop->name );
4930 SNPRINTF(s,size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4931 (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4933 } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4934 SNPRINTF(s,size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
4936 SNPRINTF(s,size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
4939 if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4940 if( PCI(pc)->num_ops == 3)
4941 SNPRINTF(s,size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
4943 SNPRINTF(s,size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
4945 SNPRINTF(s,size,"%s", pic16_get_op_from_instruction(PCI(pc)));
4949 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
4952 if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst) {
4953 SNPRINTF(s,size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
4958 r = pic16_getRegFromInstruction(pc);
4960 if(PCI(pc)->isAccess) {
4961 static char *bank_spec[2][2] = {
4962 { "", ", ACCESS" }, /* gpasm uses access bank by default */
4963 { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
4966 SNPRINTF(s,size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
4973 /* assuming that comment ends with a \n */
4974 SNPRINTF(s,size,";%s", ((pCodeComment *)pc)->comment);
4978 SNPRINTF(s,size,"; info ==>");
4981 switch( PCINF(pc)->type ) {
4982 case INF_OPTIMIZATION:
4983 SNPRINTF(s,size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
4986 SNPRINTF(s,size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
4991 /* assuming that inline code ends with a \n */
4992 SNPRINTF(s,size,"%s", ((pCodeComment *)pc)->comment);
4996 SNPRINTF(s,size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
4999 SNPRINTF(s,size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5002 SNPRINTF(s,size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5005 SNPRINTF(s,size,";\t--FLOW change\n");
5008 SNPRINTF(s,size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5009 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5012 if(PCAD(pc)->directive) {
5013 SNPRINTF(s,size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5016 /* special case to handle inline labels without a tab */
5017 SNPRINTF(s,size,"%s\n", PCAD(pc)->arg);
5022 SNPRINTF(s,size,";A bad pCode is being used\n");
5029 /*-----------------------------------------------------------------*/
5030 /* genericPrint - the contents of a pCode to a file */
5031 /*-----------------------------------------------------------------*/
5032 static void genericPrint(FILE *of, pCode *pc)
5040 // fputs(((pCodeComment *)pc)->comment, of);
5041 fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5046 pBranch *pbl = PCI(pc)->label;
5047 while(pbl && pbl->pc) {
5048 if(pbl->pc->type == PC_LABEL)
5049 pCodePrintLabel(of, pbl->pc);
5054 if(pic16_pcode_verbose) {
5055 fprintf(of, "; info ==>");
5056 switch(((pCodeInfo *)pc)->type) {
5057 case INF_OPTIMIZATION:
5058 fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5061 fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5069 fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5073 // If the opcode has a label, print that first
5075 pBranch *pbl = PCI(pc)->label;
5076 while(pbl && pbl->pc) {
5077 if(pbl->pc->type == PC_LABEL)
5078 pCodePrintLabel(of, pbl->pc);
5084 genericPrint(of,PCODE(PCI(pc)->cline));
5089 pic16_pCode2str(str, 256, pc);
5091 fprintf(of,"%s",str);
5093 if(pic16_debug_verbose) {
5094 fprintf(of, "\t;key=%03x",pc->seq);
5096 fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5103 fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5104 if(PCW(pc)->pci.label)
5105 pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5107 if(PCW(pc)->operand) {
5108 fprintf(of,";\toperand ");
5109 pCodeOpPrint(of,PCW(pc)->operand );
5114 if(pic16_debug_verbose) {
5115 fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5116 if(PCFL(pc)->ancestor)
5117 fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5124 // fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5125 fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5126 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5132 pBranch *pbl = PCAD(pc)->pci.label;
5133 while(pbl && pbl->pc) {
5134 if(pbl->pc->type == PC_LABEL)
5135 pCodePrintLabel(of, pbl->pc);
5139 if(PCAD(pc)->directive) {
5140 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5143 /* special case to handle inline labels without tab */
5144 fprintf(of, "%s\n", PCAD(pc)->arg);
5150 fprintf(of,"unknown pCode type %d\n",pc->type);
5155 /*-----------------------------------------------------------------*/
5156 /* pCodePrintFunction - prints function begin/end */
5157 /*-----------------------------------------------------------------*/
5159 static void pCodePrintFunction(FILE *of, pCode *pc)
5166 if( ((pCodeFunction *)pc)->modname)
5167 fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5170 if(!PCF(pc)->absblock) {
5171 if(PCF(pc)->fname) {
5172 pBranch *exits = PCF(pc)->to;
5175 fprintf(of,"%s:", PCF(pc)->fname);
5177 if(pic16_pcode_verbose)
5178 fprintf(of, "\t;Function start");
5184 exits = exits->next;
5188 if(pic16_pcode_verbose)
5189 fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5192 if((PCF(pc)->from &&
5193 PCF(pc)->from->pc->type == PC_FUNCTION &&
5194 PCF(PCF(pc)->from->pc)->fname) ) {
5196 if(pic16_pcode_verbose)
5197 fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5199 if(pic16_pcode_verbose)
5200 fprintf(of,"; exit point [can't find entry point]\n");
5206 /*-----------------------------------------------------------------*/
5207 /* pCodePrintLabel - prints label */
5208 /*-----------------------------------------------------------------*/
5210 static void pCodePrintLabel(FILE *of, pCode *pc)
5217 fprintf(of,"%s:\n",PCL(pc)->label);
5218 else if (PCL(pc)->key >=0)
5219 fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5221 fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5224 /*-----------------------------------------------------------------*/
5225 /* unlinkpCodeFromBranch - Search for a label in a pBranch and */
5226 /* remove it if it is found. */
5227 /*-----------------------------------------------------------------*/
5228 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5235 if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5236 b = PCI(pcl)->label;
5238 fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5243 //fprintf (stderr, "%s \n",__FUNCTION__);
5244 //pcl->print(stderr,pcl);
5245 //pc->print(stderr,pc);
5248 //fprintf (stderr, "found label\n");
5249 //pc->print(stderr, pc);
5253 bprev->next = b->next; /* Not first pCode in chain */
5257 PCI(pcl)->label = b->next; /* First pCode in chain */
5260 return; /* A label can't occur more than once */
5268 /*-----------------------------------------------------------------*/
5269 /*-----------------------------------------------------------------*/
5270 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5289 /*-----------------------------------------------------------------*/
5290 /* pBranchLink - given two pcodes, this function will link them */
5291 /* together through their pBranches */
5292 /*-----------------------------------------------------------------*/
5293 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5297 // Declare a new branch object for the 'from' pCode.
5299 //_ALLOC(b,sizeof(pBranch));
5300 b = Safe_calloc(1,sizeof(pBranch));
5301 b->pc = PCODE(t); // The link to the 'to' pCode.
5304 f->to = pic16_pBranchAppend(f->to,b);
5306 // Now do the same for the 'to' pCode.
5308 //_ALLOC(b,sizeof(pBranch));
5309 b = Safe_calloc(1,sizeof(pBranch));
5313 t->from = pic16_pBranchAppend(t->from,b);
5318 /*-----------------------------------------------------------------*/
5319 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5321 /*-----------------------------------------------------------------*/
5322 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5335 /*-----------------------------------------------------------------*/
5336 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain. */
5337 /*-----------------------------------------------------------------*/
5338 void pic16_pCodeUnlink(pCode *pc)
5347 /* Remove the branches */
5349 pb1 = PCI(pc)->from;
5351 pc1 = pb1->pc; /* Get the pCode that branches to the
5352 * one we're unlinking */
5354 /* search for the link back to this pCode (the one we're
5356 if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5357 pb2->pc = PCI(pc)->to->pc; // make the replacement
5359 /* if the pCode we're unlinking contains multiple 'to'
5360 * branches (e.g. this a skip instruction) then we need
5361 * to copy these extra branches to the chain. */
5362 if(PCI(pc)->to->next)
5363 pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5369 pic16_unlinkpCode (pc);
5373 /*-----------------------------------------------------------------*/
5374 /*-----------------------------------------------------------------*/
5376 static void genericAnalyze(pCode *pc)
5386 // Go through the pCodes that are in pCode chain and link
5387 // them together through the pBranches. Note, the pCodes
5388 // are linked together as a contiguous stream like the
5389 // assembly source code lines. The linking here mimics this
5390 // except that comments are not linked in.
5392 pCode *npc = pc->next;
5394 if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5395 pBranchLink(pc,npc);
5400 /* reached the end of the pcode chain without finding
5401 * an instruction we could link to. */
5405 fprintf(stderr,"analyze PC_FLOW\n");
5409 fprintf(stderr,,";A bad pCode is being used\n");
5415 /*-----------------------------------------------------------------*/
5416 /*-----------------------------------------------------------------*/
5417 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5421 if(pc->type == PC_LABEL) {
5422 if( ((pCodeLabel *)pc)->key == pcop_label->key)
5425 if((pc->type == PC_OPCODE)
5426 || (pc->type == PC_ASMDIR)
5428 pbr = PCI(pc)->label;
5430 if(pbr->pc->type == PC_LABEL) {
5431 if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
5441 /*-----------------------------------------------------------------*/
5442 /*-----------------------------------------------------------------*/
5443 static int checkLabel(pCode *pc)
5447 if(pc && isPCI(pc)) {
5448 pbr = PCI(pc)->label;
5450 if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5460 /*-----------------------------------------------------------------*/
5461 /* findLabelinpBlock - Search the pCode for a particular label */
5462 /*-----------------------------------------------------------------*/
5463 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5470 for(pc = pb->pcHead; pc; pc = pc->next)
5471 if(compareLabel(pc,pcop_label))
5477 /*-----------------------------------------------------------------*/
5478 /* findLabel - Search the pCode for a particular label */
5479 /*-----------------------------------------------------------------*/
5480 static pCode * findLabel(pCodeOpLabel *pcop_label)
5488 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5489 if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5493 fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5497 /*-----------------------------------------------------------------*/
5498 /* pic16_findNextpCode - given a pCode, find the next of type 'pct' */
5499 /* in the linked list */
5500 /*-----------------------------------------------------------------*/
5501 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5514 /*-----------------------------------------------------------------*/
5515 /* findPrevpCode - given a pCode, find the previous of type 'pct' */
5516 /* in the linked list */
5517 /*-----------------------------------------------------------------*/
5518 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5532 //#define PCODE_DEBUG
5533 /*-----------------------------------------------------------------*/
5534 /* pic16_findNextInstruction - given a pCode, find the next instruction */
5535 /* in the linked list */
5536 /*-----------------------------------------------------------------*/
5537 pCode * pic16_findNextInstruction(pCode *pci)
5542 if((pc->type == PC_OPCODE)
5543 || (pc->type == PC_WILD)
5544 || (pc->type == PC_ASMDIR)
5549 fprintf(stderr,"pic16_findNextInstruction: ");
5550 printpCode(stderr, pc);
5555 //fprintf(stderr,"Couldn't find instruction\n");
5559 /*-----------------------------------------------------------------*/
5560 /* pic16_findPrevInstruction - given a pCode, find the next instruction */
5561 /* in the linked list */
5562 /*-----------------------------------------------------------------*/
5563 pCode * pic16_findPrevInstruction(pCode *pci)
5569 if((pc->type == PC_OPCODE)
5570 || (pc->type == PC_WILD)
5571 || (pc->type == PC_ASMDIR)
5577 fprintf(stderr,"pic16_findPrevInstruction: ");
5578 printpCode(stderr, pc);
5583 //fprintf(stderr,"Couldn't find instruction\n");
5590 /*-----------------------------------------------------------------*/
5591 /* findFunctionEnd - given a pCode find the end of the function */
5592 /* that contains it */
5593 /*-----------------------------------------------------------------*/
5594 static pCode * findFunctionEnd(pCode *pc)
5598 if(pc->type == PC_FUNCTION && !(PCF(pc)->fname))
5604 fprintf(stderr,"Couldn't find function end\n");
5609 /*-----------------------------------------------------------------*/
5610 /* AnalyzeLabel - if the pCode is a label, then merge it with the */
5611 /* instruction with which it is associated. */
5612 /*-----------------------------------------------------------------*/
5613 static void AnalyzeLabel(pCode *pc)
5616 pic16_pCodeUnlink(pc);
5622 static void AnalyzeGOTO(pCode *pc)
5625 pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5629 static void AnalyzeSKIP(pCode *pc)
5632 pBranchLink(pc,pic16_findNextInstruction(pc->next));
5633 pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5637 static void AnalyzeRETURN(pCode *pc)
5640 // branch_link(pc,findFunctionEnd(pc->next));
5646 /*-------------------------------------------------------------------*/
5647 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp */
5648 /* if one is present. This is the common */
5649 /* part of pic16_getRegFromInstruction(2) */
5650 /*-------------------------------------------------------------------*/
5652 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5653 if (!pcop) return NULL;
5655 switch(pcop->type) {
5668 return PCOR(pcop)->r;
5670 case PO_SFR_REGISTER:
5671 //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5672 return PCOR(pcop)->r;
5676 // fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5677 return PCOR(pcop)->r;
5680 // return pic16_dirregWithName(PCOI(pcop)->r->name);
5683 return (PCOI(pcop)->r);
5688 return PCOR(pcop)->r;
5690 case PO_GPR_REGISTER:
5692 // fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5693 return PCOR(pcop)->r;
5696 //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5701 //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5706 /* this should never turn up */
5707 //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5714 return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5718 fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5726 /*-----------------------------------------------------------------*/
5727 /*-----------------------------------------------------------------*/
5728 regs * pic16_getRegFromInstruction(pCode *pc)
5733 PCI(pc)->num_ops == 0 ||
5734 (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5738 fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5739 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5742 return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5745 /*-------------------------------------------------------------------------------*/
5746 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5747 /*-------------------------------------------------------------------------------*/
5748 regs * pic16_getRegFromInstruction2(pCode *pc)
5754 PCI(pc)->num_ops == 0 ||
5755 (PCI(pc)->num_ops == 1)) // accept only 2 operand commands
5758 if (PCI(pc)->pcop->type != PO_TWO_OPS)
5762 fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5763 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5766 return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5769 /*-----------------------------------------------------------------*/
5770 /*-----------------------------------------------------------------*/
5772 static void AnalyzepBlock(pBlock *pb)
5779 /* Find all of the registers used in this pBlock
5780 * by looking at each instruction and examining it's
5783 for(pc = pb->pcHead; pc; pc = pc->next) {
5785 /* Is this an instruction with operands? */
5786 if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5788 if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5790 /* Loop through all of the registers declared so far in
5791 this block and see if we find this one there */
5793 regs *r = setFirstItem(pb->tregisters);
5796 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5797 PCOR(PCI(pc)->pcop)->r = r;
5800 r = setNextItem(pb->tregisters);
5804 /* register wasn't found */
5805 //r = Safe_calloc(1, sizeof(regs));
5806 //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5807 //addSet(&pb->tregisters, r);
5808 addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5809 //PCOR(PCI(pc)->pcop)->r = r;
5810 //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5812 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5815 if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5816 if(PCOR(PCI(pc)->pcop)->r) {
5817 pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx); /* FIXME! - VR */
5818 DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5820 if(PCI(pc)->pcop->name)
5821 fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5823 fprintf(stderr,"ERROR: NULL register\n");
5832 /*-----------------------------------------------------------------*/
5834 /*-----------------------------------------------------------------*/
5835 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5837 static void InsertpFlow(pCode *pc, pCode **pflow)
5840 PCFL(*pflow)->end = pc;
5842 if(!pc || !pc->next)
5845 *pflow = pic16_newpCodeFlow();
5846 pic16_pCodeInsertAfter(pc, *pflow);
5849 /*-----------------------------------------------------------------*/
5850 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5851 /* the flow blocks. */
5853 * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5854 * point the instruction flow changes.
5856 /*-----------------------------------------------------------------*/
5857 void pic16_BuildFlow(pBlock *pb)
5860 pCode *last_pci=NULL;
5867 //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq);
5868 /* Insert a pCodeFlow object at the beginning of a pBlock */
5870 InsertpFlow(pb->pcHead, &pflow);
5872 //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */
5873 //pflow->next = pb->pcHead; /* Make the current head the next object */
5874 //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */
5875 //pb->pcHead = pflow; /* Make the Flow object the head */
5878 for( pc = pic16_findNextInstruction(pb->pcHead);
5880 pc=pic16_findNextInstruction(pc)) {
5883 PCI(pc)->pcflow = PCFL(pflow);
5885 //fprintf(stderr," build: ");
5886 //pflow->print(stderr,pflow);
5888 if (checkLabel(pc)) {
5890 /* This instruction marks the beginning of a
5891 * new flow segment */
5896 /* If the previous pCode is not a flow object, then
5897 * insert a new flow object. (This check prevents
5898 * two consecutive flow objects from being insert in
5899 * the case where a skip instruction preceeds an
5900 * instruction containing a label.) */
5902 if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5903 InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5905 PCI(pc)->pcflow = PCFL(pflow);
5909 if( PCI(pc)->isSkip) {
5911 /* The two instructions immediately following this one
5912 * mark the beginning of a new flow segment */
5914 while(pc && PCI(pc)->isSkip) {
5916 PCI(pc)->pcflow = PCFL(pflow);
5920 InsertpFlow(pc, &pflow);
5921 pc=pic16_findNextInstruction(pc->next);
5929 PCI(pc)->pcflow = PCFL(pflow);
5931 InsertpFlow(pc, &pflow);
5933 } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) {
5935 InsertpFlow(pc, &pflow);
5943 //fprintf (stderr,",end seq %d",GpcFlowSeq);
5945 PCFL(pflow)->end = pb->pcTail;
5948 /*-------------------------------------------------------------------*/
5949 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5950 /* the flow blocks. */
5952 * unBuildFlow removes pCodeFlow objects from a pCode chain
5954 /*-----------------------------------------------------------------*/
5955 static void unBuildFlow(pBlock *pb)
5970 if(PCI(pc)->pcflow) {
5971 //Safe_free(PCI(pc)->pcflow);
5972 PCI(pc)->pcflow = NULL;
5975 } else if(isPCFL(pc) )
5984 /*-----------------------------------------------------------------*/
5985 /*-----------------------------------------------------------------*/
5986 static void dumpCond(int cond)
5989 static char *pcc_str[] = {
6003 int ncond = sizeof(pcc_str) / sizeof(char *);
6006 fprintf(stderr, "0x%04X\n",cond);
6008 for(i=0,j=1; i<ncond; i++, j<<=1)
6010 fprintf(stderr, " %s\n",pcc_str[i]);
6016 /*-----------------------------------------------------------------*/
6017 /*-----------------------------------------------------------------*/
6018 static void FlowStats(pCodeFlow *pcflow)
6026 fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6028 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6031 fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6036 fprintf(stderr, " FlowStats inCond: ");
6037 dumpCond(pcflow->inCond);
6038 fprintf(stderr, " FlowStats outCond: ");
6039 dumpCond(pcflow->outCond);
6043 /*-----------------------------------------------------------------*
6044 * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6045 * if it affects the banking bits.
6047 * return: -1 == Banking bits are unaffected by this pCode.
6049 * return: > 0 == Banking bits are affected.
6051 * If the banking bits are affected, then the returned value describes
6052 * which bits are affected and how they're affected. The lower half
6053 * of the integer maps to the bits that are affected, the upper half
6054 * to whether they're set or cleared.
6056 *-----------------------------------------------------------------*/
6058 static int isBankInstruction(pCode *pc)
6066 if( PCI(pc)->op == POC_MOVLB ||
6067 (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6068 bank = PCOL(pc)->lit;
6075 /*-----------------------------------------------------------------*/
6076 /*-----------------------------------------------------------------*/
6077 static void FillFlow(pCodeFlow *pcflow)
6086 // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6088 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6091 //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6098 isBankInstruction(pc);
6100 } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6104 fprintf(stderr, " FillFlow - Bad end of flow\n");
6106 fprintf(stderr, " FillFlow - Ending flow with\n ");
6107 pc->print(stderr,pc);
6110 fprintf(stderr, " FillFlow inCond: ");
6111 dumpCond(pcflow->inCond);
6112 fprintf(stderr, " FillFlow outCond: ");
6113 dumpCond(pcflow->outCond);
6117 /*-----------------------------------------------------------------*/
6118 /*-----------------------------------------------------------------*/
6119 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6121 pCodeFlowLink *fromLink, *toLink;
6123 if(!from || !to || !to->pcflow || !from->pcflow)
6126 fromLink = pic16_newpCodeFlowLink(from->pcflow);
6127 toLink = pic16_newpCodeFlowLink(to->pcflow);
6129 addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
6130 addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6134 pCode *pic16_getJumptabpCode (pCode *pc) {
6137 //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6138 //pc->print (stderr, pc);
6141 if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6142 if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6143 switch (PCOO(PCINF(pcinf)->oper1)->type) {
6144 case OPT_JUMPTABLE_BEGIN:
6145 /* leading begin of jump table -- in one */
6146 pcinf = pic16_findPrevInstruction (pcinf);
6150 case OPT_JUMPTABLE_END:
6151 /* leading end of jumptable -- not in one */
6156 /* ignore all other PCInfos */
6160 pcinf = pcinf->prev;
6163 /* no PCInfo found -- not in a jumptable */
6167 /*-----------------------------------------------------------------*
6168 * void LinkFlow(pBlock *pb)
6170 * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6171 * non-branching segments. In LinkFlow, we determine the execution
6172 * order of these segments. For example, if one of the segments ends
6173 * with a skip, then we know that there are two possible flow segments
6174 * to which control may be passed.
6175 *-----------------------------------------------------------------*/
6176 static void LinkFlow(pBlock *pb)
6181 pCode *jumptab_pre = NULL;
6183 //fprintf(stderr,"linkflow \n");
6185 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6187 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6190 fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6192 //fprintf(stderr," link: ");
6193 //pcflow->print(stderr,pcflow);
6195 //FillFlow(PCFL(pcflow));
6197 pc = PCFL(pcflow)->end;
6199 //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6200 if(isPCI_SKIP(pc)) {
6201 // fprintf(stderr, "ends with skip\n");
6202 // pc->print(stderr,pc);
6204 pct=pic16_findNextInstruction(pc->next);
6205 LinkFlow_pCode(PCI(pc),PCI(pct));
6206 pct=pic16_findNextInstruction(pct->next);
6207 LinkFlow_pCode(PCI(pc),PCI(pct));
6211 if(isPCI_BRANCH(pc)) {
6212 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6214 /* handle GOTOs in jumptables */
6215 if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6216 /* link to previous flow */
6217 //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6218 LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6221 switch (PCI(pc)->op) {
6227 /* unconditional branches -- do not link to next instruction */
6228 //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6233 /* unconditional calls -- link to next instruction */
6234 //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6235 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6246 /* conditional branches -- also link to next instruction */
6247 //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6248 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6252 fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6253 assert (0 && "unhandled branching instruction");
6257 //fprintf(stderr, "ends with branch\n ");
6258 //pc->print(stderr,pc);
6260 if(!(pcol && isPCOLAB(pcol))) {
6261 if((PCI(pc)->op != POC_RETLW)
6262 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6264 /* continue if label is '$' which assembler knows how to parse */
6265 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6267 if(pic16_pcode_verbose) {
6268 pc->print(stderr,pc);
6269 fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6275 if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6276 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pct)));
6278 fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6279 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6281 // fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6287 //fprintf(stderr, "ends with non-branching instruction:\n");
6288 //pc->print(stderr,pc);
6290 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6296 //fprintf(stderr, "ends with unknown\n");
6297 //pc->print(stderr,pc);
6301 //fprintf(stderr, "ends with nothing: ERROR\n");
6305 /*-----------------------------------------------------------------*/
6306 /*-----------------------------------------------------------------*/
6308 /*-----------------------------------------------------------------*/
6309 /*-----------------------------------------------------------------*/
6310 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6316 if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6319 if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6329 /*-----------------------------------------------------------------*/
6330 /* insertBankSwitch - inserts a bank switch statement in the */
6331 /* assembly listing */
6333 /* position == 0: insert before */
6334 /* position == 1: insert after pc */
6335 /* position == 2: like 0 but previous was a skip instruction */
6336 /*-----------------------------------------------------------------*/
6337 pCodeOp *pic16_popGetLabel(unsigned int key);
6338 extern int pic16_labelOffset;
6340 static void insertBankSwitch(unsigned char position, pCode *pc)
6347 /* emit BANKSEL [symbol] */
6350 new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6352 // position = 0; // position is always before (sanity check!)
6355 fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6356 pc->print(stderr, pc);
6361 /* insert the bank switch after this pc instruction */
6362 pCode *pcnext = pic16_findNextInstruction(pc);
6364 pic16_pCodeInsertAfter(pc, new_pc);
6365 if(pcnext)pc = pcnext;
6369 /* insert the bank switch BEFORE this pc instruction */
6370 pic16_pCodeInsertAfter(pc->prev, new_pc);
6375 pCode *pcnext, *pcprev, *npci, *ppc;
6377 int ofs1=0, ofs2=0, len=0;
6379 /* just like 0, but previous was a skip instruction,
6380 * so some care should be taken */
6382 pic16_labelOffset += 10000;
6383 tlbl = newiTempLabel(NULL);
6385 /* invert skip instruction */
6386 pcprev = pic16_findPrevInstruction(pc->prev);
6387 ipci = PCI(pcprev)->inverted_op;
6388 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6390 // fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6392 /* copy info from old pCode */
6393 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6394 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6395 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6396 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6397 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6398 PCI(npci)->op = PCI(pcprev)->inverted_op;
6400 /* unlink old pCode */
6402 ppc->next = pcprev->next;
6403 pcprev->next->prev = ppc;
6404 pic16_pCodeInsertAfter(ppc, npci);
6406 /* extra instructions to handle invertion */
6407 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6408 pic16_pCodeInsertAfter(npci, pcnext);
6409 pic16_pCodeInsertAfter(pc->prev, new_pc);
6411 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6412 pic16_pCodeInsertAfter(pc, pcnext);
6417 /* Move the label, if there is one */
6418 if(PCI(pc)->label) {
6419 // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6420 // __FILE__, __LINE__, pc, new_pc);
6421 PCAD(new_pc)->pci.label = PCI(pc)->label;
6422 PCI(pc)->label = NULL;
6428 /*-----------------------------------------------------------------*/
6429 /*int compareBankFlow - compare the banking requirements between */
6431 /*-----------------------------------------------------------------*/
6432 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6435 if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6438 if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6441 if(pcflow->firstBank == -1)
6445 if(pcflowLink->pcflow->firstBank == -1) {
6446 pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6447 pcflowLink->pcflow->to :
6448 pcflowLink->pcflow->from);
6449 return compareBankFlow(pcflow, pctl, toORfrom);
6453 if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6456 pcflowLink->bank_conflict++;
6457 pcflowLink->pcflow->FromConflicts++;
6458 pcflow->ToConflicts++;
6461 if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6464 pcflowLink->bank_conflict++;
6465 pcflowLink->pcflow->ToConflicts++;
6466 pcflow->FromConflicts++;
6470 fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6471 pcflowLink->pcflow->pc.seq,
6472 pcflowLink->pcflow->FromConflicts,
6473 pcflowLink->pcflow->ToConflicts);
6481 /*-----------------------------------------------------------------*/
6482 /*-----------------------------------------------------------------*/
6483 static void DumpFlow(pBlock *pb)
6487 pCodeFlowLink *pcfl;
6490 fprintf(stderr,"Dump flow \n");
6491 pb->pcHead->print(stderr, pb->pcHead);
6493 pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6494 pcflow->print(stderr,pcflow);
6496 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6498 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6500 if(!isPCFL(pcflow)) {
6501 fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6504 fprintf(stderr,"dumping: ");
6505 pcflow->print(stderr,pcflow);
6506 FlowStats(PCFL(pcflow));
6508 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6510 pc = PCODE(pcfl->pcflow);
6512 fprintf(stderr, " from seq %d:\n",pc->seq);
6514 fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6515 pc->print(stderr,pc);
6520 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6522 pc = PCODE(pcfl->pcflow);
6524 fprintf(stderr, " to seq %d:\n",pc->seq);
6526 fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6527 pc->print(stderr,pc);
6536 /*-----------------------------------------------------------------*/
6537 /*-----------------------------------------------------------------*/
6538 static int OptimizepBlock(pBlock *pb)
6543 if(!pb || !peepOptimizing)
6546 DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6548 for(pc = pb->pcHead; pc; pc = pc->next)
6549 matches += pic16_pCodePeepMatchRule(pc);
6552 pc = pic16_findNextInstruction(pb->pcHead);
6560 if(pic16_pCodePeepMatchRule(pc)) {
6565 pc = pic16_findNextInstruction(pcprev->next);
6567 pc = pic16_findNextInstruction(pb->pcHead);
6569 pc = pic16_findNextInstruction(pc->next);
6573 DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6578 /*-----------------------------------------------------------------*/
6579 /*-----------------------------------------------------------------*/
6580 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6584 for(pc = pcs; pc; pc = pc->next) {
6586 if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6588 (PCI(pc)->pcop->type == PO_LABEL) &&
6589 (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6597 /*-----------------------------------------------------------------*/
6598 /*-----------------------------------------------------------------*/
6599 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6606 (PCI(pc)->pcop->type == PO_LABEL)) {
6608 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6610 // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6611 // if(pcol->pcop.name)
6612 // Safe_free(pcol->pcop.name);
6614 /* If the key is negative, then we (probably) have a label to
6615 * a function and the name is already defined */
6618 sprintf(s=buffer,"_%05d_DS_",pcl->key);
6622 //sprintf(buffer,"_%05d_DS_",pcl->key);
6624 fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6626 pcol->pcop.name = Safe_strdup(s);
6627 pcol->key = pcl->key;
6628 //pc->print(stderr,pc);
6635 /*-----------------------------------------------------------------*/
6636 /* pBlockRemoveUnusedLabels - remove the pCode labels from the */
6637 /* pCode chain if they're not used. */
6638 /*-----------------------------------------------------------------*/
6639 static void pBlockRemoveUnusedLabels(pBlock *pb)
6641 pCode *pc; pCodeLabel *pcl;
6643 if(!pb || !pb->pcHead)
6646 for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6648 pBranch *pbr = PCI(pc)->label;
6649 if(pbr && pbr->next) {
6650 pCode *pcd = pb->pcHead;
6652 // fprintf(stderr, "multiple labels\n");
6653 // pc->print(stderr,pc);
6658 while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6659 //fprintf(stderr,"Used by:\n");
6660 //pcd->print(stderr,pcd);
6662 exchangeLabels(PCL(pbr->pc),pcd);
6671 for(pc = pb->pcHead; pc; pc = pc->next) {
6673 if(isPCL(pc)) // pc->type == PC_LABEL)
6675 else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6676 pcl = PCL(PCI(pc)->label->pc);
6679 // fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6681 /* This pCode is a label, so search the pBlock to see if anyone
6684 if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6686 //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6687 /* Couldn't find an instruction that refers to this label
6688 * So, unlink the pCode label from it's pCode chain
6689 * and destroy the label */
6690 // fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6692 DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6693 if(pc->type == PC_LABEL) {
6694 pic16_unlinkpCode(pc);
6695 pCodeLabelDestruct(pc);
6697 unlinkpCodeFromBranch(pc, PCODE(pcl));
6698 /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6699 Safe_free(pc->label);
6709 /*-----------------------------------------------------------------*/
6710 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */
6711 /* chain and put them into pBranches that are */
6712 /* associated with the appropriate pCode */
6714 /*-----------------------------------------------------------------*/
6715 void pic16_pBlockMergeLabels(pBlock *pb)
6718 pCode *pc, *pcnext=NULL;
6723 /* First, Try to remove any unused labels */
6724 //pBlockRemoveUnusedLabels(pb);
6726 /* Now loop through the pBlock and merge the labels with the opcodes */
6729 // for(pc = pb->pcHead; pc; pc = pc->next) {
6732 pCode *pcn = pc->next;
6734 if(pc->type == PC_LABEL) {
6736 // fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6737 // fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6739 if((pcnext = pic16_findNextInstruction(pc) )) {
6741 // pcnext->print(stderr, pcnext);
6743 // Unlink the pCode label from it's pCode chain
6744 pic16_unlinkpCode(pc);
6746 // fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6747 // And link it into the instruction's pBranch labels. (Note, since
6748 // it's possible to have multiple labels associated with one instruction
6749 // we must provide a means to accomodate the additional labels. Thus
6750 // the labels are placed into the singly-linked list "label" as
6751 // opposed to being a single member of the pCodeInstruction.)
6753 //_ALLOC(pbr,sizeof(pBranch));
6755 pbr = Safe_calloc(1,sizeof(pBranch));
6759 PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6762 if(pic16_pcode_verbose)
6763 fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6765 } else if(pc->type == PC_CSOURCE) {
6767 /* merge the source line symbolic info into the next instruction */
6768 if((pcnext = pic16_findNextInstruction(pc) )) {
6770 // Unlink the pCode label from it's pCode chain
6771 pic16_unlinkpCode(pc);
6772 PCI(pcnext)->cline = PCCS(pc);
6773 //fprintf(stderr, "merging CSRC\n");
6774 //genericPrint(stderr,pcnext);
6780 pBlockRemoveUnusedLabels(pb);
6784 /*-----------------------------------------------------------------*/
6785 /*-----------------------------------------------------------------*/
6786 static int OptimizepCode(char dbName)
6788 #define MAX_PASSES 4
6797 DFPRINTF((stderr," Optimizing pCode\n"));
6801 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6802 if('*' == dbName || getpBlock_dbName(pb) == dbName)
6803 matches += OptimizepBlock(pb);
6806 while(matches && ++passes < MAX_PASSES);
6813 const char *pic16_pCodeOpType(pCodeOp *pcop);
6814 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6817 /*-----------------------------------------------------------------*/
6818 /* pic16_popCopyGPR2Bit - copy a pcode operator */
6819 /*-----------------------------------------------------------------*/
6821 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6825 // fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6828 pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6830 if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6833 assert(pcop != NULL);
6835 if( !( (pcop->type == PO_LABEL) ||
6836 (pcop->type == PO_LITERAL) ||
6837 (pcop->type == PO_STR) ))
6838 PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */
6839 PCOR(pcop)->r->wasUsed = 1;
6840 PCOR(pcop)->instance = PCOR(pc)->instance;
6846 /*----------------------------------------------------------------------*
6847 * pic16_areRegsSame - check to see if the names of two registers match *
6848 *----------------------------------------------------------------------*/
6849 int pic16_areRegsSame(regs *r1, regs *r2)
6851 if(!strcmp(r1->name, r2->name))return 1;
6857 /*-----------------------------------------------------------------*/
6858 /*-----------------------------------------------------------------*/
6859 static void pic16_FixRegisterBanking(pBlock *pb)
6863 regs *reg, *prevreg;
6864 unsigned char flag=0;
6869 pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6872 /* loop through all of the flow blocks with in one pblock */
6874 // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6878 /* at this point, pc should point to a PC_FLOW object */
6879 /* for each flow block, determine the register banking
6883 /* if label, then might come from other point, force banksel */
6884 if(isPCL(pc))prevreg = NULL;
6886 if(!isPCI(pc))goto loop;
6888 if(PCI(pc)->label)prevreg = NULL;
6890 if(PCI(pc)->is2MemOp)goto loop;
6892 /* if goto, then force banksel */
6893 // if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6895 reg = pic16_getRegFromInstruction(pc);
6898 pc->print(stderr, pc);
6899 fprintf(stderr, "reg = %p\n", reg);
6902 fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6903 fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6904 reg->address,reg->isBitField, reg->isFixed);
6908 /* now make some tests to make sure that instruction needs bank switch */
6910 /* if no register exists, and if not a bit opcode goto loop */
6912 if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6915 if(isPCI_SKIP(pc)) {
6916 // fprintf(stderr, "instruction is SKIP instruction\n");
6919 if(reg && isACCESS_BANK(reg))goto loop;
6921 if(!isBankInstruction(pc))goto loop;
6923 if(isPCI_LIT(pc))goto loop;
6925 if(PCI(pc)->op == POC_CALL)goto loop;
6927 /* Examine the instruction before this one to make sure it is
6928 * not a skip type instruction */
6929 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
6931 flag = 0; /* add before this instruction */
6933 /* if previous instruction is a skip one, then set flag
6934 * to 2 and call insertBankSwitch */
6935 if(pcprev && isPCI_SKIP(pcprev)) {
6940 if(pic16_options.opt_banksel>0) {
6941 char op1[128], op2[128];
6944 strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
6945 strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
6946 if(!strcmp(op1, op2))goto loop;
6950 insertBankSwitch(flag, pc);
6952 // fprintf(stderr, "BANK SWITCH inserted\n");
6960 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
6962 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
6963 int instrSize (pCode *pc)
6968 if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
6969 return 4; // assumes only regular instructions using <= 4 bytes
6972 if (isPCI(pc)) return PCI(pc)->isize;
6977 /* Returns 1 if pc is referenced by the given label (either
6978 * pc is the label itself or is an instruction with an attached
6980 * Returns 0 if pc is not preceeded by the specified label.
6982 int isLabel (pCode *pc, char *label)
6986 // label attached to the pCode?
6987 if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
6988 pBranch *lab = NULL;
6989 lab = PCI(pc)->label;
6992 if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
6999 // is inline assembly label?
7000 if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7001 // do not compare trailing ':'
7002 if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7009 if (strcmp(PCL(pc)->label,label) == 0) {
7014 // no label/no label attached/wrong label(s)
7018 /* Returns the distance to the given label in terms of words.
7019 * Labels are searched only within -max .. max words from pc.
7020 * Returns max if the label could not be found or
7021 * its distance from pc in (-max..+max).
7023 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7024 int dist = instrSize(pc);
7028 while (dist < max && curr && !isLabel (curr, label)) {
7030 dist += instrSize(curr); // sizeof (instruction)
7032 if (curr && dist < max) {
7033 if (target != NULL) *target = curr;
7038 curr = pic16_findNextInstruction (pc->next);
7040 while (dist < max && curr && !isLabel (curr, label)) {
7041 dist += instrSize(curr); // sizeof (instruction)
7044 if (curr && dist < max) {
7045 if (target != NULL) *target = curr;
7049 if (target != NULL) *target = NULL;
7053 /* Returns -1 if pc does NOT denote an instruction like
7055 * Otherwise we return
7056 * (a) 0x10 + i for BTFSS
7057 * (b) 0x00 + i for BTFSC
7059 int isSkipOnStatus (pCode *pc)
7063 if (!pc || !isPCI(pc)) return -1;
7064 if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7065 else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7068 pcop = PCI(pc)->pcop;
7070 if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7071 return res + ((pCodeOpRegBit *)pcop)->bit;
7077 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7078 * returns 0 otherwise. */
7079 int isConditionalBranch (pCode *pc)
7081 if (!pc || !isPCI_BRANCH(pc)) return 0;
7083 switch (PCI(pc)->op) {
7101 /* Returns 1 if pc has a label attached to it.
7102 * This can be either a label stored in the pCode itself (.label)
7103 * or a label making up its own pCode preceding this pc.
7104 * Returns 0 if pc cannot be reached directly via a label.
7106 int hasNoLabel (pCode *pc)
7111 // are there any label pCodes between pc and the previous instruction?
7112 prev = pic16_findPrevInstruction (pc->prev);
7113 while (pc && pc != prev) {
7114 // pCode with attached label?
7115 if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7116 && PCI(pc)->label) {
7119 // is inline assembly label?
7120 if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7121 if (isPCW(pc) && PCW(pc)->label) return 0;
7124 if (isPCL(pc)) return 0;
7133 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7138 vsprintf (buf, fmt, va);
7141 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7144 /* Replaces the old pCode with the new one, moving the labels,
7145 * C source line and probably flow information to the new pCode.
7147 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7148 if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7151 /* first move all labels from old to new */
7152 PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7153 PCI(oldPC)->label = NULL;
7156 /* move C source line (if possible) */
7157 if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7158 PCI(newPC)->cline = PCI(oldPC)->cline;
7161 /* keep flow information intact */
7162 newPC->seq = oldPC->seq;
7163 PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7164 if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7165 PCI(newPC)->pcflow->end = newPC;
7168 /* insert a comment stating which pCode has been replaced */
7170 if (pic16_pcode_verbose || pic16_debug_verbose) {
7172 pic16_pCode2str (pc_str, 256, oldPC);
7173 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7177 /* insert new pCode into pBlock */
7178 pic16_pCodeInsertAfter (oldPC, newPC);
7179 pic16_unlinkpCode (oldPC);
7181 /* destruct replaced pCode */
7182 oldPC->destruct (oldPC);
7185 /* Returns the inverted conditional branch (if any) or NULL.
7186 * pcop must be set to the new jump target.
7188 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7192 if (!bcc || !isPCI(bcc)) return NULL;
7194 switch (PCI(bcc)->op) {
7195 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7196 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7197 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7198 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7199 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7200 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7201 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7202 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7209 #define MAX_DIST_GOTO 0x7FFFFFFF
7210 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7211 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7212 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7213 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7215 /* Follows GOTO/BRA instructions to their target instructions, stores the
7216 * final destination (not a GOTO or BRA instruction) in target and returns
7217 * the distance from the original pc to *target.
7219 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7222 pCodeOp *lastPCOP = NULL;
7226 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7228 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7229 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7230 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7232 lastPCOP = PCI(curr)->pcop;
7233 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7234 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7237 if (target) *target = last;
7238 if (pcop) *pcop = lastPCOP;
7242 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7243 * Otherwise the first pCode after the jumptable (after
7244 * the OPT_JUMPTABLE_END tag) is returned.
7246 pCode *skipJumptables (pCode *pc, int *isJumptable)
7249 if (!pc) return NULL;
7251 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7253 //fprintf (stderr, "SKIPPING jumptable\n");
7255 //pc->print(stderr, pc);
7257 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7258 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7259 //fprintf (stderr, "<<JUMPTAB:\n");
7260 // skip OPT_END as well
7261 if (pc) pc = pc->next;
7267 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7271 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7272 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7273 pc = skipJumptables (pc, &isJumptab);
7275 // pc is the first pCode after the jumptable
7278 // pc has not been changed by skipJumptables()
7286 /* Turn GOTOs into BRAs if distance between GOTO and label
7287 * is less than 1024 bytes.
7289 * This method is especially useful if GOTOs after BTFS[SC]
7290 * can be turned into BRAs as GOTO would cost another NOP
7293 void pic16_OptimizeJumps ()
7296 pCode *pc_prev = NULL;
7297 pCode *pc_next = NULL;
7300 int change, iteration, isJumptab;
7303 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7305 if (!the_pFile) return;
7307 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7309 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7310 int matchedInvertRule = 1;
7313 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7315 pc = pic16_findNextInstruction (pb->pcHead);
7318 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7320 // skip jumptable, i.e. start over with no pc_prev!
7326 /* (1) resolve chained jumps
7327 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7328 * (a) leave dead code in and
7329 * (b) skip over the dead code with an (unneccessary) jump.
7331 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7332 pCodeOp *lastTargetOp = NULL;
7333 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7334 int maxDist = MAX_DIST_BCC;
7335 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7336 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7338 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7339 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7340 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7341 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7342 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7343 PCI(pc)->pcop->name = lastTargetOp->name;
7352 int condBraType = isSkipOnStatus(pc_prev);
7353 label = PCI(pc)->pcop->name;
7354 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7355 if (dist < 0) dist = -dist;
7356 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7360 /* (2) remove "GOTO label; label:" */
7361 if (isLabel (pc_next, label)) {
7362 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7363 // first remove all preceeding SKIP instructions
7364 while (pc_prev && isPCI_SKIP(pc_prev)) {
7365 // attach labels on this instruction to pc_next
7366 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7367 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7368 PCI(pc_prev)->label = NULL;
7369 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7370 pic16_unlinkpCode (pc_prev);
7371 pc_prev = pic16_findPrevInstruction (pc);
7373 // now remove the redundant goto itself
7374 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7375 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7376 pic16_unlinkpCode (pc);
7377 pc = pic16_findPrevInstruction(pc_next->prev);
7378 isHandled = 1; // do not perform further optimizations
7384 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7385 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7386 if (dist < MAX_DIST_BCC) {
7388 switch (condBraType) {
7389 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7390 // no BDC on DIGIT CARRY available
7391 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7392 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7393 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7394 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7395 // no BNDC on DIGIT CARRY available
7396 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7397 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7398 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7400 // no replacement possible
7405 // ATTENTION: keep labels attached to BTFSx!
7406 // HINT: GOTO is label free (checked above)
7407 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7408 isHandled = 1; // do not perform further optimizations
7409 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7410 pic16_pCodeReplace (pc_prev, bcc);
7417 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7423 // (4) eliminate the following (common) tripel:
7425 // labels1: Bcc label2;
7426 // GOTO somewhere; ; <-- instruction referenced by pc
7428 // and replace it by
7429 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7431 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7432 // to <cont.> instead
7433 // ATTENTION: This optimization is only valid if <pred.> is
7434 // not a skip operation!
7435 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7436 // ATTENTION: no label may be attached to the GOTO instruction!
7437 if (isConditionalBranch(pc_prev)
7438 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7439 && (dist < MAX_DIST_BCC)
7440 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7441 && hasNoLabel(pc)) {
7442 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7445 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7446 isHandled = 1; // do not perform further optimizations
7447 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7448 pic16_pCodeReplace (pc_prev, newBcc);
7453 matchedInvertRule++;
7458 /* (5) now just turn GOTO into BRA */
7459 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7460 if (dist < MAX_DIST_BRA) {
7461 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7462 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7463 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7464 pic16_pCodeReplace (pc, newBra);
7469 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7472 } // if (!isHandled)
7479 pBlockRemoveUnusedLabels (pb);
7481 // This line enables goto chain resolution!
7482 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7485 } while (change); /* fixpoint iteration per pBlock */
7488 // emit some statistics concerning goto-optimization
7490 if (pic16_debug_verbose || pic16_pcode_verbose) {
7491 fprintf (stderr, "optimize-goto:\n"
7492 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7493 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7494 "\t%5d conditional \"skipping\" jumps inverted\n"
7495 "\t%5d GOTOs to next instruction removed\n"
7496 "\t%5d chained GOTOs resolved\n",
7497 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7500 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7504 #undef MAX_JUMPCHAIN_DEPTH
7505 #undef MAX_DIST_GOTO
7509 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7511 static void pBlockDestruct(pBlock *pb)
7522 /*-----------------------------------------------------------------*/
7523 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7524 /* name dbName and combine them */
7525 /* into one block */
7526 /*-----------------------------------------------------------------*/
7527 static void mergepBlocks(char dbName)
7530 pBlock *pb, *pbmerged = NULL,*pbn;
7532 pb = the_pFile->pbHead;
7534 //fprintf(stderr," merging blocks named %c\n",dbName);
7538 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7539 if( getpBlock_dbName(pb) == dbName) {
7541 //fprintf(stderr," merged block %c\n",dbName);
7546 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7547 /* pic16_addpCode2pBlock doesn't handle the tail: */
7548 pbmerged->pcTail = pb->pcTail;
7550 pb->prev->next = pbn;
7552 pbn->prev = pb->prev;
7557 //pic16_printpBlock(stderr, pbmerged);
7564 /*-----------------------------------------------------------------*/
7565 /* AnalyzeFlow - Examine the flow of the code and optimize */
7567 /* level 0 == minimal optimization */
7568 /* optimize registers that are used only by two instructions */
7569 /* level 1 == maximal optimization */
7570 /* optimize by looking at pairs of instructions that use the */
7572 /*-----------------------------------------------------------------*/
7574 static void AnalyzeFlow(int level)
7576 static int times_called=0;
7580 /* remove unused allocated registers before exiting */
7581 pic16_RemoveUnusedRegisters();
7586 /* if this is not the first time this function has been called,
7587 * then clean up old flow information */
7588 if(times_called++) {
7589 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7591 pic16_RegsUnMapLiveRanges();
7595 /* Phase 2 - Flow Analysis - Register Banking
7597 * In this phase, the individual flow blocks are examined
7598 * and register banking is fixed.
7602 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7603 pic16_FixRegisterBanking(pb);
7606 /* Phase 2 - Flow Analysis
7608 * In this phase, the pCode is partition into pCodeFlow
7609 * blocks. The flow blocks mark the points where a continuous
7610 * stream of instructions changes flow (e.g. because of
7611 * a call or goto or whatever).
7614 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7615 pic16_BuildFlow(pb);
7618 /* Phase 2 - Flow Analysis - linking flow blocks
7620 * In this phase, the individual flow blocks are examined
7621 * to determine their order of excution.
7624 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7628 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7629 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7630 pic16_createDF (pb);
7631 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7632 pic16_vcg_dump_default (pb);
7634 //pic16_destructDF (pb);
7638 if (0) releaseStack (); // releasing is costly...
7642 /* Phase 3 - Flow Analysis - Flow Tree
7644 * In this phase, the individual flow blocks are examined
7645 * to determine their order of execution.
7648 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7649 pic16_BuildFlowTree(pb);
7652 /* Phase x - Flow Analysis - Used Banks
7654 * In this phase, the individual flow blocks are examined
7655 * to determine the Register Banks they use
7659 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7664 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7665 pic16_pCodeRegMapLiveRanges(pb);
7667 pic16_RemoveUnusedRegisters();
7668 pic16_removeUnusedRegistersDF ();
7670 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7671 pic16_pCodeRegOptimizeRegUsage(level);
7680 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7685 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7688 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7689 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7690 pcflow = pcflow->next) {
7691 FillFlow(PCFL(pcflow));
7696 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7699 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7700 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7701 pcflow = pcflow->next) {
7702 FlowStats(PCFL(pcflow));
7708 /* VR -- no need to analyze banking in flow, but left here :
7709 * 1. because it may be used in the future for other purposes
7710 * 2. because if omitted we'll miss some optimization done here
7712 * Perhaps I should rename it to something else
7715 /*-----------------------------------------------------------------*/
7716 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7717 /* assigned to the registers. */
7719 /*-----------------------------------------------------------------*/
7721 void pic16_AnalyzeBanking(void)
7725 /* Phase x - Flow Analysis - Used Banks
7727 * In this phase, the individual flow blocks are examined
7728 * to determine the Register Banks they use
7738 if(!the_pFile)return;
7740 if(!pic16_options.no_banksel) {
7741 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7742 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7743 pic16_FixRegisterBanking(pb);
7748 /*-----------------------------------------------------------------*/
7749 /* buildCallTree - Look at the flow and extract all of the calls. */
7750 /*-----------------------------------------------------------------*/
7752 static set *register_usage(pBlock *pb);
7755 static void buildCallTree(void )
7767 /* Now build the call tree.
7768 First we examine all of the pCodes for functions.
7769 Keep in mind that the function boundaries coincide
7770 with pBlock boundaries.
7772 The algorithm goes something like this:
7773 We have two nested loops. The outer loop iterates
7774 through all of the pBlocks/functions. The inner
7775 loop iterates through all of the pCodes for
7776 a given pBlock. When we begin iterating through
7777 a pBlock, the variable pc_fstart, pCode of the start
7778 of a function, is cleared. We then search for pCodes
7779 of type PC_FUNCTION. When one is encountered, we
7780 initialize pc_fstart to this and at the same time
7781 associate a new pBranch object that signifies a
7782 branch entry. If a return is found, then this signifies
7783 a function exit point. We'll link the pCodes of these
7784 returns to the matching pc_fstart.
7786 When we're done, a doubly linked list of pBranches
7787 will exist. The head of this list is stored in
7788 `the_pFile', which is the meta structure for all
7789 of the pCode. Look at the pic16_printCallTree function
7790 on how the pBranches are linked together.
7793 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7794 pCode *pc_fstart=NULL;
7795 for(pc = pb->pcHead; pc; pc = pc->next) {
7797 if(isPCI(pc) && pc_fstart) {
7798 if(PCI(pc)->is2MemOp) {
7799 r = pic16_getRegFromInstruction2(pc);
7800 if(r && !strcmp(r->name, "POSTDEC1"))
7801 PCF(pc_fstart)->stackusage++;
7803 r = pic16_getRegFromInstruction(pc);
7804 if(r && !strcmp(r->name, "PREINC1"))
7805 PCF(pc_fstart)->stackusage--;
7810 if (PCF(pc)->fname) {
7813 sprintf(buf, "%smain", port->fun_prefix);
7814 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7815 //fprintf(stderr," found main \n");
7816 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7820 pbr = Safe_calloc(1,sizeof(pBranch));
7821 pbr->pc = pc_fstart = pc;
7824 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7826 // Here's a better way of doing the same:
7827 addSet(&pb->function_entries, pc);
7830 // Found an exit point in a function, e.g. return
7831 // (Note, there may be more than one return per function)
7833 pBranchLink(PCF(pc_fstart), PCF(pc));
7835 addSet(&pb->function_exits, pc);
7837 } else if(isCALL(pc)) {
7838 addSet(&pb->function_calls,pc);
7845 /* This is not needed because currently all register used
7846 * by a function are stored in stack -- VR */
7848 /* Re-allocate the registers so that there are no collisions
7849 * between local variables when one function call another */
7852 // pic16_deallocateAllRegs();
7854 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7862 /*-----------------------------------------------------------------*/
7863 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7864 /* all of the logical connections. */
7866 /* Essentially what's done here is that the pCode flow is */
7868 /*-----------------------------------------------------------------*/
7870 void pic16_AnalyzepCode(char dbName)
7881 /* Phase 1 - Register allocation and peep hole optimization
7883 * The first part of the analysis is to determine the registers
7884 * that are used in the pCode. Once that is done, the peep rules
7885 * are applied to the code. We continue to loop until no more
7886 * peep rule optimizations are found (or until we exceed the
7887 * MAX_PASSES threshold).
7889 * When done, the required registers will be determined.
7895 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7896 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7898 /* First, merge the labels with the instructions */
7899 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7900 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7902 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7903 //fprintf(stderr," analyze and merging block %c\n",dbName);
7904 pic16_pBlockMergeLabels(pb);
7907 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7912 changes = OptimizepCode(dbName);
7915 } while(changes && (i++ < MAX_PASSES));
7922 /* convert a series of movff's of local regs to stack, with a single call to
7923 * a support functions which does the same thing via loop */
7924 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
7928 char *fname[]={"__lr_store", "__lr_restore"};
7930 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
7932 pct = pic16_findNextInstruction(pcstart->next);
7935 pct = pc->next; //pic16_findNextInstruction(pc->next);
7936 // pc->print(stderr, pc);
7937 if(isPCI(pc) && PCI(pc)->label) {
7938 pbr = PCI(pc)->label;
7939 while(pbr && pbr->pc) {
7940 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
7944 // pc->print(stderr, pc);
7946 pc->prev->next = pct;
7947 pct->prev = pc->prev;
7951 } while ((pc) && (pc != pcend));
7953 /* unlink movff instructions */
7954 pcstart->next = pcend;
7955 pcend->prev = pcstart;
7959 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7960 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
7963 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
7964 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
7965 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
7968 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7969 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
7976 sym = newSymbol( fname[ entry?0:1 ], 0 );
7977 strcpy(sym->rname, fname[ entry?0:1 ]);
7978 checkAddSym(&externs, sym);
7980 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
7985 /*-----------------------------------------------------------------*/
7986 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
7987 /* local registers to a support function call */
7988 /*-----------------------------------------------------------------*/
7989 void pic16_OptimizeLocalRegs(void)
7994 pCodeOpLocalReg *pclr;
7997 regs *r, *lastr=NULL, *firstr=NULL;
7998 pCode *pcstart=NULL, *pcend=NULL;
8003 * local_regs begin mark
8004 * MOVFF r0x01, POSTDEC1
8005 * MOVFF r0x02, POSTDEC1
8008 * MOVFF r0x0n, POSTDEC1
8009 * local_regs end mark
8011 * convert the above to the below:
8012 * MOVLW starting_register_index
8014 * MOVLW register_count
8015 * call __save_registers_in_stack
8021 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8022 inRegCount = regCount = 0;
8023 firstr = lastr = NULL;
8024 for(pc = pb->pcHead; pc; pc = pc->next) {
8026 /* hold current function name */
8027 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8029 if(pc && (pc->type == PC_INFO)) {
8032 if(pci->type == INF_LOCALREGS) {
8033 pclr = PCOLR(pci->oper1);
8035 if((pclr->type == LR_ENTRY_BEGIN)
8036 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8039 switch(pclr->type) {
8040 case LR_ENTRY_BEGIN:
8042 inRegCount = 1; regCount = 0;
8043 pcstart = pc; //pic16_findNextInstruction(pc->next);
8044 firstr = lastr = NULL;
8050 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8053 if(curFunc && inWparamList(curFunc+1)) {
8054 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8058 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8063 firstr = lastr = NULL;
8067 if(inRegCount == -1) {
8068 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8074 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8076 r = pic16_getRegFromInstruction(pc);
8078 r = pic16_getRegFromInstruction2(pc);
8079 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8080 if(!firstr)firstr = r;
8082 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8094 /*-----------------------------------------------------------------*/
8095 /* ispCodeFunction - returns true if *pc is the pCode of a */
8097 /*-----------------------------------------------------------------*/
8098 static bool ispCodeFunction(pCode *pc)
8101 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8107 /*-----------------------------------------------------------------*/
8108 /* findFunction - Search for a function by name (given the name) */
8109 /* in the set of all functions that are in a pBlock */
8110 /* (note - I expect this to change because I'm planning to limit */
8111 /* pBlock's to just one function declaration */
8112 /*-----------------------------------------------------------------*/
8113 static pCode *findFunction(char *fname)
8120 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8122 pc = setFirstItem(pb->function_entries);
8125 if((pc->type == PC_FUNCTION) &&
8127 (strcmp(fname, PCF(pc)->fname)==0))
8130 pc = setNextItem(pb->function_entries);
8139 static void MarkUsedRegisters(set *regset)
8144 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8145 // fprintf(stderr, "marking register = %s\t", r1->name);
8146 r2 = pic16_regWithIdx(r1->rIdx);
8147 // fprintf(stderr, "to register = %s\n", r2->name);
8154 static void pBlockStats(FILE *of, pBlock *pb)
8160 if(!pic16_pcode_verbose)return;
8162 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8164 // for now just print the first element of each set
8165 pc = setFirstItem(pb->function_entries);
8167 fprintf(of,";entry: ");
8170 pc = setFirstItem(pb->function_exits);
8172 fprintf(of,";has an exit\n");
8176 pc = setFirstItem(pb->function_calls);
8178 fprintf(of,";functions called:\n");
8181 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8182 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8184 pc = setNextItem(pb->function_calls);
8188 r = setFirstItem(pb->tregisters);
8190 int n = elementsInSet(pb->tregisters);
8192 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8195 fprintf(of, "; %s\n",r->name);
8196 r = setNextItem(pb->tregisters);
8200 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8203 /*-----------------------------------------------------------------*/
8204 /*-----------------------------------------------------------------*/
8206 static void sequencepCode(void)
8212 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8214 pb->seq = GpCodeSequenceNumber+1;
8216 for( pc = pb->pcHead; pc; pc = pc->next)
8217 pc->seq = ++GpCodeSequenceNumber;
8224 /*-----------------------------------------------------------------*/
8225 /*-----------------------------------------------------------------*/
8226 static set *register_usage(pBlock *pb)
8229 set *registers=NULL;
8230 set *registersInCallPath = NULL;
8232 /* check recursion */
8234 pc = setFirstItem(pb->function_entries);
8241 if(pc->type != PC_FUNCTION)
8242 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8244 pc = setFirstItem(pb->function_calls);
8245 for( ; pc; pc = setNextItem(pb->function_calls)) {
8247 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8248 char *dest = pic16_get_op_from_instruction(PCI(pc));
8250 pcn = findFunction(dest);
8252 registersInCallPath = register_usage(pcn->pb);
8254 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8259 pBlockStats(stderr,pb); // debug
8262 // Mark the registers in this block as used.
8264 MarkUsedRegisters(pb->tregisters);
8265 if(registersInCallPath) {
8266 /* registers were used in the functions this pBlock has called */
8267 /* so now, we need to see if these collide with the ones we are */
8270 regs *r1,*r2, *newreg;
8272 DFPRINTF((stderr,"comparing registers\n"));
8274 r1 = setFirstItem(registersInCallPath);
8277 r2 = setFirstItem(pb->tregisters);
8279 while(r2 && (r1->type != REG_STK)) {
8281 if(r2->rIdx == r1->rIdx) {
8282 newreg = pic16_findFreeReg(REG_GPR);
8286 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8290 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8291 r1->rIdx, newreg->rIdx));
8292 r2->rIdx = newreg->rIdx;
8293 //if(r2->name) Safe_free(r2->name);
8295 r2->name = Safe_strdup(newreg->name);
8299 newreg->wasUsed = 1;
8301 r2 = setNextItem(pb->tregisters);
8304 r1 = setNextItem(registersInCallPath);
8307 /* Collisions have been resolved. Now free the registers in the call path */
8308 r1 = setFirstItem(registersInCallPath);
8310 if(r1->type != REG_STK) {
8311 newreg = pic16_regWithIdx(r1->rIdx);
8314 r1 = setNextItem(registersInCallPath);
8318 // MarkUsedRegisters(pb->registers);
8320 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8323 DFPRINTF((stderr,"returning regs\n"));
8325 DFPRINTF((stderr,"not returning regs\n"));
8327 DFPRINTF((stderr,"pBlock after register optim.\n"));
8328 pBlockStats(stderr,pb); // debug
8335 /*-----------------------------------------------------------------*/
8336 /* pct2 - writes the call tree to a file */
8338 /*-----------------------------------------------------------------*/
8339 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8343 // set *registersInCallPath = NULL;
8349 fprintf(of, "recursive function\n");
8350 return; //recursion ?
8353 pc = setFirstItem(pb->function_entries);
8360 for(i=0;i<indent;i++) // Indentation
8364 if(pc->type == PC_FUNCTION) {
8365 usedstack += PCF(pc)->stackusage;
8366 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8367 } else return; // ???
8370 pc = setFirstItem(pb->function_calls);
8371 for( ; pc; pc = setNextItem(pb->function_calls)) {
8373 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8374 char *dest = pic16_get_op_from_instruction(PCI(pc));
8376 pcn = findFunction(dest);
8378 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8380 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8388 /*-----------------------------------------------------------------*/
8389 /* pic16_printCallTree - writes the call tree to a file */
8391 /*-----------------------------------------------------------------*/
8393 void pic16_printCallTree(FILE *of)
8405 fprintf(of, "\npBlock statistics\n");
8406 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8410 fprintf(of,"Call Tree\n");
8411 pbr = the_pFile->functions;
8415 if(!ispCodeFunction(pc))
8416 fprintf(of,"bug in call tree");
8419 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8421 while(pc->next && !ispCodeFunction(pc->next)) {
8423 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8424 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8432 fprintf(of,"\n**************\n\na better call tree\n");
8433 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8438 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8439 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8445 /*-----------------------------------------------------------------*/
8447 /*-----------------------------------------------------------------*/
8449 static void InlineFunction(pBlock *pb)
8457 pc = setFirstItem(pb->function_calls);
8459 for( ; pc; pc = setNextItem(pb->function_calls)) {
8462 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8468 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8470 //fprintf(stderr,"Cool can inline:\n");
8471 //pcn->print(stderr,pcn);
8473 //fprintf(stderr,"recursive call Inline\n");
8474 InlineFunction(pcn->pb);
8475 //fprintf(stderr,"return from recursive call Inline\n");
8478 At this point, *pc points to a CALL mnemonic, and
8479 *pcn points to the function that is being called.
8481 To in-line this call, we need to remove the CALL
8482 and RETURN(s), and link the function pCode in with
8488 /* Remove the CALL */
8492 /* remove callee pBlock from the pBlock linked list */
8493 removepBlock(pcn->pb);
8501 /* Remove the Function pCode */
8502 pct = pic16_findNextInstruction(pcn->next);
8504 /* Link the function with the callee */
8505 pc->next = pcn->next;
8506 pcn->next->prev = pc;
8508 /* Convert the function name into a label */
8510 pbr = Safe_calloc(1,sizeof(pBranch));
8511 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8513 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8514 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8516 /* turn all of the return's except the last into goto's */
8517 /* check case for 2 instruction pBlocks */
8518 pce = pic16_findNextInstruction(pcn->next);
8520 pCode *pce_next = pic16_findNextInstruction(pce->next);
8522 if(pce_next == NULL) {
8523 /* found the last return */
8524 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8526 //fprintf(stderr,"found last return\n");
8527 //pce->print(stderr,pce);
8528 pce->prev->next = pc_call->next;
8529 pc_call->next->prev = pce->prev;
8530 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8540 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8546 /*-----------------------------------------------------------------*/
8548 /*-----------------------------------------------------------------*/
8550 void pic16_InlinepCode(void)
8559 if(!functionInlining)
8562 /* Loop through all of the function definitions and count the
8563 * number of times each one is called */
8564 //fprintf(stderr,"inlining %d\n",__LINE__);
8566 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8568 pc = setFirstItem(pb->function_calls);
8570 for( ; pc; pc = setNextItem(pb->function_calls)) {
8573 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8574 if(pcn && isPCF(pcn)) {
8575 PCF(pcn)->ncalled++;
8578 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8583 //fprintf(stderr,"inlining %d\n",__LINE__);
8585 /* Now, Loop through the function definitions again, but this
8586 * time inline those functions that have only been called once. */
8588 InlineFunction(the_pFile->pbHead);
8589 //fprintf(stderr,"inlining %d\n",__LINE__);
8591 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8596 char *pic_optype_names[]={
8597 "PO_NONE", // No operand e.g. NOP
8598 "PO_W", // The working register (as a destination)
8599 "PO_WREG", // The working register (as a file register)
8600 "PO_STATUS", // The 'STATUS' register
8601 "PO_BSR", // The 'BSR' register
8602 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8604 "PO_INDF0", // The Indirect register
8605 "PO_INTCON", // Interrupt Control register
8606 "PO_GPR_REGISTER", // A general purpose register
8607 "PO_GPR_BIT", // A bit of a general purpose register
8608 "PO_GPR_TEMP", // A general purpose temporary register
8609 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8610 "PO_PCL", // Program counter Low register
8611 "PO_PCLATH", // Program counter Latch high register
8612 "PO_PCLATU", // Program counter Latch upper register
8613 "PO_PRODL", // Product Register Low
8614 "PO_PRODH", // Product Register High
8615 "PO_LITERAL", // A constant
8616 "PO_REL_ADDR", // A relative address
8617 "PO_IMMEDIATE", // (8051 legacy)
8618 "PO_DIR", // Direct memory (8051 legacy)
8619 "PO_CRY", // bit memory (8051 legacy)
8620 "PO_BIT", // bit operand.
8621 "PO_STR", // (8051 legacy)
8623 "PO_WILD", // Wild card operand in peep optimizer
8624 "PO_TWO_OPS" // combine two operands
8628 char *dumpPicOptype(PIC_OPTYPE type)
8630 assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8631 return (pic_optype_names[ type ]);
8635 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8638 #define MAX_COMMON_BANK_SIZE 32
8639 #define FIRST_PSEUDO_BANK_NR 1000
8641 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8642 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8643 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8646 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8649 pseudoBankNr bank; // number assigned to this pseudoBank
8650 unsigned int size; // number of operands assigned to this bank
8651 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8654 /*----------------------------------------------------------------------*/
8655 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8656 /*----------------------------------------------------------------------*/
8657 unsigned int hashSymbol (const char *str)
8659 unsigned int res = 0;
8664 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8671 /*-----------------------------------------------------------------------*/
8672 /* compareSymbol - return 1 iff sym1 equals sym2 */
8673 /*-----------------------------------------------------------------------*/
8674 int compareSymbol (const void *sym1, const void *sym2)
8676 char *s1 = (char*) sym1;
8677 char *s2 = (char*) sym2;
8679 return (strcmp (s1,s2) == 0);
8682 /*-----------------------------------------------------------------------*/
8683 /* comparePre - return 1 iff p1 == p2 */
8684 /*-----------------------------------------------------------------------*/
8685 int comparePtr (const void *p1, const void *p2)
8690 /*----------------------------------------------------------*/
8691 /* getSymbolFromOperand - return a pointer to the symbol in */
8692 /* the given operand and its length */
8693 /*----------------------------------------------------------*/
8694 char *getSymbolFromOperand (char *op, int *len)
8699 if (!op) return NULL;
8701 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8703 if (*sym == '(') sym++;
8706 while (((*curr >= 'A') && (*curr <= 'Z'))
8707 || ((*curr >= 'a') && (*curr <= 'z'))
8708 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8709 || (*curr == '_')) {
8710 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8718 /*--------------------------------------------------------------------------*/
8719 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8720 /*--------------------------------------------------------------------------*/
8721 char *getSymFromBank (pseudoBankNr bank)
8725 if (bank < 0) return "<INVALID BANK NR>";
8726 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8729 /*-----------------------------------------------------------------------*/
8730 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8731 /* bank number (uses hTab sym2bank), if the */
8732 /* symbol is not yet assigned a pseudo bank it */
8733 /* is assigned one here */
8734 /*-----------------------------------------------------------------------*/
8735 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8737 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8743 hash = hashSymbol (op) % sym2bank->size;
8744 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8745 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8747 if (bank == UNKNOWN_BANK) {
8748 // create a pseudo bank for the operand
8750 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8751 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8752 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8753 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8755 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8763 /*--------------------------------------------------------------------*/
8764 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8765 /*--------------------------------------------------------------------*/
8766 int isBanksel (pCode *pc)
8770 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8771 // BANKSEL <variablename> or MOVLB <banknr>
8772 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8776 // check for inline assembler BANKSELs
8777 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8778 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8779 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8783 // assume pc is no BANKSEL instruction
8787 /*---------------------------------------------------------------------------------*/
8788 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8789 /* This method can not guarantee to find all modifications of the */
8790 /* BSR (e.g. via INDirection registers) but covers all compiler */
8791 /* generated plus some cases. */
8792 /*---------------------------------------------------------------------------------*/
8793 int invalidatesBSR(pCode *pc)
8795 // assembler directives invalidate BSR (well, they might, we don't know)
8796 if (isPCAD(pc)) return 1;
8798 // only ASMDIRs and pCodeInstructions can invalidate BSR
8799 if (!isPCI(pc)) return 0;
8801 // we have a pCodeInstruction
8803 // check for BSR modifying instructions
8804 switch (PCI(pc)->op) {
8808 case POC_RETFIE: // might be used as CALL replacement
8809 case POC_RETLW: // might be used as CALL replacement
8810 case POC_RETURN: // might be used as CALL replacement
8815 default: // other instruction do not change BSR unless BSR is an explicit operand!
8816 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8820 // no change of BSR possible/probable
8824 /*------------------------------------------------------------*/
8825 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8826 /* the symbol referenced in this BANKSEL */
8827 /*------------------------------------------------------------*/
8828 pseudoBankNr getBankFromBanksel (pCode *pc)
8833 if (!pc) return INVALID_BANK;
8835 if (isPCAD(pc) && PCAD(pc)->directive) {
8836 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8837 // get symbolname from PCAD(pc)->arg
8838 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8839 sym = PCAD(pc)->arg;
8840 data = getPseudoBankNrFromOperand (sym);
8841 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8842 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8843 // get (literal) bank number from PCAD(pc)->arg
8844 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8845 assert (0 && "not yet implemented - turn off banksel optimization for now");
8847 } else if (isPCI(pc)) {
8848 if (PCI(pc)->op == POC_BANKSEL) {
8849 // get symbolname from PCI(pc)->pcop->name (?)
8850 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8851 sym = PCI(pc)->pcop->name;
8852 data = getPseudoBankNrFromOperand (sym);
8853 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8854 } else if (PCI(pc)->op == POC_MOVLB) {
8855 // get (literal) bank number from PCI(pc)->pcop->name
8856 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8857 assert (0 && "not yet implemented - turn off banksel optimization for now");
8862 // no assigned bank could be found
8863 return UNKNOWN_BANK;
8868 /*------------------------------------------------------------------------------*/
8869 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8870 /*------------------------------------------------------------------------------*/
8871 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8875 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8878 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8879 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8881 if (data->bank != bank)
8888 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8892 /*------------------------------------------------------------------*/
8893 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8894 /* bank is selected at a given pCode */
8895 /*------------------------------------------------------------------*/
8897 /* Create a graph with pseudo banks as its nodes and switches between
8898 * these as edges (with the edge weight representing the absolute
8899 * number of BANKSELs from one to the other).
8900 * Removes redundand BANKSELs instead iff mod == 1.
8901 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8902 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8904 * TODO: check ALL instructions operands if they modify BSR directly...
8906 * pb - the pBlock to annotate
8907 * mod - select either graph creation (0) or BANKSEL removal (1)
8909 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8911 pCode *pc, *pc_next;
8912 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8913 int isBankselect = 0;
8914 unsigned int banksels=0;
8918 pc = pic16_findNextInstruction(pb->pcHead);
8920 isBankselect = isBanksel (pc);
8921 pc_next = pic16_findNextInstruction (pc->next);
8923 if (!hasNoLabel (pc)) {
8924 // we don't know our predecessors -- assume different BSRs
8925 prevBSR = UNKNOWN_BANK;
8926 pseudoBSR = UNKNOWN_BANK;
8927 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8930 // check if this is a BANKSEL instruction
8932 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
8933 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
8935 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
8936 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
8937 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
8938 pic16_unlinkpCode (pc);
8942 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
8947 if (!isBankselect && invalidatesBSR(pc)) {
8948 // check if this instruction invalidates the pseudoBSR
8949 pseudoBSR = UNKNOWN_BANK;
8950 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
8953 prevBSR = pseudoBSR;
8960 /*------------------------------------------------------------------------------------*/
8961 /* assignToSameBank - returns 0 on success or an error code */
8962 /* 1 - common bank would be too large */
8963 /* 2 - assignment to fixed (absolute) bank not performed */
8965 /* This functions assumes that unsplittable operands are already assigned to the same */
8966 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
8967 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
8968 /* TODO: Symbols with an abslute address must be handled specially! */
8969 /*------------------------------------------------------------------------------------*/
8970 int assignToSameBank (int bank0, int bank1, int doAbs, int force)
8972 int eff0, eff1, dummy;
8973 pseudoBank *pbank0, *pbank1;
8976 eff0 = getEffectiveBank (bank0);
8977 eff1 = getEffectiveBank (bank1);
8979 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
8981 // nothing to do if already same bank
8982 if (eff0 == eff1) return 0;
8984 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
8987 // ensure eff0 < eff1
8989 // swap eff0 and eff1
8998 // now assign bank eff1 to bank eff0
8999 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9001 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9002 pbank0->bank = eff0;
9005 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9009 hitem = hTabSearch (coerce, eff1 % coerce->size);
9010 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9011 hitem = hitem->next;
9013 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9016 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9017 pbank0->bank, pbank0->size,
9018 getSymFromBank (eff0), getSymFromBank (eff1));
9022 if (!force && (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE)) {
9024 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9025 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9026 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9027 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9031 pbank0->size += pbank1->size;
9033 if (pbank1->ref == 0) Safe_free (pbank1);
9039 hitem->item = pbank0;
9041 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9044 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9049 /*----------------------------------------------------------------*/
9050 /* mergeGraphNodes - combines two nodes into one and modifies all */
9051 /* edges to and from the nodes accordingly */
9052 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9053 /* then also (B,A) must be an edge (possibly with weight 0). */
9054 /*----------------------------------------------------------------*/
9055 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9057 GraphEdge *edge, *backedge, *nextedge;
9061 assert (node1 && node2);
9062 assert (node1 != node2);
9064 // add all edges starting at node2 to node1
9067 nextedge = edge->next;
9069 backedge = getGEdge (node, node2);
9071 backweight = backedge->weight;
9074 // insert edges (node1,node) and (node,node1)
9075 addGEdge2 (node1, node, edge->weight, backweight);
9076 // remove edges (node, node2) and (node2, node)
9077 remGEdge (node2, node);
9078 remGEdge (node, node2);
9082 // now node2 should not be referenced by any other GraphNode...
9083 //remGNode (adj, node2->data, node2->hash);
9086 /*----------------------------------------------------------------*/
9087 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9088 /*----------------------------------------------------------------*/
9089 void showGraph (Graph *g)
9093 pseudoBankNr bankNr;
9100 bankNr = getEffectiveBank (node->hash);
9101 assert (bankNr >= 0);
9102 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9104 bankNr = pbank->bank;
9110 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9113 if (edge->weight > 0)
9114 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9121 /*---------------------------------------------------------------*/
9122 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9123 /*---------------------------------------------------------------*/
9124 void pic16_OptimizeBanksel ()
9126 GraphNode *node, *node1, *node1next;
9129 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9130 GraphEdge *edge, *backedge;
9132 int maxWeight, weight, mergeMore, absMaxWeight;
9133 pseudoBankNr curr0, curr1;
9136 pseudoBankNr bankNr;
9137 char *base_symbol0, *base_symbol1;
9142 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9144 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9146 if (!the_pFile || !the_pFile->pbHead) return;
9148 adj = newGraph (NULL);
9149 sym2bank = newHashTable ( 255 );
9150 bank2sym = newHashTable ( 255 );
9151 coerce = newHashTable ( 255 );
9153 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9154 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9155 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9159 // assign symbols with absolute addresses to their respective bank nrs
9160 set = pic16_fix_udata;
9161 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9162 bankNr = reg->address >> 8;
9163 node = getOrAddGNode (adj, NULL, bankNr);
9164 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9165 assignToSameBank (node->hash, bankNr, 1, 1);
9167 assert (bankNr >= 0);
9168 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9170 pbank = Safe_calloc (1, sizeof (pseudoBank));
9171 pbank->bank = reg->address >> 8; //FIXED_BANK;
9174 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9176 assert (pbank->bank == (reg->address >> 8));
9177 pbank->bank = reg->address >> 8; //FIXED_BANK;
9180 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9185 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9186 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9189 if (node->hash < 0) { node = node->next; continue; }
9190 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9193 if (node1->hash < 0) { node1 = node1->next; continue; }
9194 node1next = node1->next;
9195 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9196 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9198 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9199 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9200 if (0 != (res = assignToSameBank (node->hash, node1->hash, 0, 1))) {
9201 fprintf (stderr, "%s(%d) == %s(%d), res=%d\n", base_symbol0, len0, base_symbol1, len1, res);
9202 assert (0 && "Could not assign a symbol to a bank!");
9204 mergeGraphNodes (node, node1);
9206 if (node->hash < node1->hash)
9207 mergeGraphNodes (node, node1);
9209 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9219 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9220 // assign tightly coupled operands to the same (pseudo) bank
9221 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9229 curr0 = getEffectiveBank (node->hash);
9230 if (curr0 < 0) { node = node->next; continue; }
9233 assert (edge->src == node);
9234 backedge = getGEdge (edge->node, edge->src);
9235 weight = edge->weight + (backedge ? backedge->weight : 0);
9236 curr1 = getEffectiveBank (edge->node->hash);
9237 if (curr1 < 0) { edge = edge->next; continue; }
9239 // merging is only useful if the items are not assigned to the same bank already...
9240 if (curr0 != curr1 && weight > maxWeight) {
9241 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9250 if (maxWeight > 0) {
9252 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9253 max->src->hash, getSymFromBank (max->src->hash),
9254 max->node->hash, getSymFromBank (max->node->hash));
9257 node = getGNode (adj, max->src->data, max->src->hash);
9258 node1 = getGNode (adj, max->node->data, max->node->hash);
9260 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0, 0)) {
9261 if (max->src->hash < max->node->hash)
9262 mergeGraphNodes (node, node1);
9264 mergeGraphNodes (node1, node);
9266 remGEdge (node, node1);
9267 remGEdge (node1, node);
9278 // remove redundant BANKSELs
9279 //fprintf (stderr, "removing redundant BANKSELs\n");
9280 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9281 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9286 fprintf (stderr, "display graph\n");
9291 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9294 /*** END of stuff belonging to the BANKSEL optimization ***/
9298 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9300 typedef unsigned int symbol_t;
9301 typedef unsigned int valnum_t;
9302 //typedef unsigned int hash_t;
9305 #define INT_TO_PTR(x) (((char *) 0) + (x))
9309 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9312 static int pic16_regIsLocal (regs *r);
9313 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9316 static unsigned int pic16_df_removed_pcodes = 0;
9317 static unsigned int pic16_df_saved_bytes = 0;
9318 static unsigned int df_findall_sameflow = 0;
9319 static unsigned int df_findall_otherflow = 0;
9320 static unsigned int df_findall_in_vals = 0;
9322 static void pic16_df_stats () {
9324 if (pic16_debug_verbose || pic16_pcode_verbose) {
9325 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9326 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9327 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9331 /* Remove a pCode iff possible:
9332 * - previous pCode is no SKIP
9334 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9335 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9336 pCode *pcprev, *pcnext;
9337 char buf[256], *total=NULL;
9340 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9342 pcprev = pic16_findPrevInstruction (pc->prev);
9343 pcnext = pic16_findNextInstruction (pc->next);
9345 /* move labels to next instruction (if possible) */
9346 if (PCI(pc)->label && !pcnext) return 0;
9348 /* if this is a SKIP with side-effects -- do not remove */
9349 /* XXX: might try to replace this one with the side-effect only version */
9351 && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9354 switch (PCI(pc)->op)
9358 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9359 pic16_pCodeReplace( pc, newpc );
9363 newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9364 pic16_pCodeReplace( pc, newpc );
9369 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9370 pic16_pCodeReplace( pc, newpc );
9374 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9375 pic16_pCodeReplace( pc, newpc );
9384 /* if previous instruction is a skip -- do not remove */
9385 if (pcprev && isPCI_SKIP(pcprev)) {
9386 if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9387 /* preceeding SKIP could not be removed -- keep this instruction! */
9392 if (PCI(pc)->label) {
9393 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9394 //pc->print (stderr, pc);
9395 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9396 PCI(pc)->label = NULL;
9399 /* update statistics */
9400 pic16_df_removed_pcodes++;
9401 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9403 /* remove the pCode */
9404 pic16_pCode2str (buf, 256, pc);
9405 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9406 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9407 len = strlen (buf) + strlen (comment) + 10;
9408 total = (char *) Safe_malloc (len);
9409 SNPRINTF (total, len, "%s: %s", comment, buf);
9410 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9414 /* actually unlink it from the pBlock -- also remove from to/from lists */
9415 pic16_pCodeUnlink (pc);
9417 /* remove the pCode -- release registers */
9420 /* report success */
9425 /* ======================================================================== */
9426 /* === SYMBOL HANDLING ==================================================== */
9427 /* ======================================================================== */
9429 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9430 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9431 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9433 /** Calculate a hash for a given string.
9434 * If len == 0 the string is assumed to be NUL terminated. */
9435 static hash_t symbolHash (const char *str, unsigned int len) {
9439 hash = (hash << 2) ^ *str;
9444 hash = (hash << 2) ^ *str;
9451 /** Return 1 iff strings v1 and v2 are identical. */
9452 static int symcmp (const void *v1, const void *v2) {
9453 return !strcmp ((const char *) v1, (const char *) v2);
9456 /** Return 1 iff pointers v1 and v2 are identical. */
9457 static int ptrcmp (const void *v1, const void *v2) {
9461 enum { SPO_WREG=0x1000,
9501 /* Return the unique symbol_t for the given string. */
9502 static symbol_t symFromStr (const char *str) {
9507 if (!map_symToStr) {
9509 struct { char *name; symbol_t sym; } predefsyms[] = {
9511 {"STATUS", SPO_STATUS},
9512 {"PRODL", SPO_PRODL},
9513 {"PRODH", SPO_PRODH},
9514 {"INDF0", SPO_INDF0},
9515 {"POSTDEC0", SPO_POSTDEC0},
9516 {"POSTINC0", SPO_POSTINC0},
9517 {"PREINC0", SPO_PREINC0},
9518 {"PLUSW0", SPO_PLUSW0},
9519 {"INDF1", SPO_INDF1},
9520 {"POSTDEC1", SPO_POSTDEC1},
9521 {"POSTINC1", SPO_POSTINC1},
9522 {"PREINC1", SPO_PREINC1},
9523 {"PLUSW1", SPO_PLUSW1},
9524 {"INDF2", SPO_INDF2},
9525 {"POSTDEC2", SPO_POSTDEC2},
9526 {"POSTINC2", SPO_POSTINC2},
9527 {"PREINC2", SPO_PREINC2},
9528 {"PLUSW2", SPO_PLUSW2},
9529 {"STKPTR", SPO_STKPTR},
9534 {"FSR0L", SPO_FSR0L},
9535 {"FSR0H", SPO_FSR0H},
9536 {"FSR1L", SPO_FSR1L},
9537 {"FSR1H", SPO_FSR1H},
9538 {"FSR2L", SPO_FSR2L},
9539 {"FSR2H", SPO_FSR2H},
9541 {"PCLATH", SPO_PCLATH},
9542 {"PCLATU", SPO_PCLATU},
9543 {"TABLAT", SPO_TABLAT},
9544 {"TBLPTRL", SPO_TBLPTRL},
9545 {"TBLPTRH", SPO_TBLPTRH},
9546 {"TBLPTRU", SPO_TBLPTRU},
9550 map_strToSym = newHashTable (128);
9551 map_symToStr = newHashTable (128);
9553 for (i=0; predefsyms[i].name; i++) {
9556 /* enter new symbol */
9557 sym = predefsyms[i].sym;
9558 name = predefsyms[i].name;
9559 res = Safe_strdup (name);
9560 hash = symbolHash (name, 0);
9562 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9563 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9567 hash = symbolHash (str, 0) % map_strToSym->size;
9569 /* find symbol in table */
9570 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9572 //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9576 /* enter new symbol */
9578 res = Safe_strdup (str);
9580 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9581 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9583 //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9589 static const char *strFromSym (symbol_t sym) {
9590 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9594 /* ======================================================================== */
9595 /* === DEFINITION MAP HANDLING ============================================ */
9596 /* ======================================================================== */
9598 /* A defmap provides information about which symbol is defined by which pCode.
9599 * The most recent definitions are prepended to the list, so that the most
9600 * recent definition can be found by forward scanning the list.
9601 * pc2: MOVFF r0x00, r0x01
9603 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9605 * We attach one defmap to each flow object, and each pCode will occur at
9606 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9607 * used to find definitions for a pCode in its own defmap that precede pCode.
9610 typedef struct defmap_s {
9611 symbol_t sym; /** symbol this item refers to */
9614 unsigned int in_mask:8; /** mask leaving in accessed bits */
9615 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9616 int isRead:1; /** sym/mask is read */
9617 int isWrite:1; /** sym/mask is written */
9621 pCode *pc; /** pCode this symbol is refrenced at */
9622 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9623 valnum_t val; /** new unique number for this value (if isWrite) */
9624 struct defmap_s *prev, *next; /** link to previous an next definition */
9627 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9628 static int defmap_free_count = 0; /** number of released defmap items */
9630 /* Returns a defmap_t with the specified data; this will be the new list head.
9631 * next - pointer to the current list head */
9632 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9637 defmap_free = map->next;
9638 --defmap_free_count;
9640 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9643 map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9644 map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9645 map->acc.access.isRead = (isRead != 0);
9646 map->acc.access.isWrite = (isWrite != 0);
9649 map->val = (isWrite ? val : 0);
9652 if (next) next->prev = map;
9657 /* Returns a copy of the single defmap item. */
9658 static defmap_t *copyDefmap (defmap_t *map) {
9659 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9660 memcpy (res, map, sizeof (defmap_t));
9666 /* Insert a defmap item after the specified one. */
9667 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9668 if (!ref || !newItem) return 1;
9670 newItem->next = ref->next;
9671 newItem->prev = ref;
9672 ref->next = newItem;
9673 if (newItem->next) newItem->next->prev = newItem;
9678 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9679 * item is copied before insertion into chain and therefore left untouched.
9680 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9681 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9684 while (dummy && (dummy->sym != item->sym
9685 || dummy->pc != item->pc
9686 || dummy->acc.accessmethod != item->acc.accessmethod
9687 || dummy->val != item->val
9688 || dummy->in_val != item->in_val)) {
9689 dummy = dummy->next;
9692 /* item already present? */
9693 if (dummy) return 0;
9695 /* otherwise: insert copy of item */
9696 dummy = copyDefmap (item);
9697 dummy->next = *head;
9698 if (*head) (*head)->prev = dummy;
9704 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9705 static void deleteDefmap (defmap_t *map) {
9708 /* unlink from chain -- fails for the first item (head is not updated!) */
9709 if (map->next) map->next->prev = map->prev;
9710 if (map->prev) map->prev->next = map->next;
9713 memset (map, 0, sizeof (defmap_t));
9715 /* save for future use */
9716 map->next = defmap_free;
9718 ++defmap_free_count;
9721 /* Release all defmaps referenced from map. */
9722 static void deleteDefmapChain (defmap_t **_map) {
9723 defmap_t *map, *next;
9729 /* find list head */
9730 while (map && map->prev) map = map->prev;
9732 /* delete all items */
9742 /* Free all defmap items. */
9743 static void freeDefmap (defmap_t **_map) {
9751 /* find list head */
9752 while (map->prev) map = map->prev;
9754 /* release all items */
9764 /* Returns the most recent definition for the given symbol preceeding pc.
9765 * If no definition is found, NULL is returned.
9766 * If pc == NULL the whole list is scanned. */
9767 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9768 defmap_t *curr = map;
9771 /* skip all definitions up to pc */
9772 while (curr && (curr->pc != pc)) curr = curr->next;
9774 /* pc not in the list -- scan the whole list for definitions */
9776 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9779 /* skip all definitions performed by pc */
9780 while (curr && (curr->pc == pc)) curr = curr->next;
9784 /* find definition for sym */
9785 while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9793 /* Returns the first use (read) of the given symbol AFTER pc.
9794 * If no such use is found, NULL is returned.
9795 * If pc == NULL the whole list is scanned. */
9796 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9797 defmap_t *curr = map, *prev = NULL;
9800 /* skip all definitions up to pc */
9801 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9803 /* pc not in the list -- scan the whole list for definitions */
9805 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9809 /* find end of list */
9810 while (curr && curr->next) curr = curr->next;
9813 /* find use of sym (scan list backwards) */
9814 while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9820 /* Return the defmap entry for sym AT pc.
9821 * If none is found, NULL is returned.
9822 * If more than one entry is found an assertion is triggered. */
9823 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9824 defmap_t *res = NULL;
9826 /* find entries for pc */
9827 while (map && map->pc != pc) map = map->next;
9829 /* find first entry for sym @ pc */
9830 while (map && map->pc == pc && map->sym != sym) map = map->next;
9832 /* no entry found */
9833 if (!map) return NULL;
9835 /* check for more entries */
9838 while (map && map->pc == pc) {
9839 /* more than one entry for sym @ pc found? */
9840 assert (map->sym != sym);
9844 /* return single entry for sym @ pc */
9848 /* Modifies the definition of sym at pCode to newval.
9849 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9851 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9854 /* find definitions of pc */
9855 while (m && m->pc != pc) m = m->next;
9857 /* find definition of sym at pc */
9858 while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9860 /* no definition found */
9866 /* update following uses of sym */
9867 while (m && m->pc == pc) m = m->prev;
9869 if (m->sym == sym) {
9871 if (m->acc.access.isWrite) m = NULL;
9879 /* ======================================================================== */
9880 /* === STACK ROUTINES ===================================================== */
9881 /* ======================================================================== */
9883 typedef struct stack_s {
9885 struct stack_s *next;
9888 typedef stackitem_t *dynstack_t;
9889 static stackitem_t *free_stackitems = NULL;
9891 /* Create a stack with one item. */
9892 static dynstack_t *newStack () {
9893 dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9898 /* Remove a stack -- its items are only marked free. */
9899 static void deleteStack (dynstack_t *s) {
9905 i->next = free_stackitems;
9906 free_stackitems = i;
9911 /* Release all stackitems. */
9912 static void releaseStack () {
9915 while (free_stackitems) {
9916 i = free_stackitems->next;
9917 Safe_free(free_stackitems);
9918 free_stackitems = i;
9922 static void stackPush (dynstack_t *stack, void *data) {
9925 if (free_stackitems) {
9926 i = free_stackitems;
9927 free_stackitems = free_stackitems->next;
9929 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9936 static void *stackPop (dynstack_t *stack) {
9940 if (stack && *stack) {
9941 data = (*stack)->data;
9943 *stack = (*stack)->next;
9944 i->next = free_stackitems;
9945 free_stackitems = i;
9953 static int stackContains (dynstack_t *s, void *data) {
9958 if (i->data == data) return 1;
9967 static int stackIsEmpty (dynstack_t *s) {
9968 return (*s == NULL);
9977 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9978 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9980 s->lastdef = lastdef;
9984 static void deleteState (state_t *s) {
9988 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
9991 /* scan working list for state */
9995 /* is i == state? -- state not new */
9996 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10004 /* is i == state? -- state not new */
10005 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10010 /* not found -- state is new */
10014 static inline valnum_t newValnum ();
10016 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10019 if (!pb) return "<unknown function>";
10021 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10022 if (pc && isPCF(pc)) return PCF(pc)->fname;
10023 else return "<unknown function>";
10026 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10032 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10034 /* find initial value (assigning pc == NULL) */
10035 map = PCFL(pcfl)->in_vals;
10036 while (map && map->sym != sym) map = map->next;
10038 /* initial value already present? */
10040 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10044 /* create a new initial value */
10045 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10046 PCFL(pcfl)->in_vals = map;
10047 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10051 /* insert map as last item in pcfl's defmap */
10052 if (!prev) prev = PCFL(pcfl)->defmap;
10054 PCFL(pcfl)->defmap = map;
10056 while (prev->next) prev = prev->next;
10065 /* Find all reaching definitions for sym at pc.
10066 * A new (!) list of definitions is returned.
10067 * Returns the number of reaching definitions found.
10068 * The defining defmap entries are returned in *chain.
10070 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10075 pCodeFlowLink *succ;
10077 dynstack_t *todo; /** stack of state_t */
10078 dynstack_t *done; /** stack of state_t */
10080 int firstState, n_defs;
10082 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10085 /* initialize return list */
10088 /* wildcard symbol? */
10089 if (!sym) return 0;
10091 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10093 map = PCI(pc)->pcflow->defmap;
10095 res = defmapFindDef (map, sym, pc);
10096 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10098 #define USE_PRECALCED_INVALS 1
10099 #if USE_PRECALCED_INVALS
10100 if (!res && PCI(pc)->pcflow->in_vals) {
10101 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10103 //fprintf (stderr, "found def in init values\n");
10104 df_findall_in_vals++;
10110 // found a single definition (in pc's flow)
10111 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10112 defmapAddCopyIfNew (chain, res);
10113 df_findall_sameflow++;
10117 #if USE_PRECALCED_INVALS
10119 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10125 #define FORWARD_FLOW_ANALYSIS 1
10126 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10127 /* no definition found in pc's flow preceeding pc */
10128 todo = newStack ();
10129 done = newStack ();
10130 n_defs = 0; firstState = 1;
10131 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10133 while (!stackIsEmpty (todo)) {
10134 state = (state_t *) stackPop (todo);
10135 stackPush (done, state);
10136 curr = state->flow;
10137 res = state->lastdef;
10138 //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);
10140 /* there are no definitions BEFORE pc in pc's flow (see above) */
10141 if (curr == PCI(pc)->pcflow) {
10143 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10144 res = pic16_pBlockAddInval (pc->pb, sym);
10145 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10148 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10149 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10153 /* save last definition of sym in this flow as initial def in successors */
10154 res = defmapFindDef (curr->defmap, sym, NULL);
10155 if (!res) res = state->lastdef;
10157 /* add successors to working list */
10158 state = newState (NULL, NULL);
10159 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10161 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10162 state->flow = succ->pcflow;
10163 state->lastdef = res;
10164 if (stateIsNew (state, todo, done)) {
10165 stackPush (todo, state);
10166 state = newState (NULL, NULL);
10168 succ = (pCodeFlowLink *) setNextItem (curr->to);
10170 deleteState (state);
10173 #else // !FORWARD_FLOW_ANALYSIS
10175 /* no definition found in pc's flow preceeding pc */
10176 todo = newStack ();
10177 done = newStack ();
10178 n_defs = 0; firstState = 1;
10179 stackPush (todo, newState (PCI(pc)->pcflow, res));
10181 while (!stackIsEmpty (todo)) {
10182 state = (state_t *) stackPop (todo);
10183 curr = state->flow;
10187 /* only check predecessor flows */
10189 /* get (last) definition of sym in this flow */
10190 res = defmapFindDef (curr->defmap, sym, NULL);
10194 /* definition found */
10195 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10196 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10198 /* no definition found -- check predecessor flows */
10199 state = newState (NULL, NULL);
10200 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10202 /* if no flow predecessor available -- sym might be uninitialized */
10204 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10205 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10206 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10207 deleteDefmap (res); res = NULL;
10211 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10212 state->flow = succ->pcflow;
10213 state->lastdef = res;
10214 if (stateIsNew (state, todo, done)) {
10215 stackPush (todo, state);
10216 state = newState (NULL, NULL);
10218 succ = (pCodeFlowLink *) setNextItem (curr->from);
10220 deleteState (state);
10226 /* clean up done stack */
10227 while (!stackIsEmpty(done)) {
10228 deleteState ((state_t *) stackPop (done));
10230 deleteStack (done);
10232 /* return number of items in result set */
10234 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10235 } else if (n_defs == 1) {
10237 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10238 } else if (n_defs > 0) {
10239 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10243 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10248 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10249 df_findall_otherflow++;
10253 /* ======================================================================== */
10254 /* === VALUE NUMBER HANDLING ============================================== */
10255 /* ======================================================================== */
10257 static valnum_t nextValnum = 0x1000;
10258 static hTab *map_symToValnum = NULL;
10260 /** Return a new value number. */
10261 static inline valnum_t newValnum () {
10262 return (nextValnum += 4);
10265 static valnum_t valnumFromStr (const char *str) {
10270 sym = symFromStr (str);
10272 if (!map_symToValnum) {
10273 map_symToValnum = newHashTable (128);
10276 /* literal already known? */
10277 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10279 /* return existing valnum */
10280 if (res) return (valnum_t) PTR_TO_INT(res);
10282 /* create new valnum */
10284 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10285 //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10289 /* Create a valnum for a literal. */
10290 static valnum_t valnumFromLit (unsigned int lit) {
10291 return ((valnum_t) 0x100 + (lit & 0x0FF));
10294 /* Return the (positive) literal value represented by val
10295 * or -1 iff val is no known literal's valnum. */
10296 static int litFromValnum (valnum_t val) {
10297 if (val >= 0x100 && val < 0x200) {
10298 /* valnum is a (known) literal */
10299 return val & 0x00FF;
10301 /* valnum is not a known literal */
10307 /* Sanity check - all flows in a block must be reachable from initial flow. */
10308 static int verifyAllFlowsReachable (pBlock *pb) {
10314 pCodeFlowLink *succ;
10317 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10320 flowInBlock = NULL;
10322 /* mark initial flow as reached (and "not needs to be reached") */
10323 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10325 addSetHead (&reached, pc);
10326 addSetHead (&checked, pc);
10328 /* mark all further flows in block as "need to be reached" */
10331 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10332 pc = pic16_findNextInstruction (pc->next);
10335 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10336 /* mark as reached and "not need to be reached" */
10337 deleteSetItem (&reached, pcfl);
10338 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10340 /* flow is no longer considered unreachable */
10341 deleteSetItem (&flowInBlock, pcfl);
10343 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10344 if (!isinSet (checked, succ->pcflow)) {
10345 /* flow has never been reached before */
10346 addSetHead (&reached, succ->pcflow);
10347 addSetHead (&checked, succ->pcflow);
10352 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10354 /* by now every flow should have been reached
10355 * --> flowInBlock should be empty */
10356 res = (flowInBlock == NULL);
10360 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10361 while (flowInBlock) {
10362 pcfl = indexSet (flowInBlock, 0);
10363 fprintf (stderr, "not reached: flow %p\n", pcfl);
10364 deleteSetItem (&flowInBlock, pcfl);
10370 deleteSet (&reached);
10371 deleteSet (&flowInBlock);
10372 deleteSet (&checked);
10374 /* if we reached every flow, succ is NULL by now... */
10375 //assert (res); // will fire on unreachable code...
10380 /* Checks a flow for accesses to sym AFTER pc.
10382 * Returns -1 if the symbol is read in this flow (before redefinition),
10383 * returns 0 if the symbol is redefined in this flow or
10384 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10386 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10387 defmap_t *map, *mappc;
10389 /* find pc or start of definitions */
10390 map = pcfl->defmap;
10391 while (map && (map->pc != pc) && map->next) map = map->next;
10392 /* if we found pc -- ignore it */
10393 while (map && map->pc == pc) map = map->prev;
10395 /* scan list backwards (first definition first) */
10396 while (map && mask) {
10397 // if (map->sym == sym) {
10398 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10400 /* scan list for reads at this pc first */
10401 while (map && map->pc == mappc->pc) {
10402 /* is the symbol (partially) read? */
10403 if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10404 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10411 while (map && map->pc == mappc->pc) {
10412 /* honor (partial) redefinitions of sym */
10413 if ((map->sym == sym) && (map->acc.access.isWrite)) {
10414 mask &= ~map->acc.access.mask;
10415 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10420 /* map already points to the first defmap for the next pCode */
10421 //map = mappc->prev;
10424 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10425 * is still alive; return the appropriate mask of alive bits */
10429 /* Check whether a symbol is alive (AFTER pc). */
10430 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10433 dynstack_t *todo, *done;
10436 pCodeFlowLink *succ;
10440 assert (isPCI(pc));
10441 pcfl = PCI(pc)->pcflow;
10442 map = pcfl->defmap;
10444 todo = newStack ();
10445 done = newStack ();
10447 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10448 stackPush (todo, state);
10451 while (!stackIsEmpty (todo)) {
10452 state = (state_t *) stackPop (todo);
10453 pcfl = state->flow;
10454 mask = PTR_TO_INT(state->lastdef);
10455 if (visit) stackPush (done, state); else deleteState(state);
10456 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10457 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10458 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10461 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10462 if (mask == 0) continue;
10464 /* symbol is (partially) read before redefinition in flow */
10465 if (mask == -1) break;
10467 /* symbol is neither read nor completely redefined -- check successor flows */
10468 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10469 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10470 if (stateIsNew (state, todo, done)) {
10471 stackPush (todo, state);
10473 deleteState (state);
10478 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10479 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10481 /* symbol is read in at least one flow -- is alive */
10482 if (mask == -1) return 1;
10484 /* symbol is read in no flow */
10488 /* Returns whether access to the given symbol has side effects. */
10489 static int pic16_symIsSpecial (symbol_t sym) {
10490 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10510 /* no special effects known */
10517 /* Check whether a register should be considered local (to the current function) or not. */
10518 static int pic16_regIsLocal (regs *r) {
10521 if (r->type == REG_TMP) return 1;
10523 sym = symFromStr (r->name);
10526 case SPO_FSR0L: // used in ptrget/ptrput
10527 case SPO_FSR0H: // ... as well
10528 case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10529 case SPO_FSR1H: // ... as well
10530 case SPO_FSR2L: // used as frame pointer
10531 case SPO_FSR2H: // ... as well
10532 case SPO_PRODL: // used to return values from functions
10533 case SPO_PRODH: // ... as well
10534 /* these registers (and some more...) are considered local */
10538 /* for unknown regs: check is marked local, leave if not */
10542 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10548 /* if in doubt, assume non-local... */
10552 /* Check all symbols touched by pc whether their newly assigned values are read.
10553 * Returns 0 if no symbol is used later on, 1 otherwise. */
10554 static int pic16_pCodeIsAlive (pCode *pc) {
10555 pCodeInstruction *pci;
10556 defmap_t *map, *lastpc;
10559 /* we can only handle PCIs */
10560 if (!isPCI(pc)) return 1;
10562 //pc->print (stderr, pc);
10565 assert (pci && pci->pcflow && pci->pcflow->defmap);
10567 /* NEVER remove instructions with implicit side effects */
10570 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10571 case POC_TBLRD_POSTDEC:
10572 case POC_TBLRD_PREINC:
10573 case POC_TBLWT: /* modify program memory */
10574 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10575 case POC_TBLWT_POSTDEC:
10576 case POC_TBLWT_PREINC:
10577 case POC_CLRWDT: /* clear watchdog timer */
10578 case POC_PUSH: /* should be safe to remove though... */
10579 case POC_POP: /* should be safe to remove though... */
10584 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10588 /* no special instruction */
10592 /* prevent us from removing assignments to non-local variables */
10594 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10595 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10597 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10598 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10599 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10600 //pc->print (stderr, pc);
10603 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10604 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10609 /* OVERKILL: prevent us from removing reads from non-local variables
10610 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10611 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10613 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10614 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10616 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10617 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10618 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10619 //pc->print (stderr, pc);
10622 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10623 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10628 /* now check that the defined symbols are not used */
10629 map = pci->pcflow->defmap;
10631 /* find items for pc */
10632 while (map && map->pc != pc) map = map->next;
10634 /* no entries found? something is fishy with DF analysis... -- play safe */
10636 if (pic16_pcode_verbose) {
10637 fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10642 /* remember first item assigned to pc for later use */
10645 /* check all symbols being modified by pc */
10646 while (map && map->pc == pc) {
10647 if (map->sym == 0) { map = map->next; continue; }
10649 /* keep pc if it references special symbols (like POSTDEC0) */
10653 pic16_pCode2str (buf, 256, pc);
10654 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10657 if (pic16_symIsSpecial (map->sym)) {
10658 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10661 if (map->acc.access.isWrite) {
10662 if (pic16_isAlive (map->sym, pc)) {
10663 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10670 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10674 pic16_pCode2str (buf, 256, pc);
10675 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10681 /* Adds implied operands to the list.
10682 * sym - operand being accessed in the pCode
10683 * list - list to append the operand
10684 * isRead - set to 1 iff sym is read in pCode
10685 * listRead - set to 1 iff all operands being read are to be listed
10687 * Returns 0 for "normal" operands, 1 for special operands.
10689 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10690 /* check whether accessing REG accesses other REGs as well */
10694 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10695 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10696 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10700 /* reads FSR0x and WREG */
10701 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10702 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10703 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10704 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10710 /* reads/modifies FSR0x */
10711 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10712 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10713 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10718 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10719 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10720 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10724 /* reads FSR1x and WREG */
10725 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10726 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10727 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10728 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10734 /* reads/modifies FSR1x */
10735 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10736 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10737 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10742 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10743 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10744 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10748 /* reads FSR2x and WREG */
10749 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10750 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10751 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10752 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10758 /* reads/modifies FSR2x */
10759 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10760 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10761 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10765 /* modifies PCLATH and PCLATU */
10766 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10768 /* reading PCL updates PCLATx */
10769 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10770 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10773 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10774 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10775 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10780 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10781 /* nothing special */
10786 /* has been a special operand */
10790 static symbol_t pic16_fsrsym_idx[][2] = {
10791 {SPO_FSR0L, SPO_FSR0H},
10792 {SPO_FSR1L, SPO_FSR1H},
10793 {SPO_FSR2L, SPO_FSR2H}
10796 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10797 static void mergeDefmapSymbols (defmap_t *list) {
10798 defmap_t *ref, *curr, *temp;
10800 /* now make sure that each symbol occurs at most once per pc */
10802 while (ref && (ref->pc == list->pc)) {
10804 while (curr && (curr->pc == list->pc)) {
10805 if (curr->sym == ref->sym) {
10806 //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10807 /* found a symbol occuring twice... merge the two */
10808 if (curr->acc.access.isRead) {
10809 //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10810 ref->acc.access.isRead = 1;
10811 ref->acc.access.in_mask |= curr->acc.access.in_mask;
10813 if (curr->acc.access.isWrite) {
10814 //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10815 ref->acc.access.isWrite = 1;
10816 ref->acc.access.mask |= curr->acc.access.mask;
10820 deleteDefmap (temp);
10821 continue; // do not skip curr!
10829 /** Prepend list with the reads and definitions performed by pc. */
10830 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10831 pCodeInstruction *pci;
10832 int cond, inCond, outCond;
10833 int mask = 0xff, smask;
10834 int isSpecial, isSpecial2;
10835 symbol_t sym, sym2;
10839 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10840 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10841 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10842 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10845 assert (isPCI(pc));
10848 /* handle bit instructions */
10849 if (pci->isBitInst) {
10850 assert (pci->pcop->type == PO_GPR_BIT);
10851 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10854 /* handle (additional) implicit arguments */
10860 lit = PCOL(pci->pcop)->lit;
10861 assert (lit >= 0 && lit < 3);
10862 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10863 val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10864 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10865 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10866 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...
10870 case POC_MOVLB: // BSR
10871 case POC_BANKSEL: // BSR
10872 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10875 case POC_MULWF: // PRODx
10876 case POC_MULLW: // PRODx
10877 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10878 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10881 case POC_POP: // TOS, STKPTR
10882 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10883 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10884 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10885 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10888 case POC_PUSH: // STKPTR
10889 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10890 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10891 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10892 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10895 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10896 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10897 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10898 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10899 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10900 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10902 /* needs correctly set-up stack pointer */
10903 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10904 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10907 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10908 /* pseudo read on (possible) return values */
10909 // WREG is handled below via outCond
10910 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10911 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10912 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10914 /* caller's stack pointers must be restored */
10915 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10916 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10917 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10918 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10921 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10922 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10923 /* pseudo read on (possible) return values */
10924 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10925 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10926 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10927 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10929 /* caller's stack pointers must be restored */
10930 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10931 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10932 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10933 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10937 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10938 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10939 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10940 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10943 case POC_TBLRD_POSTINC:
10944 case POC_TBLRD_POSTDEC:
10945 case POC_TBLRD_PREINC:
10946 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10947 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10948 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10949 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10953 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10954 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10955 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10956 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10959 case POC_TBLWT_POSTINC:
10960 case POC_TBLWT_POSTDEC:
10961 case POC_TBLWT_PREINC:
10962 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10963 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10964 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10965 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10969 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10973 /* handle explicit arguments */
10974 inCond = pci->inCond;
10975 outCond = pci->outCond;
10976 cond = inCond | outCond;
10977 if (cond & PCC_W) {
10978 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10981 /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
10982 if (inCond & PCC_STATUS) {
10984 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10985 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10986 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10987 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10988 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10990 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10991 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10994 if (outCond & PCC_STATUS) {
10996 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10997 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10998 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10999 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11000 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11002 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11003 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11006 isSpecial = isSpecial2 = 0;
11008 if (cond & PCC_REGISTER) {
11009 name = pic16_get_op (pci->pcop, NULL, 0);
11010 sym = symFromStr (name);
11011 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11012 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11015 if (cond & PCC_REGISTER2) {
11016 name = pic16_get_op2 (pci->pcop, NULL, 0);
11017 sym2 = symFromStr (name);
11018 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11019 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11023 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11024 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11026 mergeDefmapSymbols (list);
11032 static void printDefmap (defmap_t *map) {
11036 fprintf (stderr, "defmap @ %p:\n", curr);
11038 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11039 curr->acc.access.isRead ? "R" : " ",
11040 curr->acc.access.isWrite ? "W": " ",
11041 curr->in_val, curr->val,
11042 curr->acc.access.in_mask, curr->acc.access.mask,
11043 strFromSym(curr->sym), curr->sym,
11047 fprintf (stderr, "<EOL>\n");
11051 /* Add "additional" definitions to uniq.
11052 * 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.
11053 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11055 * If symbols defined in additional are not present in uniq, a definition is created.
11056 * Otherwise the present definition is altered to reflect the newer assignments.
11058 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11059 * before `------- noted in additional --------' after
11061 * I assume that each symbol occurs AT MOST ONCE in uniq.
11064 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11069 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11070 /* find tail of additional list (holds the first assignment) */
11072 while (curr && curr->next) curr = curr->next;
11076 /* find next assignment in additionals */
11077 while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11081 /* find item in uniq */
11083 //printDefmap (*uniq);
11084 while (old && (old->sym != curr->sym)) old = old->next;
11087 /* definition found -- replace */
11088 if (old->val != curr->val) {
11089 old->val = curr->val;
11093 /* new definition */
11094 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11101 /* return 0 iff uniq remained unchanged */
11105 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11106 * lists of its predecessor flows.
11107 * Initially *combined should be NULL, alt_in will be copied to combined.
11108 * If *combined != NULL, combined will be altered:
11109 * - for symbols defined in *combined but not in alt_in,
11110 * *combined is altered to 0 (value unknown, either *combined or INIT).
11111 * - for symbols defined in alt_in but not in *combined,
11112 * a 0 definition is created (value unknown, either INIT or alt).
11113 * - for symbols defined in both, *combined is:
11114 * > left unchanged if *combined->val == alt_in->val or
11115 * > modified to 0 otherwise (value unknown, either alt or *combined).
11117 * I assume that each symbol occurs AT MOST ONCE in each list!
11119 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11125 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11127 if (!(*combined)) {
11128 return defmapUpdateUniqueSym (combined, alt_in);
11131 /* merge the two */
11134 /* find symbols definition in *combined */
11136 while (old && (old->sym != curr->sym)) old = old->next;
11139 /* definition found */
11140 if (old->val && (old->val != curr->val)) {
11141 old->val = 0; /* value unknown */
11145 /* no definition found -- can be either INIT or alt_in's value */
11146 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11147 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11148 if (val != curr->val) change++;
11154 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11157 if (old->val != 0) {
11158 /* find definition in alt_in */
11160 while (curr && curr->sym != old->sym) curr = curr->next;
11162 /* symbol defined in *combined only -- can be either INIT or *combined */
11163 val = pic16_pBlockAddInval (pb, old->sym)->val;
11164 if (old->val != val) {
11177 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11178 defmap_t *curr1, *curr2;
11181 /* identical maps are equal */
11182 if (map1 == map2) return 0;
11184 if (!map1) return -1;
11185 if (!map2) return 1;
11187 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11192 while (curr1 && curr2) {
11193 curr1 = curr1->next;
11194 curr2 = curr2->next;
11197 /* one of them longer? */
11198 if (curr1) return 1;
11199 if (curr2) return -1;
11201 /* both lists are of equal length -- compare (in O(n^2)) */
11206 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11207 if (!curr2) return 1; // symbol not found in curr2
11208 if (curr2->val != curr1->val) return 1; // values differ
11210 /* compare next symbol */
11211 curr1 = curr1->next;
11214 /* no difference found */
11219 /* Prepare a list of all reaching definitions per flow.
11220 * This is done using a forward dataflow analysis.
11222 static void createReachingDefinitions (pBlock *pb) {
11223 defmap_t *out_vals, *in_vals;
11226 pCodeFlowLink *link;
11232 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11233 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11235 deleteDefmapChain (&PCFL(pc)->in_vals);
11236 deleteDefmapChain (&PCFL(pc)->out_vals);
11237 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11241 pc = pic16_findNextInstruction (pb->pcHead);
11243 // empty function, avoid NULL pointer dereference
11246 todo = NULL; blacklist = NULL;
11247 addSetHead (&todo, PCI(pc)->pcflow);
11249 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11250 while (elementsInSet (todo)) {
11251 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11252 pcfl = PCFL(indexSet (todo, 0));
11253 deleteSetItem (&todo, pcfl);
11254 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11258 if (isinSet (blacklist, pcfl)) {
11259 fprintf (stderr, "ignoring blacklisted flow\n");
11263 /* create in_vals from predecessors out_vals */
11264 link = setFirstItem (pcfl->from);
11266 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11267 link = setNextItem (pcfl->from);
11270 //printDefmap (in_vals);
11271 //printDefmap (pcfl->in_vals);
11273 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11274 //fprintf (stderr, "in_vals changed\n");
11275 /* in_vals changed -- update out_vals */
11276 deleteDefmapChain (&pcfl->in_vals);
11277 pcfl->in_vals = in_vals;
11279 /* create out_val from in_val and defmap */
11281 defmapUpdateUniqueSym (&out_vals, in_vals);
11282 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11284 /* is out_vals different from pcfl->out_vals */
11285 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11286 //fprintf (stderr, "out_vals changed\n");
11287 deleteDefmapChain (&pcfl->out_vals);
11288 pcfl->out_vals = out_vals;
11290 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11291 addSet (&blacklist, pcfl);
11294 /* reschedule all successors */
11295 link = setFirstItem (pcfl->to);
11297 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11298 addSetIfnotP (&todo, link->pcflow);
11299 link = setNextItem (pcfl->to);
11302 deleteDefmapChain (&out_vals);
11305 deleteDefmapChain (&in_vals);
11311 static void showAllDefs (symbol_t sym, pCode *pc) {
11315 assert (isPCI(pc));
11316 count = defmapFindAll (sym, pc, &map);
11318 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11321 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11324 pic16_pCode2str (buf, 256, map->pc);
11325 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11329 deleteDefmapChain (&map);
11333 /* safepCodeUnlink and remove pc from defmap. */
11334 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11335 defmap_t *map, *next, **head;
11339 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11340 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11341 res = pic16_safepCodeUnlink (pc, comment);
11344 /* remove pc from defmap */
11347 if (map->pc == pc) {
11348 if (!map->prev && head) *head = map->next;
11349 deleteDefmap (map);
11358 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11360 /* This breaks the defmap chain's references to pCodes... fix it! */
11361 map = PCI(pc)->pcflow->defmap;
11363 while (map && map->pc != pc) map = map->next;
11365 while (map && map->pc == pc) {
11371 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11372 * write accesses (isRead == 0). */
11373 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11374 defmap_t *map, *map_start;
11376 if (!isPCI(pc)) return;
11377 if (sym == newsym) return;
11379 map = PCI(pc)->pcflow->defmap;
11381 while (map && map->pc != pc) map = map->next;
11383 while (map && map->pc == pc) {
11384 if (map->sym == sym) {
11385 assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11386 if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11387 /* only one kind of access handled... this is easy */
11390 /* must copy defmap entry before replacing symbol... */
11391 copy = copyDefmap (map);
11393 map->acc.access.isRead = 0;
11394 copy->acc.access.isWrite = 0;
11396 map->acc.access.isWrite = 0;
11397 copy->acc.access.isRead = 0;
11399 copy->sym = newsym;
11400 /* insert copy into defmap chain */
11401 defmapInsertAfter (map, copy);
11407 /* as this might introduce multiple defmap entries for newsym... */
11408 mergeDefmapSymbols (map_start);
11411 /* Assign "better" valnums to results. */
11412 static void assignValnums (pCode *pc) {
11413 pCodeInstruction *pci;
11415 symbol_t sym1, sym2;
11416 int cond, isSpecial1, isSpecial2, count, mask, lit;
11417 defmap_t *list, *val, *oldval, *dummy;
11418 regs *reg1 = NULL, *reg2 = NULL;
11421 /* only works for pCodeInstructions... */
11422 if (!isPCI(pc)) return;
11425 cond = pci->inCond | pci->outCond;
11426 list = pci->pcflow->defmap;
11427 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11429 if (cond & PCC_REGISTER) {
11430 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11431 reg1 = pic16_getRegFromInstruction (pc);
11432 isSpecial1 = pic16_symIsSpecial (sym1);
11434 if (cond & PCC_REGISTER2) {
11435 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11436 reg2 = pic16_getRegFromInstruction (pc);
11437 isSpecial2 = pic16_symIsSpecial (sym2);
11440 /* determine input values */
11442 while (val && val->pc != pc) val = val->next;
11443 //list = val; /* might save some time later... */
11444 while (val && val->pc == pc) {
11446 if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11447 /* get valnum for sym */
11448 count = defmapFindAll (val->sym, pc, &oldval);
11449 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11451 if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11452 val->in_val = oldval->val;
11456 } else if (count == 0) {
11457 /* no definition found */
11460 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11462 dummy = oldval->next;
11463 mask = oldval->acc.access.mask;
11464 val->in_val = oldval->val;
11465 while (dummy && (dummy->val == val->in_val)) {
11466 mask &= dummy->acc.access.mask;
11467 dummy = dummy->next;
11470 /* found other values or to restictive mask */
11471 if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11475 if (count > 0) deleteDefmapChain (&oldval);
11480 /* handle valnum assignment */
11482 case POC_CLRF: /* modifies STATUS (Z) */
11483 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11484 oldval = defmapCurr (list, sym1, pc);
11485 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11486 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11487 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11489 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11493 case POC_SETF: /* SETF does not touch STATUS */
11494 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11495 oldval = defmapCurr (list, sym1, pc);
11496 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11497 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11498 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11500 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11504 case POC_MOVLW: /* does not touch STATUS */
11505 oldval = defmapCurr (list, SPO_WREG, pc);
11506 if (pci->pcop->type == PO_LITERAL) {
11507 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11508 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11510 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11511 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11513 if (oldval && oldval->in_val == litnum) {
11514 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11515 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11517 defmapUpdate (list, SPO_WREG, pc, litnum);
11520 case POC_ANDLW: /* modifies STATUS (Z,N) */
11521 case POC_IORLW: /* modifies STATUS (Z,N) */
11522 case POC_XORLW: /* modifies STATUS (Z,N) */
11523 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11524 if (pci->pcop->type == PO_LITERAL) {
11526 lit = (unsigned char) PCOL(pci->pcop)->lit;
11527 val = defmapCurr (list, SPO_WREG, pc);
11528 if (val) vallit = litFromValnum (val->in_val);
11529 if (vallit != -1) {
11530 /* xxxLW <literal>, WREG contains a known literal */
11531 //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11532 if (pci->op == POC_ANDLW) {
11534 } else if (pci->op == POC_IORLW) {
11536 } else if (pci->op == POC_XORLW) {
11539 assert (0 && "invalid operation");
11541 if (vallit == lit) {
11542 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11543 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11545 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11552 /* check if old value matches new value */
11555 assert (pci->pcop->type == PO_LITERAL);
11557 lit = PCOL(pci->pcop)->lit;
11559 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11561 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11562 //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11564 /* cannot remove this LFSR */
11568 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11569 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11570 //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11576 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11581 case POC_MOVWF: /* does not touch flags */
11582 /* find value of WREG */
11583 val = defmapCurr (list, SPO_WREG, pc);
11584 oldval = defmapCurr (list, sym1, pc);
11585 if (val) lit = litFromValnum (val->in_val);
11587 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11589 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11590 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11591 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11593 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11595 assert (lit == 0x0ff);
11596 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11598 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11599 pic16_pCodeReplace (pc, newpc);
11600 defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11601 pic16_fixDefmap (pc, newpc);
11604 /* This breaks the defmap chain's references to pCodes... fix it! */
11605 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11606 if (!val->acc.access.isWrite) {
11607 deleteDefmap (val); // delete reference to WREG as in value
11610 val->acc.access.isRead = 0; // delete reference to WREG as in value
11612 oldval = PCI(pc)->pcflow->defmap;
11614 if (oldval->pc == pc) oldval->pc = newpc;
11615 oldval = oldval->next;
11617 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11618 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11619 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11621 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11624 case POC_MOVFW: /* modifies STATUS (Z,N) */
11625 /* find value of REG */
11626 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11627 val = defmapCurr (list, sym1, pc);
11628 oldval = defmapCurr (list, SPO_WREG, pc);
11629 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11630 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11631 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11633 defmap_t *pred, *predpred;
11634 /* Optimize MOVLW immd; MOVWF reg1; [...]; MOVFW reg1
11635 * into MOVLW immd; MOVWF reg1; [...]; MOVLW immd
11636 * This might allow removal of the first two assignments. */
11637 pred = defmapFindDef (list, sym1, pc);
11638 predpred = pred ? defmapFindDef (list, SPO_WREG, pred->pc) : NULL;
11639 if (pred && predpred && (PCI(pred->pc)->op == POC_MOVWF) && (PCI(predpred->pc)->op == POC_MOVLW)
11640 && !pic16_isAlive (SPO_STATUS, pc))
11642 newpc = pic16_newpCode (POC_MOVLW, pic16_pCodeOpCopy (PCI(predpred->pc)->pcop));
11644 if (pic16_debug_verbose || pic16_pcode_verbose) {
11645 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFW: replaced last of MOVLW;MOVWF;MOVFW by MOVLW");
11647 pic16_pCodeReplace (pc, newpc);
11648 defmapReplaceSymRef (pc, sym1, 0, 1);
11649 pic16_fixDefmap (pc, newpc);
11652 /* This breaks the defmap chain's references to pCodes... fix it! */
11653 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11654 if (!val->acc.access.isWrite) {
11655 deleteDefmap (val); // delete reference to reg1 as in value
11658 val->acc.access.isRead = 0; // delete reference to reg1 as in value
11660 oldval = PCI(pc)->pcflow->defmap;
11662 if (oldval->pc == pc) oldval->pc = newpc;
11663 oldval = oldval->next;
11667 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11671 case POC_MOVFF: /* does not touch STATUS */
11672 /* find value of REG */
11673 val = defmapCurr (list, sym1, pc);
11674 oldval = defmapCurr (list, sym2, pc);
11675 if (val) lit = litFromValnum (val->in_val);
11678 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11679 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11681 newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11682 } else if (lit == 0x00ff) {
11683 newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11688 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11689 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11690 pic16_pCodeReplace (pc, newpc);
11691 defmapReplaceSymRef (pc, sym1, 0, 1);
11692 pic16_fixDefmap (pc, newpc);
11694 break; // do not process instruction as MOVFF...
11696 } else if (!isSpecial1 && !isSpecial2
11697 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11698 && val && oldval && (val->in_val != 0)) {
11699 if (val->in_val == oldval->in_val) {
11700 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11701 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11703 if (!pic16_isAlive (sym1, pc)) {
11704 defmap_t *copy = NULL;
11705 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11706 * This should help eliminate
11708 * <do something not changing A or using B>
11710 * <B is not alive anymore>
11712 * <do something not changing A or using B>
11716 /* scan defmap for symbols storing sym1's value */
11717 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11718 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11719 /* unique reaching definition for sym found */
11720 if (copy->val && copy->val == val->in_val) {
11721 //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);
11722 if (copy->sym == SPO_WREG) {
11723 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11725 pCodeOp *pcop = NULL;
11726 /* the code below fails if we try to replace
11727 * MOVFF PRODL, r0x03
11728 * MOVFF r0x03, PCLATU
11730 * MOVFF PRODL, PCLATU
11731 * as copy(PRODL) contains has pc==NULL, by name fails...
11733 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11735 if (copy->pc && PCI(copy->pc)->pcop)
11736 pcop = PCI(copy->pc)->pcop;
11738 /* This code is broken--see above. */
11741 const char *symname = strFromSym(copy->sym);
11744 pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11745 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11746 //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11750 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11752 pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11754 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11755 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11756 pic16_pCodeReplace (pc, newpc);
11757 assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11758 defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11759 pic16_fixDefmap (pc, newpc);
11763 deleteDefmapChain (©);
11766 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11771 /* cannot optimize */
11776 static void pic16_destructDF (pBlock *pb) {
11781 /* remove old defmaps */
11782 pc = pic16_findNextInstruction (pb->pcHead);
11784 next = pic16_findNextInstruction (pc->next);
11786 assert (isPCI(pc) || isPCAD(pc));
11787 assert (PCI(pc)->pcflow);
11788 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11789 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11790 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11795 if (defmap_free || defmap_free_count) {
11796 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11797 freeDefmap (&defmap_free);
11798 defmap_free_count = 0;
11802 /* Checks whether a pBlock contains ASMDIRs. */
11803 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11808 pc = pic16_findNextInstruction (pb->pcHead);
11810 if (isPCAD(pc)) return 1;
11812 pc = pic16_findNextInstruction (pc->next);
11815 /* no PCADs found */
11820 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11821 static int pic16_removeUnusedRegistersDF () {
11824 regs *reg1, *reg2, *reg3;
11825 set *seenRegs = NULL;
11827 int islocal, change = 0;
11830 if (!the_pFile || !the_pFile->pbHead) return 0;
11832 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11833 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11835 /* find set of using pCodes per register */
11836 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11837 pc = pic16_findNextInstruction(pc->next)) {
11839 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11840 reg1 = reg2 = NULL;
11841 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11842 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11845 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11846 addSetIfnotP (&seenRegs, reg1);
11847 addSetIfnotP (®1->reglives.usedpCodes, pc);
11850 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11851 addSetIfnotP (&seenRegs, reg2);
11852 addSetIfnotP (®2->reglives.usedpCodes, pc);
11856 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11857 /* may not use pic16_regIsLocal() here -- in interrupt routines
11858 * WREG, PRODx, FSR0x must be saved */
11859 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11860 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11862 for (i=0; i < 2; i++) {
11863 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11864 if (!pc2) pc2 = pc;
11865 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11866 reg2 = pic16_getRegFromInstruction (pc);
11867 reg3 = pic16_getRegFromInstruction2 (pc);
11869 || (reg2->rIdx != pic16_stack_preinc->rIdx
11870 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11872 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11873 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11874 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11875 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11879 deleteSet (®1->reglives.usedpCodes);
11882 deleteSet (&seenRegs);
11889 /* Set up pCodeFlow's defmap_ts.
11890 * Needs correctly set up to/from fields. */
11891 static void pic16_createDF (pBlock *pb) {
11897 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11899 pic16_destructDF (pb);
11901 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11902 if (pic16_pBlockHasAsmdirs (pb)) {
11903 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11907 /* integrity check -- we need to reach all flows to guarantee
11908 * correct data flow analysis (reaching definitions, aliveness) */
11910 if (!verifyAllFlowsReachable (pb)) {
11911 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11916 /* establish new defmaps */
11917 pc = pic16_findNextInstruction (pb->pcHead);
11919 next = pic16_findNextInstruction (pc->next);
11921 assert (PCI(pc)->pcflow);
11922 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11927 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11928 createReachingDefinitions (pb);
11931 /* assign better valnums */
11932 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11933 pc = pic16_findNextInstruction (pb->pcHead);
11935 next = pic16_findNextInstruction (pc->next);
11937 assert (PCI(pc)->pcflow);
11938 assignValnums (pc);
11945 /* remove dead pCodes */
11946 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11949 pc = pic16_findNextInstruction (pb->pcHead);
11951 next = pic16_findNextInstruction (pc->next);
11953 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11954 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11963 /* ======================================================================== */
11964 /* === VCG DUMPER ROUTINES ================================================ */
11965 /* ======================================================================== */
11966 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11967 hTab *dumpedNodes = NULL;
11969 /** Dump VCG header into of. */
11970 static void pic16_vcg_init (FILE *of) {
11971 /* graph defaults */
11972 fprintf (of, "graph:{\n");
11973 fprintf (of, "title:\"graph1\"\n");
11974 fprintf (of, "label:\"graph1\"\n");
11975 fprintf (of, "color:white\n");
11976 fprintf (of, "textcolor:black\n");
11977 fprintf (of, "bordercolor:black\n");
11978 fprintf (of, "borderwidth:1\n");
11979 fprintf (of, "textmode:center\n");
11981 fprintf (of, "layoutalgorithm:dfs\n");
11982 fprintf (of, "late_edge_labels:yes\n");
11983 fprintf (of, "display_edge_labels:yes\n");
11984 fprintf (of, "dirty_edge_labels:yes\n");
11985 fprintf (of, "finetuning:yes\n");
11986 fprintf (of, "ignoresingles:no\n");
11987 fprintf (of, "straight_phase:yes\n");
11988 fprintf (of, "priority_phase:yes\n");
11989 fprintf (of, "manhattan_edges:yes\n");
11990 fprintf (of, "smanhattan_edges:no\n");
11991 fprintf (of, "nearedges:no\n");
11992 fprintf (of, "node_alignment:center\n"); // bottom|top|center
11993 fprintf (of, "port_sharing:no\n");
11994 fprintf (of, "arrowmode:free\n"); // fixed|free
11995 fprintf (of, "crossingphase2:yes\n");
11996 fprintf (of, "crossingoptimization:yes\n");
11997 fprintf (of, "edges:yes\n");
11998 fprintf (of, "nodes:yes\n");
11999 fprintf (of, "splines:no\n");
12001 /* node defaults */
12002 fprintf (of, "node.color:lightyellow\n");
12003 fprintf (of, "node.textcolor:black\n");
12004 fprintf (of, "node.textmode:center\n");
12005 fprintf (of, "node.shape:box\n");
12006 fprintf (of, "node.bordercolor:black\n");
12007 fprintf (of, "node.borderwidth:1\n");
12009 /* edge defaults */
12010 fprintf (of, "edge.textcolor:black\n");
12011 fprintf (of, "edge.color:black\n");
12012 fprintf (of, "edge.thickness:1\n");
12013 fprintf (of, "edge.arrowcolor:black\n");
12014 fprintf (of, "edge.backarrowcolor:black\n");
12015 fprintf (of, "edge.arrowsize:15\n");
12016 fprintf (of, "edge.backarrowsize:15\n");
12017 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12018 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12019 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12021 fprintf (of, "\n");
12023 /* prepare data structures */
12025 hTabDeleteAll (dumpedNodes);
12026 dumpedNodes = NULL;
12028 dumpedNodes = newHashTable (128);
12031 /** Dump VCG footer into of. */
12032 static void pic16_vcg_close (FILE *of) {
12033 fprintf (of, "}\n");
12036 #define BUF_SIZE 128
12037 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12040 static int ptrcmp (const void *p1, const void *p2) {
12045 /** Dump a pCode node as VCG to of. */
12046 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12047 char buf[BUF_SIZE];
12049 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12053 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12054 //fprintf (stderr, "dumping %p\n", pc);
12056 /* only dump pCodeInstructions and Flow nodes */
12057 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12060 fprintf (of, "node:{");
12061 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12062 fprintf (of, "label:\"%s\n", pcTitle(pc));
12064 fprintf (of, "<PCFLOW>");
12065 } else if (isPCI(pc) || isPCAD(pc)) {
12066 pc->print (of, pc);
12068 fprintf (of, "<!PCI>");
12070 fprintf (of, "\" ");
12071 fprintf (of, "}\n");
12073 if (1 && isPCFL(pc)) {
12074 defmap_t *map, *prev;
12076 map = PCFL(pc)->defmap;
12079 if (map->sym != 0) {
12082 /* emit definition node */
12083 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12084 fprintf (of, "label:\"");
12088 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));
12091 } while (map && prev->pc == map->pc);
12094 fprintf (of, "\" ");
12096 fprintf (of, "color:green ");
12097 fprintf (of, "}\n");
12099 /* emit edge to previous definition */
12100 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12102 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12104 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12106 fprintf (of, "color:green ");
12107 fprintf (of, "}\n");
12110 pic16_vcg_dumpnode (map->pc, of);
12111 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12112 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12119 /* emit additional nodes (e.g. operands) */
12122 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12123 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12124 char buf[BUF_SIZE];
12125 pCodeInstruction *pci;
12129 if (1 && isPCFL(pc)) {
12130 /* emit edges to flow successors */
12132 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12133 pcfl = setFirstItem (PCFL(pc)->to);
12135 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12136 pic16_vcg_dumpnode (pc, of);
12137 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12138 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12139 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12140 pcfl = setNextItem (PCFL(pc)->to);
12144 if (!isPCI(pc) && !isPCAD(pc)) return;
12148 /* emit control flow edges (forward only) */
12152 pic16_vcg_dumpnode (curr->pc, of);
12153 fprintf (of, "edge:{");
12154 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12155 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12156 fprintf (of, "color:red ");
12157 fprintf (of, "}\n");
12162 /* dump "flow" edge (link pCode according to pBlock order) */
12165 pcnext = pic16_findNextInstruction (pc->next);
12167 pic16_vcg_dumpnode (pcnext, of);
12168 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12169 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12177 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12178 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12179 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12183 /* emit data flow edges (backward only) */
12184 /* TODO: gather data flow information... */
12187 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12192 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12193 if (pic16_pBlockHasAsmdirs (pb)) {
12194 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12198 for (pc=pb->pcHead; pc; pc = pc->next) {
12199 pic16_vcg_dumpnode (pc, of);
12202 for (pc=pb->pcHead; pc; pc = pc->next) {
12203 pic16_vcg_dumpedges (pc, of);
12207 static void pic16_vcg_dump_default (pBlock *pb) {
12209 char buf[BUF_SIZE];
12214 /* get function name */
12216 while (pc && !isPCF(pc)) pc = pc->next;
12218 SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12220 SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12223 //fprintf (stderr, "now dumping %s\n", buf);
12224 of = fopen (buf, "w");
12225 pic16_vcg_init (of);
12226 pic16_vcg_dump (of, pb);
12227 pic16_vcg_close (of);
12232 /*** END of helpers for pCode dataflow optimizations ***/