X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fpic16%2Fpcode.c;h=24f36331f42431c48fb1eff291f42557c80236bf;hb=195ee3f3ee25ce2c5f2a59fbd2779c4cb80527c3;hp=1c445ca72d33e41c30d3f91e64fd6780b948b954;hpb=3f1a04bb9806ee81cb2561be4ff4cd21f0214730;p=fw%2Fsdcc diff --git a/src/pic16/pcode.c b/src/pic16/pcode.c index 1c445ca7..24f36331 100644 --- a/src/pic16/pcode.c +++ b/src/pic16/pcode.c @@ -32,12 +32,17 @@ #include "ralloc.h" #include "device.h" +extern char *pic16_aopGet (struct asmop *aop, int offset, bool bit16, bool dname); + #if defined(__BORLANDC__) || defined(_MSC_VER) #define STRCASECMP stricmp +#define inline #else #define STRCASECMP strcasecmp #endif +#define DUMP_DF_GRAPHS 0 + /****************************************************************/ /****************************************************************/ @@ -100,10 +105,37 @@ pCodeOpReg pic16_pc_plusw2 = {{PO_INDF0, "PLUSW2"}, -1, NULL, 0, NULL}; pCodeOpReg pic16_pc_prodl = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL}; pCodeOpReg pic16_pc_prodh = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL}; +/* EEPROM registers */ +pCodeOpReg pic16_pc_eecon1 = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL}; +pCodeOpReg pic16_pc_eecon2 = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL}; +pCodeOpReg pic16_pc_eedata = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL}; +pCodeOpReg pic16_pc_eeadr = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL}; + pCodeOpReg pic16_pc_kzero = {{PO_GPR_REGISTER, "KZ"}, -1, NULL,0,NULL}; pCodeOpReg pic16_pc_wsave = {{PO_GPR_REGISTER, "WSAVE"}, -1, NULL,0,NULL}; pCodeOpReg pic16_pc_ssave = {{PO_GPR_REGISTER, "SSAVE"}, -1, NULL,0,NULL}; +pCodeOpReg *pic16_stackpnt_lo; +pCodeOpReg *pic16_stackpnt_hi; +pCodeOpReg *pic16_stack_postinc; +pCodeOpReg *pic16_stack_postdec; +pCodeOpReg *pic16_stack_preinc; +pCodeOpReg *pic16_stack_plusw; + +pCodeOpReg *pic16_framepnt_lo; +pCodeOpReg *pic16_framepnt_hi; +pCodeOpReg *pic16_frame_postinc; +pCodeOpReg *pic16_frame_postdec; +pCodeOpReg *pic16_frame_preinc; +pCodeOpReg *pic16_frame_plusw; + +pCodeOpReg pic16_pc_gpsimio = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL}; +pCodeOpReg pic16_pc_gpsimio2 = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL}; + +char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" }; +char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" }; + + static int mnemonics_initialized = 0; @@ -159,9 +191,28 @@ extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2); extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc); pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval); void pic16_pCodeRegMapLiveRanges(pBlock *pb); +void OptimizeLocalRegs(void); +pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst); char *dumpPicOptype(PIC_OPTYPE type); +pCodeOp *pic16_popGetLit2(int, pCodeOp *); +pCodeOp *pic16_popGetLit(int); +pCodeOp *pic16_popGetWithString(char *); +extern int inWparamList(char *s); + +/** data flow optimization helpers **/ +#if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0 +static void pic16_vcg_dump (FILE *of, pBlock *pb); +static void pic16_vcg_dump_default (pBlock *pb); +#endif +static int pic16_pCodeIsAlive (pCode *pc); +static void pic16_df_stats (); +static void pic16_createDF (pBlock *pb); +static int pic16_removeUnusedRegistersDF (); +static void pic16_destructDF (pBlock *pb); +static void releaseStack (); + /****************************************************************/ /* PIC Instructions */ /****************************************************************/ @@ -173,6 +224,7 @@ pCodeInstruction pic16_pciADDWF = { genericPrint}, POC_ADDWF, "ADDWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -189,7 +241,7 @@ pCodeInstruction pic16_pciADDWF = { 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER), // inCond - (PCC_REGISTER | PCC_Z), // outCond + (PCC_REGISTER | PCC_STATUS), // outCond PCI_MAGIC }; @@ -200,6 +252,7 @@ pCodeInstruction pic16_pciADDFW = { genericPrint}, POC_ADDFW, "ADDWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -216,7 +269,7 @@ pCodeInstruction pic16_pciADDFW = { 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER), // inCond - (PCC_W | PCC_Z), // outCond + (PCC_W | PCC_STATUS), // outCond PCI_MAGIC }; @@ -227,6 +280,7 @@ pCodeInstruction pic16_pciADDWFC = { // mdubuc - New genericPrint}, POC_ADDWFC, "ADDWFC", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -243,7 +297,7 @@ pCodeInstruction pic16_pciADDWFC = { // mdubuc - New 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER | PCC_C), // inCond - (PCC_REGISTER | PCC_Z), // outCond + (PCC_REGISTER | PCC_STATUS), // outCond PCI_MAGIC }; @@ -254,6 +308,7 @@ pCodeInstruction pic16_pciADDFWC = { genericPrint}, POC_ADDFWC, "ADDWFC", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -270,7 +325,7 @@ pCodeInstruction pic16_pciADDFWC = { 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER | PCC_C), // inCond - (PCC_W | PCC_Z), // outCond + (PCC_W | PCC_STATUS), // outCond PCI_MAGIC }; @@ -281,6 +336,7 @@ pCodeInstruction pic16_pciADDLW = { genericPrint}, POC_ADDLW, "ADDLW", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -297,7 +353,7 @@ pCodeInstruction pic16_pciADDLW = { 0, // second literal operand POC_NOP, (PCC_W | PCC_LITERAL), // inCond - (PCC_W | PCC_Z | PCC_C | PCC_DC | PCC_OV | PCC_N), // outCond + (PCC_W | PCC_STATUS), // outCond PCI_MAGIC }; @@ -308,6 +364,7 @@ pCodeInstruction pic16_pciANDLW = { genericPrint}, POC_ANDLW, "ANDLW", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -335,6 +392,7 @@ pCodeInstruction pic16_pciANDWF = { genericPrint}, POC_ANDWF, "ANDWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -362,6 +420,7 @@ pCodeInstruction pic16_pciANDFW = { genericPrint}, POC_ANDFW, "ANDWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -378,7 +437,7 @@ pCodeInstruction pic16_pciANDFW = { 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER), // inCond - (PCC_W | PCC_Z) // outCond + (PCC_W | PCC_Z | PCC_N) // outCond }; pCodeInstruction pic16_pciBC = { // mdubuc - New @@ -388,6 +447,7 @@ pCodeInstruction pic16_pciBC = { // mdubuc - New genericPrint}, POC_BC, "BC", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -415,6 +475,7 @@ pCodeInstruction pic16_pciBCF = { genericPrint}, POC_BCF, "BCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -442,6 +503,7 @@ pCodeInstruction pic16_pciBN = { // mdubuc - New genericPrint}, POC_BN, "BN", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -469,6 +531,7 @@ pCodeInstruction pic16_pciBNC = { // mdubuc - New genericPrint}, POC_BNC, "BNC", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -496,6 +559,7 @@ pCodeInstruction pic16_pciBNN = { // mdubuc - New genericPrint}, POC_BNN, "BNN", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -523,6 +587,7 @@ pCodeInstruction pic16_pciBNOV = { // mdubuc - New genericPrint}, POC_BNOV, "BNOV", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -550,6 +615,7 @@ pCodeInstruction pic16_pciBNZ = { // mdubuc - New genericPrint}, POC_BNZ, "BNZ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -577,6 +643,7 @@ pCodeInstruction pic16_pciBOV = { // mdubuc - New genericPrint}, POC_BOV, "BOV", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -604,6 +671,7 @@ pCodeInstruction pic16_pciBRA = { // mdubuc - New genericPrint}, POC_BRA, "BRA", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -631,6 +699,7 @@ pCodeInstruction pic16_pciBSF = { genericPrint}, POC_BSF, "BSF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -658,6 +727,7 @@ pCodeInstruction pic16_pciBTFSC = { genericPrint}, POC_BTFSC, "BTFSC", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -685,6 +755,7 @@ pCodeInstruction pic16_pciBTFSS = { genericPrint}, POC_BTFSS, "BTFSS", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -712,6 +783,7 @@ pCodeInstruction pic16_pciBTG = { // mdubuc - New genericPrint}, POC_BTG, "BTG", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -739,6 +811,7 @@ pCodeInstruction pic16_pciBZ = { // mdubuc - New genericPrint}, POC_BZ, "BZ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -754,7 +827,7 @@ pCodeInstruction pic16_pciBZ = { // mdubuc - New 0, // second memory operand 0, // second literal operand POC_NOP, - PCC_Z, // inCond + (PCC_REL_ADDR | PCC_Z), // inCond PCC_NONE, // outCond PCI_MAGIC }; @@ -766,6 +839,7 @@ pCodeInstruction pic16_pciCALL = { genericPrint}, POC_CALL, "CALL", + 4, NULL, // from branch NULL, // to branch NULL, // label @@ -782,7 +856,7 @@ pCodeInstruction pic16_pciCALL = { 0, // second literal operand POC_NOP, PCC_NONE, // inCond - PCC_NONE , // outCond + PCC_NONE, // outCond PCI_MAGIC }; @@ -793,6 +867,7 @@ pCodeInstruction pic16_pciCOMF = { genericPrint}, POC_COMF, "COMF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -809,7 +884,7 @@ pCodeInstruction pic16_pciCOMF = { 0, // second literal operand POC_NOP, PCC_REGISTER, // inCond - PCC_REGISTER , // outCond + (PCC_REGISTER | PCC_Z | PCC_N) , // outCond PCI_MAGIC }; @@ -820,6 +895,7 @@ pCodeInstruction pic16_pciCOMFW = { genericPrint}, POC_COMFW, "COMF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -836,7 +912,7 @@ pCodeInstruction pic16_pciCOMFW = { 0, // second literal operand POC_NOP, PCC_REGISTER, // inCond - PCC_W , // outCond + (PCC_W | PCC_Z | PCC_N) , // outCond PCI_MAGIC }; @@ -847,6 +923,7 @@ pCodeInstruction pic16_pciCLRF = { genericPrint}, POC_CLRF, "CLRF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -862,8 +939,8 @@ pCodeInstruction pic16_pciCLRF = { 0, // second memory operand 0, // second literal operand POC_NOP, - PCC_REGISTER, // inCond - PCC_REGISTER , // outCond + PCC_NONE, // inCond + (PCC_REGISTER | PCC_Z), // outCond PCI_MAGIC }; @@ -874,6 +951,7 @@ pCodeInstruction pic16_pciCLRWDT = { genericPrint}, POC_CLRWDT, "CLRWDT", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -901,6 +979,7 @@ pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New genericPrint}, POC_CPFSEQ, "CPFSEQ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -928,6 +1007,7 @@ pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New genericPrint}, POC_CPFSGT, "CPFSGT", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -955,6 +1035,7 @@ pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New genericPrint}, POC_CPFSLT, "CPFSLT", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -982,6 +1063,7 @@ pCodeInstruction pic16_pciDAW = { genericPrint}, POC_DAW, "DAW", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1009,6 +1091,7 @@ pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New genericPrint}, POC_DCFSNZ, "DCFSNZ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1036,6 +1119,7 @@ pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New genericPrint}, POC_DCFSNZW, "DCFSNZ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1063,6 +1147,7 @@ pCodeInstruction pic16_pciDECF = { genericPrint}, POC_DECF, "DECF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1079,7 +1164,7 @@ pCodeInstruction pic16_pciDECF = { 0, // second literal operand POC_NOP, PCC_REGISTER, // inCond - PCC_REGISTER , // outCond + (PCC_REGISTER | PCC_STATUS) , // outCond PCI_MAGIC }; @@ -1090,6 +1175,7 @@ pCodeInstruction pic16_pciDECFW = { genericPrint}, POC_DECFW, "DECF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1106,7 +1192,7 @@ pCodeInstruction pic16_pciDECFW = { 0, // second literal operand POC_NOP, PCC_REGISTER, // inCond - PCC_W , // outCond + (PCC_W | PCC_STATUS) , // outCond PCI_MAGIC }; @@ -1117,6 +1203,7 @@ pCodeInstruction pic16_pciDECFSZ = { genericPrint}, POC_DECFSZ, "DECFSZ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1144,6 +1231,7 @@ pCodeInstruction pic16_pciDECFSZW = { genericPrint}, POC_DECFSZW, "DECFSZ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1171,6 +1259,7 @@ pCodeInstruction pic16_pciGOTO = { genericPrint}, POC_GOTO, "GOTO", + 4, NULL, // from branch NULL, // to branch NULL, // label @@ -1198,6 +1287,7 @@ pCodeInstruction pic16_pciINCF = { genericPrint}, POC_INCF, "INCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1214,7 +1304,7 @@ pCodeInstruction pic16_pciINCF = { 0, // second literal operand POC_NOP, PCC_REGISTER, // inCond - (PCC_REGISTER | PCC_C | PCC_DC | PCC_Z | PCC_OV | PCC_N), // outCond + (PCC_REGISTER | PCC_STATUS), // outCond PCI_MAGIC }; @@ -1225,6 +1315,7 @@ pCodeInstruction pic16_pciINCFW = { genericPrint}, POC_INCFW, "INCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1241,7 +1332,7 @@ pCodeInstruction pic16_pciINCFW = { 0, // second literal operand POC_NOP, PCC_REGISTER, // inCond - PCC_W , // outCond + (PCC_W | PCC_STATUS) , // outCond PCI_MAGIC }; @@ -1252,6 +1343,7 @@ pCodeInstruction pic16_pciINCFSZ = { genericPrint}, POC_INCFSZ, "INCFSZ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1266,7 +1358,7 @@ pCodeInstruction pic16_pciINCFSZ = { 0, // fast call/return mode select bit 0, // second memory operand 0, // second literal operand - POC_NOP, + POC_INFSNZ, PCC_REGISTER, // inCond PCC_REGISTER , // outCond PCI_MAGIC @@ -1279,6 +1371,7 @@ pCodeInstruction pic16_pciINCFSZW = { genericPrint}, POC_INCFSZW, "INCFSZ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1293,7 +1386,7 @@ pCodeInstruction pic16_pciINCFSZW = { 0, // fast call/return mode select bit 0, // second memory operand 0, // second literal operand - POC_NOP, + POC_INFSNZW, PCC_REGISTER, // inCond PCC_W , // outCond PCI_MAGIC @@ -1305,7 +1398,8 @@ pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New genericDestruct, genericPrint}, POC_INFSNZ, - "INCFSNZ", + "INFSNZ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1320,12 +1414,40 @@ pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New 0, // fast call/return mode select bit 0, // second memory operand 0, // second literal operand - POC_NOP, + POC_INCFSZ, PCC_REGISTER, // inCond PCC_REGISTER , // outCond PCI_MAGIC }; +pCodeInstruction pic16_pciINFSNZW = { // vrokas - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeSKIP, + genericDestruct, + genericPrint}, + POC_INFSNZW, + "INFSNZ", + 2, + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + 0, // second memory operand + 0, // second literal operand + POC_INCFSZW, + PCC_REGISTER, // inCond + PCC_W , // outCond + PCI_MAGIC +}; + pCodeInstruction pic16_pciIORWF = { {PC_OPCODE, NULL, NULL, 0, NULL, // genericAnalyze, @@ -1333,6 +1455,7 @@ pCodeInstruction pic16_pciIORWF = { genericPrint}, POC_IORWF, "IORWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1360,6 +1483,7 @@ pCodeInstruction pic16_pciIORFW = { genericPrint}, POC_IORFW, "IORWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1387,6 +1511,7 @@ pCodeInstruction pic16_pciIORLW = { genericPrint}, POC_IORLW, "IORLW", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1414,6 +1539,7 @@ pCodeInstruction pic16_pciLFSR = { // mdubuc - New genericPrint}, POC_LFSR, "LFSR", + 4, NULL, // from branch NULL, // to branch NULL, // label @@ -1429,8 +1555,8 @@ pCodeInstruction pic16_pciLFSR = { // mdubuc - New 0, // second memory operand 1, // second literal operand POC_NOP, - (PCC_REGISTER | PCC_LITERAL), - PCC_REGISTER, // outCond + PCC_LITERAL, // inCond + PCC_NONE, // outCond PCI_MAGIC }; @@ -1441,6 +1567,7 @@ pCodeInstruction pic16_pciMOVF = { genericPrint}, POC_MOVF, "MOVF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1468,6 +1595,7 @@ pCodeInstruction pic16_pciMOVFW = { genericPrint}, POC_MOVFW, "MOVF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1484,7 +1612,7 @@ pCodeInstruction pic16_pciMOVFW = { 0, // second literal operand POC_NOP, PCC_REGISTER, // inCond - (PCC_W | PCC_Z), // outCond + (PCC_W | PCC_N | PCC_Z), // outCond PCI_MAGIC }; @@ -1495,6 +1623,7 @@ pCodeInstruction pic16_pciMOVFF = { // mdubuc - New genericPrint}, POC_MOVFF, "MOVFF", + 4, NULL, // from branch NULL, // to branch NULL, // label @@ -1521,6 +1650,7 @@ pCodeInstruction pic16_pciMOVLB = { // mdubuc - New genericPrint}, POC_MOVLB, "MOVLB", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1547,6 +1677,7 @@ pCodeInstruction pic16_pciMOVLW = { genericPrint}, POC_MOVLW, "MOVLW", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1574,6 +1705,7 @@ pCodeInstruction pic16_pciMOVWF = { genericPrint}, POC_MOVWF, "MOVWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1589,8 +1721,8 @@ pCodeInstruction pic16_pciMOVWF = { 0, // second memory operand 0, // second literal operand POC_NOP, - PCC_REGISTER, // inCond - PCC_W, // outCond + PCC_W, // inCond + PCC_REGISTER, // outCond PCI_MAGIC }; @@ -1600,6 +1732,7 @@ pCodeInstruction pic16_pciMULLW = { // mdubuc - New genericPrint}, POC_MULLW, "MULLW", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1616,7 +1749,7 @@ pCodeInstruction pic16_pciMULLW = { // mdubuc - New 0, // second literal operand POC_NOP, (PCC_W | PCC_LITERAL), // inCond - PCC_REGISTER, // outCond - PROD + PCC_NONE, // outCond - PROD PCI_MAGIC }; @@ -1626,6 +1759,7 @@ pCodeInstruction pic16_pciMULWF = { // mdubuc - New genericPrint}, POC_MULWF, "MULWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1652,6 +1786,7 @@ pCodeInstruction pic16_pciNEGF = { // mdubuc - New genericPrint}, POC_NEGF, "NEGF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1668,7 +1803,7 @@ pCodeInstruction pic16_pciNEGF = { // mdubuc - New 0, // second literal operand POC_NOP, PCC_REGISTER, // inCond - (PCC_REGISTER | PCC_C | PCC_DC | PCC_OV | PCC_N), // outCond + (PCC_REGISTER | PCC_STATUS), // outCond PCI_MAGIC }; @@ -1678,6 +1813,7 @@ pCodeInstruction pic16_pciNOP = { genericPrint}, POC_NOP, "NOP", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1704,6 +1840,7 @@ pCodeInstruction pic16_pciPOP = { // mdubuc - New genericPrint}, POC_POP, "POP", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1730,6 +1867,7 @@ pCodeInstruction pic16_pciPUSH = { genericPrint}, POC_PUSH, "PUSH", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1756,6 +1894,7 @@ pCodeInstruction pic16_pciRCALL = { // mdubuc - New genericPrint}, POC_RCALL, "RCALL", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1764,7 +1903,7 @@ pCodeInstruction pic16_pciRCALL = { // mdubuc - New NULL, // C source 1, // num ops 0,0, // dest, bit instruction - 0,0, // branch, skip + 1,0, // branch, skip 0, // literal operand 0, // RAM access bit 0, // fast call/return mode select bit @@ -1783,6 +1922,7 @@ pCodeInstruction pic16_pciRETFIE = { genericPrint}, POC_RETFIE, "RETFIE", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1810,6 +1950,7 @@ pCodeInstruction pic16_pciRETLW = { genericPrint}, POC_RETLW, "RETLW", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1837,6 +1978,7 @@ pCodeInstruction pic16_pciRETURN = { genericPrint}, POC_RETURN, "RETURN", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1863,6 +2005,7 @@ pCodeInstruction pic16_pciRLCF = { // mdubuc - New genericPrint}, POC_RLCF, "RLCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1890,6 +2033,7 @@ pCodeInstruction pic16_pciRLCFW = { // mdubuc - New genericPrint}, POC_RLCFW, "RLCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1917,6 +2061,7 @@ pCodeInstruction pic16_pciRLNCF = { // mdubuc - New genericPrint}, POC_RLNCF, "RLNCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1943,6 +2088,7 @@ pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New genericPrint}, POC_RLNCFW, "RLNCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1969,6 +2115,7 @@ pCodeInstruction pic16_pciRRCF = { // mdubuc - New genericPrint}, POC_RRCF, "RRCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -1995,6 +2142,7 @@ pCodeInstruction pic16_pciRRCFW = { // mdubuc - New genericPrint}, POC_RRCFW, "RRCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2021,6 +2169,7 @@ pCodeInstruction pic16_pciRRNCF = { // mdubuc - New genericPrint}, POC_RRNCF, "RRNCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2048,6 +2197,7 @@ pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New genericPrint}, POC_RRNCFW, "RRNCF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2075,6 +2225,7 @@ pCodeInstruction pic16_pciSETF = { // mdubuc - New genericPrint}, POC_SETF, "SETF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2090,7 +2241,7 @@ pCodeInstruction pic16_pciSETF = { // mdubuc - New 0, // second memory operand 0, // second literal operand POC_NOP, - PCC_REGISTER, // inCond + PCC_NONE, // inCond PCC_REGISTER , // outCond PCI_MAGIC }; @@ -2102,6 +2253,7 @@ pCodeInstruction pic16_pciSUBLW = { genericPrint}, POC_SUBLW, "SUBLW", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2118,7 +2270,7 @@ pCodeInstruction pic16_pciSUBLW = { 0, // second literal operand POC_NOP, (PCC_W | PCC_LITERAL), // inCond - (PCC_W | PCC_C | PCC_DC | PCC_Z | PCC_OV | PCC_N), // outCond + (PCC_W | PCC_STATUS), // outCond PCI_MAGIC }; @@ -2129,6 +2281,7 @@ pCodeInstruction pic16_pciSUBFWB = { genericPrint}, POC_SUBFWB, "SUBFWB", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2145,7 +2298,7 @@ pCodeInstruction pic16_pciSUBFWB = { 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER | PCC_C), // inCond - (PCC_W | PCC_C | PCC_DC | PCC_Z | PCC_OV | PCC_N), // outCond + (PCC_W | PCC_STATUS), // outCond PCI_MAGIC }; @@ -2156,6 +2309,7 @@ pCodeInstruction pic16_pciSUBWF = { genericPrint}, POC_SUBWF, "SUBWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2172,7 +2326,7 @@ pCodeInstruction pic16_pciSUBWF = { 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER), // inCond - (PCC_REGISTER | PCC_Z), // outCond + (PCC_REGISTER | PCC_STATUS), // outCond PCI_MAGIC }; @@ -2183,6 +2337,7 @@ pCodeInstruction pic16_pciSUBFW = { genericPrint}, POC_SUBFW, "SUBWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2199,7 +2354,7 @@ pCodeInstruction pic16_pciSUBFW = { 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER), // inCond - (PCC_W | PCC_Z | PCC_OV | PCC_N), // outCond + (PCC_W | PCC_STATUS), // outCond PCI_MAGIC }; @@ -2210,6 +2365,7 @@ pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New genericPrint}, POC_SUBFWB_D1, "SUBFWB", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2226,7 +2382,7 @@ pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER | PCC_C), // inCond - (PCC_REGISTER | PCC_Z | PCC_C | PCC_DC | PCC_OV | PCC_N), // outCond + (PCC_REGISTER | PCC_STATUS), // outCond PCI_MAGIC }; @@ -2237,6 +2393,7 @@ pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New genericPrint}, POC_SUBFWB_D0, "SUBFWB", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2253,7 +2410,7 @@ pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER | PCC_C), // inCond - (PCC_W | PCC_Z | PCC_C | PCC_DC | PCC_OV | PCC_N), // outCond + (PCC_W | PCC_STATUS), // outCond PCI_MAGIC }; @@ -2264,6 +2421,7 @@ pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New genericPrint}, POC_SUBWFB_D1, "SUBWFB", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2280,7 +2438,7 @@ pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER | PCC_C), // inCond - (PCC_REGISTER | PCC_Z | PCC_C | PCC_DC | PCC_OV | PCC_N), // outCond + (PCC_REGISTER | PCC_STATUS), // outCond PCI_MAGIC }; @@ -2291,6 +2449,7 @@ pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New genericPrint}, POC_SUBWFB_D0, "SUBWFB", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2307,7 +2466,7 @@ pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New 0, // second literal operand POC_NOP, (PCC_W | PCC_REGISTER | PCC_C), // inCond - (PCC_W | PCC_Z | PCC_C | PCC_DC | PCC_OV | PCC_N), // outCond + (PCC_W | PCC_STATUS), // outCond PCI_MAGIC }; @@ -2318,6 +2477,7 @@ pCodeInstruction pic16_pciSWAPF = { genericPrint}, POC_SWAPF, "SWAPF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2345,6 +2505,7 @@ pCodeInstruction pic16_pciSWAPFW = { genericPrint}, POC_SWAPFW, "SWAPF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2371,6 +2532,7 @@ pCodeInstruction pic16_pciTBLRD = { // patch 15 genericPrint}, POC_TBLRD, "TBLRD*", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2397,6 +2559,7 @@ pCodeInstruction pic16_pciTBLRD_POSTINC = { // patch 15 genericPrint}, POC_TBLRD_POSTINC, "TBLRD*+", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2423,6 +2586,7 @@ pCodeInstruction pic16_pciTBLRD_POSTDEC = { // patch 15 genericPrint}, POC_TBLRD_POSTDEC, "TBLRD*-", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2449,6 +2613,7 @@ pCodeInstruction pic16_pciTBLRD_PREINC = { // patch 15 genericPrint}, POC_TBLRD_PREINC, "TBLRD+*", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2475,6 +2640,7 @@ pCodeInstruction pic16_pciTBLWT = { // patch 15 genericPrint}, POC_TBLWT, "TBLWT*", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2501,6 +2667,7 @@ pCodeInstruction pic16_pciTBLWT_POSTINC = { // patch 15 genericPrint}, POC_TBLWT_POSTINC, "TBLWT*+", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2527,6 +2694,7 @@ pCodeInstruction pic16_pciTBLWT_POSTDEC = { // patch 15 genericPrint}, POC_TBLWT_POSTDEC, "TBLWT*-", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2553,6 +2721,7 @@ pCodeInstruction pic16_pciTBLWT_PREINC = { // patch 15 genericPrint}, POC_TBLWT_PREINC, "TBLWT+*", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2580,6 +2749,7 @@ pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New genericPrint}, POC_TSTFSZ, "TSTFSZ", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2607,6 +2777,7 @@ pCodeInstruction pic16_pciXORWF = { genericPrint}, POC_XORWF, "XORWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2634,6 +2805,7 @@ pCodeInstruction pic16_pciXORFW = { genericPrint}, POC_XORFW, "XORWF", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2661,6 +2833,7 @@ pCodeInstruction pic16_pciXORLW = { genericPrint}, POC_XORLW, "XORLW", + 2, NULL, // from branch NULL, // to branch NULL, // label @@ -2677,7 +2850,35 @@ pCodeInstruction pic16_pciXORLW = { 0, // second literal operand POC_NOP, (PCC_W | PCC_LITERAL), // inCond - (PCC_W | PCC_Z | PCC_C | PCC_DC | PCC_N), // outCond + (PCC_W | PCC_Z | PCC_N), // outCond + PCI_MAGIC +}; + + +pCodeInstruction pic16_pciBANKSEL = { + {PC_OPCODE, NULL, NULL, 0, NULL, + genericDestruct, + genericPrint}, + POC_BANKSEL, + "BANKSEL", + 2, + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 0, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + 0, // second memory operand + 0, // second literal operand + POC_NOP, + PCC_NONE, // inCond + PCC_NONE, // outCond PCI_MAGIC }; @@ -2755,6 +2956,7 @@ void SAFE_snprintf(char **str, size_t *size, const char *format, ...) #endif // USE_VSNPRINTF #endif +extern set *externs; extern void pic16_initStack(int base_address, int size); extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias); extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias); @@ -2769,7 +2971,7 @@ void pic16_pCodeInitRegisters(void) initialized = 1; - pic16_initStack(0xfff, 8); +// pic16_initStack(0xfff, 8); pic16_init_pic(port->processor); pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80); @@ -2784,13 +2986,10 @@ void pic16_pCodeInitRegisters(void) pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80); pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80); - pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80); // patch 15 - pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80); // patch 15 - pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80); // patch 15 - pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80); // patch 15 - - -// pic16_pc_fsr0.r = pic16_allocProcessorRegister(IDX_FSR0,"FSR0", PO_FSR0, 0x80); // deprecated ! + pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80); + pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80); + pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80); + pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80); pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80); pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80); @@ -2799,6 +2998,20 @@ void pic16_pCodeInitRegisters(void) pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80); pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80); + pic16_stackpnt_lo = &pic16_pc_fsr1l; + pic16_stackpnt_hi = &pic16_pc_fsr1h; + pic16_stack_postdec = &pic16_pc_postdec1; + pic16_stack_postinc = &pic16_pc_postinc1; + pic16_stack_preinc = &pic16_pc_preinc1; + pic16_stack_plusw = &pic16_pc_plusw1; + + pic16_framepnt_lo = &pic16_pc_fsr2l; + pic16_framepnt_hi = &pic16_pc_fsr2h; + pic16_frame_postdec = &pic16_pc_postdec2; + pic16_frame_postinc = &pic16_pc_postinc2; + pic16_frame_preinc = &pic16_pc_preinc2; + pic16_frame_plusw = &pic16_pc_plusw2; + pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80); pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80); pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80); @@ -2819,6 +3032,13 @@ void pic16_pCodeInitRegisters(void) pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80); pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80); + + + pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80); + pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80); + pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80); + pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80); + pic16_pc_status.rIdx = IDX_STATUS; pic16_pc_intcon.rIdx = IDX_INTCON; @@ -2832,12 +3052,11 @@ void pic16_pCodeInitRegisters(void) pic16_pc_tosh.rIdx = IDX_TOSH; pic16_pc_tosu.rIdx = IDX_TOSU; - pic16_pc_tblptrl.rIdx = IDX_TBLPTRL; // patch 15 - pic16_pc_tblptrh.rIdx = IDX_TBLPTRH; // patch 15 - pic16_pc_tblptru.rIdx = IDX_TBLPTRU; // patch 15 - pic16_pc_tablat.rIdx = IDX_TABLAT; // patch 15 + pic16_pc_tblptrl.rIdx = IDX_TBLPTRL; + pic16_pc_tblptrh.rIdx = IDX_TBLPTRH; + pic16_pc_tblptru.rIdx = IDX_TBLPTRU; + pic16_pc_tablat.rIdx = IDX_TABLAT; -// pic16_pc_fsr0.rIdx = IDX_FSR0; pic16_pc_fsr0l.rIdx = IDX_FSR0L; pic16_pc_fsr0h.rIdx = IDX_FSR0H; pic16_pc_fsr1l.rIdx = IDX_FSR1L; @@ -2870,6 +3089,18 @@ void pic16_pCodeInitRegisters(void) pic16_pc_wsave.rIdx = IDX_WSAVE; pic16_pc_ssave.rIdx = IDX_SSAVE; + pic16_pc_eecon1.rIdx = IDX_EECON1; + pic16_pc_eecon2.rIdx = IDX_EECON2; + pic16_pc_eedata.rIdx = IDX_EEDATA; + pic16_pc_eeadr.rIdx = IDX_EEADR; + + + pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80); + pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80); + + pic16_pc_gpsimio.rIdx = IDX_GPSIMIO; + pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2; + /* probably should put this in a separate initialization routine */ pb_dead_pcodes = newpBlock(); @@ -2882,7 +3113,7 @@ void pic16_pCodeInitRegisters(void) /* */ /*-----------------------------------------------------------------*/ -int mnem2key(char const *mnem) +int mnem2key(unsigned char const *mnem) { int key = 0; @@ -2959,6 +3190,7 @@ void pic16initMnemonics(void) pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ; pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW; pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ; + pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW; pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF; pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW; pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW; @@ -2981,7 +3213,7 @@ void pic16initMnemonics(void) pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN; pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF; pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW; - pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF; // was [POC_RLCF] !!! + pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF; pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW; pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF; pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW; @@ -2997,18 +3229,19 @@ void pic16initMnemonics(void) pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1; pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF; pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW; - pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD; // patch 15 - pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC; // - pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC; // - pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC; // - pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT; // - pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC; // - pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC; // - pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC; // patch 15 + pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD; + pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC; + pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC; + pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC; + pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT; + pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC; + pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC; + pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC; pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ; pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW; pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF; pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW; + pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL; for(i=0; ipbHead; pb; pb = pb->next) { + for(pc = pb->pcHead; pc; pc = pc->next) { + if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize; + } + } + return (isize); +} + + /*-----------------------------------------------------------------*/ /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg- */ /* ister, RegCond will return the bit being referenced. */ @@ -3256,6 +3508,8 @@ static int RegCond(pCodeOp *pcop) if(!pcop) return 0; + if(!pcop->name)return 0; + if(pcop->type == PO_GPR_BIT && !strcmp(pcop->name, pic16_pc_status.pcop.name)) { switch(PCORB(pcop)->bit) { case PIC_C_BIT: @@ -3446,7 +3700,8 @@ pCode *pic16_newpCodeFunction(char *mod,char *f) pcf->pc.print = pCodePrintFunction; pcf->ncalled = 0; - + pcf->absblock = 0; + if(mod) { pcf->modname = Safe_calloc(1,strlen(mod)+1); strcpy(pcf->modname,mod); @@ -3459,8 +3714,9 @@ pCode *pic16_newpCodeFunction(char *mod,char *f) } else pcf->fname = NULL; - return ( (pCode *)pcf); + pcf->stackusage = 0; + return ( (pCode *)pcf); } /*-----------------------------------------------------------------*/ @@ -3480,7 +3736,17 @@ static void destructpCodeFlow(pCode *pc) deleteSet(&PCFL(pc)->registers); deleteSet(&PCFL(pc)->from); deleteSet(&PCFL(pc)->to); - free(pc); + + /* Instead of deleting the memory used by this pCode, mark + * the object as bad so that if there's a pointer to this pCode + * dangling around somewhere then (hopefully) when the type is + * checked we'll catch it. + */ + + pc->type = PC_BAD; + pic16_addpCode2pBlock(pb_dead_pcodes, pc); + +// Safe_free(pc); } @@ -3584,13 +3850,13 @@ pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...) pcad->pci.pc.type = PC_ASMDIR; pcad->pci.pc.prev = pcad->pci.pc.next = NULL; pcad->pci.pc.pb = NULL; - + pcad->pci.isize = 2; pcad->pci.pc.destruct = genericDestruct; pcad->pci.pc.print = genericPrint; if(asdir && *asdir) { - while(isspace(*asdir))asdir++; // strip any white space from the beginning + while(isspace((unsigned char)*asdir))asdir++; // strip any white space from the beginning pcad->directive = Safe_strdup( asdir ); } @@ -3603,7 +3869,7 @@ pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...) va_end(ap); - while(isspace(*lbp))lbp++; + while(isspace((unsigned char)*lbp))lbp++; if(lbp && *lbp) pcad->arg = Safe_strdup( lbp ); @@ -3620,10 +3886,19 @@ static void pCodeLabelDestruct(pCode *pc) if(!pc) return; - if((pc->type == PC_LABEL) && PCL(pc)->label) - free(PCL(pc)->label); +// if((pc->type == PC_LABEL) && PCL(pc)->label) +// Safe_free(PCL(pc)->label); + + /* Instead of deleting the memory used by this pCode, mark + * the object as bad so that if there's a pointer to this pCode + * dangling around somewhere then (hopefully) when the type is + * checked we'll catch it. + */ + + pc->type = PC_BAD; + pic16_addpCode2pBlock(pb_dead_pcodes, pc); - free(pc); +// Safe_free(pc); } @@ -3645,7 +3920,8 @@ pCode *pic16_newpCodeLabel(char *name, int key) pcl->pc.print = pCodePrintLabel; pcl->key = key; - + pcl->force = 0; + pcl->label = NULL; if(key>0) { sprintf(s,"_%05d_DS_",key); @@ -3655,10 +3931,42 @@ pCode *pic16_newpCodeLabel(char *name, int key) if(s) pcl->label = Safe_strdup(s); +// if(pic16_pcode_verbose) +// fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label); + + return ( (pCode *)pcl); } +pCode *pic16_newpCodeLabelFORCE(char *name, int key) +{ + pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key); + + pcl->force = 1; + + return ( (pCode *)pcl ); +} + +pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop) +{ + pCodeInfo *pci; + + pci = Safe_calloc(1, sizeof(pCodeInfo)); + pci->pci.pc.type = PC_INFO; + pci->pci.pc.prev = pci->pci.pc.next = NULL; + pci->pci.pc.pb = NULL; + pci->pci.label = NULL; + + pci->pci.pc.destruct = genericDestruct; + pci->pci.pc.print = genericPrint; + + pci->type = type; + pci->oper1 = pcop; + + return ((pCode *)pci); +} + /*-----------------------------------------------------------------*/ /* newpBlock - create and return a pointer to a new pBlock */ @@ -3701,6 +4009,8 @@ pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc) return pB; } + + /*-----------------------------------------------------------------*/ /* pic16_newpCodeOpLabel - Create a new label given the key */ /* Note, a negative key means that the label is part of wild card */ @@ -3746,11 +4056,13 @@ pCodeOp *pic16_newpCodeOpLit(int lit) pcop->type = PO_LITERAL; pcop->name = NULL; - if(lit>=0) { - sprintf(s,"0x%02x",lit); - if(s) - pcop->name = Safe_strdup(s); - } + //if(lit>=0) + sprintf(s,"0x%02hhx", (unsigned char)lit); + //else + // sprintf(s, "%i", lit); + + if(s) + pcop->name = Safe_strdup(s); ((pCodeOpLit *)pcop)->lit = lit; @@ -3770,11 +4082,11 @@ pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2) pcop->type = PO_LITERAL; pcop->name = NULL; - if(lit>=0) { - sprintf(s,"0x%02x, %s",lit, tb); + //if(lit>=0) { + sprintf(s,"0x%02x, %s", (unsigned char)lit, tb); if(s) pcop->name = Safe_strdup(s); - } + //} ((pCodeOpLit2 *)pcop)->lit = lit; ((pCodeOpLit2 *)pcop)->arg2 = arg2; @@ -3796,11 +4108,10 @@ pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space) PCOI(pcop)->r = r; if(r) { -// fprintf(stderr, "%s:%d %s reg %s exists\n",__FILE__, __LINE__, __FUNCTION__, name); +// fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r); PCOI(pcop)->rIdx = r->rIdx; } else { -// fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", -// __FILE__, __LINE__, __FUNCTION__, name); +// fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name); PCOI(pcop)->rIdx = -1; } // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset); @@ -3838,15 +4149,65 @@ pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype) PCOW(pcop)->subtype = subtype; PCOW(pcop)->matched = NULL; + PCOW(pcop)->pcop2 = NULL; + return pcop; } /*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/ -pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace) +pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2) { + char *s = buffer; pCodeOp *pcop; + + if(!pcwb || !subtype || !subtype2) { + fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__); + exit(1); + } + + pcop = Safe_calloc(1,sizeof(pCodeOpWild)); + pcop->type = PO_WILD; + sprintf(s,"%%%d",id); + pcop->name = Safe_strdup(s); + + PCOW(pcop)->id = id; + PCOW(pcop)->pcwb = pcwb; + PCOW(pcop)->subtype = subtype; + PCOW(pcop)->matched = NULL; + + PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild)); + + if(!subtype2->name) { + PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild)); + PCOW2(pcop)->pcop.type = PO_WILD; + sprintf(s, "%%%d", id2); + PCOW2(pcop)->pcop.name = Safe_strdup(s); + PCOW2(pcop)->id = id2; + PCOW2(pcop)->subtype = subtype2; + +// fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__, +// pcop->name, id, PCOW2(pcop)->pcop.name, id2); + } else { + PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 ); + +// fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__, +// pcop->name, id, PCOW2(pcop)->pcop.name, id2); + } + + + + return pcop; +} + + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt) +{ + pCodeOp *pcop; + pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) ); pcop->type = PO_GPR_BIT; if(s) @@ -3856,13 +4217,22 @@ pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace) PCORB(pcop)->bit = bit; PCORB(pcop)->inBitSpace = inBitSpace; + PCORB(pcop)->subtype = subt; /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */ - PCOR(pcop)->r = NULL; - PCOR(pcop)->rIdx = 0; + PCOR(pcop)->r = pic16_regWithName(s); //NULL; +// fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r); +// PCOR(pcop)->rIdx = 0; return pcop; } +pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit) +{ + return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE), + bit, 0, PO_GPR_REGISTER); +} + + /*-----------------------------------------------------------------* * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register * @@ -3899,13 +4269,39 @@ pCodeOp *pic16_newpCodeOpReg(int rIdx) return pcop; } +pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv) +{ + pCodeOp *pcop; + regs *r; + + pcop = Safe_calloc(1, sizeof(pCodeOpReg)); + pcop->name = NULL; + + r = pic16_findFreeReg(REG_GPR); + + while(r) { + if(!bitVectBitValue(bv, r->rIdx)) { + PCOR(pcop)->r = r; + PCOR(pcop)->rIdx = r->rIdx; + pcop->type = r->pc_type; + return (pcop); + } + + r = pic16_findFreeRegNext(REG_GPR, r); + } + + return NULL; +} + + + pCodeOp *pic16_newpCodeOpRegFromStr(char *name) { pCodeOp *pcop; regs *r; pcop = Safe_calloc(1,sizeof(pCodeOpReg) ); - PCOR(pcop)->r = r = pic16_allocRegByName(name, 1); + PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL); PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx; pcop->type = PCOR(pcop)->r->pc_type; pcop->name = PCOR(pcop)->r->name; @@ -3918,6 +4314,34 @@ pCodeOp *pic16_newpCodeOpRegFromStr(char *name) return pcop; } +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key) +{ + pCodeOpOpt *pcop; + + pcop = Safe_calloc(1, sizeof(pCodeOpOpt)); + + pcop->type = type; + pcop->key = Safe_strdup( key ); + + return (PCOP(pcop)); +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type) +{ + pCodeOpLocalReg *pcop; + + pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg)); + + pcop->type = type; + + return (PCOP(pcop)); +} + + /*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/ @@ -3928,7 +4352,7 @@ pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type) switch(type) { case PO_BIT: case PO_GPR_BIT: - pcop = pic16_newpCodeOpBit(name, -1,0); + pcop = pic16_newpCodeOpBit(name, -1,0, type); break; case PO_LITERAL: @@ -3961,88 +4385,143 @@ pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type) return pcop; } +/* This is a multiple of two as gpasm pads DB directives to even length, + * thus the data would be interleaved with \0 bytes... + * This is a multiple of three in order to have arrays of 3-byte pointers + * continuously in memory (without 0-padding at the lines' end). + * This is rather 12 than 6 in order not to split up 4-byte data types + * in arrays right in the middle of a 4-byte word. */ +#define DB_ITEMS_PER_LINE 12 typedef struct DBdata { int count; - char buffer[256]; + char buffer[512]; } DBdata; struct DBdata DBd; static int DBd_init = -1; /*-----------------------------------------------------------------*/ -/* Add "DB" directives to a pBlock */ +/* Initialiase "DB" data buffer */ /*-----------------------------------------------------------------*/ -void pic16_emitDB(pBlock *pb, char c) +void pic16_initDB(void) { - int l; - if (DBd_init<0) // we need to initialize - { - DBd_init = 0; - DBd.count = 0; - DBd.buffer[0] = '\0'; - } - - l = strlen(DBd.buffer); - - if (DBd.count>0) - { - sprintf(DBd.buffer+l,", 0x%02x", c & 0xff); - } - else - { - sprintf(DBd.buffer,"0x%02x", c & 0xff); - } - - DBd.count++; - - if (DBd.count>=16) - { - pic16_addpCode2pBlock(pb,pic16_newpCodeAsmDir("DB", "%s", DBd.buffer)); - DBd.count = 0; - DBd.buffer[0] = '\0'; - } - + DBd_init = -1; } + /*-----------------------------------------------------------------*/ /* Flush pending "DB" data to a pBlock */ +/* */ +/* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */ /*-----------------------------------------------------------------*/ -void pic16_flushDB(pBlock *pb) +void pic16_flushDB(char ptype, void *p) { - if (DBd.count>0) - { - pic16_addpCode2pBlock(pb,pic16_newpCodeAsmDir("DB", "%s", DBd.buffer)); - DBd.count = 0; - DBd.buffer[0] = '\0'; - } + if (DBd.count>0) { + if(ptype == 'p') + pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer)); + else + if(ptype == 'f') + fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer); + else { + /* sanity check */ + fprintf(stderr, "PIC16 port error: could not emit initial value data\n"); + } + + DBd.count = 0; + DBd.buffer[0] = '\0'; + } } + /*-----------------------------------------------------------------*/ +/* Add "DB" directives to a pBlock */ /*-----------------------------------------------------------------*/ -void pic16_pCodeConstString(char *name, char *value) +void pic16_emitDB(char c, char ptype, void *p) { - pBlock *pb; - - // fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value); + int l; - if(!name || !value) - return; + if (DBd_init<0) { + // we need to initialize + DBd_init = 0; + DBd.count = 0; + DBd.buffer[0] = '\0'; + } - pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block")); + l = strlen(DBd.buffer); + sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff); - pic16_addpBlock(pb); +// fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer); + + DBd.count++; + if (DBd.count>= DB_ITEMS_PER_LINE) + pic16_flushDB(ptype, p); +} - sprintf(buffer,"; %s = %s",name,value); - - pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer)); +void pic16_emitDS(char *s, char ptype, void *p) +{ + int l; + + if (DBd_init<0) { + // we need to initialize + DBd_init = 0; + DBd.count = 0; + DBd.buffer[0] = '\0'; + } + + l = strlen(DBd.buffer); + sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s); + +// fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer); + + DBd.count++; //=strlen(s); + if (DBd.count>=DB_ITEMS_PER_LINE) + pic16_flushDB(ptype, p); +} + + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +void pic16_pCodeConstString(char *name, char *value) +{ + pBlock *pb; + char *item; + static set *emittedSymbols = NULL; + + if(!name || !value) + return; + + /* keep track of emitted symbols to avoid multiple definition of str_ */ + if (emittedSymbols) { + /* scan set for name */ + for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols)) + { + if (!strcmp (item,name)) { + //fprintf (stderr, "%s already emitted\n", name); + return; + } // if + } // for + } // if + addSet (&emittedSymbols, Safe_strdup (name)); + + //fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value); + + pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block")); + + pic16_addpBlock(pb); + +// sprintf(buffer,"; %s = ", name); +// strcat(buffer, value); +// fputs(buffer, stderr); + +// pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer)); pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1)); do { - pic16_emitDB(pb, *value); + pic16_emitDB(*value, 'p', (void *)pb); }while (*value++); - pic16_flushDB(pb); + pic16_flushDB('p', (void *)pb); } /*-----------------------------------------------------------------*/ @@ -4189,8 +4668,11 @@ void pic16_printpBlock(FILE *of, pBlock *pb) if(pb->dbName == 'A') { absSym *ab; for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) { +// fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name); if(!strcmp(ab->name, PCF(pc)->fname)) { - fprintf(of, "\t0X%06X\n", ab->address); +// fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address); + if(ab->address != -1) + fprintf(of, "\t0X%06X", ab->address); break; } } @@ -4208,10 +4690,12 @@ void pic16_printpBlock(FILE *of, pBlock *pb) /* */ /* */ /*-----------------------------------------------------------------*/ +pCode * pic16_findNextInstruction(pCode *pci); +pCode * pic16_findPrevInstruction(pCode *pci); void pic16_unlinkpCode(pCode *pc) { - + pCode *prev; if(pc) { #ifdef PCODE_DEBUG @@ -4223,6 +4707,17 @@ void pic16_unlinkpCode(pCode *pc) if(pc->next) pc->next->prev = pc->prev; + /* move C source line down (or up) */ + if (isPCI(pc) && PCI(pc)->cline) { + prev = pic16_findNextInstruction (pc->next); + if (prev && isPCI(prev) && !PCI(prev)->cline) { + PCI(prev)->cline = PCI(pc)->cline; + } else { + prev = pic16_findPrevInstruction (pc->prev); + if (prev && isPCI(prev) && !PCI(prev)->cline) + PCI(prev)->cline = PCI(pc)->cline; + } + } pc->prev = pc->next = NULL; } } @@ -4256,15 +4751,13 @@ static void genericDestruct(pCode *pc) */ pc->type = PC_BAD; - pic16_addpCode2pBlock(pb_dead_pcodes, pc); - //free(pc); - + //Safe_free(pc); } - +void DEBUGpic16_emitcode (char *inst,char *fmt, ...); /*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/ /* modifiers for constant immediate */ @@ -4273,7 +4766,7 @@ const char *immdmod[3]={"LOW", "HIGH", "UPPER"}; char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size) { regs *r; - static char b[50]; + static char b[128]; char *s; int use_buffer = 1; // copy the string to the passed buffer pointer @@ -4285,6 +4778,8 @@ char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size) if(pcop) { switch(pcop->type) { + case PO_W: + case PO_WREG: case PO_PRODL: case PO_PRODH: case PO_INDF0: @@ -4330,6 +4825,7 @@ char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size) } return buffer; + case PO_GPR_REGISTER: case PO_DIR: s = buffer; // size = sizeof(buffer); @@ -4341,7 +4837,18 @@ char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size) SAFE_snprintf(&s,&size,"%s",pcop->name); } return buffer; + case PO_GPR_BIT: + s = buffer; + if(PCORB(pcop)->subtype == PO_GPR_TEMP) { + SAFE_snprintf(&s, &size, "%s", pcop->name); + } else { + if(PCORB(pcop)->pcor.instance) + SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance); + else + SAFE_snprintf(&s, &size, "%s", pcop->name); + } + return (buffer); default: if(pcop->name) { if(use_buffer) { @@ -4363,7 +4870,7 @@ char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size) char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size) { regs *r; - static char b[50]; + static char b[128]; char *s; int use_buffer = 1; // copy the string to the passed buffer pointer @@ -4381,6 +4888,8 @@ char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size) if(pcop) { switch(PCOR2(pcop)->pcop2->type) { + case PO_W: + case PO_WREG: case PO_PRODL: case PO_PRODH: case PO_INDF0: @@ -4479,7 +4988,7 @@ static void pCodeOpPrint(FILE *of, pCodeOp *pcop) /*-----------------------------------------------------------------*/ /* pic16_pCode2str - convert a pCode instruction to string */ /*-----------------------------------------------------------------*/ -static char *pic16_pCode2str(char *str, size_t size, pCode *pc) +char *pic16_pCode2str(char *str, size_t size, pCode *pc) { char *s = str; regs *r; @@ -4488,7 +4997,7 @@ static char *pic16_pCode2str(char *str, size_t size, pCode *pc) if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) { fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n", __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC); - exit(-1); +// exit(-1); } #endif @@ -4512,17 +5021,19 @@ static char *pic16_pCode2str(char *str, size_t size, pCode *pc) } if(PCI(pc)->isBitInst) { - if(PCI(pc)->pcop->type == PO_GPR_BIT) { + if(PCI(pc)->pcop->type != PO_GPR_BIT) { if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) ) SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", PCI(pc)->pcop->name , PCI(pc)->pcop->name ); else - SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)), + SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)), +// (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance), (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit )); + } else if(PCI(pc)->pcop->type == PO_GPR_BIT) { - SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit); - }else + SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit); + } else SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc))); //PCI(pc)->pcop->t.bit ); } else { @@ -4533,21 +5044,30 @@ static char *pic16_pCode2str(char *str, size_t size, pCode *pc) else SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc))); - }else { - SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc))); - - if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) { - if(PCI(pc)->num_ops == 3) - SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W')); - - r = pic16_getRegFromInstruction(pc); -// fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n", -// __FUNCTION__, __LINE__, r, (r)?r->name:"", (r)?r->accessBank:-1); - - if(r && !r->accessBank)SAFE_snprintf(&s,&size,", %s", "B"); - } } + else + { + SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc))); + } } + if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) { + if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst) + SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W')); + + r = pic16_getRegFromInstruction(pc); +// fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n", +// __FUNCTION__, __LINE__, r, (r)?r->name:"", (r)?r->accessBank:-1); + + if(PCI(pc)->isAccess) { + static char *bank_spec[2][2] = { + { "", ", ACCESS" }, /* gpasm uses access bank by default */ + { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */ + }; + + SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !r->accessBank) ? 1 : 0][pic16_mplab_comp ? 1 : 0]); + } + } +// } break; @@ -4557,6 +5077,17 @@ static char *pic16_pCode2str(char *str, size_t size, pCode *pc) SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment); break; + case PC_INFO: + SAFE_snprintf(&s,&size,"; info ==>"); + switch( PCINF(pc)->type ) { + case INF_OPTIMIZATION: + SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]); + break; + case INF_LOCALREGS: + SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]); + break; + }; break; + case PC_INLINE: /* assuming that inline code ends with a \n */ SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment); @@ -4575,7 +5106,9 @@ static char *pic16_pCode2str(char *str, size_t size, pCode *pc) SAFE_snprintf(&s,&size,";\t--FLOW change\n"); break; case PC_CSOURCE: - SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line); +// SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line); + SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""), + PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line); break; case PC_ASMDIR: if(PCAD(pc)->directive) { @@ -4589,6 +5122,7 @@ static char *pic16_pCode2str(char *str, size_t size, pCode *pc) case PC_BAD: SAFE_snprintf(&s,&size,";A bad pCode is being used\n"); + break; } return str; @@ -4606,7 +5140,32 @@ static void genericPrint(FILE *of, pCode *pc) switch(pc->type) { case PC_COMMENT: - fprintf(of,";%s\n", ((pCodeComment *)pc)->comment); +// fputs(((pCodeComment *)pc)->comment, of); + fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment); + break; + + case PC_INFO: + { + pBranch *pbl = PCI(pc)->label; + while(pbl && pbl->pc) { + if(pbl->pc->type == PC_LABEL) + pCodePrintLabel(of, pbl->pc); + pbl = pbl->next; + } + } + + if(pic16_pcode_verbose) { + fprintf(of, "; info ==>"); + switch(((pCodeInfo *)pc)->type) { + case INF_OPTIMIZATION: + fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]); + break; + case INF_LOCALREGS: + fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]); + break; + } + }; + break; case PC_INLINE: @@ -4665,7 +5224,10 @@ static void genericPrint(FILE *of, pCode *pc) break; case PC_CSOURCE: - fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line); +// fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line); + fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""), + PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line); + break; case PC_ASMDIR: @@ -4708,28 +5270,30 @@ static void pCodePrintFunction(FILE *of, pCode *pc) fprintf(of,"F_%s",((pCodeFunction *)pc)->modname); #endif - if(PCF(pc)->fname) { - pBranch *exits = PCF(pc)->to; - int i=0; - fprintf(of,"%s", PCF(pc)->fname); + if(!PCF(pc)->absblock) { + if(PCF(pc)->fname) { + pBranch *exits = PCF(pc)->to; + int i=0; + + fprintf(of,"%s:", PCF(pc)->fname); -// if(pic16_pcode_verbose) - fprintf(of, "\t;Function start"); + if(pic16_pcode_verbose) + fprintf(of, "\t;Function start"); - fprintf(of, "\n"); + fprintf(of, "\n"); - while(exits) { - i++; - exits = exits->next; - } - //if(i) i--; + while(exits) { + i++; + exits = exits->next; + } + //if(i) i--; - if(pic16_pcode_verbose) - fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s')); + if(pic16_pcode_verbose) + fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s')); - } else { - if((PCF(pc)->from && - PCF(pc)->from->pc->type == PC_FUNCTION && + } else { + if((PCF(pc)->from && + PCF(pc)->from->pc->type == PC_FUNCTION && PCF(PCF(pc)->from->pc)->fname) ) { if(pic16_pcode_verbose) @@ -4739,6 +5303,7 @@ static void pCodePrintFunction(FILE *of, pCode *pc) fprintf(of,"; exit point [can't find entry point]\n"); } fprintf(of, "\n"); + } } } /*-----------------------------------------------------------------*/ @@ -4770,7 +5335,7 @@ static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc) bprev = NULL; - if(pcl->type == PC_OPCODE) + if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR) b = PCI(pcl)->label; else { fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__); @@ -4789,11 +5354,11 @@ static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc) /* Found a label */ if(bprev) { bprev->next = b->next; /* Not first pCode in chain */ - free(b); +// Safe_free(b); } else { pc->destruct(pc); PCI(pcl)->label = b->next; /* First pCode in chain */ - free(b); +// Safe_free(b); } return; /* A label can't occur more than once */ } @@ -4852,7 +5417,7 @@ static void pBranchLink(pCodeFunction *f, pCodeFunction *t) } -#if 0 +#if 1 /*-----------------------------------------------------------------*/ /* pBranchFind - find the pBranch in a pBranch chain that contains */ /* a pCode */ @@ -4871,9 +5436,9 @@ static pBranch *pBranchFind(pBranch *pb,pCode *pc) } /*-----------------------------------------------------------------*/ -/* pCodeUnlink - Unlink the given pCode from its pCode chain. */ +/* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain. */ /*-----------------------------------------------------------------*/ -static void pCodeUnlink(pCode *pc) +void pic16_pCodeUnlink(pCode *pc) { pBranch *pb1,*pb2; pCode *pc1; @@ -4882,30 +5447,44 @@ static void pCodeUnlink(pCode *pc) fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__); exit(1); } + + /* move C source line down (or up) */ + if (isPCI(pc) && PCI(pc)->cline) { + pc1 = pic16_findNextInstruction (pc->next); + if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) { + PCI(pc1)->cline = PCI(pc)->cline; + } else { + pc1 = pic16_findPrevInstruction (pc->prev); + if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) + PCI(pc1)->cline = PCI(pc)->cline; + } + } /* first remove the pCode from the chain */ pc->prev->next = pc->next; pc->next->prev = pc->prev; + pc->prev = pc->next = NULL; + /* Now for the hard part... */ /* Remove the branches */ - pb1 = pc->from; + pb1 = PCI(pc)->from; while(pb1) { pc1 = pb1->pc; /* Get the pCode that branches to the * one we're unlinking */ /* search for the link back to this pCode (the one we're * unlinking) */ - if(pb2 = pBranchFind(pc1->to,pc)) { - pb2->pc = pc->to->pc; // make the replacement + if((pb2 = pBranchFind(PCI(pc1)->to,pc))) { + pb2->pc = PCI(pc)->to->pc; // make the replacement /* if the pCode we're unlinking contains multiple 'to' * branches (e.g. this a skip instruction) then we need * to copy these extra branches to the chain. */ - if(pc->to->next) - pic16_pBranchAppend(pb2, pc->to->next); + if(PCI(pc)->to->next) + pic16_pBranchAppend(pb2, PCI(pc)->to->next); } pb1 = pb1->next; @@ -5101,7 +5680,7 @@ pCode * pic16_findNextInstruction(pCode *pci) } /*-----------------------------------------------------------------*/ -/* pic16_findNextInstruction - given a pCode, find the next instruction */ +/* pic16_findPrevInstruction - given a pCode, find the next instruction */ /* in the linked list */ /*-----------------------------------------------------------------*/ pCode * pic16_findPrevInstruction(pCode *pci) @@ -5109,6 +5688,7 @@ pCode * pic16_findPrevInstruction(pCode *pci) pCode *pc = pci; while(pc) { + if((pc->type == PC_OPCODE) || (pc->type == PC_WILD) || (pc->type == PC_ASMDIR) @@ -5120,7 +5700,7 @@ pCode * pic16_findPrevInstruction(pCode *pci) fprintf(stderr,"pic16_findPrevInstruction: "); printpCode(stderr, pc); #endif - pc = pc->next; + pc = pc->prev; } //fprintf(stderr,"Couldn't find instruction\n"); @@ -5156,7 +5736,7 @@ static pCode * findFunctionEnd(pCode *pc) static void AnalyzeLabel(pCode *pc) { - pCodeUnlink(pc); + pic16_pCodeUnlink(pc); } #endif @@ -5186,66 +5766,102 @@ static void AnalyzeRETURN(pCode *pc) #endif -/*-----------------------------------------------------------------*/ -/*-----------------------------------------------------------------*/ -regs * pic16_getRegFromInstruction(pCode *pc) -{ - - if(!pc || - !isPCI(pc) || - !PCI(pc)->pcop || - PCI(pc)->num_ops == 0 || - (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall)) - return NULL; - -#if 0 - fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n", - dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type); -#endif +/*-------------------------------------------------------------------*/ +/* pic16_getRegFrompCodeOp - extract the register from a pCodeOp */ +/* if one is present. This is the common */ +/* part of pic16_getRegFromInstruction(2) */ +/*-------------------------------------------------------------------*/ - switch(PCI(pc)->pcop->type) { +regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) { + if (!pcop) return NULL; + + switch(pcop->type) { case PO_PRODL: case PO_PRODH: - case PO_INDF0: case PO_FSR0: - return PCOR(PCI(pc)->pcop)->r; - - // return typeRegWithIdx (PCOR(PCI(pc)->pcop)->rIdx, REG_SFR, 0); + case PO_W: + case PO_WREG: + case PO_STATUS: + case PO_INTCON: + case PO_PCL: + case PO_PCLATH: + case PO_PCLATU: + case PO_BSR: + return PCOR(pcop)->r; + + case PO_SFR_REGISTER: + //fprintf (stderr, "%s - SFR\n", __FUNCTION__); + return PCOR(pcop)->r; case PO_BIT: case PO_GPR_TEMP: // fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n"); - return PCOR(PCI(pc)->pcop)->r; + return PCOR(pcop)->r; case PO_IMMEDIATE: - if(PCOI(PCI(pc)->pcop)->r) - return (PCOI(PCI(pc)->pcop)->r); - - //fprintf(stderr, "pic16_getRegFromInstruction - immediate\n"); - return pic16_dirregWithName(PCI(pc)->pcop->name); - //return NULL; // PCOR(PCI(pc)->pcop)->r; +// return pic16_dirregWithName(PCOI(pcop)->r->name); + if(PCOI(pcop)->r) + return (PCOI(pcop)->r); + else + return NULL; + case PO_GPR_BIT: - return PCOR(PCI(pc)->pcop)->r; + return PCOR(pcop)->r; + case PO_GPR_REGISTER: case PO_DIR: // fprintf(stderr, "pic16_getRegFromInstruction - dir\n"); - return PCOR(PCI(pc)->pcop)->r; + return PCOR(pcop)->r; + case PO_LITERAL: //fprintf(stderr, "pic16_getRegFromInstruction - literal\n"); break; + case PO_REL_ADDR: + case PO_LABEL: + //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type)); + break; + + case PO_CRY: + case PO_STR: + /* this should never turn up */ + //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type)); + break; + + case PO_WILD: + break; + default: -// fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d\n",PCI(pc)->pcop->type); -// genericPrint(stderr, pc); + fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type)); // assert( 0 ); - break; + break; } return NULL; } +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +regs * pic16_getRegFromInstruction(pCode *pc) +{ + + if(!pc || + !isPCI(pc) || + !PCI(pc)->pcop || + PCI(pc)->num_ops == 0 || + (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall)) + return NULL; + +#if 0 + fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n", + dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type); +#endif + + return pic16_getRegFrompCodeOp (PCI(pc)->pcop); +} + /*-------------------------------------------------------------------------------*/ /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */ /*-------------------------------------------------------------------------------*/ @@ -5265,60 +5881,7 @@ regs * pic16_getRegFromInstruction2(pCode *pc) dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type); #endif -/* - * operands supported in MOVFF: - * PO_INF0/PO_FSR0 - * PO_GPR_TEMP - * PO_IMMEDIATE - * PO_DIR - * - */ - switch(PCI(pc)->pcop->type) { - case PO_PRODL: - case PO_PRODH: - - case PO_INDF0: - case PO_FSR0: - return PCOR(PCOR2(PCI(pc)->pcop)->pcop2)->r; - - // return typeRegWithIdx (PCOR(PCI(pc)->pcop)->rIdx, REG_SFR, 0); - -// case PO_BIT: - case PO_GPR_TEMP: - //fprintf(stderr, "pic16_getRegFromInstruction2 - bit or temp\n"); - return PCOR(PCOR2(PCI(pc)->pcop)->pcop2)->r; - - case PO_IMMEDIATE: -// break; -#if 1 -// if(PCOI(PCI(pc)->pcop)->r) -// return (PCOI(PCOR2(PCI(pc)->pcop)->pcop2)->r); - - //fprintf(stderr, "pic16_getRegFromInstruction2 - immediate\n"); - return pic16_dirregWithName(PCOR(PCOR2(PCI(pc)->pcop)->pcop2)->r->name); - //return NULL; // PCOR(PCI(pc)->pcop)->r; -#endif - - case PO_GPR_BIT: - break; -// return PCOR2(PCI(pc)->pcop)->r; - - case PO_DIR: - //fprintf(stderr, "pic16_getRegFromInstruction2 - dir\n"); - return PCOR(PCOR2(PCI(pc)->pcop)->pcop2)->r; - - case PO_LITERAL: - break; - //fprintf(stderr, "pic16_getRegFromInstruction2 - literal\n"); - - default: - //fprintf(stderr, "pic16_getRegFromInstruction2 - unknown reg type %d\n",PCI(pc)->pcop->type); - //genericPrint(stderr, pc); - break; - } - - return NULL; - + return pic16_getRegFrompCodeOp (PCOR2(PCI(pc)->pcop)->pcop2); } /*-----------------------------------------------------------------*/ @@ -5440,6 +6003,27 @@ void pic16_BuildFlow(pBlock *pb) //fprintf(stderr," build: "); //pflow->print(stderr,pflow); + if (checkLabel(pc)) { + + /* This instruction marks the beginning of a + * new flow segment */ + + pc->seq = 0; + seq = 1; + + /* If the previous pCode is not a flow object, then + * insert a new flow object. (This check prevents + * two consecutive flow objects from being insert in + * the case where a skip instruction preceeds an + * instruction containing a label.) */ + + if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow))) + InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow); + + PCI(pc)->pcflow = PCFL(pflow); + + } + if( PCI(pc)->isSkip) { /* The two instructions immediately following this one @@ -5469,25 +6053,6 @@ void pic16_BuildFlow(pBlock *pb) InsertpFlow(pc, &pflow); seq = 0; - } else if (checkLabel(pc)) { - - /* This instruction marks the beginning of a - * new flow segment */ - - pc->seq = 0; - seq = 1; - - /* If the previous pCode is not a flow object, then - * insert a new flow object. (This check prevents - * two consecutive flow objects from being insert in - * the case where a skip instruction preceeds an - * instruction containing a label.) */ - - if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow))) - InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow); - - PCI(pc)->pcflow = PCFL(pflow); - } last_pci = pc; pc = pc->next; @@ -5521,7 +6086,7 @@ static void unBuildFlow(pBlock *pb) pc->seq = 0; if(PCI(pc)->pcflow) { - //free(PCI(pc)->pcflow); + //Safe_free(PCI(pc)->pcflow); PCI(pc)->pcflow = NULL; } @@ -5542,7 +6107,6 @@ static void dumpCond(int cond) static char *pcc_str[] = { //"PCC_NONE", "PCC_REGISTER", - "PCC_REGISTER2", "PCC_C", "PCC_Z", "PCC_DC", @@ -5615,14 +6179,14 @@ static int isBankInstruction(pCode *pc) int bank = -1; if(!isPCI(pc)) - return -1; + return 0; if( PCI(pc)->op == POC_MOVLB || (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) { bank = PCOL(pc)->lit; } - return bank; + return 1; } @@ -5685,6 +6249,39 @@ static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to) } +pCode *pic16_getJumptabpCode (pCode *pc) { + pCode *pcinf; + + //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL); + //pc->print (stderr, pc); + pcinf = pc; + while (pcinf) { + if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL; + if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) { + switch (PCOO(PCINF(pcinf)->oper1)->type) { + case OPT_JUMPTABLE_BEGIN: + /* leading begin of jump table -- in one */ + pcinf = pic16_findPrevInstruction (pcinf); + return pcinf; + break; + + case OPT_JUMPTABLE_END: + /* leading end of jumptable -- not in one */ + return NULL; + break; + + default: + /* ignore all other PCInfos */ + break; + } + } + pcinf = pcinf->prev; + } + + /* no PCInfo found -- not in a jumptable */ + return NULL; +} + /*-----------------------------------------------------------------* * void LinkFlow(pBlock *pb) * @@ -5699,6 +6296,7 @@ static void LinkFlow(pBlock *pb) pCode *pc=NULL; pCode *pcflow; pCode *pct; + pCode *jumptab_pre = NULL; //fprintf(stderr,"linkflow \n"); @@ -5718,8 +6316,9 @@ static void LinkFlow(pBlock *pb) //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq); if(isPCI_SKIP(pc)) { - //fprintf(stderr, "ends with skip\n"); - //pc->print(stderr,pc); +// fprintf(stderr, "ends with skip\n"); +// pc->print(stderr,pc); + pct=pic16_findNextInstruction(pc->next); LinkFlow_pCode(PCI(pc),PCI(pct)); pct=pic16_findNextInstruction(pct->next); @@ -5730,18 +6329,63 @@ static void LinkFlow(pBlock *pb) if(isPCI_BRANCH(pc)) { pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop); + /* handle GOTOs in jumptables */ + if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) { + /* link to previous flow */ + //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow); + LinkFlow_pCode (PCI(jumptab_pre), PCI(pc)); + } + + switch (PCI(pc)->op) { + case POC_GOTO: + case POC_BRA: + case POC_RETURN: + case POC_RETLW: + case POC_RETFIE: + /* unconditional branches -- do not link to next instruction */ + //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__); + break; + + case POC_CALL: + case POC_RCALL: + /* unconditional calls -- link to next instruction */ + //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__); + LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next))); + break; + + case POC_BC: + case POC_BN: + case POC_BNC: + case POC_BNN: + case POC_BNOV: + case POC_BNZ: + case POC_BOV: + case POC_BZ: + /* conditional branches -- also link to next instruction */ + //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__); + LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next))); + break; + + default: + fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic); + assert (0 && "unhandled branching instruction"); + break; + } + //fprintf(stderr, "ends with branch\n "); //pc->print(stderr,pc); if(!(pcol && isPCOLAB(pcol))) { if((PCI(pc)->op != POC_RETLW) - && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RETFIE) ) { + && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) { /* continue if label is '$' which assembler knows how to parse */ if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue; - pc->print(stderr,pc); - fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__); + if(pic16_pcode_verbose) { + pc->print(stderr,pc); + fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__); + } } continue; } @@ -5751,7 +6395,8 @@ static void LinkFlow(pBlock *pb) else fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n", __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-")); - //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:"")); + +// fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):""); continue; } @@ -5786,7 +6431,7 @@ int pic16_isPCinFlow(pCode *pc, pCode *pcflow) if(!pc || !pcflow) return 0; - if(!isPCI(pc) || !PCI(pc)->pcflow || !isPCFL(pcflow) ) + if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) ) return 0; if( PCI(pc)->pcflow->pc.seq == pcflow->seq) @@ -5800,65 +6445,100 @@ int pic16_isPCinFlow(pCode *pc, pCode *pcflow) /*-----------------------------------------------------------------*/ -/* insertBankSwitch - inserts a bank switch statement in the assembly listing */ +/* insertBankSwitch - inserts a bank switch statement in the */ +/* assembly listing */ +/* */ +/* position == 0: insert before */ +/* position == 1: insert after pc */ +/* position == 2: like 0 but previous was a skip instruction */ /*-----------------------------------------------------------------*/ -static void insertBankSwitch(int position, pCode *pc, int bsr) +pCodeOp *pic16_popGetLabel(unsigned int key); +extern int pic16_labelOffset; + +static void insertBankSwitch(unsigned char position, pCode *pc) { pCode *new_pc; - regs *reg; - - if(!pc) - return; - -/* - * if bsr == -1 then do not insert a MOVLB instruction, but rather - * insert a BANKSEL assembler directive for the symbol used by - * the pCode. This will allow the linker to setup the correct - * bank at linking time - */ - if(!pic16_options.gen_banksel || bsr != -1) { -// new_pc = pic16_newpCode(POC_MOVLB, pic16_newpCodeOpLit(bsr)); + if(!pc) return; - } else { - /* emit the BANKSEL [symbol] */ - /* FIXME */ - /* IMPORTANT: The following code does not check if a symbol is - * split in multiple banks. This should be corrected. - VR 6/6/2003 */ + /* emit BANKSEL [symbol] */ - reg = pic16_getRegFromInstruction(pc); - if(!reg)return; - new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc))); - - position = 0; // position is always before (sanity check!) - } + + new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc))); + +// position = 0; // position is always before (sanity check!) #if 0 - fprintf(stderr, "%s:%d: inserting bank switch\tbank = %d\n", __FUNCTION__, __LINE__, bsr); + fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position); pc->print(stderr, pc); #endif - if(position) { - /* insert the bank switch after this pc instruction */ - pCode *pcnext = pic16_findNextInstruction(pc); - pic16_pCodeInsertAfter(pc, new_pc); - if(pcnext) - pc = pcnext; - - } else - pic16_pCodeInsertAfter(pc->prev, new_pc); + switch(position) { + case 1: { + /* insert the bank switch after this pc instruction */ + pCode *pcnext = pic16_findNextInstruction(pc); - /* Move the label, if there is one */ + pic16_pCodeInsertAfter(pc, new_pc); + if(pcnext)pc = pcnext; + }; break; + + case 0: + /* insert the bank switch BEFORE this pc instruction */ + pic16_pCodeInsertAfter(pc->prev, new_pc); + break; + + case 2: { + symbol *tlbl; + pCode *pcnext, *pcprev, *npci, *ppc; + PIC_OPCODE ipci; + int ofs1=0, ofs2=0, len=0; + + /* just like 0, but previous was a skip instruction, + * so some care should be taken */ + + pic16_labelOffset += 10000; + tlbl = newiTempLabel(NULL); + + /* invert skip instruction */ + pcprev = pic16_findPrevInstruction(pc->prev); + ipci = PCI(pcprev)->inverted_op; + npci = pic16_newpCode(ipci, PCI(pcprev)->pcop); + +// fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci); + + /* copy info from old pCode */ + ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE); + len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *); + ofs1 += strlen( PCI(pcprev)->mnemonic) + 1; + ofs2 += strlen( PCI(npci)->mnemonic) + 1; + memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from))); + PCI(npci)->op = PCI(pcprev)->inverted_op; + + /* unlink old pCode */ + ppc = pcprev->prev; + ppc->next = pcprev->next; + pcprev->next->prev = ppc; + pic16_pCodeInsertAfter(ppc, npci); + + /* extra instructions to handle invertion */ + pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key)); + pic16_pCodeInsertAfter(npci, pcnext); + pic16_pCodeInsertAfter(pc->prev, new_pc); + + pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset); + pic16_pCodeInsertAfter(pc, pcnext); + }; break; + } + + /* Move the label, if there is one */ if(PCI(pc)->label) { // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n", // __FILE__, __LINE__, pc, new_pc); PCAD(new_pc)->pci.label = PCI(pc)->label; PCI(pc)->label = NULL; } - -// fprintf(stderr, "BankSwitch has been inserted\n"); } @@ -6019,7 +6699,7 @@ static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs) for(pc = pcs; pc; pc = pc->next) { - if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE)) && + if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) && (PCI(pc)->pcop) && (PCI(pc)->pcop->type == PO_LABEL) && (PCOLAB(PCI(pc)->pcop)->key == pcl->key)) @@ -6044,8 +6724,8 @@ static void exchangeLabels(pCodeLabel *pcl, pCode *pc) pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop); // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key); - if(pcol->pcop.name) - free(pcol->pcop.name); +// if(pcol->pcop.name) +// Safe_free(pcol->pcop.name); /* If the key is negative, then we (probably) have a label to * a function and the name is already defined */ @@ -6085,8 +6765,8 @@ static void pBlockRemoveUnusedLabels(pBlock *pb) if(pbr && pbr->next) { pCode *pcd = pb->pcHead; - //fprintf(stderr, "multiple labels\n"); - //pc->print(stderr,pc); +// fprintf(stderr, "multiple labels\n"); +// pc->print(stderr,pc); pbr = pbr->next; while(pbr) { @@ -6112,17 +6792,18 @@ static void pBlockRemoveUnusedLabels(pBlock *pb) pcl = PCL(PCI(pc)->label->pc); else continue; - //fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label); +// fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label); /* This pCode is a label, so search the pBlock to see if anyone * refers to it */ - if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))) { + if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead)) + && (!pcl->force)) { //if( !findInstructionUsingLabel(pcl, pb->pcHead)) { /* Couldn't find an instruction that refers to this label * So, unlink the pCode label from it's pCode chain * and destroy the label */ - //fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label); +// fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label); DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label)); if(pc->type == PC_LABEL) { @@ -6131,7 +6812,7 @@ static void pBlockRemoveUnusedLabels(pBlock *pb) } else { unlinkpCodeFromBranch(pc, PCODE(pcl)); /*if(pc->label->next == NULL && pc->label->pc == NULL) { - free(pc->label); + Safe_free(pc->label); }*/ } @@ -6194,6 +6875,7 @@ void pic16_pBlockMergeLabels(pBlock *pb) PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr); #endif } else { + if(pic16_pcode_verbose) fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label); } } else if(pc->type == PC_CSOURCE) { @@ -6242,21 +6924,36 @@ static int OptimizepCode(char dbName) return matches; } + + +const char *pic16_pCodeOpType(pCodeOp *pcop); +const char *pic16_pCodeOpSubType(pCodeOp *pcop); + + /*-----------------------------------------------------------------*/ /* pic16_popCopyGPR2Bit - copy a pcode operator */ /*-----------------------------------------------------------------*/ pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval) { - pCodeOp *pcop; + pCodeOp *pcop=NULL; - pcop = pic16_newpCodeOpBit(pc->name, bitval, 0); +// fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name); + + if(pc->name) { + pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type); + } else { + if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type); + } + + assert(pcop != NULL); if( !( (pcop->type == PO_LABEL) || (pcop->type == PO_LITERAL) || (pcop->type == PO_STR) )) PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */ PCOR(pcop)->r->wasUsed = 1; + PCOR(pcop)->instance = PCOR(pc)->instance; return pcop; } @@ -6280,100 +6977,652 @@ static void pic16_FixRegisterBanking(pBlock *pb) pCode *pc=NULL; pCode *pcprev=NULL; regs *reg, *prevreg; - + unsigned char flag=0; + if(!pb) return; pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE); - if(!pc) - return; + if(!pc)return; /* loop through all of the flow blocks with in one pblock */ // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__); - prevreg = NULL; - do { - /* at this point, pc should point to a PC_FLOW object */ - /* for each flow block, determine the register banking - requirements */ + prevreg = NULL; + do { + /* at this point, pc should point to a PC_FLOW object */ + /* for each flow block, determine the register banking + * requirements */ + + + /* if label, then might come from other point, force banksel */ + if(isPCL(pc))prevreg = NULL; + + if(!isPCI(pc))goto loop; - if(isPCI(pc) && !PCI(pc)->is2MemOp) { + if(PCI(pc)->label)prevreg = NULL; + + if(PCI(pc)->is2MemOp)goto loop; + + /* if goto, then force banksel */ +// if(PCI(pc)->op == POC_GOTO)prevreg = NULL; + reg = pic16_getRegFromInstruction(pc); #if 0 + pc->print(stderr, pc); fprintf(stderr, "reg = %p\n", reg); + if(reg) { fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx); - fprintf(stderr, "addr = 0x%03x, bank = %d, bit=%d\tmapped = %d sfr=%d fix=%d\n", - reg->address,REG_BANK(reg),reg->isBitField, reg->isMapped, - pic16_finalMapping[ reg->address ].isSFR, reg->isFixed); + fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n", + reg->address,reg->isBitField, reg->isFixed); } #endif - /* we can be 99% that within a pBlock, between two consequtive - * refernces to the same register, the extra banksel is needless */ - - if((reg && !isACCESS_BANK(reg) && (isBankInstruction(pc) == -1)) - && (!isPCI_LIT(pc)) - && (PCI(pc)->op != POC_CALL) - - && ( ((pic16_options.opt_banksel>0) - && (!prevreg || (prevreg && !pic16_areRegsSame(reg, prevreg)))) - || (!pic16_options.opt_banksel) - ) - ) - { - /* Examine the instruction before this one to make sure it is - * not a skip type instruction */ - pcprev = findPrevpCode(pc->prev, PC_OPCODE); - - /* FIXME: if previous is SKIP pCode, we should move the BANKSEL - * before SKIP, but we have to check if the SKIP uses BANKSEL, etc... */ - if(!pcprev || (pcprev && !isPCI_SKIP(pcprev))) { - prevreg = reg; - insertBankSwitch(0, pc, (pic16_options.gen_banksel)?-1:0); - } + /* now make some tests to make sure that instruction needs bank switch */ + + /* if no register exists, and if not a bit opcode goto loop */ + if(!reg) { + if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop; + } + + if(isPCI_SKIP(pc)) { +// fprintf(stderr, "instruction is SKIP instruction\n"); +// prevreg = NULL; + } + if(reg && isACCESS_BANK(reg))goto loop; + + if(!isBankInstruction(pc))goto loop; + + if(isPCI_LIT(pc))goto loop; + + if(PCI(pc)->op == POC_CALL)goto loop; + + /* Examine the instruction before this one to make sure it is + * not a skip type instruction */ + pcprev = findPrevpCode(pc->prev, PC_OPCODE); + + flag = 0; /* add before this instruction */ + + /* if previous instruction is a skip one, then set flag + * to 2 and call insertBankSwitch */ + if(pcprev && isPCI_SKIP(pcprev)) { + flag=2; //goto loop +// prevreg = NULL; + } + + if(pic16_options.opt_banksel>0) { + char op1[128], op2[128]; + + if(prevreg) { + strcpy(op1, pic16_get_op_from_instruction(PCI(pc))); + strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev))); + if(!strcmp(op1, op2))goto loop; + } } + prevreg = reg; + insertBankSwitch(flag, pc); + +// fprintf(stderr, "BANK SWITCH inserted\n"); + +loop: + pcprev = pc; + pc = pc->next; + } while (pc); +} + +/** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/ + +/* Returns the (maximum of the) number of bytes used by the specified pCode. */ +int instrSize (pCode *pc) +{ + if (!pc) return 0; + + if (isPCAD(pc)) { + if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0; + return 4; // assumes only regular instructions using <= 4 bytes + } + + if (isPCI(pc)) return PCI(pc)->isize; + + return 0; +} + +/* Returns 1 if pc is referenced by the given label (either + * pc is the label itself or is an instruction with an attached + * label). + * Returns 0 if pc is not preceeded by the specified label. + */ +int isLabel (pCode *pc, char *label) +{ + if (!pc) return 0; - pcprev = pc; + // label attached to the pCode? + if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) { + pBranch *lab = NULL; + lab = PCI(pc)->label; + while (lab) { + if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) { + return 1; } + lab = lab->next; + } // while + } // if + + // is inline assembly label? + if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) { + // do not compare trailing ':' + if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) { + return 1; + } + } // if + + // is pCodeLabel? + if (isPCL(pc)) { + if (strcmp(PCL(pc)->label,label) == 0) { + return 1; + } + } // if + + // no label/no label attached/wrong label(s) + return 0; +} - pc = pc->next; - }while (pc); +/* Returns the distance to the given label in terms of words. + * Labels are searched only within -max .. max words from pc. + * Returns max if the label could not be found or + * its distance from pc in (-max..+max). + */ +int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) { + int dist = instrSize(pc); + pCode *curr = pc; + + // search backwards + while (dist < max && curr && !isLabel (curr, label)) { + curr = curr->prev; + dist += instrSize(curr); // sizeof (instruction) + } // while + if (curr && dist < max) { + if (target != NULL) *target = curr; + return -dist; + } -#if 0 - if(pcprev && cur_bank) { + dist = 0; + curr = pic16_findNextInstruction (pc->next); + //search forwards + while (dist < max && curr && !isLabel (curr, label)) { + dist += instrSize(curr); // sizeof (instruction) + curr = curr->next; + } // while + if (curr && dist < max) { + if (target != NULL) *target = curr; + return dist; + } + + if (target != NULL) *target = NULL; + return max; +} + +/* Returns -1 if pc does NOT denote an instruction like + * BTFS[SC] STATUS,i + * Otherwise we return + * (a) 0x10 + i for BTFSS + * (b) 0x00 + i for BTFSC + */ +int isSkipOnStatus (pCode *pc) +{ + int res = -1; + pCodeOp *pcop; + if (!pc || !isPCI(pc)) return -1; + if (PCI(pc)->op == POC_BTFSS) res = 0x10; + else if (PCI(pc)->op == POC_BTFSC) res = 0x00; + else return -1; - int pos = 1; /* Assume that the bank switch instruction(s) - * are inserted after this instruction */ + pcop = PCI(pc)->pcop; - if((PCI(pcprev)->op == POC_RETLW) || - (PCI(pcprev)->op == POC_RETURN) || - (PCI(pcprev)->op == POC_RETFIE)) { + if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) { + return res + ((pCodeOpRegBit *)pcop)->bit; + } - /* oops, a RETURN - we need to switch banks *before* the RETURN */ + return -1; +} - pos = 0; +/* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN, + * returns 0 otherwise. */ +int isConditionalBranch (pCode *pc) +{ + if (!pc || !isPCI_BRANCH(pc)) return 0; + + switch (PCI(pc)->op) { + case POC_BC: + case POC_BZ: + case POC_BOV: + case POC_BN: + case POC_BNC: + case POC_BNZ: + case POC_BNOV: + case POC_BNN: + return 1; - } - - /* Brute force - make sure that we point to bank 0 at the - * end of each flow block */ + default: + break; + } // switch -// insertBankSwitch(pos, pcprev, 0); -/* - new_pc = pic16_newpCode(POC_MOVLB, pic16_newpCodeOpLit(0)); - pic16_pCodeInsertAfter(pcprev, new_pc); -*/ - cur_bank = 0; - //fprintf(stderr, "Brute force switch\n"); + return 0; +} + +/* Returns 1 if pc has a label attached to it. + * This can be either a label stored in the pCode itself (.label) + * or a label making up its own pCode preceding this pc. + * Returns 0 if pc cannot be reached directly via a label. + */ +int hasNoLabel (pCode *pc) +{ + pCode *prev; + if (!pc) return 1; + + // are there any label pCodes between pc and the previous instruction? + prev = pic16_findPrevInstruction (pc->prev); + while (pc && pc != prev) { + // pCode with attached label? + if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) + && PCI(pc)->label) { + return 0; + } + // is inline assembly label? + if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0; + if (isPCW(pc) && PCW(pc)->label) return 0; + + // pCodeLabel? + if (isPCL(pc)) return 0; + + pc = pc->prev; + } // if + + // no label found + return 1; +} + +static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) { + char buf[512]; + va_list va; + + va_start (va, fmt); + vsprintf (buf, fmt, va); + va_end (va); + + pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf)); +} + +/* Replaces the old pCode with the new one, moving the labels, + * C source line and probably flow information to the new pCode. + */ +void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) { + if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC)) + return; + + /* first move all labels from old to new */ + PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label); + PCI(oldPC)->label = NULL; + +#if 0 + /* move C source line (if possible) */ + if (PCI(oldPC)->cline && !PCI(newPC)->cline) + PCI(newPC)->cline = PCI(oldPC)->cline; +#endif + + /* keep flow information intact */ + newPC->seq = oldPC->seq; + PCI(newPC)->pcflow = PCI(oldPC)->pcflow; + if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) { + PCI(newPC)->pcflow->end = newPC; + } + + /* insert a comment stating which pCode has been replaced */ +#if 1 + if (pic16_pcode_verbose || pic16_debug_verbose) { + char pc_str[256]; + pic16_pCode2str (pc_str, 256, oldPC); + pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str); } #endif + + /* insert new pCode into pBlock */ + pic16_pCodeInsertAfter (oldPC, newPC); + pic16_unlinkpCode (oldPC); + + /* destruct replaced pCode */ + oldPC->destruct (oldPC); +} + +/* Returns the inverted conditional branch (if any) or NULL. + * pcop must be set to the new jump target. + */ +pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop) +{ + pCode *newBcc; + + if (!bcc || !isPCI(bcc)) return NULL; + + switch (PCI(bcc)->op) { + case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break; + case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break; + case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break; + case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break; + case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break; + case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break; + case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break; + case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break; + default: + newBcc = NULL; + } + return newBcc; +} + +#define MAX_DIST_GOTO 0x7FFFFFFF +#define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA +#define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc +#define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops) +#define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA)) + +/* Follows GOTO/BRA instructions to their target instructions, stores the + * final destination (not a GOTO or BRA instruction) in target and returns + * the distance from the original pc to *target. + */ +int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) { + pCode *curr = pc; + pCode *last = NULL; + pCodeOp *lastPCOP = NULL; + int dist = 0; + int depth = 0; + + //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__); + + /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */ + while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr) + && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) { + last = curr; + lastPCOP = PCI(curr)->pcop; + dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr); + //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name); + } // while + + if (target) *target = last; + if (pcop) *pcop = lastPCOP; + return dist; +} + +/* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode. + * Otherwise the first pCode after the jumptable (after + * the OPT_JUMPTABLE_END tag) is returned. + */ +pCode *skipJumptables (pCode *pc, int *isJumptable) +{ + *isJumptable = 0; + if (!pc) return NULL; + + while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) { + *isJumptable = 1; + //fprintf (stderr, "SKIPPING jumptable\n"); + do { + //pc->print(stderr, pc); + pc = pc->next; + } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION + || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END)); + //fprintf (stderr, "<next; + } // while + + return pc; +} + +pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable) +{ + int isJumptab; + *isJumptable = 0; + while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) { + // set pc to the first pCode after a jumptable, leave pc untouched otherwise + pc = skipJumptables (pc, &isJumptab); + if (isJumptab) { + // pc is the first pCode after the jumptable + *isJumptable = 1; + } else { + // pc has not been changed by skipJumptables() + pc = pc->next; + } + } // while + + return pc; +} + +/* Turn GOTOs into BRAs if distance between GOTO and label + * is less than 1024 bytes. + * + * This method is especially useful if GOTOs after BTFS[SC] + * can be turned into BRAs as GOTO would cost another NOP + * if skipped. + */ +void pic16_OptimizeJumps () +{ + pCode *pc; + pCode *pc_prev = NULL; + pCode *pc_next = NULL; + pBlock *pb; + pCode *target; + int change, iteration, isJumptab; + int isHandled = 0; + char *label; + int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0; + + if (!the_pFile) return; + + //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__); + + for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) { + int matchedInvertRule = 1; + iteration = 1; + do { + //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb); + change = 0; + pc = pic16_findNextInstruction (pb->pcHead); + + while (pc) { + pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab); + if (isJumptab) { + // skip jumptable, i.e. start over with no pc_prev! + pc_prev = NULL; + pc = pc_next; + continue; + } // if + + /* (1) resolve chained jumps + * Do not perform this until pattern (4) is no longer present! Otherwise we will + * (a) leave dead code in and + * (b) skip over the dead code with an (unneccessary) jump. + */ + if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) { + pCodeOp *lastTargetOp = NULL; + int newDist = resolveJumpChain (pc, &target, &lastTargetOp); + int maxDist = MAX_DIST_BCC; + if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA; + if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO; + + /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */ + if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop + && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) { + //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name); + if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); } + PCI(pc)->pcop->name = lastTargetOp->name; + change++; + opt_gotochain++; + } // if + } // if + + + if (IS_GOTO(pc)) { + int dist; + int condBraType = isSkipOnStatus(pc_prev); + label = PCI(pc)->pcop->name; + dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target); + if (dist < 0) dist = -dist; + //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n"); + isHandled = 0; + + + /* (2) remove "GOTO label; label:" */ + if (isLabel (pc_next, label)) { + //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n"); + // first remove all preceeding SKIP instructions + while (pc_prev && isPCI_SKIP(pc_prev)) { + // attach labels on this instruction to pc_next + //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n"); + PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label); + PCI(pc_prev)->label = NULL; + if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); } + pic16_unlinkpCode (pc_prev); + pc_prev = pic16_findPrevInstruction (pc); + } // while + // now remove the redundant goto itself + PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label); + if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); } + pic16_unlinkpCode (pc); + pc = pic16_findPrevInstruction(pc_next->prev); + isHandled = 1; // do not perform further optimizations + opt_gotonext++; + change++; + } // if + + + /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */ + if (!isHandled && condBraType != -1 && hasNoLabel(pc)) { + if (dist < MAX_DIST_BCC) { + pCode *bcc = NULL; + switch (condBraType) { + case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break; + // no BDC on DIGIT CARRY available + case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break; + case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break; + case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break; + case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break; + // no BNDC on DIGIT CARRY available + case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break; + case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break; + case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break; + default: + // no replacement possible + bcc = NULL; + break; + } // switch + if (bcc) { + // ATTENTION: keep labels attached to BTFSx! + // HINT: GOTO is label free (checked above) + //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label); + isHandled = 1; // do not perform further optimizations + if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); } + pic16_pCodeReplace (pc_prev, bcc); + pc->destruct(pc); + pc = bcc; + opt_cond++; + change++; + } // if + } else { + //fprintf (stderr, "(%d, too far for Bcc)\n", dist); + cond_toofar++; + } // if + } // if + + if (!isHandled) { + // (4) eliminate the following (common) tripel: + // ; + // labels1: Bcc label2; + // GOTO somewhere; ; <-- instruction referenced by pc + // label2: + // and replace it by + // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc + // label2: + // ATTENTION: all labels pointing to "Bcc label2" must be attached + // to instead + // ATTENTION: This optimization is only valid if is + // not a skip operation! + // ATTENTION: somewhere must be within MAX_DIST_BCC bytes! + // ATTENTION: no label may be attached to the GOTO instruction! + if (isConditionalBranch(pc_prev) + && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev))) + && (dist < MAX_DIST_BCC) + && isLabel(pc_next,PCI(pc_prev)->pcop->name) + && hasNoLabel(pc)) { + pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop); + + if (newBcc) { + //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label); + isHandled = 1; // do not perform further optimizations + if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); } + pic16_pCodeReplace (pc_prev, newBcc); + pc->destruct(pc); + pc = newBcc; + opt_reorder++; + change++; + matchedInvertRule++; + } + } + } + + /* (5) now just turn GOTO into BRA */ + if (!isHandled && (PCI(pc)->op == POC_GOTO)) { + if (dist < MAX_DIST_BRA) { + pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop); + //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label); + if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); } + pic16_pCodeReplace (pc, newBra); + pc = newBra; + opt++; + change++; + } else { + //fprintf (stderr, "(%d, too far for BRA)\n", dist); + toofar++; + } + } // if (!isHandled) + } // if + + pc_prev = pc; + pc = pc_next; + } // while (pc) + + pBlockRemoveUnusedLabels (pb); + + // This line enables goto chain resolution! + if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0; + iteration++; + } while (change); /* fixpoint iteration per pBlock */ + } // for (pb) + + // emit some statistics concerning goto-optimization +#if 0 + if (pic16_debug_verbose || pic16_pcode_verbose) { + fprintf (stderr, "optimize-goto:\n" + "\t%5d GOTO->BRA; (%d GOTOs too far)\n" + "\t%5d BTFSx, GOTO->Bcc (%d too far)\n" + "\t%5d conditional \"skipping\" jumps inverted\n" + "\t%5d GOTOs to next instruction removed\n" + "\t%5d chained GOTOs resolved\n", + opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain); + } // if +#endif + //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__); } +#undef IS_GOTO +#undef MAX_JUMPCHAIN_DEPTH +#undef MAX_DIST_GOTO +#undef MAX_DIST_BRA +#undef MAX_DIST_BCC + +/** END OF RAPHAEL NEIDER'S ADDITIONS **/ static void pBlockDestruct(pBlock *pb) { @@ -6382,7 +7631,7 @@ static void pBlockDestruct(pBlock *pb) return; - free(pb); +// Safe_free(pb); } @@ -6443,120 +7692,132 @@ static void AnalyzeFlow(int level) static int times_called=0; pBlock *pb; - if(!the_pFile) { - - /* remove unused allocated registers before exiting */ - pic16_RemoveUnusedRegisters(); - - return; - } - - - /* if this is not the first time this function has been called, - then clean up old flow information */ - if(times_called++) { - for(pb = the_pFile->pbHead; pb; pb = pb->next) - unBuildFlow(pb); + if(!the_pFile) { + /* remove unused allocated registers before exiting */ + pic16_RemoveUnusedRegisters(); + return; + } - pic16_RegsUnMapLiveRanges(); - } - GpcFlowSeq = 1; + /* if this is not the first time this function has been called, + * then clean up old flow information */ + if(times_called++) { + for(pb = the_pFile->pbHead; pb; pb = pb->next) + unBuildFlow(pb); + pic16_RegsUnMapLiveRanges(); + } + GpcFlowSeq = 1; - /* Phase 2 - Flow Analysis - Register Banking - * - * In this phase, the individual flow blocks are examined - * and register banking is fixed. - */ + /* Phase 2 - Flow Analysis - Register Banking + * + * In this phase, the individual flow blocks are examined + * and register banking is fixed. + */ #if 0 - for(pb = the_pFile->pbHead; pb; pb = pb->next) - pic16_FixRegisterBanking(pb); + for(pb = the_pFile->pbHead; pb; pb = pb->next) + pic16_FixRegisterBanking(pb); #endif - /* Phase 2 - Flow Analysis - * - * In this phase, the pCode is partition into pCodeFlow - * blocks. The flow blocks mark the points where a continuous - * stream of instructions changes flow (e.g. because of - * a call or goto or whatever). - */ + /* Phase 2 - Flow Analysis + * + * In this phase, the pCode is partition into pCodeFlow + * blocks. The flow blocks mark the points where a continuous + * stream of instructions changes flow (e.g. because of + * a call or goto or whatever). + */ - for(pb = the_pFile->pbHead; pb; pb = pb->next) - pic16_BuildFlow(pb); + for(pb = the_pFile->pbHead; pb; pb = pb->next) + pic16_BuildFlow(pb); - /* Phase 2 - Flow Analysis - linking flow blocks - * - * In this phase, the individual flow blocks are examined - * to determine their order of excution. - */ + /* Phase 2 - Flow Analysis - linking flow blocks + * + * In this phase, the individual flow blocks are examined + * to determine their order of excution. + */ - for(pb = the_pFile->pbHead; pb; pb = pb->next) - LinkFlow(pb); + for(pb = the_pFile->pbHead; pb; pb = pb->next) + LinkFlow(pb); - /* Phase 3 - Flow Analysis - Flow Tree - * - * In this phase, the individual flow blocks are examined - * to determine their order of execution. - */ +#if 1 + if (pic16_options.opt_flags & OF_OPTIMIZE_DF) { + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + pic16_createDF (pb); +#if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0 + pic16_vcg_dump_default (pb); +#endif + //pic16_destructDF (pb); + } - for(pb = the_pFile->pbHead; pb; pb = pb->next) - pic16_BuildFlowTree(pb); + pic16_df_stats (); + if (0) releaseStack (); // releasing is costly... + } +#endif + /* Phase 3 - Flow Analysis - Flow Tree + * + * In this phase, the individual flow blocks are examined + * to determine their order of execution. + */ - /* Phase x - Flow Analysis - Used Banks - * - * In this phase, the individual flow blocks are examined - * to determine the Register Banks they use - */ + for(pb = the_pFile->pbHead; pb; pb = pb->next) + pic16_BuildFlowTree(pb); + + + /* Phase x - Flow Analysis - Used Banks + * + * In this phase, the individual flow blocks are examined + * to determine the Register Banks they use + */ #if 0 - for(pb = the_pFile->pbHead; pb; pb = pb->next) - FixBankFlow(pb); + for(pb = the_pFile->pbHead; pb; pb = pb->next) + FixBankFlow(pb); #endif - for(pb = the_pFile->pbHead; pb; pb = pb->next) - pic16_pCodeRegMapLiveRanges(pb); + for(pb = the_pFile->pbHead; pb; pb = pb->next) + pic16_pCodeRegMapLiveRanges(pb); - pic16_RemoveUnusedRegisters(); + pic16_RemoveUnusedRegisters(); + pic16_removeUnusedRegistersDF (); // for(pb = the_pFile->pbHead; pb; pb = pb->next) - pic16_pCodeRegOptimizeRegUsage(level); - - - if(!options.nopeep) - OptimizepCode('*'); + pic16_pCodeRegOptimizeRegUsage(level); #if 0 - for(pb = the_pFile->pbHead; pb; pb = pb->next) - DumpFlow(pb); + if(!options.nopeep) + OptimizepCode('*'); #endif - /* debug stuff */ - for(pb = the_pFile->pbHead; pb; pb = pb->next) { - pCode *pcflow; - for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); - (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL; - pcflow = pcflow->next) { +#if 0 + for(pb = the_pFile->pbHead; pb; pb = pb->next) + DumpFlow(pb); +#endif - FillFlow(PCFL(pcflow)); - } - } + /* debug stuff */ + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + pCode *pcflow; + + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL; + pcflow = pcflow->next) { + FillFlow(PCFL(pcflow)); + } + } #if 0 - for(pb = the_pFile->pbHead; pb; pb = pb->next) { - pCode *pcflow; - - for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); - (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL; - pcflow = pcflow->next) { + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + pCode *pcflow; - FlowStats(PCFL(pcflow)); - } - } + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL; + pcflow = pcflow->next) { + FlowStats(PCFL(pcflow)); + } + } #endif } @@ -6577,37 +7838,27 @@ void pic16_AnalyzeBanking(void) { pBlock *pb; - if(!pic16_picIsInitialized()) { - fprintf(stderr,"Temporary ERROR: at the moment you have to use\n"); - fprintf(stderr,"an include file create by inc2h.pl. See SDCC source:\n"); - fprintf(stderr,"support/scripts/inc2h.pl\n"); - fprintf(stderr,"this is a nuisance bug that will be fixed shortly\n"); - - /* I think it took a long long time to fix this bug! ;-) -- VR */ - - exit(1); - } - + /* Phase x - Flow Analysis - Used Banks + * + * In this phase, the individual flow blocks are examined + * to determine the Register Banks they use + */ - /* Phase x - Flow Analysis - Used Banks - * - * In this phase, the individual flow blocks are examined - * to determine the Register Banks they use - */ + AnalyzeFlow(0); + AnalyzeFlow(1); - AnalyzeFlow(0); - AnalyzeFlow(1); + if(!options.nopeep) + OptimizepCode('*'); -// for(pb = the_pFile->pbHead; pb; pb = pb->next) -// BanksUsedFlow(pb); - if(!the_pFile)return; - - for(pb = the_pFile->pbHead; pb; pb = pb->next) { -// fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb); - pic16_FixRegisterBanking(pb); - } + if(!the_pFile)return; + if(!pic16_options.no_banksel) { + for(pb = the_pFile->pbHead; pb; pb = pb->next) { +// fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb); + pic16_FixRegisterBanking(pb); + } + } } /*-----------------------------------------------------------------*/ @@ -6620,7 +7871,8 @@ static void buildCallTree(void ) pBranch *pbr; pBlock *pb; pCode *pc; - + regs *r; + if(!the_pFile) return; @@ -6655,10 +7907,25 @@ static void buildCallTree(void ) for(pb = the_pFile->pbHead; pb; pb = pb->next) { pCode *pc_fstart=NULL; for(pc = pb->pcHead; pc; pc = pc->next) { + + if(isPCI(pc) && pc_fstart) { + if(PCI(pc)->is2MemOp) { + r = pic16_getRegFromInstruction2(pc); + if(r && !strcmp(r->name, "POSTDEC1")) + PCF(pc_fstart)->stackusage++; + } else { + r = pic16_getRegFromInstruction(pc); + if(r && !strcmp(r->name, "PREINC1")) + PCF(pc_fstart)->stackusage--; + } + } + if(isPCF(pc)) { if (PCF(pc)->fname) { + char buf[16]; - if(STRCASECMP(PCF(pc)->fname, "_main") == 0) { + sprintf(buf, "%smain", port->fun_prefix); + if(STRCASECMP(PCF(pc)->fname, buf) == 0) { //fprintf(stderr," found main \n"); pb->cmemmap = NULL; /* FIXME do we need to free ? */ pb->dbName = 'M'; @@ -6687,6 +7954,11 @@ static void buildCallTree(void ) } } + +#if 0 + /* This is not needed because currently all register used + * by a function are stored in stack -- VR */ + /* Re-allocate the registers so that there are no collisions * between local variables when one function call another */ @@ -6697,6 +7969,7 @@ static void buildCallTree(void ) if(!pb->visited) register_usage(pb); } +#endif } @@ -6755,9 +8028,183 @@ void pic16_AnalyzepCode(char dbName) } while(changes && (i++ < MAX_PASSES)); + buildCallTree(); } + +/* convert a series of movff's of local regs to stack, with a single call to + * a support functions which does the same thing via loop */ +static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry) +{ + pBranch *pbr; + pCode *pc, *pct; + char *fname[]={"__lr_store", "__lr_restore"}; + +// pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) )); + + pct = pic16_findNextInstruction(pcstart->next); + do { + pc = pct; + pct = pc->next; //pic16_findNextInstruction(pc->next); +// pc->print(stderr, pc); + if(isPCI(pc) && PCI(pc)->label) { + pbr = PCI(pc)->label; + while(pbr && pbr->pc) { + PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr); + pbr = pbr->next; + } + +// pc->print(stderr, pc); + /* unlink pCode */ + pc->prev->next = pct; + pct->prev = pc->prev; +// pc->next = NULL; +// pc->prev = NULL; + } + } while ((pc) && (pc != pcend)); + + /* unlink movff instructions */ + pcstart->next = pcend; + pcend->prev = pcstart; + + pc = pcstart; +// if(!entry) { +// pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p( +// pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct; +// } + + pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct; + pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct; + pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct; + +// if(!entry) { +// pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p( +// pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct; +// } + + + { + symbol *sym; + + sym = newSymbol( fname[ entry?0:1 ], 0 ); + strcpy(sym->rname, fname[ entry?0:1 ]); + checkAddSym(&externs, sym); + +// fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]); + } + +} + +/*-----------------------------------------------------------------*/ +/* OptimizeLocalRegs - turn sequence of MOVFF instructions for */ +/* local registers to a support function call */ +/*-----------------------------------------------------------------*/ +void pic16_OptimizeLocalRegs(void) +{ + pBlock *pb; + pCode *pc; + pCodeInfo *pci; + pCodeOpLocalReg *pclr; + int regCount=0; + int inRegCount=0; + regs *r, *lastr=NULL, *firstr=NULL; + pCode *pcstart=NULL, *pcend=NULL; + int inEntry=0; + char *curFunc=NULL; + + /* Overview: + * local_regs begin mark + * MOVFF r0x01, POSTDEC1 + * MOVFF r0x02, POSTDEC1 + * ... + * ... + * MOVFF r0x0n, POSTDEC1 + * local_regs end mark + * + * convert the above to the below: + * MOVLW starting_register_index + * MOVWF PRODL + * MOVLW register_count + * call __save_registers_in_stack + */ + + if(!the_pFile) + return; + + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + inRegCount = regCount = 0; + firstr = lastr = NULL; + for(pc = pb->pcHead; pc; pc = pc->next) { + + /* hold current function name */ + if(pc && isPCF(pc))curFunc = PCF(pc)->fname; + + if(pc && (pc->type == PC_INFO)) { + pci = PCINF(pc); + + if(pci->type == INF_LOCALREGS) { + pclr = PCOLR(pci->oper1); + + if((pclr->type == LR_ENTRY_BEGIN) + || (pclr->type == LR_ENTRY_END))inEntry = 1; + else inEntry = 0; + + switch(pclr->type) { + case LR_ENTRY_BEGIN: + case LR_EXIT_BEGIN: + inRegCount = 1; regCount = 0; + pcstart = pc; //pic16_findNextInstruction(pc->next); + firstr = lastr = NULL; + break; + + case LR_ENTRY_END: + case LR_EXIT_END: + inRegCount = -1; + pcend = pc; //pic16_findPrevInstruction(pc->prev); + +#if 1 + if(curFunc && inWparamList(curFunc+1)) { + fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n", + filename, curFunc); + } else { + if(regCount>2) { + pic16_convertLocalRegs2Support(pcstart, pcend, regCount, + firstr, inEntry); + } + } +#endif + firstr = lastr = NULL; + break; + } + + if(inRegCount == -1) { +// fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount); + regCount = 0; + inRegCount = 0; + } + } + } else { + if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) { + if(inEntry) + r = pic16_getRegFromInstruction(pc); + else + r = pic16_getRegFromInstruction2(pc); + if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) { + if(!firstr)firstr = r; + regCount++; +// fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx); + } + } + } + } + } +} + + + + + /*-----------------------------------------------------------------*/ /* ispCodeFunction - returns true if *pc is the pCode of a */ /* function */ @@ -6857,10 +8304,12 @@ static void pBlockStats(FILE *of, pBlock *pb) fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' ')); while (r) { - fprintf(of,"; %s\n",r->name); + fprintf(of, "; %s\n",r->name); r = setNextItem(pb->tregisters); } } + + fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters)); } /*-----------------------------------------------------------------*/ @@ -6952,7 +8401,7 @@ static set *register_usage(pBlock *pb) DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n", r1->rIdx, newreg->rIdx)); r2->rIdx = newreg->rIdx; - //if(r2->name) free(r2->name); + //if(r2->name) Safe_free(r2->name); if(newreg->name) r2->name = Safe_strdup(newreg->name); else @@ -6997,7 +8446,7 @@ static set *register_usage(pBlock *pb) /* pct2 - writes the call tree to a file */ /* */ /*-----------------------------------------------------------------*/ -static void pct2(FILE *of,pBlock *pb,int indent) +static void pct2(FILE *of,pBlock *pb,int indent,int usedstack) { pCode *pc,*pcn; int i; @@ -7006,8 +8455,10 @@ static void pct2(FILE *of,pBlock *pb,int indent) if(!of) return; - if(indent > 10) + if(indent > 10) { + fprintf(of, "recursive function\n"); return; //recursion ? + } pc = setFirstItem(pb->function_entries); @@ -7017,12 +8468,13 @@ static void pct2(FILE *of,pBlock *pb,int indent) pb->visited = 0; for(i=0;itype == PC_FUNCTION) - fprintf(of,"%s\n",PCF(pc)->fname); - else - return; // ??? + if(pc->type == PC_FUNCTION) { + usedstack += PCF(pc)->stackusage; + fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack); + } else return; // ??? pc = setFirstItem(pb->function_calls); @@ -7033,7 +8485,7 @@ static void pct2(FILE *of,pBlock *pb,int indent) pcn = findFunction(dest); if(pcn) - pct2(of,pcn->pb,indent+1); + pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage); } else fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__); @@ -7065,7 +8517,6 @@ void pic16_printCallTree(FILE *of) pBlockStats(of,pb); - fprintf(of,"Call Tree\n"); pbr = the_pFile->functions; while(pbr) { @@ -7090,8 +8541,8 @@ void pic16_printCallTree(FILE *of) fprintf(of,"\n**************\n\na better call tree\n"); for(pb = the_pFile->pbHead; pb; pb = pb->next) { - if(pb->visited) - pct2(of,pb,0); +// if(pb->visited) + pct2(of,pb,0,0); } for(pb = the_pFile->pbHead; pb; pb = pb->next) { @@ -7287,3 +8738,3632 @@ char *dumpPicOptype(PIC_OPTYPE type) { return (pic_optype_names[ type ]); } + + +/*** BEGIN of stuff belonging to the BANKSEL optimization ***/ +#include "graph.h" + +#define MAX_COMMON_BANK_SIZE 32 +#define FIRST_PSEUDO_BANK_NR 1000 + +hTab *sym2bank = NULL; // --> +hTab *bank2sym = NULL; // --> +hTab *coerce = NULL; // --> <&PSEUDOBANK> +Graph *adj = NULL; + +typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr; + +typedef struct { + pseudoBankNr bank; // number assigned to this pseudoBank + unsigned int size; // number of operands assigned to this bank + unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection) +} pseudoBank; + +/*----------------------------------------------------------------------*/ +/* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */ +/*----------------------------------------------------------------------*/ +unsigned int hashSymbol (const char *str) +{ + unsigned int res = 0; + if (!str) return 0; + + while (*str) { + res ^= (*str); + res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4)); + str++; + } // while + + return res; +} + +/*-----------------------------------------------------------------------*/ +/* compareSymbol - return 1 iff sym1 equals sym2 */ +/*-----------------------------------------------------------------------*/ +int compareSymbol (const void *sym1, const void *sym2) +{ + char *s1 = (char*) sym1; + char *s2 = (char*) sym2; + + return (strcmp (s1,s2) == 0); +} + +/*-----------------------------------------------------------------------*/ +/* comparePre - return 1 iff p1 == p2 */ +/*-----------------------------------------------------------------------*/ +int comparePtr (const void *p1, const void *p2) +{ + return (p1 == p2); +} + +/*----------------------------------------------------------*/ +/* getSymbolFromOperand - return a pointer to the symbol in */ +/* the given operand and its length */ +/*----------------------------------------------------------*/ +char *getSymbolFromOperand (char *op, unsigned int *len) +{ + char *sym, *curr; + *len = 0; + + if (!op) return NULL; + + // we recognize two forms of operands: SYMBOL and (SYMBOL + offset) + sym = op; + if (*sym == '(') sym++; + + curr = sym; + while (((*curr >= 'A') && (*curr <= 'Z')) + || ((*curr >= 'a') && (*curr <= 'z')) + || ((curr != sym) && (*curr >= '0') && (*curr <= '9')) + || (*curr == '_')) { + // find end of symbol [A-Za-z_]?[A-Za-z0-9]* + curr++; + (*len)++; + } // while + + return sym; +} + +/*--------------------------------------------------------------------------*/ +/* getSymFromBank - get (one) name of a symbol assigned to the given bank */ +/*--------------------------------------------------------------------------*/ +char *getSymFromBank (pseudoBankNr bank) +{ + assert (bank2sym); + + if (bank < 0) return ""; + return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr); +} + +/*-----------------------------------------------------------------------*/ +/* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */ +/* bank number (uses hTab sym2bank), if the */ +/* symbol is not yet assigned a pseudo bank it */ +/* is assigned one here */ +/*-----------------------------------------------------------------------*/ +pseudoBankNr getPseudoBankNrFromOperand (const char *op) +{ + static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR; + pseudoBankNr bank; + unsigned int hash; + + assert (sym2bank); + + hash = hashSymbol (op) % sym2bank->size; + bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol); + if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK; + + if (bank == UNKNOWN_BANK) { + // create a pseudo bank for the operand + bank = next_bank++; + hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank); + hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op); + getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet + //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank); + } else { + //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank); + } // if + + assert (bank >= 0); + + return bank; +} + +/*--------------------------------------------------------------------*/ +/* isBanksel - check whether the given pCode is a BANKSEL instruction */ +/*--------------------------------------------------------------------*/ +int isBanksel (pCode *pc) +{ + if (!pc) return 0; + + if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) { + // BANKSEL or MOVLB + //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg); + return 1; + } + + // check for inline assembler BANKSELs + if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 || + STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) { + //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg); + return 1; + } + + // assume pc is no BANKSEL instruction + return 0; +} + +/*---------------------------------------------------------------------------------*/ +/* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */ +/* This method can not guarantee to find all modifications of the */ +/* BSR (e.g. via INDirection registers) but covers all compiler */ +/* generated plus some cases. */ +/*---------------------------------------------------------------------------------*/ +int invalidatesBSR(pCode *pc) +{ + // assembler directives invalidate BSR (well, they might, we don't know) + if (isPCAD(pc)) return 1; + + // only ASMDIRs and pCodeInstructions can invalidate BSR + if (!isPCI(pc)) return 0; + + // we have a pCodeInstruction + + // check for BSR modifying instructions + switch (PCI(pc)->op) { + case POC_CALL: + case POC_RCALL: + case POC_MOVLB: + case POC_RETFIE: // might be used as CALL replacement + case POC_RETLW: // might be used as CALL replacement + case POC_RETURN: // might be used as CALL replacement + case POC_BANKSEL: + return 1; + break; + + default: // other instruction do not change BSR unless BSR is an explicit operand! + // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...! + break; + } // switch + + // no change of BSR possible/probable + return 0; +} + +/*------------------------------------------------------------*/ +/* getBankFromBanksel - return the pseudo bank nr assigned to */ +/* the symbol referenced in this BANKSEL */ +/*------------------------------------------------------------*/ +pseudoBankNr getBankFromBanksel (pCode *pc) +{ + char *sym; + int data = (int)NULL; + + if (!pc) return INVALID_BANK; + + if (isPCAD(pc) && PCAD(pc)->directive) { + if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) { + // get symbolname from PCAD(pc)->arg + //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg); + sym = PCAD(pc)->arg; + data = getPseudoBankNrFromOperand (sym); + //fprintf (stderr, "symbol: %s, data=%i\n", sym, data); + } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) { + // get (literal) bank number from PCAD(pc)->arg + fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg); + assert (0 && "not yet implemented - turn off banksel optimization for now"); + } + } else if (isPCI(pc)) { + if (PCI(pc)->op == POC_BANKSEL) { + // get symbolname from PCI(pc)->pcop->name (?) + //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name); + sym = PCI(pc)->pcop->name; + data = getPseudoBankNrFromOperand (sym); + //fprintf (stderr, "symbol: %s, data=%i\n", sym, data); + } else if (PCI(pc)->op == POC_MOVLB) { + // get (literal) bank number from PCI(pc)->pcop->name + fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name); + assert (0 && "not yet implemented - turn off banksel optimization for now"); + } + } + + if (data == 0) + // no assigned bank could be found + return UNKNOWN_BANK; + else + return data; +} + +/*------------------------------------------------------------------------------*/ +/* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */ +/*------------------------------------------------------------------------------*/ +pseudoBankNr getEffectiveBank (pseudoBankNr bank) +{ + pseudoBank *data; + + if (bank < FIRST_PSEUDO_BANK_NR) return bank; + + do { + //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank); + data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr); + if (data) { + if (data->bank != bank) + bank = data->bank; + else + data = NULL; + } + } while (data); + + //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank); + return bank; +} + +/*------------------------------------------------------------------*/ +/* attachBsrInfo2pBlock - create a look-up table as to which pseudo */ +/* bank is selected at a given pCode */ +/*------------------------------------------------------------------*/ + +/* Create a graph with pseudo banks as its nodes and switches between + * these as edges (with the edge weight representing the absolute + * number of BANKSELs from one to the other). + * Removes redundand BANKSELs instead iff mod == 1. + * BANKSELs update the pseudo BSR, labels invalidate the current BSR + * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the + * pseudo BSR. + * TODO: check ALL instructions operands if they modify BSR directly... + * + * pb - the pBlock to annotate + * mod - select either graph creation (0) or BANKSEL removal (1) + */ +unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod) +{ + pCode *pc, *pc_next; + unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK; + int isBankselect = 0; + unsigned int banksels=0; + + if (!pb) return 0; + + pc = pic16_findNextInstruction(pb->pcHead); + while (pc) { + isBankselect = isBanksel (pc); + pc_next = pic16_findNextInstruction (pc->next); + + if (!hasNoLabel (pc)) { + // we don't know our predecessors -- assume different BSRs + prevBSR = UNKNOWN_BANK; + pseudoBSR = UNKNOWN_BANK; + //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc); + } // if + + // check if this is a BANKSEL instruction + if (isBankselect) { + pseudoBSR = getEffectiveBank (getBankFromBanksel(pc)); + //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc); + if (mod) { + if (prevBSR == pseudoBSR && pseudoBSR >= 0) { + //fprintf (stderr, "removing redundant "); pc->print (stderr, pc); + if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL")); + pic16_unlinkpCode (pc); + banksels++; + } + } else { + addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0); + banksels++; + } + } // if + + if (!isBankselect && invalidatesBSR(pc)) { + // check if this instruction invalidates the pseudoBSR + pseudoBSR = UNKNOWN_BANK; + //fprintf (stderr, "invalidated via "); pc->print (stderr, pc); + } // if + + prevBSR = pseudoBSR; + pc = pc_next; + } // while + + return banksels; +} + +/*------------------------------------------------------------------------------------*/ +/* assignToSameBank - returns 0 on success or an error code */ +/* 1 - common bank would be too large */ +/* 2 - assignment to fixed (absolute) bank not performed */ +/* */ +/* This functions assumes that unsplittable operands are already assigned to the same */ +/* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */ +/* bank so that we can make sure the bytes are laid out sequentially in memory) */ +/* TODO: Symbols with an abslute address must be handled specially! */ +/*------------------------------------------------------------------------------------*/ +int assignToSameBank (int bank0, int bank1, int doAbs) +{ + int eff0, eff1, dummy; + pseudoBank *pbank0, *pbank1; + hashtItem *hitem; + + eff0 = getEffectiveBank (bank0); + eff1 = getEffectiveBank (bank1); + + //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs); + + // nothing to do if already same bank + if (eff0 == eff1) return 0; + + if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR)) + return 2; + + // ensure eff0 < eff1 + if (eff0 > eff1) { + // swap eff0 and eff1 + dummy = eff0; + eff0 = eff1; + eff1 = dummy; + dummy = bank0; + bank0 = bank1; + bank1 = dummy; + } // if + + // now assign bank eff1 to bank eff0 + pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr); + if (!pbank0) { + pbank0 = Safe_calloc (1, sizeof (pseudoBank)); + pbank0->bank = eff0; + pbank0->size = 1; + pbank0->ref = 1; + hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0); + } // if + + pbank1 = NULL; + hitem = hTabSearch (coerce, eff1 % coerce->size); + while (hitem && hitem->pkey != (void *)((char*)0+eff1)) + hitem = hitem->next; + + if (hitem) pbank1 = (pseudoBank *) hitem->item; + +#if 0 + fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1, + pbank0->bank, pbank0->size, + getSymFromBank (eff0), getSymFromBank (eff1)); +#endif + + if (pbank1) { + if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) { +#if 0 + fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n", + pbank0->bank, pbank0->size, pbank1->bank, pbank1->size, + pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE, + getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank)); +#endif + return 1; + } // if + pbank0->size += pbank1->size; + pbank1->ref--; + if (pbank1->ref == 0) Safe_free (pbank1); + } else { + pbank0->size++; + } // if + + if (hitem) + hitem->item = pbank0; + else + hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0); + pbank0->ref++; + + //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__); + + return 0; +} + +/*----------------------------------------------------------------*/ +/* mergeGraphNodes - combines two nodes into one and modifies all */ +/* edges to and from the nodes accordingly */ +/* This method needs complete backedges, i.e. if (A,B) is an edge */ +/* then also (B,A) must be an edge (possibly with weight 0). */ +/*----------------------------------------------------------------*/ +void mergeGraphNodes (GraphNode *node1, GraphNode *node2) +{ + GraphEdge *edge, *backedge, *nextedge; + GraphNode *node; + int backweight; + + assert (node1 && node2); + assert (node1 != node2); + + // add all edges starting at node2 to node1 + edge = node2->edge; + while (edge) { + nextedge = edge->next; + node = edge->node; + backedge = getGEdge (node, node2); + if (backedge) + backweight = backedge->weight; + else + backweight = 0; + // insert edges (node1,node) and (node,node1) + addGEdge2 (node1, node, edge->weight, backweight); + // remove edges (node, node2) and (node2, node) + remGEdge (node2, node); + remGEdge (node, node2); + edge = nextedge; + } // while + + // now node2 should not be referenced by any other GraphNode... + //remGNode (adj, node2->data, node2->hash); +} + +/*----------------------------------------------------------------*/ +/* showGraph - dump the current BANKSEL graph as a node/edge list */ +/*----------------------------------------------------------------*/ +void showGraph (Graph *g) +{ + GraphNode *node; + GraphEdge *edge; + pseudoBankNr bankNr; + pseudoBank *pbank; + unsigned int size; + + node = g->node; + while (node) { + edge = node->edge; + bankNr = getEffectiveBank (node->hash); + assert (bankNr >= 0); + pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr); + if (pbank) { + bankNr = pbank->bank; + size = pbank->size; + } else { + size = 1; + } + + fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size); + + while (edge) { + if (edge->weight > 0) + fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash)); + edge = edge->next; + } // while (edge) + node = node->next; + } // while (node) +} + +/*---------------------------------------------------------------*/ +/* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */ +/*---------------------------------------------------------------*/ +void pic16_OptimizeBanksel () +{ + GraphNode *node, *node1, *node1next; + +#if 0 + // needed for more effective bank assignment (needs adjusted pic16_emit_usection()) + GraphEdge *edge, *backedge; + GraphEdge *max; + int maxWeight, weight, mergeMore, absMaxWeight; + pseudoBankNr curr0, curr1; +#endif + pseudoBank *pbank; + pseudoBankNr bankNr; + char *base_symbol0, *base_symbol1; + int len0, len1; + pBlock *pb; + set *set; + regs *reg; + unsigned int bankselsTotal = 0, bankselsRemoved = 0; + + //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__); + + if (!the_pFile || !the_pFile->pbHead) return; + + adj = newGraph (NULL); + sym2bank = newHashTable ( 255 ); + bank2sym = newHashTable ( 255 ); + coerce = newHashTable ( 255 ); + + // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A) + for (pb = the_pFile->pbHead; pb; pb = pb->next) { + bankselsTotal += attachBsrInfo2pBlock (pb, 0); + } // for pb + +#if 1 + // assign symbols with absolute addresses to their respective bank nrs + set = pic16_fix_udata; + for (reg = setFirstItem (set); reg; reg = setNextItem (set)) { + bankNr = reg->address >> 8; + node = getOrAddGNode (adj, NULL, bankNr); + bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name)); + assignToSameBank (node->hash, bankNr, 1); + + assert (bankNr >= 0); + pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr); + if (!pbank) { + pbank = Safe_calloc (1, sizeof (pseudoBank)); + pbank->bank = reg->address >> 8; //FIXED_BANK; + pbank->size = 1; + pbank->ref = 1; + hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank); + } else { + assert (pbank->bank == (reg->address >> 8)); + pbank->bank = reg->address >> 8; //FIXED_BANK; + } + //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr); + } // for reg +#endif + +#if 1 + // assign operands referring to the same symbol (which is not given an absolute address) to the same bank + //fprintf (stderr, "assign operands with the same symbol to the same bank\n"); + node = adj->node; + while (node) { + if (node->hash < 0) { node = node->next; continue; } + base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0); + node1 = node->next; + while (node1) { + if (node1->hash < 0) { node1 = node1->next; continue; } + node1next = node1->next; + base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1); + if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) { + // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries! + //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash))); + if (assignToSameBank (node->hash, node1->hash, 0)) { + fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1); + assert (0 && "Could not assign a symbol to a bank!"); + } + mergeGraphNodes (node, node1); + /* + if (node->hash < node1->hash) + mergeGraphNodes (node, node1); + else + mergeGraphNodes (node1, node); // this removes node so node->next will fail... + */ + } // if + node1 = node1next; + } // while (node1) + node = node->next; + } // while (node) +#endif + +#if 0 + // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<< + // assign tightly coupled operands to the same (pseudo) bank + //fprintf (stderr, "assign tightly coupled operands to the same bank\n"); + mergeMore = 1; + absMaxWeight = 0; + while (mergeMore) { + node = adj->node; + max = NULL; + maxWeight = 0; + while (node) { + curr0 = getEffectiveBank (node->hash); + if (curr0 < 0) { node = node->next; continue; } + edge = node->edge; + while (edge) { + assert (edge->src == node); + backedge = getGEdge (edge->node, edge->src); + weight = edge->weight + (backedge ? backedge->weight : 0); + curr1 = getEffectiveBank (edge->node->hash); + if (curr1 < 0) { edge = edge->next; continue; } + + // merging is only useful if the items are not assigned to the same bank already... + if (curr0 != curr1 && weight > maxWeight) { + if (maxWeight > absMaxWeight) absMaxWeight = maxWeight; + maxWeight = weight; + max = edge; + } // if + edge = edge->next; + } // while + node = node->next; + } // while + + if (maxWeight > 0) { +#if 0 + fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight, + max->src->hash, getSymFromBank (max->src->hash), + max->node->hash, getSymFromBank (max->node->hash)); +#endif + + node = getGNode (adj, max->src->data, max->src->hash); + node1 = getGNode (adj, max->node->data, max->node->hash); + + if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) { + if (max->src->hash < max->node->hash) + mergeGraphNodes (node, node1); + else + mergeGraphNodes (node1, node); + } else { + remGEdge (node, node1); + remGEdge (node1, node); + //mergeMore = 0; + } + + } else { + mergeMore = 0; + } + } // while +#endif + +#if 1 + // remove redundant BANKSELs + //fprintf (stderr, "removing redundant BANKSELs\n"); + for (pb = the_pFile->pbHead; pb; pb = pb->next) { + bankselsRemoved += attachBsrInfo2pBlock (pb, 1); + } // for pb +#endif + +#if 0 + fprintf (stderr, "display graph\n"); + showGraph (); +#endif + + deleteGraph (adj); + //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal); +} + +/*** END of stuff belonging to the BANKSEL optimization ***/ + + + +/*** BEGIN of helpers for pCode dataflow optimizations ***/ + +typedef unsigned int symbol_t; +typedef unsigned int valnum_t; +//typedef unsigned int hash_t; + +#ifndef INT_TO_PTR +#define INT_TO_PTR(x) (((char *) 0) + (x)) +#endif + +#ifndef PTR_TO_INT +#define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0)) +#endif + +/* statistics */ +static unsigned int pic16_df_removed_pcodes = 0; +static unsigned int pic16_df_saved_bytes = 0; +static unsigned int df_findall_sameflow = 0; +static unsigned int df_findall_otherflow = 0; +static unsigned int df_findall_in_vals = 0; + +static void pic16_df_stats () { + return; + if (pic16_debug_verbose || pic16_pcode_verbose) { + fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes); + fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow); + //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0; + } +} + +/* Remove a pCode iff possible: + * - previous pCode is no SKIP + * - pc has no label + * Returns 1 iff the pCode has been removed, 0 otherwise. */ +static int pic16_safepCodeUnlink (pCode *pc, char *comment) { + pCode *pcprev, *pcnext; + char buf[256], *total=NULL; + int len; + + if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink"; + + pcprev = pic16_findPrevInstruction (pc->prev); + pcnext = pic16_findNextInstruction (pc->next); + + /* if previous instruction is a skip -- do not remove */ + if (pcprev && isPCI_SKIP(pcprev)) return 0; + + /* move labels to next instruction (if possible) */ + if (PCI(pc)->label && !pcnext) return 0; + + if (PCI(pc)->label) { + //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__); + //pc->print (stderr, pc); + PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label); + PCI(pc)->label = NULL; + } + + /* update statistics */ + pic16_df_removed_pcodes++; + if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize; + + /* remove the pCode */ + pic16_pCode2str (buf, 256, pc); + //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf); + if (0 || pic16_debug_verbose || pic16_pcode_verbose) { + len = strlen (buf) + strlen (comment) + 10; + total = (char *) Safe_malloc (len); + SNPRINTF (total, len, "%s: %s", comment, buf); + pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total)); + Safe_free (total); + } + + /* actually unlink it from the pBlock -- also remove from to/from lists */ + pic16_pCodeUnlink (pc); + + /* remove the pCode -- release registers */ + pc->destruct (pc); + + /* report success */ + return 1; +} + + +/* ======================================================================== */ +/* === SYMBOL HANDLING ==================================================== */ +/* ======================================================================== */ + +static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */ +static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */ +static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */ + +/** Calculate a hash for a given string. + * If len == 0 the string is assumed to be NUL terminated. */ +static hash_t symbolHash (const char *str, unsigned int len) { + hash_t hash = 0; + if (!len) { + while (*str) { + hash = (hash << 2) ^ *str; + str++; + } // while + } else { + while (len--) { + hash = (hash << 2) ^ *str; + str++; + } + } + return hash; +} + +/** Return 1 iff strings v1 and v2 are identical. */ +static int symcmp (const void *v1, const void *v2) { + return !strcmp ((const char *) v1, (const char *) v2); +} + +/** Return 1 iff pointers v1 and v2 are identical. */ +static int ptrcmp (const void *v1, const void *v2) { + return (v1 == v2); +} + +enum { SPO_WREG=0x1000, + SPO_STATUS, + SPO_PRODL, + SPO_PRODH, + SPO_INDF0, + SPO_POSTDEC0, + SPO_POSTINC0, + SPO_PREINC0, + SPO_PLUSW0, + SPO_INDF1, + SPO_POSTDEC1, + SPO_POSTINC1, + SPO_PREINC1, + SPO_PLUSW1, + SPO_INDF2, + SPO_POSTDEC2, + SPO_POSTINC2, + SPO_PREINC2, + SPO_PLUSW2, + SPO_STKPTR, + SPO_TOSL, + SPO_TOSH, + SPO_TOSU, + SPO_BSR, + SPO_FSR0L, + SPO_FSR0H, + SPO_FSR1L, + SPO_FSR1H, + SPO_FSR2L, + SPO_FSR2H, + SPO_PCL, + SPO_PCLATH, + SPO_PCLATU, + SPO_TABLAT, + SPO_TBLPTRL, + SPO_TBLPTRH, + SPO_TBLPTRU, + SPO_LAST +}; + +/* Return the unique symbol_t for the given string. */ +static symbol_t symFromStr (const char *str) { + hash_t hash; + char *res; + symbol_t sym; + + if (!map_symToStr) { + int i; + struct { char *name; symbol_t sym; } predefsyms[] = { + {"WREG", SPO_WREG}, + {"STATUS", SPO_STATUS}, + {"PRODL", SPO_PRODL}, + {"PRODH", SPO_PRODH}, + {"INDF0", SPO_INDF0}, + {"POSTDEC0", SPO_POSTDEC0}, + {"POSTINC0", SPO_POSTINC0}, + {"PREINC0", SPO_PREINC0}, + {"PLUSW0", SPO_PLUSW0}, + {"INDF1", SPO_INDF1}, + {"POSTDEC1", SPO_POSTDEC1}, + {"POSTINC1", SPO_POSTINC1}, + {"PREINC1", SPO_PREINC1}, + {"PLUSW1", SPO_PLUSW1}, + {"INDF2", SPO_INDF2}, + {"POSTDEC2", SPO_POSTDEC2}, + {"POSTINC2", SPO_POSTINC2}, + {"PREINC2", SPO_PREINC2}, + {"PLUSW2", SPO_PLUSW2}, + {"STKPTR", SPO_STKPTR}, + {"TOSL", SPO_TOSL}, + {"TOSH", SPO_TOSH}, + {"TOSU", SPO_TOSU}, + {"BSR", SPO_BSR}, + {"FSR0L", SPO_FSR0L}, + {"FSR0H", SPO_FSR0H}, + {"FSR1L", SPO_FSR1L}, + {"FSR1H", SPO_FSR1H}, + {"FSR2L", SPO_FSR2L}, + {"FSR2H", SPO_FSR2H}, + {"PCL", SPO_PCL}, + {"PCLATH", SPO_PCLATH}, + {"PCLATU", SPO_PCLATU}, + {"TABLAT", SPO_TABLAT}, + {"TBLPTRL", SPO_TBLPTRL}, + {"TBLPTRH", SPO_TBLPTRH}, + {"TBLPTRU", SPO_TBLPTRU}, + {NULL, 0} + }; + + map_strToSym = newHashTable (128); + map_symToStr = newHashTable (128); + + for (i=0; predefsyms[i].name; i++) { + char *name; + + /* enter new symbol */ + sym = predefsyms[i].sym; + name = predefsyms[i].name; + res = Safe_strdup (name); + hash = symbolHash (name, 0); + + hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym)); + hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res); + } // for i + } + + hash = symbolHash (str, 0) % map_strToSym->size; + + /* find symbol in table */ + sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp)); + if (sym) { + //fprintf (stderr, "found symbol %x for %s\n", sym, str); + return sym; + } + + /* enter new symbol */ + sym = nextSymbol++; + res = Safe_strdup (str); + + hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym)); + hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res); + + //fprintf (stderr, "created symbol %x for %s\n", sym, res); + + return sym; +} + +#if 1 +static const char *strFromSym (symbol_t sym) { + return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp); +} +#endif + +/* ======================================================================== */ +/* === DEFINITION MAP HANDLING ============================================ */ +/* ======================================================================== */ + +/* A defmap provides information about which symbol is defined by which pCode. + * The most recent definitions are prepended to the list, so that the most + * recent definition can be found by forward scanning the list. + * pc2: MOVFF r0x00, r0x01 + * pc1: INCF r0x01 + * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL + * + * We attach one defmap to each flow object, and each pCode will occur at + * least once in its flow's defmap (maybe defining the 0 symbol). This can be + * used to find definitions for a pCode in its own defmap that precede pCode. + */ + +typedef struct defmap_s { + symbol_t sym; /** symbol this item refers to */ + union { + struct { + unsigned int in_mask:8; /** mask leaving in accessed bits */ + unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */ + int isRead:1; /** sym/mask is read */ + int isWrite:1; /** sym/mask is written */ + } access; + int accessmethod; + } acc; + pCode *pc; /** pCode this symbol is refrenced at */ + valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */ + valnum_t val; /** new unique number for this value (if isWrite) */ + struct defmap_s *prev, *next; /** link to previous an next definition */ +} defmap_t; + +static defmap_t *defmap_free = NULL; /** list of unused defmaps */ +static int defmap_free_count = 0; /** number of released defmap items */ + +/* Returns a defmap_t with the specified data; this will be the new list head. + * next - pointer to the current list head */ +static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) { + defmap_t *map; + + if (defmap_free) { + map = defmap_free; + defmap_free = map->next; + --defmap_free_count; + } else { + map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t)); + } + map->sym = sym; + map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00); + map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00); + map->acc.access.isRead = (isRead != 0); + map->acc.access.isWrite = (isWrite != 0); + map->pc = pc; + map->in_val = 0; + map->val = (isWrite ? val : 0); + map->prev = NULL; + map->next = next; + if (next) next->prev = map; + + return map; +} + +/* Returns a copy of the single defmap item. */ +static defmap_t *copyDefmap (defmap_t *map) { + defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t)); + memcpy (res, map, sizeof (defmap_t)); + res->next = NULL; + res->prev = NULL; + return res; +} + +/* Insert a defmap item after the specified one. */ +static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) { + if (!ref || !newItem) return 1; + + newItem->next = ref->next; + newItem->prev = ref; + ref->next = newItem; + if (newItem->next) newItem->next->prev = newItem; + + return 0; +} + +/* Check whether item (or an identical one) is already in the chain and add it if neccessary. + * item is copied before insertion into chain and therefore left untouched. + * Returns 1 iff the item has been inserted into the list, 0 otherwise. */ +static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) { + defmap_t *dummy; + dummy = *head; + while (dummy && (dummy->sym != item->sym + || dummy->pc != item->pc + || dummy->acc.accessmethod != item->acc.accessmethod + || dummy->val != item->val + || dummy->in_val != item->in_val)) { + dummy = dummy->next; + } // while + + /* item already present? */ + if (dummy) return 0; + + /* otherwise: insert copy of item */ + dummy = copyDefmap (item); + dummy->next = *head; + if (*head) (*head)->prev = dummy; + *head = dummy; + + return 1; +} + +/* Releases a defmap. This also removes the map from its chain -- update the head manually! */ +static void deleteDefmap (defmap_t *map) { + if (!map) return; + + /* unlink from chain -- fails for the first item (head is not updated!) */ + if (map->next) map->next->prev = map->prev; + if (map->prev) map->prev->next = map->next; + + /* clear map */ + memset (map, 0, sizeof (defmap_t)); + + /* save for future use */ + map->next = defmap_free; + defmap_free = map; + ++defmap_free_count; +} + +/* Release all defmaps referenced from map. */ +static void deleteDefmapChain (defmap_t **_map) { + defmap_t *map, *next; + + if (!_map) return; + + map = *_map; + + /* find list head */ + while (map && map->prev) map = map->prev; + + /* delete all items */ + while (map) { + next = map->next; + deleteDefmap (map); + map = next; + } // while + + *_map = NULL; +} + +/* Free all defmap items. */ +static void freeDefmap (defmap_t **_map) { + defmap_t *next; + defmap_t *map; + + if (!_map) return; + + map = (*_map); + + /* find list head */ + while (map->prev) map = map->prev; + + /* release all items */ + while (map) { + next = map->next; + Safe_free (map); + map = next; + } + + (*_map) = NULL; +} + +/* Returns the most recent definition for the given symbol preceeding pc. + * If no definition is found, NULL is returned. + * If pc == NULL the whole list is scanned. */ +static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) { + defmap_t *curr = map; + + if (pc) { + /* skip all definitions up to pc */ + while (curr && (curr->pc != pc)) curr = curr->next; + + /* pc not in the list -- scan the whole list for definitions */ + if (!curr) { + fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym)); + curr = map; + } else { + /* skip all definitions performed by pc */ + while (curr && (curr->pc == pc)) curr = curr->next; + } + } // if (pc) + + /* find definition for sym */ + while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) { + curr = curr->next; + } + + return curr; +} + +#if 0 +/* Returns the first use (read) of the given symbol AFTER pc. + * If no such use is found, NULL is returned. + * If pc == NULL the whole list is scanned. */ +static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) { + defmap_t *curr = map, *prev = NULL; + + if (pc) { + /* skip all definitions up to pc */ + while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; } + + /* pc not in the list -- scan the whole list for definitions */ + if (!curr) { + //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym)); + curr = prev; + } + } else { + /* find end of list */ + while (curr && curr->next) curr = curr->next; + } // if (pc) + + /* find use of sym (scan list backwards) */ + while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev; + + return curr; +} +#endif + +/* Return the defmap entry for sym AT pc. + * If none is found, NULL is returned. + * If more than one entry is found an assertion is triggered. */ +static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) { + defmap_t *res = NULL; + + /* find entries for pc */ + while (map && map->pc != pc) map = map->next; + + /* find first entry for sym @ pc */ + while (map && map->pc == pc && map->sym != sym) map = map->next; + + /* no entry found */ + if (!map) return NULL; + + /* check for more entries */ + res = map; + map = map->next; + while (map && map->pc == pc) { + /* more than one entry for sym @ pc found? */ + assert (map->sym != sym); + map = map->next; + } + + /* return single entry for sym @ pc */ + return res; +} + +/* Modifies the definition of sym at pCode to newval. + * Returns 0 on success, 1 if no definition of sym in pc has been found. + */ +static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) { + defmap_t *m = map; + + /* find definitions of pc */ + while (m && m->pc != pc) m = m->next; + + /* find definition of sym at pc */ + while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next; + + /* no definition found */ + if (!m) return 1; + + /* redefine */ + m->val = newval; + + /* update following uses of sym */ + while (m && m->pc == pc) m = m->prev; + while (m) { + if (m->sym == sym) { + m->in_val = newval; + if (m->acc.access.isWrite) m = NULL; + } // if + if (m) m = m->prev; + } // while + + return 0; +} + +/* ======================================================================== */ +/* === STACK ROUTINES ===================================================== */ +/* ======================================================================== */ + +typedef struct stack_s { + void *data; + struct stack_s *next; +} stackitem_t; + +typedef stackitem_t *dynstack_t; +static stackitem_t *free_stackitems = NULL; + +/* Create a stack with one item. */ +static dynstack_t *newStack () { + dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t)); + *s = NULL; + return s; +} + +/* Remove a stack -- its items are only marked free. */ +static void deleteStack (dynstack_t *s) { + stackitem_t *i; + + while (*s) { + i = *s; + *s = (*s)->next; + i->next = free_stackitems; + free_stackitems = i; + } // while + Safe_free (s); +} + +/* Release all stackitems. */ +static void releaseStack () { + stackitem_t *i; + + while (free_stackitems) { + i = free_stackitems->next; + Safe_free(free_stackitems); + free_stackitems = i; + } // while +} + +static void stackPush (dynstack_t *stack, void *data) { + stackitem_t *i; + + if (free_stackitems) { + i = free_stackitems; + free_stackitems = free_stackitems->next; + } else { + i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t)); + } + i->data = data; + i->next = *stack; + *stack = i; +} + +static void *stackPop (dynstack_t *stack) { + void *data; + stackitem_t *i; + + if (stack && *stack) { + data = (*stack)->data; + i = *stack; + *stack = (*stack)->next; + i->next = free_stackitems; + free_stackitems = i; + return data; + } else { + return NULL; + } +} + +#if 0 +static int stackContains (dynstack_t *s, void *data) { + stackitem_t *i; + if (!s) return 0; + i = *s; + while (i) { + if (i->data == data) return 1; + i = i->next; + } // while + + /* not found */ + return 0; +} +#endif + +static int stackIsEmpty (dynstack_t *s) { + return (*s == NULL); +} + + +typedef struct { + pCodeFlow *flow; + defmap_t *lastdef; +} state_t; + +static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) { + state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t)); + s->flow = flow; + s->lastdef = lastdef; + return s; +} + +static void deleteState (state_t *s) { + Safe_free (s); +} + +static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) { + stackitem_t *i; + + /* scan working list for state */ + if (todo) { + i = *todo; + while (i) { + /* is i == state? -- state not new */ + if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0; + i = i->next; + } // while + } + + if (done) { + i = *done; + while (i) { + /* is i == state? -- state not new */ + if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0; + i = i->next; + } // while + } + + /* not found -- state is new */ + return 1; +} + +static inline valnum_t newValnum (); + +const char *pic16_pBlockGetFunctionName (pBlock *pb) { + pCode *pc; + + if (!pb) return ""; + + pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION); + if (pc && isPCF(pc)) return PCF(pc)->fname; + else return ""; +} + +static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) { + defmap_t *map; + pCodeFlow *pcfl; + + pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow; + + /* find initial value (assigning pc == NULL) */ + map = PCFL(pcfl)->in_vals; + while (map && map->sym != sym) map = map->next; + + /* initial value already present? */ + if (map) { + //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val); + return map; + } + + /* create a new initial value */ + map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals); + PCFL(pcfl)->in_vals = map; + //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val); + return map; + +#if 0 + /* insert map as last item in pcfl's defmap */ + if (!prev) prev = PCFL(pcfl)->defmap; + if (!prev) { + PCFL(pcfl)->defmap = map; + } else { + while (prev->next) prev = prev->next; + prev->next = map; + map->prev = prev; + } + + return map; +#endif +} + +/* Find all reaching definitions for sym at pc. + * A new (!) list of definitions is returned. + * Returns the number of reaching definitions found. + * The defining defmap entries are returned in *chain. + */ +static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) { + defmap_t *map; + defmap_t *res; + + pCodeFlow *curr; + pCodeFlowLink *succ; + state_t *state; + dynstack_t *todo; /** stack of state_t */ + dynstack_t *done; /** stack of state_t */ + + int firstState, n_defs; + + assert (pc && isPCI(pc) && PCI(pc)->pcflow); + assert (chain); + + /* initialize return list */ + *chain = NULL; + + /* wildcard symbol? */ + if (!sym) return 0; + + //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb); + + map = PCI(pc)->pcflow->defmap; + + res = defmapFindDef (map, sym, pc); + //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc); + +#define USE_PRECALCED_INVALS 1 +#if USE_PRECALCED_INVALS + if (!res && PCI(pc)->pcflow->in_vals) { + res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL); + if (res) { + //fprintf (stderr, "found def in init values\n"); + df_findall_in_vals++; + } + } +#endif + + if (res) { + // found a single definition (in pc's flow) + //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val); + defmapAddCopyIfNew (chain, res); + df_findall_sameflow++; + return 1; + } + +#if USE_PRECALCED_INVALS + else { + defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym)); + return 1; + } + +#endif + +#define FORWARD_FLOW_ANALYSIS 1 +#if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS + /* no definition found in pc's flow preceeding pc */ + todo = newStack (); + done = newStack (); + n_defs = 0; firstState = 1; + stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res)); + + while (!stackIsEmpty (todo)) { + state = (state_t *) stackPop (todo); + stackPush (done, state); + curr = state->flow; + res = state->lastdef; + //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); + + /* there are no definitions BEFORE pc in pc's flow (see above) */ + if (curr == PCI(pc)->pcflow) { + if (!res) { + //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc); + res = pic16_pBlockAddInval (pc->pb, sym); + if (defmapAddCopyIfNew (chain, res)) n_defs++; + res = NULL; + } else { + //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val); + if (defmapAddCopyIfNew (chain, res)) n_defs++; + } + } + + /* save last definition of sym in this flow as initial def in successors */ + res = defmapFindDef (curr->defmap, sym, NULL); + if (!res) res = state->lastdef; + + /* add successors to working list */ + state = newState (NULL, NULL); + succ = (pCodeFlowLink *) setFirstItem (curr->to); + while (succ) { + //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0); + state->flow = succ->pcflow; + state->lastdef = res; + if (stateIsNew (state, todo, done)) { + stackPush (todo, state); + state = newState (NULL, NULL); + } // if + succ = (pCodeFlowLink *) setNextItem (curr->to); + } // while + deleteState (state); + } // while + +#else // !FORWARD_FLOW_ANALYSIS + + /* no definition found in pc's flow preceeding pc */ + todo = newStack (); + done = newStack (); + n_defs = 0; firstState = 1; + stackPush (todo, newState (PCI(pc)->pcflow, res)); + + while (!stackIsEmpty (todo)) { + state = (state_t *) stackPop (todo); + curr = state->flow; + + if (firstState) { + firstState = 0; + /* only check predecessor flows */ + } else { + /* get (last) definition of sym in this flow */ + res = defmapFindDef (curr->defmap, sym, NULL); + } + + if (res) { + /* definition found */ + //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val); + if (defmapAddCopyIfNew (chain, res)) n_defs++; + } else { + /* no definition found -- check predecessor flows */ + state = newState (NULL, NULL); + succ = (pCodeFlowLink *) setFirstItem (curr->from); + + /* if no flow predecessor available -- sym might be uninitialized */ + if (!succ) { + //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc); + res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain); + if (defmapAddCopyIfNew (chain, res)) n_defs++; + deleteDefmap (res); res = NULL; + } + + while (succ) { + //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0); + state->flow = succ->pcflow; + state->lastdef = res; + if (stateIsNew (state, todo, done)) { + stackPush (todo, state); + state = newState (NULL, NULL); + } // if + succ = (pCodeFlowLink *) setNextItem (curr->from); + } // while + deleteState (state); + } + } // while + +#endif + + /* clean up done stack */ + while (!stackIsEmpty(done)) { + deleteState ((state_t *) stackPop (done)); + } // while + deleteStack (done); + + /* return number of items in result set */ + if (n_defs == 0) { + //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc); + } else if (n_defs == 1) { + assert (*chain); + //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc); + } else if (n_defs > 0) { + //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc); +#if 0 + res = *chain; + while (res) { + fprintf (stderr, " as %4x @ %p\n", res->val, res->pc); + res = res->next; + } // while +#endif + } + //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc); + df_findall_otherflow++; + return n_defs; +} + +/* ======================================================================== */ +/* === VALUE NUMBER HANDLING ============================================== */ +/* ======================================================================== */ + +static valnum_t nextValnum = 0x1000; +static hTab *map_symToValnum = NULL; + +/** Return a new value number. */ +static inline valnum_t newValnum () { + return (nextValnum += 4); +} + +static valnum_t valnumFromStr (const char *str) { + symbol_t sym; + valnum_t val; + void *res; + + sym = symFromStr (str); + + if (!map_symToValnum) { + map_symToValnum = newHashTable (128); + } // if + + /* literal already known? */ + res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp); + + /* return existing valnum */ + if (res) return (valnum_t) PTR_TO_INT(res); + + /* create new valnum */ + val = newValnum(); + hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val)); + //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str); + return val; +} + +/* Create a valnum for a literal. */ +static valnum_t valnumFromLit (unsigned int lit) { + return ((valnum_t) 0x100 + (lit & 0x0FF)); +} + +/* Return the (positive) literal value represented by val + * or -1 iff val is no known literal's valnum. */ +static int litFromValnum (valnum_t val) { + if (val >= 0x100 && val < 0x200) { + /* valnum is a (known) literal */ + return val & 0x00FF; + } else { + /* valnum is not a known literal */ + return -1; + } +} + +#if 0 +/* Sanity check - all flows in a block must be reachable from initial flow. */ +static int verifyAllFlowsReachable (pBlock *pb) { + set *reached; + set *flowInBlock; + set *checked; + pCode *pc; + pCodeFlow *pcfl; + pCodeFlowLink *succ; + int res; + + //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb)); + + reached = NULL; + flowInBlock = NULL; + checked = NULL; + /* mark initial flow as reached (and "not needs to be reached") */ + pc = pic16_findNextpCode (pb->pcHead, PC_FLOW); + assert (pc); + addSetHead (&reached, pc); + addSetHead (&checked, pc); + + /* mark all further flows in block as "need to be reached" */ + pc = pb->pcHead; + do { + if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow); + pc = pic16_findNextInstruction (pc->next); + } while (pc); + + while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) { + /* mark as reached and "not need to be reached" */ + deleteSetItem (&reached, pcfl); + //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl); + + /* flow is no longer considered unreachable */ + deleteSetItem (&flowInBlock, pcfl); + + for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) { + if (!isinSet (checked, succ->pcflow)) { + /* flow has never been reached before */ + addSetHead (&reached, succ->pcflow); + addSetHead (&checked, succ->pcflow); + } // if + } // for succ + } // while + + //fprintf (stderr, "%s - finished\n", __FUNCTION__); + + /* by now every flow should have been reached + * --> flowInBlock should be empty */ + res = (flowInBlock == NULL); + +#if 1 + if (flowInBlock) { + fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb)); + while (flowInBlock) { + pcfl = indexSet (flowInBlock, 0); + fprintf (stderr, "not reached: flow %p\n", pcfl); + deleteSetItem (&flowInBlock, pcfl); + } // while + } +#endif + + /* clean up */ + deleteSet (&reached); + deleteSet (&flowInBlock); + deleteSet (&checked); + + /* if we reached every flow, succ is NULL by now... */ + //assert (res); // will fire on unreachable code... + return (res); +} +#endif + +/* Checks a flow for accesses to sym AFTER pc. + * + * Returns -1 if the symbol is read in this flow (before redefinition), + * returns 0 if the symbol is redefined in this flow or + * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow. + */ +int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) { + defmap_t *map, *mappc; + + /* find pc or start of definitions */ + map = pcfl->defmap; + while (map && (map->pc != pc) && map->next) map = map->next; + /* if we found pc -- ignore it */ + while (map && map->pc == pc) map = map->prev; + + /* scan list backwards (first definition first) */ + while (map && mask) { +// if (map->sym == sym) { + //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map); + mappc = map; + /* scan list for reads at this pc first */ + while (map && map->pc == mappc->pc) { + /* is the symbol (partially) read? */ + if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) { + //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc); + return -1; + } + map = map->prev; + } // while + map = mappc; + + while (map && map->pc == mappc->pc) { + /* honor (partial) redefinitions of sym */ + if ((map->sym == sym) && (map->acc.access.isWrite)) { + mask &= ~map->acc.access.mask; + //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask); + } + map = map->prev; + } // while +// } // if + /* map already points to the first defmap for the next pCode */ + //map = mappc->prev; + } // while + + /* the symbol is not completely redefined in this flow and not accessed -- symbol + * is still alive; return the appropriate mask of alive bits */ + return mask; +} + +/* Check whether a symbol is alive (AFTER pc). */ +static int pic16_isAlive (symbol_t sym, pCode *pc) { + int mask, visit; + defmap_t *map; + dynstack_t *todo, *done; + state_t *state; + pCodeFlow *pcfl; + pCodeFlowLink *succ; + + mask = 0x00ff; + + assert (isPCI(pc)); + pcfl = PCI(pc)->pcflow; + map = pcfl->defmap; + + todo = newStack (); + done = newStack (); + + state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask)); + stackPush (todo, state); + visit = 0; + + while (!stackIsEmpty (todo)) { + state = (state_t *) stackPop (todo); + pcfl = state->flow; + mask = PTR_TO_INT(state->lastdef); + if (visit) stackPush (done, state); else deleteState(state); + //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask); + // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly! + mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL); + visit++; + + /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */ + if (mask == 0) continue; + + /* symbol is (partially) read before redefinition in flow */ + if (mask == -1) break; + + /* symbol is neither read nor completely redefined -- check successor flows */ + for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) { + state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask)); + if (stateIsNew (state, todo, done)) { + stackPush (todo, state); + } else { + deleteState (state); + } + } // for + } // while + + while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo)); + while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done)); + + /* symbol is read in at least one flow -- is alive */ + if (mask == -1) return 1; + + /* symbol is read in no flow */ + return 0; +} + +/* Returns whether access to the given symbol has side effects. */ +static int pic16_symIsSpecial (symbol_t sym) { + //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym); + switch (sym) { + case SPO_INDF0: + case SPO_PLUSW0: + case SPO_POSTINC0: + case SPO_POSTDEC0: + case SPO_PREINC0: + case SPO_INDF1: + case SPO_PLUSW1: + case SPO_POSTINC1: + case SPO_POSTDEC1: + case SPO_PREINC1: + case SPO_INDF2: + case SPO_PLUSW2: + case SPO_POSTINC2: + case SPO_POSTDEC2: + case SPO_PREINC2: + case SPO_PCL: + return 1; + default: + /* no special effects known */ + return 0; + } // switch + + return 0; +} + +/* Check whether a register should be considered local (to the current function) or not. */ +static int pic16_regIsLocal (regs *r) { + symbol_t sym; + if (r) { + sym = symFromStr (r->name); + switch (sym) { + case SPO_WREG: + case SPO_FSR0L: // used in ptrget/ptrput + case SPO_FSR0H: // ... as well + case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls) + case SPO_FSR1H: // ... as well + case SPO_FSR2L: // used as frame pointer + case SPO_FSR2H: // ... as well + case SPO_PRODL: // used to return values from functions + case SPO_PRODH: // ... as well + /* these registers (and some more...) are considered local */ + return 1; + break; + default: + /* for unknown regs: check is marked local, leave if not */ + if (r->isLocal) { + return 1; + } else { + //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name); + return 0; + } + } // switch + } // if + + /* if in doubt, assume non-local... */ + return 0; +} + +/* Check all symbols touched by pc whether their newly assigned values are read. + * Returns 0 if no symbol is used later on, 1 otherwise. */ +static int pic16_pCodeIsAlive (pCode *pc) { + pCodeInstruction *pci; + defmap_t *map, *lastpc; + regs *checkreg; + + /* we can only handle PCIs */ + if (!isPCI(pc)) return 1; + + //pc->print (stderr, pc); + + pci = PCI(pc); + assert (pci && pci->pcflow && pci->pcflow->defmap); + + /* NEVER remove instructions with implicit side effects */ + switch (pci->op) { + case POC_TBLRD: + case POC_TBLRD_POSTINC: /* modify TBLPTRx */ + case POC_TBLRD_POSTDEC: + case POC_TBLRD_PREINC: + case POC_TBLWT: /* modify program memory */ + case POC_TBLWT_POSTINC: /* modify TBLPTRx */ + case POC_TBLWT_POSTDEC: + case POC_TBLWT_PREINC: + case POC_CLRWDT: /* clear watchdog timer */ + case POC_PUSH: /* should be safe to remove though... */ + case POC_POP: /* should be safe to remove though... */ + case POC_CALL: + case POC_RCALL: + case POC_RETFIE: + case POC_RETURN: + //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic); + return 1; + + default: + /* no special instruction */ + break; + } // switch + + /* prevent us from removing assignments to non-local variables */ + checkreg = NULL; + if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc); + else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc); + + if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) { + /* assignment to DIRECT operand like "BSF (_global + 1),6" */ + //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__); + //pc->print (stderr, pc); + return 1; + } + if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) { + //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : ""); + return 1; + } + +#if 1 + /* OVERKILL: prevent us from removing reads from non-local variables + * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY! + * Once registers get a "isVolatile" field this might be handled more efficiently... */ + checkreg = NULL; + if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc); + else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc); + + if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) { + /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */ + //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__); + //pc->print (stderr, pc); + return 1; + } + if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) { + //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : ""); + return 1; + } +#endif + + /* now check that the defined symbols are not used */ + map = pci->pcflow->defmap; + + /* find items for pc */ + while (map && map->pc != pc) map = map->next; + + /* no entries found? something is fishy with DF analysis... -- play safe */ + if (!map) { fprintf (stderr, "%s: defmap not found\n", __FUNCTION__); return 1; } + + /* remember first item assigned to pc for later use */ + lastpc = map; + + /* check all symbols being modified by pc */ + while (map && map->pc == pc) { + if (map->sym == 0) { map = map->next; continue; } + + /* keep pc if it references special symbols (like POSTDEC0) */ +#if 0 + { + char buf[256]; + pic16_pCode2str (buf, 256, pc); + fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf); + } +#endif + if (pic16_symIsSpecial (map->sym)) { + //fprintf (stderr, "%s: special sym\n", __FUNCTION__); + return 1; + } + if (map->acc.access.isWrite) { + if (pic16_isAlive (map->sym, pc)) { + //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym)); + return 1; + } + } + map = map->next; + } // while + + /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */ +#if 0 + { + char buf[256]; + pic16_pCode2str (buf, 256, pc); + fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf); + } +#endif + return 0; +} + +/* Adds implied operands to the list. + * sym - operand being accessed in the pCode + * list - list to append the operand + * isRead - set to 1 iff sym is read in pCode + * listRead - set to 1 iff all operands being read are to be listed + * + * Returns 0 for "normal" operands, 1 for special operands. + */ +static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) { + /* check whether accessing REG accesses other REGs as well */ + switch (sym) { + case SPO_INDF0: + /* reads FSR0x */ + *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list); + break; + + case SPO_PLUSW0: + /* reads FSR0x and WREG */ + *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list); + *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list); + break; + + case SPO_POSTDEC0: + case SPO_POSTINC0: + case SPO_PREINC0: + /* reads/modifies FSR0x */ + *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list); + *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list); + break; + + case SPO_INDF1: + /* reads FSR1x */ + *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list); + break; + + case SPO_PLUSW1: + /* reads FSR1x and WREG */ + *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list); + *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list); + break; + + case SPO_POSTDEC1: + case SPO_POSTINC1: + case SPO_PREINC1: + /* reads/modifies FSR1x */ + *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list); + *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list); + break; + + case SPO_INDF2: + /* reads FSR2x */ + *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list); + break; + + case SPO_PLUSW2: + /* reads FSR2x and WREG */ + *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list); + *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list); + break; + + case SPO_POSTDEC2: + case SPO_POSTINC2: + case SPO_PREINC2: + /* reads/modifies FSR2x */ + *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list); + *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list); + *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list); + break; + + case SPO_PCL: + /* modifies PCLATH and PCLATU */ + *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list); + if (isRead) { + /* reading PCL updates PCLATx */ + *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list); + *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list); + } + if (isWrite) { + /* writing PCL implicitly reads PCLATx (computed GOTO) */ + *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list); + *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list); + } + break; + + default: + *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list); + /* nothing special */ + return 0; + break; + } + + /* has been a special operand */ + return 1; +} + +static symbol_t pic16_fsrsym_idx[][2] = { + {SPO_FSR0L, SPO_FSR0H}, + {SPO_FSR1L, SPO_FSR1H}, + {SPO_FSR2L, SPO_FSR2H} +}; + +/* Merge multiple defmap entries for the same symbol for list's pCode. */ +static void mergeDefmapSymbols (defmap_t *list) { + defmap_t *ref, *curr, *temp; + + /* now make sure that each symbol occurs at most once per pc */ + ref = list; + while (ref && (ref->pc == list->pc)) { + curr = ref->next; + while (curr && (curr->pc == list->pc)) { + if (curr->sym == ref->sym) { + //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym)); + /* found a symbol occuring twice... merge the two */ + if (curr->acc.access.isRead) { + //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc); + ref->acc.access.isRead = 1; + ref->acc.access.in_mask |= curr->acc.access.in_mask; + } + if (curr->acc.access.isWrite) { + //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc); + ref->acc.access.isWrite = 1; + ref->acc.access.mask |= curr->acc.access.mask; + } + temp = curr; + curr = curr->next; + deleteDefmap (temp); + continue; // do not skip curr! + } // if + curr = curr->next; + } // while + ref = ref->next; + } // while +} + +/** Prepend list with the reads and definitions performed by pc. */ +static defmap_t *createDefmap (pCode *pc, defmap_t *list) { + pCodeInstruction *pci; + int cond, inCond, outCond; + int mask = 0xff, smask; + int isSpecial, isSpecial2; + symbol_t sym, sym2; + char *name; + + if (isPCAD(pc)) { + /* make sure there is at least one entry for each pc (needed by list traversal routines) */ + /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */ + fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n"); + list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list); + return list; + } + assert (isPCI(pc)); + pci = PCI(pc); + + /* handle bit instructions */ + if (pci->isBitInst) { + assert (pci->pcop->type == PO_GPR_BIT); + mask = 1U << (PCORB(PCI(pc)->pcop)->bit); + } + + /* handle (additional) implicit arguments */ + switch (pci->op) { + case POC_LFSR: + { + int lit; + valnum_t val; + lit = PCOL(pci->pcop)->lit; + assert (lit >= 0 && lit < 3); + //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)); + val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)); + //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val); + list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list); + 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... + } + break; + + case POC_MOVLB: // BSR + case POC_BANKSEL: // BSR + list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list); + break; + + case POC_MULWF: // PRODx + case POC_MULLW: // PRODx + list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list); + list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list); + break; + + case POC_POP: // TOS, STKPTR + list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list); + list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list); + list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list); + list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list); + break; + + case POC_PUSH: // STKPTR + list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list); + list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list); + list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list); + list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list); + break; + + case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L + case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L + list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list); + list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list); + list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list); + list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list); + + /* needs correctly set-up stack pointer */ + list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list); + break; + + case POC_RETLW: // return values: WREG, PRODx, FSR0L + /* pseudo read on (possible) return values */ + // WREG is handled below via outCond + list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list); + + /* caller's stack pointers must be restored */ + list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list); + break; + + case POC_RETURN: // return values; WREG, PRODx, FSR0L + case POC_RETFIE: // return value: WREG, PRODx, FSR0L + /* pseudo read on (possible) return values */ + list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list); + + /* caller's stack pointers must be restored */ + list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list); + break; + + case POC_TBLRD: + list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list); + break; + + case POC_TBLRD_POSTINC: + case POC_TBLRD_POSTDEC: + case POC_TBLRD_PREINC: + list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list); + list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list); + list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list); + list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list); + break; + + case POC_TBLWT: + list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list); + list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list); + break; + + case POC_TBLWT_POSTINC: + case POC_TBLWT_POSTDEC: + case POC_TBLWT_PREINC: + list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list); + list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list); + list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list); + list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list); + break; + + default: + /* many instruction implicitly read BSR... -- THIS IS IGNORED! */ + break; + } // switch + + /* handle explicit arguments */ + inCond = pci->inCond; + outCond = pci->outCond; + cond = inCond | outCond; + if (cond & PCC_W) { + list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list); + } // if + + /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */ + if (inCond & PCC_STATUS) { + smask = 0; + if (inCond & PCC_C) smask |= 1U << PIC_C_BIT; + if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT; + if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT; + if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT; + if (inCond & PCC_N) smask |= 1U << PIC_N_BIT; + + list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list); + //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask); + } // if + + if (outCond & PCC_STATUS) { + smask = 0; + if (outCond & PCC_C) smask |= 1U << PIC_C_BIT; + if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT; + if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT; + if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT; + if (outCond & PCC_N) smask |= 1U << PIC_N_BIT; + + list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list); + //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask); + } // if + + isSpecial = isSpecial2 = 0; + sym = sym2 = 0; + if (cond & PCC_REGISTER) { + name = pic16_get_op (pci->pcop, NULL, 0); + sym = symFromStr (name); + isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER); + //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask); + } + + if (cond & PCC_REGISTER2) { + name = pic16_get_op2 (pci->pcop, NULL, 0); + sym2 = symFromStr (name); + isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2); + //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask); + } + + + /* make sure there is at least one entry for each pc (needed by list traversal routines) */ + list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list); + + mergeDefmapSymbols (list); + + return list; +} + +#if 0 +static void printDefmap (defmap_t *map) { + defmap_t *curr; + + curr = map; + fprintf (stderr, "defmap @ %p:\n", curr); + while (curr) { + fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n", + curr->acc.access.isRead ? "R" : " ", + curr->acc.access.isWrite ? "W": " ", + curr->in_val, curr->val, + curr->acc.access.in_mask, curr->acc.access.mask, + strFromSym(curr->sym), curr->sym, + curr->pc); + curr = curr->next; + } // while + fprintf (stderr, "\n"); +} +#endif + +/* Add "additional" definitions to uniq. + * 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. + * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL. + * + * If symbols defined in additional are not present in uniq, a definition is created. + * Otherwise the present definition is altered to reflect the newer assignments. + * + * flow: --> assign1 --> assign2 --> assign3 --> ... --> + * before `------- noted in additional --------' after + * + * I assume that each symbol occurs AT MOST ONCE in uniq. + * + */ +static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) { + defmap_t *curr; + defmap_t *old; + int change = 0; + + //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional); + /* find tail of additional list (holds the first assignment) */ + curr = additional; + while (curr && curr->next) curr = curr->next; + + /* update uniq */ + do { + /* find next assignment in additionals */ + while (curr && !curr->acc.access.isWrite) curr = curr->prev; + + if (!curr) break; + + /* find item in uniq */ + old = *uniq; + //printDefmap (*uniq); + while (old && (old->sym != curr->sym)) old = old->next; + + if (old) { + /* definition found -- replace */ + if (old->val != curr->val) { + old->val = curr->val; + change++; + } // if + } else { + /* new definition */ + *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq); + change++; + } + + curr = curr->prev; + } while (1); + + /* return 0 iff uniq remained unchanged */ + return change; +} + +/* Creates the in_value list of a flow by (iteratively) merging the out_value + * lists of its predecessor flows. + * Initially *combined should be NULL, alt_in will be copied to combined. + * If *combined != NULL, combined will be altered: + * - for symbols defined in *combined but not in alt_in, + * *combined is altered to 0 (value unknown, either *combined or INIT). + * - for symbols defined in alt_in but not in *combined, + * a 0 definition is created (value unknown, either INIT or alt). + * - for symbols defined in both, *combined is: + * > left unchanged if *combined->val == alt_in->val or + * > modified to 0 otherwise (value unknown, either alt or *combined). + * + * I assume that each symbol occurs AT MOST ONCE in each list! + */ +static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) { + defmap_t *curr; + defmap_t *old; + int change = 0; + valnum_t val; + + //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in); + + if (!(*combined)) { + return defmapUpdateUniqueSym (combined, alt_in); + } // if + + /* merge the two */ + curr = alt_in; + while (curr) { + /* find symbols definition in *combined */ + old = *combined; + while (old && (old->sym != curr->sym)) old = old->next; + + if (old) { + /* definition found */ + if (old->val && (old->val != curr->val)) { + old->val = 0; /* value unknown */ + change++; + } + } else { + /* no definition found -- can be either INIT or alt_in's value */ + val = pic16_pBlockAddInval (pb, curr->sym)->val; + *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined); + if (val != curr->val) change++; + } + + curr = curr->next; + } // while (curr) + + /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */ + old = *combined; + while (old) { + if (old->val != 0) { + /* find definition in alt_in */ + curr = alt_in; + while (curr && curr->sym != old->sym) curr = curr->next; + if (!curr) { + /* symbol defined in *combined only -- can be either INIT or *combined */ + val = pic16_pBlockAddInval (pb, old->sym)->val; + if (old->val != val) { + old->val = 0; + change++; + } + } // if + } // if + + old = old->next; + } // while + + return change; +} + +static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) { + defmap_t *curr1, *curr2; + symbol_t sym; + + /* identical maps are equal */ + if (map1 == map2) return 0; + + if (!map1) return -1; + if (!map2) return 1; + + //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2); + + /* check length */ + curr1 = map1; + curr2 = map2; + while (curr1 && curr2) { + curr1 = curr1->next; + curr2 = curr2->next; + } // while + + /* one of them longer? */ + if (curr1) return 1; + if (curr2) return -1; + + /* both lists are of equal length -- compare (in O(n^2)) */ + curr1 = map1; + while (curr1) { + sym = curr1->sym; + curr2 = map2; + while (curr2 && curr2->sym != sym) curr2 = curr2->next; + if (!curr2) return 1; // symbol not found in curr2 + if (curr2->val != curr1->val) return 1; // values differ + + /* compare next symbol */ + curr1 = curr1->next; + } // while + + /* no difference found */ + return 0; +} + + +/* Prepare a list of all reaching definitions per flow. + * This is done using a forward dataflow analysis. + */ +static void createReachingDefinitions (pBlock *pb) { + defmap_t *out_vals, *in_vals; + pCode *pc; + pCodeFlow *pcfl; + pCodeFlowLink *link; + set *todo; + set *blacklist; + + /* initialize out_vals to unique'fied defmaps per pCodeFlow */ + for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) { + if (isPCFL(pc)) { + deleteDefmapChain (&PCFL(pc)->in_vals); + deleteDefmapChain (&PCFL(pc)->out_vals); + defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap); + } // if + } // for + + pc = pic16_findNextInstruction (pb->pcHead); + todo = NULL; blacklist = NULL; + addSetHead (&todo, PCI(pc)->pcflow); + + //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb)); + while (elementsInSet (todo)) { + //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo)); + pcfl = PCFL(indexSet (todo, 0)); + deleteSetItem (&todo, pcfl); + //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl); + in_vals = NULL; + out_vals = NULL; + + if (isinSet (blacklist, pcfl)) { + fprintf (stderr, "ignoring blacklisted flow\n"); + continue; + } + + /* create in_vals from predecessors out_vals */ + link = setFirstItem (pcfl->from); + while (link) { + defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb); + link = setNextItem (pcfl->from); + } // while + + //printDefmap (in_vals); + //printDefmap (pcfl->in_vals); + + if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) { + //fprintf (stderr, "in_vals changed\n"); + /* in_vals changed -- update out_vals */ + deleteDefmapChain (&pcfl->in_vals); + pcfl->in_vals = in_vals; + + /* create out_val from in_val and defmap */ + out_vals = NULL; + defmapUpdateUniqueSym (&out_vals, in_vals); + defmapUpdateUniqueSym (&out_vals, pcfl->defmap); + + /* is out_vals different from pcfl->out_vals */ + if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) { + //fprintf (stderr, "out_vals changed\n"); + deleteDefmapChain (&pcfl->out_vals); + pcfl->out_vals = out_vals; + + if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) { + addSet (&blacklist, pcfl); + } // if + + /* reschedule all successors */ + link = setFirstItem (pcfl->to); + while (link) { + //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow); + addSetIfnotP (&todo, link->pcflow); + link = setNextItem (pcfl->to); + } // while + } else { + deleteDefmapChain (&out_vals); + }// if + } else { + deleteDefmapChain (&in_vals); + } // if + } // while +} + +#if 0 +static void showAllDefs (symbol_t sym, pCode *pc) { + defmap_t *map; + int count; + + assert (isPCI(pc)); + count = defmapFindAll (sym, pc, &map); + + fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc); + while (map) { +#if 1 + fprintf (stderr, "(%x @ %p) ", map->val, map->pc); +#else + { char buf[256]; + pic16_pCode2str (buf, 256, map->pc); + fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf); +#endif + map = map->next; + } + deleteDefmapChain (&map); +} +#endif + +/* safepCodeUnlink and remove pc from defmap. */ +static int pic16_safepCodeRemove (pCode *pc, char *comment) { + defmap_t *map, *next, **head; + int res, ispci; + + ispci = isPCI(pc); + map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL; + head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL; + res = pic16_safepCodeUnlink (pc, comment); + + if (res && map) { + /* remove pc from defmap */ + while (map) { + next = map->next; + if (map->pc == pc) { + if (!map->prev && head) *head = map->next; + deleteDefmap (map); + } // if + map = next; + } + } + + return res; +} + +void pic16_fixDefmap (pCode *pc, pCode *newpc) { + defmap_t *map; + /* This breaks the defmap chain's references to pCodes... fix it! */ + map = PCI(pc)->pcflow->defmap; + + while (map && map->pc != pc) map = map->next; + + while (map && map->pc == pc) { + map->pc = newpc; + map = map->next; + } // while +} + +/* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or + * write accesses (isRead == 0). */ +void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) { + defmap_t *map, *map_start; + defmap_t *copy; + if (!isPCI(pc)) return; + if (sym == newsym) return; + + map = PCI(pc)->pcflow->defmap; + + while (map && map->pc != pc) map = map->next; + map_start = map; + while (map && map->pc == pc) { + if (map->sym == sym) { + assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite))); + if (!(map->acc.access.isRead && map->acc.access.isWrite)) { + /* only one kind of access handled... this is easy */ + map->sym = newsym; + } else { + /* must copy defmap entry before replacing symbol... */ + copy = copyDefmap (map); + if (isRead) { + map->acc.access.isRead = 0; + copy->acc.access.isWrite = 0; + } else { + map->acc.access.isWrite = 0; + copy->acc.access.isRead = 0; + } + copy->sym = newsym; + /* insert copy into defmap chain */ + defmapInsertAfter (map, copy); + } + } + map = map->next; + } // while + + /* as this might introduce multiple defmap entries for newsym... */ + mergeDefmapSymbols (map_start); +} + +/* Assign "better" valnums to results. */ +static void assignValnums (pCode *pc) { + pCodeInstruction *pci; + pCode *newpc; + symbol_t sym1, sym2; + int cond, isSpecial1, isSpecial2, count, mask, lit; + defmap_t *list, *val, *oldval, *dummy; + regs *reg1 = NULL, *reg2 = NULL; + valnum_t litnum; + + /* only works for pCodeInstructions... */ + if (!isPCI(pc)) return; + + pci = PCI(pc); + cond = pci->inCond | pci->outCond; + list = pci->pcflow->defmap; + sym1 = sym2 = isSpecial1 = isSpecial2 = 0; + + if (cond & PCC_REGISTER) { + sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0)); + reg1 = pic16_getRegFromInstruction (pc); + isSpecial1 = pic16_symIsSpecial (sym1); + } + if (cond & PCC_REGISTER2) { + sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0)); + reg2 = pic16_getRegFromInstruction (pc); + isSpecial2 = pic16_symIsSpecial (sym2); + } + + /* determine input values */ + val = list; + while (val && val->pc != pc) val = val->next; + //list = val; /* might save some time later... */ + while (val && val->pc == pc) { + val->in_val = 0; + if (val->sym != 0 && (1 || val->acc.access.isRead)) { + /* get valnum for sym */ + count = defmapFindAll (val->sym, pc, &oldval); + //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym)); + if (count == 1) { + if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) { + val->in_val = oldval->val; + } else { + val->in_val = 0; + } + } else if (count == 0) { + /* no definition found */ + val->in_val = 0; + } else { + /* multiple definition(s) found -- value not known (unless always the same valnum) */ + assert (oldval); + dummy = oldval->next; + mask = oldval->acc.access.mask; + val->in_val = oldval->val; + while (dummy && (dummy->val == val->in_val)) { + mask &= dummy->acc.access.mask; + dummy = dummy->next; + } // while + + /* found other values or to restictive mask */ + if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) { + val->in_val = 0; + } + } + if (count > 0) deleteDefmapChain (&oldval); + } // if + val = val->next; + } + + /* handle valnum assignment */ + switch (pci->op) { + case POC_CLRF: /* modifies STATUS (Z) */ + if (!isSpecial1 && pic16_regIsLocal (reg1)) { + oldval = defmapCurr (list, sym1, pc); + if (oldval && (litFromValnum (oldval->in_val) == 0)) { + //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val); + if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed"); + } + defmapUpdate (list, sym1, pc, valnumFromLit(0)); + } + break; + + case POC_SETF: /* SETF does not touch STATUS */ + if (!isSpecial1 && pic16_regIsLocal (reg1)) { + oldval = defmapCurr (list, sym1, pc); + if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) { + //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val); + pic16_safepCodeRemove (pc, "=DF= redundant SETF removed"); + } + defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF)); + } + break; + + case POC_MOVLW: /* does not touch STATUS */ + oldval = defmapCurr (list, SPO_WREG, pc); + if (pci->pcop->type == PO_LITERAL) { + //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit); + litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit); + } else { + //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0)); + litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0)); + } + if (oldval && oldval->in_val == litnum) { + //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val); + pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed"); + } + defmapUpdate (list, SPO_WREG, pc, litnum); + break; + + case POC_ANDLW: /* modifies STATUS (Z,N) */ + case POC_IORLW: /* modifies STATUS (Z,N) */ + case POC_XORLW: /* modifies STATUS (Z,N) */ + /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */ + if (pci->pcop->type == PO_LITERAL) { + int vallit = -1; + lit = (unsigned char) PCOL(pci->pcop)->lit; + val = defmapCurr (list, SPO_WREG, pc); + if (val) vallit = litFromValnum (val->in_val); + if (vallit != -1) { + /* xxxLW , WREG contains a known literal */ + //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit); + if (pci->op == POC_ANDLW) { + lit &= vallit; + } else if (pci->op == POC_IORLW) { + lit |= vallit; + } else if (pci->op == POC_XORLW) { + lit ^= vallit; + } else { + assert (0 && "invalid operation"); + } + if (vallit == lit) { + //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val); + if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed"); + } + defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit)); + } // if + } + break; + + case POC_LFSR: + { + /* check if old value matches new value */ + int lit; + int ok = 1; + assert (pci->pcop->type == PO_LITERAL); + + lit = PCOL(pci->pcop)->lit; + + val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc); + + if (val && (val->in_val != 0) && (val->in_val == val->val)) { + //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val); + } else { + /* cannot remove this LFSR */ + ok = 0; + } // if + + val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc); + if (val && (val->in_val != 0) && (val->in_val == val->val)) { + //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val); + } else { + ok = 0; + } // if + + if (ok) { + pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed"); + } + } + break; + + case POC_MOVWF: /* does not touch flags */ + /* find value of WREG */ + val = defmapCurr (list, SPO_WREG, pc); + oldval = defmapCurr (list, sym1, pc); + if (val) lit = litFromValnum (val->in_val); + else lit = -1; + //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val); + + if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) { + /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */ + //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n"); + if (lit == 0) { + newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop)); + } else { + assert (lit == 0x0ff); + newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop)); + } + if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF"); + pic16_pCodeReplace (pc, newpc); + defmapReplaceSymRef (pc, SPO_WREG, 0, 1); + pic16_fixDefmap (pc, newpc); + pc = newpc; + + /* This breaks the defmap chain's references to pCodes... fix it! */ + if (!val->prev) PCI(pc)->pcflow->defmap = val->next; + if (!val->acc.access.isWrite) { + deleteDefmap (val); // delete reference to WREG as in value + val = NULL; + } else { + val->acc.access.isRead = 0; // delete reference to WREG as in value + } + oldval = PCI(pc)->pcflow->defmap; + while (oldval) { + if (oldval->pc == pc) oldval->pc = newpc; + oldval = oldval->next; + } // while + } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) { + //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc); + pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed"); + } + if (val) defmapUpdate (list, sym1, pc, val->in_val); + break; + + case POC_MOVFW: /* modifies STATUS (Z,N) */ + /* find value of REG */ + if (!isSpecial1 && pic16_regIsLocal (reg1)) { + val = defmapCurr (list, sym1, pc); + oldval = defmapCurr (list, SPO_WREG, pc); + if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) { + //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc); + if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed"); + } + if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val); + } + break; + + case POC_MOVFF: /* does not touch STATUS */ + /* find value of REG */ + val = defmapCurr (list, sym1, pc); + oldval = defmapCurr (list, sym2, pc); + if (val) lit = litFromValnum (val->in_val); + else lit = -1; + newpc = NULL; + if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) { + //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val); + if (lit == 0) { + newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2); + } else if (lit == 0x00ff) { + newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2); + } else { + newpc = NULL; + } + if (newpc) { + pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF"); + pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize; + pic16_pCodeReplace (pc, newpc); + defmapReplaceSymRef (pc, sym1, 0, 1); + pic16_fixDefmap (pc, newpc); + pc = newpc; + break; // do not process instruction as MOVFF... + } + } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) { + if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) { + //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc); + pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed"); + } else { + if (!pic16_isAlive (sym1, pc)) { + defmap_t *copy = NULL; + /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1. + * This should help eliminate + * MOVFF A,B + * + * MOVFF B,C + * + * and turn it into + * + * MOVFF A,C + */ + + /* scan defmap for symbols storing sym1's value */ + while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next; + if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) { + /* unique reaching definition for sym found */ + if (copy->val && copy->val == val->in_val) { + //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); + if (copy->sym == SPO_WREG) { + newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)); + } else { + newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p( +// /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop), + pic16_pCodeOpCopy (PCI(copy->pc)->pcop), + pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2))); + } + pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym)); + pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize; + pic16_pCodeReplace (pc, newpc); + assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite); + defmapReplaceSymRef (pc, sym1, copy->sym, 1); + pic16_fixDefmap (pc, newpc); + pc = newpc; + } + } + deleteDefmapChain (©); + } + } + if (val) defmapUpdate (list, sym2, pc, val->in_val); + } + break; + + default: + /* cannot optimize */ + break; + } // switch +} + +static void pic16_destructDF (pBlock *pb) { + pCode *pc, *next; + + /* remove old defmaps */ + pc = pic16_findNextInstruction (pb->pcHead); + while (pc) { + next = pic16_findNextInstruction (pc->next); + + assert (isPCI(pc) || isPCAD(pc)); + assert (PCI(pc)->pcflow); + deleteDefmapChain (&PCI(pc)->pcflow->defmap); + deleteDefmapChain (&PCI(pc)->pcflow->in_vals); + deleteDefmapChain (&PCI(pc)->pcflow->out_vals); + + pc = next; + } // while + + if (defmap_free || defmap_free_count) { + //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count); + freeDefmap (&defmap_free); + defmap_free_count = 0; + } +} + +/* Checks whether a pBlock contains ASMDIRs. */ +static int pic16_pBlockHasAsmdirs (pBlock *pb) { + pCode *pc; + + pc = pic16_findNextInstruction (pb->pcHead); + while (pc) { + if (isPCAD(pc)) return 1; + + pc = pic16_findNextInstruction (pc->next); + } // while + + /* no PCADs found */ + return 0; +} + +#if 1 +/* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */ +static int pic16_removeUnusedRegistersDF () { + pCode *pc, *pc2; + pBlock *pb; + regs *reg1, *reg2, *reg3; + set *seenRegs = NULL; + int cond, i; + int islocal, change = 0; + + /* no pBlocks? */ + if (!the_pFile || !the_pFile->pbHead) return 0; + + for (pb = the_pFile->pbHead; pb; pb = pb->next) { + //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb)); +#if 1 + /* find set of using pCodes per register */ + for (pc = pic16_findNextInstruction (pb->pcHead); pc; + pc = pic16_findNextInstruction(pc->next)) { + + cond = PCI(pc)->inCond | PCI(pc)->outCond; + reg1 = reg2 = NULL; + if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc); + if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc); + + if (reg1) { + if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL; + addSetIfnotP (&seenRegs, reg1); + addSetIfnotP (®1->reglives.usedpCodes, pc); + } + if (reg2) { + if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL; + addSetIfnotP (&seenRegs, reg2); + addSetIfnotP (®2->reglives.usedpCodes, pc); + } + } // for pc +#endif + for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) { + /* may not use pic16_regIsLocal() here -- in interrupt routines + * WREG, PRODx, FSR0x must be saved */ + islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx); + if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) { + pc = pc2 = NULL; + for (i=0; i < 2; i++) { + pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i); + if (!pc2) pc2 = pc; + if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue; + reg2 = pic16_getRegFromInstruction (pc); + reg3 = pic16_getRegFromInstruction2 (pc); + if (!reg2 || !reg3 + || (reg2->rIdx != pic16_stack_preinc->rIdx + && reg3->rIdx != pic16_stack_postdec->rIdx)) break; + if (i == 1) { + /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */ + //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb)); + pic16_safepCodeRemove (pc, "removed unused local reg IN"); + pic16_safepCodeRemove (pc2, "removed unused local reg OUT"); + } + } // for + } // if + deleteSet (®1->reglives.usedpCodes); + } // for reg1 + + deleteSet (&seenRegs); + } // for pb + + return change; +} +#endif + +/* Set up pCodeFlow's defmap_ts. + * Needs correctly set up to/from fields. */ +static void pic16_createDF (pBlock *pb) { + pCode *pc, *next; + int change=0; + + //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb)); + + pic16_destructDF (pb); + + /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */ + if (pic16_pBlockHasAsmdirs (pb)) { + //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__); + return; + } + + /* integrity check -- we need to reach all flows to guarantee + * correct data flow analysis (reaching definitions, aliveness) */ +#if 0 + if (!verifyAllFlowsReachable (pb)) { + fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb)); + return; + } +#endif + + /* establish new defmaps */ + pc = pic16_findNextInstruction (pb->pcHead); + while (pc) { + next = pic16_findNextInstruction (pc->next); + + assert (PCI(pc)->pcflow); + PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap); + + pc = next; + } // while + + //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__); + createReachingDefinitions (pb); + +#if 1 + /* assign better valnums */ + //fprintf (stderr, "assigning valnums for pb %p\n", pb); + pc = pic16_findNextInstruction (pb->pcHead); + while (pc) { + next = pic16_findNextInstruction (pc->next); + + assert (PCI(pc)->pcflow); + assignValnums (pc); + + pc = next; + } // while +#endif + +#if 1 + /* remove dead pCodes */ + //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb)); + do { + change = 0; + pc = pic16_findNextInstruction (pb->pcHead); + while (pc) { + next = pic16_findNextInstruction (pc->next); + + if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) { + change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode"); + } + + pc = next; + } // while + } while (change); +#endif +} + + +/* ======================================================================= */ +/* === DEPRECATED CONTROL FLOW CREATION ROUTINES ========================= */ +/* ======================================================================= */ + +#if 0 + +/* connect pCode f anf t via their to/from pBranches */ +static void pic16_pCodeLink (pCode *f, pCode *t) { + pBranch *br; + pCodeInstruction *_f, *_t; + + if (!f || !t) return; + +#if 0 + fprintf (stderr, "linking:\n"); + f->print(stderr, f); + f->print(stderr, t); +#endif + + assert (isPCI(f) || isPCAD(f)); + assert (isPCI(t) || isPCAD(t)); + _f = PCI(f); + _t = PCI(t); + + /* define t to be CF successor of f */ + br = Safe_malloc (sizeof (pBranch)); + br->pc = t; + br->next = NULL; + _f->to = pic16_pBranchAppend (_f->to, br); + + /* define f to be CF predecessor of t */ + br = Safe_malloc (sizeof (pBranch)); + br->pc = f; + br->next = NULL; + _t->from = pic16_pBranchAppend (_t->from, br); + + /* also update pcflow information */ + if (_f->pcflow && _t->pcflow && _f->pcflow != _t->pcflow) { + //fprintf (stderr, "creating flow %p --> %p\n", _f->pcflow, _t->pcflow); + LinkFlow_pCode (_f, _t); + } // if +} + +static void pic16_destructCF (pBlock *pb) { + pCode *pc; + pBranch *br; + + /* remove old CF information */ + pc = pb->pcHead; + while (pc) { + if (isPCI(pc)) { + while (PCI(pc)->to) { + br = PCI(pc)->to->next; + Safe_free (PCI(pc)->to); + PCI(pc)->to = br; + } // while + while (PCI(pc)->from) { + br = PCI(pc)->from->next; + Safe_free (PCI(pc)->from); + PCI(pc)->from = br; + } + } else if (isPCFL(pc)) { + deleteSet (&PCFL(pc)->to); + deleteSet (&PCFL(pc)->from); + } + pc = pc->next; + } + + releaseStack (); +} + +/* Set up pCodeInstruction's to and from pBranches. */ +static void pic16_createCF (pBlock *pb) { + pCode *pc; + pCode *next, *dest; + char *label; + + //fprintf (stderr, "creating CF for %p\n", pb); + + pic16_destructCF (pb); + + /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */ + if (pic16_pBlockHasAsmdirs (pb)) { + //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__); + return; + } + + pc = pic16_findNextInstruction(pb->pcHead); + while (pc) { + next = pic16_findNextInstruction(pc->next); + if (isPCI_SKIP(pc)) { + pic16_pCodeLink(pc, next); + pic16_pCodeLink(pc, pic16_findNextInstruction(next->next)); + } else if (isPCI_BRANCH(pc)) { + // Bcc, BRA, CALL, GOTO + if (PCI(pc)->pcop) { + switch (PCI(pc)->pcop->type) { + case PO_LABEL: + label = PCOLAB(PCI(pc)->pcop)->pcop.name; + dest = findLabelinpBlock (pc->pb, PCOLAB(PCI(pc)->pcop)); + break; + + case PO_STR: + /* needed for GOTO ___irq_handler */ + label = PCI(pc)->pcop->name; + dest = NULL; + break; + + default: + assert (0 && "invalid label format"); + break; + } // switch + } else { + label = "NO PCOP"; + dest = NULL; + } + + switch (PCI(pc)->op) { + case POC_BRA: + case POC_GOTO: + if (dest != NULL) { + pic16_pCodeLink(pc, dest); + } else { + //fprintf (stderr, "jump target \"%s\" not found!\n", label); + } + break; + case POC_CALL: + case POC_RETURN: + case POC_RETFIE: + pic16_pCodeLink(pc, next); + break; + case POC_BC: + case POC_BNC: + case POC_BZ: + case POC_BNZ: + case POC_BN: + case POC_BNN: + case POC_BOV: + case POC_BNOV: + if (dest != NULL) { + pic16_pCodeLink(pc, dest); + } else { + //fprintf (stderr, "jump target \"%s\"not found!\n", label); + } + pic16_pCodeLink(pc, next); + break; + default: + fprintf (stderr, "BRANCH instruction: %s\n", PCI(pc)->mnemonic); + assert (0 && "unhandled branch instruction"); + break; + } // switch + } else { + pic16_pCodeLink (pc, next); + } + pc = next; + } // while +} +#endif + +/* ======================================================================== */ +/* === VCG DUMPER ROUTINES ================================================ */ +/* ======================================================================== */ +#if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0 +hTab *dumpedNodes = NULL; + +/** Dump VCG header into of. */ +static void pic16_vcg_init (FILE *of) { + /* graph defaults */ + fprintf (of, "graph:{\n"); + fprintf (of, "title:\"graph1\"\n"); + fprintf (of, "label:\"graph1\"\n"); + fprintf (of, "color:white\n"); + fprintf (of, "textcolor:black\n"); + fprintf (of, "bordercolor:black\n"); + fprintf (of, "borderwidth:1\n"); + fprintf (of, "textmode:center\n"); + + fprintf (of, "layoutalgorithm:dfs\n"); + fprintf (of, "late_edge_labels:yes\n"); + fprintf (of, "display_edge_labels:yes\n"); + fprintf (of, "dirty_edge_labels:yes\n"); + fprintf (of, "finetuning:yes\n"); + fprintf (of, "ignoresingles:no\n"); + fprintf (of, "straight_phase:yes\n"); + fprintf (of, "priority_phase:yes\n"); + fprintf (of, "manhattan_edges:yes\n"); + fprintf (of, "smanhattan_edges:no\n"); + fprintf (of, "nearedges:no\n"); + fprintf (of, "node_alignment:center\n"); // bottom|top|center + fprintf (of, "port_sharing:no\n"); + fprintf (of, "arrowmode:free\n"); // fixed|free + fprintf (of, "crossingphase2:yes\n"); + fprintf (of, "crossingoptimization:yes\n"); + fprintf (of, "edges:yes\n"); + fprintf (of, "nodes:yes\n"); + fprintf (of, "splines:no\n"); + + /* node defaults */ + fprintf (of, "node.color:lightyellow\n"); + fprintf (of, "node.textcolor:black\n"); + fprintf (of, "node.textmode:center\n"); + fprintf (of, "node.shape:box\n"); + fprintf (of, "node.bordercolor:black\n"); + fprintf (of, "node.borderwidth:1\n"); + + /* edge defaults */ + fprintf (of, "edge.textcolor:black\n"); + fprintf (of, "edge.color:black\n"); + fprintf (of, "edge.thickness:1\n"); + fprintf (of, "edge.arrowcolor:black\n"); + fprintf (of, "edge.backarrowcolor:black\n"); + fprintf (of, "edge.arrowsize:15\n"); + fprintf (of, "edge.backarrowsize:15\n"); + fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line + fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line + fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible + + fprintf (of, "\n"); + + /* prepare data structures */ + if (dumpedNodes) { + hTabDeleteAll (dumpedNodes); + dumpedNodes = NULL; + } + dumpedNodes = newHashTable (128); +} + +/** Dump VCG footer into of. */ +static void pic16_vcg_close (FILE *of) { + fprintf (of, "}\n"); +} + +#define BUF_SIZE 128 +#define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0]) + +#if 0 +static int ptrcmp (const void *p1, const void *p2) { + return p1 == p2; +} +#endif + +/** Dump a pCode node as VCG to of. */ +static void pic16_vcg_dumpnode (pCode *pc, FILE *of) { + char buf[BUF_SIZE]; + + if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) { + // dumped already + return; + } + hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc); + //fprintf (stderr, "dumping %p\n", pc); + + /* only dump pCodeInstructions and Flow nodes */ + if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return; + + /* emit node */ + fprintf (of, "node:{"); + fprintf (of, "title:\"%s\" ", pcTitle(pc)); + fprintf (of, "label:\"%s\n", pcTitle(pc)); + if (isPCFL(pc)) { + fprintf (of, ""); + } else if (isPCI(pc) || isPCAD(pc)) { + pc->print (of, pc); + } else { + fprintf (of, ""); + } + fprintf (of, "\" "); + fprintf (of, "}\n"); + + if (1 && isPCFL(pc)) { + defmap_t *map, *prev; + unsigned int i; + map = PCFL(pc)->defmap; + i=0; + while (map) { + if (map->sym != 0) { + i++; + + /* emit definition node */ + fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i); + fprintf (of, "label:\""); + + prev = map; + do { + 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)); + prev = map; + map = map->next; + } while (map && prev->pc == map->pc); + map = prev; + + fprintf (of, "\" "); + + fprintf (of, "color:green "); + fprintf (of, "}\n"); + + /* emit edge to previous definition */ + fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i); + if (i == 1) { + fprintf (of, "targetname:\"%s\" ", pcTitle(pc)); + } else { + fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1); + } + fprintf (of, "color:green "); + fprintf (of, "}\n"); + + if (map->pc) { + pic16_vcg_dumpnode (map->pc, of); + fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i); + fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc)); + } + } + map = map->next; + } // while + } + + /* emit additional nodes (e.g. operands) */ +} + +/** Dump a pCode's edges (control flow/data flow) as VCG to of. */ +static void pic16_vcg_dumpedges (pCode *pc, FILE *of) { + char buf[BUF_SIZE]; + pCodeInstruction *pci; + pBranch *curr; + int i; + + if (1 && isPCFL(pc)) { + /* emit edges to flow successors */ + void *pcfl; + //fprintf (stderr, "PCFLOWe @ %p\n", pc); + pcfl = setFirstItem (PCFL(pc)->to); + while (pcfl) { + pcfl = ((pCodeFlowLink *) (pcfl))->pcflow; + pic16_vcg_dumpnode (pc, of); + pic16_vcg_dumpnode ((pCode *) pcfl, of); + fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc)); + fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl)); + pcfl = setNextItem (PCFL(pc)->to); + } // while + } // if + + if (!isPCI(pc) && !isPCAD(pc)) return; + + pci = PCI(pc); + + /* emit control flow edges (forward only) */ + curr = pci->to; + i=0; + while (curr) { + pic16_vcg_dumpnode (curr->pc, of); + fprintf (of, "edge:{"); + fprintf (of, "sourcename:\"%s\" ", pcTitle(pc)); + fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc)); + fprintf (of, "color:red "); + fprintf (of, "}\n"); + curr = curr->next; + } // while + +#if 1 + /* dump "flow" edge (link pCode according to pBlock order) */ + { + pCode *pcnext; + pcnext = pic16_findNextInstruction (pc->next); + if (pcnext) { + pic16_vcg_dumpnode (pcnext, of); + fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc)); + fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext)); + } + } +#endif + +#if 0 + /* emit flow */ + if (pci->pcflow) { + pic16_vcg_dumpnode (&pci->pcflow->pc, of); + fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc)); + fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow)); + } +#endif + + /* emit data flow edges (backward only) */ + /* TODO: gather data flow information... */ +} + +static void pic16_vcg_dump (FILE *of, pBlock *pb) { + pCode *pc; + + /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */ + if (pic16_pBlockHasAsmdirs (pb)) { + //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__); + return; + } + + for (pc=pb->pcHead; pc; pc = pc->next) { + pic16_vcg_dumpnode (pc, of); + } // for pc + + for (pc=pb->pcHead; pc; pc = pc->next) { + pic16_vcg_dumpedges (pc, of); + } // for pc +} + +static void pic16_vcg_dump_default (pBlock *pb) { + FILE *of; + char buf[BUF_SIZE]; + pCode *pc; + + /* get function name */ + pc = pb->pcHead; + while (pc && !isPCF(pc)) pc = pc->next; + if (pc) { + SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname); + } else { + SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb); + } + + //fprintf (stderr, "now dumping %s\n", buf); + of = fopen (buf, "w"); + pic16_vcg_init (of); + pic16_vcg_dump (of, pb); + pic16_vcg_close (of); + fclose (of); +} +#endif + +/*** END of helpers for pCode dataflow optimizations ***/