+ /* if the usage has only one operand then we can */
+ if (IC_LEFT (uic) == NULL ||
+ IC_RIGHT (uic) == NULL)
+ goto accuse;
+
+ /* make sure this is on the left side if not
+ a '+' since '+' is commutative */
+ if (ic->op != '+' &&
+ IC_LEFT (uic)->key != IC_RESULT (ic)->key)
+ return;
+
+ // See mcs51 ralloc for reasoning
+#if 0
+ /* if one of them is a literal then we can */
+ if ((IC_LEFT (uic) && IS_OP_LITERAL (IC_LEFT (uic))) ||
+ (IC_RIGHT (uic) && IS_OP_LITERAL (IC_RIGHT (uic))))
+ {
+ goto accuse;
+ return;
+ }
+#endif
+
+/** This is confusing :) Guess for now */
+ if (IC_LEFT (uic)->key == IC_RESULT (ic)->key &&
+ (IS_ITEMP (IC_RIGHT (uic)) ||
+ (IS_TRUE_SYMOP (IC_RIGHT (uic)))))
+ goto accuse;
+
+ if (IC_RIGHT (uic)->key == IC_RESULT (ic)->key &&
+ (IS_ITEMP (IC_LEFT (uic)) ||
+ (IS_TRUE_SYMOP (IC_LEFT (uic)))))
+ goto accuse;
+ return;
+accuse:
+ OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_A;
+}
+#endif
+
+static void
+packRegsForHLUse (iCode * ic)
+{
+ iCode *uic;
+
+ if (IS_GB)
+ return;
+
+ /* has only one definition */
+ if (bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) > 1)
+ return;
+
+ /* has only one use */
+ if (bitVectnBitsOn (OP_USES (IC_RESULT (ic))) > 1)
+ return;
+
+ /* and the usage immediately follows this iCode */
+ if (!(uic = hTabItemWithKey (iCodehTab,
+ bitVectFirstBit (OP_USES (IC_RESULT (ic))))))
+ return;
+
+ if (ic->next != uic)
+ return;
+
+ if (ic->op == ADDRESS_OF && uic->op == IPUSH)
+ goto hluse;
+ if (ic->op == CALL && ic->parmBytes == 0 && (uic->op == '-' || uic->op == '+'))
+ goto hluse;
+ return;
+hluse:
+ OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_HL;
+}
+
+static bool
+opPreservesA (iCode * ic, iCode * uic)
+{
+ if (uic->op == IFX)
+ {
+ /* If we've gotten this far then the thing to compare must be
+ small enough and must be in A.
+ */
+ return TRUE;
+ }
+
+ if (uic->op == JUMPTABLE)
+ {
+ D (D_ACCUSE2, (" + Dropping as operation is a Jumptable\n"));
+ return FALSE;
+ }
+
+ /* A pointer assign preserves A if A is the left value. */
+ if (uic->op == '=' && POINTER_SET (uic))
+ {
+ return TRUE;
+ }
+
+ /* if the usage has only one operand then we can */
+ /* PENDING: check */
+ if (IC_LEFT (uic) == NULL ||
+ IC_RIGHT (uic) == NULL)
+ {
+ D (D_ACCUSE2, (" + Dropping as operation has only one operand\n"));
+ return FALSE;
+ }
+
+ /* PENDING: check this rule */
+ if (getSize (operandType (IC_RESULT (uic))) > 1)
+ {
+ D (D_ACCUSE2, (" + Dropping as operation has size is too big\n"));
+ return FALSE;
+ }
+
+
+ /* Disabled all of the old rules as they weren't verified and have
+ caused at least one problem.
+ */
+ return FALSE;
+}
+
+static bool
+opIgnoresA (iCode * ic, iCode * uic)
+{
+ /* A increment of an iTemp by a constant is OK. */
+ if ( uic->op == '+' &&
+ IS_ITEMP (IC_LEFT (uic)) &&
+ IS_ITEMP (IC_RESULT (uic)) &&
+ IS_OP_LITERAL (IC_RIGHT (uic)))
+ {
+ unsigned int icount = (unsigned int) floatFromVal (IC_RIGHT (uic)->operand.valOperand);
+
+ /* Being an ITEMP means that we're already a symbol. */
+ if (icount == 1 &&
+ IC_RESULT (uic)->operand.symOperand->key == IC_LEFT (uic)->operand.symOperand->key
+ )
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/* Some optimisation cases:
+
+ 1. Part of memcpy
+; genPointerGet
+ ld l,-4(ix)
+ ld h,-3(ix)
+ ld c,(hl)
+; genPlus
+ inc -4(ix)
+ jp nz,00108$
+ inc -3(ix)
+00108$:
+; genAssign (pointer)
+ ld a,c
+ ld (de),a
+
+ want to optimise down to:
+ ld hl,-4(ix) ...
+ ld a,(hl)
+ inc -4(ix).w ...
+ ld (de),a
+
+ So genPointer get is OK
+ genPlus where the right is constant, left is iTemp, and result is same as left
+ genAssign (pointer) is OK
+
+ 2. Part of _strcpy
+; genPointerGet
+ ld a,(de)
+ ld c,a
+; genIfx
+ xor a,a
+ or a,c
+ jp z,00103$
+; _strcpy.c 40
+; genAssign (pointer)
+; AOP_STK for _strcpy_to_1_1
+ ld l,-2(ix)
+ ld h,-1(ix)
+ ld (hl),c
+
+ want to optimise down to:
+ ld a,(de)
+ or a,a
+ jp z,00103$
+ ld (bc),a
+
+ So genIfx where IC_COND has size of 1 and is a constant.
+*/
+
+/** Pack registers for acc use.
+ When the result of this operation is small and short lived it may
+ be able to be stored in the accumulator.
+
+ Note that the 'A preserving' list is currently emperical :)
+ */
+static void
+packRegsForAccUse2 (iCode * ic)
+{
+ iCode *uic;
+
+ D (D_ALLOC, ("packRegsForAccUse2: running on ic %p\n", ic));
+
+ /* Filter out all but those 'good' commands */
+ if (
+ !POINTER_GET (ic) &&
+ ic->op != '+' &&
+ !IS_BITWISE_OP (ic) &&
+ ic->op != '=' &&
+ ic->op != EQ_OP &&
+ ic->op != CAST &&
+ 1)
+ {
+ D (D_ACCUSE2, (" + Dropping as not a 'good' source command\n"));
+ return;
+ }
+
+ /* if + or - then it has to be one byte result.
+ MLH: Ok.
+ */
+ if ((ic->op == '+' || ic->op == '-')
+ && getSize (operandType (IC_RESULT (ic))) > 1)
+ {
+ D (D_ACCUSE2, (" + Dropping as it's a big + or -\n"));
+ return;
+ }
+
+ /* has only one definition */
+ if (bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) > 1)
+ {
+ D (D_ACCUSE2, (" + Dropping as it has more than one definition\n"));
+ return;
+ }
+
+ /* Right. We may be able to propagate it through if:
+ For each in the chain of uses the intermediate is OK.
+ */
+ /* Get next with 'uses result' bit on
+ If this->next == next
+ Validate use of next
+ If OK, increase count
+ */
+ /* and the usage immediately follows this iCode */
+ if (!(uic = hTabItemWithKey (iCodehTab,
+ bitVectFirstBit (OP_USES (IC_RESULT (ic))))))
+ {
+ D (D_ACCUSE2, (" + Dropping as usage does not follow first\n"));
+ return;
+ }
+
+ {
+ /* Create a copy of the OP_USES bit vect */
+ bitVect *uses = bitVectCopy (OP_USES (IC_RESULT (ic)));
+ int setBit;
+ iCode *scan = ic, *next;
+
+ do
+ {
+ setBit = bitVectFirstBit (uses);
+ next = hTabItemWithKey (iCodehTab, setBit);
+ if (scan->next == next)
+ {
+ D (D_ACCUSE2_VERBOSE, (" ! Is next in line\n"));
+
+ bitVectUnSetBit (uses, setBit);
+ /* Still contigous. */
+ if (!opPreservesA (ic, next))
+ {
+ D (D_ACCUSE2, (" + Dropping as operation doesn't preserve A\n"));
+ return;
+ }
+ D (D_ACCUSE2_VERBOSE, (" ! Preserves A, so continue scanning\n"));
+ scan = next;
+ }
+ else if (scan->next == NULL && bitVectnBitsOn (uses) == 1 && next != NULL)
+ {
+ if (next->prev == NULL)
+ {
+ if (!opPreservesA (ic, next))
+ {
+ D (D_ACCUSE2, (" + Dropping as operation doesn't preserve A #2\n"));
+ return;
+ }
+ bitVectUnSetBit (uses, setBit);
+ scan = next;
+ }
+ else
+ {
+ D (D_ACCUSE2, (" + Dropping as last in list and next doesn't start a block\n"));
+ return;
+ }
+ }
+ else if (scan->next == NULL)
+ {
+ D (D_ACCUSE2, (" + Dropping as hit the end of the list\n"));
+ D (D_ACCUSE2, (" + Next in htab: %p\n", next));
+ return;
+ }
+ else
+ {
+ if (opIgnoresA (ic, scan->next))
+ {
+ /* Safe for now. */
+ scan = scan->next;
+ D (D_ACCUSE2_VERBOSE, (" ! Op ignores A, so continue scanning\n"));
+ }
+ else
+ {
+ D (D_ACCUSE2, (" + Dropping as parts are not consecuitive and intermediate might use A\n"));
+ return;
+ }
+ }
+ }
+ while (!bitVectIsZero (uses));
+
+ OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_A;
+ return;
+ }
+
+ /* OLD CODE FOLLOWS */
+ /* if it is a conditional branch then we definitely can
+ MLH: Depends.
+ */
+#if 0
+ if (uic->op == IFX)
+ goto accuse;
+
+ /* MLH: Depends. */
+ if (uic->op == JUMPTABLE)
+ return;
+#endif
+
+ /* if the usage is not is an assignment or an
+ arithmetic / bitwise / shift operation then not.
+ MLH: Pending: Invalid. Our pointer sets are always peechy.
+ */
+#if 0
+ if (POINTER_SET (uic) &&
+ getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)) > 1)
+ {
+ printf ("e5 %u\n", getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)));
+ return;
+ }
+#endif
+
+ printf ("1\n");
+ if (uic->op != '=' &&
+ !IS_ARITHMETIC_OP (uic) &&
+ !IS_BITWISE_OP (uic) &&
+ uic->op != LEFT_OP &&
+ uic->op != RIGHT_OP)
+ {
+ printf ("e6\n");
+ return;
+ }
+
+ /* if used in ^ operation then make sure right is not a
+ literl */
+ if (uic->op == '^' && isOperandLiteral (IC_RIGHT (uic)))
+ return;
+
+ /* if shift operation make sure right side is not a literal */
+ if (uic->op == RIGHT_OP &&
+ (isOperandLiteral (IC_RIGHT (uic)) ||
+ getSize (operandType (IC_RESULT (uic))) > 1))
+ return;
+
+ if (uic->op == LEFT_OP &&
+ (isOperandLiteral (IC_RIGHT (uic)) ||
+ getSize (operandType (IC_RESULT (uic))) > 1))
+ return;
+
+#if 0
+ /* make sure that the result of this icode is not on the
+ stack, since acc is used to compute stack offset */
+ if (IS_TRUE_SYMOP (IC_RESULT (uic)) &&
+ OP_SYMBOL (IC_RESULT (uic))->onStack)
+ return;
+#endif
+
+#if 0
+ /* if either one of them in far space then we cannot */
+ if ((IS_TRUE_SYMOP (IC_LEFT (uic)) &&
+ isOperandInFarSpace (IC_LEFT (uic))) ||
+ (IS_TRUE_SYMOP (IC_RIGHT (uic)) &&
+ isOperandInFarSpace (IC_RIGHT (uic))))
+ return;
+#endif
+
+ /* if the usage has only one operand then we can */
+ if (IC_LEFT (uic) == NULL ||
+ IC_RIGHT (uic) == NULL)
+ goto accuse;
+
+ /* make sure this is on the left side if not
+ a '+' since '+' is commutative */
+ if (ic->op != '+' &&
+ IC_LEFT (uic)->key != IC_RESULT (ic)->key)
+ return;
+
+ /* if one of them is a literal then we can */
+ if ((IC_LEFT (uic) && IS_OP_LITERAL (IC_LEFT (uic))) ||
+ (IC_RIGHT (uic) && IS_OP_LITERAL (IC_RIGHT (uic))))
+ {
+ goto accuse;
+ return;
+ }
+
+/** This is confusing :) Guess for now */
+ if (IC_LEFT (uic)->key == IC_RESULT (ic)->key &&
+ (IS_ITEMP (IC_RIGHT (uic)) ||
+ (IS_TRUE_SYMOP (IC_RIGHT (uic)))))
+ goto accuse;
+
+ if (IC_RIGHT (uic)->key == IC_RESULT (ic)->key &&
+ (IS_ITEMP (IC_LEFT (uic)) ||
+ (IS_TRUE_SYMOP (IC_LEFT (uic)))))
+ goto accuse;
+ return;
+accuse:
+ printf ("acc ok!\n");
+ OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_A;