1 /*-------------------------------------------------------------------------
3 pcode.c - post code generation
5 Written By - Scott Dattalo scott@dattalo.com
6 Ported to PIC16 By - Martin Dubuc m.dubuc@rogers.com
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 -------------------------------------------------------------------------*/
25 #include "common.h" // Include everything in the SDCC src directory
31 #include "pcodeflow.h"
35 extern char *pic16_aopGet (struct asmop *aop, int offset, bool bit16, bool dname);
37 #if defined(__BORLANDC__) || defined(_MSC_VER)
41 #define DUMP_DF_GRAPHS 0
43 /****************************************************************/
44 /****************************************************************/
46 static peepCommand peepCommands[] = {
48 {NOTBITSKIP, "_NOTBITSKIP_"},
49 {BITSKIP, "_BITSKIP_"},
50 {INVERTBITSKIP, "_INVERTBITSKIP_"},
57 // Eventually this will go into device dependent files:
58 pCodeOpReg pic16_pc_status = {{PO_STATUS, "STATUS"}, -1, NULL,0,NULL};
59 pCodeOpReg pic16_pc_intcon = {{PO_INTCON, "INTCON"}, -1, NULL,0,NULL};
60 pCodeOpReg pic16_pc_pcl = {{PO_PCL, "PCL"}, -1, NULL,0,NULL};
61 pCodeOpReg pic16_pc_pclath = {{PO_PCLATH, "PCLATH"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_pclatu = {{PO_PCLATU, "PCLATU"}, -1, NULL,0,NULL}; // patch 14
63 pCodeOpReg pic16_pc_wreg = {{PO_WREG, "WREG"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_bsr = {{PO_BSR, "BSR"}, -1, NULL,0,NULL};
66 pCodeOpReg pic16_pc_tosl = {{PO_SFR_REGISTER, "TOSL"}, -1, NULL,0,NULL}; // patch 14
67 pCodeOpReg pic16_pc_tosh = {{PO_SFR_REGISTER, "TOSH"}, -1, NULL,0,NULL}; //
68 pCodeOpReg pic16_pc_tosu = {{PO_SFR_REGISTER, "TOSU"}, -1, NULL,0,NULL}; // patch 14
70 pCodeOpReg pic16_pc_tblptrl = {{PO_SFR_REGISTER, "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
71 pCodeOpReg pic16_pc_tblptrh = {{PO_SFR_REGISTER, "TBLPTRH"}, -1, NULL,0,NULL}; //
72 pCodeOpReg pic16_pc_tblptru = {{PO_SFR_REGISTER, "TBLPTRU"}, -1, NULL,0,NULL}; //
73 pCodeOpReg pic16_pc_tablat = {{PO_SFR_REGISTER, "TABLAT"}, -1, NULL,0,NULL}; // patch 15
75 //pCodeOpReg pic16_pc_fsr0 = {{PO_FSR0, "FSR0"}, -1, NULL,0,NULL}; //deprecated !
77 pCodeOpReg pic16_pc_fsr0l = {{PO_FSR0, "FSR0L"}, -1, NULL, 0, NULL};
78 pCodeOpReg pic16_pc_fsr0h = {{PO_FSR0, "FSR0H"}, -1, NULL, 0, NULL};
79 pCodeOpReg pic16_pc_fsr1l = {{PO_FSR0, "FSR1L"}, -1, NULL, 0, NULL};
80 pCodeOpReg pic16_pc_fsr1h = {{PO_FSR0, "FSR1H"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr2l = {{PO_FSR0, "FSR2L"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr2h = {{PO_FSR0, "FSR2H"}, -1, NULL, 0, NULL};
84 pCodeOpReg pic16_pc_indf0 = {{PO_INDF0, "INDF0"}, -1, NULL,0,NULL};
85 pCodeOpReg pic16_pc_postinc0 = {{PO_INDF0, "POSTINC0"}, -1, NULL, 0, NULL};
86 pCodeOpReg pic16_pc_postdec0 = {{PO_INDF0, "POSTDEC0"}, -1, NULL, 0, NULL};
87 pCodeOpReg pic16_pc_preinc0 = {{PO_INDF0, "PREINC0"}, -1, NULL, 0, NULL};
88 pCodeOpReg pic16_pc_plusw0 = {{PO_INDF0, "PLUSW0"}, -1, NULL, 0, NULL};
90 pCodeOpReg pic16_pc_indf1 = {{PO_INDF0, "INDF1"}, -1, NULL,0,NULL};
91 pCodeOpReg pic16_pc_postinc1 = {{PO_INDF0, "POSTINC1"}, -1, NULL, 0, NULL};
92 pCodeOpReg pic16_pc_postdec1 = {{PO_INDF0, "POSTDEC1"}, -1, NULL, 0, NULL};
93 pCodeOpReg pic16_pc_preinc1 = {{PO_INDF0, "PREINC1"}, -1, NULL, 0, NULL};
94 pCodeOpReg pic16_pc_plusw1 = {{PO_INDF0, "PLUSW1"}, -1, NULL, 0, NULL};
96 pCodeOpReg pic16_pc_indf2 = {{PO_INDF0, "INDF2"}, -1, NULL,0,NULL};
97 pCodeOpReg pic16_pc_postinc2 = {{PO_INDF0, "POSTINC2"}, -1, NULL, 0, NULL};
98 pCodeOpReg pic16_pc_postdec2 = {{PO_INDF0, "POSTDEC2"}, -1, NULL, 0, NULL};
99 pCodeOpReg pic16_pc_preinc2 = {{PO_INDF0, "PREINC2"}, -1, NULL, 0, NULL};
100 pCodeOpReg pic16_pc_plusw2 = {{PO_INDF0, "PLUSW2"}, -1, NULL, 0, NULL};
102 pCodeOpReg pic16_pc_prodl = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_prodh = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
105 /* EEPROM registers */
106 pCodeOpReg pic16_pc_eecon1 = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
107 pCodeOpReg pic16_pc_eecon2 = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
108 pCodeOpReg pic16_pc_eedata = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
109 pCodeOpReg pic16_pc_eeadr = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
111 pCodeOpReg pic16_pc_kzero = {{PO_GPR_REGISTER, "KZ"}, -1, NULL,0,NULL};
112 pCodeOpReg pic16_pc_wsave = {{PO_GPR_REGISTER, "WSAVE"}, -1, NULL,0,NULL};
113 pCodeOpReg pic16_pc_ssave = {{PO_GPR_REGISTER, "SSAVE"}, -1, NULL,0,NULL};
115 pCodeOpReg *pic16_stackpnt_lo;
116 pCodeOpReg *pic16_stackpnt_hi;
117 pCodeOpReg *pic16_stack_postinc;
118 pCodeOpReg *pic16_stack_postdec;
119 pCodeOpReg *pic16_stack_preinc;
120 pCodeOpReg *pic16_stack_plusw;
122 pCodeOpReg *pic16_framepnt_lo;
123 pCodeOpReg *pic16_framepnt_hi;
124 pCodeOpReg *pic16_frame_postinc;
125 pCodeOpReg *pic16_frame_postdec;
126 pCodeOpReg *pic16_frame_preinc;
127 pCodeOpReg *pic16_frame_plusw;
129 pCodeOpReg pic16_pc_gpsimio = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
130 pCodeOpReg pic16_pc_gpsimio2 = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
132 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
133 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
136 static int mnemonics_initialized = 0;
139 static hTab *pic16MnemonicsHash = NULL;
140 static hTab *pic16pCodePeepCommandsHash = NULL;
142 static pFile *the_pFile = NULL;
143 static pBlock *pb_dead_pcodes = NULL;
145 /* Hardcoded flags to change the behavior of the PIC port */
146 static int peepOptimizing = 1; /* run the peephole optimizer if nonzero */
147 static int functionInlining = 1; /* inline functions if nonzero */
148 int pic16_debug_verbose = 0; /* Set true to inundate .asm file */
150 int pic16_pcode_verbose = 0;
152 //static int GpCodeSequenceNumber = 1;
153 static int GpcFlowSeq = 1;
155 extern void pic16_RemoveUnusedRegisters(void);
156 extern void pic16_RegsUnMapLiveRanges(void);
157 extern void pic16_BuildFlowTree(pBlock *pb);
158 extern void pic16_pCodeRegOptimizeRegUsage(int level);
160 /****************************************************************/
161 /* Forward declarations */
162 /****************************************************************/
164 void pic16_unlinkpCode(pCode *pc);
166 static void genericAnalyze(pCode *pc);
167 static void AnalyzeGOTO(pCode *pc);
168 static void AnalyzeSKIP(pCode *pc);
169 static void AnalyzeRETURN(pCode *pc);
172 static void genericDestruct(pCode *pc);
173 static void genericPrint(FILE *of,pCode *pc);
175 static void pCodePrintLabel(FILE *of, pCode *pc);
176 static void pCodePrintFunction(FILE *of, pCode *pc);
177 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
178 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
179 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
180 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
181 int pic16_pCodePeepMatchRule(pCode *pc);
182 static void pBlockStats(FILE *of, pBlock *pb);
183 static pBlock *newpBlock(void);
184 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
185 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
186 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
187 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
188 void OptimizeLocalRegs(void);
189 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
191 char *dumpPicOptype(PIC_OPTYPE type);
193 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
194 pCodeOp *pic16_popGetLit(int);
195 pCodeOp *pic16_popGetWithString(char *);
196 extern int inWparamList(char *s);
198 /** data flow optimization helpers **/
199 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
200 static void pic16_vcg_dump (FILE *of, pBlock *pb);
201 static void pic16_vcg_dump_default (pBlock *pb);
203 static int pic16_pCodeIsAlive (pCode *pc);
204 static void pic16_df_stats ();
205 static void pic16_createDF (pBlock *pb);
206 static int pic16_removeUnusedRegistersDF ();
207 static void pic16_destructDF (pBlock *pb);
208 static void releaseStack ();
210 /****************************************************************/
211 /* PIC Instructions */
212 /****************************************************************/
214 pCodeInstruction pic16_pciADDWF = {
215 {PC_OPCODE, NULL, NULL, 0, NULL,
229 1,0, // dest, bit instruction
231 0, // literal operand
233 0, // fast call/return mode select bit
234 0, // second memory operand
235 0, // second literal operand
237 (PCC_W | PCC_REGISTER), // inCond
238 (PCC_REGISTER | PCC_STATUS), // outCond
242 pCodeInstruction pic16_pciADDFW = {
243 {PC_OPCODE, NULL, NULL, 0, NULL,
257 0,0, // dest, bit instruction
259 0, // literal operand
261 0, // fast call/return mode select bit
262 0, // second memory operand
263 0, // second literal operand
265 (PCC_W | PCC_REGISTER), // inCond
266 (PCC_W | PCC_STATUS), // outCond
270 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
271 {PC_OPCODE, NULL, NULL, 0, NULL,
285 1,0, // dest, bit instruction
287 0, // literal operand
289 0, // fast call/return mode select bit
290 0, // second memory operand
291 0, // second literal operand
293 (PCC_W | PCC_REGISTER | PCC_C), // inCond
294 (PCC_REGISTER | PCC_STATUS), // outCond
298 pCodeInstruction pic16_pciADDFWC = {
299 {PC_OPCODE, NULL, NULL, 0, NULL,
313 0,0, // dest, bit instruction
315 0, // literal operand
317 0, // fast call/return mode select bit
318 0, // second memory operand
319 0, // second literal operand
321 (PCC_W | PCC_REGISTER | PCC_C), // inCond
322 (PCC_W | PCC_STATUS), // outCond
326 pCodeInstruction pic16_pciADDLW = {
327 {PC_OPCODE, NULL, NULL, 0, NULL,
341 0,0, // dest, bit instruction
343 1, // literal operand
345 0, // fast call/return mode select bit
346 0, // second memory operand
347 0, // second literal operand
349 (PCC_W | PCC_LITERAL), // inCond
350 (PCC_W | PCC_STATUS), // outCond
354 pCodeInstruction pic16_pciANDLW = {
355 {PC_OPCODE, NULL, NULL, 0, NULL,
369 0,0, // dest, bit instruction
371 1, // literal operand
373 0, // fast call/return mode select bit
374 0, // second memory operand
375 0, // second literal operand
377 (PCC_W | PCC_LITERAL), // inCond
378 (PCC_W | PCC_Z | PCC_N), // outCond
382 pCodeInstruction pic16_pciANDWF = {
383 {PC_OPCODE, NULL, NULL, 0, NULL,
397 1,0, // dest, bit instruction
399 0, // literal operand
401 0, // fast call/return mode select bit
402 0, // second memory operand
403 0, // second literal operand
405 (PCC_W | PCC_REGISTER), // inCond
406 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
410 pCodeInstruction pic16_pciANDFW = {
411 {PC_OPCODE, NULL, NULL, 0, NULL,
425 0,0, // dest, bit instruction
427 0, // literal operand
429 0, // fast call/return mode select bit
430 0, // second memory operand
431 0, // second literal operand
433 (PCC_W | PCC_REGISTER), // inCond
434 (PCC_W | PCC_Z | PCC_N) // outCond
437 pCodeInstruction pic16_pciBC = { // mdubuc - New
438 {PC_OPCODE, NULL, NULL, 0, NULL,
452 0,0, // dest, bit instruction
454 0, // literal operand
456 0, // fast call/return mode select bit
457 0, // second memory operand
458 0, // second literal operand
460 (PCC_REL_ADDR | PCC_C), // inCond
465 pCodeInstruction pic16_pciBCF = {
466 {PC_OPCODE, NULL, NULL, 0, NULL,
480 1,1, // dest, bit instruction
482 0, // literal operand
484 0, // fast call/return mode select bit
485 0, // second memory operand
486 0, // second literal operand
488 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
489 PCC_REGISTER, // outCond
493 pCodeInstruction pic16_pciBN = { // mdubuc - New
494 {PC_OPCODE, NULL, NULL, 0, NULL,
508 0,0, // dest, bit instruction
510 0, // literal operand
512 0, // fast call/return mode select bit
513 0, // second memory operand
514 0, // second literal operand
516 (PCC_REL_ADDR | PCC_N), // inCond
517 PCC_NONE , // outCond
521 pCodeInstruction pic16_pciBNC = { // mdubuc - New
522 {PC_OPCODE, NULL, NULL, 0, NULL,
536 0,0, // dest, bit instruction
538 0, // literal operand
540 0, // fast call/return mode select bit
541 0, // second memory operand
542 0, // second literal operand
544 (PCC_REL_ADDR | PCC_C), // inCond
545 PCC_NONE , // outCond
549 pCodeInstruction pic16_pciBNN = { // mdubuc - New
550 {PC_OPCODE, NULL, NULL, 0, NULL,
564 0,0, // dest, bit instruction
566 0, // literal operand
568 0, // fast call/return mode select bit
569 0, // second memory operand
570 0, // second literal operand
572 (PCC_REL_ADDR | PCC_N), // inCond
573 PCC_NONE , // outCond
577 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
578 {PC_OPCODE, NULL, NULL, 0, NULL,
592 0,0, // dest, bit instruction
594 0, // literal operand
596 0, // fast call/return mode select bit
597 0, // second memory operand
598 0, // second literal operand
600 (PCC_REL_ADDR | PCC_OV), // inCond
601 PCC_NONE , // outCond
605 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
606 {PC_OPCODE, NULL, NULL, 0, NULL,
620 0,0, // dest, bit instruction
622 0, // literal operand
624 0, // fast call/return mode select bit
625 0, // second memory operand
626 0, // second literal operand
628 (PCC_REL_ADDR | PCC_Z), // inCond
629 PCC_NONE , // outCond
633 pCodeInstruction pic16_pciBOV = { // mdubuc - New
634 {PC_OPCODE, NULL, NULL, 0, NULL,
648 0,0, // dest, bit instruction
650 0, // literal operand
652 0, // fast call/return mode select bit
653 0, // second memory operand
654 0, // second literal operand
656 (PCC_REL_ADDR | PCC_OV), // inCond
657 PCC_NONE , // outCond
661 pCodeInstruction pic16_pciBRA = { // mdubuc - New
662 {PC_OPCODE, NULL, NULL, 0, NULL,
676 0,0, // dest, bit instruction
678 0, // literal operand
680 0, // fast call/return mode select bit
681 0, // second memory operand
682 0, // second literal operand
684 PCC_REL_ADDR, // inCond
685 PCC_NONE , // outCond
689 pCodeInstruction pic16_pciBSF = {
690 {PC_OPCODE, NULL, NULL, 0, NULL,
704 1,1, // dest, bit instruction
706 0, // literal operand
708 0, // fast call/return mode select bit
709 0, // second memory operand
710 0, // second literal operand
712 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
713 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
717 pCodeInstruction pic16_pciBTFSC = {
718 {PC_OPCODE, NULL, NULL, 0, NULL,
732 0,1, // dest, bit instruction
734 0, // literal operand
736 0, // fast call/return mode select bit
737 0, // second memory operand
738 0, // second literal operand
740 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
741 PCC_EXAMINE_PCOP, // outCond
745 pCodeInstruction pic16_pciBTFSS = {
746 {PC_OPCODE, NULL, NULL, 0, NULL,
760 0,1, // dest, bit instruction
762 0, // literal operand
764 0, // fast call/return mode select bit
765 0, // second memory operand
766 0, // second literal operand
768 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
769 PCC_EXAMINE_PCOP, // outCond
773 pCodeInstruction pic16_pciBTG = { // mdubuc - New
774 {PC_OPCODE, NULL, NULL, 0, NULL,
788 0,1, // dest, bit instruction
790 0, // literal operand
792 0, // fast call/return mode select bit
793 0, // second memory operand
794 0, // second literal operand
796 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
797 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
801 pCodeInstruction pic16_pciBZ = { // mdubuc - New
802 {PC_OPCODE, NULL, NULL, 0, NULL,
816 0,0, // dest, bit instruction
818 0, // literal operand
820 0, // fast call/return mode select bit
821 0, // second memory operand
822 0, // second literal operand
824 (PCC_REL_ADDR | PCC_Z), // inCond
829 pCodeInstruction pic16_pciCALL = {
830 {PC_OPCODE, NULL, NULL, 0, NULL,
844 0,0, // dest, bit instruction
846 0, // literal operand
848 1, // fast call/return mode select bit
849 0, // second memory operand
850 0, // second literal operand
857 pCodeInstruction pic16_pciCOMF = {
858 {PC_OPCODE, NULL, NULL, 0, NULL,
872 1,0, // dest, bit instruction
874 0, // literal operand
876 0, // fast call/return mode select bit
877 0, // second memory operand
878 0, // second literal operand
880 PCC_REGISTER, // inCond
881 (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
885 pCodeInstruction pic16_pciCOMFW = {
886 {PC_OPCODE, NULL, NULL, 0, NULL,
900 0,0, // dest, bit instruction
902 0, // literal operand
904 0, // fast call/return mode select bit
905 0, // second memory operand
906 0, // second literal operand
908 PCC_REGISTER, // inCond
909 (PCC_W | PCC_Z | PCC_N) , // outCond
913 pCodeInstruction pic16_pciCLRF = {
914 {PC_OPCODE, NULL, NULL, 0, NULL,
928 0,0, // dest, bit instruction
930 0, // literal operand
932 0, // fast call/return mode select bit
933 0, // second memory operand
934 0, // second literal operand
937 (PCC_REGISTER | PCC_Z), // outCond
941 pCodeInstruction pic16_pciCLRWDT = {
942 {PC_OPCODE, NULL, NULL, 0, NULL,
956 0,0, // dest, bit instruction
958 0, // literal operand
960 0, // fast call/return mode select bit
961 0, // second memory operand
962 0, // second literal operand
965 PCC_NONE , // outCond
969 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
970 {PC_OPCODE, NULL, NULL, 0, NULL,
984 0,0, // dest, bit instruction
986 0, // literal operand
988 0, // fast call/return mode select bit
989 0, // second memory operand
990 0, // second literal operand
992 (PCC_W | PCC_REGISTER), // inCond
993 PCC_NONE , // outCond
997 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
998 {PC_OPCODE, NULL, NULL, 0, NULL,
1005 NULL, // from branch
1012 0,0, // dest, bit instruction
1013 1,1, // branch, skip
1014 0, // literal operand
1015 1, // RAM access bit
1016 0, // fast call/return mode select bit
1017 0, // second memory operand
1018 0, // second literal operand
1020 (PCC_W | PCC_REGISTER), // inCond
1021 PCC_NONE , // outCond
1025 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1026 {PC_OPCODE, NULL, NULL, 0, NULL,
1033 NULL, // from branch
1040 1,0, // dest, bit instruction
1041 1,1, // branch, skip
1042 0, // literal operand
1043 1, // RAM access bit
1044 0, // fast call/return mode select bit
1045 0, // second memory operand
1046 0, // second literal operand
1048 (PCC_W | PCC_REGISTER), // inCond
1049 PCC_NONE , // outCond
1053 pCodeInstruction pic16_pciDAW = {
1054 {PC_OPCODE, NULL, NULL, 0, NULL,
1061 NULL, // from branch
1068 0,0, // dest, bit instruction
1069 0,0, // branch, skip
1070 0, // literal operand
1071 0, // RAM access bit
1072 0, // fast call/return mode select bit
1073 0, // second memory operand
1074 0, // second literal operand
1077 (PCC_W | PCC_C), // outCond
1081 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1082 {PC_OPCODE, NULL, NULL, 0, NULL,
1089 NULL, // from branch
1096 1,0, // dest, bit instruction
1097 1,1, // branch, skip
1098 0, // literal operand
1099 1, // RAM access bit
1100 0, // fast call/return mode select bit
1101 0, // second memory operand
1102 0, // second literal operand
1104 PCC_REGISTER, // inCond
1105 PCC_REGISTER , // outCond
1109 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1110 {PC_OPCODE, NULL, NULL, 0, NULL,
1117 NULL, // from branch
1124 0,0, // dest, bit instruction
1125 1,1, // branch, skip
1126 0, // literal operand
1127 1, // RAM access bit
1128 0, // fast call/return mode select bit
1129 0, // second memory operand
1130 0, // second literal operand
1132 PCC_REGISTER, // inCond
1137 pCodeInstruction pic16_pciDECF = {
1138 {PC_OPCODE, NULL, NULL, 0, NULL,
1145 NULL, // from branch
1152 1,0, // dest, bit instruction
1153 0,0, // branch, skip
1154 0, // literal operand
1155 1, // RAM access bit
1156 0, // fast call/return mode select bit
1157 0, // second memory operand
1158 0, // second literal operand
1160 PCC_REGISTER, // inCond
1161 (PCC_REGISTER | PCC_STATUS) , // outCond
1165 pCodeInstruction pic16_pciDECFW = {
1166 {PC_OPCODE, NULL, NULL, 0, NULL,
1173 NULL, // from branch
1180 0,0, // dest, bit instruction
1181 0,0, // branch, skip
1182 0, // literal operand
1183 1, // RAM access bit
1184 0, // fast call/return mode select bit
1185 0, // second memory operand
1186 0, // second literal operand
1188 PCC_REGISTER, // inCond
1189 (PCC_W | PCC_STATUS) , // outCond
1193 pCodeInstruction pic16_pciDECFSZ = {
1194 {PC_OPCODE, NULL, NULL, 0, NULL,
1201 NULL, // from branch
1208 1,0, // dest, bit instruction
1209 1,1, // branch, skip
1210 0, // literal operand
1211 1, // RAM access bit
1212 0, // fast call/return mode select bit
1213 0, // second memory operand
1214 0, // second literal operand
1216 PCC_REGISTER, // inCond
1217 PCC_REGISTER , // outCond
1221 pCodeInstruction pic16_pciDECFSZW = {
1222 {PC_OPCODE, NULL, NULL, 0, NULL,
1229 NULL, // from branch
1236 0,0, // dest, bit instruction
1237 1,1, // branch, skip
1238 0, // literal operand
1239 1, // RAM access bit
1240 0, // fast call/return mode select bit
1241 0, // second memory operand
1242 0, // second literal operand
1244 PCC_REGISTER, // inCond
1249 pCodeInstruction pic16_pciGOTO = {
1250 {PC_OPCODE, NULL, NULL, 0, NULL,
1257 NULL, // from branch
1264 0,0, // dest, bit instruction
1265 1,0, // branch, skip
1266 0, // literal operand
1267 0, // RAM access bit
1268 0, // fast call/return mode select bit
1269 0, // second memory operand
1270 0, // second literal operand
1272 PCC_REL_ADDR, // inCond
1273 PCC_NONE , // outCond
1277 pCodeInstruction pic16_pciINCF = {
1278 {PC_OPCODE, NULL, NULL, 0, NULL,
1285 NULL, // from branch
1292 1,0, // dest, bit instruction
1293 0,0, // branch, skip
1294 0, // literal operand
1295 1, // RAM access bit
1296 0, // fast call/return mode select bit
1297 0, // second memory operand
1298 0, // second literal operand
1300 PCC_REGISTER, // inCond
1301 (PCC_REGISTER | PCC_STATUS), // outCond
1305 pCodeInstruction pic16_pciINCFW = {
1306 {PC_OPCODE, NULL, NULL, 0, NULL,
1313 NULL, // from branch
1320 0,0, // dest, bit instruction
1321 0,0, // branch, skip
1322 0, // literal operand
1323 1, // RAM access bit
1324 0, // fast call/return mode select bit
1325 0, // second memory operand
1326 0, // second literal operand
1328 PCC_REGISTER, // inCond
1329 (PCC_W | PCC_STATUS) , // outCond
1333 pCodeInstruction pic16_pciINCFSZ = {
1334 {PC_OPCODE, NULL, NULL, 0, NULL,
1341 NULL, // from branch
1348 1,0, // dest, bit instruction
1349 1,1, // branch, skip
1350 0, // literal operand
1351 1, // RAM access bit
1352 0, // fast call/return mode select bit
1353 0, // second memory operand
1354 0, // second literal operand
1356 PCC_REGISTER, // inCond
1357 PCC_REGISTER , // outCond
1361 pCodeInstruction pic16_pciINCFSZW = {
1362 {PC_OPCODE, NULL, NULL, 0, NULL,
1369 NULL, // from branch
1376 0,0, // dest, bit instruction
1377 1,1, // branch, skip
1378 0, // literal operand
1379 1, // RAM access bit
1380 0, // fast call/return mode select bit
1381 0, // second memory operand
1382 0, // second literal operand
1384 PCC_REGISTER, // inCond
1389 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1390 {PC_OPCODE, NULL, NULL, 0, NULL,
1397 NULL, // from branch
1404 1,0, // dest, bit instruction
1405 1,1, // branch, skip
1406 0, // literal operand
1407 1, // RAM access bit
1408 0, // fast call/return mode select bit
1409 0, // second memory operand
1410 0, // second literal operand
1412 PCC_REGISTER, // inCond
1413 PCC_REGISTER , // outCond
1417 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1418 {PC_OPCODE, NULL, NULL, 0, NULL,
1425 NULL, // from branch
1432 0,0, // dest, bit instruction
1433 1,1, // branch, skip
1434 0, // literal operand
1435 1, // RAM access bit
1436 0, // fast call/return mode select bit
1437 0, // second memory operand
1438 0, // second literal operand
1440 PCC_REGISTER, // inCond
1445 pCodeInstruction pic16_pciIORWF = {
1446 {PC_OPCODE, NULL, NULL, 0, NULL,
1453 NULL, // from branch
1460 1,0, // dest, bit instruction
1461 0,0, // branch, skip
1462 0, // literal operand
1463 1, // RAM access bit
1464 0, // fast call/return mode select bit
1465 0, // second memory operand
1466 0, // second literal operand
1468 (PCC_W | PCC_REGISTER), // inCond
1469 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1473 pCodeInstruction pic16_pciIORFW = {
1474 {PC_OPCODE, NULL, NULL, 0, NULL,
1481 NULL, // from branch
1488 0,0, // dest, bit instruction
1489 0,0, // branch, skip
1490 0, // literal operand
1491 1, // RAM access bit
1492 0, // fast call/return mode select bit
1493 0, // second memory operand
1494 0, // second literal operand
1496 (PCC_W | PCC_REGISTER), // inCond
1497 (PCC_W | PCC_Z | PCC_N), // outCond
1501 pCodeInstruction pic16_pciIORLW = {
1502 {PC_OPCODE, NULL, NULL, 0, NULL,
1509 NULL, // from branch
1516 0,0, // dest, bit instruction
1517 0,0, // branch, skip
1518 1, // literal operand
1519 0, // RAM access bit
1520 0, // fast call/return mode select bit
1521 0, // second memory operand
1522 0, // second literal operand
1524 (PCC_W | PCC_LITERAL), // inCond
1525 (PCC_W | PCC_Z | PCC_N), // outCond
1529 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1530 {PC_OPCODE, NULL, NULL, 0, NULL,
1537 NULL, // from branch
1544 0,0, // dest, bit instruction
1545 0,0, // branch, skip
1546 1, // literal operand
1547 0, // RAM access bit
1548 0, // fast call/return mode select bit
1549 0, // second memory operand
1550 1, // second literal operand
1552 PCC_LITERAL, // inCond
1553 PCC_NONE, // outCond
1557 pCodeInstruction pic16_pciMOVF = {
1558 {PC_OPCODE, NULL, NULL, 0, NULL,
1565 NULL, // from branch
1572 1,0, // dest, bit instruction
1573 0,0, // branch, skip
1574 0, // literal operand
1575 1, // RAM access bit
1576 0, // fast call/return mode select bit
1577 0, // second memory operand
1578 0, // second literal operand
1580 PCC_REGISTER, // inCond
1581 (PCC_Z | PCC_N), // outCond
1585 pCodeInstruction pic16_pciMOVFW = {
1586 {PC_OPCODE, NULL, NULL, 0, NULL,
1593 NULL, // from branch
1600 0,0, // dest, bit instruction
1601 0,0, // branch, skip
1602 0, // literal operand
1603 1, // RAM access bit
1604 0, // fast call/return mode select bit
1605 0, // second memory operand
1606 0, // second literal operand
1608 PCC_REGISTER, // inCond
1609 (PCC_W | PCC_N | PCC_Z), // outCond
1613 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1614 {PC_OPCODE, NULL, NULL, 0, NULL,
1621 NULL, // from branch
1628 0,0, // dest, bit instruction
1629 0,0, // branch, skip
1630 0, // literal operand
1631 0, // RAM access bit
1632 0, // fast call/return mode select bit
1633 1, // second memory operand
1634 0, // second literal operand
1636 PCC_REGISTER, // inCond
1637 PCC_REGISTER2, // outCond
1641 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1642 {PC_OPCODE, NULL, NULL, 0, NULL,
1648 NULL, // from branch
1655 0,0, // dest, bit instruction
1656 0,0, // branch, skip
1657 1, // literal operand
1658 0, // RAM access bit
1659 0, // fast call/return mode select bit
1660 0, // second memory operand
1661 0, // second literal operand
1663 (PCC_NONE | PCC_LITERAL), // inCond
1664 PCC_REGISTER, // outCond - BSR
1668 pCodeInstruction pic16_pciMOVLW = {
1669 {PC_OPCODE, NULL, NULL, 0, NULL,
1675 NULL, // from branch
1682 0,0, // dest, bit instruction
1683 0,0, // branch, skip
1684 1, // literal operand
1685 0, // RAM access bit
1686 0, // fast call/return mode select bit
1687 0, // second memory operand
1688 0, // second literal operand
1690 (PCC_NONE | PCC_LITERAL), // inCond
1695 pCodeInstruction pic16_pciMOVWF = {
1696 {PC_OPCODE, NULL, NULL, 0, NULL,
1703 NULL, // from branch
1710 0,0, // dest, bit instruction
1711 0,0, // branch, skip
1712 0, // literal operand
1713 1, // RAM access bit
1714 0, // fast call/return mode select bit
1715 0, // second memory operand
1716 0, // second literal operand
1719 PCC_REGISTER, // outCond
1723 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1724 {PC_OPCODE, NULL, NULL, 0, NULL,
1730 NULL, // from branch
1737 0,0, // dest, bit instruction
1738 0,0, // branch, skip
1739 1, // literal operand
1740 0, // RAM access bit
1741 0, // fast call/return mode select bit
1742 0, // second memory operand
1743 0, // second literal operand
1745 (PCC_W | PCC_LITERAL), // inCond
1746 PCC_NONE, // outCond - PROD
1750 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1751 {PC_OPCODE, NULL, NULL, 0, NULL,
1757 NULL, // from branch
1764 0,0, // dest, bit instruction
1765 0,0, // branch, skip
1766 0, // literal operand
1767 1, // RAM access bit
1768 0, // fast call/return mode select bit
1769 0, // second memory operand
1770 0, // second literal operand
1772 (PCC_W | PCC_REGISTER), // inCond
1773 PCC_REGISTER, // outCond - PROD
1777 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1778 {PC_OPCODE, NULL, NULL, 0, NULL,
1784 NULL, // from branch
1791 0,0, // dest, bit instruction
1792 0,0, // branch, skip
1793 0, // literal operand
1794 1, // RAM access bit
1795 0, // fast call/return mode select bit
1796 0, // second memory operand
1797 0, // second literal operand
1799 PCC_REGISTER, // inCond
1800 (PCC_REGISTER | PCC_STATUS), // outCond
1804 pCodeInstruction pic16_pciNOP = {
1805 {PC_OPCODE, NULL, NULL, 0, NULL,
1811 NULL, // from branch
1818 0,0, // dest, bit instruction
1819 0,0, // branch, skip
1820 0, // literal operand
1821 0, // RAM access bit
1822 0, // fast call/return mode select bit
1823 0, // second memory operand
1824 0, // second literal operand
1827 PCC_NONE, // outCond
1831 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1832 {PC_OPCODE, NULL, NULL, 0, NULL,
1838 NULL, // from branch
1845 0,0, // dest, bit instruction
1846 0,0, // branch, skip
1847 0, // literal operand
1848 0, // RAM access bit
1849 0, // fast call/return mode select bit
1850 0, // second memory operand
1851 0, // second literal operand
1854 PCC_NONE , // outCond
1858 pCodeInstruction pic16_pciPUSH = {
1859 {PC_OPCODE, NULL, NULL, 0, NULL,
1865 NULL, // from branch
1872 0,0, // dest, bit instruction
1873 0,0, // branch, skip
1874 0, // literal operand
1875 0, // RAM access bit
1876 0, // fast call/return mode select bit
1877 0, // second memory operand
1878 0, // second literal operand
1881 PCC_NONE , // outCond
1885 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1886 {PC_OPCODE, NULL, NULL, 0, NULL,
1892 NULL, // from branch
1899 0,0, // dest, bit instruction
1900 1,0, // branch, skip
1901 0, // literal operand
1902 0, // RAM access bit
1903 0, // fast call/return mode select bit
1904 0, // second memory operand
1905 0, // second literal operand
1907 PCC_REL_ADDR, // inCond
1908 PCC_NONE , // outCond
1912 pCodeInstruction pic16_pciRETFIE = {
1913 {PC_OPCODE, NULL, NULL, 0, NULL,
1920 NULL, // from branch
1927 0,0, // dest, bit instruction
1928 1,0, // branch, skip
1929 0, // literal operand
1930 0, // RAM access bit
1931 1, // fast call/return mode select bit
1932 0, // second memory operand
1933 0, // second literal operand
1936 PCC_NONE, // outCond (not true... affects the GIE bit too)
1940 pCodeInstruction pic16_pciRETLW = {
1941 {PC_OPCODE, NULL, NULL, 0, NULL,
1948 NULL, // from branch
1955 0,0, // dest, bit instruction
1956 1,0, // branch, skip
1957 1, // literal operand
1958 0, // RAM access bit
1959 0, // fast call/return mode select bit
1960 0, // second memory operand
1961 0, // second literal operand
1963 PCC_LITERAL, // inCond
1968 pCodeInstruction pic16_pciRETURN = {
1969 {PC_OPCODE, NULL, NULL, 0, NULL,
1976 NULL, // from branch
1983 0,0, // dest, bit instruction
1984 1,0, // branch, skip
1985 0, // literal operand
1986 0, // RAM access bit
1987 1, // fast call/return mode select bit
1988 0, // second memory operand
1989 0, // second literal operand
1992 PCC_NONE, // outCond
1995 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
1996 {PC_OPCODE, NULL, NULL, 0, NULL,
2003 NULL, // from branch
2010 1,0, // dest, bit instruction
2011 0,0, // branch, skip
2012 0, // literal operand
2013 1, // RAM access bit
2014 0, // fast call/return mode select bit
2015 0, // second memory operand
2016 0, // second literal operand
2018 (PCC_C | PCC_REGISTER), // inCond
2019 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2023 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2024 {PC_OPCODE, NULL, NULL, 0, NULL,
2031 NULL, // from branch
2038 0,0, // dest, bit instruction
2039 0,0, // branch, skip
2040 0, // literal operand
2041 1, // RAM access bit
2042 0, // fast call/return mode select bit
2043 0, // second memory operand
2044 0, // second literal operand
2046 (PCC_C | PCC_REGISTER), // inCond
2047 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2051 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2052 {PC_OPCODE, NULL, NULL, 0, NULL,
2059 NULL, // from branch
2066 1,0, // dest, bit instruction
2067 0,0, // branch, skip
2068 0, // literal operand
2069 1, // RAM access bit
2070 0, // fast call/return mode select bit
2071 0, // second memory operand
2072 0, // second literal operand
2074 PCC_REGISTER, // inCond
2075 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2078 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2079 {PC_OPCODE, NULL, NULL, 0, NULL,
2086 NULL, // from branch
2093 0,0, // dest, bit instruction
2094 0,0, // branch, skip
2095 0, // literal operand
2096 1, // RAM access bit
2097 0, // fast call/return mode select bit
2098 0, // second memory operand
2099 0, // second literal operand
2101 PCC_REGISTER, // inCond
2102 (PCC_W | PCC_Z | PCC_N), // outCond
2105 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2106 {PC_OPCODE, NULL, NULL, 0, NULL,
2113 NULL, // from branch
2120 1,0, // dest, bit instruction
2121 0,0, // branch, skip
2122 0, // literal operand
2123 1, // RAM access bit
2124 0, // fast call/return mode select bit
2125 0, // second memory operand
2126 0, // second literal operand
2128 (PCC_C | PCC_REGISTER), // inCond
2129 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2132 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2133 {PC_OPCODE, NULL, NULL, 0, NULL,
2140 NULL, // from branch
2147 0,0, // dest, bit instruction
2148 0,0, // branch, skip
2149 0, // literal operand
2150 1, // RAM access bit
2151 0, // fast call/return mode select bit
2152 0, // second memory operand
2153 0, // second literal operand
2155 (PCC_C | PCC_REGISTER), // inCond
2156 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2159 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2160 {PC_OPCODE, NULL, NULL, 0, NULL,
2167 NULL, // from branch
2174 1,0, // dest, bit instruction
2175 0,0, // branch, skip
2176 0, // literal operand
2177 1, // RAM access bit
2178 0, // fast call/return mode select bit
2179 0, // second memory operand
2180 0, // second literal operand
2182 PCC_REGISTER, // inCond
2183 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2187 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2188 {PC_OPCODE, NULL, NULL, 0, NULL,
2195 NULL, // from branch
2202 0,0, // dest, bit instruction
2203 0,0, // branch, skip
2204 0, // literal operand
2205 1, // RAM access bit
2206 0, // fast call/return mode select bit
2207 0, // second memory operand
2208 0, // second literal operand
2210 PCC_REGISTER, // inCond
2211 (PCC_W | PCC_Z | PCC_N), // outCond
2215 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2216 {PC_OPCODE, NULL, NULL, 0, NULL,
2223 NULL, // from branch
2230 0,0, // dest, bit instruction
2231 0,0, // branch, skip
2232 0, // literal operand
2233 1, // RAM access bit
2234 0, // fast call/return mode select bit
2235 0, // second memory operand
2236 0, // second literal operand
2239 PCC_REGISTER , // outCond
2243 pCodeInstruction pic16_pciSUBLW = {
2244 {PC_OPCODE, NULL, NULL, 0, NULL,
2251 NULL, // from branch
2258 0,0, // dest, bit instruction
2259 0,0, // branch, skip
2260 1, // literal operand
2261 0, // RAM access bit
2262 0, // fast call/return mode select bit
2263 0, // second memory operand
2264 0, // second literal operand
2266 (PCC_W | PCC_LITERAL), // inCond
2267 (PCC_W | PCC_STATUS), // outCond
2271 pCodeInstruction pic16_pciSUBFWB = {
2272 {PC_OPCODE, NULL, NULL, 0, NULL,
2279 NULL, // from branch
2286 1,0, // dest, bit instruction
2287 0,0, // branch, skip
2288 0, // literal operand
2289 1, // RAM access bit
2290 0, // fast call/return mode select bit
2291 0, // second memory operand
2292 0, // second literal operand
2294 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2295 (PCC_W | PCC_STATUS), // outCond
2299 pCodeInstruction pic16_pciSUBWF = {
2300 {PC_OPCODE, NULL, NULL, 0, NULL,
2307 NULL, // from branch
2314 1,0, // dest, bit instruction
2315 0,0, // branch, skip
2316 0, // literal operand
2317 1, // RAM access bit
2318 0, // fast call/return mode select bit
2319 0, // second memory operand
2320 0, // second literal operand
2322 (PCC_W | PCC_REGISTER), // inCond
2323 (PCC_REGISTER | PCC_STATUS), // outCond
2327 pCodeInstruction pic16_pciSUBFW = {
2328 {PC_OPCODE, NULL, NULL, 0, NULL,
2335 NULL, // from branch
2342 0,0, // dest, bit instruction
2343 0,0, // branch, skip
2344 0, // literal operand
2345 1, // RAM access bit
2346 0, // fast call/return mode select bit
2347 0, // second memory operand
2348 0, // second literal operand
2350 (PCC_W | PCC_REGISTER), // inCond
2351 (PCC_W | PCC_STATUS), // outCond
2355 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2356 {PC_OPCODE, NULL, NULL, 0, NULL,
2363 NULL, // from branch
2370 1,0, // dest, bit instruction
2371 0,0, // branch, skip
2372 0, // literal operand
2373 1, // RAM access bit
2374 0, // fast call/return mode select bit
2375 0, // second memory operand
2376 0, // second literal operand
2378 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2379 (PCC_REGISTER | PCC_STATUS), // outCond
2383 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2384 {PC_OPCODE, NULL, NULL, 0, NULL,
2391 NULL, // from branch
2398 0,0, // dest, bit instruction
2399 0,0, // branch, skip
2400 0, // literal operand
2401 1, // RAM access bit
2402 0, // fast call/return mode select bit
2403 0, // second memory operand
2404 0, // second literal operand
2406 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2407 (PCC_W | PCC_STATUS), // outCond
2411 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2412 {PC_OPCODE, NULL, NULL, 0, NULL,
2419 NULL, // from branch
2426 1,0, // dest, bit instruction
2427 0,0, // branch, skip
2428 0, // literal operand
2429 1, // RAM access bit
2430 0, // fast call/return mode select bit
2431 0, // second memory operand
2432 0, // second literal operand
2434 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2435 (PCC_REGISTER | PCC_STATUS), // outCond
2439 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2440 {PC_OPCODE, NULL, NULL, 0, NULL,
2447 NULL, // from branch
2454 0,0, // dest, bit instruction
2455 0,0, // branch, skip
2456 0, // literal operand
2457 1, // RAM access bit
2458 0, // fast call/return mode select bit
2459 0, // second memory operand
2460 0, // second literal operand
2462 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2463 (PCC_W | PCC_STATUS), // outCond
2467 pCodeInstruction pic16_pciSWAPF = {
2468 {PC_OPCODE, NULL, NULL, 0, NULL,
2475 NULL, // from branch
2482 1,0, // dest, bit instruction
2483 0,0, // branch, skip
2484 0, // literal operand
2485 1, // RAM access bit
2486 0, // fast call/return mode select bit
2487 0, // second memory operand
2488 0, // second literal operand
2490 (PCC_REGISTER), // inCond
2491 (PCC_REGISTER), // outCond
2495 pCodeInstruction pic16_pciSWAPFW = {
2496 {PC_OPCODE, NULL, NULL, 0, NULL,
2503 NULL, // from branch
2510 0,0, // dest, bit instruction
2511 0,0, // branch, skip
2512 0, // literal operand
2513 1, // RAM access bit
2514 0, // fast call/return mode select bit
2515 0, // second memory operand
2516 0, // second literal operand
2518 (PCC_REGISTER), // inCond
2523 pCodeInstruction pic16_pciTBLRD = { // patch 15
2524 {PC_OPCODE, NULL, NULL, 0, NULL,
2530 NULL, // from branch
2537 0,0, // dest, bit instruction
2538 0,0, // branch, skip
2539 0, // literal operand
2540 0, // RAM access bit
2541 0, // fast call/return mode select bit
2542 0, // second memory operand
2543 0, // second literal operand
2546 PCC_NONE , // outCond
2550 pCodeInstruction pic16_pciTBLRD_POSTINC = { // patch 15
2551 {PC_OPCODE, NULL, NULL, 0, NULL,
2557 NULL, // from branch
2564 0,0, // dest, bit instruction
2565 0,0, // branch, skip
2566 0, // literal operand
2567 0, // RAM access bit
2568 0, // fast call/return mode select bit
2569 0, // second memory operand
2570 0, // second literal operand
2573 PCC_NONE , // outCond
2577 pCodeInstruction pic16_pciTBLRD_POSTDEC = { // patch 15
2578 {PC_OPCODE, NULL, NULL, 0, NULL,
2584 NULL, // from branch
2591 0,0, // dest, bit instruction
2592 0,0, // branch, skip
2593 0, // literal operand
2594 0, // RAM access bit
2595 0, // fast call/return mode select bit
2596 0, // second memory operand
2597 0, // second literal operand
2600 PCC_NONE , // outCond
2604 pCodeInstruction pic16_pciTBLRD_PREINC = { // patch 15
2605 {PC_OPCODE, NULL, NULL, 0, NULL,
2611 NULL, // from branch
2618 0,0, // dest, bit instruction
2619 0,0, // branch, skip
2620 0, // literal operand
2621 0, // RAM access bit
2622 0, // fast call/return mode select bit
2623 0, // second memory operand
2624 0, // second literal operand
2627 PCC_NONE , // outCond
2631 pCodeInstruction pic16_pciTBLWT = { // patch 15
2632 {PC_OPCODE, NULL, NULL, 0, NULL,
2638 NULL, // from branch
2645 0,0, // dest, bit instruction
2646 0,0, // branch, skip
2647 0, // literal operand
2648 0, // RAM access bit
2649 0, // fast call/return mode select bit
2650 0, // second memory operand
2651 0, // second literal operand
2654 PCC_NONE , // outCond
2658 pCodeInstruction pic16_pciTBLWT_POSTINC = { // patch 15
2659 {PC_OPCODE, NULL, NULL, 0, NULL,
2665 NULL, // from branch
2672 0,0, // dest, bit instruction
2673 0,0, // branch, skip
2674 0, // literal operand
2675 0, // RAM access bit
2676 0, // fast call/return mode select bit
2677 0, // second memory operand
2678 0, // second literal operand
2681 PCC_NONE , // outCond
2685 pCodeInstruction pic16_pciTBLWT_POSTDEC = { // patch 15
2686 {PC_OPCODE, NULL, NULL, 0, NULL,
2692 NULL, // from branch
2699 0,0, // dest, bit instruction
2700 0,0, // branch, skip
2701 0, // literal operand
2702 0, // RAM access bit
2703 0, // fast call/return mode select bit
2704 0, // second memory operand
2705 0, // second literal operand
2708 PCC_NONE , // outCond
2712 pCodeInstruction pic16_pciTBLWT_PREINC = { // patch 15
2713 {PC_OPCODE, NULL, NULL, 0, NULL,
2719 NULL, // from branch
2726 0,0, // dest, bit instruction
2727 0,0, // branch, skip
2728 0, // literal operand
2729 0, // RAM access bit
2730 0, // fast call/return mode select bit
2731 0, // second memory operand
2732 0, // second literal operand
2735 PCC_NONE , // outCond
2739 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2740 {PC_OPCODE, NULL, NULL, 0, NULL,
2747 NULL, // from branch
2754 0,0, // dest, bit instruction
2755 1,1, // branch, skip
2756 0, // literal operand
2757 1, // RAM access bit
2758 0, // fast call/return mode select bit
2759 0, // second memory operand
2760 0, // second literal operand
2762 PCC_REGISTER, // inCond
2763 PCC_NONE, // outCond
2767 pCodeInstruction pic16_pciXORWF = {
2768 {PC_OPCODE, NULL, NULL, 0, NULL,
2775 NULL, // from branch
2782 1,0, // dest, bit instruction
2783 0,0, // branch, skip
2784 0, // literal operand
2785 1, // RAM access bit
2786 0, // fast call/return mode select bit
2787 0, // second memory operand
2788 0, // second literal operand
2790 (PCC_W | PCC_REGISTER), // inCond
2791 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2795 pCodeInstruction pic16_pciXORFW = {
2796 {PC_OPCODE, NULL, NULL, 0, NULL,
2803 NULL, // from branch
2810 0,0, // dest, bit instruction
2811 0,0, // branch, skip
2812 0, // literal operand
2813 1, // RAM access bit
2814 0, // fast call/return mode select bit
2815 0, // second memory operand
2816 0, // second literal operand
2818 (PCC_W | PCC_REGISTER), // inCond
2819 (PCC_W | PCC_Z | PCC_N), // outCond
2823 pCodeInstruction pic16_pciXORLW = {
2824 {PC_OPCODE, NULL, NULL, 0, NULL,
2831 NULL, // from branch
2838 0,0, // dest, bit instruction
2839 0,0, // branch, skip
2840 1, // literal operand
2841 1, // RAM access bit
2842 0, // fast call/return mode select bit
2843 0, // second memory operand
2844 0, // second literal operand
2846 (PCC_W | PCC_LITERAL), // inCond
2847 (PCC_W | PCC_Z | PCC_N), // outCond
2852 pCodeInstruction pic16_pciBANKSEL = {
2853 {PC_OPCODE, NULL, NULL, 0, NULL,
2859 NULL, // from branch
2866 0,0, // dest, bit instruction
2867 0,0, // branch, skip
2868 0, // literal operand
2869 0, // RAM access bit
2870 0, // fast call/return mode select bit
2871 0, // second memory operand
2872 0, // second literal operand
2875 PCC_NONE, // outCond
2880 #define MAX_PIC16MNEMONICS 100
2881 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2883 extern set *externs;
2884 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2885 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2887 void pic16_pCodeInitRegisters(void)
2889 static int initialized=0;
2896 pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2897 pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2898 pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2899 pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2900 pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2901 pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2902 pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2904 pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2905 pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2906 pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2908 pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2909 pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2910 pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2911 pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2913 pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2914 pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2915 pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2916 pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2917 pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2918 pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2920 pic16_stackpnt_lo = &pic16_pc_fsr1l;
2921 pic16_stackpnt_hi = &pic16_pc_fsr1h;
2922 pic16_stack_postdec = &pic16_pc_postdec1;
2923 pic16_stack_postinc = &pic16_pc_postinc1;
2924 pic16_stack_preinc = &pic16_pc_preinc1;
2925 pic16_stack_plusw = &pic16_pc_plusw1;
2927 pic16_framepnt_lo = &pic16_pc_fsr2l;
2928 pic16_framepnt_hi = &pic16_pc_fsr2h;
2929 pic16_frame_postdec = &pic16_pc_postdec2;
2930 pic16_frame_postinc = &pic16_pc_postinc2;
2931 pic16_frame_preinc = &pic16_pc_preinc2;
2932 pic16_frame_plusw = &pic16_pc_plusw2;
2934 pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
2935 pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
2936 pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
2937 pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
2938 pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
2940 pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
2941 pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
2942 pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
2943 pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
2944 pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
2946 pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
2947 pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
2948 pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
2949 pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
2950 pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
2952 pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
2953 pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
2956 pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
2957 pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
2958 pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
2959 pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
2962 pic16_pc_status.rIdx = IDX_STATUS;
2963 pic16_pc_intcon.rIdx = IDX_INTCON;
2964 pic16_pc_pcl.rIdx = IDX_PCL;
2965 pic16_pc_pclath.rIdx = IDX_PCLATH;
2966 pic16_pc_pclatu.rIdx = IDX_PCLATU;
2967 pic16_pc_wreg.rIdx = IDX_WREG;
2968 pic16_pc_bsr.rIdx = IDX_BSR;
2970 pic16_pc_tosl.rIdx = IDX_TOSL;
2971 pic16_pc_tosh.rIdx = IDX_TOSH;
2972 pic16_pc_tosu.rIdx = IDX_TOSU;
2974 pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
2975 pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
2976 pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
2977 pic16_pc_tablat.rIdx = IDX_TABLAT;
2979 pic16_pc_fsr0l.rIdx = IDX_FSR0L;
2980 pic16_pc_fsr0h.rIdx = IDX_FSR0H;
2981 pic16_pc_fsr1l.rIdx = IDX_FSR1L;
2982 pic16_pc_fsr1h.rIdx = IDX_FSR1H;
2983 pic16_pc_fsr2l.rIdx = IDX_FSR2L;
2984 pic16_pc_fsr2h.rIdx = IDX_FSR2H;
2985 pic16_pc_indf0.rIdx = IDX_INDF0;
2986 pic16_pc_postinc0.rIdx = IDX_POSTINC0;
2987 pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
2988 pic16_pc_preinc0.rIdx = IDX_PREINC0;
2989 pic16_pc_plusw0.rIdx = IDX_PLUSW0;
2990 pic16_pc_indf1.rIdx = IDX_INDF1;
2991 pic16_pc_postinc1.rIdx = IDX_POSTINC1;
2992 pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
2993 pic16_pc_preinc1.rIdx = IDX_PREINC1;
2994 pic16_pc_plusw1.rIdx = IDX_PLUSW1;
2995 pic16_pc_indf2.rIdx = IDX_INDF2;
2996 pic16_pc_postinc2.rIdx = IDX_POSTINC2;
2997 pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
2998 pic16_pc_preinc2.rIdx = IDX_PREINC2;
2999 pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3000 pic16_pc_prodl.rIdx = IDX_PRODL;
3001 pic16_pc_prodh.rIdx = IDX_PRODH;
3003 pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3004 pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3005 pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3007 pic16_pc_kzero.rIdx = IDX_KZ;
3008 pic16_pc_wsave.rIdx = IDX_WSAVE;
3009 pic16_pc_ssave.rIdx = IDX_SSAVE;
3011 pic16_pc_eecon1.rIdx = IDX_EECON1;
3012 pic16_pc_eecon2.rIdx = IDX_EECON2;
3013 pic16_pc_eedata.rIdx = IDX_EEDATA;
3014 pic16_pc_eeadr.rIdx = IDX_EEADR;
3017 pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3018 pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3020 pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3021 pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3023 /* probably should put this in a separate initialization routine */
3024 pb_dead_pcodes = newpBlock();
3028 /*-----------------------------------------------------------------*/
3029 /* mnem2key - convert a pic mnemonic into a hash key */
3030 /* (BTW - this spreads the mnemonics quite well) */
3032 /*-----------------------------------------------------------------*/
3034 static int mnem2key(unsigned char const *mnem)
3043 key += toupper(*mnem++) +1;
3047 return (key & 0x1f);
3051 void pic16initMnemonics(void)
3056 pCodeInstruction *pci;
3058 if(mnemonics_initialized)
3061 // NULL out the array before making the assignments
3062 // since we check the array contents below this initialization.
3064 for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3065 pic16Mnemonics[i] = NULL;
3068 pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3069 pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3070 pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3071 pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3072 pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3073 pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3074 pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3075 pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3076 pic16Mnemonics[POC_BC] = &pic16_pciBC;
3077 pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3078 pic16Mnemonics[POC_BN] = &pic16_pciBN;
3079 pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3080 pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3081 pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3082 pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3083 pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3084 pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3085 pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3086 pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3087 pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3088 pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3089 pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3090 pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3091 pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3092 pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3093 pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3094 pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3095 pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3096 pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3097 pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3098 pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3099 pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3100 pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3101 pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3102 pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3103 pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3104 pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3105 pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3106 pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3107 pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3108 pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3109 pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3110 pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3111 pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3112 pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3113 pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3114 pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3115 pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3116 pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3117 pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3118 pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3119 pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3120 pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3121 pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3122 pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3123 pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3124 pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3125 pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3126 pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3127 pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3128 pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3129 pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3130 pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3131 pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3132 pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3133 pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3134 pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3135 pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3136 pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3137 pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3138 pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3139 pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3140 pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3141 pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3142 pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3143 pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3144 pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3145 pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3146 pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3147 pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3148 pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3149 pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3150 pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3151 pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3152 pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3153 pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3154 pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3155 pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3156 pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3157 pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3158 pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3159 pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3160 pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3161 pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3163 for(i=0; i<MAX_PIC16MNEMONICS; i++)
3164 if(pic16Mnemonics[i])
3165 hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3166 pci = hTabFirstItem(pic16MnemonicsHash, &key);
3169 DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3170 pci = hTabNextItem(pic16MnemonicsHash, &key);
3173 mnemonics_initialized = 1;
3176 int pic16_getpCodePeepCommand(char *cmd);
3178 int pic16_getpCode(char *mnem,unsigned dest)
3181 pCodeInstruction *pci;
3182 int key = mnem2key((unsigned char *)mnem);
3184 if(!mnemonics_initialized)
3185 pic16initMnemonics();
3187 pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3191 if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3192 if((pci->num_ops <= 1)
3193 || (pci->isModReg == dest)
3195 || (pci->num_ops <= 2 && pci->isAccess)
3196 || (pci->num_ops <= 2 && pci->isFastCall)
3197 || (pci->num_ops <= 2 && pci->is2MemOp)
3198 || (pci->num_ops <= 2 && pci->is2LitOp) )
3202 pci = hTabNextItemWK (pic16MnemonicsHash);
3209 /*-----------------------------------------------------------------*
3210 * pic16initpCodePeepCommands
3212 *-----------------------------------------------------------------*/
3213 void pic16initpCodePeepCommands(void)
3221 hTabAddItem(&pic16pCodePeepCommandsHash,
3222 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3224 } while (peepCommands[i].cmd);
3226 pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3229 //fprintf(stderr, "peep command %s key %d\n",pcmd->cmd,pcmd->id);
3230 pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3235 /*-----------------------------------------------------------------
3238 *-----------------------------------------------------------------*/
3240 int pic16_getpCodePeepCommand(char *cmd)
3244 int key = mnem2key((unsigned char *)cmd);
3247 pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3250 // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3251 if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3255 pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3262 static char getpBlock_dbName(pBlock *pb)
3268 return pb->cmemmap->dbName;
3272 void pic16_pBlockConvert2ISR(pBlock *pb)
3276 if(pb->cmemmap)pb->cmemmap = NULL;
3280 if(pic16_pcode_verbose)
3281 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3284 void pic16_pBlockConvert2Absolute(pBlock *pb)
3287 if(pb->cmemmap)pb->cmemmap = NULL;
3291 if(pic16_pcode_verbose)
3292 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3295 /*-----------------------------------------------------------------*/
3296 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all */
3297 /* instances to the front of the doubly linked */
3298 /* list of pBlocks */
3299 /*-----------------------------------------------------------------*/
3301 void pic16_movepBlock2Head(char dbName)
3306 /* this can happen in sources without code,
3307 * only variable definitions */
3308 if(!the_pFile)return;
3310 pb = the_pFile->pbHead;
3314 if(getpBlock_dbName(pb) == dbName) {
3315 pBlock *pbn = pb->next;
3316 pb->next = the_pFile->pbHead;
3317 the_pFile->pbHead->prev = pb;
3318 the_pFile->pbHead = pb;
3321 pb->prev->next = pbn;
3323 // If the pBlock that we just moved was the last
3324 // one in the link of all of the pBlocks, then we
3325 // need to point the tail to the block just before
3326 // the one we moved.
3327 // Note: if pb->next is NULL, then pb must have
3328 // been the last pBlock in the chain.
3331 pbn->prev = pb->prev;
3333 the_pFile->pbTail = pb->prev;
3344 void pic16_copypCode(FILE *of, char dbName)
3348 if(!of || !the_pFile)
3351 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3352 if(getpBlock_dbName(pb) == dbName) {
3353 // fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3355 pic16_printpBlock(of,pb);
3360 void pic16_pcode_test(void)
3363 DFPRINTF((stderr,"pcode is alive!\n"));
3373 /* create the file name */
3374 strcpy(buffer,dstFileName);
3375 strcat(buffer,".p");
3377 if( !(pFile = fopen(buffer, "w" ))) {
3378 werror(E_FILE_OPEN_ERR,buffer);
3382 fprintf(pFile,"pcode dump\n\n");
3384 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3385 fprintf(pFile,"\n\tNew pBlock\n\n");
3387 fprintf(pFile,"%s",pb->cmemmap->sname);
3389 fprintf(pFile,"internal pblock");
3391 fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3392 pic16_printpBlock(pFile,pb);
3398 unsigned long pic16_countInstructions(void)
3402 unsigned long isize=0;
3404 if(!the_pFile)return -1;
3406 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3407 for(pc = pb->pcHead; pc; pc = pc->next) {
3408 if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3415 /*-----------------------------------------------------------------*/
3416 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg- */
3417 /* ister, RegCond will return the bit being referenced. */
3419 /* fixme - why not just OR in the pcop bit field */
3420 /*-----------------------------------------------------------------*/
3422 static int RegCond(pCodeOp *pcop)
3428 if(!pcop->name)return 0;
3430 if(pcop->type == PO_GPR_BIT && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3431 switch(PCORB(pcop)->bit) {
3446 /*-----------------------------------------------------------------*/
3447 /* pic16_newpCode - create and return a newly initialized pCode */
3449 /* fixme - rename this */
3451 /* The purpose of this routine is to create a new Instruction */
3452 /* pCode. This is called by gen.c while the assembly code is being */
3456 /* PIC_OPCODE op - the assembly instruction we wish to create. */
3457 /* (note that the op is analogous to but not the */
3458 /* same thing as the opcode of the instruction.) */
3459 /* pCdoeOp *pcop - pointer to the operand of the instruction. */
3462 /* a pointer to the new malloc'd pCode is returned. */
3466 /*-----------------------------------------------------------------*/
3467 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3469 pCodeInstruction *pci ;
3471 if(!mnemonics_initialized)
3472 pic16initMnemonics();
3474 pci = Safe_calloc(1, sizeof(pCodeInstruction));
3476 if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3477 memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3480 if(pci->inCond & PCC_EXAMINE_PCOP)
3481 pci->inCond |= RegCond(pcop);
3483 if(pci->outCond & PCC_EXAMINE_PCOP)
3484 pci->outCond |= RegCond(pcop);
3486 pci->pc.prev = pci->pc.next = NULL;
3487 return (pCode *)pci;
3490 fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3496 /*-----------------------------------------------------------------*/
3497 /* pic16_newpCodeWild - create a "wild" as in wild card pCode */
3499 /* Wild pcodes are used during the peep hole optimizer to serve */
3500 /* as place holders for any instruction. When a snippet of code is */
3501 /* compared to a peep hole rule, the wild card opcode will match */
3502 /* any instruction. However, the optional operand and label are */
3503 /* additional qualifiers that must also be matched before the */
3504 /* line (of assembly code) is declared matched. Note that the */
3505 /* operand may be wild too. */
3507 /* Note, a wild instruction is specified just like a wild var: */
3508 /* %4 ; A wild instruction, */
3509 /* See the peeph.def file for additional examples */
3511 /*-----------------------------------------------------------------*/
3513 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3518 pcw = Safe_calloc(1,sizeof(pCodeWild));
3520 pcw->pci.pc.type = PC_WILD;
3521 pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3522 pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3523 pcw->pci.pc.pb = NULL;
3525 // pcw->pci.pc.analyze = genericAnalyze;
3526 pcw->pci.pc.destruct = genericDestruct;
3527 pcw->pci.pc.print = genericPrint;
3529 pcw->id = pCodeID; // this is the 'n' in %n
3530 pcw->operand = optional_operand;
3531 pcw->label = optional_label;
3533 pcw->mustBeBitSkipInst = 0;
3534 pcw->mustNotBeBitSkipInst = 0;
3535 pcw->invertBitSkipInst = 0;
3537 return ( (pCode *)pcw);
3541 /*-----------------------------------------------------------------*/
3542 /* newPcodeInlineP - create a new pCode from a char string */
3543 /*-----------------------------------------------------------------*/
3546 pCode *pic16_newpCodeInlineP(char *cP)
3551 pcc = Safe_calloc(1,sizeof(pCodeComment));
3553 pcc->pc.type = PC_INLINE;
3554 pcc->pc.prev = pcc->pc.next = NULL;
3555 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3558 // pcc->pc.analyze = genericAnalyze;
3559 pcc->pc.destruct = genericDestruct;
3560 pcc->pc.print = genericPrint;
3563 pcc->comment = Safe_strdup(cP);
3565 pcc->comment = NULL;
3567 return ( (pCode *)pcc);
3571 /*-----------------------------------------------------------------*/
3572 /* newPcodeCharP - create a new pCode from a char string */
3573 /*-----------------------------------------------------------------*/
3575 pCode *pic16_newpCodeCharP(char *cP)
3580 pcc = Safe_calloc(1,sizeof(pCodeComment));
3582 pcc->pc.type = PC_COMMENT;
3583 pcc->pc.prev = pcc->pc.next = NULL;
3584 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3587 // pcc->pc.analyze = genericAnalyze;
3588 pcc->pc.destruct = genericDestruct;
3589 pcc->pc.print = genericPrint;
3592 pcc->comment = Safe_strdup(cP);
3594 pcc->comment = NULL;
3596 return ( (pCode *)pcc);
3600 /*-----------------------------------------------------------------*/
3601 /* pic16_newpCodeFunction - */
3602 /*-----------------------------------------------------------------*/
3605 pCode *pic16_newpCodeFunction(char *mod,char *f)
3609 pcf = Safe_calloc(1,sizeof(pCodeFunction));
3611 pcf->pc.type = PC_FUNCTION;
3612 pcf->pc.prev = pcf->pc.next = NULL;
3613 //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3616 // pcf->pc.analyze = genericAnalyze;
3617 pcf->pc.destruct = genericDestruct;
3618 pcf->pc.print = pCodePrintFunction;
3624 pcf->modname = Safe_calloc(1,strlen(mod)+1);
3625 strcpy(pcf->modname,mod);
3627 pcf->modname = NULL;
3630 pcf->fname = Safe_calloc(1,strlen(f)+1);
3631 strcpy(pcf->fname,f);
3635 pcf->stackusage = 0;
3637 return ( (pCode *)pcf);
3640 /*-----------------------------------------------------------------*/
3641 /* pic16_newpCodeFlow */
3642 /*-----------------------------------------------------------------*/
3643 static void destructpCodeFlow(pCode *pc)
3645 if(!pc || !isPCFL(pc))
3652 pic16_unlinkpCode(pc);
3654 deleteSet(&PCFL(pc)->registers);
3655 deleteSet(&PCFL(pc)->from);
3656 deleteSet(&PCFL(pc)->to);
3658 /* Instead of deleting the memory used by this pCode, mark
3659 * the object as bad so that if there's a pointer to this pCode
3660 * dangling around somewhere then (hopefully) when the type is
3661 * checked we'll catch it.
3665 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3671 pCode *pic16_newpCodeFlow(void )
3675 //_ALLOC(pcflow,sizeof(pCodeFlow));
3676 pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3678 pcflow->pc.type = PC_FLOW;
3679 pcflow->pc.prev = pcflow->pc.next = NULL;
3680 pcflow->pc.pb = NULL;
3682 // pcflow->pc.analyze = genericAnalyze;
3683 pcflow->pc.destruct = destructpCodeFlow;
3684 pcflow->pc.print = genericPrint;
3686 pcflow->pc.seq = GpcFlowSeq++;
3688 pcflow->from = pcflow->to = NULL;
3690 pcflow->inCond = PCC_NONE;
3691 pcflow->outCond = PCC_NONE;
3693 pcflow->firstBank = -1;
3694 pcflow->lastBank = -1;
3696 pcflow->FromConflicts = 0;
3697 pcflow->ToConflicts = 0;
3701 pcflow->registers = newSet();
3703 return ( (pCode *)pcflow);
3707 /*-----------------------------------------------------------------*/
3708 /*-----------------------------------------------------------------*/
3709 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3711 pCodeFlowLink *pcflowLink;
3713 pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3715 pcflowLink->pcflow = pcflow;
3716 pcflowLink->bank_conflict = 0;
3721 /*-----------------------------------------------------------------*/
3722 /* pic16_newpCodeCSource - create a new pCode Source Symbol */
3723 /*-----------------------------------------------------------------*/
3725 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3730 pccs = Safe_calloc(1,sizeof(pCodeCSource));
3732 pccs->pc.type = PC_CSOURCE;
3733 pccs->pc.prev = pccs->pc.next = NULL;
3736 pccs->pc.destruct = genericDestruct;
3737 pccs->pc.print = genericPrint;
3739 pccs->line_number = ln;
3741 pccs->line = Safe_strdup(l);
3746 pccs->file_name = Safe_strdup(f);
3748 pccs->file_name = NULL;
3750 return ( (pCode *)pccs);
3755 /*******************************************************************/
3756 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive */
3757 /* added by VR 6-Jun-2003 */
3758 /*******************************************************************/
3760 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3767 pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3768 pcad->pci.pc.type = PC_ASMDIR;
3769 pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3770 pcad->pci.pc.pb = NULL;
3771 pcad->pci.isize = 2;
3772 pcad->pci.pc.destruct = genericDestruct;
3773 pcad->pci.pc.print = genericPrint;
3775 if(asdir && *asdir) {
3777 while(isspace((unsigned char)*asdir))asdir++; // strip any white space from the beginning
3779 pcad->directive = Safe_strdup( asdir );
3782 va_start(ap, argfmt);
3784 memset(buffer, 0, sizeof(buffer));
3785 if(argfmt && *argfmt)
3786 vsprintf(buffer, argfmt, ap);
3790 while(isspace((unsigned char)*lbp))lbp++;
3793 pcad->arg = Safe_strdup( lbp );
3795 return ((pCode *)pcad);
3798 /*-----------------------------------------------------------------*/
3799 /* pCodeLabelDestruct - free memory used by a label. */
3800 /*-----------------------------------------------------------------*/
3801 static void pCodeLabelDestruct(pCode *pc)
3807 pic16_unlinkpCode(pc);
3809 // if((pc->type == PC_LABEL) && PCL(pc)->label)
3810 // Safe_free(PCL(pc)->label);
3812 /* Instead of deleting the memory used by this pCode, mark
3813 * the object as bad so that if there's a pointer to this pCode
3814 * dangling around somewhere then (hopefully) when the type is
3815 * checked we'll catch it.
3819 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3825 pCode *pic16_newpCodeLabel(char *name, int key)
3831 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3833 pcl->pc.type = PC_LABEL;
3834 pcl->pc.prev = pcl->pc.next = NULL;
3835 //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3838 // pcl->pc.analyze = genericAnalyze;
3839 pcl->pc.destruct = pCodeLabelDestruct;
3840 pcl->pc.print = pCodePrintLabel;
3847 sprintf(s,"_%05d_DS_",key);
3852 pcl->label = Safe_strdup(s);
3854 // if(pic16_pcode_verbose)
3855 // fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3858 return ( (pCode *)pcl);
3862 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3864 pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3868 return ( (pCode *)pcl );
3871 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3875 pci = Safe_calloc(1, sizeof(pCodeInfo));
3876 pci->pci.pc.type = PC_INFO;
3877 pci->pci.pc.prev = pci->pci.pc.next = NULL;
3878 pci->pci.pc.pb = NULL;
3879 pci->pci.label = NULL;
3881 pci->pci.pc.destruct = genericDestruct;
3882 pci->pci.pc.print = genericPrint;
3887 return ((pCode *)pci);
3891 /*-----------------------------------------------------------------*/
3892 /* newpBlock - create and return a pointer to a new pBlock */
3893 /*-----------------------------------------------------------------*/
3894 static pBlock *newpBlock(void)
3899 PpB = Safe_calloc(1,sizeof(pBlock) );
3900 PpB->next = PpB->prev = NULL;
3902 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3903 PpB->tregisters = NULL;
3905 PpB->FlowTree = NULL;
3911 /*-----------------------------------------------------------------*/
3912 /* pic16_newpCodeChain - create a new chain of pCodes */
3913 /*-----------------------------------------------------------------*
3915 * This function will create a new pBlock and the pointer to the
3916 * pCode that is passed in will be the first pCode in the block.
3917 *-----------------------------------------------------------------*/
3920 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3923 pBlock *pB = newpBlock();
3925 pB->pcHead = pB->pcTail = pc;
3934 /*-----------------------------------------------------------------*/
3935 /* pic16_newpCodeOpLabel - Create a new label given the key */
3936 /* Note, a negative key means that the label is part of wild card */
3937 /* (and hence a wild card label) used in the pCodePeep */
3938 /* optimizations). */
3939 /*-----------------------------------------------------------------*/
3941 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
3944 static int label_key=-1;
3948 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
3949 pcop->type = PO_LABEL;
3954 sprintf(s=buffer,"_%05d_DS_",key);
3956 s = name, key = label_key--;
3959 pcop->name = Safe_strdup(s);
3961 ((pCodeOpLabel *)pcop)->key = key;
3963 //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
3967 /*-----------------------------------------------------------------*/
3968 /*-----------------------------------------------------------------*/
3969 pCodeOp *pic16_newpCodeOpLit(int lit)
3975 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
3976 pcop->type = PO_LITERAL;
3980 sprintf(s,"0x%02hhx", (unsigned char)lit);
3982 // sprintf(s, "%i", lit);
3985 pcop->name = Safe_strdup(s);
3987 ((pCodeOpLit *)pcop)->lit = lit;
3992 /* Allow for 12 bit literals, required for LFSR */
3993 pCodeOp *pic16_newpCodeOpLit12(int lit)
3999 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4000 pcop->type = PO_LITERAL;
4004 sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4006 // sprintf(s, "%i", lit);
4009 pcop->name = Safe_strdup(s);
4011 ((pCodeOpLit *)pcop)->lit = lit;
4016 /*-----------------------------------------------------------------*/
4017 /*-----------------------------------------------------------------*/
4018 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4020 char *s = buffer, tbuf[256], *tb=tbuf;
4024 tb = pic16_get_op(arg2, NULL, 0);
4025 pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4026 pcop->type = PO_LITERAL;
4030 sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4032 pcop->name = Safe_strdup(s);
4035 ((pCodeOpLit2 *)pcop)->lit = lit;
4036 ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4041 /*-----------------------------------------------------------------*/
4042 /*-----------------------------------------------------------------*/
4043 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4047 pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4048 pcop->type = PO_IMMEDIATE;
4050 regs *r = pic16_dirregWithName(name);
4051 pcop->name = Safe_strdup(name);
4055 // fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4056 PCOI(pcop)->rIdx = r->rIdx;
4058 // fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4059 PCOI(pcop)->rIdx = -1;
4061 // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4064 PCOI(pcop)->rIdx = -1;
4067 PCOI(pcop)->index = index;
4068 PCOI(pcop)->offset = offset;
4069 PCOI(pcop)->_const = code_space;
4074 /*-----------------------------------------------------------------*/
4075 /*-----------------------------------------------------------------*/
4076 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4082 if(!pcwb || !subtype) {
4083 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4087 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4088 pcop->type = PO_WILD;
4089 sprintf(s,"%%%d",id);
4090 pcop->name = Safe_strdup(s);
4092 PCOW(pcop)->id = id;
4093 PCOW(pcop)->pcwb = pcwb;
4094 PCOW(pcop)->subtype = subtype;
4095 PCOW(pcop)->matched = NULL;
4097 PCOW(pcop)->pcop2 = NULL;
4102 /*-----------------------------------------------------------------*/
4103 /*-----------------------------------------------------------------*/
4104 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4110 if(!pcwb || !subtype || !subtype2) {
4111 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4115 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4116 pcop->type = PO_WILD;
4117 sprintf(s,"%%%d",id);
4118 pcop->name = Safe_strdup(s);
4120 PCOW(pcop)->id = id;
4121 PCOW(pcop)->pcwb = pcwb;
4122 PCOW(pcop)->subtype = subtype;
4123 PCOW(pcop)->matched = NULL;
4125 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4127 if(!subtype2->name) {
4128 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4129 PCOW2(pcop)->pcop.type = PO_WILD;
4130 sprintf(s, "%%%d", id2);
4131 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4132 PCOW2(pcop)->id = id2;
4133 PCOW2(pcop)->subtype = subtype2;
4135 // fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4136 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4138 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4140 // fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4141 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4150 /*-----------------------------------------------------------------*/
4151 /*-----------------------------------------------------------------*/
4152 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4156 pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4157 pcop->type = PO_GPR_BIT;
4159 pcop->name = Safe_strdup(s);
4163 PCORB(pcop)->bit = bit;
4164 PCORB(pcop)->inBitSpace = inBitSpace;
4165 PCORB(pcop)->subtype = subt;
4167 /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4168 PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4169 // fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4170 // PCOR(pcop)->rIdx = 0;
4174 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4176 return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4177 bit, 0, PO_GPR_REGISTER);
4181 /*-----------------------------------------------------------------*
4182 * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4184 * If rIdx >=0 then a specific register from the set of registers
4185 * will be selected. If rIdx <0, then a new register will be searched
4187 *-----------------------------------------------------------------*/
4189 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4194 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4199 r = pic16_regWithIdx(rIdx);
4201 r = pic16_allocWithIdx(rIdx);
4203 r = pic16_findFreeReg(REG_GPR);
4206 fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4207 __FUNCTION__, __LINE__);
4212 PCOR(pcop)->rIdx = rIdx;
4214 pcop->type = PCOR(pcop)->r->pc_type;
4219 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4224 pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4227 r = pic16_findFreeReg(REG_GPR);
4230 if(!bitVectBitValue(bv, r->rIdx)) {
4232 PCOR(pcop)->rIdx = r->rIdx;
4233 pcop->type = r->pc_type;
4237 r = pic16_findFreeRegNext(REG_GPR, r);
4245 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4250 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4251 PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4252 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4253 pcop->type = PCOR(pcop)->r->pc_type;
4254 pcop->name = PCOR(pcop)->r->name;
4256 // if(pic16_pcode_verbose) {
4257 // fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4258 // __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4264 /*-----------------------------------------------------------------*/
4265 /*-----------------------------------------------------------------*/
4266 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4270 pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4273 pcop->key = Safe_strdup( key );
4275 return (PCOP(pcop));
4278 /*-----------------------------------------------------------------*/
4279 /*-----------------------------------------------------------------*/
4280 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4282 pCodeOpLocalReg *pcop;
4284 pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4288 return (PCOP(pcop));
4292 /*-----------------------------------------------------------------*/
4293 /*-----------------------------------------------------------------*/
4295 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4302 pcop = pic16_newpCodeOpBit(name, -1,0, type);
4306 pcop = pic16_newpCodeOpLit(-1);
4310 pcop = pic16_newpCodeOpLabel(NULL,-1);
4313 pcop = pic16_newpCodeOpReg(-1);
4316 case PO_GPR_REGISTER:
4318 pcop = pic16_newpCodeOpRegFromStr(name);
4320 pcop = pic16_newpCodeOpReg(-1);
4324 assert( !"Cannot create PO_TWO_OPS from string!" );
4329 pcop = Safe_calloc(1,sizeof(pCodeOp) );
4332 pcop->name = Safe_strdup(name);
4340 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4342 pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4343 pcop2->pcop.type = PO_TWO_OPS;
4349 /* This is a multiple of two as gpasm pads DB directives to even length,
4350 * thus the data would be interleaved with \0 bytes...
4351 * This is a multiple of three in order to have arrays of 3-byte pointers
4352 * continuously in memory (without 0-padding at the lines' end).
4353 * This is rather 12 than 6 in order not to split up 4-byte data types
4354 * in arrays right in the middle of a 4-byte word. */
4355 #define DB_ITEMS_PER_LINE 12
4357 typedef struct DBdata
4364 static int DBd_init = -1;
4366 /*-----------------------------------------------------------------*/
4367 /* Initialiase "DB" data buffer */
4368 /*-----------------------------------------------------------------*/
4369 void pic16_initDB(void)
4375 /*-----------------------------------------------------------------*/
4376 /* Flush pending "DB" data to a pBlock */
4378 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4379 /*-----------------------------------------------------------------*/
4380 void pic16_flushDB(char ptype, void *p)
4384 pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4387 fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4390 fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4394 DBd.buffer[0] = '\0';
4399 /*-----------------------------------------------------------------*/
4400 /* Add "DB" directives to a pBlock */
4401 /*-----------------------------------------------------------------*/
4402 void pic16_emitDB(int c, char ptype, void *p)
4407 // we need to initialize
4410 DBd.buffer[0] = '\0';
4413 l = strlen(DBd.buffer);
4414 sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4416 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4419 if (DBd.count>= DB_ITEMS_PER_LINE)
4420 pic16_flushDB(ptype, p);
4423 void pic16_emitDS(char *s, char ptype, void *p)
4428 // we need to initialize
4431 DBd.buffer[0] = '\0';
4434 l = strlen(DBd.buffer);
4435 sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4437 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4439 DBd.count++; //=strlen(s);
4440 if (DBd.count>=DB_ITEMS_PER_LINE)
4441 pic16_flushDB(ptype, p);
4445 /*-----------------------------------------------------------------*/
4446 /*-----------------------------------------------------------------*/
4447 void pic16_pCodeConstString(char *name, char *value, unsigned length)
4451 static set *emittedSymbols = NULL;
4456 /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4457 if (emittedSymbols) {
4458 /* scan set for name */
4459 for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4461 if (!strcmp (item,name)) {
4462 //fprintf (stderr, "%s already emitted\n", name);
4467 addSet (&emittedSymbols, Safe_strdup (name));
4469 //fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value);
4471 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4473 pic16_addpBlock(pb);
4475 // sprintf(buffer,"; %s = ", name);
4476 // strcat(buffer, value);
4477 // fputs(buffer, stderr);
4479 // pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4480 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4483 pic16_emitDB(*value++, 'p', (void *)pb);
4485 pic16_flushDB('p', (void *)pb);
4488 /*-----------------------------------------------------------------*/
4489 /*-----------------------------------------------------------------*/
4491 static void pCodeReadCodeTable(void)
4495 fprintf(stderr, " %s\n",__FUNCTION__);
4497 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4499 pic16_addpBlock(pb);
4501 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4502 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4503 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4504 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4506 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4507 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4508 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4509 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4514 /*-----------------------------------------------------------------*/
4515 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */
4516 /*-----------------------------------------------------------------*/
4517 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4524 /* If this is the first pcode to be added to a block that
4525 * was initialized with a NULL pcode, then go ahead and
4526 * make this pcode the head and tail */
4527 pb->pcHead = pb->pcTail = pc;
4530 pb->pcTail->next = pc;
4532 pc->prev = pb->pcTail;
4539 /*-----------------------------------------------------------------*/
4540 /* pic16_addpBlock - place a pBlock into the pFile */
4541 /*-----------------------------------------------------------------*/
4542 void pic16_addpBlock(pBlock *pb)
4544 // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4547 /* First time called, we'll pass through here. */
4548 //_ALLOC(the_pFile,sizeof(pFile));
4549 the_pFile = Safe_calloc(1,sizeof(pFile));
4550 the_pFile->pbHead = the_pFile->pbTail = pb;
4551 the_pFile->functions = NULL;
4555 the_pFile->pbTail->next = pb;
4556 pb->prev = the_pFile->pbTail;
4558 the_pFile->pbTail = pb;
4561 /*-----------------------------------------------------------------*/
4562 /* removepBlock - remove a pBlock from the pFile */
4563 /*-----------------------------------------------------------------*/
4564 static void removepBlock(pBlock *pb)
4572 //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4574 for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4577 if(pbs == the_pFile->pbHead)
4578 the_pFile->pbHead = pbs->next;
4580 if (pbs == the_pFile->pbTail)
4581 the_pFile->pbTail = pbs->prev;
4584 pbs->next->prev = pbs->prev;
4587 pbs->prev->next = pbs->next;
4594 fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4598 /*-----------------------------------------------------------------*/
4599 /* printpCode - write the contents of a pCode to a file */
4600 /*-----------------------------------------------------------------*/
4601 static void printpCode(FILE *of, pCode *pc)
4612 fprintf(of,"warning - unable to print pCode\n");
4615 /*-----------------------------------------------------------------*/
4616 /* pic16_printpBlock - write the contents of a pBlock to a file */
4617 /*-----------------------------------------------------------------*/
4618 void pic16_printpBlock(FILE *of, pBlock *pb)
4626 for(pc = pb->pcHead; pc; pc = pc->next) {
4627 if(isPCF(pc) && PCF(pc)->fname) {
4628 fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4629 if(pb->dbName == 'A') {
4631 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4632 // fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4633 if(!strcmp(ab->name, PCF(pc)->fname)) {
4634 // fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4635 if(ab->address != -1)
4636 fprintf(of, "\t0X%06X", ab->address);
4647 /*-----------------------------------------------------------------*/
4649 /* pCode processing */
4653 /*-----------------------------------------------------------------*/
4654 pCode * pic16_findNextInstruction(pCode *pci);
4655 pCode * pic16_findPrevInstruction(pCode *pci);
4657 void pic16_unlinkpCode(pCode *pc)
4663 fprintf(stderr,"Unlinking: ");
4664 printpCode(stderr, pc);
4667 pc->prev->next = pc->next;
4668 } else if (pc->pb && (pc->pb->pcHead == pc)) {
4669 pc->pb->pcHead = pc->next;
4672 pc->next->prev = pc->prev;
4673 } else if (pc->pb && (pc->pb->pcTail == pc)) {
4674 pc->pb->pcTail = pc->prev;
4677 /* move C source line down (or up) */
4678 if (isPCI(pc) && PCI(pc)->cline) {
4679 prev = pic16_findNextInstruction (pc->next);
4680 if (prev && isPCI(prev) && !PCI(prev)->cline) {
4681 PCI(prev)->cline = PCI(pc)->cline;
4683 prev = pic16_findPrevInstruction (pc->prev);
4684 if (prev && isPCI(prev) && !PCI(prev)->cline)
4685 PCI(prev)->cline = PCI(pc)->cline;
4688 pc->prev = pc->next = NULL;
4692 /*-----------------------------------------------------------------*/
4693 /*-----------------------------------------------------------------*/
4695 static void genericDestruct(pCode *pc)
4698 pic16_unlinkpCode(pc);
4701 /* For instructions, tell the register (if there's one used)
4702 * that it's no longer needed */
4703 regs *reg = pic16_getRegFromInstruction(pc);
4705 deleteSetItem (&(reg->reglives.usedpCodes),pc);
4707 if(PCI(pc)->is2MemOp) {
4708 reg = pic16_getRegFromInstruction2(pc);
4710 deleteSetItem(&(reg->reglives.usedpCodes), pc);
4714 /* Instead of deleting the memory used by this pCode, mark
4715 * the object as bad so that if there's a pointer to this pCode
4716 * dangling around somewhere then (hopefully) when the type is
4717 * checked we'll catch it.
4721 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4727 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4728 /*-----------------------------------------------------------------*/
4729 /*-----------------------------------------------------------------*/
4730 /* modifiers for constant immediate */
4731 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4733 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4738 int use_buffer = 1; // copy the string to the passed buffer pointer
4743 use_buffer = 0; // Don't bother copying the string to the buffer.
4748 switch(pcop->type) {
4756 SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
4759 return (PCOR(pcop)->r->name);
4762 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4764 SNPRINTF(buffer,size,"%s",r->name);
4772 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4773 if(PCOI(pcop)->index) {
4774 SNPRINTF(s,size, "%s(%s + %d)",
4775 immdmod[ PCOI(pcop)->offset ],
4779 SNPRINTF(s,size,"%s(%s)",
4780 immdmod[ PCOI(pcop)->offset ],
4784 if(PCOI(pcop)->index) {
4785 SNPRINTF(s,size, "%s(%s + %d)",
4790 SNPRINTF(s,size, "%s(%s)",
4798 case PO_GPR_REGISTER:
4801 //size = sizeof(buffer);
4802 if( PCOR(pcop)->instance) {
4803 SNPRINTF(s,size,"(%s + %d)",
4805 PCOR(pcop)->instance );
4807 SNPRINTF(s,size,"%s",pcop->name);
4814 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4815 SNPRINTF(s, size, "%s", pcop->name);
4817 if(PCORB(pcop)->pcor.instance)
4818 SNPRINTF(s, size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4820 SNPRINTF(s, size, "%s", pcop->name);
4826 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4832 SNPRINTF(buffer,size,"%s",pcop->name);
4835 return (pcop->name);
4839 return ("unhandled type for op1");
4842 return ("NO operand1");
4845 /*-----------------------------------------------------------------*/
4846 /* pic16_get_op2 - variant to support two memory operand commands */
4847 /*-----------------------------------------------------------------*/
4848 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4851 if(pcop && pcop->type == PO_TWO_OPS) {
4852 return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4855 return "NO operand2";
4858 /*-----------------------------------------------------------------*/
4859 /*-----------------------------------------------------------------*/
4860 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4864 return pic16_get_op(pcc->pcop,NULL,0);
4866 /* gcc 3.2: warning: concatenation of string literals with __FUNCTION__ is deprecated
4867 * return ("ERROR Null: "__FUNCTION__);
4869 return ("ERROR Null: pic16_get_op_from_instruction");
4873 /*-----------------------------------------------------------------*/
4874 /*-----------------------------------------------------------------*/
4875 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4878 fprintf(of,"pcodeopprint- not implemented\n");
4881 /*-----------------------------------------------------------------*/
4882 /* pic16_pCode2str - convert a pCode instruction to string */
4883 /*-----------------------------------------------------------------*/
4884 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4890 if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4891 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4892 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4893 // exit(EXIT_FAILURE);
4900 SNPRINTF(s, size, "\t%s\t", PCI(pc)->mnemonic);
4904 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4906 if (PCI(pc)->pcop->type == PO_TWO_OPS)
4908 /* split into two phases due to static buffer in pic16_get_op() */
4909 SNPRINTF(s, size, "%s",
4910 pic16_get_op((PCI(pc)->pcop), NULL, 0));
4913 SNPRINTF(s, size, ", %s",
4914 pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4918 if(PCI(pc)->is2LitOp) {
4919 SNPRINTF(s,size, "%s", PCOP(PCI(pc)->pcop)->name);
4923 if(PCI(pc)->isBitInst) {
4924 if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4925 if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4926 SNPRINTF(s,size,"(%s >> 3), (%s & 7)",
4927 PCI(pc)->pcop->name ,
4928 PCI(pc)->pcop->name );
4930 SNPRINTF(s,size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4931 (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4933 } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4934 SNPRINTF(s,size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
4936 SNPRINTF(s,size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
4939 if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4940 if( PCI(pc)->num_ops == 3)
4941 SNPRINTF(s,size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
4943 SNPRINTF(s,size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
4945 SNPRINTF(s,size,"%s", pic16_get_op_from_instruction(PCI(pc)));
4949 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
4952 if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst) {
4953 SNPRINTF(s,size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
4958 r = pic16_getRegFromInstruction(pc);
4960 if(PCI(pc)->isAccess) {
4961 static char *bank_spec[2][2] = {
4962 { "", ", ACCESS" }, /* gpasm uses access bank by default */
4963 { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
4966 SNPRINTF(s,size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
4973 /* assuming that comment ends with a \n */
4974 SNPRINTF(s,size,";%s", ((pCodeComment *)pc)->comment);
4978 SNPRINTF(s,size,"; info ==>");
4981 switch( PCINF(pc)->type ) {
4982 case INF_OPTIMIZATION:
4983 SNPRINTF(s,size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
4986 SNPRINTF(s,size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
4991 /* assuming that inline code ends with a \n */
4992 SNPRINTF(s,size,"%s", ((pCodeComment *)pc)->comment);
4996 SNPRINTF(s,size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
4999 SNPRINTF(s,size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5002 SNPRINTF(s,size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5005 SNPRINTF(s,size,";\t--FLOW change\n");
5008 SNPRINTF(s,size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5009 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5012 if(PCAD(pc)->directive) {
5013 SNPRINTF(s,size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5016 /* special case to handle inline labels without a tab */
5017 SNPRINTF(s,size,"%s\n", PCAD(pc)->arg);
5022 SNPRINTF(s,size,";A bad pCode is being used\n");
5029 /*-----------------------------------------------------------------*/
5030 /* genericPrint - the contents of a pCode to a file */
5031 /*-----------------------------------------------------------------*/
5032 static void genericPrint(FILE *of, pCode *pc)
5040 // fputs(((pCodeComment *)pc)->comment, of);
5041 fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5046 pBranch *pbl = PCI(pc)->label;
5047 while(pbl && pbl->pc) {
5048 if(pbl->pc->type == PC_LABEL)
5049 pCodePrintLabel(of, pbl->pc);
5054 if(pic16_pcode_verbose) {
5055 fprintf(of, "; info ==>");
5056 switch(((pCodeInfo *)pc)->type) {
5057 case INF_OPTIMIZATION:
5058 fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5061 fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5069 fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5073 // If the opcode has a label, print that first
5075 pBranch *pbl = PCI(pc)->label;
5076 while(pbl && pbl->pc) {
5077 if(pbl->pc->type == PC_LABEL)
5078 pCodePrintLabel(of, pbl->pc);
5084 genericPrint(of,PCODE(PCI(pc)->cline));
5089 pic16_pCode2str(str, 256, pc);
5091 fprintf(of,"%s",str);
5093 if(pic16_debug_verbose) {
5094 fprintf(of, "\t;key=%03x",pc->seq);
5096 fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5103 fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5104 if(PCW(pc)->pci.label)
5105 pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5107 if(PCW(pc)->operand) {
5108 fprintf(of,";\toperand ");
5109 pCodeOpPrint(of,PCW(pc)->operand );
5114 if(pic16_debug_verbose) {
5115 fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5116 if(PCFL(pc)->ancestor)
5117 fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5124 // fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5125 fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5126 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5132 pBranch *pbl = PCAD(pc)->pci.label;
5133 while(pbl && pbl->pc) {
5134 if(pbl->pc->type == PC_LABEL)
5135 pCodePrintLabel(of, pbl->pc);
5139 if(PCAD(pc)->directive) {
5140 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5143 /* special case to handle inline labels without tab */
5144 fprintf(of, "%s\n", PCAD(pc)->arg);
5150 fprintf(of,"unknown pCode type %d\n",pc->type);
5155 /*-----------------------------------------------------------------*/
5156 /* pCodePrintFunction - prints function begin/end */
5157 /*-----------------------------------------------------------------*/
5159 static void pCodePrintFunction(FILE *of, pCode *pc)
5166 if( ((pCodeFunction *)pc)->modname)
5167 fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5170 if(!PCF(pc)->absblock) {
5171 if(PCF(pc)->fname) {
5172 pBranch *exits = PCF(pc)->to;
5175 fprintf(of,"%s:", PCF(pc)->fname);
5177 if(pic16_pcode_verbose)
5178 fprintf(of, "\t;Function start");
5184 exits = exits->next;
5188 if(pic16_pcode_verbose)
5189 fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5192 if((PCF(pc)->from &&
5193 PCF(pc)->from->pc->type == PC_FUNCTION &&
5194 PCF(PCF(pc)->from->pc)->fname) ) {
5196 if(pic16_pcode_verbose)
5197 fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5199 if(pic16_pcode_verbose)
5200 fprintf(of,"; exit point [can't find entry point]\n");
5206 /*-----------------------------------------------------------------*/
5207 /* pCodePrintLabel - prints label */
5208 /*-----------------------------------------------------------------*/
5210 static void pCodePrintLabel(FILE *of, pCode *pc)
5217 fprintf(of,"%s:\n",PCL(pc)->label);
5218 else if (PCL(pc)->key >=0)
5219 fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5221 fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5224 /*-----------------------------------------------------------------*/
5225 /* unlinkpCodeFromBranch - Search for a label in a pBranch and */
5226 /* remove it if it is found. */
5227 /*-----------------------------------------------------------------*/
5228 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5235 if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5236 b = PCI(pcl)->label;
5238 fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5243 //fprintf (stderr, "%s \n",__FUNCTION__);
5244 //pcl->print(stderr,pcl);
5245 //pc->print(stderr,pc);
5248 //fprintf (stderr, "found label\n");
5249 //pc->print(stderr, pc);
5253 bprev->next = b->next; /* Not first pCode in chain */
5257 PCI(pcl)->label = b->next; /* First pCode in chain */
5260 return; /* A label can't occur more than once */
5268 /*-----------------------------------------------------------------*/
5269 /*-----------------------------------------------------------------*/
5270 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5289 /*-----------------------------------------------------------------*/
5290 /* pBranchLink - given two pcodes, this function will link them */
5291 /* together through their pBranches */
5292 /*-----------------------------------------------------------------*/
5293 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5297 // Declare a new branch object for the 'from' pCode.
5299 //_ALLOC(b,sizeof(pBranch));
5300 b = Safe_calloc(1,sizeof(pBranch));
5301 b->pc = PCODE(t); // The link to the 'to' pCode.
5304 f->to = pic16_pBranchAppend(f->to,b);
5306 // Now do the same for the 'to' pCode.
5308 //_ALLOC(b,sizeof(pBranch));
5309 b = Safe_calloc(1,sizeof(pBranch));
5313 t->from = pic16_pBranchAppend(t->from,b);
5318 /*-----------------------------------------------------------------*/
5319 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5321 /*-----------------------------------------------------------------*/
5322 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5335 /*-----------------------------------------------------------------*/
5336 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain. */
5337 /*-----------------------------------------------------------------*/
5338 void pic16_pCodeUnlink(pCode *pc)
5347 /* Remove the branches */
5349 pb1 = PCI(pc)->from;
5351 pc1 = pb1->pc; /* Get the pCode that branches to the
5352 * one we're unlinking */
5354 /* search for the link back to this pCode (the one we're
5356 if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5357 pb2->pc = PCI(pc)->to->pc; // make the replacement
5359 /* if the pCode we're unlinking contains multiple 'to'
5360 * branches (e.g. this a skip instruction) then we need
5361 * to copy these extra branches to the chain. */
5362 if(PCI(pc)->to->next)
5363 pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5369 pic16_unlinkpCode (pc);
5373 /*-----------------------------------------------------------------*/
5374 /*-----------------------------------------------------------------*/
5376 static void genericAnalyze(pCode *pc)
5386 // Go through the pCodes that are in pCode chain and link
5387 // them together through the pBranches. Note, the pCodes
5388 // are linked together as a contiguous stream like the
5389 // assembly source code lines. The linking here mimics this
5390 // except that comments are not linked in.
5392 pCode *npc = pc->next;
5394 if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5395 pBranchLink(pc,npc);
5400 /* reached the end of the pcode chain without finding
5401 * an instruction we could link to. */
5405 fprintf(stderr,"analyze PC_FLOW\n");
5409 fprintf(stderr,,";A bad pCode is being used\n");
5415 /*-----------------------------------------------------------------*/
5416 /*-----------------------------------------------------------------*/
5417 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5421 if(pc->type == PC_LABEL) {
5422 if( ((pCodeLabel *)pc)->key == pcop_label->key)
5425 if((pc->type == PC_OPCODE)
5426 || (pc->type == PC_ASMDIR)
5428 pbr = PCI(pc)->label;
5430 if(pbr->pc->type == PC_LABEL) {
5431 if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
5441 /*-----------------------------------------------------------------*/
5442 /*-----------------------------------------------------------------*/
5443 static int checkLabel(pCode *pc)
5447 if(pc && isPCI(pc)) {
5448 pbr = PCI(pc)->label;
5450 if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5460 /*-----------------------------------------------------------------*/
5461 /* findLabelinpBlock - Search the pCode for a particular label */
5462 /*-----------------------------------------------------------------*/
5463 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5470 for(pc = pb->pcHead; pc; pc = pc->next)
5471 if(compareLabel(pc,pcop_label))
5477 /*-----------------------------------------------------------------*/
5478 /* findLabel - Search the pCode for a particular label */
5479 /*-----------------------------------------------------------------*/
5480 static pCode * findLabel(pCodeOpLabel *pcop_label)
5488 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5489 if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5493 fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5497 /*-----------------------------------------------------------------*/
5498 /* pic16_findNextpCode - given a pCode, find the next of type 'pct' */
5499 /* in the linked list */
5500 /*-----------------------------------------------------------------*/
5501 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5514 /*-----------------------------------------------------------------*/
5515 /* findPrevpCode - given a pCode, find the previous of type 'pct' */
5516 /* in the linked list */
5517 /*-----------------------------------------------------------------*/
5518 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5532 //#define PCODE_DEBUG
5533 /*-----------------------------------------------------------------*/
5534 /* pic16_findNextInstruction - given a pCode, find the next instruction */
5535 /* in the linked list */
5536 /*-----------------------------------------------------------------*/
5537 pCode * pic16_findNextInstruction(pCode *pci)
5542 if((pc->type == PC_OPCODE)
5543 || (pc->type == PC_WILD)
5544 || (pc->type == PC_ASMDIR)
5549 fprintf(stderr,"pic16_findNextInstruction: ");
5550 printpCode(stderr, pc);
5555 //fprintf(stderr,"Couldn't find instruction\n");
5559 /*-----------------------------------------------------------------*/
5560 /* pic16_findPrevInstruction - given a pCode, find the next instruction */
5561 /* in the linked list */
5562 /*-----------------------------------------------------------------*/
5563 pCode * pic16_findPrevInstruction(pCode *pci)
5569 if((pc->type == PC_OPCODE)
5570 || (pc->type == PC_WILD)
5571 || (pc->type == PC_ASMDIR)
5577 fprintf(stderr,"pic16_findPrevInstruction: ");
5578 printpCode(stderr, pc);
5583 //fprintf(stderr,"Couldn't find instruction\n");
5590 /*-----------------------------------------------------------------*/
5591 /* findFunctionEnd - given a pCode find the end of the function */
5592 /* that contains it */
5593 /*-----------------------------------------------------------------*/
5594 static pCode * findFunctionEnd(pCode *pc)
5598 if(pc->type == PC_FUNCTION && !(PCF(pc)->fname))
5604 fprintf(stderr,"Couldn't find function end\n");
5609 /*-----------------------------------------------------------------*/
5610 /* AnalyzeLabel - if the pCode is a label, then merge it with the */
5611 /* instruction with which it is associated. */
5612 /*-----------------------------------------------------------------*/
5613 static void AnalyzeLabel(pCode *pc)
5616 pic16_pCodeUnlink(pc);
5622 static void AnalyzeGOTO(pCode *pc)
5625 pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5629 static void AnalyzeSKIP(pCode *pc)
5632 pBranchLink(pc,pic16_findNextInstruction(pc->next));
5633 pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5637 static void AnalyzeRETURN(pCode *pc)
5640 // branch_link(pc,findFunctionEnd(pc->next));
5646 /*-------------------------------------------------------------------*/
5647 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp */
5648 /* if one is present. This is the common */
5649 /* part of pic16_getRegFromInstruction(2) */
5650 /*-------------------------------------------------------------------*/
5652 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5653 if (!pcop) return NULL;
5655 switch(pcop->type) {
5668 return PCOR(pcop)->r;
5670 case PO_SFR_REGISTER:
5671 //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5672 return PCOR(pcop)->r;
5676 // fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5677 return PCOR(pcop)->r;
5680 // return pic16_dirregWithName(PCOI(pcop)->r->name);
5683 return (PCOI(pcop)->r);
5688 return PCOR(pcop)->r;
5690 case PO_GPR_REGISTER:
5692 // fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5693 return PCOR(pcop)->r;
5696 //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5701 //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5706 /* this should never turn up */
5707 //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5714 return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5718 fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5726 /*-----------------------------------------------------------------*/
5727 /*-----------------------------------------------------------------*/
5728 regs * pic16_getRegFromInstruction(pCode *pc)
5733 PCI(pc)->num_ops == 0 ||
5734 (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5738 fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5739 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5742 return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5745 /*-------------------------------------------------------------------------------*/
5746 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5747 /*-------------------------------------------------------------------------------*/
5748 regs * pic16_getRegFromInstruction2(pCode *pc)
5754 PCI(pc)->num_ops == 0 ||
5755 (PCI(pc)->num_ops == 1)) // accept only 2 operand commands
5758 if (PCI(pc)->pcop->type != PO_TWO_OPS)
5762 fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5763 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5766 return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5769 /*-----------------------------------------------------------------*/
5770 /*-----------------------------------------------------------------*/
5772 static void AnalyzepBlock(pBlock *pb)
5779 /* Find all of the registers used in this pBlock
5780 * by looking at each instruction and examining it's
5783 for(pc = pb->pcHead; pc; pc = pc->next) {
5785 /* Is this an instruction with operands? */
5786 if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5788 if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5790 /* Loop through all of the registers declared so far in
5791 this block and see if we find this one there */
5793 regs *r = setFirstItem(pb->tregisters);
5796 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5797 PCOR(PCI(pc)->pcop)->r = r;
5800 r = setNextItem(pb->tregisters);
5804 /* register wasn't found */
5805 //r = Safe_calloc(1, sizeof(regs));
5806 //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5807 //addSet(&pb->tregisters, r);
5808 addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5809 //PCOR(PCI(pc)->pcop)->r = r;
5810 //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5812 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5815 if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5816 if(PCOR(PCI(pc)->pcop)->r) {
5817 pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx); /* FIXME! - VR */
5818 DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5820 if(PCI(pc)->pcop->name)
5821 fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5823 fprintf(stderr,"ERROR: NULL register\n");
5832 /*-----------------------------------------------------------------*/
5834 /*-----------------------------------------------------------------*/
5835 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5837 static void InsertpFlow(pCode *pc, pCode **pflow)
5840 PCFL(*pflow)->end = pc;
5842 if(!pc || !pc->next)
5845 *pflow = pic16_newpCodeFlow();
5846 pic16_pCodeInsertAfter(pc, *pflow);
5849 /*-----------------------------------------------------------------*/
5850 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5851 /* the flow blocks. */
5853 * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5854 * point the instruction flow changes.
5856 /*-----------------------------------------------------------------*/
5857 void pic16_BuildFlow(pBlock *pb)
5860 pCode *last_pci=NULL;
5867 //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq);
5868 /* Insert a pCodeFlow object at the beginning of a pBlock */
5870 InsertpFlow(pb->pcHead, &pflow);
5872 //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */
5873 //pflow->next = pb->pcHead; /* Make the current head the next object */
5874 //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */
5875 //pb->pcHead = pflow; /* Make the Flow object the head */
5878 for( pc = pic16_findNextInstruction(pb->pcHead);
5880 pc=pic16_findNextInstruction(pc)) {
5883 PCI(pc)->pcflow = PCFL(pflow);
5885 //fprintf(stderr," build: ");
5886 //pflow->print(stderr,pflow);
5888 if (checkLabel(pc)) {
5890 /* This instruction marks the beginning of a
5891 * new flow segment */
5896 /* If the previous pCode is not a flow object, then
5897 * insert a new flow object. (This check prevents
5898 * two consecutive flow objects from being insert in
5899 * the case where a skip instruction preceeds an
5900 * instruction containing a label.) */
5902 if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5903 InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5905 PCI(pc)->pcflow = PCFL(pflow);
5909 if( PCI(pc)->isSkip) {
5911 /* The two instructions immediately following this one
5912 * mark the beginning of a new flow segment */
5914 while(pc && PCI(pc)->isSkip) {
5916 PCI(pc)->pcflow = PCFL(pflow);
5920 InsertpFlow(pc, &pflow);
5921 pc=pic16_findNextInstruction(pc->next);
5929 PCI(pc)->pcflow = PCFL(pflow);
5931 InsertpFlow(pc, &pflow);
5933 } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) {
5935 InsertpFlow(pc, &pflow);
5943 //fprintf (stderr,",end seq %d",GpcFlowSeq);
5945 PCFL(pflow)->end = pb->pcTail;
5948 /*-------------------------------------------------------------------*/
5949 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5950 /* the flow blocks. */
5952 * unBuildFlow removes pCodeFlow objects from a pCode chain
5954 /*-----------------------------------------------------------------*/
5955 static void unBuildFlow(pBlock *pb)
5970 if(PCI(pc)->pcflow) {
5971 //Safe_free(PCI(pc)->pcflow);
5972 PCI(pc)->pcflow = NULL;
5975 } else if(isPCFL(pc) )
5984 /*-----------------------------------------------------------------*/
5985 /*-----------------------------------------------------------------*/
5986 static void dumpCond(int cond)
5989 static char *pcc_str[] = {
6003 int ncond = sizeof(pcc_str) / sizeof(char *);
6006 fprintf(stderr, "0x%04X\n",cond);
6008 for(i=0,j=1; i<ncond; i++, j<<=1)
6010 fprintf(stderr, " %s\n",pcc_str[i]);
6016 /*-----------------------------------------------------------------*/
6017 /*-----------------------------------------------------------------*/
6018 static void FlowStats(pCodeFlow *pcflow)
6026 fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6028 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6031 fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6036 fprintf(stderr, " FlowStats inCond: ");
6037 dumpCond(pcflow->inCond);
6038 fprintf(stderr, " FlowStats outCond: ");
6039 dumpCond(pcflow->outCond);
6043 /*-----------------------------------------------------------------*
6044 * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6045 * if it affects the banking bits.
6047 * return: -1 == Banking bits are unaffected by this pCode.
6049 * return: > 0 == Banking bits are affected.
6051 * If the banking bits are affected, then the returned value describes
6052 * which bits are affected and how they're affected. The lower half
6053 * of the integer maps to the bits that are affected, the upper half
6054 * to whether they're set or cleared.
6056 *-----------------------------------------------------------------*/
6058 static int isBankInstruction(pCode *pc)
6066 if( PCI(pc)->op == POC_MOVLB ||
6067 (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6068 bank = PCOL(pc)->lit;
6075 /*-----------------------------------------------------------------*/
6076 /*-----------------------------------------------------------------*/
6077 static void FillFlow(pCodeFlow *pcflow)
6086 // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6088 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6091 //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6098 isBankInstruction(pc);
6100 } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6104 fprintf(stderr, " FillFlow - Bad end of flow\n");
6106 fprintf(stderr, " FillFlow - Ending flow with\n ");
6107 pc->print(stderr,pc);
6110 fprintf(stderr, " FillFlow inCond: ");
6111 dumpCond(pcflow->inCond);
6112 fprintf(stderr, " FillFlow outCond: ");
6113 dumpCond(pcflow->outCond);
6117 /*-----------------------------------------------------------------*/
6118 /*-----------------------------------------------------------------*/
6119 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6121 pCodeFlowLink *fromLink, *toLink;
6123 if(!from || !to || !to->pcflow || !from->pcflow)
6126 fromLink = pic16_newpCodeFlowLink(from->pcflow);
6127 toLink = pic16_newpCodeFlowLink(to->pcflow);
6129 addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
6130 addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6134 pCode *pic16_getJumptabpCode (pCode *pc) {
6137 //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6138 //pc->print (stderr, pc);
6141 if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6142 if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6143 switch (PCOO(PCINF(pcinf)->oper1)->type) {
6144 case OPT_JUMPTABLE_BEGIN:
6145 /* leading begin of jump table -- in one */
6146 pcinf = pic16_findPrevInstruction (pcinf);
6150 case OPT_JUMPTABLE_END:
6151 /* leading end of jumptable -- not in one */
6156 /* ignore all other PCInfos */
6160 pcinf = pcinf->prev;
6163 /* no PCInfo found -- not in a jumptable */
6167 /*-----------------------------------------------------------------*
6168 * void LinkFlow(pBlock *pb)
6170 * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6171 * non-branching segments. In LinkFlow, we determine the execution
6172 * order of these segments. For example, if one of the segments ends
6173 * with a skip, then we know that there are two possible flow segments
6174 * to which control may be passed.
6175 *-----------------------------------------------------------------*/
6176 static void LinkFlow(pBlock *pb)
6181 pCode *jumptab_pre = NULL;
6183 //fprintf(stderr,"linkflow \n");
6185 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6187 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6190 fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6192 //fprintf(stderr," link: ");
6193 //pcflow->print(stderr,pcflow);
6195 //FillFlow(PCFL(pcflow));
6197 pc = PCFL(pcflow)->end;
6199 //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6200 if(isPCI_SKIP(pc)) {
6201 // fprintf(stderr, "ends with skip\n");
6202 // pc->print(stderr,pc);
6204 pct=pic16_findNextInstruction(pc->next);
6205 LinkFlow_pCode(PCI(pc),PCI(pct));
6206 pct=pic16_findNextInstruction(pct->next);
6207 LinkFlow_pCode(PCI(pc),PCI(pct));
6211 if(isPCI_BRANCH(pc)) {
6212 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6214 /* handle GOTOs in jumptables */
6215 if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6216 /* link to previous flow */
6217 //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6218 LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6221 switch (PCI(pc)->op) {
6227 /* unconditional branches -- do not link to next instruction */
6228 //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6233 /* unconditional calls -- link to next instruction */
6234 //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6235 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6246 /* conditional branches -- also link to next instruction */
6247 //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6248 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6252 fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6253 assert (0 && "unhandled branching instruction");
6257 //fprintf(stderr, "ends with branch\n ");
6258 //pc->print(stderr,pc);
6260 if(!(pcol && isPCOLAB(pcol))) {
6261 if((PCI(pc)->op != POC_RETLW)
6262 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6264 /* continue if label is '$' which assembler knows how to parse */
6265 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6267 if(pic16_pcode_verbose) {
6268 pc->print(stderr,pc);
6269 fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6275 if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6276 LinkFlow_pCode(PCI(pc),PCI(pct));
6278 fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6279 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6281 // fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6287 //fprintf(stderr, "ends with non-branching instruction:\n");
6288 //pc->print(stderr,pc);
6290 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6296 //fprintf(stderr, "ends with unknown\n");
6297 //pc->print(stderr,pc);
6301 //fprintf(stderr, "ends with nothing: ERROR\n");
6305 /*-----------------------------------------------------------------*/
6306 /*-----------------------------------------------------------------*/
6308 /*-----------------------------------------------------------------*/
6309 /*-----------------------------------------------------------------*/
6310 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6316 if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6319 if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6329 /*-----------------------------------------------------------------*/
6330 /* insertBankSwitch - inserts a bank switch statement in the */
6331 /* assembly listing */
6333 /* position == 0: insert before */
6334 /* position == 1: insert after pc */
6335 /* position == 2: like 0 but previous was a skip instruction */
6336 /*-----------------------------------------------------------------*/
6337 pCodeOp *pic16_popGetLabel(unsigned int key);
6338 extern int pic16_labelOffset;
6340 static void insertBankSwitch(unsigned char position, pCode *pc)
6347 /* emit BANKSEL [symbol] */
6350 new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6352 // position = 0; // position is always before (sanity check!)
6355 fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6356 pc->print(stderr, pc);
6361 /* insert the bank switch after this pc instruction */
6362 pCode *pcnext = pic16_findNextInstruction(pc);
6364 pic16_pCodeInsertAfter(pc, new_pc);
6365 if(pcnext)pc = pcnext;
6369 /* insert the bank switch BEFORE this pc instruction */
6370 pic16_pCodeInsertAfter(pc->prev, new_pc);
6375 pCode *pcnext, *pcprev, *npci, *ppc;
6377 int ofs1=0, ofs2=0, len=0;
6379 /* just like 0, but previous was a skip instruction,
6380 * so some care should be taken */
6382 pic16_labelOffset += 10000;
6383 tlbl = newiTempLabel(NULL);
6385 /* invert skip instruction */
6386 pcprev = pic16_findPrevInstruction(pc->prev);
6387 ipci = PCI(pcprev)->inverted_op;
6388 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6390 // fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6392 /* copy info from old pCode */
6393 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6394 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6395 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6396 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6397 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6398 PCI(npci)->op = PCI(pcprev)->inverted_op;
6400 /* unlink old pCode */
6402 ppc->next = pcprev->next;
6403 pcprev->next->prev = ppc;
6404 pic16_pCodeInsertAfter(ppc, npci);
6406 /* extra instructions to handle invertion */
6407 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6408 pic16_pCodeInsertAfter(npci, pcnext);
6409 pic16_pCodeInsertAfter(pc->prev, new_pc);
6411 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6412 pic16_pCodeInsertAfter(pc, pcnext);
6417 /* Move the label, if there is one */
6418 if(PCI(pc)->label) {
6419 // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6420 // __FILE__, __LINE__, pc, new_pc);
6421 PCAD(new_pc)->pci.label = PCI(pc)->label;
6422 PCI(pc)->label = NULL;
6427 /*-----------------------------------------------------------------*/
6428 /*int compareBankFlow - compare the banking requirements between */
6430 /*-----------------------------------------------------------------*/
6431 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6434 if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6437 if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6440 if(pcflow->firstBank == -1)
6444 if(pcflowLink->pcflow->firstBank == -1) {
6445 pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6446 pcflowLink->pcflow->to :
6447 pcflowLink->pcflow->from);
6448 return compareBankFlow(pcflow, pctl, toORfrom);
6452 if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6455 pcflowLink->bank_conflict++;
6456 pcflowLink->pcflow->FromConflicts++;
6457 pcflow->ToConflicts++;
6460 if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6463 pcflowLink->bank_conflict++;
6464 pcflowLink->pcflow->ToConflicts++;
6465 pcflow->FromConflicts++;
6469 fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6470 pcflowLink->pcflow->pc.seq,
6471 pcflowLink->pcflow->FromConflicts,
6472 pcflowLink->pcflow->ToConflicts);
6479 /*-----------------------------------------------------------------*/
6480 /*-----------------------------------------------------------------*/
6481 static void DumpFlow(pBlock *pb)
6485 pCodeFlowLink *pcfl;
6488 fprintf(stderr,"Dump flow \n");
6489 pb->pcHead->print(stderr, pb->pcHead);
6491 pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6492 pcflow->print(stderr,pcflow);
6494 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6496 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6498 if(!isPCFL(pcflow)) {
6499 fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6502 fprintf(stderr,"dumping: ");
6503 pcflow->print(stderr,pcflow);
6504 FlowStats(PCFL(pcflow));
6506 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6508 pc = PCODE(pcfl->pcflow);
6510 fprintf(stderr, " from seq %d:\n",pc->seq);
6512 fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6513 pc->print(stderr,pc);
6518 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6520 pc = PCODE(pcfl->pcflow);
6522 fprintf(stderr, " to seq %d:\n",pc->seq);
6524 fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6525 pc->print(stderr,pc);
6534 /*-----------------------------------------------------------------*/
6535 /*-----------------------------------------------------------------*/
6536 static int OptimizepBlock(pBlock *pb)
6541 if(!pb || !peepOptimizing)
6544 DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6546 for(pc = pb->pcHead; pc; pc = pc->next)
6547 matches += pic16_pCodePeepMatchRule(pc);
6550 pc = pic16_findNextInstruction(pb->pcHead);
6558 if(pic16_pCodePeepMatchRule(pc)) {
6563 pc = pic16_findNextInstruction(pcprev->next);
6565 pc = pic16_findNextInstruction(pb->pcHead);
6567 pc = pic16_findNextInstruction(pc->next);
6571 DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6576 /*-----------------------------------------------------------------*/
6577 /*-----------------------------------------------------------------*/
6578 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6582 for(pc = pcs; pc; pc = pc->next) {
6584 if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6586 (PCI(pc)->pcop->type == PO_LABEL) &&
6587 (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6595 /*-----------------------------------------------------------------*/
6596 /*-----------------------------------------------------------------*/
6597 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6604 (PCI(pc)->pcop->type == PO_LABEL)) {
6606 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6608 // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6609 // if(pcol->pcop.name)
6610 // Safe_free(pcol->pcop.name);
6612 /* If the key is negative, then we (probably) have a label to
6613 * a function and the name is already defined */
6616 sprintf(s=buffer,"_%05d_DS_",pcl->key);
6620 //sprintf(buffer,"_%05d_DS_",pcl->key);
6622 fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6624 pcol->pcop.name = Safe_strdup(s);
6625 pcol->key = pcl->key;
6626 //pc->print(stderr,pc);
6633 /*-----------------------------------------------------------------*/
6634 /* pBlockRemoveUnusedLabels - remove the pCode labels from the */
6635 /* pCode chain if they're not used. */
6636 /*-----------------------------------------------------------------*/
6637 static void pBlockRemoveUnusedLabels(pBlock *pb)
6639 pCode *pc; pCodeLabel *pcl;
6641 if(!pb || !pb->pcHead)
6644 for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6646 pBranch *pbr = PCI(pc)->label;
6647 if(pbr && pbr->next) {
6648 pCode *pcd = pb->pcHead;
6650 // fprintf(stderr, "multiple labels\n");
6651 // pc->print(stderr,pc);
6656 while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6657 //fprintf(stderr,"Used by:\n");
6658 //pcd->print(stderr,pcd);
6660 exchangeLabels(PCL(pbr->pc),pcd);
6669 for(pc = pb->pcHead; pc; pc = pc->next) {
6671 if(isPCL(pc)) // pc->type == PC_LABEL)
6673 else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6674 pcl = PCL(PCI(pc)->label->pc);
6677 // fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6679 /* This pCode is a label, so search the pBlock to see if anyone
6682 if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6684 //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6685 /* Couldn't find an instruction that refers to this label
6686 * So, unlink the pCode label from it's pCode chain
6687 * and destroy the label */
6688 // fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6690 DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6691 if(pc->type == PC_LABEL) {
6692 pic16_unlinkpCode(pc);
6693 pCodeLabelDestruct(pc);
6695 unlinkpCodeFromBranch(pc, PCODE(pcl));
6696 /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6697 Safe_free(pc->label);
6707 /*-----------------------------------------------------------------*/
6708 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */
6709 /* chain and put them into pBranches that are */
6710 /* associated with the appropriate pCode */
6712 /*-----------------------------------------------------------------*/
6713 void pic16_pBlockMergeLabels(pBlock *pb)
6716 pCode *pc, *pcnext=NULL;
6721 /* First, Try to remove any unused labels */
6722 //pBlockRemoveUnusedLabels(pb);
6724 /* Now loop through the pBlock and merge the labels with the opcodes */
6727 // for(pc = pb->pcHead; pc; pc = pc->next) {
6730 pCode *pcn = pc->next;
6732 if(pc->type == PC_LABEL) {
6734 // fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6735 // fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6737 if((pcnext = pic16_findNextInstruction(pc) )) {
6739 // pcnext->print(stderr, pcnext);
6741 // Unlink the pCode label from it's pCode chain
6742 pic16_unlinkpCode(pc);
6744 // fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6745 // And link it into the instruction's pBranch labels. (Note, since
6746 // it's possible to have multiple labels associated with one instruction
6747 // we must provide a means to accomodate the additional labels. Thus
6748 // the labels are placed into the singly-linked list "label" as
6749 // opposed to being a single member of the pCodeInstruction.)
6751 //_ALLOC(pbr,sizeof(pBranch));
6753 pbr = Safe_calloc(1,sizeof(pBranch));
6757 PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6760 if(pic16_pcode_verbose)
6761 fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6763 } else if(pc->type == PC_CSOURCE) {
6765 /* merge the source line symbolic info into the next instruction */
6766 if((pcnext = pic16_findNextInstruction(pc) )) {
6768 // Unlink the pCode label from it's pCode chain
6769 pic16_unlinkpCode(pc);
6770 PCI(pcnext)->cline = PCCS(pc);
6771 //fprintf(stderr, "merging CSRC\n");
6772 //genericPrint(stderr,pcnext);
6778 pBlockRemoveUnusedLabels(pb);
6782 /*-----------------------------------------------------------------*/
6783 /*-----------------------------------------------------------------*/
6784 static int OptimizepCode(char dbName)
6786 #define MAX_PASSES 4
6795 DFPRINTF((stderr," Optimizing pCode\n"));
6799 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6800 if('*' == dbName || getpBlock_dbName(pb) == dbName)
6801 matches += OptimizepBlock(pb);
6804 while(matches && ++passes < MAX_PASSES);
6811 const char *pic16_pCodeOpType(pCodeOp *pcop);
6812 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6815 /*-----------------------------------------------------------------*/
6816 /* pic16_popCopyGPR2Bit - copy a pcode operator */
6817 /*-----------------------------------------------------------------*/
6819 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6823 // fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6826 pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6828 if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6831 assert(pcop != NULL);
6833 if( !( (pcop->type == PO_LABEL) ||
6834 (pcop->type == PO_LITERAL) ||
6835 (pcop->type == PO_STR) ))
6836 PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */
6837 PCOR(pcop)->r->wasUsed = 1;
6838 PCOR(pcop)->instance = PCOR(pc)->instance;
6844 /*----------------------------------------------------------------------*
6845 * pic16_areRegsSame - check to see if the names of two registers match *
6846 *----------------------------------------------------------------------*/
6847 int pic16_areRegsSame(regs *r1, regs *r2)
6849 if(!strcmp(r1->name, r2->name))return 1;
6855 /*-----------------------------------------------------------------*/
6856 /*-----------------------------------------------------------------*/
6857 static void pic16_FixRegisterBanking(pBlock *pb)
6861 regs *reg, *prevreg;
6862 unsigned char flag=0;
6867 pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6870 /* loop through all of the flow blocks with in one pblock */
6872 // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6876 /* at this point, pc should point to a PC_FLOW object */
6877 /* for each flow block, determine the register banking
6881 /* if label, then might come from other point, force banksel */
6882 if(isPCL(pc))prevreg = NULL;
6884 if(!isPCI(pc))goto loop;
6886 if(PCI(pc)->label)prevreg = NULL;
6888 if(PCI(pc)->is2MemOp)goto loop;
6890 /* if goto, then force banksel */
6891 // if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6893 reg = pic16_getRegFromInstruction(pc);
6896 pc->print(stderr, pc);
6897 fprintf(stderr, "reg = %p\n", reg);
6900 fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6901 fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6902 reg->address,reg->isBitField, reg->isFixed);
6906 /* now make some tests to make sure that instruction needs bank switch */
6908 /* if no register exists, and if not a bit opcode goto loop */
6910 if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6913 if(isPCI_SKIP(pc)) {
6914 // fprintf(stderr, "instruction is SKIP instruction\n");
6917 if(reg && isACCESS_BANK(reg))goto loop;
6919 if(!isBankInstruction(pc))goto loop;
6921 if(isPCI_LIT(pc))goto loop;
6923 if(PCI(pc)->op == POC_CALL)goto loop;
6925 /* Examine the instruction before this one to make sure it is
6926 * not a skip type instruction */
6927 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
6929 flag = 0; /* add before this instruction */
6931 /* if previous instruction is a skip one, then set flag
6932 * to 2 and call insertBankSwitch */
6933 if(pcprev && isPCI_SKIP(pcprev)) {
6938 if(pic16_options.opt_banksel>0) {
6939 char op1[128], op2[128];
6942 strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
6943 strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
6944 if(!strcmp(op1, op2))goto loop;
6948 insertBankSwitch(flag, pc);
6950 // fprintf(stderr, "BANK SWITCH inserted\n");
6958 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
6960 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
6961 int instrSize (pCode *pc)
6966 if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
6967 return 4; // assumes only regular instructions using <= 4 bytes
6970 if (isPCI(pc)) return PCI(pc)->isize;
6975 /* Returns 1 if pc is referenced by the given label (either
6976 * pc is the label itself or is an instruction with an attached
6978 * Returns 0 if pc is not preceeded by the specified label.
6980 int isLabel (pCode *pc, char *label)
6984 // label attached to the pCode?
6985 if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
6986 pBranch *lab = NULL;
6987 lab = PCI(pc)->label;
6990 if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
6997 // is inline assembly label?
6998 if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
6999 // do not compare trailing ':'
7000 if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7007 if (strcmp(PCL(pc)->label,label) == 0) {
7012 // no label/no label attached/wrong label(s)
7016 /* Returns the distance to the given label in terms of words.
7017 * Labels are searched only within -max .. max words from pc.
7018 * Returns max if the label could not be found or
7019 * its distance from pc in (-max..+max).
7021 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7022 int dist = instrSize(pc);
7026 while (dist < max && curr && !isLabel (curr, label)) {
7028 dist += instrSize(curr); // sizeof (instruction)
7030 if (curr && dist < max) {
7031 if (target != NULL) *target = curr;
7036 curr = pic16_findNextInstruction (pc->next);
7038 while (dist < max && curr && !isLabel (curr, label)) {
7039 dist += instrSize(curr); // sizeof (instruction)
7042 if (curr && dist < max) {
7043 if (target != NULL) *target = curr;
7047 if (target != NULL) *target = NULL;
7051 /* Returns -1 if pc does NOT denote an instruction like
7053 * Otherwise we return
7054 * (a) 0x10 + i for BTFSS
7055 * (b) 0x00 + i for BTFSC
7057 int isSkipOnStatus (pCode *pc)
7061 if (!pc || !isPCI(pc)) return -1;
7062 if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7063 else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7066 pcop = PCI(pc)->pcop;
7068 if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7069 return res + ((pCodeOpRegBit *)pcop)->bit;
7075 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7076 * returns 0 otherwise. */
7077 int isConditionalBranch (pCode *pc)
7079 if (!pc || !isPCI_BRANCH(pc)) return 0;
7081 switch (PCI(pc)->op) {
7099 /* Returns 1 if pc has a label attached to it.
7100 * This can be either a label stored in the pCode itself (.label)
7101 * or a label making up its own pCode preceding this pc.
7102 * Returns 0 if pc cannot be reached directly via a label.
7104 int hasNoLabel (pCode *pc)
7109 // are there any label pCodes between pc and the previous instruction?
7110 prev = pic16_findPrevInstruction (pc->prev);
7111 while (pc && pc != prev) {
7112 // pCode with attached label?
7113 if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7114 && PCI(pc)->label) {
7117 // is inline assembly label?
7118 if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7119 if (isPCW(pc) && PCW(pc)->label) return 0;
7122 if (isPCL(pc)) return 0;
7131 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7136 vsprintf (buf, fmt, va);
7139 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7142 /* Replaces the old pCode with the new one, moving the labels,
7143 * C source line and probably flow information to the new pCode.
7145 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7146 if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7149 /* first move all labels from old to new */
7150 PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7151 PCI(oldPC)->label = NULL;
7154 /* move C source line (if possible) */
7155 if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7156 PCI(newPC)->cline = PCI(oldPC)->cline;
7159 /* keep flow information intact */
7160 newPC->seq = oldPC->seq;
7161 PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7162 if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7163 PCI(newPC)->pcflow->end = newPC;
7166 /* insert a comment stating which pCode has been replaced */
7168 if (pic16_pcode_verbose || pic16_debug_verbose) {
7170 pic16_pCode2str (pc_str, 256, oldPC);
7171 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7175 /* insert new pCode into pBlock */
7176 pic16_pCodeInsertAfter (oldPC, newPC);
7177 pic16_unlinkpCode (oldPC);
7179 /* destruct replaced pCode */
7180 oldPC->destruct (oldPC);
7183 /* Returns the inverted conditional branch (if any) or NULL.
7184 * pcop must be set to the new jump target.
7186 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7190 if (!bcc || !isPCI(bcc)) return NULL;
7192 switch (PCI(bcc)->op) {
7193 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7194 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7195 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7196 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7197 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7198 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7199 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7200 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7207 #define MAX_DIST_GOTO 0x7FFFFFFF
7208 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7209 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7210 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7211 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7213 /* Follows GOTO/BRA instructions to their target instructions, stores the
7214 * final destination (not a GOTO or BRA instruction) in target and returns
7215 * the distance from the original pc to *target.
7217 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7220 pCodeOp *lastPCOP = NULL;
7224 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7226 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7227 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7228 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7230 lastPCOP = PCI(curr)->pcop;
7231 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7232 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7235 if (target) *target = last;
7236 if (pcop) *pcop = lastPCOP;
7240 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7241 * Otherwise the first pCode after the jumptable (after
7242 * the OPT_JUMPTABLE_END tag) is returned.
7244 pCode *skipJumptables (pCode *pc, int *isJumptable)
7247 if (!pc) return NULL;
7249 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7251 //fprintf (stderr, "SKIPPING jumptable\n");
7253 //pc->print(stderr, pc);
7255 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7256 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7257 //fprintf (stderr, "<<JUMPTAB:\n");
7258 // skip OPT_END as well
7259 if (pc) pc = pc->next;
7265 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7269 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7270 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7271 pc = skipJumptables (pc, &isJumptab);
7273 // pc is the first pCode after the jumptable
7276 // pc has not been changed by skipJumptables()
7284 /* Turn GOTOs into BRAs if distance between GOTO and label
7285 * is less than 1024 bytes.
7287 * This method is especially useful if GOTOs after BTFS[SC]
7288 * can be turned into BRAs as GOTO would cost another NOP
7291 void pic16_OptimizeJumps ()
7294 pCode *pc_prev = NULL;
7295 pCode *pc_next = NULL;
7298 int change, iteration, isJumptab;
7301 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7303 if (!the_pFile) return;
7305 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7307 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7308 int matchedInvertRule = 1;
7311 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7313 pc = pic16_findNextInstruction (pb->pcHead);
7316 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7318 // skip jumptable, i.e. start over with no pc_prev!
7324 /* (1) resolve chained jumps
7325 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7326 * (a) leave dead code in and
7327 * (b) skip over the dead code with an (unneccessary) jump.
7329 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7330 pCodeOp *lastTargetOp = NULL;
7331 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7332 int maxDist = MAX_DIST_BCC;
7333 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7334 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7336 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7337 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7338 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7339 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7340 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7341 PCI(pc)->pcop->name = lastTargetOp->name;
7350 int condBraType = isSkipOnStatus(pc_prev);
7351 label = PCI(pc)->pcop->name;
7352 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7353 if (dist < 0) dist = -dist;
7354 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7358 /* (2) remove "GOTO label; label:" */
7359 if (isLabel (pc_next, label)) {
7360 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7361 // first remove all preceeding SKIP instructions
7362 while (pc_prev && isPCI_SKIP(pc_prev)) {
7363 // attach labels on this instruction to pc_next
7364 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7365 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7366 PCI(pc_prev)->label = NULL;
7367 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7368 pic16_unlinkpCode (pc_prev);
7369 pc_prev = pic16_findPrevInstruction (pc);
7371 // now remove the redundant goto itself
7372 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7373 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7374 pic16_unlinkpCode (pc);
7375 pc = pic16_findPrevInstruction(pc_next->prev);
7376 isHandled = 1; // do not perform further optimizations
7382 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7383 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7384 if (dist < MAX_DIST_BCC) {
7386 switch (condBraType) {
7387 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7388 // no BDC on DIGIT CARRY available
7389 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7390 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7391 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7392 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7393 // no BNDC on DIGIT CARRY available
7394 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7395 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7396 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7398 // no replacement possible
7403 // ATTENTION: keep labels attached to BTFSx!
7404 // HINT: GOTO is label free (checked above)
7405 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7406 isHandled = 1; // do not perform further optimizations
7407 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7408 pic16_pCodeReplace (pc_prev, bcc);
7415 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7421 // (4) eliminate the following (common) tripel:
7423 // labels1: Bcc label2;
7424 // GOTO somewhere; ; <-- instruction referenced by pc
7426 // and replace it by
7427 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7429 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7430 // to <cont.> instead
7431 // ATTENTION: This optimization is only valid if <pred.> is
7432 // not a skip operation!
7433 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7434 // ATTENTION: no label may be attached to the GOTO instruction!
7435 if (isConditionalBranch(pc_prev)
7436 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7437 && (dist < MAX_DIST_BCC)
7438 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7439 && hasNoLabel(pc)) {
7440 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7443 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7444 isHandled = 1; // do not perform further optimizations
7445 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7446 pic16_pCodeReplace (pc_prev, newBcc);
7451 matchedInvertRule++;
7456 /* (5) now just turn GOTO into BRA */
7457 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7458 if (dist < MAX_DIST_BRA) {
7459 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7460 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7461 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7462 pic16_pCodeReplace (pc, newBra);
7467 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7470 } // if (!isHandled)
7477 pBlockRemoveUnusedLabels (pb);
7479 // This line enables goto chain resolution!
7480 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7483 } while (change); /* fixpoint iteration per pBlock */
7486 // emit some statistics concerning goto-optimization
7488 if (pic16_debug_verbose || pic16_pcode_verbose) {
7489 fprintf (stderr, "optimize-goto:\n"
7490 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7491 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7492 "\t%5d conditional \"skipping\" jumps inverted\n"
7493 "\t%5d GOTOs to next instruction removed\n"
7494 "\t%5d chained GOTOs resolved\n",
7495 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7498 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7502 #undef MAX_JUMPCHAIN_DEPTH
7503 #undef MAX_DIST_GOTO
7507 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7509 static void pBlockDestruct(pBlock *pb)
7520 /*-----------------------------------------------------------------*/
7521 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7522 /* name dbName and combine them */
7523 /* into one block */
7524 /*-----------------------------------------------------------------*/
7525 static void mergepBlocks(char dbName)
7528 pBlock *pb, *pbmerged = NULL,*pbn;
7530 pb = the_pFile->pbHead;
7532 //fprintf(stderr," merging blocks named %c\n",dbName);
7536 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7537 if( getpBlock_dbName(pb) == dbName) {
7539 //fprintf(stderr," merged block %c\n",dbName);
7544 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7545 /* pic16_addpCode2pBlock doesn't handle the tail: */
7546 pbmerged->pcTail = pb->pcTail;
7548 pb->prev->next = pbn;
7550 pbn->prev = pb->prev;
7555 //pic16_printpBlock(stderr, pbmerged);
7562 /*-----------------------------------------------------------------*/
7563 /* AnalyzeFlow - Examine the flow of the code and optimize */
7565 /* level 0 == minimal optimization */
7566 /* optimize registers that are used only by two instructions */
7567 /* level 1 == maximal optimization */
7568 /* optimize by looking at pairs of instructions that use the */
7570 /*-----------------------------------------------------------------*/
7572 static void AnalyzeFlow(int level)
7574 static int times_called=0;
7578 /* remove unused allocated registers before exiting */
7579 pic16_RemoveUnusedRegisters();
7584 /* if this is not the first time this function has been called,
7585 * then clean up old flow information */
7586 if(times_called++) {
7587 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7589 pic16_RegsUnMapLiveRanges();
7593 /* Phase 2 - Flow Analysis - Register Banking
7595 * In this phase, the individual flow blocks are examined
7596 * and register banking is fixed.
7600 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7601 pic16_FixRegisterBanking(pb);
7604 /* Phase 2 - Flow Analysis
7606 * In this phase, the pCode is partition into pCodeFlow
7607 * blocks. The flow blocks mark the points where a continuous
7608 * stream of instructions changes flow (e.g. because of
7609 * a call or goto or whatever).
7612 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7613 pic16_BuildFlow(pb);
7616 /* Phase 2 - Flow Analysis - linking flow blocks
7618 * In this phase, the individual flow blocks are examined
7619 * to determine their order of excution.
7622 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7626 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7627 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7628 pic16_createDF (pb);
7629 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7630 pic16_vcg_dump_default (pb);
7632 //pic16_destructDF (pb);
7636 if (0) releaseStack (); // releasing is costly...
7640 /* Phase 3 - Flow Analysis - Flow Tree
7642 * In this phase, the individual flow blocks are examined
7643 * to determine their order of execution.
7646 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7647 pic16_BuildFlowTree(pb);
7650 /* Phase x - Flow Analysis - Used Banks
7652 * In this phase, the individual flow blocks are examined
7653 * to determine the Register Banks they use
7657 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7662 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7663 pic16_pCodeRegMapLiveRanges(pb);
7665 pic16_RemoveUnusedRegisters();
7666 pic16_removeUnusedRegistersDF ();
7668 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7669 pic16_pCodeRegOptimizeRegUsage(level);
7678 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7683 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7686 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7687 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7688 pcflow = pcflow->next) {
7689 FillFlow(PCFL(pcflow));
7694 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7697 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7698 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7699 pcflow = pcflow->next) {
7700 FlowStats(PCFL(pcflow));
7706 /* VR -- no need to analyze banking in flow, but left here :
7707 * 1. because it may be used in the future for other purposes
7708 * 2. because if omitted we'll miss some optimization done here
7710 * Perhaps I should rename it to something else
7713 /*-----------------------------------------------------------------*/
7714 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7715 /* assigned to the registers. */
7717 /*-----------------------------------------------------------------*/
7719 void pic16_AnalyzeBanking(void)
7723 /* Phase x - Flow Analysis - Used Banks
7725 * In this phase, the individual flow blocks are examined
7726 * to determine the Register Banks they use
7736 if(!the_pFile)return;
7738 if(!pic16_options.no_banksel) {
7739 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7740 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7741 pic16_FixRegisterBanking(pb);
7746 /*-----------------------------------------------------------------*/
7747 /* buildCallTree - Look at the flow and extract all of the calls. */
7748 /*-----------------------------------------------------------------*/
7749 static set *register_usage(pBlock *pb);
7751 static void buildCallTree(void )
7763 /* Now build the call tree.
7764 First we examine all of the pCodes for functions.
7765 Keep in mind that the function boundaries coincide
7766 with pBlock boundaries.
7768 The algorithm goes something like this:
7769 We have two nested loops. The outer loop iterates
7770 through all of the pBlocks/functions. The inner
7771 loop iterates through all of the pCodes for
7772 a given pBlock. When we begin iterating through
7773 a pBlock, the variable pc_fstart, pCode of the start
7774 of a function, is cleared. We then search for pCodes
7775 of type PC_FUNCTION. When one is encountered, we
7776 initialize pc_fstart to this and at the same time
7777 associate a new pBranch object that signifies a
7778 branch entry. If a return is found, then this signifies
7779 a function exit point. We'll link the pCodes of these
7780 returns to the matching pc_fstart.
7782 When we're done, a doubly linked list of pBranches
7783 will exist. The head of this list is stored in
7784 `the_pFile', which is the meta structure for all
7785 of the pCode. Look at the pic16_printCallTree function
7786 on how the pBranches are linked together.
7789 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7790 pCode *pc_fstart=NULL;
7791 for(pc = pb->pcHead; pc; pc = pc->next) {
7793 if(isPCI(pc) && pc_fstart) {
7794 if(PCI(pc)->is2MemOp) {
7795 r = pic16_getRegFromInstruction2(pc);
7796 if(r && !strcmp(r->name, "POSTDEC1"))
7797 PCF(pc_fstart)->stackusage++;
7799 r = pic16_getRegFromInstruction(pc);
7800 if(r && !strcmp(r->name, "PREINC1"))
7801 PCF(pc_fstart)->stackusage--;
7806 if (PCF(pc)->fname) {
7809 sprintf(buf, "%smain", port->fun_prefix);
7810 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7811 //fprintf(stderr," found main \n");
7812 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7816 pbr = Safe_calloc(1,sizeof(pBranch));
7817 pbr->pc = pc_fstart = pc;
7820 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7822 // Here's a better way of doing the same:
7823 addSet(&pb->function_entries, pc);
7826 // Found an exit point in a function, e.g. return
7827 // (Note, there may be more than one return per function)
7829 pBranchLink(PCF(pc_fstart), PCF(pc));
7831 addSet(&pb->function_exits, pc);
7833 } else if(isCALL(pc)) {
7834 addSet(&pb->function_calls,pc);
7841 /* This is not needed because currently all register used
7842 * by a function are stored in stack -- VR */
7844 /* Re-allocate the registers so that there are no collisions
7845 * between local variables when one function call another */
7848 // pic16_deallocateAllRegs();
7850 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7858 /*-----------------------------------------------------------------*/
7859 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7860 /* all of the logical connections. */
7862 /* Essentially what's done here is that the pCode flow is */
7864 /*-----------------------------------------------------------------*/
7866 void pic16_AnalyzepCode(char dbName)
7877 /* Phase 1 - Register allocation and peep hole optimization
7879 * The first part of the analysis is to determine the registers
7880 * that are used in the pCode. Once that is done, the peep rules
7881 * are applied to the code. We continue to loop until no more
7882 * peep rule optimizations are found (or until we exceed the
7883 * MAX_PASSES threshold).
7885 * When done, the required registers will be determined.
7891 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7892 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7894 /* First, merge the labels with the instructions */
7895 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7896 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7898 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7899 //fprintf(stderr," analyze and merging block %c\n",dbName);
7900 pic16_pBlockMergeLabels(pb);
7903 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7908 changes = OptimizepCode(dbName);
7911 } while(changes && (i++ < MAX_PASSES));
7918 /* convert a series of movff's of local regs to stack, with a single call to
7919 * a support functions which does the same thing via loop */
7920 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
7924 char *fname[]={"__lr_store", "__lr_restore"};
7926 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
7928 pct = pic16_findNextInstruction(pcstart->next);
7931 pct = pc->next; //pic16_findNextInstruction(pc->next);
7932 // pc->print(stderr, pc);
7933 if(isPCI(pc) && PCI(pc)->label) {
7934 pbr = PCI(pc)->label;
7935 while(pbr && pbr->pc) {
7936 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
7940 // pc->print(stderr, pc);
7942 pc->prev->next = pct;
7943 pct->prev = pc->prev;
7947 } while ((pc) && (pc != pcend));
7949 /* unlink movff instructions */
7950 pcstart->next = pcend;
7951 pcend->prev = pcstart;
7955 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7956 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
7959 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
7960 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
7961 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
7964 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7965 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
7972 sym = newSymbol( fname[ entry?0:1 ], 0 );
7973 strcpy(sym->rname, fname[ entry?0:1 ]);
7974 checkAddSym(&externs, sym);
7976 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
7981 /*-----------------------------------------------------------------*/
7982 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
7983 /* local registers to a support function call */
7984 /*-----------------------------------------------------------------*/
7985 void pic16_OptimizeLocalRegs(void)
7990 pCodeOpLocalReg *pclr;
7993 regs *r, *lastr=NULL, *firstr=NULL;
7994 pCode *pcstart=NULL, *pcend=NULL;
7999 * local_regs begin mark
8000 * MOVFF r0x01, POSTDEC1
8001 * MOVFF r0x02, POSTDEC1
8004 * MOVFF r0x0n, POSTDEC1
8005 * local_regs end mark
8007 * convert the above to the below:
8008 * MOVLW starting_register_index
8010 * MOVLW register_count
8011 * call __save_registers_in_stack
8017 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8018 inRegCount = regCount = 0;
8019 firstr = lastr = NULL;
8020 for(pc = pb->pcHead; pc; pc = pc->next) {
8022 /* hold current function name */
8023 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8025 if(pc && (pc->type == PC_INFO)) {
8028 if(pci->type == INF_LOCALREGS) {
8029 pclr = PCOLR(pci->oper1);
8031 if((pclr->type == LR_ENTRY_BEGIN)
8032 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8035 switch(pclr->type) {
8036 case LR_ENTRY_BEGIN:
8038 inRegCount = 1; regCount = 0;
8039 pcstart = pc; //pic16_findNextInstruction(pc->next);
8040 firstr = lastr = NULL;
8046 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8049 if(curFunc && inWparamList(curFunc+1)) {
8050 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8054 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8059 firstr = lastr = NULL;
8063 if(inRegCount == -1) {
8064 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8070 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8072 r = pic16_getRegFromInstruction(pc);
8074 r = pic16_getRegFromInstruction2(pc);
8075 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8076 if(!firstr)firstr = r;
8078 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8090 /*-----------------------------------------------------------------*/
8091 /* ispCodeFunction - returns true if *pc is the pCode of a */
8093 /*-----------------------------------------------------------------*/
8094 static bool ispCodeFunction(pCode *pc)
8097 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8103 /*-----------------------------------------------------------------*/
8104 /* findFunction - Search for a function by name (given the name) */
8105 /* in the set of all functions that are in a pBlock */
8106 /* (note - I expect this to change because I'm planning to limit */
8107 /* pBlock's to just one function declaration */
8108 /*-----------------------------------------------------------------*/
8109 static pCode *findFunction(char *fname)
8116 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8118 pc = setFirstItem(pb->function_entries);
8121 if((pc->type == PC_FUNCTION) &&
8123 (strcmp(fname, PCF(pc)->fname)==0))
8126 pc = setNextItem(pb->function_entries);
8134 static void MarkUsedRegisters(set *regset)
8139 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8140 // fprintf(stderr, "marking register = %s\t", r1->name);
8141 r2 = pic16_regWithIdx(r1->rIdx);
8142 // fprintf(stderr, "to register = %s\n", r2->name);
8148 static void pBlockStats(FILE *of, pBlock *pb)
8154 if(!pic16_pcode_verbose)return;
8156 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8158 // for now just print the first element of each set
8159 pc = setFirstItem(pb->function_entries);
8161 fprintf(of,";entry: ");
8164 pc = setFirstItem(pb->function_exits);
8166 fprintf(of,";has an exit\n");
8170 pc = setFirstItem(pb->function_calls);
8172 fprintf(of,";functions called:\n");
8175 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8176 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8178 pc = setNextItem(pb->function_calls);
8182 r = setFirstItem(pb->tregisters);
8184 int n = elementsInSet(pb->tregisters);
8186 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8189 fprintf(of, "; %s\n",r->name);
8190 r = setNextItem(pb->tregisters);
8194 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8197 /*-----------------------------------------------------------------*/
8198 /*-----------------------------------------------------------------*/
8200 static void sequencepCode(void)
8206 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8208 pb->seq = GpCodeSequenceNumber+1;
8210 for( pc = pb->pcHead; pc; pc = pc->next)
8211 pc->seq = ++GpCodeSequenceNumber;
8217 /*-----------------------------------------------------------------*/
8218 /*-----------------------------------------------------------------*/
8219 static set *register_usage(pBlock *pb)
8222 set *registers=NULL;
8223 set *registersInCallPath = NULL;
8225 /* check recursion */
8227 pc = setFirstItem(pb->function_entries);
8234 if(pc->type != PC_FUNCTION)
8235 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8237 pc = setFirstItem(pb->function_calls);
8238 for( ; pc; pc = setNextItem(pb->function_calls)) {
8240 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8241 char *dest = pic16_get_op_from_instruction(PCI(pc));
8243 pcn = findFunction(dest);
8245 registersInCallPath = register_usage(pcn->pb);
8247 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8252 pBlockStats(stderr,pb); // debug
8255 // Mark the registers in this block as used.
8257 MarkUsedRegisters(pb->tregisters);
8258 if(registersInCallPath) {
8259 /* registers were used in the functions this pBlock has called */
8260 /* so now, we need to see if these collide with the ones we are */
8263 regs *r1,*r2, *newreg;
8265 DFPRINTF((stderr,"comparing registers\n"));
8267 r1 = setFirstItem(registersInCallPath);
8270 r2 = setFirstItem(pb->tregisters);
8272 while(r2 && (r1->type != REG_STK)) {
8274 if(r2->rIdx == r1->rIdx) {
8275 newreg = pic16_findFreeReg(REG_GPR);
8279 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8283 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8284 r1->rIdx, newreg->rIdx));
8285 r2->rIdx = newreg->rIdx;
8286 //if(r2->name) Safe_free(r2->name);
8288 r2->name = Safe_strdup(newreg->name);
8292 newreg->wasUsed = 1;
8294 r2 = setNextItem(pb->tregisters);
8297 r1 = setNextItem(registersInCallPath);
8300 /* Collisions have been resolved. Now free the registers in the call path */
8301 r1 = setFirstItem(registersInCallPath);
8303 if(r1->type != REG_STK) {
8304 newreg = pic16_regWithIdx(r1->rIdx);
8307 r1 = setNextItem(registersInCallPath);
8311 // MarkUsedRegisters(pb->registers);
8313 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8316 DFPRINTF((stderr,"returning regs\n"));
8318 DFPRINTF((stderr,"not returning regs\n"));
8320 DFPRINTF((stderr,"pBlock after register optim.\n"));
8321 pBlockStats(stderr,pb); // debug
8327 /*-----------------------------------------------------------------*/
8328 /* pct2 - writes the call tree to a file */
8330 /*-----------------------------------------------------------------*/
8331 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8335 // set *registersInCallPath = NULL;
8341 fprintf(of, "recursive function\n");
8342 return; //recursion ?
8345 pc = setFirstItem(pb->function_entries);
8352 for(i=0;i<indent;i++) // Indentation
8356 if(pc->type == PC_FUNCTION) {
8357 usedstack += PCF(pc)->stackusage;
8358 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8359 } else return; // ???
8362 pc = setFirstItem(pb->function_calls);
8363 for( ; pc; pc = setNextItem(pb->function_calls)) {
8365 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8366 char *dest = pic16_get_op_from_instruction(PCI(pc));
8368 pcn = findFunction(dest);
8370 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8372 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8380 /*-----------------------------------------------------------------*/
8381 /* pic16_printCallTree - writes the call tree to a file */
8383 /*-----------------------------------------------------------------*/
8385 void pic16_printCallTree(FILE *of)
8397 fprintf(of, "\npBlock statistics\n");
8398 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8402 fprintf(of,"Call Tree\n");
8403 pbr = the_pFile->functions;
8407 if(!ispCodeFunction(pc))
8408 fprintf(of,"bug in call tree");
8411 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8413 while(pc->next && !ispCodeFunction(pc->next)) {
8415 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8416 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8424 fprintf(of,"\n**************\n\na better call tree\n");
8425 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8430 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8431 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8437 /*-----------------------------------------------------------------*/
8439 /*-----------------------------------------------------------------*/
8441 static void InlineFunction(pBlock *pb)
8449 pc = setFirstItem(pb->function_calls);
8451 for( ; pc; pc = setNextItem(pb->function_calls)) {
8454 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8460 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8462 //fprintf(stderr,"Cool can inline:\n");
8463 //pcn->print(stderr,pcn);
8465 //fprintf(stderr,"recursive call Inline\n");
8466 InlineFunction(pcn->pb);
8467 //fprintf(stderr,"return from recursive call Inline\n");
8470 At this point, *pc points to a CALL mnemonic, and
8471 *pcn points to the function that is being called.
8473 To in-line this call, we need to remove the CALL
8474 and RETURN(s), and link the function pCode in with
8480 /* Remove the CALL */
8484 /* remove callee pBlock from the pBlock linked list */
8485 removepBlock(pcn->pb);
8493 /* Remove the Function pCode */
8494 pct = pic16_findNextInstruction(pcn->next);
8496 /* Link the function with the callee */
8497 pc->next = pcn->next;
8498 pcn->next->prev = pc;
8500 /* Convert the function name into a label */
8502 pbr = Safe_calloc(1,sizeof(pBranch));
8503 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8505 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8506 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8508 /* turn all of the return's except the last into goto's */
8509 /* check case for 2 instruction pBlocks */
8510 pce = pic16_findNextInstruction(pcn->next);
8512 pCode *pce_next = pic16_findNextInstruction(pce->next);
8514 if(pce_next == NULL) {
8515 /* found the last return */
8516 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8518 //fprintf(stderr,"found last return\n");
8519 //pce->print(stderr,pce);
8520 pce->prev->next = pc_call->next;
8521 pc_call->next->prev = pce->prev;
8522 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8532 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8538 /*-----------------------------------------------------------------*/
8540 /*-----------------------------------------------------------------*/
8542 void pic16_InlinepCode(void)
8551 if(!functionInlining)
8554 /* Loop through all of the function definitions and count the
8555 * number of times each one is called */
8556 //fprintf(stderr,"inlining %d\n",__LINE__);
8558 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8560 pc = setFirstItem(pb->function_calls);
8562 for( ; pc; pc = setNextItem(pb->function_calls)) {
8565 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8566 if(pcn && isPCF(pcn)) {
8567 PCF(pcn)->ncalled++;
8570 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8575 //fprintf(stderr,"inlining %d\n",__LINE__);
8577 /* Now, Loop through the function definitions again, but this
8578 * time inline those functions that have only been called once. */
8580 InlineFunction(the_pFile->pbHead);
8581 //fprintf(stderr,"inlining %d\n",__LINE__);
8583 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8588 char *pic_optype_names[]={
8589 "PO_NONE", // No operand e.g. NOP
8590 "PO_W", // The working register (as a destination)
8591 "PO_WREG", // The working register (as a file register)
8592 "PO_STATUS", // The 'STATUS' register
8593 "PO_BSR", // The 'BSR' register
8594 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8596 "PO_INDF0", // The Indirect register
8597 "PO_INTCON", // Interrupt Control register
8598 "PO_GPR_REGISTER", // A general purpose register
8599 "PO_GPR_BIT", // A bit of a general purpose register
8600 "PO_GPR_TEMP", // A general purpose temporary register
8601 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8602 "PO_PCL", // Program counter Low register
8603 "PO_PCLATH", // Program counter Latch high register
8604 "PO_PCLATU", // Program counter Latch upper register
8605 "PO_PRODL", // Product Register Low
8606 "PO_PRODH", // Product Register High
8607 "PO_LITERAL", // A constant
8608 "PO_REL_ADDR", // A relative address
8609 "PO_IMMEDIATE", // (8051 legacy)
8610 "PO_DIR", // Direct memory (8051 legacy)
8611 "PO_CRY", // bit memory (8051 legacy)
8612 "PO_BIT", // bit operand.
8613 "PO_STR", // (8051 legacy)
8615 "PO_WILD", // Wild card operand in peep optimizer
8616 "PO_TWO_OPS" // combine two operands
8620 char *dumpPicOptype(PIC_OPTYPE type)
8622 assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8623 return (pic_optype_names[ type ]);
8627 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8630 #define MAX_COMMON_BANK_SIZE 32
8631 #define FIRST_PSEUDO_BANK_NR 1000
8633 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8634 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8635 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8638 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8641 pseudoBankNr bank; // number assigned to this pseudoBank
8642 unsigned int size; // number of operands assigned to this bank
8643 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8646 /*----------------------------------------------------------------------*/
8647 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8648 /*----------------------------------------------------------------------*/
8649 unsigned int hashSymbol (const char *str)
8651 unsigned int res = 0;
8656 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8663 /*-----------------------------------------------------------------------*/
8664 /* compareSymbol - return 1 iff sym1 equals sym2 */
8665 /*-----------------------------------------------------------------------*/
8666 int compareSymbol (const void *sym1, const void *sym2)
8668 char *s1 = (char*) sym1;
8669 char *s2 = (char*) sym2;
8671 return (strcmp (s1,s2) == 0);
8674 /*-----------------------------------------------------------------------*/
8675 /* comparePre - return 1 iff p1 == p2 */
8676 /*-----------------------------------------------------------------------*/
8677 int comparePtr (const void *p1, const void *p2)
8682 /*----------------------------------------------------------*/
8683 /* getSymbolFromOperand - return a pointer to the symbol in */
8684 /* the given operand and its length */
8685 /*----------------------------------------------------------*/
8686 char *getSymbolFromOperand (char *op, int *len)
8691 if (!op) return NULL;
8693 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8695 if (*sym == '(') sym++;
8698 while (((*curr >= 'A') && (*curr <= 'Z'))
8699 || ((*curr >= 'a') && (*curr <= 'z'))
8700 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8701 || (*curr == '_')) {
8702 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8710 /*--------------------------------------------------------------------------*/
8711 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8712 /*--------------------------------------------------------------------------*/
8713 char *getSymFromBank (pseudoBankNr bank)
8717 if (bank < 0) return "<INVALID BANK NR>";
8718 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8721 /*-----------------------------------------------------------------------*/
8722 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8723 /* bank number (uses hTab sym2bank), if the */
8724 /* symbol is not yet assigned a pseudo bank it */
8725 /* is assigned one here */
8726 /*-----------------------------------------------------------------------*/
8727 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8729 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8735 hash = hashSymbol (op) % sym2bank->size;
8736 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8737 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8739 if (bank == UNKNOWN_BANK) {
8740 // create a pseudo bank for the operand
8742 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8743 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8744 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8745 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8747 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8755 /*--------------------------------------------------------------------*/
8756 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8757 /*--------------------------------------------------------------------*/
8758 int isBanksel (pCode *pc)
8762 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8763 // BANKSEL <variablename> or MOVLB <banknr>
8764 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8768 // check for inline assembler BANKSELs
8769 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8770 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8771 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8775 // assume pc is no BANKSEL instruction
8779 /*---------------------------------------------------------------------------------*/
8780 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8781 /* This method can not guarantee to find all modifications of the */
8782 /* BSR (e.g. via INDirection registers) but covers all compiler */
8783 /* generated plus some cases. */
8784 /*---------------------------------------------------------------------------------*/
8785 int invalidatesBSR(pCode *pc)
8787 // assembler directives invalidate BSR (well, they might, we don't know)
8788 if (isPCAD(pc)) return 1;
8790 // only ASMDIRs and pCodeInstructions can invalidate BSR
8791 if (!isPCI(pc)) return 0;
8793 // we have a pCodeInstruction
8795 // check for BSR modifying instructions
8796 switch (PCI(pc)->op) {
8800 case POC_RETFIE: // might be used as CALL replacement
8801 case POC_RETLW: // might be used as CALL replacement
8802 case POC_RETURN: // might be used as CALL replacement
8807 default: // other instruction do not change BSR unless BSR is an explicit operand!
8808 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8812 // no change of BSR possible/probable
8816 /*------------------------------------------------------------*/
8817 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8818 /* the symbol referenced in this BANKSEL */
8819 /*------------------------------------------------------------*/
8820 pseudoBankNr getBankFromBanksel (pCode *pc)
8825 if (!pc) return INVALID_BANK;
8827 if (isPCAD(pc) && PCAD(pc)->directive) {
8828 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8829 // get symbolname from PCAD(pc)->arg
8830 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8831 sym = PCAD(pc)->arg;
8832 data = getPseudoBankNrFromOperand (sym);
8833 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8834 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8835 // get (literal) bank number from PCAD(pc)->arg
8836 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8837 assert (0 && "not yet implemented - turn off banksel optimization for now");
8839 } else if (isPCI(pc)) {
8840 if (PCI(pc)->op == POC_BANKSEL) {
8841 // get symbolname from PCI(pc)->pcop->name (?)
8842 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8843 sym = PCI(pc)->pcop->name;
8844 data = getPseudoBankNrFromOperand (sym);
8845 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8846 } else if (PCI(pc)->op == POC_MOVLB) {
8847 // get (literal) bank number from PCI(pc)->pcop->name
8848 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8849 assert (0 && "not yet implemented - turn off banksel optimization for now");
8854 // no assigned bank could be found
8855 return UNKNOWN_BANK;
8860 /*------------------------------------------------------------------------------*/
8861 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8862 /*------------------------------------------------------------------------------*/
8863 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8867 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8870 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8871 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8873 if (data->bank != bank)
8880 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8884 /*------------------------------------------------------------------*/
8885 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8886 /* bank is selected at a given pCode */
8887 /*------------------------------------------------------------------*/
8889 /* Create a graph with pseudo banks as its nodes and switches between
8890 * these as edges (with the edge weight representing the absolute
8891 * number of BANKSELs from one to the other).
8892 * Removes redundand BANKSELs instead iff mod == 1.
8893 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8894 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8896 * TODO: check ALL instructions operands if they modify BSR directly...
8898 * pb - the pBlock to annotate
8899 * mod - select either graph creation (0) or BANKSEL removal (1)
8901 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8903 pCode *pc, *pc_next;
8904 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8905 int isBankselect = 0;
8906 unsigned int banksels=0;
8910 pc = pic16_findNextInstruction(pb->pcHead);
8912 isBankselect = isBanksel (pc);
8913 pc_next = pic16_findNextInstruction (pc->next);
8915 if (!hasNoLabel (pc)) {
8916 // we don't know our predecessors -- assume different BSRs
8917 prevBSR = UNKNOWN_BANK;
8918 pseudoBSR = UNKNOWN_BANK;
8919 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8922 // check if this is a BANKSEL instruction
8924 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
8925 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
8927 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
8928 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
8929 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
8930 pic16_unlinkpCode (pc);
8934 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
8939 if (!isBankselect && invalidatesBSR(pc)) {
8940 // check if this instruction invalidates the pseudoBSR
8941 pseudoBSR = UNKNOWN_BANK;
8942 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
8945 prevBSR = pseudoBSR;
8952 /*------------------------------------------------------------------------------------*/
8953 /* assignToSameBank - returns 0 on success or an error code */
8954 /* 1 - common bank would be too large */
8955 /* 2 - assignment to fixed (absolute) bank not performed */
8957 /* This functions assumes that unsplittable operands are already assigned to the same */
8958 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
8959 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
8960 /* TODO: Symbols with an abslute address must be handled specially! */
8961 /*------------------------------------------------------------------------------------*/
8962 int assignToSameBank (int bank0, int bank1, int doAbs)
8964 int eff0, eff1, dummy;
8965 pseudoBank *pbank0, *pbank1;
8968 eff0 = getEffectiveBank (bank0);
8969 eff1 = getEffectiveBank (bank1);
8971 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
8973 // nothing to do if already same bank
8974 if (eff0 == eff1) return 0;
8976 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
8979 // ensure eff0 < eff1
8981 // swap eff0 and eff1
8990 // now assign bank eff1 to bank eff0
8991 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
8993 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
8994 pbank0->bank = eff0;
8997 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9001 hitem = hTabSearch (coerce, eff1 % coerce->size);
9002 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9003 hitem = hitem->next;
9005 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9008 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9009 pbank0->bank, pbank0->size,
9010 getSymFromBank (eff0), getSymFromBank (eff1));
9014 if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9016 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9017 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9018 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9019 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9023 pbank0->size += pbank1->size;
9025 if (pbank1->ref == 0) Safe_free (pbank1);
9031 hitem->item = pbank0;
9033 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9036 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9041 /*----------------------------------------------------------------*/
9042 /* mergeGraphNodes - combines two nodes into one and modifies all */
9043 /* edges to and from the nodes accordingly */
9044 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9045 /* then also (B,A) must be an edge (possibly with weight 0). */
9046 /*----------------------------------------------------------------*/
9047 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9049 GraphEdge *edge, *backedge, *nextedge;
9053 assert (node1 && node2);
9054 assert (node1 != node2);
9056 // add all edges starting at node2 to node1
9059 nextedge = edge->next;
9061 backedge = getGEdge (node, node2);
9063 backweight = backedge->weight;
9066 // insert edges (node1,node) and (node,node1)
9067 addGEdge2 (node1, node, edge->weight, backweight);
9068 // remove edges (node, node2) and (node2, node)
9069 remGEdge (node2, node);
9070 remGEdge (node, node2);
9074 // now node2 should not be referenced by any other GraphNode...
9075 //remGNode (adj, node2->data, node2->hash);
9078 /*----------------------------------------------------------------*/
9079 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9080 /*----------------------------------------------------------------*/
9081 void showGraph (Graph *g)
9085 pseudoBankNr bankNr;
9092 bankNr = getEffectiveBank (node->hash);
9093 assert (bankNr >= 0);
9094 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9096 bankNr = pbank->bank;
9102 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9105 if (edge->weight > 0)
9106 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9113 /*---------------------------------------------------------------*/
9114 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9115 /*---------------------------------------------------------------*/
9116 void pic16_OptimizeBanksel ()
9118 GraphNode *node, *node1, *node1next;
9121 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9122 GraphEdge *edge, *backedge;
9124 int maxWeight, weight, mergeMore, absMaxWeight;
9125 pseudoBankNr curr0, curr1;
9128 pseudoBankNr bankNr;
9129 char *base_symbol0, *base_symbol1;
9134 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9136 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9138 if (!the_pFile || !the_pFile->pbHead) return;
9140 adj = newGraph (NULL);
9141 sym2bank = newHashTable ( 255 );
9142 bank2sym = newHashTable ( 255 );
9143 coerce = newHashTable ( 255 );
9145 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9146 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9147 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9151 // assign symbols with absolute addresses to their respective bank nrs
9152 set = pic16_fix_udata;
9153 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9154 bankNr = reg->address >> 8;
9155 node = getOrAddGNode (adj, NULL, bankNr);
9156 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9157 assignToSameBank (node->hash, bankNr, 1);
9159 assert (bankNr >= 0);
9160 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9162 pbank = Safe_calloc (1, sizeof (pseudoBank));
9163 pbank->bank = reg->address >> 8; //FIXED_BANK;
9166 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9168 assert (pbank->bank == (reg->address >> 8));
9169 pbank->bank = reg->address >> 8; //FIXED_BANK;
9171 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9176 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9177 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9180 if (node->hash < 0) { node = node->next; continue; }
9181 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9184 if (node1->hash < 0) { node1 = node1->next; continue; }
9185 node1next = node1->next;
9186 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9187 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9188 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9189 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9190 if (assignToSameBank (node->hash, node1->hash, 0)) {
9191 fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9192 assert (0 && "Could not assign a symbol to a bank!");
9194 mergeGraphNodes (node, node1);
9196 if (node->hash < node1->hash)
9197 mergeGraphNodes (node, node1);
9199 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9209 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9210 // assign tightly coupled operands to the same (pseudo) bank
9211 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9219 curr0 = getEffectiveBank (node->hash);
9220 if (curr0 < 0) { node = node->next; continue; }
9223 assert (edge->src == node);
9224 backedge = getGEdge (edge->node, edge->src);
9225 weight = edge->weight + (backedge ? backedge->weight : 0);
9226 curr1 = getEffectiveBank (edge->node->hash);
9227 if (curr1 < 0) { edge = edge->next; continue; }
9229 // merging is only useful if the items are not assigned to the same bank already...
9230 if (curr0 != curr1 && weight > maxWeight) {
9231 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9240 if (maxWeight > 0) {
9242 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9243 max->src->hash, getSymFromBank (max->src->hash),
9244 max->node->hash, getSymFromBank (max->node->hash));
9247 node = getGNode (adj, max->src->data, max->src->hash);
9248 node1 = getGNode (adj, max->node->data, max->node->hash);
9250 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9251 if (max->src->hash < max->node->hash)
9252 mergeGraphNodes (node, node1);
9254 mergeGraphNodes (node1, node);
9256 remGEdge (node, node1);
9257 remGEdge (node1, node);
9268 // remove redundant BANKSELs
9269 //fprintf (stderr, "removing redundant BANKSELs\n");
9270 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9271 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9276 fprintf (stderr, "display graph\n");
9281 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9284 /*** END of stuff belonging to the BANKSEL optimization ***/
9288 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9290 typedef unsigned int symbol_t;
9291 typedef unsigned int valnum_t;
9292 //typedef unsigned int hash_t;
9295 #define INT_TO_PTR(x) (((char *) 0) + (x))
9299 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9302 static int pic16_regIsLocal (regs *r);
9303 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9306 static unsigned int pic16_df_removed_pcodes = 0;
9307 static unsigned int pic16_df_saved_bytes = 0;
9308 static unsigned int df_findall_sameflow = 0;
9309 static unsigned int df_findall_otherflow = 0;
9310 static unsigned int df_findall_in_vals = 0;
9312 static void pic16_df_stats () {
9314 if (pic16_debug_verbose || pic16_pcode_verbose) {
9315 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9316 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9317 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9321 /* Remove a pCode iff possible:
9322 * - previous pCode is no SKIP
9324 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9325 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9326 pCode *pcprev, *pcnext;
9327 char buf[256], *total=NULL;
9330 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9332 pcprev = pic16_findPrevInstruction (pc->prev);
9333 pcnext = pic16_findNextInstruction (pc->next);
9335 /* move labels to next instruction (if possible) */
9336 if (PCI(pc)->label && !pcnext) return 0;
9338 /* if this is a SKIP with side-effects -- do not remove */
9339 /* XXX: might try to replace this one with the side-effect only version */
9341 && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9344 switch (PCI(pc)->op)
9348 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9349 pic16_pCodeReplace( pc, newpc );
9353 newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9354 pic16_pCodeReplace( pc, newpc );
9359 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9360 pic16_pCodeReplace( pc, newpc );
9364 newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9365 pic16_pCodeReplace( pc, newpc );
9374 /* if previous instruction is a skip -- do not remove */
9375 if (pcprev && isPCI_SKIP(pcprev)) {
9376 if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9377 /* preceeding SKIP could not be removed -- keep this instruction! */
9382 if (PCI(pc)->label) {
9383 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9384 //pc->print (stderr, pc);
9385 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9386 PCI(pc)->label = NULL;
9389 /* update statistics */
9390 pic16_df_removed_pcodes++;
9391 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9393 /* remove the pCode */
9394 pic16_pCode2str (buf, 256, pc);
9395 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9396 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9397 len = strlen (buf) + strlen (comment) + 10;
9398 total = (char *) Safe_malloc (len);
9399 SNPRINTF (total, len, "%s: %s", comment, buf);
9400 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9404 /* actually unlink it from the pBlock -- also remove from to/from lists */
9405 pic16_pCodeUnlink (pc);
9407 /* remove the pCode -- release registers */
9410 /* report success */
9415 /* ======================================================================== */
9416 /* === SYMBOL HANDLING ==================================================== */
9417 /* ======================================================================== */
9419 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9420 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9421 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9423 /** Calculate a hash for a given string.
9424 * If len == 0 the string is assumed to be NUL terminated. */
9425 static hash_t symbolHash (const char *str, unsigned int len) {
9429 hash = (hash << 2) ^ *str;
9434 hash = (hash << 2) ^ *str;
9441 /** Return 1 iff strings v1 and v2 are identical. */
9442 static int symcmp (const void *v1, const void *v2) {
9443 return !strcmp ((const char *) v1, (const char *) v2);
9446 /** Return 1 iff pointers v1 and v2 are identical. */
9447 static int ptrcmp (const void *v1, const void *v2) {
9451 enum { SPO_WREG=0x1000,
9491 /* Return the unique symbol_t for the given string. */
9492 static symbol_t symFromStr (const char *str) {
9497 if (!map_symToStr) {
9499 struct { char *name; symbol_t sym; } predefsyms[] = {
9501 {"STATUS", SPO_STATUS},
9502 {"PRODL", SPO_PRODL},
9503 {"PRODH", SPO_PRODH},
9504 {"INDF0", SPO_INDF0},
9505 {"POSTDEC0", SPO_POSTDEC0},
9506 {"POSTINC0", SPO_POSTINC0},
9507 {"PREINC0", SPO_PREINC0},
9508 {"PLUSW0", SPO_PLUSW0},
9509 {"INDF1", SPO_INDF1},
9510 {"POSTDEC1", SPO_POSTDEC1},
9511 {"POSTINC1", SPO_POSTINC1},
9512 {"PREINC1", SPO_PREINC1},
9513 {"PLUSW1", SPO_PLUSW1},
9514 {"INDF2", SPO_INDF2},
9515 {"POSTDEC2", SPO_POSTDEC2},
9516 {"POSTINC2", SPO_POSTINC2},
9517 {"PREINC2", SPO_PREINC2},
9518 {"PLUSW2", SPO_PLUSW2},
9519 {"STKPTR", SPO_STKPTR},
9524 {"FSR0L", SPO_FSR0L},
9525 {"FSR0H", SPO_FSR0H},
9526 {"FSR1L", SPO_FSR1L},
9527 {"FSR1H", SPO_FSR1H},
9528 {"FSR2L", SPO_FSR2L},
9529 {"FSR2H", SPO_FSR2H},
9531 {"PCLATH", SPO_PCLATH},
9532 {"PCLATU", SPO_PCLATU},
9533 {"TABLAT", SPO_TABLAT},
9534 {"TBLPTRL", SPO_TBLPTRL},
9535 {"TBLPTRH", SPO_TBLPTRH},
9536 {"TBLPTRU", SPO_TBLPTRU},
9540 map_strToSym = newHashTable (128);
9541 map_symToStr = newHashTable (128);
9543 for (i=0; predefsyms[i].name; i++) {
9546 /* enter new symbol */
9547 sym = predefsyms[i].sym;
9548 name = predefsyms[i].name;
9549 res = Safe_strdup (name);
9550 hash = symbolHash (name, 0);
9552 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9553 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9557 hash = symbolHash (str, 0) % map_strToSym->size;
9559 /* find symbol in table */
9560 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9562 //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9566 /* enter new symbol */
9568 res = Safe_strdup (str);
9570 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9571 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9573 //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9579 static const char *strFromSym (symbol_t sym) {
9580 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9584 /* ======================================================================== */
9585 /* === DEFINITION MAP HANDLING ============================================ */
9586 /* ======================================================================== */
9588 /* A defmap provides information about which symbol is defined by which pCode.
9589 * The most recent definitions are prepended to the list, so that the most
9590 * recent definition can be found by forward scanning the list.
9591 * pc2: MOVFF r0x00, r0x01
9593 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9595 * We attach one defmap to each flow object, and each pCode will occur at
9596 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9597 * used to find definitions for a pCode in its own defmap that precede pCode.
9600 typedef struct defmap_s {
9601 symbol_t sym; /** symbol this item refers to */
9604 unsigned int in_mask:8; /** mask leaving in accessed bits */
9605 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9606 int isRead:1; /** sym/mask is read */
9607 int isWrite:1; /** sym/mask is written */
9611 pCode *pc; /** pCode this symbol is refrenced at */
9612 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9613 valnum_t val; /** new unique number for this value (if isWrite) */
9614 struct defmap_s *prev, *next; /** link to previous an next definition */
9617 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9618 static int defmap_free_count = 0; /** number of released defmap items */
9620 /* Returns a defmap_t with the specified data; this will be the new list head.
9621 * next - pointer to the current list head */
9622 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9627 defmap_free = map->next;
9628 --defmap_free_count;
9630 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9633 map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9634 map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9635 map->acc.access.isRead = (isRead != 0);
9636 map->acc.access.isWrite = (isWrite != 0);
9639 map->val = (isWrite ? val : 0);
9642 if (next) next->prev = map;
9647 /* Returns a copy of the single defmap item. */
9648 static defmap_t *copyDefmap (defmap_t *map) {
9649 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9650 memcpy (res, map, sizeof (defmap_t));
9656 /* Insert a defmap item after the specified one. */
9657 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9658 if (!ref || !newItem) return 1;
9660 newItem->next = ref->next;
9661 newItem->prev = ref;
9662 ref->next = newItem;
9663 if (newItem->next) newItem->next->prev = newItem;
9668 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9669 * item is copied before insertion into chain and therefore left untouched.
9670 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9671 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9674 while (dummy && (dummy->sym != item->sym
9675 || dummy->pc != item->pc
9676 || dummy->acc.accessmethod != item->acc.accessmethod
9677 || dummy->val != item->val
9678 || dummy->in_val != item->in_val)) {
9679 dummy = dummy->next;
9682 /* item already present? */
9683 if (dummy) return 0;
9685 /* otherwise: insert copy of item */
9686 dummy = copyDefmap (item);
9687 dummy->next = *head;
9688 if (*head) (*head)->prev = dummy;
9694 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9695 static void deleteDefmap (defmap_t *map) {
9698 /* unlink from chain -- fails for the first item (head is not updated!) */
9699 if (map->next) map->next->prev = map->prev;
9700 if (map->prev) map->prev->next = map->next;
9703 memset (map, 0, sizeof (defmap_t));
9705 /* save for future use */
9706 map->next = defmap_free;
9708 ++defmap_free_count;
9711 /* Release all defmaps referenced from map. */
9712 static void deleteDefmapChain (defmap_t **_map) {
9713 defmap_t *map, *next;
9719 /* find list head */
9720 while (map && map->prev) map = map->prev;
9722 /* delete all items */
9732 /* Free all defmap items. */
9733 static void freeDefmap (defmap_t **_map) {
9741 /* find list head */
9742 while (map->prev) map = map->prev;
9744 /* release all items */
9754 /* Returns the most recent definition for the given symbol preceeding pc.
9755 * If no definition is found, NULL is returned.
9756 * If pc == NULL the whole list is scanned. */
9757 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9758 defmap_t *curr = map;
9761 /* skip all definitions up to pc */
9762 while (curr && (curr->pc != pc)) curr = curr->next;
9764 /* pc not in the list -- scan the whole list for definitions */
9766 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9769 /* skip all definitions performed by pc */
9770 while (curr && (curr->pc == pc)) curr = curr->next;
9774 /* find definition for sym */
9775 while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9783 /* Returns the first use (read) of the given symbol AFTER pc.
9784 * If no such use is found, NULL is returned.
9785 * If pc == NULL the whole list is scanned. */
9786 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9787 defmap_t *curr = map, *prev = NULL;
9790 /* skip all definitions up to pc */
9791 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9793 /* pc not in the list -- scan the whole list for definitions */
9795 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9799 /* find end of list */
9800 while (curr && curr->next) curr = curr->next;
9803 /* find use of sym (scan list backwards) */
9804 while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9810 /* Return the defmap entry for sym AT pc.
9811 * If none is found, NULL is returned.
9812 * If more than one entry is found an assertion is triggered. */
9813 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9814 defmap_t *res = NULL;
9816 /* find entries for pc */
9817 while (map && map->pc != pc) map = map->next;
9819 /* find first entry for sym @ pc */
9820 while (map && map->pc == pc && map->sym != sym) map = map->next;
9822 /* no entry found */
9823 if (!map) return NULL;
9825 /* check for more entries */
9828 while (map && map->pc == pc) {
9829 /* more than one entry for sym @ pc found? */
9830 assert (map->sym != sym);
9834 /* return single entry for sym @ pc */
9838 /* Modifies the definition of sym at pCode to newval.
9839 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9841 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9844 /* find definitions of pc */
9845 while (m && m->pc != pc) m = m->next;
9847 /* find definition of sym at pc */
9848 while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9850 /* no definition found */
9856 /* update following uses of sym */
9857 while (m && m->pc == pc) m = m->prev;
9859 if (m->sym == sym) {
9861 if (m->acc.access.isWrite) m = NULL;
9869 /* ======================================================================== */
9870 /* === STACK ROUTINES ===================================================== */
9871 /* ======================================================================== */
9873 typedef struct stack_s {
9875 struct stack_s *next;
9878 typedef stackitem_t *dynstack_t;
9879 static stackitem_t *free_stackitems = NULL;
9881 /* Create a stack with one item. */
9882 static dynstack_t *newStack () {
9883 dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9888 /* Remove a stack -- its items are only marked free. */
9889 static void deleteStack (dynstack_t *s) {
9895 i->next = free_stackitems;
9896 free_stackitems = i;
9901 /* Release all stackitems. */
9902 static void releaseStack () {
9905 while (free_stackitems) {
9906 i = free_stackitems->next;
9907 Safe_free(free_stackitems);
9908 free_stackitems = i;
9912 static void stackPush (dynstack_t *stack, void *data) {
9915 if (free_stackitems) {
9916 i = free_stackitems;
9917 free_stackitems = free_stackitems->next;
9919 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9926 static void *stackPop (dynstack_t *stack) {
9930 if (stack && *stack) {
9931 data = (*stack)->data;
9933 *stack = (*stack)->next;
9934 i->next = free_stackitems;
9935 free_stackitems = i;
9943 static int stackContains (dynstack_t *s, void *data) {
9948 if (i->data == data) return 1;
9957 static int stackIsEmpty (dynstack_t *s) {
9958 return (*s == NULL);
9967 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9968 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9970 s->lastdef = lastdef;
9974 static void deleteState (state_t *s) {
9978 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
9981 /* scan working list for state */
9985 /* is i == state? -- state not new */
9986 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
9994 /* is i == state? -- state not new */
9995 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10000 /* not found -- state is new */
10004 static inline valnum_t newValnum ();
10006 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10009 if (!pb) return "<unknown function>";
10011 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10012 if (pc && isPCF(pc)) return PCF(pc)->fname;
10013 else return "<unknown function>";
10016 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10022 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10024 /* find initial value (assigning pc == NULL) */
10025 map = PCFL(pcfl)->in_vals;
10026 while (map && map->sym != sym) map = map->next;
10028 /* initial value already present? */
10030 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10034 /* create a new initial value */
10035 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10036 PCFL(pcfl)->in_vals = map;
10037 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10041 /* insert map as last item in pcfl's defmap */
10042 if (!prev) prev = PCFL(pcfl)->defmap;
10044 PCFL(pcfl)->defmap = map;
10046 while (prev->next) prev = prev->next;
10055 /* Find all reaching definitions for sym at pc.
10056 * A new (!) list of definitions is returned.
10057 * Returns the number of reaching definitions found.
10058 * The defining defmap entries are returned in *chain.
10060 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10065 pCodeFlowLink *succ;
10067 dynstack_t *todo; /** stack of state_t */
10068 dynstack_t *done; /** stack of state_t */
10070 int firstState, n_defs;
10072 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10075 /* initialize return list */
10078 /* wildcard symbol? */
10079 if (!sym) return 0;
10081 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10083 map = PCI(pc)->pcflow->defmap;
10085 res = defmapFindDef (map, sym, pc);
10086 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10088 #define USE_PRECALCED_INVALS 1
10089 #if USE_PRECALCED_INVALS
10090 if (!res && PCI(pc)->pcflow->in_vals) {
10091 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10093 //fprintf (stderr, "found def in init values\n");
10094 df_findall_in_vals++;
10100 // found a single definition (in pc's flow)
10101 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10102 defmapAddCopyIfNew (chain, res);
10103 df_findall_sameflow++;
10107 #if USE_PRECALCED_INVALS
10109 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10115 #define FORWARD_FLOW_ANALYSIS 1
10116 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10117 /* no definition found in pc's flow preceeding pc */
10118 todo = newStack ();
10119 done = newStack ();
10120 n_defs = 0; firstState = 1;
10121 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10123 while (!stackIsEmpty (todo)) {
10124 state = (state_t *) stackPop (todo);
10125 stackPush (done, state);
10126 curr = state->flow;
10127 res = state->lastdef;
10128 //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);
10130 /* there are no definitions BEFORE pc in pc's flow (see above) */
10131 if (curr == PCI(pc)->pcflow) {
10133 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10134 res = pic16_pBlockAddInval (pc->pb, sym);
10135 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10138 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10139 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10143 /* save last definition of sym in this flow as initial def in successors */
10144 res = defmapFindDef (curr->defmap, sym, NULL);
10145 if (!res) res = state->lastdef;
10147 /* add successors to working list */
10148 state = newState (NULL, NULL);
10149 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10151 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10152 state->flow = succ->pcflow;
10153 state->lastdef = res;
10154 if (stateIsNew (state, todo, done)) {
10155 stackPush (todo, state);
10156 state = newState (NULL, NULL);
10158 succ = (pCodeFlowLink *) setNextItem (curr->to);
10160 deleteState (state);
10163 #else // !FORWARD_FLOW_ANALYSIS
10165 /* no definition found in pc's flow preceeding pc */
10166 todo = newStack ();
10167 done = newStack ();
10168 n_defs = 0; firstState = 1;
10169 stackPush (todo, newState (PCI(pc)->pcflow, res));
10171 while (!stackIsEmpty (todo)) {
10172 state = (state_t *) stackPop (todo);
10173 curr = state->flow;
10177 /* only check predecessor flows */
10179 /* get (last) definition of sym in this flow */
10180 res = defmapFindDef (curr->defmap, sym, NULL);
10184 /* definition found */
10185 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10186 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10188 /* no definition found -- check predecessor flows */
10189 state = newState (NULL, NULL);
10190 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10192 /* if no flow predecessor available -- sym might be uninitialized */
10194 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10195 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10196 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10197 deleteDefmap (res); res = NULL;
10201 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10202 state->flow = succ->pcflow;
10203 state->lastdef = res;
10204 if (stateIsNew (state, todo, done)) {
10205 stackPush (todo, state);
10206 state = newState (NULL, NULL);
10208 succ = (pCodeFlowLink *) setNextItem (curr->from);
10210 deleteState (state);
10216 /* clean up done stack */
10217 while (!stackIsEmpty(done)) {
10218 deleteState ((state_t *) stackPop (done));
10220 deleteStack (done);
10222 /* return number of items in result set */
10224 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10225 } else if (n_defs == 1) {
10227 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10228 } else if (n_defs > 0) {
10229 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10233 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10238 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10239 df_findall_otherflow++;
10243 /* ======================================================================== */
10244 /* === VALUE NUMBER HANDLING ============================================== */
10245 /* ======================================================================== */
10247 static valnum_t nextValnum = 0x1000;
10248 static hTab *map_symToValnum = NULL;
10250 /** Return a new value number. */
10251 static inline valnum_t newValnum () {
10252 return (nextValnum += 4);
10255 static valnum_t valnumFromStr (const char *str) {
10260 sym = symFromStr (str);
10262 if (!map_symToValnum) {
10263 map_symToValnum = newHashTable (128);
10266 /* literal already known? */
10267 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10269 /* return existing valnum */
10270 if (res) return (valnum_t) PTR_TO_INT(res);
10272 /* create new valnum */
10274 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10275 //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10279 /* Create a valnum for a literal. */
10280 static valnum_t valnumFromLit (unsigned int lit) {
10281 return ((valnum_t) 0x100 + (lit & 0x0FF));
10284 /* Return the (positive) literal value represented by val
10285 * or -1 iff val is no known literal's valnum. */
10286 static int litFromValnum (valnum_t val) {
10287 if (val >= 0x100 && val < 0x200) {
10288 /* valnum is a (known) literal */
10289 return val & 0x00FF;
10291 /* valnum is not a known literal */
10297 /* Sanity check - all flows in a block must be reachable from initial flow. */
10298 static int verifyAllFlowsReachable (pBlock *pb) {
10304 pCodeFlowLink *succ;
10307 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10310 flowInBlock = NULL;
10312 /* mark initial flow as reached (and "not needs to be reached") */
10313 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10315 addSetHead (&reached, pc);
10316 addSetHead (&checked, pc);
10318 /* mark all further flows in block as "need to be reached" */
10321 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10322 pc = pic16_findNextInstruction (pc->next);
10325 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10326 /* mark as reached and "not need to be reached" */
10327 deleteSetItem (&reached, pcfl);
10328 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10330 /* flow is no longer considered unreachable */
10331 deleteSetItem (&flowInBlock, pcfl);
10333 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10334 if (!isinSet (checked, succ->pcflow)) {
10335 /* flow has never been reached before */
10336 addSetHead (&reached, succ->pcflow);
10337 addSetHead (&checked, succ->pcflow);
10342 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10344 /* by now every flow should have been reached
10345 * --> flowInBlock should be empty */
10346 res = (flowInBlock == NULL);
10350 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10351 while (flowInBlock) {
10352 pcfl = indexSet (flowInBlock, 0);
10353 fprintf (stderr, "not reached: flow %p\n", pcfl);
10354 deleteSetItem (&flowInBlock, pcfl);
10360 deleteSet (&reached);
10361 deleteSet (&flowInBlock);
10362 deleteSet (&checked);
10364 /* if we reached every flow, succ is NULL by now... */
10365 //assert (res); // will fire on unreachable code...
10370 /* Checks a flow for accesses to sym AFTER pc.
10372 * Returns -1 if the symbol is read in this flow (before redefinition),
10373 * returns 0 if the symbol is redefined in this flow or
10374 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10376 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10377 defmap_t *map, *mappc;
10379 /* find pc or start of definitions */
10380 map = pcfl->defmap;
10381 while (map && (map->pc != pc) && map->next) map = map->next;
10382 /* if we found pc -- ignore it */
10383 while (map && map->pc == pc) map = map->prev;
10385 /* scan list backwards (first definition first) */
10386 while (map && mask) {
10387 // if (map->sym == sym) {
10388 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10390 /* scan list for reads at this pc first */
10391 while (map && map->pc == mappc->pc) {
10392 /* is the symbol (partially) read? */
10393 if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10394 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10401 while (map && map->pc == mappc->pc) {
10402 /* honor (partial) redefinitions of sym */
10403 if ((map->sym == sym) && (map->acc.access.isWrite)) {
10404 mask &= ~map->acc.access.mask;
10405 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10410 /* map already points to the first defmap for the next pCode */
10411 //map = mappc->prev;
10414 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10415 * is still alive; return the appropriate mask of alive bits */
10419 /* Check whether a symbol is alive (AFTER pc). */
10420 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10423 dynstack_t *todo, *done;
10426 pCodeFlowLink *succ;
10430 assert (isPCI(pc));
10431 pcfl = PCI(pc)->pcflow;
10432 map = pcfl->defmap;
10434 todo = newStack ();
10435 done = newStack ();
10437 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10438 stackPush (todo, state);
10441 while (!stackIsEmpty (todo)) {
10442 state = (state_t *) stackPop (todo);
10443 pcfl = state->flow;
10444 mask = PTR_TO_INT(state->lastdef);
10445 if (visit) stackPush (done, state); else deleteState(state);
10446 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10447 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10448 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10451 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10452 if (mask == 0) continue;
10454 /* symbol is (partially) read before redefinition in flow */
10455 if (mask == -1) break;
10457 /* symbol is neither read nor completely redefined -- check successor flows */
10458 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10459 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10460 if (stateIsNew (state, todo, done)) {
10461 stackPush (todo, state);
10463 deleteState (state);
10468 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10469 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10471 /* symbol is read in at least one flow -- is alive */
10472 if (mask == -1) return 1;
10474 /* symbol is read in no flow */
10478 /* Returns whether access to the given symbol has side effects. */
10479 static int pic16_symIsSpecial (symbol_t sym) {
10480 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10500 /* no special effects known */
10507 /* Check whether a register should be considered local (to the current function) or not. */
10508 static int pic16_regIsLocal (regs *r) {
10511 if (r->type == REG_TMP) return 1;
10513 sym = symFromStr (r->name);
10516 case SPO_FSR0L: // used in ptrget/ptrput
10517 case SPO_FSR0H: // ... as well
10518 case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10519 case SPO_FSR1H: // ... as well
10520 case SPO_FSR2L: // used as frame pointer
10521 case SPO_FSR2H: // ... as well
10522 case SPO_PRODL: // used to return values from functions
10523 case SPO_PRODH: // ... as well
10524 /* these registers (and some more...) are considered local */
10528 /* for unknown regs: check is marked local, leave if not */
10532 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10538 /* if in doubt, assume non-local... */
10542 /* Check all symbols touched by pc whether their newly assigned values are read.
10543 * Returns 0 if no symbol is used later on, 1 otherwise. */
10544 static int pic16_pCodeIsAlive (pCode *pc) {
10545 pCodeInstruction *pci;
10546 defmap_t *map, *lastpc;
10549 /* we can only handle PCIs */
10550 if (!isPCI(pc)) return 1;
10552 //pc->print (stderr, pc);
10555 assert (pci && pci->pcflow && pci->pcflow->defmap);
10557 /* NEVER remove instructions with implicit side effects */
10560 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10561 case POC_TBLRD_POSTDEC:
10562 case POC_TBLRD_PREINC:
10563 case POC_TBLWT: /* modify program memory */
10564 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10565 case POC_TBLWT_POSTDEC:
10566 case POC_TBLWT_PREINC:
10567 case POC_CLRWDT: /* clear watchdog timer */
10568 case POC_PUSH: /* should be safe to remove though... */
10569 case POC_POP: /* should be safe to remove though... */
10574 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10578 /* no special instruction */
10582 /* prevent us from removing assignments to non-local variables */
10584 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10585 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10587 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10588 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10589 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10590 //pc->print (stderr, pc);
10593 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10594 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10599 /* OVERKILL: prevent us from removing reads from non-local variables
10600 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10601 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10603 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10604 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10606 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10607 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10608 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10609 //pc->print (stderr, pc);
10612 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10613 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10618 /* now check that the defined symbols are not used */
10619 map = pci->pcflow->defmap;
10621 /* find items for pc */
10622 while (map && map->pc != pc) map = map->next;
10624 /* no entries found? something is fishy with DF analysis... -- play safe */
10626 if (pic16_pcode_verbose) {
10627 fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10632 /* remember first item assigned to pc for later use */
10635 /* check all symbols being modified by pc */
10636 while (map && map->pc == pc) {
10637 if (map->sym == 0) { map = map->next; continue; }
10639 /* keep pc if it references special symbols (like POSTDEC0) */
10643 pic16_pCode2str (buf, 256, pc);
10644 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10647 if (pic16_symIsSpecial (map->sym)) {
10648 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10651 if (map->acc.access.isWrite) {
10652 if (pic16_isAlive (map->sym, pc)) {
10653 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10660 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10664 pic16_pCode2str (buf, 256, pc);
10665 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10671 /* Adds implied operands to the list.
10672 * sym - operand being accessed in the pCode
10673 * list - list to append the operand
10674 * isRead - set to 1 iff sym is read in pCode
10675 * listRead - set to 1 iff all operands being read are to be listed
10677 * Returns 0 for "normal" operands, 1 for special operands.
10679 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10680 /* check whether accessing REG accesses other REGs as well */
10684 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10685 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10686 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10690 /* reads FSR0x and WREG */
10691 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10692 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10693 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10694 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10700 /* reads/modifies FSR0x */
10701 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10702 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10703 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10708 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10709 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10710 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10714 /* reads FSR1x and WREG */
10715 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10716 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10717 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10718 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10724 /* reads/modifies FSR1x */
10725 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10726 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10727 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10732 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10733 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10734 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10738 /* reads FSR2x and WREG */
10739 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10740 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10741 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10742 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10748 /* reads/modifies FSR2x */
10749 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10750 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10751 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10755 /* modifies PCLATH and PCLATU */
10756 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10758 /* reading PCL updates PCLATx */
10759 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10760 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10763 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10764 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10765 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10770 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10771 /* nothing special */
10776 /* has been a special operand */
10780 static symbol_t pic16_fsrsym_idx[][2] = {
10781 {SPO_FSR0L, SPO_FSR0H},
10782 {SPO_FSR1L, SPO_FSR1H},
10783 {SPO_FSR2L, SPO_FSR2H}
10786 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10787 static void mergeDefmapSymbols (defmap_t *list) {
10788 defmap_t *ref, *curr, *temp;
10790 /* now make sure that each symbol occurs at most once per pc */
10792 while (ref && (ref->pc == list->pc)) {
10794 while (curr && (curr->pc == list->pc)) {
10795 if (curr->sym == ref->sym) {
10796 //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10797 /* found a symbol occuring twice... merge the two */
10798 if (curr->acc.access.isRead) {
10799 //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10800 ref->acc.access.isRead = 1;
10801 ref->acc.access.in_mask |= curr->acc.access.in_mask;
10803 if (curr->acc.access.isWrite) {
10804 //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10805 ref->acc.access.isWrite = 1;
10806 ref->acc.access.mask |= curr->acc.access.mask;
10810 deleteDefmap (temp);
10811 continue; // do not skip curr!
10819 /** Prepend list with the reads and definitions performed by pc. */
10820 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10821 pCodeInstruction *pci;
10822 int cond, inCond, outCond;
10823 int mask = 0xff, smask;
10824 int isSpecial, isSpecial2;
10825 symbol_t sym, sym2;
10829 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10830 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10831 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10832 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10835 assert (isPCI(pc));
10838 /* handle bit instructions */
10839 if (pci->isBitInst) {
10840 assert (pci->pcop->type == PO_GPR_BIT);
10841 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10844 /* handle (additional) implicit arguments */
10850 lit = PCOL(pci->pcop)->lit;
10851 assert (lit >= 0 && lit < 3);
10852 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10853 val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10854 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10855 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10856 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...
10860 case POC_MOVLB: // BSR
10861 case POC_BANKSEL: // BSR
10862 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10865 case POC_MULWF: // PRODx
10866 case POC_MULLW: // PRODx
10867 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10868 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10871 case POC_POP: // TOS, STKPTR
10872 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10873 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10874 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10875 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10878 case POC_PUSH: // STKPTR
10879 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10880 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10881 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10882 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10885 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10886 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10887 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10888 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10889 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10890 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10892 /* needs correctly set-up stack pointer */
10893 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10894 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10897 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10898 /* pseudo read on (possible) return values */
10899 // WREG is handled below via outCond
10900 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10901 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10902 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10904 /* caller's stack pointers must be restored */
10905 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10906 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10907 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10908 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10911 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10912 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10913 /* pseudo read on (possible) return values */
10914 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10915 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10916 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10917 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10919 /* caller's stack pointers must be restored */
10920 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10921 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10922 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10923 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10927 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10928 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10929 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10930 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10933 case POC_TBLRD_POSTINC:
10934 case POC_TBLRD_POSTDEC:
10935 case POC_TBLRD_PREINC:
10936 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10937 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10938 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10939 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10943 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10944 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10945 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10946 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10949 case POC_TBLWT_POSTINC:
10950 case POC_TBLWT_POSTDEC:
10951 case POC_TBLWT_PREINC:
10952 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10953 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10954 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10955 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10959 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10963 /* handle explicit arguments */
10964 inCond = pci->inCond;
10965 outCond = pci->outCond;
10966 cond = inCond | outCond;
10967 if (cond & PCC_W) {
10968 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10971 /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
10972 if (inCond & PCC_STATUS) {
10974 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10975 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10976 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10977 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10978 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10980 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10981 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10984 if (outCond & PCC_STATUS) {
10986 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10987 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10988 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10989 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10990 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
10992 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
10993 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10996 isSpecial = isSpecial2 = 0;
10998 if (cond & PCC_REGISTER) {
10999 name = pic16_get_op (pci->pcop, NULL, 0);
11000 sym = symFromStr (name);
11001 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11002 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11005 if (cond & PCC_REGISTER2) {
11006 name = pic16_get_op2 (pci->pcop, NULL, 0);
11007 sym2 = symFromStr (name);
11008 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11009 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11013 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11014 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11016 mergeDefmapSymbols (list);
11022 static void printDefmap (defmap_t *map) {
11026 fprintf (stderr, "defmap @ %p:\n", curr);
11028 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11029 curr->acc.access.isRead ? "R" : " ",
11030 curr->acc.access.isWrite ? "W": " ",
11031 curr->in_val, curr->val,
11032 curr->acc.access.in_mask, curr->acc.access.mask,
11033 strFromSym(curr->sym), curr->sym,
11037 fprintf (stderr, "<EOL>\n");
11041 /* Add "additional" definitions to uniq.
11042 * 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.
11043 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11045 * If symbols defined in additional are not present in uniq, a definition is created.
11046 * Otherwise the present definition is altered to reflect the newer assignments.
11048 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11049 * before `------- noted in additional --------' after
11051 * I assume that each symbol occurs AT MOST ONCE in uniq.
11054 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11059 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11060 /* find tail of additional list (holds the first assignment) */
11062 while (curr && curr->next) curr = curr->next;
11066 /* find next assignment in additionals */
11067 while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11071 /* find item in uniq */
11073 //printDefmap (*uniq);
11074 while (old && (old->sym != curr->sym)) old = old->next;
11077 /* definition found -- replace */
11078 if (old->val != curr->val) {
11079 old->val = curr->val;
11083 /* new definition */
11084 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11091 /* return 0 iff uniq remained unchanged */
11095 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11096 * lists of its predecessor flows.
11097 * Initially *combined should be NULL, alt_in will be copied to combined.
11098 * If *combined != NULL, combined will be altered:
11099 * - for symbols defined in *combined but not in alt_in,
11100 * *combined is altered to 0 (value unknown, either *combined or INIT).
11101 * - for symbols defined in alt_in but not in *combined,
11102 * a 0 definition is created (value unknown, either INIT or alt).
11103 * - for symbols defined in both, *combined is:
11104 * > left unchanged if *combined->val == alt_in->val or
11105 * > modified to 0 otherwise (value unknown, either alt or *combined).
11107 * I assume that each symbol occurs AT MOST ONCE in each list!
11109 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11115 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11117 if (!(*combined)) {
11118 return defmapUpdateUniqueSym (combined, alt_in);
11121 /* merge the two */
11124 /* find symbols definition in *combined */
11126 while (old && (old->sym != curr->sym)) old = old->next;
11129 /* definition found */
11130 if (old->val && (old->val != curr->val)) {
11131 old->val = 0; /* value unknown */
11135 /* no definition found -- can be either INIT or alt_in's value */
11136 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11137 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11138 if (val != curr->val) change++;
11144 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11147 if (old->val != 0) {
11148 /* find definition in alt_in */
11150 while (curr && curr->sym != old->sym) curr = curr->next;
11152 /* symbol defined in *combined only -- can be either INIT or *combined */
11153 val = pic16_pBlockAddInval (pb, old->sym)->val;
11154 if (old->val != val) {
11167 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11168 defmap_t *curr1, *curr2;
11171 /* identical maps are equal */
11172 if (map1 == map2) return 0;
11174 if (!map1) return -1;
11175 if (!map2) return 1;
11177 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11182 while (curr1 && curr2) {
11183 curr1 = curr1->next;
11184 curr2 = curr2->next;
11187 /* one of them longer? */
11188 if (curr1) return 1;
11189 if (curr2) return -1;
11191 /* both lists are of equal length -- compare (in O(n^2)) */
11196 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11197 if (!curr2) return 1; // symbol not found in curr2
11198 if (curr2->val != curr1->val) return 1; // values differ
11200 /* compare next symbol */
11201 curr1 = curr1->next;
11204 /* no difference found */
11209 /* Prepare a list of all reaching definitions per flow.
11210 * This is done using a forward dataflow analysis.
11212 static void createReachingDefinitions (pBlock *pb) {
11213 defmap_t *out_vals, *in_vals;
11216 pCodeFlowLink *link;
11222 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11223 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11225 deleteDefmapChain (&PCFL(pc)->in_vals);
11226 deleteDefmapChain (&PCFL(pc)->out_vals);
11227 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11231 pc = pic16_findNextInstruction (pb->pcHead);
11233 // empty function, avoid NULL pointer dereference
11236 todo = NULL; blacklist = NULL;
11237 addSetHead (&todo, PCI(pc)->pcflow);
11239 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11240 while (elementsInSet (todo)) {
11241 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11242 pcfl = PCFL(indexSet (todo, 0));
11243 deleteSetItem (&todo, pcfl);
11244 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11248 if (isinSet (blacklist, pcfl)) {
11249 fprintf (stderr, "ignoring blacklisted flow\n");
11253 /* create in_vals from predecessors out_vals */
11254 link = setFirstItem (pcfl->from);
11256 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11257 link = setNextItem (pcfl->from);
11260 //printDefmap (in_vals);
11261 //printDefmap (pcfl->in_vals);
11263 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11264 //fprintf (stderr, "in_vals changed\n");
11265 /* in_vals changed -- update out_vals */
11266 deleteDefmapChain (&pcfl->in_vals);
11267 pcfl->in_vals = in_vals;
11269 /* create out_val from in_val and defmap */
11271 defmapUpdateUniqueSym (&out_vals, in_vals);
11272 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11274 /* is out_vals different from pcfl->out_vals */
11275 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11276 //fprintf (stderr, "out_vals changed\n");
11277 deleteDefmapChain (&pcfl->out_vals);
11278 pcfl->out_vals = out_vals;
11280 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11281 addSet (&blacklist, pcfl);
11284 /* reschedule all successors */
11285 link = setFirstItem (pcfl->to);
11287 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11288 addSetIfnotP (&todo, link->pcflow);
11289 link = setNextItem (pcfl->to);
11292 deleteDefmapChain (&out_vals);
11295 deleteDefmapChain (&in_vals);
11301 static void showAllDefs (symbol_t sym, pCode *pc) {
11305 assert (isPCI(pc));
11306 count = defmapFindAll (sym, pc, &map);
11308 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11311 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11314 pic16_pCode2str (buf, 256, map->pc);
11315 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11319 deleteDefmapChain (&map);
11323 /* safepCodeUnlink and remove pc from defmap. */
11324 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11325 defmap_t *map, *next, **head;
11329 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11330 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11331 res = pic16_safepCodeUnlink (pc, comment);
11334 /* remove pc from defmap */
11337 if (map->pc == pc) {
11338 if (!map->prev && head) *head = map->next;
11339 deleteDefmap (map);
11348 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11350 /* This breaks the defmap chain's references to pCodes... fix it! */
11351 map = PCI(pc)->pcflow->defmap;
11353 while (map && map->pc != pc) map = map->next;
11355 while (map && map->pc == pc) {
11361 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11362 * write accesses (isRead == 0). */
11363 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11364 defmap_t *map, *map_start;
11366 if (!isPCI(pc)) return;
11367 if (sym == newsym) return;
11369 map = PCI(pc)->pcflow->defmap;
11371 while (map && map->pc != pc) map = map->next;
11373 while (map && map->pc == pc) {
11374 if (map->sym == sym) {
11375 assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11376 if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11377 /* only one kind of access handled... this is easy */
11380 /* must copy defmap entry before replacing symbol... */
11381 copy = copyDefmap (map);
11383 map->acc.access.isRead = 0;
11384 copy->acc.access.isWrite = 0;
11386 map->acc.access.isWrite = 0;
11387 copy->acc.access.isRead = 0;
11389 copy->sym = newsym;
11390 /* insert copy into defmap chain */
11391 defmapInsertAfter (map, copy);
11397 /* as this might introduce multiple defmap entries for newsym... */
11398 mergeDefmapSymbols (map_start);
11401 /* Assign "better" valnums to results. */
11402 static void assignValnums (pCode *pc) {
11403 pCodeInstruction *pci;
11405 symbol_t sym1, sym2;
11406 int cond, isSpecial1, isSpecial2, count, mask, lit;
11407 defmap_t *list, *val, *oldval, *dummy;
11408 regs *reg1 = NULL, *reg2 = NULL;
11411 /* only works for pCodeInstructions... */
11412 if (!isPCI(pc)) return;
11415 cond = pci->inCond | pci->outCond;
11416 list = pci->pcflow->defmap;
11417 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11419 if (cond & PCC_REGISTER) {
11420 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11421 reg1 = pic16_getRegFromInstruction (pc);
11422 isSpecial1 = pic16_symIsSpecial (sym1);
11424 if (cond & PCC_REGISTER2) {
11425 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11426 reg2 = pic16_getRegFromInstruction (pc);
11427 isSpecial2 = pic16_symIsSpecial (sym2);
11430 /* determine input values */
11432 while (val && val->pc != pc) val = val->next;
11433 //list = val; /* might save some time later... */
11434 while (val && val->pc == pc) {
11436 if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11437 /* get valnum for sym */
11438 count = defmapFindAll (val->sym, pc, &oldval);
11439 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11441 if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11442 val->in_val = oldval->val;
11446 } else if (count == 0) {
11447 /* no definition found */
11450 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11452 dummy = oldval->next;
11453 mask = oldval->acc.access.mask;
11454 val->in_val = oldval->val;
11455 while (dummy && (dummy->val == val->in_val)) {
11456 mask &= dummy->acc.access.mask;
11457 dummy = dummy->next;
11460 /* found other values or to restictive mask */
11461 if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11465 if (count > 0) deleteDefmapChain (&oldval);
11470 /* handle valnum assignment */
11472 case POC_CLRF: /* modifies STATUS (Z) */
11473 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11474 oldval = defmapCurr (list, sym1, pc);
11475 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11476 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11477 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11479 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11483 case POC_SETF: /* SETF does not touch STATUS */
11484 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11485 oldval = defmapCurr (list, sym1, pc);
11486 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11487 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11488 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11490 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11494 case POC_MOVLW: /* does not touch STATUS */
11495 oldval = defmapCurr (list, SPO_WREG, pc);
11496 if (pci->pcop->type == PO_LITERAL) {
11497 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11498 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11500 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11501 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11503 if (oldval && oldval->in_val == litnum) {
11504 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11505 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11507 defmapUpdate (list, SPO_WREG, pc, litnum);
11510 case POC_ANDLW: /* modifies STATUS (Z,N) */
11511 case POC_IORLW: /* modifies STATUS (Z,N) */
11512 case POC_XORLW: /* modifies STATUS (Z,N) */
11513 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11514 if (pci->pcop->type == PO_LITERAL) {
11516 lit = (unsigned char) PCOL(pci->pcop)->lit;
11517 val = defmapCurr (list, SPO_WREG, pc);
11518 if (val) vallit = litFromValnum (val->in_val);
11519 if (vallit != -1) {
11520 /* xxxLW <literal>, WREG contains a known literal */
11521 //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11522 if (pci->op == POC_ANDLW) {
11524 } else if (pci->op == POC_IORLW) {
11526 } else if (pci->op == POC_XORLW) {
11529 assert (0 && "invalid operation");
11531 if (vallit == lit) {
11532 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11533 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11535 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11542 /* check if old value matches new value */
11545 assert (pci->pcop->type == PO_LITERAL);
11547 lit = PCOL(pci->pcop)->lit;
11549 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11551 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11552 //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11554 /* cannot remove this LFSR */
11558 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11559 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11560 //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11566 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11571 case POC_MOVWF: /* does not touch flags */
11572 /* find value of WREG */
11573 val = defmapCurr (list, SPO_WREG, pc);
11574 oldval = defmapCurr (list, sym1, pc);
11575 if (val) lit = litFromValnum (val->in_val);
11577 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11579 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11580 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11581 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11583 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11585 assert (lit == 0x0ff);
11586 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11588 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11589 pic16_pCodeReplace (pc, newpc);
11590 defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11591 pic16_fixDefmap (pc, newpc);
11594 /* This breaks the defmap chain's references to pCodes... fix it! */
11595 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11596 if (!val->acc.access.isWrite) {
11597 deleteDefmap (val); // delete reference to WREG as in value
11600 val->acc.access.isRead = 0; // delete reference to WREG as in value
11602 oldval = PCI(pc)->pcflow->defmap;
11604 if (oldval->pc == pc) oldval->pc = newpc;
11605 oldval = oldval->next;
11607 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11608 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11609 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11611 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11614 case POC_MOVFW: /* modifies STATUS (Z,N) */
11615 /* find value of REG */
11616 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11617 val = defmapCurr (list, sym1, pc);
11618 oldval = defmapCurr (list, SPO_WREG, pc);
11619 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11620 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11621 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11623 defmap_t *pred, *predpred;
11624 /* Optimize MOVLW immd; MOVWF reg1; [...]; MOVFW reg1
11625 * into MOVLW immd; MOVWF reg1; [...]; MOVLW immd
11626 * This might allow removal of the first two assignments. */
11627 pred = defmapFindDef (list, sym1, pc);
11628 predpred = pred ? defmapFindDef (list, SPO_WREG, pred->pc) : NULL;
11629 if (pred && predpred && (PCI(pred->pc)->op == POC_MOVWF) && (PCI(predpred->pc)->op == POC_MOVLW)
11630 && !pic16_isAlive (SPO_STATUS, pc))
11632 newpc = pic16_newpCode (POC_MOVLW, pic16_pCodeOpCopy (PCI(predpred->pc)->pcop));
11634 if (pic16_debug_verbose || pic16_pcode_verbose) {
11635 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFW: replaced last of MOVLW;MOVWF;MOVFW by MOVLW");
11637 pic16_pCodeReplace (pc, newpc);
11638 defmapReplaceSymRef (pc, sym1, 0, 1);
11639 pic16_fixDefmap (pc, newpc);
11642 /* This breaks the defmap chain's references to pCodes... fix it! */
11643 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11644 if (!val->acc.access.isWrite) {
11645 deleteDefmap (val); // delete reference to reg1 as in value
11648 val->acc.access.isRead = 0; // delete reference to reg1 as in value
11650 oldval = PCI(pc)->pcflow->defmap;
11652 if (oldval->pc == pc) oldval->pc = newpc;
11653 oldval = oldval->next;
11657 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11661 case POC_MOVFF: /* does not touch STATUS */
11662 /* find value of REG */
11663 val = defmapCurr (list, sym1, pc);
11664 oldval = defmapCurr (list, sym2, pc);
11665 if (val) lit = litFromValnum (val->in_val);
11668 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11669 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11671 newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11672 } else if (lit == 0x00ff) {
11673 newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11678 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11679 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11680 pic16_pCodeReplace (pc, newpc);
11681 defmapReplaceSymRef (pc, sym1, 0, 1);
11682 pic16_fixDefmap (pc, newpc);
11684 break; // do not process instruction as MOVFF...
11686 } else if (!isSpecial1 && !isSpecial2
11687 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11688 && val && oldval && (val->in_val != 0)) {
11689 if (val->in_val == oldval->in_val) {
11690 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11691 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11693 if (!pic16_isAlive (sym1, pc)) {
11694 defmap_t *copy = NULL;
11695 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11696 * This should help eliminate
11698 * <do something not changing A or using B>
11700 * <B is not alive anymore>
11702 * <do something not changing A or using B>
11706 /* scan defmap for symbols storing sym1's value */
11707 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11708 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11709 /* unique reaching definition for sym found */
11710 if (copy->val && copy->val == val->in_val) {
11711 //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);
11712 if (copy->sym == SPO_WREG) {
11713 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11715 pCodeOp *pcop = NULL;
11716 /* the code below fails if we try to replace
11717 * MOVFF PRODL, r0x03
11718 * MOVFF r0x03, PCLATU
11720 * MOVFF PRODL, PCLATU
11721 * as copy(PRODL) contains has pc==NULL, by name fails...
11723 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11725 if (copy->pc && PCI(copy->pc)->pcop)
11726 pcop = PCI(copy->pc)->pcop;
11728 /* This code is broken--see above. */
11731 const char *symname = strFromSym(copy->sym);
11734 pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11735 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11736 //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11740 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11742 pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11744 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11745 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11746 pic16_pCodeReplace (pc, newpc);
11747 assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11748 defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11749 pic16_fixDefmap (pc, newpc);
11753 deleteDefmapChain (©);
11756 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11761 /* cannot optimize */
11766 static void pic16_destructDF (pBlock *pb) {
11771 /* remove old defmaps */
11772 pc = pic16_findNextInstruction (pb->pcHead);
11774 next = pic16_findNextInstruction (pc->next);
11776 assert (isPCI(pc) || isPCAD(pc));
11777 assert (PCI(pc)->pcflow);
11778 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11779 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11780 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11785 if (defmap_free || defmap_free_count) {
11786 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11787 freeDefmap (&defmap_free);
11788 defmap_free_count = 0;
11792 /* Checks whether a pBlock contains ASMDIRs. */
11793 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11798 pc = pic16_findNextInstruction (pb->pcHead);
11800 if (isPCAD(pc)) return 1;
11802 pc = pic16_findNextInstruction (pc->next);
11805 /* no PCADs found */
11810 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11811 static int pic16_removeUnusedRegistersDF () {
11814 regs *reg1, *reg2, *reg3;
11815 set *seenRegs = NULL;
11817 int islocal, change = 0;
11820 if (!the_pFile || !the_pFile->pbHead) return 0;
11822 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11823 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11825 /* find set of using pCodes per register */
11826 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11827 pc = pic16_findNextInstruction(pc->next)) {
11829 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11830 reg1 = reg2 = NULL;
11831 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11832 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11835 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11836 addSetIfnotP (&seenRegs, reg1);
11837 addSetIfnotP (®1->reglives.usedpCodes, pc);
11840 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11841 addSetIfnotP (&seenRegs, reg2);
11842 addSetIfnotP (®2->reglives.usedpCodes, pc);
11846 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11847 /* may not use pic16_regIsLocal() here -- in interrupt routines
11848 * WREG, PRODx, FSR0x must be saved */
11849 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11850 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11852 for (i=0; i < 2; i++) {
11853 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11854 if (!pc2) pc2 = pc;
11855 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11856 reg2 = pic16_getRegFromInstruction (pc);
11857 reg3 = pic16_getRegFromInstruction2 (pc);
11859 || (reg2->rIdx != pic16_stack_preinc->rIdx
11860 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11862 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11863 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11864 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11865 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11869 deleteSet (®1->reglives.usedpCodes);
11872 deleteSet (&seenRegs);
11879 /* Set up pCodeFlow's defmap_ts.
11880 * Needs correctly set up to/from fields. */
11881 static void pic16_createDF (pBlock *pb) {
11887 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11889 pic16_destructDF (pb);
11891 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11892 if (pic16_pBlockHasAsmdirs (pb)) {
11893 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11897 /* integrity check -- we need to reach all flows to guarantee
11898 * correct data flow analysis (reaching definitions, aliveness) */
11900 if (!verifyAllFlowsReachable (pb)) {
11901 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11906 /* establish new defmaps */
11907 pc = pic16_findNextInstruction (pb->pcHead);
11909 next = pic16_findNextInstruction (pc->next);
11911 assert (PCI(pc)->pcflow);
11912 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11917 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11918 createReachingDefinitions (pb);
11921 /* assign better valnums */
11922 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11923 pc = pic16_findNextInstruction (pb->pcHead);
11925 next = pic16_findNextInstruction (pc->next);
11927 assert (PCI(pc)->pcflow);
11928 assignValnums (pc);
11935 /* remove dead pCodes */
11936 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11939 pc = pic16_findNextInstruction (pb->pcHead);
11941 next = pic16_findNextInstruction (pc->next);
11943 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11944 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11953 /* ======================================================================== */
11954 /* === VCG DUMPER ROUTINES ================================================ */
11955 /* ======================================================================== */
11956 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11957 hTab *dumpedNodes = NULL;
11959 /** Dump VCG header into of. */
11960 static void pic16_vcg_init (FILE *of) {
11961 /* graph defaults */
11962 fprintf (of, "graph:{\n");
11963 fprintf (of, "title:\"graph1\"\n");
11964 fprintf (of, "label:\"graph1\"\n");
11965 fprintf (of, "color:white\n");
11966 fprintf (of, "textcolor:black\n");
11967 fprintf (of, "bordercolor:black\n");
11968 fprintf (of, "borderwidth:1\n");
11969 fprintf (of, "textmode:center\n");
11971 fprintf (of, "layoutalgorithm:dfs\n");
11972 fprintf (of, "late_edge_labels:yes\n");
11973 fprintf (of, "display_edge_labels:yes\n");
11974 fprintf (of, "dirty_edge_labels:yes\n");
11975 fprintf (of, "finetuning:yes\n");
11976 fprintf (of, "ignoresingles:no\n");
11977 fprintf (of, "straight_phase:yes\n");
11978 fprintf (of, "priority_phase:yes\n");
11979 fprintf (of, "manhattan_edges:yes\n");
11980 fprintf (of, "smanhattan_edges:no\n");
11981 fprintf (of, "nearedges:no\n");
11982 fprintf (of, "node_alignment:center\n"); // bottom|top|center
11983 fprintf (of, "port_sharing:no\n");
11984 fprintf (of, "arrowmode:free\n"); // fixed|free
11985 fprintf (of, "crossingphase2:yes\n");
11986 fprintf (of, "crossingoptimization:yes\n");
11987 fprintf (of, "edges:yes\n");
11988 fprintf (of, "nodes:yes\n");
11989 fprintf (of, "splines:no\n");
11991 /* node defaults */
11992 fprintf (of, "node.color:lightyellow\n");
11993 fprintf (of, "node.textcolor:black\n");
11994 fprintf (of, "node.textmode:center\n");
11995 fprintf (of, "node.shape:box\n");
11996 fprintf (of, "node.bordercolor:black\n");
11997 fprintf (of, "node.borderwidth:1\n");
11999 /* edge defaults */
12000 fprintf (of, "edge.textcolor:black\n");
12001 fprintf (of, "edge.color:black\n");
12002 fprintf (of, "edge.thickness:1\n");
12003 fprintf (of, "edge.arrowcolor:black\n");
12004 fprintf (of, "edge.backarrowcolor:black\n");
12005 fprintf (of, "edge.arrowsize:15\n");
12006 fprintf (of, "edge.backarrowsize:15\n");
12007 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12008 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12009 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12011 fprintf (of, "\n");
12013 /* prepare data structures */
12015 hTabDeleteAll (dumpedNodes);
12016 dumpedNodes = NULL;
12018 dumpedNodes = newHashTable (128);
12021 /** Dump VCG footer into of. */
12022 static void pic16_vcg_close (FILE *of) {
12023 fprintf (of, "}\n");
12026 #define BUF_SIZE 128
12027 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12030 static int ptrcmp (const void *p1, const void *p2) {
12035 /** Dump a pCode node as VCG to of. */
12036 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12037 char buf[BUF_SIZE];
12039 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12043 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12044 //fprintf (stderr, "dumping %p\n", pc);
12046 /* only dump pCodeInstructions and Flow nodes */
12047 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12050 fprintf (of, "node:{");
12051 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12052 fprintf (of, "label:\"%s\n", pcTitle(pc));
12054 fprintf (of, "<PCFLOW>");
12055 } else if (isPCI(pc) || isPCAD(pc)) {
12056 pc->print (of, pc);
12058 fprintf (of, "<!PCI>");
12060 fprintf (of, "\" ");
12061 fprintf (of, "}\n");
12063 if (1 && isPCFL(pc)) {
12064 defmap_t *map, *prev;
12066 map = PCFL(pc)->defmap;
12069 if (map->sym != 0) {
12072 /* emit definition node */
12073 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12074 fprintf (of, "label:\"");
12078 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));
12081 } while (map && prev->pc == map->pc);
12084 fprintf (of, "\" ");
12086 fprintf (of, "color:green ");
12087 fprintf (of, "}\n");
12089 /* emit edge to previous definition */
12090 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12092 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12094 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12096 fprintf (of, "color:green ");
12097 fprintf (of, "}\n");
12100 pic16_vcg_dumpnode (map->pc, of);
12101 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12102 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12109 /* emit additional nodes (e.g. operands) */
12112 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12113 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12114 char buf[BUF_SIZE];
12115 pCodeInstruction *pci;
12119 if (1 && isPCFL(pc)) {
12120 /* emit edges to flow successors */
12122 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12123 pcfl = setFirstItem (PCFL(pc)->to);
12125 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12126 pic16_vcg_dumpnode (pc, of);
12127 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12128 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12129 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12130 pcfl = setNextItem (PCFL(pc)->to);
12134 if (!isPCI(pc) && !isPCAD(pc)) return;
12138 /* emit control flow edges (forward only) */
12142 pic16_vcg_dumpnode (curr->pc, of);
12143 fprintf (of, "edge:{");
12144 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12145 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12146 fprintf (of, "color:red ");
12147 fprintf (of, "}\n");
12152 /* dump "flow" edge (link pCode according to pBlock order) */
12155 pcnext = pic16_findNextInstruction (pc->next);
12157 pic16_vcg_dumpnode (pcnext, of);
12158 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12159 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12167 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12168 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12169 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12173 /* emit data flow edges (backward only) */
12174 /* TODO: gather data flow information... */
12177 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12182 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12183 if (pic16_pBlockHasAsmdirs (pb)) {
12184 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12188 for (pc=pb->pcHead; pc; pc = pc->next) {
12189 pic16_vcg_dumpnode (pc, of);
12192 for (pc=pb->pcHead; pc; pc = pc->next) {
12193 pic16_vcg_dumpedges (pc, of);
12197 static void pic16_vcg_dump_default (pBlock *pb) {
12199 char buf[BUF_SIZE];
12204 /* get function name */
12206 while (pc && !isPCF(pc)) pc = pc->next;
12208 SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12210 SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12213 //fprintf (stderr, "now dumping %s\n", buf);
12214 of = fopen (buf, "w");
12215 pic16_vcg_init (of);
12216 pic16_vcg_dump (of, pb);
12217 pic16_vcg_close (of);
12222 /*** END of helpers for pCode dataflow optimizations ***/