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 // if((pc->type == PC_LABEL) && PCL(pc)->label)
3808 // Safe_free(PCL(pc)->label);
3810 /* Instead of deleting the memory used by this pCode, mark
3811 * the object as bad so that if there's a pointer to this pCode
3812 * dangling around somewhere then (hopefully) when the type is
3813 * checked we'll catch it.
3817 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3823 pCode *pic16_newpCodeLabel(char *name, int key)
3829 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3831 pcl->pc.type = PC_LABEL;
3832 pcl->pc.prev = pcl->pc.next = NULL;
3833 //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3836 // pcl->pc.analyze = genericAnalyze;
3837 pcl->pc.destruct = pCodeLabelDestruct;
3838 pcl->pc.print = pCodePrintLabel;
3845 sprintf(s,"_%05d_DS_",key);
3850 pcl->label = Safe_strdup(s);
3852 // if(pic16_pcode_verbose)
3853 // fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3856 return ( (pCode *)pcl);
3860 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3862 pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3866 return ( (pCode *)pcl );
3869 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3873 pci = Safe_calloc(1, sizeof(pCodeInfo));
3874 pci->pci.pc.type = PC_INFO;
3875 pci->pci.pc.prev = pci->pci.pc.next = NULL;
3876 pci->pci.pc.pb = NULL;
3877 pci->pci.label = NULL;
3879 pci->pci.pc.destruct = genericDestruct;
3880 pci->pci.pc.print = genericPrint;
3885 return ((pCode *)pci);
3889 /*-----------------------------------------------------------------*/
3890 /* newpBlock - create and return a pointer to a new pBlock */
3891 /*-----------------------------------------------------------------*/
3892 static pBlock *newpBlock(void)
3897 PpB = Safe_calloc(1,sizeof(pBlock) );
3898 PpB->next = PpB->prev = NULL;
3900 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3901 PpB->tregisters = NULL;
3903 PpB->FlowTree = NULL;
3909 /*-----------------------------------------------------------------*/
3910 /* pic16_newpCodeChain - create a new chain of pCodes */
3911 /*-----------------------------------------------------------------*
3913 * This function will create a new pBlock and the pointer to the
3914 * pCode that is passed in will be the first pCode in the block.
3915 *-----------------------------------------------------------------*/
3918 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3921 pBlock *pB = newpBlock();
3923 pB->pcHead = pB->pcTail = pc;
3932 /*-----------------------------------------------------------------*/
3933 /* pic16_newpCodeOpLabel - Create a new label given the key */
3934 /* Note, a negative key means that the label is part of wild card */
3935 /* (and hence a wild card label) used in the pCodePeep */
3936 /* optimizations). */
3937 /*-----------------------------------------------------------------*/
3939 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
3942 static int label_key=-1;
3946 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
3947 pcop->type = PO_LABEL;
3952 sprintf(s=buffer,"_%05d_DS_",key);
3954 s = name, key = label_key--;
3957 pcop->name = Safe_strdup(s);
3959 ((pCodeOpLabel *)pcop)->key = key;
3961 //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
3965 /*-----------------------------------------------------------------*/
3966 /*-----------------------------------------------------------------*/
3967 pCodeOp *pic16_newpCodeOpLit(int lit)
3973 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
3974 pcop->type = PO_LITERAL;
3978 sprintf(s,"0x%02hhx", (unsigned char)lit);
3980 // sprintf(s, "%i", lit);
3983 pcop->name = Safe_strdup(s);
3985 ((pCodeOpLit *)pcop)->lit = lit;
3990 /* Allow for 12 bit literals, required for LFSR */
3991 pCodeOp *pic16_newpCodeOpLit12(int lit)
3997 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
3998 pcop->type = PO_LITERAL;
4002 sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4004 // sprintf(s, "%i", lit);
4007 pcop->name = Safe_strdup(s);
4009 ((pCodeOpLit *)pcop)->lit = lit;
4014 /*-----------------------------------------------------------------*/
4015 /*-----------------------------------------------------------------*/
4016 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4018 char *s = buffer, tbuf[256], *tb=tbuf;
4022 tb = pic16_get_op(arg2, NULL, 0);
4023 pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4024 pcop->type = PO_LITERAL;
4028 sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4030 pcop->name = Safe_strdup(s);
4033 ((pCodeOpLit2 *)pcop)->lit = lit;
4034 ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4039 /*-----------------------------------------------------------------*/
4040 /*-----------------------------------------------------------------*/
4041 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4045 pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4046 pcop->type = PO_IMMEDIATE;
4048 regs *r = pic16_dirregWithName(name);
4049 pcop->name = Safe_strdup(name);
4053 // fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4054 PCOI(pcop)->rIdx = r->rIdx;
4056 // fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4057 PCOI(pcop)->rIdx = -1;
4059 // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4062 PCOI(pcop)->rIdx = -1;
4065 PCOI(pcop)->index = index;
4066 PCOI(pcop)->offset = offset;
4067 PCOI(pcop)->_const = code_space;
4072 /*-----------------------------------------------------------------*/
4073 /*-----------------------------------------------------------------*/
4074 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4080 if(!pcwb || !subtype) {
4081 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4085 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4086 pcop->type = PO_WILD;
4087 sprintf(s,"%%%d",id);
4088 pcop->name = Safe_strdup(s);
4090 PCOW(pcop)->id = id;
4091 PCOW(pcop)->pcwb = pcwb;
4092 PCOW(pcop)->subtype = subtype;
4093 PCOW(pcop)->matched = NULL;
4095 PCOW(pcop)->pcop2 = NULL;
4100 /*-----------------------------------------------------------------*/
4101 /*-----------------------------------------------------------------*/
4102 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4108 if(!pcwb || !subtype || !subtype2) {
4109 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4113 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4114 pcop->type = PO_WILD;
4115 sprintf(s,"%%%d",id);
4116 pcop->name = Safe_strdup(s);
4118 PCOW(pcop)->id = id;
4119 PCOW(pcop)->pcwb = pcwb;
4120 PCOW(pcop)->subtype = subtype;
4121 PCOW(pcop)->matched = NULL;
4123 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4125 if(!subtype2->name) {
4126 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4127 PCOW2(pcop)->pcop.type = PO_WILD;
4128 sprintf(s, "%%%d", id2);
4129 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4130 PCOW2(pcop)->id = id2;
4131 PCOW2(pcop)->subtype = subtype2;
4133 // fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4134 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4136 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4138 // fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4139 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4148 /*-----------------------------------------------------------------*/
4149 /*-----------------------------------------------------------------*/
4150 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4154 pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4155 pcop->type = PO_GPR_BIT;
4157 pcop->name = Safe_strdup(s);
4161 PCORB(pcop)->bit = bit;
4162 PCORB(pcop)->inBitSpace = inBitSpace;
4163 PCORB(pcop)->subtype = subt;
4165 /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4166 PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4167 // fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4168 // PCOR(pcop)->rIdx = 0;
4172 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4174 return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4175 bit, 0, PO_GPR_REGISTER);
4179 /*-----------------------------------------------------------------*
4180 * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4182 * If rIdx >=0 then a specific register from the set of registers
4183 * will be selected. If rIdx <0, then a new register will be searched
4185 *-----------------------------------------------------------------*/
4187 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4192 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4197 r = pic16_regWithIdx(rIdx);
4199 r = pic16_allocWithIdx(rIdx);
4201 r = pic16_findFreeReg(REG_GPR);
4204 fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4205 __FUNCTION__, __LINE__);
4210 PCOR(pcop)->rIdx = rIdx;
4212 pcop->type = PCOR(pcop)->r->pc_type;
4217 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4222 pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4225 r = pic16_findFreeReg(REG_GPR);
4228 if(!bitVectBitValue(bv, r->rIdx)) {
4230 PCOR(pcop)->rIdx = r->rIdx;
4231 pcop->type = r->pc_type;
4235 r = pic16_findFreeRegNext(REG_GPR, r);
4243 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4248 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4249 PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4250 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4251 pcop->type = PCOR(pcop)->r->pc_type;
4252 pcop->name = PCOR(pcop)->r->name;
4254 // if(pic16_pcode_verbose) {
4255 // fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4256 // __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4262 /*-----------------------------------------------------------------*/
4263 /*-----------------------------------------------------------------*/
4264 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4268 pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4271 pcop->key = Safe_strdup( key );
4273 return (PCOP(pcop));
4276 /*-----------------------------------------------------------------*/
4277 /*-----------------------------------------------------------------*/
4278 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4280 pCodeOpLocalReg *pcop;
4282 pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4286 return (PCOP(pcop));
4290 /*-----------------------------------------------------------------*/
4291 /*-----------------------------------------------------------------*/
4293 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4300 pcop = pic16_newpCodeOpBit(name, -1,0, type);
4304 pcop = pic16_newpCodeOpLit(-1);
4308 pcop = pic16_newpCodeOpLabel(NULL,-1);
4311 pcop = pic16_newpCodeOpReg(-1);
4314 case PO_GPR_REGISTER:
4316 pcop = pic16_newpCodeOpRegFromStr(name);
4318 pcop = pic16_newpCodeOpReg(-1);
4322 assert( !"Cannot create PO_TWO_OPS from string!" );
4327 pcop = Safe_calloc(1,sizeof(pCodeOp) );
4330 pcop->name = Safe_strdup(name);
4338 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4340 pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4341 pcop2->pcop.type = PO_TWO_OPS;
4347 /* This is a multiple of two as gpasm pads DB directives to even length,
4348 * thus the data would be interleaved with \0 bytes...
4349 * This is a multiple of three in order to have arrays of 3-byte pointers
4350 * continuously in memory (without 0-padding at the lines' end).
4351 * This is rather 12 than 6 in order not to split up 4-byte data types
4352 * in arrays right in the middle of a 4-byte word. */
4353 #define DB_ITEMS_PER_LINE 12
4355 typedef struct DBdata
4362 static int DBd_init = -1;
4364 /*-----------------------------------------------------------------*/
4365 /* Initialiase "DB" data buffer */
4366 /*-----------------------------------------------------------------*/
4367 void pic16_initDB(void)
4373 /*-----------------------------------------------------------------*/
4374 /* Flush pending "DB" data to a pBlock */
4376 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4377 /*-----------------------------------------------------------------*/
4378 void pic16_flushDB(char ptype, void *p)
4382 pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4385 fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4388 fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4392 DBd.buffer[0] = '\0';
4397 /*-----------------------------------------------------------------*/
4398 /* Add "DB" directives to a pBlock */
4399 /*-----------------------------------------------------------------*/
4400 void pic16_emitDB(int c, char ptype, void *p)
4405 // we need to initialize
4408 DBd.buffer[0] = '\0';
4411 l = strlen(DBd.buffer);
4412 sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4414 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4417 if (DBd.count>= DB_ITEMS_PER_LINE)
4418 pic16_flushDB(ptype, p);
4421 void pic16_emitDS(char *s, char ptype, void *p)
4426 // we need to initialize
4429 DBd.buffer[0] = '\0';
4432 l = strlen(DBd.buffer);
4433 sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4435 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4437 DBd.count++; //=strlen(s);
4438 if (DBd.count>=DB_ITEMS_PER_LINE)
4439 pic16_flushDB(ptype, p);
4443 /*-----------------------------------------------------------------*/
4444 /*-----------------------------------------------------------------*/
4445 void pic16_pCodeConstString(char *name, char *value, unsigned length)
4449 static set *emittedSymbols = NULL;
4454 /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4455 if (emittedSymbols) {
4456 /* scan set for name */
4457 for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4459 if (!strcmp (item,name)) {
4460 //fprintf (stderr, "%s already emitted\n", name);
4465 addSet (&emittedSymbols, Safe_strdup (name));
4467 //fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value);
4469 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4471 pic16_addpBlock(pb);
4473 // sprintf(buffer,"; %s = ", name);
4474 // strcat(buffer, value);
4475 // fputs(buffer, stderr);
4477 // pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4478 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4481 pic16_emitDB(*value++, 'p', (void *)pb);
4483 pic16_flushDB('p', (void *)pb);
4486 /*-----------------------------------------------------------------*/
4487 /*-----------------------------------------------------------------*/
4489 static void pCodeReadCodeTable(void)
4493 fprintf(stderr, " %s\n",__FUNCTION__);
4495 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4497 pic16_addpBlock(pb);
4499 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4500 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4501 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4502 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4504 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4505 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4506 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4507 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4512 /*-----------------------------------------------------------------*/
4513 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */
4514 /*-----------------------------------------------------------------*/
4515 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4522 /* If this is the first pcode to be added to a block that
4523 * was initialized with a NULL pcode, then go ahead and
4524 * make this pcode the head and tail */
4525 pb->pcHead = pb->pcTail = pc;
4528 pb->pcTail->next = pc;
4530 pc->prev = pb->pcTail;
4537 /*-----------------------------------------------------------------*/
4538 /* pic16_addpBlock - place a pBlock into the pFile */
4539 /*-----------------------------------------------------------------*/
4540 void pic16_addpBlock(pBlock *pb)
4542 // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4545 /* First time called, we'll pass through here. */
4546 //_ALLOC(the_pFile,sizeof(pFile));
4547 the_pFile = Safe_calloc(1,sizeof(pFile));
4548 the_pFile->pbHead = the_pFile->pbTail = pb;
4549 the_pFile->functions = NULL;
4553 the_pFile->pbTail->next = pb;
4554 pb->prev = the_pFile->pbTail;
4556 the_pFile->pbTail = pb;
4559 /*-----------------------------------------------------------------*/
4560 /* removepBlock - remove a pBlock from the pFile */
4561 /*-----------------------------------------------------------------*/
4562 static void removepBlock(pBlock *pb)
4570 //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4572 for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4575 if(pbs == the_pFile->pbHead)
4576 the_pFile->pbHead = pbs->next;
4578 if (pbs == the_pFile->pbTail)
4579 the_pFile->pbTail = pbs->prev;
4582 pbs->next->prev = pbs->prev;
4585 pbs->prev->next = pbs->next;
4592 fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4596 /*-----------------------------------------------------------------*/
4597 /* printpCode - write the contents of a pCode to a file */
4598 /*-----------------------------------------------------------------*/
4599 static void printpCode(FILE *of, pCode *pc)
4610 fprintf(of,"warning - unable to print pCode\n");
4613 /*-----------------------------------------------------------------*/
4614 /* pic16_printpBlock - write the contents of a pBlock to a file */
4615 /*-----------------------------------------------------------------*/
4616 void pic16_printpBlock(FILE *of, pBlock *pb)
4624 for(pc = pb->pcHead; pc; pc = pc->next) {
4625 if(isPCF(pc) && PCF(pc)->fname) {
4626 fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4627 if(pb->dbName == 'A') {
4629 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4630 // fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4631 if(!strcmp(ab->name, PCF(pc)->fname)) {
4632 // fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4633 if(ab->address != -1)
4634 fprintf(of, "\t0X%06X", ab->address);
4645 /*-----------------------------------------------------------------*/
4647 /* pCode processing */
4651 /*-----------------------------------------------------------------*/
4652 pCode * pic16_findNextInstruction(pCode *pci);
4653 pCode * pic16_findPrevInstruction(pCode *pci);
4655 void pic16_unlinkpCode(pCode *pc)
4661 fprintf(stderr,"Unlinking: ");
4662 printpCode(stderr, pc);
4665 pc->prev->next = pc->next;
4667 pc->next->prev = pc->prev;
4669 /* move C source line down (or up) */
4670 if (isPCI(pc) && PCI(pc)->cline) {
4671 prev = pic16_findNextInstruction (pc->next);
4672 if (prev && isPCI(prev) && !PCI(prev)->cline) {
4673 PCI(prev)->cline = PCI(pc)->cline;
4675 prev = pic16_findPrevInstruction (pc->prev);
4676 if (prev && isPCI(prev) && !PCI(prev)->cline)
4677 PCI(prev)->cline = PCI(pc)->cline;
4680 pc->prev = pc->next = NULL;
4684 /*-----------------------------------------------------------------*/
4685 /*-----------------------------------------------------------------*/
4687 static void genericDestruct(pCode *pc)
4690 pic16_unlinkpCode(pc);
4693 /* For instructions, tell the register (if there's one used)
4694 * that it's no longer needed */
4695 regs *reg = pic16_getRegFromInstruction(pc);
4697 deleteSetItem (&(reg->reglives.usedpCodes),pc);
4699 if(PCI(pc)->is2MemOp) {
4700 reg = pic16_getRegFromInstruction2(pc);
4702 deleteSetItem(&(reg->reglives.usedpCodes), pc);
4706 /* Instead of deleting the memory used by this pCode, mark
4707 * the object as bad so that if there's a pointer to this pCode
4708 * dangling around somewhere then (hopefully) when the type is
4709 * checked we'll catch it.
4713 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4719 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4720 /*-----------------------------------------------------------------*/
4721 /*-----------------------------------------------------------------*/
4722 /* modifiers for constant immediate */
4723 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4725 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4730 int use_buffer = 1; // copy the string to the passed buffer pointer
4735 use_buffer = 0; // Don't bother copying the string to the buffer.
4740 switch(pcop->type) {
4748 SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
4751 return (PCOR(pcop)->r->name);
4754 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4756 SNPRINTF(buffer,size,"%s",r->name);
4764 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4765 if(PCOI(pcop)->index) {
4766 SNPRINTF(s,size, "%s(%s + %d)",
4767 immdmod[ PCOI(pcop)->offset ],
4771 SNPRINTF(s,size,"%s(%s)",
4772 immdmod[ PCOI(pcop)->offset ],
4776 if(PCOI(pcop)->index) {
4777 SNPRINTF(s,size, "%s(%s + %d)",
4782 SNPRINTF(s,size, "%s(%s)",
4790 case PO_GPR_REGISTER:
4793 //size = sizeof(buffer);
4794 if( PCOR(pcop)->instance) {
4795 SNPRINTF(s,size,"(%s + %d)",
4797 PCOR(pcop)->instance );
4799 SNPRINTF(s,size,"%s",pcop->name);
4806 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4807 SNPRINTF(s, size, "%s", pcop->name);
4809 if(PCORB(pcop)->pcor.instance)
4810 SNPRINTF(s, size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4812 SNPRINTF(s, size, "%s", pcop->name);
4818 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4824 SNPRINTF(buffer,size,"%s",pcop->name);
4827 return (pcop->name);
4831 return ("unhandled type for op1");
4834 return ("NO operand1");
4837 /*-----------------------------------------------------------------*/
4838 /* pic16_get_op2 - variant to support two memory operand commands */
4839 /*-----------------------------------------------------------------*/
4840 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4843 if(pcop && pcop->type == PO_TWO_OPS) {
4844 return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4847 return "NO operand2";
4850 /*-----------------------------------------------------------------*/
4851 /*-----------------------------------------------------------------*/
4852 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4856 return pic16_get_op(pcc->pcop,NULL,0);
4858 /* gcc 3.2: warning: concatenation of string literals with __FUNCTION__ is deprecated
4859 * return ("ERROR Null: "__FUNCTION__);
4861 return ("ERROR Null: pic16_get_op_from_instruction");
4865 /*-----------------------------------------------------------------*/
4866 /*-----------------------------------------------------------------*/
4867 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4870 fprintf(of,"pcodeopprint- not implemented\n");
4873 /*-----------------------------------------------------------------*/
4874 /* pic16_pCode2str - convert a pCode instruction to string */
4875 /*-----------------------------------------------------------------*/
4876 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4882 if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4883 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4884 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4885 // exit(EXIT_FAILURE);
4892 SNPRINTF(s, size, "\t%s\t", PCI(pc)->mnemonic);
4896 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4898 if (PCI(pc)->pcop->type == PO_TWO_OPS)
4900 /* split into two phases due to static buffer in pic16_get_op() */
4901 SNPRINTF(s, size, "%s",
4902 pic16_get_op((PCI(pc)->pcop), NULL, 0));
4905 SNPRINTF(s, size, ", %s",
4906 pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4910 if(PCI(pc)->is2LitOp) {
4911 SNPRINTF(s,size, "%s", PCOP(PCI(pc)->pcop)->name);
4915 if(PCI(pc)->isBitInst) {
4916 if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4917 if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4918 SNPRINTF(s,size,"(%s >> 3), (%s & 7)",
4919 PCI(pc)->pcop->name ,
4920 PCI(pc)->pcop->name );
4922 SNPRINTF(s,size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4923 (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4925 } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4926 SNPRINTF(s,size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
4928 SNPRINTF(s,size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
4931 if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4932 if( PCI(pc)->num_ops == 3)
4933 SNPRINTF(s,size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
4935 SNPRINTF(s,size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
4937 SNPRINTF(s,size,"%s", pic16_get_op_from_instruction(PCI(pc)));
4941 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
4944 if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst) {
4945 SNPRINTF(s,size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
4950 r = pic16_getRegFromInstruction(pc);
4952 if(PCI(pc)->isAccess) {
4953 static char *bank_spec[2][2] = {
4954 { "", ", ACCESS" }, /* gpasm uses access bank by default */
4955 { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
4958 SNPRINTF(s,size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
4965 /* assuming that comment ends with a \n */
4966 SNPRINTF(s,size,";%s", ((pCodeComment *)pc)->comment);
4970 SNPRINTF(s,size,"; info ==>");
4973 switch( PCINF(pc)->type ) {
4974 case INF_OPTIMIZATION:
4975 SNPRINTF(s,size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
4978 SNPRINTF(s,size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
4983 /* assuming that inline code ends with a \n */
4984 SNPRINTF(s,size,"%s", ((pCodeComment *)pc)->comment);
4988 SNPRINTF(s,size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
4991 SNPRINTF(s,size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
4994 SNPRINTF(s,size,";\tWild opcode: id=%d\n",PCW(pc)->id);
4997 SNPRINTF(s,size,";\t--FLOW change\n");
5000 SNPRINTF(s,size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5001 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5004 if(PCAD(pc)->directive) {
5005 SNPRINTF(s,size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5008 /* special case to handle inline labels without a tab */
5009 SNPRINTF(s,size,"%s\n", PCAD(pc)->arg);
5014 SNPRINTF(s,size,";A bad pCode is being used\n");
5021 /*-----------------------------------------------------------------*/
5022 /* genericPrint - the contents of a pCode to a file */
5023 /*-----------------------------------------------------------------*/
5024 static void genericPrint(FILE *of, pCode *pc)
5032 // fputs(((pCodeComment *)pc)->comment, of);
5033 fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5038 pBranch *pbl = PCI(pc)->label;
5039 while(pbl && pbl->pc) {
5040 if(pbl->pc->type == PC_LABEL)
5041 pCodePrintLabel(of, pbl->pc);
5046 if(pic16_pcode_verbose) {
5047 fprintf(of, "; info ==>");
5048 switch(((pCodeInfo *)pc)->type) {
5049 case INF_OPTIMIZATION:
5050 fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5053 fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5061 fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5065 // If the opcode has a label, print that first
5067 pBranch *pbl = PCI(pc)->label;
5068 while(pbl && pbl->pc) {
5069 if(pbl->pc->type == PC_LABEL)
5070 pCodePrintLabel(of, pbl->pc);
5076 genericPrint(of,PCODE(PCI(pc)->cline));
5081 pic16_pCode2str(str, 256, pc);
5083 fprintf(of,"%s",str);
5085 if(pic16_debug_verbose) {
5086 fprintf(of, "\t;key=%03x",pc->seq);
5088 fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5095 fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5096 if(PCW(pc)->pci.label)
5097 pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5099 if(PCW(pc)->operand) {
5100 fprintf(of,";\toperand ");
5101 pCodeOpPrint(of,PCW(pc)->operand );
5106 if(pic16_debug_verbose) {
5107 fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5108 if(PCFL(pc)->ancestor)
5109 fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5116 // fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5117 fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5118 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5124 pBranch *pbl = PCAD(pc)->pci.label;
5125 while(pbl && pbl->pc) {
5126 if(pbl->pc->type == PC_LABEL)
5127 pCodePrintLabel(of, pbl->pc);
5131 if(PCAD(pc)->directive) {
5132 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5135 /* special case to handle inline labels without tab */
5136 fprintf(of, "%s\n", PCAD(pc)->arg);
5142 fprintf(of,"unknown pCode type %d\n",pc->type);
5147 /*-----------------------------------------------------------------*/
5148 /* pCodePrintFunction - prints function begin/end */
5149 /*-----------------------------------------------------------------*/
5151 static void pCodePrintFunction(FILE *of, pCode *pc)
5158 if( ((pCodeFunction *)pc)->modname)
5159 fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5162 if(!PCF(pc)->absblock) {
5163 if(PCF(pc)->fname) {
5164 pBranch *exits = PCF(pc)->to;
5167 fprintf(of,"%s:", PCF(pc)->fname);
5169 if(pic16_pcode_verbose)
5170 fprintf(of, "\t;Function start");
5176 exits = exits->next;
5180 if(pic16_pcode_verbose)
5181 fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5184 if((PCF(pc)->from &&
5185 PCF(pc)->from->pc->type == PC_FUNCTION &&
5186 PCF(PCF(pc)->from->pc)->fname) ) {
5188 if(pic16_pcode_verbose)
5189 fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5191 if(pic16_pcode_verbose)
5192 fprintf(of,"; exit point [can't find entry point]\n");
5198 /*-----------------------------------------------------------------*/
5199 /* pCodePrintLabel - prints label */
5200 /*-----------------------------------------------------------------*/
5202 static void pCodePrintLabel(FILE *of, pCode *pc)
5209 fprintf(of,"%s:\n",PCL(pc)->label);
5210 else if (PCL(pc)->key >=0)
5211 fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5213 fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5216 /*-----------------------------------------------------------------*/
5217 /* unlinkpCodeFromBranch - Search for a label in a pBranch and */
5218 /* remove it if it is found. */
5219 /*-----------------------------------------------------------------*/
5220 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5227 if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5228 b = PCI(pcl)->label;
5230 fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5235 //fprintf (stderr, "%s \n",__FUNCTION__);
5236 //pcl->print(stderr,pcl);
5237 //pc->print(stderr,pc);
5240 //fprintf (stderr, "found label\n");
5241 //pc->print(stderr, pc);
5245 bprev->next = b->next; /* Not first pCode in chain */
5249 PCI(pcl)->label = b->next; /* First pCode in chain */
5252 return; /* A label can't occur more than once */
5260 /*-----------------------------------------------------------------*/
5261 /*-----------------------------------------------------------------*/
5262 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5281 /*-----------------------------------------------------------------*/
5282 /* pBranchLink - given two pcodes, this function will link them */
5283 /* together through their pBranches */
5284 /*-----------------------------------------------------------------*/
5285 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5289 // Declare a new branch object for the 'from' pCode.
5291 //_ALLOC(b,sizeof(pBranch));
5292 b = Safe_calloc(1,sizeof(pBranch));
5293 b->pc = PCODE(t); // The link to the 'to' pCode.
5296 f->to = pic16_pBranchAppend(f->to,b);
5298 // Now do the same for the 'to' pCode.
5300 //_ALLOC(b,sizeof(pBranch));
5301 b = Safe_calloc(1,sizeof(pBranch));
5305 t->from = pic16_pBranchAppend(t->from,b);
5310 /*-----------------------------------------------------------------*/
5311 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5313 /*-----------------------------------------------------------------*/
5314 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5327 /*-----------------------------------------------------------------*/
5328 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain. */
5329 /*-----------------------------------------------------------------*/
5330 void pic16_pCodeUnlink(pCode *pc)
5335 if(!pc->prev || !pc->next) {
5336 fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5340 /* move C source line down (or up) */
5341 if (isPCI(pc) && PCI(pc)->cline) {
5342 pc1 = pic16_findNextInstruction (pc->next);
5343 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5344 PCI(pc1)->cline = PCI(pc)->cline;
5346 pc1 = pic16_findPrevInstruction (pc->prev);
5347 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5348 PCI(pc1)->cline = PCI(pc)->cline;
5352 /* first remove the pCode from the chain */
5353 pc->prev->next = pc->next;
5354 pc->next->prev = pc->prev;
5356 pc->prev = pc->next = NULL;
5358 /* Now for the hard part... */
5360 /* Remove the branches */
5362 pb1 = PCI(pc)->from;
5364 pc1 = pb1->pc; /* Get the pCode that branches to the
5365 * one we're unlinking */
5367 /* search for the link back to this pCode (the one we're
5369 if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5370 pb2->pc = PCI(pc)->to->pc; // make the replacement
5372 /* if the pCode we're unlinking contains multiple 'to'
5373 * branches (e.g. this a skip instruction) then we need
5374 * to copy these extra branches to the chain. */
5375 if(PCI(pc)->to->next)
5376 pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5385 /*-----------------------------------------------------------------*/
5386 /*-----------------------------------------------------------------*/
5388 static void genericAnalyze(pCode *pc)
5398 // Go through the pCodes that are in pCode chain and link
5399 // them together through the pBranches. Note, the pCodes
5400 // are linked together as a contiguous stream like the
5401 // assembly source code lines. The linking here mimics this
5402 // except that comments are not linked in.
5404 pCode *npc = pc->next;
5406 if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5407 pBranchLink(pc,npc);
5412 /* reached the end of the pcode chain without finding
5413 * an instruction we could link to. */
5417 fprintf(stderr,"analyze PC_FLOW\n");
5421 fprintf(stderr,,";A bad pCode is being used\n");
5427 /*-----------------------------------------------------------------*/
5428 /*-----------------------------------------------------------------*/
5429 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5433 if(pc->type == PC_LABEL) {
5434 if( ((pCodeLabel *)pc)->key == pcop_label->key)
5437 if((pc->type == PC_OPCODE)
5438 || (pc->type == PC_ASMDIR)
5440 pbr = PCI(pc)->label;
5442 if(pbr->pc->type == PC_LABEL) {
5443 if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
5453 /*-----------------------------------------------------------------*/
5454 /*-----------------------------------------------------------------*/
5455 static int checkLabel(pCode *pc)
5459 if(pc && isPCI(pc)) {
5460 pbr = PCI(pc)->label;
5462 if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5472 /*-----------------------------------------------------------------*/
5473 /* findLabelinpBlock - Search the pCode for a particular label */
5474 /*-----------------------------------------------------------------*/
5475 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5482 for(pc = pb->pcHead; pc; pc = pc->next)
5483 if(compareLabel(pc,pcop_label))
5489 /*-----------------------------------------------------------------*/
5490 /* findLabel - Search the pCode for a particular label */
5491 /*-----------------------------------------------------------------*/
5492 static pCode * findLabel(pCodeOpLabel *pcop_label)
5500 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5501 if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5505 fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5509 /*-----------------------------------------------------------------*/
5510 /* pic16_findNextpCode - given a pCode, find the next of type 'pct' */
5511 /* in the linked list */
5512 /*-----------------------------------------------------------------*/
5513 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5526 /*-----------------------------------------------------------------*/
5527 /* findPrevpCode - given a pCode, find the previous of type 'pct' */
5528 /* in the linked list */
5529 /*-----------------------------------------------------------------*/
5530 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5544 //#define PCODE_DEBUG
5545 /*-----------------------------------------------------------------*/
5546 /* pic16_findNextInstruction - given a pCode, find the next instruction */
5547 /* in the linked list */
5548 /*-----------------------------------------------------------------*/
5549 pCode * pic16_findNextInstruction(pCode *pci)
5554 if((pc->type == PC_OPCODE)
5555 || (pc->type == PC_WILD)
5556 || (pc->type == PC_ASMDIR)
5561 fprintf(stderr,"pic16_findNextInstruction: ");
5562 printpCode(stderr, pc);
5567 //fprintf(stderr,"Couldn't find instruction\n");
5571 /*-----------------------------------------------------------------*/
5572 /* pic16_findPrevInstruction - given a pCode, find the next instruction */
5573 /* in the linked list */
5574 /*-----------------------------------------------------------------*/
5575 pCode * pic16_findPrevInstruction(pCode *pci)
5581 if((pc->type == PC_OPCODE)
5582 || (pc->type == PC_WILD)
5583 || (pc->type == PC_ASMDIR)
5589 fprintf(stderr,"pic16_findPrevInstruction: ");
5590 printpCode(stderr, pc);
5595 //fprintf(stderr,"Couldn't find instruction\n");
5602 /*-----------------------------------------------------------------*/
5603 /* findFunctionEnd - given a pCode find the end of the function */
5604 /* that contains it */
5605 /*-----------------------------------------------------------------*/
5606 static pCode * findFunctionEnd(pCode *pc)
5610 if(pc->type == PC_FUNCTION && !(PCF(pc)->fname))
5616 fprintf(stderr,"Couldn't find function end\n");
5621 /*-----------------------------------------------------------------*/
5622 /* AnalyzeLabel - if the pCode is a label, then merge it with the */
5623 /* instruction with which it is associated. */
5624 /*-----------------------------------------------------------------*/
5625 static void AnalyzeLabel(pCode *pc)
5628 pic16_pCodeUnlink(pc);
5634 static void AnalyzeGOTO(pCode *pc)
5637 pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5641 static void AnalyzeSKIP(pCode *pc)
5644 pBranchLink(pc,pic16_findNextInstruction(pc->next));
5645 pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5649 static void AnalyzeRETURN(pCode *pc)
5652 // branch_link(pc,findFunctionEnd(pc->next));
5658 /*-------------------------------------------------------------------*/
5659 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp */
5660 /* if one is present. This is the common */
5661 /* part of pic16_getRegFromInstruction(2) */
5662 /*-------------------------------------------------------------------*/
5664 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5665 if (!pcop) return NULL;
5667 switch(pcop->type) {
5680 return PCOR(pcop)->r;
5682 case PO_SFR_REGISTER:
5683 //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5684 return PCOR(pcop)->r;
5688 // fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5689 return PCOR(pcop)->r;
5692 // return pic16_dirregWithName(PCOI(pcop)->r->name);
5695 return (PCOI(pcop)->r);
5700 return PCOR(pcop)->r;
5702 case PO_GPR_REGISTER:
5704 // fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5705 return PCOR(pcop)->r;
5708 //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5713 //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5718 /* this should never turn up */
5719 //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5726 return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5730 fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5738 /*-----------------------------------------------------------------*/
5739 /*-----------------------------------------------------------------*/
5740 regs * pic16_getRegFromInstruction(pCode *pc)
5745 PCI(pc)->num_ops == 0 ||
5746 (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5750 fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5751 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5754 return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5757 /*-------------------------------------------------------------------------------*/
5758 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5759 /*-------------------------------------------------------------------------------*/
5760 regs * pic16_getRegFromInstruction2(pCode *pc)
5766 PCI(pc)->num_ops == 0 ||
5767 (PCI(pc)->num_ops == 1)) // accept only 2 operand commands
5770 if (PCI(pc)->pcop->type != PO_TWO_OPS)
5774 fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5775 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5778 return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5781 /*-----------------------------------------------------------------*/
5782 /*-----------------------------------------------------------------*/
5784 static void AnalyzepBlock(pBlock *pb)
5791 /* Find all of the registers used in this pBlock
5792 * by looking at each instruction and examining it's
5795 for(pc = pb->pcHead; pc; pc = pc->next) {
5797 /* Is this an instruction with operands? */
5798 if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5800 if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5802 /* Loop through all of the registers declared so far in
5803 this block and see if we find this one there */
5805 regs *r = setFirstItem(pb->tregisters);
5808 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5809 PCOR(PCI(pc)->pcop)->r = r;
5812 r = setNextItem(pb->tregisters);
5816 /* register wasn't found */
5817 //r = Safe_calloc(1, sizeof(regs));
5818 //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5819 //addSet(&pb->tregisters, r);
5820 addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5821 //PCOR(PCI(pc)->pcop)->r = r;
5822 //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5824 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5827 if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5828 if(PCOR(PCI(pc)->pcop)->r) {
5829 pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx); /* FIXME! - VR */
5830 DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5832 if(PCI(pc)->pcop->name)
5833 fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5835 fprintf(stderr,"ERROR: NULL register\n");
5844 /*-----------------------------------------------------------------*/
5846 /*-----------------------------------------------------------------*/
5847 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5849 static void InsertpFlow(pCode *pc, pCode **pflow)
5852 PCFL(*pflow)->end = pc;
5854 if(!pc || !pc->next)
5857 *pflow = pic16_newpCodeFlow();
5858 pic16_pCodeInsertAfter(pc, *pflow);
5861 /*-----------------------------------------------------------------*/
5862 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5863 /* the flow blocks. */
5865 * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5866 * point the instruction flow changes.
5868 /*-----------------------------------------------------------------*/
5869 void pic16_BuildFlow(pBlock *pb)
5872 pCode *last_pci=NULL;
5879 //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq);
5880 /* Insert a pCodeFlow object at the beginning of a pBlock */
5882 InsertpFlow(pb->pcHead, &pflow);
5884 //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */
5885 //pflow->next = pb->pcHead; /* Make the current head the next object */
5886 //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */
5887 //pb->pcHead = pflow; /* Make the Flow object the head */
5890 for( pc = pic16_findNextInstruction(pb->pcHead);
5892 pc=pic16_findNextInstruction(pc)) {
5895 PCI(pc)->pcflow = PCFL(pflow);
5897 //fprintf(stderr," build: ");
5898 //pflow->print(stderr,pflow);
5900 if (checkLabel(pc)) {
5902 /* This instruction marks the beginning of a
5903 * new flow segment */
5908 /* If the previous pCode is not a flow object, then
5909 * insert a new flow object. (This check prevents
5910 * two consecutive flow objects from being insert in
5911 * the case where a skip instruction preceeds an
5912 * instruction containing a label.) */
5914 if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5915 InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5917 PCI(pc)->pcflow = PCFL(pflow);
5921 if( PCI(pc)->isSkip) {
5923 /* The two instructions immediately following this one
5924 * mark the beginning of a new flow segment */
5926 while(pc && PCI(pc)->isSkip) {
5928 PCI(pc)->pcflow = PCFL(pflow);
5932 InsertpFlow(pc, &pflow);
5933 pc=pic16_findNextInstruction(pc->next);
5941 PCI(pc)->pcflow = PCFL(pflow);
5943 InsertpFlow(pc, &pflow);
5945 } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) {
5947 InsertpFlow(pc, &pflow);
5955 //fprintf (stderr,",end seq %d",GpcFlowSeq);
5957 PCFL(pflow)->end = pb->pcTail;
5960 /*-------------------------------------------------------------------*/
5961 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5962 /* the flow blocks. */
5964 * unBuildFlow removes pCodeFlow objects from a pCode chain
5966 /*-----------------------------------------------------------------*/
5967 static void unBuildFlow(pBlock *pb)
5982 if(PCI(pc)->pcflow) {
5983 //Safe_free(PCI(pc)->pcflow);
5984 PCI(pc)->pcflow = NULL;
5987 } else if(isPCFL(pc) )
5996 /*-----------------------------------------------------------------*/
5997 /*-----------------------------------------------------------------*/
5998 static void dumpCond(int cond)
6001 static char *pcc_str[] = {
6015 int ncond = sizeof(pcc_str) / sizeof(char *);
6018 fprintf(stderr, "0x%04X\n",cond);
6020 for(i=0,j=1; i<ncond; i++, j<<=1)
6022 fprintf(stderr, " %s\n",pcc_str[i]);
6028 /*-----------------------------------------------------------------*/
6029 /*-----------------------------------------------------------------*/
6030 static void FlowStats(pCodeFlow *pcflow)
6038 fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6040 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6043 fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6048 fprintf(stderr, " FlowStats inCond: ");
6049 dumpCond(pcflow->inCond);
6050 fprintf(stderr, " FlowStats outCond: ");
6051 dumpCond(pcflow->outCond);
6055 /*-----------------------------------------------------------------*
6056 * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6057 * if it affects the banking bits.
6059 * return: -1 == Banking bits are unaffected by this pCode.
6061 * return: > 0 == Banking bits are affected.
6063 * If the banking bits are affected, then the returned value describes
6064 * which bits are affected and how they're affected. The lower half
6065 * of the integer maps to the bits that are affected, the upper half
6066 * to whether they're set or cleared.
6068 *-----------------------------------------------------------------*/
6070 static int isBankInstruction(pCode *pc)
6078 if( PCI(pc)->op == POC_MOVLB ||
6079 (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6080 bank = PCOL(pc)->lit;
6087 /*-----------------------------------------------------------------*/
6088 /*-----------------------------------------------------------------*/
6089 static void FillFlow(pCodeFlow *pcflow)
6098 // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6100 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6103 //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6110 isBankInstruction(pc);
6112 } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6116 fprintf(stderr, " FillFlow - Bad end of flow\n");
6118 fprintf(stderr, " FillFlow - Ending flow with\n ");
6119 pc->print(stderr,pc);
6122 fprintf(stderr, " FillFlow inCond: ");
6123 dumpCond(pcflow->inCond);
6124 fprintf(stderr, " FillFlow outCond: ");
6125 dumpCond(pcflow->outCond);
6129 /*-----------------------------------------------------------------*/
6130 /*-----------------------------------------------------------------*/
6131 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6133 pCodeFlowLink *fromLink, *toLink;
6135 if(!from || !to || !to->pcflow || !from->pcflow)
6138 fromLink = pic16_newpCodeFlowLink(from->pcflow);
6139 toLink = pic16_newpCodeFlowLink(to->pcflow);
6141 addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
6142 addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6146 pCode *pic16_getJumptabpCode (pCode *pc) {
6149 //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6150 //pc->print (stderr, pc);
6153 if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6154 if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6155 switch (PCOO(PCINF(pcinf)->oper1)->type) {
6156 case OPT_JUMPTABLE_BEGIN:
6157 /* leading begin of jump table -- in one */
6158 pcinf = pic16_findPrevInstruction (pcinf);
6162 case OPT_JUMPTABLE_END:
6163 /* leading end of jumptable -- not in one */
6168 /* ignore all other PCInfos */
6172 pcinf = pcinf->prev;
6175 /* no PCInfo found -- not in a jumptable */
6179 /*-----------------------------------------------------------------*
6180 * void LinkFlow(pBlock *pb)
6182 * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6183 * non-branching segments. In LinkFlow, we determine the execution
6184 * order of these segments. For example, if one of the segments ends
6185 * with a skip, then we know that there are two possible flow segments
6186 * to which control may be passed.
6187 *-----------------------------------------------------------------*/
6188 static void LinkFlow(pBlock *pb)
6193 pCode *jumptab_pre = NULL;
6195 //fprintf(stderr,"linkflow \n");
6197 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6199 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6202 fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6204 //fprintf(stderr," link: ");
6205 //pcflow->print(stderr,pcflow);
6207 //FillFlow(PCFL(pcflow));
6209 pc = PCFL(pcflow)->end;
6211 //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6212 if(isPCI_SKIP(pc)) {
6213 // fprintf(stderr, "ends with skip\n");
6214 // pc->print(stderr,pc);
6216 pct=pic16_findNextInstruction(pc->next);
6217 LinkFlow_pCode(PCI(pc),PCI(pct));
6218 pct=pic16_findNextInstruction(pct->next);
6219 LinkFlow_pCode(PCI(pc),PCI(pct));
6223 if(isPCI_BRANCH(pc)) {
6224 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6226 /* handle GOTOs in jumptables */
6227 if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6228 /* link to previous flow */
6229 //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6230 LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6233 switch (PCI(pc)->op) {
6239 /* unconditional branches -- do not link to next instruction */
6240 //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6245 /* unconditional calls -- link to next instruction */
6246 //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6247 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6258 /* conditional branches -- also link to next instruction */
6259 //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6260 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6264 fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6265 assert (0 && "unhandled branching instruction");
6269 //fprintf(stderr, "ends with branch\n ");
6270 //pc->print(stderr,pc);
6272 if(!(pcol && isPCOLAB(pcol))) {
6273 if((PCI(pc)->op != POC_RETLW)
6274 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6276 /* continue if label is '$' which assembler knows how to parse */
6277 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6279 if(pic16_pcode_verbose) {
6280 pc->print(stderr,pc);
6281 fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6287 if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6288 LinkFlow_pCode(PCI(pc),PCI(pct));
6290 fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6291 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6293 // fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6299 //fprintf(stderr, "ends with non-branching instruction:\n");
6300 //pc->print(stderr,pc);
6302 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6308 //fprintf(stderr, "ends with unknown\n");
6309 //pc->print(stderr,pc);
6313 //fprintf(stderr, "ends with nothing: ERROR\n");
6317 /*-----------------------------------------------------------------*/
6318 /*-----------------------------------------------------------------*/
6320 /*-----------------------------------------------------------------*/
6321 /*-----------------------------------------------------------------*/
6322 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6328 if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6331 if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6341 /*-----------------------------------------------------------------*/
6342 /* insertBankSwitch - inserts a bank switch statement in the */
6343 /* assembly listing */
6345 /* position == 0: insert before */
6346 /* position == 1: insert after pc */
6347 /* position == 2: like 0 but previous was a skip instruction */
6348 /*-----------------------------------------------------------------*/
6349 pCodeOp *pic16_popGetLabel(unsigned int key);
6350 extern int pic16_labelOffset;
6352 static void insertBankSwitch(unsigned char position, pCode *pc)
6359 /* emit BANKSEL [symbol] */
6362 new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6364 // position = 0; // position is always before (sanity check!)
6367 fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6368 pc->print(stderr, pc);
6373 /* insert the bank switch after this pc instruction */
6374 pCode *pcnext = pic16_findNextInstruction(pc);
6376 pic16_pCodeInsertAfter(pc, new_pc);
6377 if(pcnext)pc = pcnext;
6381 /* insert the bank switch BEFORE this pc instruction */
6382 pic16_pCodeInsertAfter(pc->prev, new_pc);
6387 pCode *pcnext, *pcprev, *npci, *ppc;
6389 int ofs1=0, ofs2=0, len=0;
6391 /* just like 0, but previous was a skip instruction,
6392 * so some care should be taken */
6394 pic16_labelOffset += 10000;
6395 tlbl = newiTempLabel(NULL);
6397 /* invert skip instruction */
6398 pcprev = pic16_findPrevInstruction(pc->prev);
6399 ipci = PCI(pcprev)->inverted_op;
6400 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6402 // fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6404 /* copy info from old pCode */
6405 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6406 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6407 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6408 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6409 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6410 PCI(npci)->op = PCI(pcprev)->inverted_op;
6412 /* unlink old pCode */
6414 ppc->next = pcprev->next;
6415 pcprev->next->prev = ppc;
6416 pic16_pCodeInsertAfter(ppc, npci);
6418 /* extra instructions to handle invertion */
6419 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6420 pic16_pCodeInsertAfter(npci, pcnext);
6421 pic16_pCodeInsertAfter(pc->prev, new_pc);
6423 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6424 pic16_pCodeInsertAfter(pc, pcnext);
6429 /* Move the label, if there is one */
6430 if(PCI(pc)->label) {
6431 // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6432 // __FILE__, __LINE__, pc, new_pc);
6433 PCAD(new_pc)->pci.label = PCI(pc)->label;
6434 PCI(pc)->label = NULL;
6439 /*-----------------------------------------------------------------*/
6440 /*int compareBankFlow - compare the banking requirements between */
6442 /*-----------------------------------------------------------------*/
6443 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6446 if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6449 if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6452 if(pcflow->firstBank == -1)
6456 if(pcflowLink->pcflow->firstBank == -1) {
6457 pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6458 pcflowLink->pcflow->to :
6459 pcflowLink->pcflow->from);
6460 return compareBankFlow(pcflow, pctl, toORfrom);
6464 if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6467 pcflowLink->bank_conflict++;
6468 pcflowLink->pcflow->FromConflicts++;
6469 pcflow->ToConflicts++;
6472 if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6475 pcflowLink->bank_conflict++;
6476 pcflowLink->pcflow->ToConflicts++;
6477 pcflow->FromConflicts++;
6481 fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6482 pcflowLink->pcflow->pc.seq,
6483 pcflowLink->pcflow->FromConflicts,
6484 pcflowLink->pcflow->ToConflicts);
6491 /*-----------------------------------------------------------------*/
6492 /*-----------------------------------------------------------------*/
6493 static void DumpFlow(pBlock *pb)
6497 pCodeFlowLink *pcfl;
6500 fprintf(stderr,"Dump flow \n");
6501 pb->pcHead->print(stderr, pb->pcHead);
6503 pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6504 pcflow->print(stderr,pcflow);
6506 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6508 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6510 if(!isPCFL(pcflow)) {
6511 fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6514 fprintf(stderr,"dumping: ");
6515 pcflow->print(stderr,pcflow);
6516 FlowStats(PCFL(pcflow));
6518 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6520 pc = PCODE(pcfl->pcflow);
6522 fprintf(stderr, " from seq %d:\n",pc->seq);
6524 fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6525 pc->print(stderr,pc);
6530 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6532 pc = PCODE(pcfl->pcflow);
6534 fprintf(stderr, " to seq %d:\n",pc->seq);
6536 fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6537 pc->print(stderr,pc);
6546 /*-----------------------------------------------------------------*/
6547 /*-----------------------------------------------------------------*/
6548 static int OptimizepBlock(pBlock *pb)
6553 if(!pb || !peepOptimizing)
6556 DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6558 for(pc = pb->pcHead; pc; pc = pc->next)
6559 matches += pic16_pCodePeepMatchRule(pc);
6562 pc = pic16_findNextInstruction(pb->pcHead);
6570 if(pic16_pCodePeepMatchRule(pc)) {
6575 pc = pic16_findNextInstruction(pcprev->next);
6577 pc = pic16_findNextInstruction(pb->pcHead);
6579 pc = pic16_findNextInstruction(pc->next);
6583 DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6588 /*-----------------------------------------------------------------*/
6589 /*-----------------------------------------------------------------*/
6590 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6594 for(pc = pcs; pc; pc = pc->next) {
6596 if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6598 (PCI(pc)->pcop->type == PO_LABEL) &&
6599 (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6607 /*-----------------------------------------------------------------*/
6608 /*-----------------------------------------------------------------*/
6609 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6616 (PCI(pc)->pcop->type == PO_LABEL)) {
6618 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6620 // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6621 // if(pcol->pcop.name)
6622 // Safe_free(pcol->pcop.name);
6624 /* If the key is negative, then we (probably) have a label to
6625 * a function and the name is already defined */
6628 sprintf(s=buffer,"_%05d_DS_",pcl->key);
6632 //sprintf(buffer,"_%05d_DS_",pcl->key);
6634 fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6636 pcol->pcop.name = Safe_strdup(s);
6637 pcol->key = pcl->key;
6638 //pc->print(stderr,pc);
6645 /*-----------------------------------------------------------------*/
6646 /* pBlockRemoveUnusedLabels - remove the pCode labels from the */
6647 /* pCode chain if they're not used. */
6648 /*-----------------------------------------------------------------*/
6649 static void pBlockRemoveUnusedLabels(pBlock *pb)
6651 pCode *pc; pCodeLabel *pcl;
6653 if(!pb || !pb->pcHead)
6656 for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6658 pBranch *pbr = PCI(pc)->label;
6659 if(pbr && pbr->next) {
6660 pCode *pcd = pb->pcHead;
6662 // fprintf(stderr, "multiple labels\n");
6663 // pc->print(stderr,pc);
6668 while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6669 //fprintf(stderr,"Used by:\n");
6670 //pcd->print(stderr,pcd);
6672 exchangeLabels(PCL(pbr->pc),pcd);
6681 for(pc = pb->pcHead; pc; pc = pc->next) {
6683 if(isPCL(pc)) // pc->type == PC_LABEL)
6685 else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6686 pcl = PCL(PCI(pc)->label->pc);
6689 // fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6691 /* This pCode is a label, so search the pBlock to see if anyone
6694 if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6696 //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6697 /* Couldn't find an instruction that refers to this label
6698 * So, unlink the pCode label from it's pCode chain
6699 * and destroy the label */
6700 // fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6702 DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6703 if(pc->type == PC_LABEL) {
6704 pic16_unlinkpCode(pc);
6705 pCodeLabelDestruct(pc);
6707 unlinkpCodeFromBranch(pc, PCODE(pcl));
6708 /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6709 Safe_free(pc->label);
6719 /*-----------------------------------------------------------------*/
6720 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */
6721 /* chain and put them into pBranches that are */
6722 /* associated with the appropriate pCode */
6724 /*-----------------------------------------------------------------*/
6725 void pic16_pBlockMergeLabels(pBlock *pb)
6728 pCode *pc, *pcnext=NULL;
6733 /* First, Try to remove any unused labels */
6734 //pBlockRemoveUnusedLabels(pb);
6736 /* Now loop through the pBlock and merge the labels with the opcodes */
6739 // for(pc = pb->pcHead; pc; pc = pc->next) {
6742 pCode *pcn = pc->next;
6744 if(pc->type == PC_LABEL) {
6746 // fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6747 // fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6749 if((pcnext = pic16_findNextInstruction(pc) )) {
6751 // pcnext->print(stderr, pcnext);
6753 // Unlink the pCode label from it's pCode chain
6754 pic16_unlinkpCode(pc);
6756 // fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6757 // And link it into the instruction's pBranch labels. (Note, since
6758 // it's possible to have multiple labels associated with one instruction
6759 // we must provide a means to accomodate the additional labels. Thus
6760 // the labels are placed into the singly-linked list "label" as
6761 // opposed to being a single member of the pCodeInstruction.)
6763 //_ALLOC(pbr,sizeof(pBranch));
6765 pbr = Safe_calloc(1,sizeof(pBranch));
6769 PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6772 if(pic16_pcode_verbose)
6773 fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6775 } else if(pc->type == PC_CSOURCE) {
6777 /* merge the source line symbolic info into the next instruction */
6778 if((pcnext = pic16_findNextInstruction(pc) )) {
6780 // Unlink the pCode label from it's pCode chain
6781 pic16_unlinkpCode(pc);
6782 PCI(pcnext)->cline = PCCS(pc);
6783 //fprintf(stderr, "merging CSRC\n");
6784 //genericPrint(stderr,pcnext);
6790 pBlockRemoveUnusedLabels(pb);
6794 /*-----------------------------------------------------------------*/
6795 /*-----------------------------------------------------------------*/
6796 static int OptimizepCode(char dbName)
6798 #define MAX_PASSES 4
6807 DFPRINTF((stderr," Optimizing pCode\n"));
6811 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6812 if('*' == dbName || getpBlock_dbName(pb) == dbName)
6813 matches += OptimizepBlock(pb);
6816 while(matches && ++passes < MAX_PASSES);
6823 const char *pic16_pCodeOpType(pCodeOp *pcop);
6824 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6827 /*-----------------------------------------------------------------*/
6828 /* pic16_popCopyGPR2Bit - copy a pcode operator */
6829 /*-----------------------------------------------------------------*/
6831 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6835 // fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6838 pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6840 if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6843 assert(pcop != NULL);
6845 if( !( (pcop->type == PO_LABEL) ||
6846 (pcop->type == PO_LITERAL) ||
6847 (pcop->type == PO_STR) ))
6848 PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */
6849 PCOR(pcop)->r->wasUsed = 1;
6850 PCOR(pcop)->instance = PCOR(pc)->instance;
6856 /*----------------------------------------------------------------------*
6857 * pic16_areRegsSame - check to see if the names of two registers match *
6858 *----------------------------------------------------------------------*/
6859 int pic16_areRegsSame(regs *r1, regs *r2)
6861 if(!strcmp(r1->name, r2->name))return 1;
6867 /*-----------------------------------------------------------------*/
6868 /*-----------------------------------------------------------------*/
6869 static void pic16_FixRegisterBanking(pBlock *pb)
6873 regs *reg, *prevreg;
6874 unsigned char flag=0;
6879 pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6882 /* loop through all of the flow blocks with in one pblock */
6884 // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6888 /* at this point, pc should point to a PC_FLOW object */
6889 /* for each flow block, determine the register banking
6893 /* if label, then might come from other point, force banksel */
6894 if(isPCL(pc))prevreg = NULL;
6896 if(!isPCI(pc))goto loop;
6898 if(PCI(pc)->label)prevreg = NULL;
6900 if(PCI(pc)->is2MemOp)goto loop;
6902 /* if goto, then force banksel */
6903 // if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6905 reg = pic16_getRegFromInstruction(pc);
6908 pc->print(stderr, pc);
6909 fprintf(stderr, "reg = %p\n", reg);
6912 fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6913 fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6914 reg->address,reg->isBitField, reg->isFixed);
6918 /* now make some tests to make sure that instruction needs bank switch */
6920 /* if no register exists, and if not a bit opcode goto loop */
6922 if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6925 if(isPCI_SKIP(pc)) {
6926 // fprintf(stderr, "instruction is SKIP instruction\n");
6929 if(reg && isACCESS_BANK(reg))goto loop;
6931 if(!isBankInstruction(pc))goto loop;
6933 if(isPCI_LIT(pc))goto loop;
6935 if(PCI(pc)->op == POC_CALL)goto loop;
6937 /* Examine the instruction before this one to make sure it is
6938 * not a skip type instruction */
6939 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
6941 flag = 0; /* add before this instruction */
6943 /* if previous instruction is a skip one, then set flag
6944 * to 2 and call insertBankSwitch */
6945 if(pcprev && isPCI_SKIP(pcprev)) {
6950 if(pic16_options.opt_banksel>0) {
6951 char op1[128], op2[128];
6954 strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
6955 strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
6956 if(!strcmp(op1, op2))goto loop;
6960 insertBankSwitch(flag, pc);
6962 // fprintf(stderr, "BANK SWITCH inserted\n");
6970 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
6972 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
6973 int instrSize (pCode *pc)
6978 if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
6979 return 4; // assumes only regular instructions using <= 4 bytes
6982 if (isPCI(pc)) return PCI(pc)->isize;
6987 /* Returns 1 if pc is referenced by the given label (either
6988 * pc is the label itself or is an instruction with an attached
6990 * Returns 0 if pc is not preceeded by the specified label.
6992 int isLabel (pCode *pc, char *label)
6996 // label attached to the pCode?
6997 if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
6998 pBranch *lab = NULL;
6999 lab = PCI(pc)->label;
7002 if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7009 // is inline assembly label?
7010 if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7011 // do not compare trailing ':'
7012 if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7019 if (strcmp(PCL(pc)->label,label) == 0) {
7024 // no label/no label attached/wrong label(s)
7028 /* Returns the distance to the given label in terms of words.
7029 * Labels are searched only within -max .. max words from pc.
7030 * Returns max if the label could not be found or
7031 * its distance from pc in (-max..+max).
7033 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7034 int dist = instrSize(pc);
7038 while (dist < max && curr && !isLabel (curr, label)) {
7040 dist += instrSize(curr); // sizeof (instruction)
7042 if (curr && dist < max) {
7043 if (target != NULL) *target = curr;
7048 curr = pic16_findNextInstruction (pc->next);
7050 while (dist < max && curr && !isLabel (curr, label)) {
7051 dist += instrSize(curr); // sizeof (instruction)
7054 if (curr && dist < max) {
7055 if (target != NULL) *target = curr;
7059 if (target != NULL) *target = NULL;
7063 /* Returns -1 if pc does NOT denote an instruction like
7065 * Otherwise we return
7066 * (a) 0x10 + i for BTFSS
7067 * (b) 0x00 + i for BTFSC
7069 int isSkipOnStatus (pCode *pc)
7073 if (!pc || !isPCI(pc)) return -1;
7074 if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7075 else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7078 pcop = PCI(pc)->pcop;
7080 if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7081 return res + ((pCodeOpRegBit *)pcop)->bit;
7087 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7088 * returns 0 otherwise. */
7089 int isConditionalBranch (pCode *pc)
7091 if (!pc || !isPCI_BRANCH(pc)) return 0;
7093 switch (PCI(pc)->op) {
7111 /* Returns 1 if pc has a label attached to it.
7112 * This can be either a label stored in the pCode itself (.label)
7113 * or a label making up its own pCode preceding this pc.
7114 * Returns 0 if pc cannot be reached directly via a label.
7116 int hasNoLabel (pCode *pc)
7121 // are there any label pCodes between pc and the previous instruction?
7122 prev = pic16_findPrevInstruction (pc->prev);
7123 while (pc && pc != prev) {
7124 // pCode with attached label?
7125 if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7126 && PCI(pc)->label) {
7129 // is inline assembly label?
7130 if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7131 if (isPCW(pc) && PCW(pc)->label) return 0;
7134 if (isPCL(pc)) return 0;
7143 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7148 vsprintf (buf, fmt, va);
7151 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7154 /* Replaces the old pCode with the new one, moving the labels,
7155 * C source line and probably flow information to the new pCode.
7157 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7158 if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7161 /* first move all labels from old to new */
7162 PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7163 PCI(oldPC)->label = NULL;
7166 /* move C source line (if possible) */
7167 if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7168 PCI(newPC)->cline = PCI(oldPC)->cline;
7171 /* keep flow information intact */
7172 newPC->seq = oldPC->seq;
7173 PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7174 if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7175 PCI(newPC)->pcflow->end = newPC;
7178 /* insert a comment stating which pCode has been replaced */
7180 if (pic16_pcode_verbose || pic16_debug_verbose) {
7182 pic16_pCode2str (pc_str, 256, oldPC);
7183 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7187 /* insert new pCode into pBlock */
7188 pic16_pCodeInsertAfter (oldPC, newPC);
7189 pic16_unlinkpCode (oldPC);
7191 /* destruct replaced pCode */
7192 oldPC->destruct (oldPC);
7195 /* Returns the inverted conditional branch (if any) or NULL.
7196 * pcop must be set to the new jump target.
7198 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7202 if (!bcc || !isPCI(bcc)) return NULL;
7204 switch (PCI(bcc)->op) {
7205 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7206 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7207 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7208 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7209 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7210 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7211 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7212 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7219 #define MAX_DIST_GOTO 0x7FFFFFFF
7220 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7221 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7222 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7223 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7225 /* Follows GOTO/BRA instructions to their target instructions, stores the
7226 * final destination (not a GOTO or BRA instruction) in target and returns
7227 * the distance from the original pc to *target.
7229 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7232 pCodeOp *lastPCOP = NULL;
7236 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7238 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7239 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7240 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7242 lastPCOP = PCI(curr)->pcop;
7243 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7244 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7247 if (target) *target = last;
7248 if (pcop) *pcop = lastPCOP;
7252 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7253 * Otherwise the first pCode after the jumptable (after
7254 * the OPT_JUMPTABLE_END tag) is returned.
7256 pCode *skipJumptables (pCode *pc, int *isJumptable)
7259 if (!pc) return NULL;
7261 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7263 //fprintf (stderr, "SKIPPING jumptable\n");
7265 //pc->print(stderr, pc);
7267 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7268 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7269 //fprintf (stderr, "<<JUMPTAB:\n");
7270 // skip OPT_END as well
7271 if (pc) pc = pc->next;
7277 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7281 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7282 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7283 pc = skipJumptables (pc, &isJumptab);
7285 // pc is the first pCode after the jumptable
7288 // pc has not been changed by skipJumptables()
7296 /* Turn GOTOs into BRAs if distance between GOTO and label
7297 * is less than 1024 bytes.
7299 * This method is especially useful if GOTOs after BTFS[SC]
7300 * can be turned into BRAs as GOTO would cost another NOP
7303 void pic16_OptimizeJumps ()
7306 pCode *pc_prev = NULL;
7307 pCode *pc_next = NULL;
7310 int change, iteration, isJumptab;
7313 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7315 if (!the_pFile) return;
7317 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7319 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7320 int matchedInvertRule = 1;
7323 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7325 pc = pic16_findNextInstruction (pb->pcHead);
7328 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7330 // skip jumptable, i.e. start over with no pc_prev!
7336 /* (1) resolve chained jumps
7337 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7338 * (a) leave dead code in and
7339 * (b) skip over the dead code with an (unneccessary) jump.
7341 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7342 pCodeOp *lastTargetOp = NULL;
7343 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7344 int maxDist = MAX_DIST_BCC;
7345 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7346 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7348 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7349 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7350 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7351 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7352 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7353 PCI(pc)->pcop->name = lastTargetOp->name;
7362 int condBraType = isSkipOnStatus(pc_prev);
7363 label = PCI(pc)->pcop->name;
7364 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7365 if (dist < 0) dist = -dist;
7366 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7370 /* (2) remove "GOTO label; label:" */
7371 if (isLabel (pc_next, label)) {
7372 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7373 // first remove all preceeding SKIP instructions
7374 while (pc_prev && isPCI_SKIP(pc_prev)) {
7375 // attach labels on this instruction to pc_next
7376 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7377 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7378 PCI(pc_prev)->label = NULL;
7379 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7380 pic16_unlinkpCode (pc_prev);
7381 pc_prev = pic16_findPrevInstruction (pc);
7383 // now remove the redundant goto itself
7384 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7385 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7386 pic16_unlinkpCode (pc);
7387 pc = pic16_findPrevInstruction(pc_next->prev);
7388 isHandled = 1; // do not perform further optimizations
7394 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7395 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7396 if (dist < MAX_DIST_BCC) {
7398 switch (condBraType) {
7399 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7400 // no BDC on DIGIT CARRY available
7401 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7402 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7403 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7404 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7405 // no BNDC on DIGIT CARRY available
7406 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7407 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7408 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7410 // no replacement possible
7415 // ATTENTION: keep labels attached to BTFSx!
7416 // HINT: GOTO is label free (checked above)
7417 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7418 isHandled = 1; // do not perform further optimizations
7419 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7420 pic16_pCodeReplace (pc_prev, bcc);
7427 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7433 // (4) eliminate the following (common) tripel:
7435 // labels1: Bcc label2;
7436 // GOTO somewhere; ; <-- instruction referenced by pc
7438 // and replace it by
7439 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7441 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7442 // to <cont.> instead
7443 // ATTENTION: This optimization is only valid if <pred.> is
7444 // not a skip operation!
7445 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7446 // ATTENTION: no label may be attached to the GOTO instruction!
7447 if (isConditionalBranch(pc_prev)
7448 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7449 && (dist < MAX_DIST_BCC)
7450 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7451 && hasNoLabel(pc)) {
7452 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7455 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7456 isHandled = 1; // do not perform further optimizations
7457 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7458 pic16_pCodeReplace (pc_prev, newBcc);
7463 matchedInvertRule++;
7468 /* (5) now just turn GOTO into BRA */
7469 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7470 if (dist < MAX_DIST_BRA) {
7471 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7472 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7473 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7474 pic16_pCodeReplace (pc, newBra);
7479 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7482 } // if (!isHandled)
7489 pBlockRemoveUnusedLabels (pb);
7491 // This line enables goto chain resolution!
7492 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7495 } while (change); /* fixpoint iteration per pBlock */
7498 // emit some statistics concerning goto-optimization
7500 if (pic16_debug_verbose || pic16_pcode_verbose) {
7501 fprintf (stderr, "optimize-goto:\n"
7502 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7503 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7504 "\t%5d conditional \"skipping\" jumps inverted\n"
7505 "\t%5d GOTOs to next instruction removed\n"
7506 "\t%5d chained GOTOs resolved\n",
7507 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7510 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7514 #undef MAX_JUMPCHAIN_DEPTH
7515 #undef MAX_DIST_GOTO
7519 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7521 static void pBlockDestruct(pBlock *pb)
7532 /*-----------------------------------------------------------------*/
7533 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7534 /* name dbName and combine them */
7535 /* into one block */
7536 /*-----------------------------------------------------------------*/
7537 static void mergepBlocks(char dbName)
7540 pBlock *pb, *pbmerged = NULL,*pbn;
7542 pb = the_pFile->pbHead;
7544 //fprintf(stderr," merging blocks named %c\n",dbName);
7548 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7549 if( getpBlock_dbName(pb) == dbName) {
7551 //fprintf(stderr," merged block %c\n",dbName);
7556 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7557 /* pic16_addpCode2pBlock doesn't handle the tail: */
7558 pbmerged->pcTail = pb->pcTail;
7560 pb->prev->next = pbn;
7562 pbn->prev = pb->prev;
7567 //pic16_printpBlock(stderr, pbmerged);
7574 /*-----------------------------------------------------------------*/
7575 /* AnalyzeFlow - Examine the flow of the code and optimize */
7577 /* level 0 == minimal optimization */
7578 /* optimize registers that are used only by two instructions */
7579 /* level 1 == maximal optimization */
7580 /* optimize by looking at pairs of instructions that use the */
7582 /*-----------------------------------------------------------------*/
7584 static void AnalyzeFlow(int level)
7586 static int times_called=0;
7590 /* remove unused allocated registers before exiting */
7591 pic16_RemoveUnusedRegisters();
7596 /* if this is not the first time this function has been called,
7597 * then clean up old flow information */
7598 if(times_called++) {
7599 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7601 pic16_RegsUnMapLiveRanges();
7605 /* Phase 2 - Flow Analysis - Register Banking
7607 * In this phase, the individual flow blocks are examined
7608 * and register banking is fixed.
7612 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7613 pic16_FixRegisterBanking(pb);
7616 /* Phase 2 - Flow Analysis
7618 * In this phase, the pCode is partition into pCodeFlow
7619 * blocks. The flow blocks mark the points where a continuous
7620 * stream of instructions changes flow (e.g. because of
7621 * a call or goto or whatever).
7624 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7625 pic16_BuildFlow(pb);
7628 /* Phase 2 - Flow Analysis - linking flow blocks
7630 * In this phase, the individual flow blocks are examined
7631 * to determine their order of excution.
7634 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7638 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7639 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7640 pic16_createDF (pb);
7641 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7642 pic16_vcg_dump_default (pb);
7644 //pic16_destructDF (pb);
7648 if (0) releaseStack (); // releasing is costly...
7652 /* Phase 3 - Flow Analysis - Flow Tree
7654 * In this phase, the individual flow blocks are examined
7655 * to determine their order of execution.
7658 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7659 pic16_BuildFlowTree(pb);
7662 /* Phase x - Flow Analysis - Used Banks
7664 * In this phase, the individual flow blocks are examined
7665 * to determine the Register Banks they use
7669 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7674 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7675 pic16_pCodeRegMapLiveRanges(pb);
7677 pic16_RemoveUnusedRegisters();
7678 pic16_removeUnusedRegistersDF ();
7680 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7681 pic16_pCodeRegOptimizeRegUsage(level);
7690 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7695 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7698 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7699 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7700 pcflow = pcflow->next) {
7701 FillFlow(PCFL(pcflow));
7706 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7709 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7710 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7711 pcflow = pcflow->next) {
7712 FlowStats(PCFL(pcflow));
7718 /* VR -- no need to analyze banking in flow, but left here :
7719 * 1. because it may be used in the future for other purposes
7720 * 2. because if omitted we'll miss some optimization done here
7722 * Perhaps I should rename it to something else
7725 /*-----------------------------------------------------------------*/
7726 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7727 /* assigned to the registers. */
7729 /*-----------------------------------------------------------------*/
7731 void pic16_AnalyzeBanking(void)
7735 /* Phase x - Flow Analysis - Used Banks
7737 * In this phase, the individual flow blocks are examined
7738 * to determine the Register Banks they use
7748 if(!the_pFile)return;
7750 if(!pic16_options.no_banksel) {
7751 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7752 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7753 pic16_FixRegisterBanking(pb);
7758 /*-----------------------------------------------------------------*/
7759 /* buildCallTree - Look at the flow and extract all of the calls. */
7760 /*-----------------------------------------------------------------*/
7761 static set *register_usage(pBlock *pb);
7763 static void buildCallTree(void )
7775 /* Now build the call tree.
7776 First we examine all of the pCodes for functions.
7777 Keep in mind that the function boundaries coincide
7778 with pBlock boundaries.
7780 The algorithm goes something like this:
7781 We have two nested loops. The outer loop iterates
7782 through all of the pBlocks/functions. The inner
7783 loop iterates through all of the pCodes for
7784 a given pBlock. When we begin iterating through
7785 a pBlock, the variable pc_fstart, pCode of the start
7786 of a function, is cleared. We then search for pCodes
7787 of type PC_FUNCTION. When one is encountered, we
7788 initialize pc_fstart to this and at the same time
7789 associate a new pBranch object that signifies a
7790 branch entry. If a return is found, then this signifies
7791 a function exit point. We'll link the pCodes of these
7792 returns to the matching pc_fstart.
7794 When we're done, a doubly linked list of pBranches
7795 will exist. The head of this list is stored in
7796 `the_pFile', which is the meta structure for all
7797 of the pCode. Look at the pic16_printCallTree function
7798 on how the pBranches are linked together.
7801 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7802 pCode *pc_fstart=NULL;
7803 for(pc = pb->pcHead; pc; pc = pc->next) {
7805 if(isPCI(pc) && pc_fstart) {
7806 if(PCI(pc)->is2MemOp) {
7807 r = pic16_getRegFromInstruction2(pc);
7808 if(r && !strcmp(r->name, "POSTDEC1"))
7809 PCF(pc_fstart)->stackusage++;
7811 r = pic16_getRegFromInstruction(pc);
7812 if(r && !strcmp(r->name, "PREINC1"))
7813 PCF(pc_fstart)->stackusage--;
7818 if (PCF(pc)->fname) {
7821 sprintf(buf, "%smain", port->fun_prefix);
7822 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7823 //fprintf(stderr," found main \n");
7824 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7828 pbr = Safe_calloc(1,sizeof(pBranch));
7829 pbr->pc = pc_fstart = pc;
7832 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7834 // Here's a better way of doing the same:
7835 addSet(&pb->function_entries, pc);
7838 // Found an exit point in a function, e.g. return
7839 // (Note, there may be more than one return per function)
7841 pBranchLink(PCF(pc_fstart), PCF(pc));
7843 addSet(&pb->function_exits, pc);
7845 } else if(isCALL(pc)) {
7846 addSet(&pb->function_calls,pc);
7853 /* This is not needed because currently all register used
7854 * by a function are stored in stack -- VR */
7856 /* Re-allocate the registers so that there are no collisions
7857 * between local variables when one function call another */
7860 // pic16_deallocateAllRegs();
7862 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7870 /*-----------------------------------------------------------------*/
7871 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7872 /* all of the logical connections. */
7874 /* Essentially what's done here is that the pCode flow is */
7876 /*-----------------------------------------------------------------*/
7878 void pic16_AnalyzepCode(char dbName)
7889 /* Phase 1 - Register allocation and peep hole optimization
7891 * The first part of the analysis is to determine the registers
7892 * that are used in the pCode. Once that is done, the peep rules
7893 * are applied to the code. We continue to loop until no more
7894 * peep rule optimizations are found (or until we exceed the
7895 * MAX_PASSES threshold).
7897 * When done, the required registers will be determined.
7903 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7904 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7906 /* First, merge the labels with the instructions */
7907 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7908 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7910 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7911 //fprintf(stderr," analyze and merging block %c\n",dbName);
7912 pic16_pBlockMergeLabels(pb);
7915 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7920 changes = OptimizepCode(dbName);
7923 } while(changes && (i++ < MAX_PASSES));
7930 /* convert a series of movff's of local regs to stack, with a single call to
7931 * a support functions which does the same thing via loop */
7932 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
7936 char *fname[]={"__lr_store", "__lr_restore"};
7938 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
7940 pct = pic16_findNextInstruction(pcstart->next);
7943 pct = pc->next; //pic16_findNextInstruction(pc->next);
7944 // pc->print(stderr, pc);
7945 if(isPCI(pc) && PCI(pc)->label) {
7946 pbr = PCI(pc)->label;
7947 while(pbr && pbr->pc) {
7948 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
7952 // pc->print(stderr, pc);
7954 pc->prev->next = pct;
7955 pct->prev = pc->prev;
7959 } while ((pc) && (pc != pcend));
7961 /* unlink movff instructions */
7962 pcstart->next = pcend;
7963 pcend->prev = pcstart;
7967 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7968 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
7971 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
7972 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
7973 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
7976 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7977 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
7984 sym = newSymbol( fname[ entry?0:1 ], 0 );
7985 strcpy(sym->rname, fname[ entry?0:1 ]);
7986 checkAddSym(&externs, sym);
7988 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
7993 /*-----------------------------------------------------------------*/
7994 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
7995 /* local registers to a support function call */
7996 /*-----------------------------------------------------------------*/
7997 void pic16_OptimizeLocalRegs(void)
8002 pCodeOpLocalReg *pclr;
8005 regs *r, *lastr=NULL, *firstr=NULL;
8006 pCode *pcstart=NULL, *pcend=NULL;
8011 * local_regs begin mark
8012 * MOVFF r0x01, POSTDEC1
8013 * MOVFF r0x02, POSTDEC1
8016 * MOVFF r0x0n, POSTDEC1
8017 * local_regs end mark
8019 * convert the above to the below:
8020 * MOVLW starting_register_index
8022 * MOVLW register_count
8023 * call __save_registers_in_stack
8029 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8030 inRegCount = regCount = 0;
8031 firstr = lastr = NULL;
8032 for(pc = pb->pcHead; pc; pc = pc->next) {
8034 /* hold current function name */
8035 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8037 if(pc && (pc->type == PC_INFO)) {
8040 if(pci->type == INF_LOCALREGS) {
8041 pclr = PCOLR(pci->oper1);
8043 if((pclr->type == LR_ENTRY_BEGIN)
8044 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8047 switch(pclr->type) {
8048 case LR_ENTRY_BEGIN:
8050 inRegCount = 1; regCount = 0;
8051 pcstart = pc; //pic16_findNextInstruction(pc->next);
8052 firstr = lastr = NULL;
8058 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8061 if(curFunc && inWparamList(curFunc+1)) {
8062 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8066 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8071 firstr = lastr = NULL;
8075 if(inRegCount == -1) {
8076 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8082 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8084 r = pic16_getRegFromInstruction(pc);
8086 r = pic16_getRegFromInstruction2(pc);
8087 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8088 if(!firstr)firstr = r;
8090 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8102 /*-----------------------------------------------------------------*/
8103 /* ispCodeFunction - returns true if *pc is the pCode of a */
8105 /*-----------------------------------------------------------------*/
8106 static bool ispCodeFunction(pCode *pc)
8109 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8115 /*-----------------------------------------------------------------*/
8116 /* findFunction - Search for a function by name (given the name) */
8117 /* in the set of all functions that are in a pBlock */
8118 /* (note - I expect this to change because I'm planning to limit */
8119 /* pBlock's to just one function declaration */
8120 /*-----------------------------------------------------------------*/
8121 static pCode *findFunction(char *fname)
8128 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8130 pc = setFirstItem(pb->function_entries);
8133 if((pc->type == PC_FUNCTION) &&
8135 (strcmp(fname, PCF(pc)->fname)==0))
8138 pc = setNextItem(pb->function_entries);
8146 static void MarkUsedRegisters(set *regset)
8151 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8152 // fprintf(stderr, "marking register = %s\t", r1->name);
8153 r2 = pic16_regWithIdx(r1->rIdx);
8154 // fprintf(stderr, "to register = %s\n", r2->name);
8160 static void pBlockStats(FILE *of, pBlock *pb)
8166 if(!pic16_pcode_verbose)return;
8168 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8170 // for now just print the first element of each set
8171 pc = setFirstItem(pb->function_entries);
8173 fprintf(of,";entry: ");
8176 pc = setFirstItem(pb->function_exits);
8178 fprintf(of,";has an exit\n");
8182 pc = setFirstItem(pb->function_calls);
8184 fprintf(of,";functions called:\n");
8187 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8188 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8190 pc = setNextItem(pb->function_calls);
8194 r = setFirstItem(pb->tregisters);
8196 int n = elementsInSet(pb->tregisters);
8198 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8201 fprintf(of, "; %s\n",r->name);
8202 r = setNextItem(pb->tregisters);
8206 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8209 /*-----------------------------------------------------------------*/
8210 /*-----------------------------------------------------------------*/
8212 static void sequencepCode(void)
8218 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8220 pb->seq = GpCodeSequenceNumber+1;
8222 for( pc = pb->pcHead; pc; pc = pc->next)
8223 pc->seq = ++GpCodeSequenceNumber;
8229 /*-----------------------------------------------------------------*/
8230 /*-----------------------------------------------------------------*/
8231 static set *register_usage(pBlock *pb)
8234 set *registers=NULL;
8235 set *registersInCallPath = NULL;
8237 /* check recursion */
8239 pc = setFirstItem(pb->function_entries);
8246 if(pc->type != PC_FUNCTION)
8247 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8249 pc = setFirstItem(pb->function_calls);
8250 for( ; pc; pc = setNextItem(pb->function_calls)) {
8252 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8253 char *dest = pic16_get_op_from_instruction(PCI(pc));
8255 pcn = findFunction(dest);
8257 registersInCallPath = register_usage(pcn->pb);
8259 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8264 pBlockStats(stderr,pb); // debug
8267 // Mark the registers in this block as used.
8269 MarkUsedRegisters(pb->tregisters);
8270 if(registersInCallPath) {
8271 /* registers were used in the functions this pBlock has called */
8272 /* so now, we need to see if these collide with the ones we are */
8275 regs *r1,*r2, *newreg;
8277 DFPRINTF((stderr,"comparing registers\n"));
8279 r1 = setFirstItem(registersInCallPath);
8282 r2 = setFirstItem(pb->tregisters);
8284 while(r2 && (r1->type != REG_STK)) {
8286 if(r2->rIdx == r1->rIdx) {
8287 newreg = pic16_findFreeReg(REG_GPR);
8291 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8295 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8296 r1->rIdx, newreg->rIdx));
8297 r2->rIdx = newreg->rIdx;
8298 //if(r2->name) Safe_free(r2->name);
8300 r2->name = Safe_strdup(newreg->name);
8304 newreg->wasUsed = 1;
8306 r2 = setNextItem(pb->tregisters);
8309 r1 = setNextItem(registersInCallPath);
8312 /* Collisions have been resolved. Now free the registers in the call path */
8313 r1 = setFirstItem(registersInCallPath);
8315 if(r1->type != REG_STK) {
8316 newreg = pic16_regWithIdx(r1->rIdx);
8319 r1 = setNextItem(registersInCallPath);
8323 // MarkUsedRegisters(pb->registers);
8325 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8328 DFPRINTF((stderr,"returning regs\n"));
8330 DFPRINTF((stderr,"not returning regs\n"));
8332 DFPRINTF((stderr,"pBlock after register optim.\n"));
8333 pBlockStats(stderr,pb); // debug
8339 /*-----------------------------------------------------------------*/
8340 /* pct2 - writes the call tree to a file */
8342 /*-----------------------------------------------------------------*/
8343 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8347 // set *registersInCallPath = NULL;
8353 fprintf(of, "recursive function\n");
8354 return; //recursion ?
8357 pc = setFirstItem(pb->function_entries);
8364 for(i=0;i<indent;i++) // Indentation
8368 if(pc->type == PC_FUNCTION) {
8369 usedstack += PCF(pc)->stackusage;
8370 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8371 } else return; // ???
8374 pc = setFirstItem(pb->function_calls);
8375 for( ; pc; pc = setNextItem(pb->function_calls)) {
8377 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8378 char *dest = pic16_get_op_from_instruction(PCI(pc));
8380 pcn = findFunction(dest);
8382 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8384 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8392 /*-----------------------------------------------------------------*/
8393 /* pic16_printCallTree - writes the call tree to a file */
8395 /*-----------------------------------------------------------------*/
8397 void pic16_printCallTree(FILE *of)
8409 fprintf(of, "\npBlock statistics\n");
8410 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8414 fprintf(of,"Call Tree\n");
8415 pbr = the_pFile->functions;
8419 if(!ispCodeFunction(pc))
8420 fprintf(of,"bug in call tree");
8423 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8425 while(pc->next && !ispCodeFunction(pc->next)) {
8427 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8428 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8436 fprintf(of,"\n**************\n\na better call tree\n");
8437 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8442 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8443 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8449 /*-----------------------------------------------------------------*/
8451 /*-----------------------------------------------------------------*/
8453 static void InlineFunction(pBlock *pb)
8461 pc = setFirstItem(pb->function_calls);
8463 for( ; pc; pc = setNextItem(pb->function_calls)) {
8466 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8472 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8474 //fprintf(stderr,"Cool can inline:\n");
8475 //pcn->print(stderr,pcn);
8477 //fprintf(stderr,"recursive call Inline\n");
8478 InlineFunction(pcn->pb);
8479 //fprintf(stderr,"return from recursive call Inline\n");
8482 At this point, *pc points to a CALL mnemonic, and
8483 *pcn points to the function that is being called.
8485 To in-line this call, we need to remove the CALL
8486 and RETURN(s), and link the function pCode in with
8492 /* Remove the CALL */
8496 /* remove callee pBlock from the pBlock linked list */
8497 removepBlock(pcn->pb);
8505 /* Remove the Function pCode */
8506 pct = pic16_findNextInstruction(pcn->next);
8508 /* Link the function with the callee */
8509 pc->next = pcn->next;
8510 pcn->next->prev = pc;
8512 /* Convert the function name into a label */
8514 pbr = Safe_calloc(1,sizeof(pBranch));
8515 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8517 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8518 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8520 /* turn all of the return's except the last into goto's */
8521 /* check case for 2 instruction pBlocks */
8522 pce = pic16_findNextInstruction(pcn->next);
8524 pCode *pce_next = pic16_findNextInstruction(pce->next);
8526 if(pce_next == NULL) {
8527 /* found the last return */
8528 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8530 //fprintf(stderr,"found last return\n");
8531 //pce->print(stderr,pce);
8532 pce->prev->next = pc_call->next;
8533 pc_call->next->prev = pce->prev;
8534 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8544 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8550 /*-----------------------------------------------------------------*/
8552 /*-----------------------------------------------------------------*/
8554 void pic16_InlinepCode(void)
8563 if(!functionInlining)
8566 /* Loop through all of the function definitions and count the
8567 * number of times each one is called */
8568 //fprintf(stderr,"inlining %d\n",__LINE__);
8570 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8572 pc = setFirstItem(pb->function_calls);
8574 for( ; pc; pc = setNextItem(pb->function_calls)) {
8577 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8578 if(pcn && isPCF(pcn)) {
8579 PCF(pcn)->ncalled++;
8582 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8587 //fprintf(stderr,"inlining %d\n",__LINE__);
8589 /* Now, Loop through the function definitions again, but this
8590 * time inline those functions that have only been called once. */
8592 InlineFunction(the_pFile->pbHead);
8593 //fprintf(stderr,"inlining %d\n",__LINE__);
8595 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8600 char *pic_optype_names[]={
8601 "PO_NONE", // No operand e.g. NOP
8602 "PO_W", // The working register (as a destination)
8603 "PO_WREG", // The working register (as a file register)
8604 "PO_STATUS", // The 'STATUS' register
8605 "PO_BSR", // The 'BSR' register
8606 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8608 "PO_INDF0", // The Indirect register
8609 "PO_INTCON", // Interrupt Control register
8610 "PO_GPR_REGISTER", // A general purpose register
8611 "PO_GPR_BIT", // A bit of a general purpose register
8612 "PO_GPR_TEMP", // A general purpose temporary register
8613 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8614 "PO_PCL", // Program counter Low register
8615 "PO_PCLATH", // Program counter Latch high register
8616 "PO_PCLATU", // Program counter Latch upper register
8617 "PO_PRODL", // Product Register Low
8618 "PO_PRODH", // Product Register High
8619 "PO_LITERAL", // A constant
8620 "PO_REL_ADDR", // A relative address
8621 "PO_IMMEDIATE", // (8051 legacy)
8622 "PO_DIR", // Direct memory (8051 legacy)
8623 "PO_CRY", // bit memory (8051 legacy)
8624 "PO_BIT", // bit operand.
8625 "PO_STR", // (8051 legacy)
8627 "PO_WILD", // Wild card operand in peep optimizer
8628 "PO_TWO_OPS" // combine two operands
8632 char *dumpPicOptype(PIC_OPTYPE type)
8634 assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8635 return (pic_optype_names[ type ]);
8639 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8642 #define MAX_COMMON_BANK_SIZE 32
8643 #define FIRST_PSEUDO_BANK_NR 1000
8645 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8646 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8647 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8650 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8653 pseudoBankNr bank; // number assigned to this pseudoBank
8654 unsigned int size; // number of operands assigned to this bank
8655 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8658 /*----------------------------------------------------------------------*/
8659 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8660 /*----------------------------------------------------------------------*/
8661 unsigned int hashSymbol (const char *str)
8663 unsigned int res = 0;
8668 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8675 /*-----------------------------------------------------------------------*/
8676 /* compareSymbol - return 1 iff sym1 equals sym2 */
8677 /*-----------------------------------------------------------------------*/
8678 int compareSymbol (const void *sym1, const void *sym2)
8680 char *s1 = (char*) sym1;
8681 char *s2 = (char*) sym2;
8683 return (strcmp (s1,s2) == 0);
8686 /*-----------------------------------------------------------------------*/
8687 /* comparePre - return 1 iff p1 == p2 */
8688 /*-----------------------------------------------------------------------*/
8689 int comparePtr (const void *p1, const void *p2)
8694 /*----------------------------------------------------------*/
8695 /* getSymbolFromOperand - return a pointer to the symbol in */
8696 /* the given operand and its length */
8697 /*----------------------------------------------------------*/
8698 char *getSymbolFromOperand (char *op, int *len)
8703 if (!op) return NULL;
8705 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8707 if (*sym == '(') sym++;
8710 while (((*curr >= 'A') && (*curr <= 'Z'))
8711 || ((*curr >= 'a') && (*curr <= 'z'))
8712 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8713 || (*curr == '_')) {
8714 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8722 /*--------------------------------------------------------------------------*/
8723 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8724 /*--------------------------------------------------------------------------*/
8725 char *getSymFromBank (pseudoBankNr bank)
8729 if (bank < 0) return "<INVALID BANK NR>";
8730 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8733 /*-----------------------------------------------------------------------*/
8734 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8735 /* bank number (uses hTab sym2bank), if the */
8736 /* symbol is not yet assigned a pseudo bank it */
8737 /* is assigned one here */
8738 /*-----------------------------------------------------------------------*/
8739 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8741 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8747 hash = hashSymbol (op) % sym2bank->size;
8748 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8749 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8751 if (bank == UNKNOWN_BANK) {
8752 // create a pseudo bank for the operand
8754 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8755 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8756 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8757 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8759 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8767 /*--------------------------------------------------------------------*/
8768 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8769 /*--------------------------------------------------------------------*/
8770 int isBanksel (pCode *pc)
8774 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8775 // BANKSEL <variablename> or MOVLB <banknr>
8776 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8780 // check for inline assembler BANKSELs
8781 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8782 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8783 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8787 // assume pc is no BANKSEL instruction
8791 /*---------------------------------------------------------------------------------*/
8792 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8793 /* This method can not guarantee to find all modifications of the */
8794 /* BSR (e.g. via INDirection registers) but covers all compiler */
8795 /* generated plus some cases. */
8796 /*---------------------------------------------------------------------------------*/
8797 int invalidatesBSR(pCode *pc)
8799 // assembler directives invalidate BSR (well, they might, we don't know)
8800 if (isPCAD(pc)) return 1;
8802 // only ASMDIRs and pCodeInstructions can invalidate BSR
8803 if (!isPCI(pc)) return 0;
8805 // we have a pCodeInstruction
8807 // check for BSR modifying instructions
8808 switch (PCI(pc)->op) {
8812 case POC_RETFIE: // might be used as CALL replacement
8813 case POC_RETLW: // might be used as CALL replacement
8814 case POC_RETURN: // might be used as CALL replacement
8819 default: // other instruction do not change BSR unless BSR is an explicit operand!
8820 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8824 // no change of BSR possible/probable
8828 /*------------------------------------------------------------*/
8829 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8830 /* the symbol referenced in this BANKSEL */
8831 /*------------------------------------------------------------*/
8832 pseudoBankNr getBankFromBanksel (pCode *pc)
8837 if (!pc) return INVALID_BANK;
8839 if (isPCAD(pc) && PCAD(pc)->directive) {
8840 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8841 // get symbolname from PCAD(pc)->arg
8842 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8843 sym = PCAD(pc)->arg;
8844 data = getPseudoBankNrFromOperand (sym);
8845 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8846 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8847 // get (literal) bank number from PCAD(pc)->arg
8848 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8849 assert (0 && "not yet implemented - turn off banksel optimization for now");
8851 } else if (isPCI(pc)) {
8852 if (PCI(pc)->op == POC_BANKSEL) {
8853 // get symbolname from PCI(pc)->pcop->name (?)
8854 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8855 sym = PCI(pc)->pcop->name;
8856 data = getPseudoBankNrFromOperand (sym);
8857 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8858 } else if (PCI(pc)->op == POC_MOVLB) {
8859 // get (literal) bank number from PCI(pc)->pcop->name
8860 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8861 assert (0 && "not yet implemented - turn off banksel optimization for now");
8866 // no assigned bank could be found
8867 return UNKNOWN_BANK;
8872 /*------------------------------------------------------------------------------*/
8873 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8874 /*------------------------------------------------------------------------------*/
8875 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8879 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8882 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8883 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8885 if (data->bank != bank)
8892 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8896 /*------------------------------------------------------------------*/
8897 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8898 /* bank is selected at a given pCode */
8899 /*------------------------------------------------------------------*/
8901 /* Create a graph with pseudo banks as its nodes and switches between
8902 * these as edges (with the edge weight representing the absolute
8903 * number of BANKSELs from one to the other).
8904 * Removes redundand BANKSELs instead iff mod == 1.
8905 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8906 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8908 * TODO: check ALL instructions operands if they modify BSR directly...
8910 * pb - the pBlock to annotate
8911 * mod - select either graph creation (0) or BANKSEL removal (1)
8913 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8915 pCode *pc, *pc_next;
8916 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8917 int isBankselect = 0;
8918 unsigned int banksels=0;
8922 pc = pic16_findNextInstruction(pb->pcHead);
8924 isBankselect = isBanksel (pc);
8925 pc_next = pic16_findNextInstruction (pc->next);
8927 if (!hasNoLabel (pc)) {
8928 // we don't know our predecessors -- assume different BSRs
8929 prevBSR = UNKNOWN_BANK;
8930 pseudoBSR = UNKNOWN_BANK;
8931 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8934 // check if this is a BANKSEL instruction
8936 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
8937 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
8939 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
8940 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
8941 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
8942 pic16_unlinkpCode (pc);
8946 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
8951 if (!isBankselect && invalidatesBSR(pc)) {
8952 // check if this instruction invalidates the pseudoBSR
8953 pseudoBSR = UNKNOWN_BANK;
8954 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
8957 prevBSR = pseudoBSR;
8964 /*------------------------------------------------------------------------------------*/
8965 /* assignToSameBank - returns 0 on success or an error code */
8966 /* 1 - common bank would be too large */
8967 /* 2 - assignment to fixed (absolute) bank not performed */
8969 /* This functions assumes that unsplittable operands are already assigned to the same */
8970 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
8971 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
8972 /* TODO: Symbols with an abslute address must be handled specially! */
8973 /*------------------------------------------------------------------------------------*/
8974 int assignToSameBank (int bank0, int bank1, int doAbs)
8976 int eff0, eff1, dummy;
8977 pseudoBank *pbank0, *pbank1;
8980 eff0 = getEffectiveBank (bank0);
8981 eff1 = getEffectiveBank (bank1);
8983 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
8985 // nothing to do if already same bank
8986 if (eff0 == eff1) return 0;
8988 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
8991 // ensure eff0 < eff1
8993 // swap eff0 and eff1
9002 // now assign bank eff1 to bank eff0
9003 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9005 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9006 pbank0->bank = eff0;
9009 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9013 hitem = hTabSearch (coerce, eff1 % coerce->size);
9014 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9015 hitem = hitem->next;
9017 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9020 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9021 pbank0->bank, pbank0->size,
9022 getSymFromBank (eff0), getSymFromBank (eff1));
9026 if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9028 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9029 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9030 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9031 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9035 pbank0->size += pbank1->size;
9037 if (pbank1->ref == 0) Safe_free (pbank1);
9043 hitem->item = pbank0;
9045 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9048 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9053 /*----------------------------------------------------------------*/
9054 /* mergeGraphNodes - combines two nodes into one and modifies all */
9055 /* edges to and from the nodes accordingly */
9056 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9057 /* then also (B,A) must be an edge (possibly with weight 0). */
9058 /*----------------------------------------------------------------*/
9059 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9061 GraphEdge *edge, *backedge, *nextedge;
9065 assert (node1 && node2);
9066 assert (node1 != node2);
9068 // add all edges starting at node2 to node1
9071 nextedge = edge->next;
9073 backedge = getGEdge (node, node2);
9075 backweight = backedge->weight;
9078 // insert edges (node1,node) and (node,node1)
9079 addGEdge2 (node1, node, edge->weight, backweight);
9080 // remove edges (node, node2) and (node2, node)
9081 remGEdge (node2, node);
9082 remGEdge (node, node2);
9086 // now node2 should not be referenced by any other GraphNode...
9087 //remGNode (adj, node2->data, node2->hash);
9090 /*----------------------------------------------------------------*/
9091 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9092 /*----------------------------------------------------------------*/
9093 void showGraph (Graph *g)
9097 pseudoBankNr bankNr;
9104 bankNr = getEffectiveBank (node->hash);
9105 assert (bankNr >= 0);
9106 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9108 bankNr = pbank->bank;
9114 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9117 if (edge->weight > 0)
9118 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9125 /*---------------------------------------------------------------*/
9126 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9127 /*---------------------------------------------------------------*/
9128 void pic16_OptimizeBanksel ()
9130 GraphNode *node, *node1, *node1next;
9133 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9134 GraphEdge *edge, *backedge;
9136 int maxWeight, weight, mergeMore, absMaxWeight;
9137 pseudoBankNr curr0, curr1;
9140 pseudoBankNr bankNr;
9141 char *base_symbol0, *base_symbol1;
9146 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9148 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9150 if (!the_pFile || !the_pFile->pbHead) return;
9152 adj = newGraph (NULL);
9153 sym2bank = newHashTable ( 255 );
9154 bank2sym = newHashTable ( 255 );
9155 coerce = newHashTable ( 255 );
9157 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9158 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9159 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9163 // assign symbols with absolute addresses to their respective bank nrs
9164 set = pic16_fix_udata;
9165 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9166 bankNr = reg->address >> 8;
9167 node = getOrAddGNode (adj, NULL, bankNr);
9168 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9169 assignToSameBank (node->hash, bankNr, 1);
9171 assert (bankNr >= 0);
9172 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9174 pbank = Safe_calloc (1, sizeof (pseudoBank));
9175 pbank->bank = reg->address >> 8; //FIXED_BANK;
9178 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9180 assert (pbank->bank == (reg->address >> 8));
9181 pbank->bank = reg->address >> 8; //FIXED_BANK;
9183 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9188 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9189 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9192 if (node->hash < 0) { node = node->next; continue; }
9193 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9196 if (node1->hash < 0) { node1 = node1->next; continue; }
9197 node1next = node1->next;
9198 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9199 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9200 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9201 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9202 if (assignToSameBank (node->hash, node1->hash, 0)) {
9203 fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9204 assert (0 && "Could not assign a symbol to a bank!");
9206 mergeGraphNodes (node, node1);
9208 if (node->hash < node1->hash)
9209 mergeGraphNodes (node, node1);
9211 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9221 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9222 // assign tightly coupled operands to the same (pseudo) bank
9223 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9231 curr0 = getEffectiveBank (node->hash);
9232 if (curr0 < 0) { node = node->next; continue; }
9235 assert (edge->src == node);
9236 backedge = getGEdge (edge->node, edge->src);
9237 weight = edge->weight + (backedge ? backedge->weight : 0);
9238 curr1 = getEffectiveBank (edge->node->hash);
9239 if (curr1 < 0) { edge = edge->next; continue; }
9241 // merging is only useful if the items are not assigned to the same bank already...
9242 if (curr0 != curr1 && weight > maxWeight) {
9243 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9252 if (maxWeight > 0) {
9254 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9255 max->src->hash, getSymFromBank (max->src->hash),
9256 max->node->hash, getSymFromBank (max->node->hash));
9259 node = getGNode (adj, max->src->data, max->src->hash);
9260 node1 = getGNode (adj, max->node->data, max->node->hash);
9262 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9263 if (max->src->hash < max->node->hash)
9264 mergeGraphNodes (node, node1);
9266 mergeGraphNodes (node1, node);
9268 remGEdge (node, node1);
9269 remGEdge (node1, node);
9280 // remove redundant BANKSELs
9281 //fprintf (stderr, "removing redundant BANKSELs\n");
9282 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9283 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9288 fprintf (stderr, "display graph\n");
9293 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9296 /*** END of stuff belonging to the BANKSEL optimization ***/
9300 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9302 typedef unsigned int symbol_t;
9303 typedef unsigned int valnum_t;
9304 //typedef unsigned int hash_t;
9307 #define INT_TO_PTR(x) (((char *) 0) + (x))
9311 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9314 static int pic16_regIsLocal (regs *r);
9315 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9318 static unsigned int pic16_df_removed_pcodes = 0;
9319 static unsigned int pic16_df_saved_bytes = 0;
9320 static unsigned int df_findall_sameflow = 0;
9321 static unsigned int df_findall_otherflow = 0;
9322 static unsigned int df_findall_in_vals = 0;
9324 static void pic16_df_stats () {
9326 if (pic16_debug_verbose || pic16_pcode_verbose) {
9327 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9328 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9329 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9333 /* Remove a pCode iff possible:
9334 * - previous pCode is no SKIP
9336 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9337 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9338 pCode *pcprev, *pcnext;
9339 char buf[256], *total=NULL;
9342 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9344 pcprev = pic16_findPrevInstruction (pc->prev);
9345 pcnext = pic16_findNextInstruction (pc->next);
9347 /* move labels to next instruction (if possible) */
9348 if (PCI(pc)->label && !pcnext) return 0;
9350 /* if this is a SKIP with side-effects -- do not remove */
9351 /* XXX: might try to replace this one with the side-effect only version */
9353 && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9356 switch (PCI(pc)->op)
9360 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9361 pic16_pCodeReplace( pc, newpc );
9365 newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9366 pic16_pCodeReplace( pc, newpc );
9371 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9372 pic16_pCodeReplace( pc, newpc );
9376 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9377 pic16_pCodeReplace( pc, newpc );
9386 /* if previous instruction is a skip -- do not remove */
9387 if (pcprev && isPCI_SKIP(pcprev)) {
9388 if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9389 /* preceeding SKIP could not be removed -- keep this instruction! */
9394 if (PCI(pc)->label) {
9395 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9396 //pc->print (stderr, pc);
9397 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9398 PCI(pc)->label = NULL;
9401 /* update statistics */
9402 pic16_df_removed_pcodes++;
9403 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9405 /* remove the pCode */
9406 pic16_pCode2str (buf, 256, pc);
9407 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9408 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9409 len = strlen (buf) + strlen (comment) + 10;
9410 total = (char *) Safe_malloc (len);
9411 SNPRINTF (total, len, "%s: %s", comment, buf);
9412 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9416 /* actually unlink it from the pBlock -- also remove from to/from lists */
9417 pic16_pCodeUnlink (pc);
9419 /* remove the pCode -- release registers */
9422 /* report success */
9427 /* ======================================================================== */
9428 /* === SYMBOL HANDLING ==================================================== */
9429 /* ======================================================================== */
9431 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9432 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9433 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9435 /** Calculate a hash for a given string.
9436 * If len == 0 the string is assumed to be NUL terminated. */
9437 static hash_t symbolHash (const char *str, unsigned int len) {
9441 hash = (hash << 2) ^ *str;
9446 hash = (hash << 2) ^ *str;
9453 /** Return 1 iff strings v1 and v2 are identical. */
9454 static int symcmp (const void *v1, const void *v2) {
9455 return !strcmp ((const char *) v1, (const char *) v2);
9458 /** Return 1 iff pointers v1 and v2 are identical. */
9459 static int ptrcmp (const void *v1, const void *v2) {
9463 enum { SPO_WREG=0x1000,
9503 /* Return the unique symbol_t for the given string. */
9504 static symbol_t symFromStr (const char *str) {
9509 if (!map_symToStr) {
9511 struct { char *name; symbol_t sym; } predefsyms[] = {
9513 {"STATUS", SPO_STATUS},
9514 {"PRODL", SPO_PRODL},
9515 {"PRODH", SPO_PRODH},
9516 {"INDF0", SPO_INDF0},
9517 {"POSTDEC0", SPO_POSTDEC0},
9518 {"POSTINC0", SPO_POSTINC0},
9519 {"PREINC0", SPO_PREINC0},
9520 {"PLUSW0", SPO_PLUSW0},
9521 {"INDF1", SPO_INDF1},
9522 {"POSTDEC1", SPO_POSTDEC1},
9523 {"POSTINC1", SPO_POSTINC1},
9524 {"PREINC1", SPO_PREINC1},
9525 {"PLUSW1", SPO_PLUSW1},
9526 {"INDF2", SPO_INDF2},
9527 {"POSTDEC2", SPO_POSTDEC2},
9528 {"POSTINC2", SPO_POSTINC2},
9529 {"PREINC2", SPO_PREINC2},
9530 {"PLUSW2", SPO_PLUSW2},
9531 {"STKPTR", SPO_STKPTR},
9536 {"FSR0L", SPO_FSR0L},
9537 {"FSR0H", SPO_FSR0H},
9538 {"FSR1L", SPO_FSR1L},
9539 {"FSR1H", SPO_FSR1H},
9540 {"FSR2L", SPO_FSR2L},
9541 {"FSR2H", SPO_FSR2H},
9543 {"PCLATH", SPO_PCLATH},
9544 {"PCLATU", SPO_PCLATU},
9545 {"TABLAT", SPO_TABLAT},
9546 {"TBLPTRL", SPO_TBLPTRL},
9547 {"TBLPTRH", SPO_TBLPTRH},
9548 {"TBLPTRU", SPO_TBLPTRU},
9552 map_strToSym = newHashTable (128);
9553 map_symToStr = newHashTable (128);
9555 for (i=0; predefsyms[i].name; i++) {
9558 /* enter new symbol */
9559 sym = predefsyms[i].sym;
9560 name = predefsyms[i].name;
9561 res = Safe_strdup (name);
9562 hash = symbolHash (name, 0);
9564 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9565 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9569 hash = symbolHash (str, 0) % map_strToSym->size;
9571 /* find symbol in table */
9572 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9574 //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9578 /* enter new symbol */
9580 res = Safe_strdup (str);
9582 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9583 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9585 //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9591 static const char *strFromSym (symbol_t sym) {
9592 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9596 /* ======================================================================== */
9597 /* === DEFINITION MAP HANDLING ============================================ */
9598 /* ======================================================================== */
9600 /* A defmap provides information about which symbol is defined by which pCode.
9601 * The most recent definitions are prepended to the list, so that the most
9602 * recent definition can be found by forward scanning the list.
9603 * pc2: MOVFF r0x00, r0x01
9605 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9607 * We attach one defmap to each flow object, and each pCode will occur at
9608 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9609 * used to find definitions for a pCode in its own defmap that precede pCode.
9612 typedef struct defmap_s {
9613 symbol_t sym; /** symbol this item refers to */
9616 unsigned int in_mask:8; /** mask leaving in accessed bits */
9617 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9618 int isRead:1; /** sym/mask is read */
9619 int isWrite:1; /** sym/mask is written */
9623 pCode *pc; /** pCode this symbol is refrenced at */
9624 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9625 valnum_t val; /** new unique number for this value (if isWrite) */
9626 struct defmap_s *prev, *next; /** link to previous an next definition */
9629 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9630 static int defmap_free_count = 0; /** number of released defmap items */
9632 /* Returns a defmap_t with the specified data; this will be the new list head.
9633 * next - pointer to the current list head */
9634 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9639 defmap_free = map->next;
9640 --defmap_free_count;
9642 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9645 map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9646 map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9647 map->acc.access.isRead = (isRead != 0);
9648 map->acc.access.isWrite = (isWrite != 0);
9651 map->val = (isWrite ? val : 0);
9654 if (next) next->prev = map;
9659 /* Returns a copy of the single defmap item. */
9660 static defmap_t *copyDefmap (defmap_t *map) {
9661 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9662 memcpy (res, map, sizeof (defmap_t));
9668 /* Insert a defmap item after the specified one. */
9669 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9670 if (!ref || !newItem) return 1;
9672 newItem->next = ref->next;
9673 newItem->prev = ref;
9674 ref->next = newItem;
9675 if (newItem->next) newItem->next->prev = newItem;
9680 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9681 * item is copied before insertion into chain and therefore left untouched.
9682 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9683 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9686 while (dummy && (dummy->sym != item->sym
9687 || dummy->pc != item->pc
9688 || dummy->acc.accessmethod != item->acc.accessmethod
9689 || dummy->val != item->val
9690 || dummy->in_val != item->in_val)) {
9691 dummy = dummy->next;
9694 /* item already present? */
9695 if (dummy) return 0;
9697 /* otherwise: insert copy of item */
9698 dummy = copyDefmap (item);
9699 dummy->next = *head;
9700 if (*head) (*head)->prev = dummy;
9706 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9707 static void deleteDefmap (defmap_t *map) {
9710 /* unlink from chain -- fails for the first item (head is not updated!) */
9711 if (map->next) map->next->prev = map->prev;
9712 if (map->prev) map->prev->next = map->next;
9715 memset (map, 0, sizeof (defmap_t));
9717 /* save for future use */
9718 map->next = defmap_free;
9720 ++defmap_free_count;
9723 /* Release all defmaps referenced from map. */
9724 static void deleteDefmapChain (defmap_t **_map) {
9725 defmap_t *map, *next;
9731 /* find list head */
9732 while (map && map->prev) map = map->prev;
9734 /* delete all items */
9744 /* Free all defmap items. */
9745 static void freeDefmap (defmap_t **_map) {
9753 /* find list head */
9754 while (map->prev) map = map->prev;
9756 /* release all items */
9766 /* Returns the most recent definition for the given symbol preceeding pc.
9767 * If no definition is found, NULL is returned.
9768 * If pc == NULL the whole list is scanned. */
9769 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9770 defmap_t *curr = map;
9773 /* skip all definitions up to pc */
9774 while (curr && (curr->pc != pc)) curr = curr->next;
9776 /* pc not in the list -- scan the whole list for definitions */
9778 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9781 /* skip all definitions performed by pc */
9782 while (curr && (curr->pc == pc)) curr = curr->next;
9786 /* find definition for sym */
9787 while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9795 /* Returns the first use (read) of the given symbol AFTER pc.
9796 * If no such use is found, NULL is returned.
9797 * If pc == NULL the whole list is scanned. */
9798 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9799 defmap_t *curr = map, *prev = NULL;
9802 /* skip all definitions up to pc */
9803 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9805 /* pc not in the list -- scan the whole list for definitions */
9807 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9811 /* find end of list */
9812 while (curr && curr->next) curr = curr->next;
9815 /* find use of sym (scan list backwards) */
9816 while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9822 /* Return the defmap entry for sym AT pc.
9823 * If none is found, NULL is returned.
9824 * If more than one entry is found an assertion is triggered. */
9825 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9826 defmap_t *res = NULL;
9828 /* find entries for pc */
9829 while (map && map->pc != pc) map = map->next;
9831 /* find first entry for sym @ pc */
9832 while (map && map->pc == pc && map->sym != sym) map = map->next;
9834 /* no entry found */
9835 if (!map) return NULL;
9837 /* check for more entries */
9840 while (map && map->pc == pc) {
9841 /* more than one entry for sym @ pc found? */
9842 assert (map->sym != sym);
9846 /* return single entry for sym @ pc */
9850 /* Modifies the definition of sym at pCode to newval.
9851 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9853 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9856 /* find definitions of pc */
9857 while (m && m->pc != pc) m = m->next;
9859 /* find definition of sym at pc */
9860 while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9862 /* no definition found */
9868 /* update following uses of sym */
9869 while (m && m->pc == pc) m = m->prev;
9871 if (m->sym == sym) {
9873 if (m->acc.access.isWrite) m = NULL;
9881 /* ======================================================================== */
9882 /* === STACK ROUTINES ===================================================== */
9883 /* ======================================================================== */
9885 typedef struct stack_s {
9887 struct stack_s *next;
9890 typedef stackitem_t *dynstack_t;
9891 static stackitem_t *free_stackitems = NULL;
9893 /* Create a stack with one item. */
9894 static dynstack_t *newStack () {
9895 dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9900 /* Remove a stack -- its items are only marked free. */
9901 static void deleteStack (dynstack_t *s) {
9907 i->next = free_stackitems;
9908 free_stackitems = i;
9913 /* Release all stackitems. */
9914 static void releaseStack () {
9917 while (free_stackitems) {
9918 i = free_stackitems->next;
9919 Safe_free(free_stackitems);
9920 free_stackitems = i;
9924 static void stackPush (dynstack_t *stack, void *data) {
9927 if (free_stackitems) {
9928 i = free_stackitems;
9929 free_stackitems = free_stackitems->next;
9931 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9938 static void *stackPop (dynstack_t *stack) {
9942 if (stack && *stack) {
9943 data = (*stack)->data;
9945 *stack = (*stack)->next;
9946 i->next = free_stackitems;
9947 free_stackitems = i;
9955 static int stackContains (dynstack_t *s, void *data) {
9960 if (i->data == data) return 1;
9969 static int stackIsEmpty (dynstack_t *s) {
9970 return (*s == NULL);
9979 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9980 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9982 s->lastdef = lastdef;
9986 static void deleteState (state_t *s) {
9990 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
9993 /* scan working list for state */
9997 /* is i == state? -- state not new */
9998 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10006 /* is i == state? -- state not new */
10007 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10012 /* not found -- state is new */
10016 static inline valnum_t newValnum ();
10018 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10021 if (!pb) return "<unknown function>";
10023 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10024 if (pc && isPCF(pc)) return PCF(pc)->fname;
10025 else return "<unknown function>";
10028 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10034 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10036 /* find initial value (assigning pc == NULL) */
10037 map = PCFL(pcfl)->in_vals;
10038 while (map && map->sym != sym) map = map->next;
10040 /* initial value already present? */
10042 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10046 /* create a new initial value */
10047 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10048 PCFL(pcfl)->in_vals = map;
10049 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10053 /* insert map as last item in pcfl's defmap */
10054 if (!prev) prev = PCFL(pcfl)->defmap;
10056 PCFL(pcfl)->defmap = map;
10058 while (prev->next) prev = prev->next;
10067 /* Find all reaching definitions for sym at pc.
10068 * A new (!) list of definitions is returned.
10069 * Returns the number of reaching definitions found.
10070 * The defining defmap entries are returned in *chain.
10072 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10077 pCodeFlowLink *succ;
10079 dynstack_t *todo; /** stack of state_t */
10080 dynstack_t *done; /** stack of state_t */
10082 int firstState, n_defs;
10084 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10087 /* initialize return list */
10090 /* wildcard symbol? */
10091 if (!sym) return 0;
10093 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10095 map = PCI(pc)->pcflow->defmap;
10097 res = defmapFindDef (map, sym, pc);
10098 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10100 #define USE_PRECALCED_INVALS 1
10101 #if USE_PRECALCED_INVALS
10102 if (!res && PCI(pc)->pcflow->in_vals) {
10103 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10105 //fprintf (stderr, "found def in init values\n");
10106 df_findall_in_vals++;
10112 // found a single definition (in pc's flow)
10113 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10114 defmapAddCopyIfNew (chain, res);
10115 df_findall_sameflow++;
10119 #if USE_PRECALCED_INVALS
10121 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10127 #define FORWARD_FLOW_ANALYSIS 1
10128 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10129 /* no definition found in pc's flow preceeding pc */
10130 todo = newStack ();
10131 done = newStack ();
10132 n_defs = 0; firstState = 1;
10133 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10135 while (!stackIsEmpty (todo)) {
10136 state = (state_t *) stackPop (todo);
10137 stackPush (done, state);
10138 curr = state->flow;
10139 res = state->lastdef;
10140 //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);
10142 /* there are no definitions BEFORE pc in pc's flow (see above) */
10143 if (curr == PCI(pc)->pcflow) {
10145 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10146 res = pic16_pBlockAddInval (pc->pb, sym);
10147 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10150 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10151 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10155 /* save last definition of sym in this flow as initial def in successors */
10156 res = defmapFindDef (curr->defmap, sym, NULL);
10157 if (!res) res = state->lastdef;
10159 /* add successors to working list */
10160 state = newState (NULL, NULL);
10161 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10163 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10164 state->flow = succ->pcflow;
10165 state->lastdef = res;
10166 if (stateIsNew (state, todo, done)) {
10167 stackPush (todo, state);
10168 state = newState (NULL, NULL);
10170 succ = (pCodeFlowLink *) setNextItem (curr->to);
10172 deleteState (state);
10175 #else // !FORWARD_FLOW_ANALYSIS
10177 /* no definition found in pc's flow preceeding pc */
10178 todo = newStack ();
10179 done = newStack ();
10180 n_defs = 0; firstState = 1;
10181 stackPush (todo, newState (PCI(pc)->pcflow, res));
10183 while (!stackIsEmpty (todo)) {
10184 state = (state_t *) stackPop (todo);
10185 curr = state->flow;
10189 /* only check predecessor flows */
10191 /* get (last) definition of sym in this flow */
10192 res = defmapFindDef (curr->defmap, sym, NULL);
10196 /* definition found */
10197 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10198 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10200 /* no definition found -- check predecessor flows */
10201 state = newState (NULL, NULL);
10202 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10204 /* if no flow predecessor available -- sym might be uninitialized */
10206 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10207 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10208 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10209 deleteDefmap (res); res = NULL;
10213 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10214 state->flow = succ->pcflow;
10215 state->lastdef = res;
10216 if (stateIsNew (state, todo, done)) {
10217 stackPush (todo, state);
10218 state = newState (NULL, NULL);
10220 succ = (pCodeFlowLink *) setNextItem (curr->from);
10222 deleteState (state);
10228 /* clean up done stack */
10229 while (!stackIsEmpty(done)) {
10230 deleteState ((state_t *) stackPop (done));
10232 deleteStack (done);
10234 /* return number of items in result set */
10236 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10237 } else if (n_defs == 1) {
10239 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10240 } else if (n_defs > 0) {
10241 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10245 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10250 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10251 df_findall_otherflow++;
10255 /* ======================================================================== */
10256 /* === VALUE NUMBER HANDLING ============================================== */
10257 /* ======================================================================== */
10259 static valnum_t nextValnum = 0x1000;
10260 static hTab *map_symToValnum = NULL;
10262 /** Return a new value number. */
10263 static inline valnum_t newValnum () {
10264 return (nextValnum += 4);
10267 static valnum_t valnumFromStr (const char *str) {
10272 sym = symFromStr (str);
10274 if (!map_symToValnum) {
10275 map_symToValnum = newHashTable (128);
10278 /* literal already known? */
10279 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10281 /* return existing valnum */
10282 if (res) return (valnum_t) PTR_TO_INT(res);
10284 /* create new valnum */
10286 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10287 //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10291 /* Create a valnum for a literal. */
10292 static valnum_t valnumFromLit (unsigned int lit) {
10293 return ((valnum_t) 0x100 + (lit & 0x0FF));
10296 /* Return the (positive) literal value represented by val
10297 * or -1 iff val is no known literal's valnum. */
10298 static int litFromValnum (valnum_t val) {
10299 if (val >= 0x100 && val < 0x200) {
10300 /* valnum is a (known) literal */
10301 return val & 0x00FF;
10303 /* valnum is not a known literal */
10309 /* Sanity check - all flows in a block must be reachable from initial flow. */
10310 static int verifyAllFlowsReachable (pBlock *pb) {
10316 pCodeFlowLink *succ;
10319 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10322 flowInBlock = NULL;
10324 /* mark initial flow as reached (and "not needs to be reached") */
10325 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10327 addSetHead (&reached, pc);
10328 addSetHead (&checked, pc);
10330 /* mark all further flows in block as "need to be reached" */
10333 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10334 pc = pic16_findNextInstruction (pc->next);
10337 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10338 /* mark as reached and "not need to be reached" */
10339 deleteSetItem (&reached, pcfl);
10340 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10342 /* flow is no longer considered unreachable */
10343 deleteSetItem (&flowInBlock, pcfl);
10345 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10346 if (!isinSet (checked, succ->pcflow)) {
10347 /* flow has never been reached before */
10348 addSetHead (&reached, succ->pcflow);
10349 addSetHead (&checked, succ->pcflow);
10354 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10356 /* by now every flow should have been reached
10357 * --> flowInBlock should be empty */
10358 res = (flowInBlock == NULL);
10362 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10363 while (flowInBlock) {
10364 pcfl = indexSet (flowInBlock, 0);
10365 fprintf (stderr, "not reached: flow %p\n", pcfl);
10366 deleteSetItem (&flowInBlock, pcfl);
10372 deleteSet (&reached);
10373 deleteSet (&flowInBlock);
10374 deleteSet (&checked);
10376 /* if we reached every flow, succ is NULL by now... */
10377 //assert (res); // will fire on unreachable code...
10382 /* Checks a flow for accesses to sym AFTER pc.
10384 * Returns -1 if the symbol is read in this flow (before redefinition),
10385 * returns 0 if the symbol is redefined in this flow or
10386 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10388 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10389 defmap_t *map, *mappc;
10391 /* find pc or start of definitions */
10392 map = pcfl->defmap;
10393 while (map && (map->pc != pc) && map->next) map = map->next;
10394 /* if we found pc -- ignore it */
10395 while (map && map->pc == pc) map = map->prev;
10397 /* scan list backwards (first definition first) */
10398 while (map && mask) {
10399 // if (map->sym == sym) {
10400 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10402 /* scan list for reads at this pc first */
10403 while (map && map->pc == mappc->pc) {
10404 /* is the symbol (partially) read? */
10405 if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10406 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10413 while (map && map->pc == mappc->pc) {
10414 /* honor (partial) redefinitions of sym */
10415 if ((map->sym == sym) && (map->acc.access.isWrite)) {
10416 mask &= ~map->acc.access.mask;
10417 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10422 /* map already points to the first defmap for the next pCode */
10423 //map = mappc->prev;
10426 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10427 * is still alive; return the appropriate mask of alive bits */
10431 /* Check whether a symbol is alive (AFTER pc). */
10432 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10435 dynstack_t *todo, *done;
10438 pCodeFlowLink *succ;
10442 assert (isPCI(pc));
10443 pcfl = PCI(pc)->pcflow;
10444 map = pcfl->defmap;
10446 todo = newStack ();
10447 done = newStack ();
10449 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10450 stackPush (todo, state);
10453 while (!stackIsEmpty (todo)) {
10454 state = (state_t *) stackPop (todo);
10455 pcfl = state->flow;
10456 mask = PTR_TO_INT(state->lastdef);
10457 if (visit) stackPush (done, state); else deleteState(state);
10458 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10459 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10460 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10463 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10464 if (mask == 0) continue;
10466 /* symbol is (partially) read before redefinition in flow */
10467 if (mask == -1) break;
10469 /* symbol is neither read nor completely redefined -- check successor flows */
10470 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10471 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10472 if (stateIsNew (state, todo, done)) {
10473 stackPush (todo, state);
10475 deleteState (state);
10480 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10481 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10483 /* symbol is read in at least one flow -- is alive */
10484 if (mask == -1) return 1;
10486 /* symbol is read in no flow */
10490 /* Returns whether access to the given symbol has side effects. */
10491 static int pic16_symIsSpecial (symbol_t sym) {
10492 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10512 /* no special effects known */
10519 /* Check whether a register should be considered local (to the current function) or not. */
10520 static int pic16_regIsLocal (regs *r) {
10523 if (r->type == REG_TMP) return 1;
10525 sym = symFromStr (r->name);
10528 case SPO_FSR0L: // used in ptrget/ptrput
10529 case SPO_FSR0H: // ... as well
10530 case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10531 case SPO_FSR1H: // ... as well
10532 case SPO_FSR2L: // used as frame pointer
10533 case SPO_FSR2H: // ... as well
10534 case SPO_PRODL: // used to return values from functions
10535 case SPO_PRODH: // ... as well
10536 /* these registers (and some more...) are considered local */
10540 /* for unknown regs: check is marked local, leave if not */
10544 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10550 /* if in doubt, assume non-local... */
10554 /* Check all symbols touched by pc whether their newly assigned values are read.
10555 * Returns 0 if no symbol is used later on, 1 otherwise. */
10556 static int pic16_pCodeIsAlive (pCode *pc) {
10557 pCodeInstruction *pci;
10558 defmap_t *map, *lastpc;
10561 /* we can only handle PCIs */
10562 if (!isPCI(pc)) return 1;
10564 //pc->print (stderr, pc);
10567 assert (pci && pci->pcflow && pci->pcflow->defmap);
10569 /* NEVER remove instructions with implicit side effects */
10572 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10573 case POC_TBLRD_POSTDEC:
10574 case POC_TBLRD_PREINC:
10575 case POC_TBLWT: /* modify program memory */
10576 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10577 case POC_TBLWT_POSTDEC:
10578 case POC_TBLWT_PREINC:
10579 case POC_CLRWDT: /* clear watchdog timer */
10580 case POC_PUSH: /* should be safe to remove though... */
10581 case POC_POP: /* should be safe to remove though... */
10586 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10590 /* no special instruction */
10594 /* prevent us from removing assignments to non-local variables */
10596 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10597 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10599 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10600 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10601 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10602 //pc->print (stderr, pc);
10605 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10606 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10611 /* OVERKILL: prevent us from removing reads from non-local variables
10612 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10613 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10615 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10616 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10618 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10619 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10620 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10621 //pc->print (stderr, pc);
10624 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10625 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10630 /* now check that the defined symbols are not used */
10631 map = pci->pcflow->defmap;
10633 /* find items for pc */
10634 while (map && map->pc != pc) map = map->next;
10636 /* no entries found? something is fishy with DF analysis... -- play safe */
10638 if (pic16_pcode_verbose) {
10639 fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10644 /* remember first item assigned to pc for later use */
10647 /* check all symbols being modified by pc */
10648 while (map && map->pc == pc) {
10649 if (map->sym == 0) { map = map->next; continue; }
10651 /* keep pc if it references special symbols (like POSTDEC0) */
10655 pic16_pCode2str (buf, 256, pc);
10656 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10659 if (pic16_symIsSpecial (map->sym)) {
10660 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10663 if (map->acc.access.isWrite) {
10664 if (pic16_isAlive (map->sym, pc)) {
10665 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10672 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10676 pic16_pCode2str (buf, 256, pc);
10677 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10683 /* Adds implied operands to the list.
10684 * sym - operand being accessed in the pCode
10685 * list - list to append the operand
10686 * isRead - set to 1 iff sym is read in pCode
10687 * listRead - set to 1 iff all operands being read are to be listed
10689 * Returns 0 for "normal" operands, 1 for special operands.
10691 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10692 /* check whether accessing REG accesses other REGs as well */
10696 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10697 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10698 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10702 /* reads FSR0x and WREG */
10703 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10704 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10705 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10706 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10712 /* reads/modifies FSR0x */
10713 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10714 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10715 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10720 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10721 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10722 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10726 /* reads FSR1x and WREG */
10727 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10728 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10729 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10730 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10736 /* reads/modifies FSR1x */
10737 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10738 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10739 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10744 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10745 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10746 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10750 /* reads FSR2x and WREG */
10751 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10752 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10753 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10754 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10760 /* reads/modifies FSR2x */
10761 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10762 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10763 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10767 /* modifies PCLATH and PCLATU */
10768 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10770 /* reading PCL updates PCLATx */
10771 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10772 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10775 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10776 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10777 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10782 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10783 /* nothing special */
10788 /* has been a special operand */
10792 static symbol_t pic16_fsrsym_idx[][2] = {
10793 {SPO_FSR0L, SPO_FSR0H},
10794 {SPO_FSR1L, SPO_FSR1H},
10795 {SPO_FSR2L, SPO_FSR2H}
10798 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10799 static void mergeDefmapSymbols (defmap_t *list) {
10800 defmap_t *ref, *curr, *temp;
10802 /* now make sure that each symbol occurs at most once per pc */
10804 while (ref && (ref->pc == list->pc)) {
10806 while (curr && (curr->pc == list->pc)) {
10807 if (curr->sym == ref->sym) {
10808 //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10809 /* found a symbol occuring twice... merge the two */
10810 if (curr->acc.access.isRead) {
10811 //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10812 ref->acc.access.isRead = 1;
10813 ref->acc.access.in_mask |= curr->acc.access.in_mask;
10815 if (curr->acc.access.isWrite) {
10816 //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10817 ref->acc.access.isWrite = 1;
10818 ref->acc.access.mask |= curr->acc.access.mask;
10822 deleteDefmap (temp);
10823 continue; // do not skip curr!
10831 /** Prepend list with the reads and definitions performed by pc. */
10832 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10833 pCodeInstruction *pci;
10834 int cond, inCond, outCond;
10835 int mask = 0xff, smask;
10836 int isSpecial, isSpecial2;
10837 symbol_t sym, sym2;
10841 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10842 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10843 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10844 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10847 assert (isPCI(pc));
10850 /* handle bit instructions */
10851 if (pci->isBitInst) {
10852 assert (pci->pcop->type == PO_GPR_BIT);
10853 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10856 /* handle (additional) implicit arguments */
10862 lit = PCOL(pci->pcop)->lit;
10863 assert (lit >= 0 && lit < 3);
10864 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10865 val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10866 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10867 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10868 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...
10872 case POC_MOVLB: // BSR
10873 case POC_BANKSEL: // BSR
10874 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10877 case POC_MULWF: // PRODx
10878 case POC_MULLW: // PRODx
10879 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10880 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10883 case POC_POP: // TOS, STKPTR
10884 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10885 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10886 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10887 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10890 case POC_PUSH: // STKPTR
10891 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10892 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10893 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10894 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10897 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10898 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10899 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10900 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10901 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10902 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10904 /* needs correctly set-up stack pointer */
10905 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10906 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10909 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10910 /* pseudo read on (possible) return values */
10911 // WREG is handled below via outCond
10912 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10913 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10914 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10916 /* caller's stack pointers must be restored */
10917 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10918 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10919 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10920 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10923 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10924 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10925 /* pseudo read on (possible) return values */
10926 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10927 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10928 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10929 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10931 /* caller's stack pointers must be restored */
10932 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10933 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10934 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10935 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10939 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10940 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10941 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10942 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10945 case POC_TBLRD_POSTINC:
10946 case POC_TBLRD_POSTDEC:
10947 case POC_TBLRD_PREINC:
10948 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10949 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10950 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10951 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10955 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10956 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10957 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10958 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10961 case POC_TBLWT_POSTINC:
10962 case POC_TBLWT_POSTDEC:
10963 case POC_TBLWT_PREINC:
10964 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10965 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10966 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10967 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10971 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10975 /* handle explicit arguments */
10976 inCond = pci->inCond;
10977 outCond = pci->outCond;
10978 cond = inCond | outCond;
10979 if (cond & PCC_W) {
10980 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10983 /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
10984 if (inCond & PCC_STATUS) {
10986 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10987 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10988 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10989 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10990 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10992 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10993 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10996 if (outCond & PCC_STATUS) {
10998 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10999 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11000 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11001 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11002 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11004 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11005 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11008 isSpecial = isSpecial2 = 0;
11010 if (cond & PCC_REGISTER) {
11011 name = pic16_get_op (pci->pcop, NULL, 0);
11012 sym = symFromStr (name);
11013 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11014 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11017 if (cond & PCC_REGISTER2) {
11018 name = pic16_get_op2 (pci->pcop, NULL, 0);
11019 sym2 = symFromStr (name);
11020 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11021 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11025 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11026 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11028 mergeDefmapSymbols (list);
11034 static void printDefmap (defmap_t *map) {
11038 fprintf (stderr, "defmap @ %p:\n", curr);
11040 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11041 curr->acc.access.isRead ? "R" : " ",
11042 curr->acc.access.isWrite ? "W": " ",
11043 curr->in_val, curr->val,
11044 curr->acc.access.in_mask, curr->acc.access.mask,
11045 strFromSym(curr->sym), curr->sym,
11049 fprintf (stderr, "<EOL>\n");
11053 /* Add "additional" definitions to uniq.
11054 * 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.
11055 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11057 * If symbols defined in additional are not present in uniq, a definition is created.
11058 * Otherwise the present definition is altered to reflect the newer assignments.
11060 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11061 * before `------- noted in additional --------' after
11063 * I assume that each symbol occurs AT MOST ONCE in uniq.
11066 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11071 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11072 /* find tail of additional list (holds the first assignment) */
11074 while (curr && curr->next) curr = curr->next;
11078 /* find next assignment in additionals */
11079 while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11083 /* find item in uniq */
11085 //printDefmap (*uniq);
11086 while (old && (old->sym != curr->sym)) old = old->next;
11089 /* definition found -- replace */
11090 if (old->val != curr->val) {
11091 old->val = curr->val;
11095 /* new definition */
11096 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11103 /* return 0 iff uniq remained unchanged */
11107 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11108 * lists of its predecessor flows.
11109 * Initially *combined should be NULL, alt_in will be copied to combined.
11110 * If *combined != NULL, combined will be altered:
11111 * - for symbols defined in *combined but not in alt_in,
11112 * *combined is altered to 0 (value unknown, either *combined or INIT).
11113 * - for symbols defined in alt_in but not in *combined,
11114 * a 0 definition is created (value unknown, either INIT or alt).
11115 * - for symbols defined in both, *combined is:
11116 * > left unchanged if *combined->val == alt_in->val or
11117 * > modified to 0 otherwise (value unknown, either alt or *combined).
11119 * I assume that each symbol occurs AT MOST ONCE in each list!
11121 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11127 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11129 if (!(*combined)) {
11130 return defmapUpdateUniqueSym (combined, alt_in);
11133 /* merge the two */
11136 /* find symbols definition in *combined */
11138 while (old && (old->sym != curr->sym)) old = old->next;
11141 /* definition found */
11142 if (old->val && (old->val != curr->val)) {
11143 old->val = 0; /* value unknown */
11147 /* no definition found -- can be either INIT or alt_in's value */
11148 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11149 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11150 if (val != curr->val) change++;
11156 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11159 if (old->val != 0) {
11160 /* find definition in alt_in */
11162 while (curr && curr->sym != old->sym) curr = curr->next;
11164 /* symbol defined in *combined only -- can be either INIT or *combined */
11165 val = pic16_pBlockAddInval (pb, old->sym)->val;
11166 if (old->val != val) {
11179 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11180 defmap_t *curr1, *curr2;
11183 /* identical maps are equal */
11184 if (map1 == map2) return 0;
11186 if (!map1) return -1;
11187 if (!map2) return 1;
11189 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11194 while (curr1 && curr2) {
11195 curr1 = curr1->next;
11196 curr2 = curr2->next;
11199 /* one of them longer? */
11200 if (curr1) return 1;
11201 if (curr2) return -1;
11203 /* both lists are of equal length -- compare (in O(n^2)) */
11208 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11209 if (!curr2) return 1; // symbol not found in curr2
11210 if (curr2->val != curr1->val) return 1; // values differ
11212 /* compare next symbol */
11213 curr1 = curr1->next;
11216 /* no difference found */
11221 /* Prepare a list of all reaching definitions per flow.
11222 * This is done using a forward dataflow analysis.
11224 static void createReachingDefinitions (pBlock *pb) {
11225 defmap_t *out_vals, *in_vals;
11228 pCodeFlowLink *link;
11234 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11235 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11237 deleteDefmapChain (&PCFL(pc)->in_vals);
11238 deleteDefmapChain (&PCFL(pc)->out_vals);
11239 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11243 pc = pic16_findNextInstruction (pb->pcHead);
11244 todo = NULL; blacklist = NULL;
11245 addSetHead (&todo, PCI(pc)->pcflow);
11247 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11248 while (elementsInSet (todo)) {
11249 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11250 pcfl = PCFL(indexSet (todo, 0));
11251 deleteSetItem (&todo, pcfl);
11252 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11256 if (isinSet (blacklist, pcfl)) {
11257 fprintf (stderr, "ignoring blacklisted flow\n");
11261 /* create in_vals from predecessors out_vals */
11262 link = setFirstItem (pcfl->from);
11264 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11265 link = setNextItem (pcfl->from);
11268 //printDefmap (in_vals);
11269 //printDefmap (pcfl->in_vals);
11271 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11272 //fprintf (stderr, "in_vals changed\n");
11273 /* in_vals changed -- update out_vals */
11274 deleteDefmapChain (&pcfl->in_vals);
11275 pcfl->in_vals = in_vals;
11277 /* create out_val from in_val and defmap */
11279 defmapUpdateUniqueSym (&out_vals, in_vals);
11280 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11282 /* is out_vals different from pcfl->out_vals */
11283 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11284 //fprintf (stderr, "out_vals changed\n");
11285 deleteDefmapChain (&pcfl->out_vals);
11286 pcfl->out_vals = out_vals;
11288 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11289 addSet (&blacklist, pcfl);
11292 /* reschedule all successors */
11293 link = setFirstItem (pcfl->to);
11295 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11296 addSetIfnotP (&todo, link->pcflow);
11297 link = setNextItem (pcfl->to);
11300 deleteDefmapChain (&out_vals);
11303 deleteDefmapChain (&in_vals);
11309 static void showAllDefs (symbol_t sym, pCode *pc) {
11313 assert (isPCI(pc));
11314 count = defmapFindAll (sym, pc, &map);
11316 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11319 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11322 pic16_pCode2str (buf, 256, map->pc);
11323 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11327 deleteDefmapChain (&map);
11331 /* safepCodeUnlink and remove pc from defmap. */
11332 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11333 defmap_t *map, *next, **head;
11337 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11338 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11339 res = pic16_safepCodeUnlink (pc, comment);
11342 /* remove pc from defmap */
11345 if (map->pc == pc) {
11346 if (!map->prev && head) *head = map->next;
11347 deleteDefmap (map);
11356 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11358 /* This breaks the defmap chain's references to pCodes... fix it! */
11359 map = PCI(pc)->pcflow->defmap;
11361 while (map && map->pc != pc) map = map->next;
11363 while (map && map->pc == pc) {
11369 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11370 * write accesses (isRead == 0). */
11371 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11372 defmap_t *map, *map_start;
11374 if (!isPCI(pc)) return;
11375 if (sym == newsym) return;
11377 map = PCI(pc)->pcflow->defmap;
11379 while (map && map->pc != pc) map = map->next;
11381 while (map && map->pc == pc) {
11382 if (map->sym == sym) {
11383 assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11384 if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11385 /* only one kind of access handled... this is easy */
11388 /* must copy defmap entry before replacing symbol... */
11389 copy = copyDefmap (map);
11391 map->acc.access.isRead = 0;
11392 copy->acc.access.isWrite = 0;
11394 map->acc.access.isWrite = 0;
11395 copy->acc.access.isRead = 0;
11397 copy->sym = newsym;
11398 /* insert copy into defmap chain */
11399 defmapInsertAfter (map, copy);
11405 /* as this might introduce multiple defmap entries for newsym... */
11406 mergeDefmapSymbols (map_start);
11409 /* Assign "better" valnums to results. */
11410 static void assignValnums (pCode *pc) {
11411 pCodeInstruction *pci;
11413 symbol_t sym1, sym2;
11414 int cond, isSpecial1, isSpecial2, count, mask, lit;
11415 defmap_t *list, *val, *oldval, *dummy;
11416 regs *reg1 = NULL, *reg2 = NULL;
11419 /* only works for pCodeInstructions... */
11420 if (!isPCI(pc)) return;
11423 cond = pci->inCond | pci->outCond;
11424 list = pci->pcflow->defmap;
11425 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11427 if (cond & PCC_REGISTER) {
11428 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11429 reg1 = pic16_getRegFromInstruction (pc);
11430 isSpecial1 = pic16_symIsSpecial (sym1);
11432 if (cond & PCC_REGISTER2) {
11433 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11434 reg2 = pic16_getRegFromInstruction (pc);
11435 isSpecial2 = pic16_symIsSpecial (sym2);
11438 /* determine input values */
11440 while (val && val->pc != pc) val = val->next;
11441 //list = val; /* might save some time later... */
11442 while (val && val->pc == pc) {
11444 if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11445 /* get valnum for sym */
11446 count = defmapFindAll (val->sym, pc, &oldval);
11447 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11449 if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11450 val->in_val = oldval->val;
11454 } else if (count == 0) {
11455 /* no definition found */
11458 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11460 dummy = oldval->next;
11461 mask = oldval->acc.access.mask;
11462 val->in_val = oldval->val;
11463 while (dummy && (dummy->val == val->in_val)) {
11464 mask &= dummy->acc.access.mask;
11465 dummy = dummy->next;
11468 /* found other values or to restictive mask */
11469 if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11473 if (count > 0) deleteDefmapChain (&oldval);
11478 /* handle valnum assignment */
11480 case POC_CLRF: /* modifies STATUS (Z) */
11481 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11482 oldval = defmapCurr (list, sym1, pc);
11483 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11484 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11485 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11487 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11491 case POC_SETF: /* SETF does not touch STATUS */
11492 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11493 oldval = defmapCurr (list, sym1, pc);
11494 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11495 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11496 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11498 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11502 case POC_MOVLW: /* does not touch STATUS */
11503 oldval = defmapCurr (list, SPO_WREG, pc);
11504 if (pci->pcop->type == PO_LITERAL) {
11505 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11506 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11508 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11509 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11511 if (oldval && oldval->in_val == litnum) {
11512 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11513 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11515 defmapUpdate (list, SPO_WREG, pc, litnum);
11518 case POC_ANDLW: /* modifies STATUS (Z,N) */
11519 case POC_IORLW: /* modifies STATUS (Z,N) */
11520 case POC_XORLW: /* modifies STATUS (Z,N) */
11521 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11522 if (pci->pcop->type == PO_LITERAL) {
11524 lit = (unsigned char) PCOL(pci->pcop)->lit;
11525 val = defmapCurr (list, SPO_WREG, pc);
11526 if (val) vallit = litFromValnum (val->in_val);
11527 if (vallit != -1) {
11528 /* xxxLW <literal>, WREG contains a known literal */
11529 //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11530 if (pci->op == POC_ANDLW) {
11532 } else if (pci->op == POC_IORLW) {
11534 } else if (pci->op == POC_XORLW) {
11537 assert (0 && "invalid operation");
11539 if (vallit == lit) {
11540 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11541 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11543 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11550 /* check if old value matches new value */
11553 assert (pci->pcop->type == PO_LITERAL);
11555 lit = PCOL(pci->pcop)->lit;
11557 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11559 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11560 //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11562 /* cannot remove this LFSR */
11566 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11567 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11568 //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11574 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11579 case POC_MOVWF: /* does not touch flags */
11580 /* find value of WREG */
11581 val = defmapCurr (list, SPO_WREG, pc);
11582 oldval = defmapCurr (list, sym1, pc);
11583 if (val) lit = litFromValnum (val->in_val);
11585 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11587 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11588 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11589 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11591 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11593 assert (lit == 0x0ff);
11594 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11596 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11597 pic16_pCodeReplace (pc, newpc);
11598 defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11599 pic16_fixDefmap (pc, newpc);
11602 /* This breaks the defmap chain's references to pCodes... fix it! */
11603 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11604 if (!val->acc.access.isWrite) {
11605 deleteDefmap (val); // delete reference to WREG as in value
11608 val->acc.access.isRead = 0; // delete reference to WREG as in value
11610 oldval = PCI(pc)->pcflow->defmap;
11612 if (oldval->pc == pc) oldval->pc = newpc;
11613 oldval = oldval->next;
11615 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11616 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11617 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11619 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11622 case POC_MOVFW: /* modifies STATUS (Z,N) */
11623 /* find value of REG */
11624 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11625 val = defmapCurr (list, sym1, pc);
11626 oldval = defmapCurr (list, SPO_WREG, pc);
11627 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11628 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11629 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11631 defmap_t *pred, *predpred;
11632 /* Optimize MOVLW immd; MOVWF reg1; [...]; MOVFW reg1
11633 * into MOVLW immd; MOVWF reg1; [...]; MOVLW immd
11634 * This might allow removal of the first two assignments. */
11635 pred = defmapFindDef (list, sym1, pc);
11636 predpred = pred ? defmapFindDef (list, SPO_WREG, pred->pc) : NULL;
11637 if (pred && predpred && (PCI(pred->pc)->op == POC_MOVWF) && (PCI(predpred->pc)->op == POC_MOVLW)
11638 && !pic16_isAlive (SPO_STATUS, pc))
11640 newpc = pic16_newpCode (POC_MOVLW, pic16_pCodeOpCopy (PCI(predpred->pc)->pcop));
11642 if (pic16_debug_verbose || pic16_pcode_verbose) {
11643 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFW: replaced last of MOVLW;MOVWF;MOVFW by MOVLW");
11645 pic16_pCodeReplace (pc, newpc);
11646 defmapReplaceSymRef (pc, sym1, 0, 1);
11647 pic16_fixDefmap (pc, newpc);
11650 /* This breaks the defmap chain's references to pCodes... fix it! */
11651 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11652 if (!val->acc.access.isWrite) {
11653 deleteDefmap (val); // delete reference to reg1 as in value
11656 val->acc.access.isRead = 0; // delete reference to reg1 as in value
11658 oldval = PCI(pc)->pcflow->defmap;
11660 if (oldval->pc == pc) oldval->pc = newpc;
11661 oldval = oldval->next;
11665 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11669 case POC_MOVFF: /* does not touch STATUS */
11670 /* find value of REG */
11671 val = defmapCurr (list, sym1, pc);
11672 oldval = defmapCurr (list, sym2, pc);
11673 if (val) lit = litFromValnum (val->in_val);
11676 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11677 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11679 newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11680 } else if (lit == 0x00ff) {
11681 newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11686 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11687 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11688 pic16_pCodeReplace (pc, newpc);
11689 defmapReplaceSymRef (pc, sym1, 0, 1);
11690 pic16_fixDefmap (pc, newpc);
11692 break; // do not process instruction as MOVFF...
11694 } else if (!isSpecial1 && !isSpecial2
11695 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11696 && val && oldval && (val->in_val != 0)) {
11697 if (val->in_val == oldval->in_val) {
11698 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11699 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11701 if (!pic16_isAlive (sym1, pc)) {
11702 defmap_t *copy = NULL;
11703 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11704 * This should help eliminate
11706 * <do something not changing A or using B>
11708 * <B is not alive anymore>
11710 * <do something not changing A or using B>
11714 /* scan defmap for symbols storing sym1's value */
11715 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11716 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11717 /* unique reaching definition for sym found */
11718 if (copy->val && copy->val == val->in_val) {
11719 //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);
11720 if (copy->sym == SPO_WREG) {
11721 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11723 pCodeOp *pcop = NULL;
11724 /* the code below fails if we try to replace
11725 * MOVFF PRODL, r0x03
11726 * MOVFF r0x03, PCLATU
11728 * MOVFF PRODL, PCLATU
11729 * as copy(PRODL) contains has pc==NULL, by name fails...
11731 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11733 if (copy->pc && PCI(copy->pc)->pcop)
11734 pcop = PCI(copy->pc)->pcop;
11736 /* This code is broken--see above. */
11739 const char *symname = strFromSym(copy->sym);
11742 pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11743 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11744 //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11748 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11750 pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11752 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11753 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11754 pic16_pCodeReplace (pc, newpc);
11755 assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11756 defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11757 pic16_fixDefmap (pc, newpc);
11761 deleteDefmapChain (©);
11764 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11769 /* cannot optimize */
11774 static void pic16_destructDF (pBlock *pb) {
11779 /* remove old defmaps */
11780 pc = pic16_findNextInstruction (pb->pcHead);
11782 next = pic16_findNextInstruction (pc->next);
11784 assert (isPCI(pc) || isPCAD(pc));
11785 assert (PCI(pc)->pcflow);
11786 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11787 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11788 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11793 if (defmap_free || defmap_free_count) {
11794 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11795 freeDefmap (&defmap_free);
11796 defmap_free_count = 0;
11800 /* Checks whether a pBlock contains ASMDIRs. */
11801 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11806 pc = pic16_findNextInstruction (pb->pcHead);
11808 if (isPCAD(pc)) return 1;
11810 pc = pic16_findNextInstruction (pc->next);
11813 /* no PCADs found */
11818 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11819 static int pic16_removeUnusedRegistersDF () {
11822 regs *reg1, *reg2, *reg3;
11823 set *seenRegs = NULL;
11825 int islocal, change = 0;
11828 if (!the_pFile || !the_pFile->pbHead) return 0;
11830 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11831 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11833 /* find set of using pCodes per register */
11834 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11835 pc = pic16_findNextInstruction(pc->next)) {
11837 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11838 reg1 = reg2 = NULL;
11839 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11840 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11843 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11844 addSetIfnotP (&seenRegs, reg1);
11845 addSetIfnotP (®1->reglives.usedpCodes, pc);
11848 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11849 addSetIfnotP (&seenRegs, reg2);
11850 addSetIfnotP (®2->reglives.usedpCodes, pc);
11854 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11855 /* may not use pic16_regIsLocal() here -- in interrupt routines
11856 * WREG, PRODx, FSR0x must be saved */
11857 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11858 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11860 for (i=0; i < 2; i++) {
11861 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11862 if (!pc2) pc2 = pc;
11863 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11864 reg2 = pic16_getRegFromInstruction (pc);
11865 reg3 = pic16_getRegFromInstruction2 (pc);
11867 || (reg2->rIdx != pic16_stack_preinc->rIdx
11868 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11870 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11871 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11872 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11873 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11877 deleteSet (®1->reglives.usedpCodes);
11880 deleteSet (&seenRegs);
11887 /* Set up pCodeFlow's defmap_ts.
11888 * Needs correctly set up to/from fields. */
11889 static void pic16_createDF (pBlock *pb) {
11895 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11897 pic16_destructDF (pb);
11899 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11900 if (pic16_pBlockHasAsmdirs (pb)) {
11901 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11905 /* integrity check -- we need to reach all flows to guarantee
11906 * correct data flow analysis (reaching definitions, aliveness) */
11908 if (!verifyAllFlowsReachable (pb)) {
11909 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11914 /* establish new defmaps */
11915 pc = pic16_findNextInstruction (pb->pcHead);
11917 next = pic16_findNextInstruction (pc->next);
11919 assert (PCI(pc)->pcflow);
11920 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11925 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11926 createReachingDefinitions (pb);
11929 /* assign better valnums */
11930 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11931 pc = pic16_findNextInstruction (pb->pcHead);
11933 next = pic16_findNextInstruction (pc->next);
11935 assert (PCI(pc)->pcflow);
11936 assignValnums (pc);
11943 /* remove dead pCodes */
11944 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11947 pc = pic16_findNextInstruction (pb->pcHead);
11949 next = pic16_findNextInstruction (pc->next);
11951 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11952 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11961 /* ======================================================================== */
11962 /* === VCG DUMPER ROUTINES ================================================ */
11963 /* ======================================================================== */
11964 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11965 hTab *dumpedNodes = NULL;
11967 /** Dump VCG header into of. */
11968 static void pic16_vcg_init (FILE *of) {
11969 /* graph defaults */
11970 fprintf (of, "graph:{\n");
11971 fprintf (of, "title:\"graph1\"\n");
11972 fprintf (of, "label:\"graph1\"\n");
11973 fprintf (of, "color:white\n");
11974 fprintf (of, "textcolor:black\n");
11975 fprintf (of, "bordercolor:black\n");
11976 fprintf (of, "borderwidth:1\n");
11977 fprintf (of, "textmode:center\n");
11979 fprintf (of, "layoutalgorithm:dfs\n");
11980 fprintf (of, "late_edge_labels:yes\n");
11981 fprintf (of, "display_edge_labels:yes\n");
11982 fprintf (of, "dirty_edge_labels:yes\n");
11983 fprintf (of, "finetuning:yes\n");
11984 fprintf (of, "ignoresingles:no\n");
11985 fprintf (of, "straight_phase:yes\n");
11986 fprintf (of, "priority_phase:yes\n");
11987 fprintf (of, "manhattan_edges:yes\n");
11988 fprintf (of, "smanhattan_edges:no\n");
11989 fprintf (of, "nearedges:no\n");
11990 fprintf (of, "node_alignment:center\n"); // bottom|top|center
11991 fprintf (of, "port_sharing:no\n");
11992 fprintf (of, "arrowmode:free\n"); // fixed|free
11993 fprintf (of, "crossingphase2:yes\n");
11994 fprintf (of, "crossingoptimization:yes\n");
11995 fprintf (of, "edges:yes\n");
11996 fprintf (of, "nodes:yes\n");
11997 fprintf (of, "splines:no\n");
11999 /* node defaults */
12000 fprintf (of, "node.color:lightyellow\n");
12001 fprintf (of, "node.textcolor:black\n");
12002 fprintf (of, "node.textmode:center\n");
12003 fprintf (of, "node.shape:box\n");
12004 fprintf (of, "node.bordercolor:black\n");
12005 fprintf (of, "node.borderwidth:1\n");
12007 /* edge defaults */
12008 fprintf (of, "edge.textcolor:black\n");
12009 fprintf (of, "edge.color:black\n");
12010 fprintf (of, "edge.thickness:1\n");
12011 fprintf (of, "edge.arrowcolor:black\n");
12012 fprintf (of, "edge.backarrowcolor:black\n");
12013 fprintf (of, "edge.arrowsize:15\n");
12014 fprintf (of, "edge.backarrowsize:15\n");
12015 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12016 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12017 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12019 fprintf (of, "\n");
12021 /* prepare data structures */
12023 hTabDeleteAll (dumpedNodes);
12024 dumpedNodes = NULL;
12026 dumpedNodes = newHashTable (128);
12029 /** Dump VCG footer into of. */
12030 static void pic16_vcg_close (FILE *of) {
12031 fprintf (of, "}\n");
12034 #define BUF_SIZE 128
12035 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12038 static int ptrcmp (const void *p1, const void *p2) {
12043 /** Dump a pCode node as VCG to of. */
12044 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12045 char buf[BUF_SIZE];
12047 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12051 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12052 //fprintf (stderr, "dumping %p\n", pc);
12054 /* only dump pCodeInstructions and Flow nodes */
12055 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12058 fprintf (of, "node:{");
12059 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12060 fprintf (of, "label:\"%s\n", pcTitle(pc));
12062 fprintf (of, "<PCFLOW>");
12063 } else if (isPCI(pc) || isPCAD(pc)) {
12064 pc->print (of, pc);
12066 fprintf (of, "<!PCI>");
12068 fprintf (of, "\" ");
12069 fprintf (of, "}\n");
12071 if (1 && isPCFL(pc)) {
12072 defmap_t *map, *prev;
12074 map = PCFL(pc)->defmap;
12077 if (map->sym != 0) {
12080 /* emit definition node */
12081 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12082 fprintf (of, "label:\"");
12086 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));
12089 } while (map && prev->pc == map->pc);
12092 fprintf (of, "\" ");
12094 fprintf (of, "color:green ");
12095 fprintf (of, "}\n");
12097 /* emit edge to previous definition */
12098 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12100 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12102 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12104 fprintf (of, "color:green ");
12105 fprintf (of, "}\n");
12108 pic16_vcg_dumpnode (map->pc, of);
12109 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12110 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12117 /* emit additional nodes (e.g. operands) */
12120 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12121 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12122 char buf[BUF_SIZE];
12123 pCodeInstruction *pci;
12127 if (1 && isPCFL(pc)) {
12128 /* emit edges to flow successors */
12130 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12131 pcfl = setFirstItem (PCFL(pc)->to);
12133 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12134 pic16_vcg_dumpnode (pc, of);
12135 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12136 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12137 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12138 pcfl = setNextItem (PCFL(pc)->to);
12142 if (!isPCI(pc) && !isPCAD(pc)) return;
12146 /* emit control flow edges (forward only) */
12150 pic16_vcg_dumpnode (curr->pc, of);
12151 fprintf (of, "edge:{");
12152 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12153 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12154 fprintf (of, "color:red ");
12155 fprintf (of, "}\n");
12160 /* dump "flow" edge (link pCode according to pBlock order) */
12163 pcnext = pic16_findNextInstruction (pc->next);
12165 pic16_vcg_dumpnode (pcnext, of);
12166 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12167 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12175 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12176 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12177 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12181 /* emit data flow edges (backward only) */
12182 /* TODO: gather data flow information... */
12185 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12190 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12191 if (pic16_pBlockHasAsmdirs (pb)) {
12192 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12196 for (pc=pb->pcHead; pc; pc = pc->next) {
12197 pic16_vcg_dumpnode (pc, of);
12200 for (pc=pb->pcHead; pc; pc = pc->next) {
12201 pic16_vcg_dumpedges (pc, of);
12205 static void pic16_vcg_dump_default (pBlock *pb) {
12207 char buf[BUF_SIZE];
12212 /* get function name */
12214 while (pc && !isPCF(pc)) pc = pc->next;
12216 SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12218 SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12221 //fprintf (stderr, "now dumping %s\n", buf);
12222 of = fopen (buf, "w");
12223 pic16_vcg_init (of);
12224 pic16_vcg_dump (of, pb);
12225 pic16_vcg_close (of);
12230 /*** END of helpers for pCode dataflow optimizations ***/