#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
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
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
// fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
// __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?r->accessBank:-1);
- if(r && !r->accessBank)SAFE_snprintf(&s,&size,", %s", (!pic16_mplab_comp?"B":"BANKED"));
+ 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]);
+ }
}
//
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);
+ SNPRINTF (total, len, "%s: %s", comment, buf);
pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
Safe_free (total);
}
if (!map_symToStr) {
int i;
- map_strToSym = newHashTable (128);
- map_symToStr = newHashTable (128);
-
struct { char *name; symbol_t sym; } predefsyms[] = {
{"WREG", SPO_WREG},
{"STATUS", SPO_STATUS},
{NULL, 0}
};
+ map_strToSym = newHashTable (128);
+ map_symToStr = newHashTable (128);
+
for (i=0; predefsyms[i].name; i++) {
char *name;
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) */
map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
}
map->sym = sym;
- map->access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
- map->access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
- map->access.isRead = (isRead != 0);
- map->access.isWrite = (isWrite != 0);
+ 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);
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. */
dummy = *head;
while (dummy && (dummy->sym != item->sym
|| dummy->pc != item->pc
- || dummy->accessmethod != item->accessmethod
+ || dummy->acc.accessmethod != item->acc.accessmethod
|| dummy->val != item->val
|| dummy->in_val != item->in_val)) {
dummy = dummy->next;
} // if (pc)
/* find definition for sym */
- while (curr && (!curr->access.isWrite || (curr->sym != sym))) {
+ while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
curr = curr->next;
}
} // if (pc)
/* find use of sym (scan list backwards) */
- while (curr && (!curr->access.isRead || (curr->sym != sym))) curr = curr->prev;
+ while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
return curr;
}
while (m && m->pc != pc) m = m->next;
/* find definition of sym at pc */
- while (m && m->pc == pc && (!m->access.isWrite || (m->sym != sym))) m = m->next;
+ while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
/* no definition found */
if (!m) return 1;
while (m) {
if (m->sym == sym) {
m->in_val = newval;
- if (m->access.isWrite) m = NULL;
+ if (m->acc.access.isWrite) m = NULL;
} // if
if (m) m = m->prev;
} // while
struct stack_s *next;
} stackitem_t;
-typedef stackitem_t *stack_t;
+typedef stackitem_t *dynstack_t;
static stackitem_t *free_stackitems = NULL;
/* Create a stack with one item. */
-static stack_t *newStack () {
- stack_t *s = (stack_t *) Safe_malloc (sizeof (stack_t));
+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 (stack_t *s) {
+static void deleteStack (dynstack_t *s) {
stackitem_t *i;
while (*s) {
} // while
}
-static void stackPush (stack_t *stack, void *data) {
+static void stackPush (dynstack_t *stack, void *data) {
stackitem_t *i;
if (free_stackitems) {
*stack = i;
}
-static void *stackPop (stack_t *stack) {
+static void *stackPop (dynstack_t *stack) {
void *data;
stackitem_t *i;
}
#if 0
-static int stackContains (stack_t *s, void *data) {
+static int stackContains (dynstack_t *s, void *data) {
stackitem_t *i;
if (!s) return 0;
i = *s;
}
#endif
-static int stackIsEmpty (stack_t *s) {
+static int stackIsEmpty (dynstack_t *s) {
return (*s == NULL);
}
Safe_free (s);
}
-static int stateIsNew (state_t *state, stack_t *todo, stack_t *done) {
+static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
stackitem_t *i;
/* scan working list for state */
pCodeFlow *curr;
pCodeFlowLink *succ;
state_t *state;
- stack_t *todo; /** stack of state_t */
- stack_t *done; /** stack of state_t */
+ dynstack_t *todo; /** stack of state_t */
+ dynstack_t *done; /** stack of state_t */
int firstState, n_defs;
/* scan list for reads at this pc first */
while (map && map->pc == mappc->pc) {
/* is the symbol (partially) read? */
- if ((map->sym == sym) && (map->access.isRead && ((map->access.in_mask & mask) != 0))) {
+ 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;
}
while (map && map->pc == mappc->pc) {
/* honor (partial) redefinitions of sym */
- if ((map->sym == sym) && (map->access.isWrite)) {
- mask &= ~map->access.mask;
+ 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;
static int pic16_isAlive (symbol_t sym, pCode *pc) {
int mask, visit;
defmap_t *map;
- stack_t *todo, *done;
+ dynstack_t *todo, *done;
state_t *state;
pCodeFlow *pcfl;
pCodeFlowLink *succ;
//fprintf (stderr, "%s: special sym\n", __FUNCTION__);
return 1;
}
- if (map->access.isWrite) {
+ 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;
{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;
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 */
+ /* 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;
/* 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;
}
fprintf (stderr, "defmap @ %p:\n", curr);
while (curr) {
fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
- curr->access.isRead ? "R" : " ",
- curr->access.isWrite ? "W": " ",
+ curr->acc.access.isRead ? "R" : " ",
+ curr->acc.access.isWrite ? "W": " ",
curr->in_val, curr->val,
- curr->access.in_mask, curr->access.mask,
+ curr->acc.access.in_mask, curr->acc.access.mask,
strFromSym(curr->sym), curr->sym,
curr->pc);
curr = curr->next;
/* update uniq */
do {
/* find next assignment in additionals */
- while (curr && !curr->access.isWrite) curr = curr->prev;
+ while (curr && !curr->acc.access.isWrite) curr = curr->prev;
if (!curr) break;
} // while
}
-void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym) {
- defmap_t *map;
+/* 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) map->sym = newsym;
+ 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. */
//list = val; /* might save some time later... */
while (val && val->pc == pc) {
val->in_val = 0;
- if (val->sym != 0 && (1 || val->access.isRead)) {
+ 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->access.in_mask & oldval->access.mask) == val->access.in_mask) {
+ 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;
/* multiple definition(s) found -- value not known (unless always the same valnum) */
assert (oldval);
dummy = oldval->next;
- mask = oldval->access.mask;
+ mask = oldval->acc.access.mask;
val->in_val = oldval->val;
while (dummy && (dummy->val == val->in_val)) {
- mask &= dummy->access.mask;
+ mask &= dummy->acc.access.mask;
dummy = dummy->next;
} // while
/* found other values or to restictive mask */
- if (dummy || ((mask & val->access.in_mask) != val->access.in_mask)) {
+ if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
val->in_val = 0;
}
}
case POC_XORLW: /* modifies STATUS (Z,N) */
/* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
if (pci->pcop->type == PO_LITERAL) {
- lit = (unsigned char) PCOL(pci->pcop)->lit;
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) {
}
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);
+ 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;
- deleteDefmap (val); // delete reference to WREG as in value
- val = NULL;
+ 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;
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);
+ defmapReplaceSymRef (pc, sym1, 0, 1);
pic16_fixDefmap (pc, newpc);
pc = newpc;
break; // do not process instruction as MOVFF...
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->access.isRead && !val->access.isWrite);
- defmapReplaceSymRef (pc, sym1, copy->sym);
+ assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
+ defmapReplaceSymRef (pc, sym1, copy->sym, 1);
pic16_fixDefmap (pc, newpc);
pc = newpc;
}
}
#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])
+#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) {
prev = map;
do {
- fprintf (of, "%s%c%c: val %4x|%4x & %02x|%02x, sym %s", (prev == map) ? "" : "\n", map->access.isRead ? 'R' : ' ', map->access.isWrite ? 'W' : ' ', map->in_val, map->val, map->access.in_mask, map->access.mask, strFromSym (map->sym));
+ 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);
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);
+ SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
} else {
- snprintf (buf, BUF_SIZE, "pb_%p.vcg", pb);
+ SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
}
//fprintf (stderr, "now dumping %s\n", buf);