+ else
+ {
+ /* false label is present */
+ jlbl = IC_FALSE (ic);
+ if (!strcmp (jval, "a"))
+ {
+ inst = "z";
+ }
+ else if (!strcmp (jval, "c"))
+ {
+ inst = "nc";
+ }
+ else if (!strcmp (jval, "nc"))
+ {
+ inst = "c";
+ }
+ else if (!strcmp (jval, "m"))
+ {
+ inst = "p";
+ }
+ else if (!strcmp (jval, "p"))
+ {
+ inst = "m";
+ }
+ else
+ {
+ /* The buffer contains the bit on A that we should test */
+ inst = "z";
+ }
+ }
+ /* Z80 can do a conditional long jump */
+ if (!strcmp (jval, "a"))
+ {
+ emit2 ("or a,a");
+ }
+ else if (!strcmp (jval, "c"))
+ {
+ }
+ else if (!strcmp (jval, "nc"))
+ {
+ }
+ else if (!strcmp (jval, "m"))
+ {
+ }
+ else if (!strcmp (jval, "p"))
+ {
+ }
+ else
+ {
+ emit2 ("bit %s,a", jval);
+ }
+ emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
+
+ /* mark the icode as generated */
+ ic->generated = 1;
+}
+
+#if DISABLED
+static const char *
+_getPairIdName (PAIR_ID id)
+{
+ return _pairs[id].name;
+}
+#endif
+
+#if OLD
+ /* if unsigned char cmp with lit, just compare */
+ if ((size == 1) &&
+ (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
+ {
+ emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
+ if (sign)
+ {
+ emit2 ("xor a,!immedbyte", 0x80);
+ emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
+ }
+ else
+ emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
+ }
+ else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
+ {
+ // On the Gameboy we can't afford to adjust HL as it may trash the carry.
+ // Pull left into DE and right into HL
+ aopGet (AOP(left), LSB, FALSE);
+ emit2 ("ld d,h");
+ emit2 ("ld e,l");
+ aopGet (AOP(right), LSB, FALSE);
+
+ while (size--)
+ {
+ if (size == 0 && sign)
+ {
+ // Highest byte when signed needs the bits flipped
+ // Save the flags
+ emit2 ("push af");
+ emit2 ("ld a,(de)");
+ emit2 ("xor #0x80");
+ emit2 ("ld e,a");
+ emit2 ("ld a,(hl)");
+ emit2 ("xor #0x80");
+ emit2 ("ld d,a");
+ emit2 ("pop af");
+ emit2 ("ld a,e");
+ emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
+ }
+ else
+ {
+ emit2 ("ld a,(de)");
+ emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
+ }
+
+ if (size != 0)
+ {
+ emit2 ("inc hl");
+ emit2 ("inc de");
+ }
+ offset++;
+ }
+ spillPair (PAIR_HL);
+ }
+ else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
+ {
+ setupPair (PAIR_HL, AOP (left), 0);
+ aopGet (AOP(right), LSB, FALSE);
+
+ while (size--)
+ {
+ if (size == 0 && sign)
+ {
+ // Highest byte when signed needs the bits flipped
+ // Save the flags
+ emit2 ("push af");
+ emit2 ("ld a,(hl)");
+ emit2 ("xor #0x80");
+ emit2 ("ld l,a");
+ emit2 ("ld a,%d(iy)", offset);
+ emit2 ("xor #0x80");
+ emit2 ("ld h,a");
+ emit2 ("pop af");
+ emit2 ("ld a,l");
+ emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
+ }
+ else
+ {
+ emit2 ("ld a,(hl)");
+ emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
+ }
+
+ if (size != 0)
+ {
+ emit2 ("inc hl");
+ }
+ offset++;
+ }
+ spillPair (PAIR_HL);
+ spillPair (PAIR_IY);
+ }
+ else
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ /* optimize if(x < 0) or if(x >= 0) */
+ if (lit == 0L)
+ {
+ if (!sign)
+ {
+ /* No sign so it's always false */
+ _clearCarry();
+ }
+ else
+ {
+ /* Just load in the top most bit */
+ _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
+ if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
+ {
+ genIfxJump (ifx, "7");
+ return;
+ }
+ else
+ emit2 ("rlc a");
+ }
+ goto release;
+ }
+ }
+
+ if (sign)
+ {
+ /* First setup h and l contaning the top most bytes XORed */
+ bool fDidXor = FALSE;
+ if (AOP_TYPE (left) == AOP_LIT)
+ {
+ unsigned long lit = (unsigned long)
+ floatFromVal (AOP (left)->aopu.aop_lit);
+ emit2 ("ld %s,!immedbyte", _fTmp[0],
+ 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
+ }
+ else
+ {
+ emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
+ emit2 ("xor a,!immedbyte", 0x80);
+ emit2 ("ld %s,a", _fTmp[0]);
+ fDidXor = TRUE;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ unsigned long lit = (unsigned long)
+ floatFromVal (AOP (right)->aopu.aop_lit);
+ emit2 ("ld %s,!immedbyte", _fTmp[1],
+ 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
+ }
+ else
+ {
+ emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
+ emit2 ("xor a,!immedbyte", 0x80);
+ emit2 ("ld %s,a", _fTmp[1]);
+ fDidXor = TRUE;
+ }
+ }
+ while (size--)
+ {
+ /* Do a long subtract */
+ if (!sign || size)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ }
+ if (sign && size == 0)
+ {
+ emit2 ("ld a,%s", _fTmp[0]);
+ emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
+ }
+ else
+ {
+ /* Subtract through, propagating the carry */
+ emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
+ offset++;
+ }
+ }
+ }
+ }
+#endif
+
+/** Generic compare for > or <
+ */
+static void
+genCmp (operand * left, operand * right,
+ operand * result, iCode * ifx, int sign)
+{
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ bool swap_sense = FALSE;
+
+ /* if left & right are bit variables */
+ if (AOP_TYPE (left) == AOP_CRY &&
+ AOP_TYPE (right) == AOP_CRY)
+ {
+ /* Cant happen on the Z80 */
+ wassertl (0, "Tried to compare two bits");
+ }
+ else
+ {
+ /* Do a long subtract of right from left. */
+ size = max (AOP_SIZE (left), AOP_SIZE (right));
+
+ if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
+ {
+ // On the Gameboy we can't afford to adjust HL as it may trash the carry.
+ // Pull left into DE and right into HL
+ aopGet (AOP(left), LSB, FALSE);
+ emit2 ("ld d,h");
+ emit2 ("ld e,l");
+ aopGet (AOP(right), LSB, FALSE);
+
+ while (size--)
+ {
+ emit2 ("ld a,(de)");
+ emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
+
+ if (size != 0)
+ {
+ emit2 ("inc hl");
+ emit2 ("inc de");
+ }
+ offset++;
+ }
+ spillPair (PAIR_HL);
+ goto release;
+ }
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ /* optimize if(x < 0) or if(x >= 0) */
+ if (lit == 0)
+ {
+ if (!sign)
+ {
+ /* No sign so it's always false */
+ _clearCarry();
+ }
+ else
+ {
+ /* Just load in the top most bit */
+ _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
+ if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
+ {
+ genIfxJump (ifx, "7");
+ return;
+ }
+ else
+ {
+ if (!sign)
+ {
+ emit2 ("rlc a");
+ }
+ if (ifx)
+ {
+ genIfxJump (ifx, swap_sense ? "c" : "nc");
+ return;
+ }
+ }
+ }
+ goto release;
+ }
+ }
+
+ while (size--)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ /* Subtract through, propagating the carry */
+ emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
+ offset++;
+ }
+ }
+
+release:
+ if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
+ {
+ if (sign)
+ {
+ /* Shift the sign bit up into carry */
+ emit2 ("rlca");
+ }
+ outBitCLong (result, swap_sense);
+ }
+ else
+ {
+ /* if the result is used in the next
+ ifx conditional branch then generate
+ code a little differently */
+ if (ifx)
+ {
+ if (sign)
+ {
+ if (IS_GB)
+ {
+ emit2 ("rlca");
+ genIfxJump (ifx, swap_sense ? "nc" : "c");
+ }
+ else
+ {
+ genIfxJump (ifx, swap_sense ? "p" : "m");
+ }
+ }
+ else
+ {
+ genIfxJump (ifx, swap_sense ? "nc" : "c");
+ }
+ }
+ else
+ {
+ if (sign)
+ {
+ /* Shift the sign bit up into carry */
+ emit2 ("rlca");
+ }
+ outBitCLong (result, swap_sense);
+ }
+ /* leave the result in acc */
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpGt :- greater than comparison */
+/*-----------------------------------------------------------------*/
+static void
+genCmpGt (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ sym_link *letype, *retype;
+ int sign;
+
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ letype = getSpec (operandType (left));
+ retype = getSpec (operandType (right));
+ sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
+ /* assign the amsops */
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (right, ic, FALSE, FALSE);
+ aopOp (result, ic, TRUE, FALSE);
+
+ genCmp (right, left, result, ifx, sign);
+
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpLt - less than comparisons */
+/*-----------------------------------------------------------------*/
+static void
+genCmpLt (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ sym_link *letype, *retype;
+ int sign;
+
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ letype = getSpec (operandType (left));
+ retype = getSpec (operandType (right));
+ sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
+
+ /* assign the amsops */
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (right, ic, FALSE, FALSE);
+ aopOp (result, ic, TRUE, FALSE);
+
+ genCmp (left, right, result, ifx, sign);
+
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* gencjneshort - compare and jump if not equal */
+/*-----------------------------------------------------------------*/
+static void
+gencjneshort (operand * left, operand * right, symbol * lbl)
+{
+ int size = max (AOP_SIZE (left), AOP_SIZE (right));
+ int offset = 0;
+ unsigned long lit = 0L;
+
+ /* Swap the left and right if it makes the computation easier */
+ if (AOP_TYPE (left) == AOP_LIT)
+ {
+ operand *t = right;
+ right = left;
+ left = t;
+ }
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ /* if the right side is a literal then anything goes */
+ if (AOP_TYPE (right) == AOP_LIT &&
+ AOP_TYPE (left) != AOP_DIR)
+ {
+ if (lit == 0)
+ {
+ emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
+ if (size > 1)
+ {
+ while (--size)
+ {
+ emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
+ }
+ }
+ else
+ {
+ emit2 ("or a,a");
+ }
+ emit2 ("jp nz,!tlabel", lbl->key + 100);
+ }
+ else
+ {
+ while (size--)
+ {
+ emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
+ if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
+ emit2 ("or a,a");
+ else
+ emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
+ emit2 ("jp nz,!tlabel", lbl->key + 100);
+ offset++;
+ }
+ }
+ }
+ /* if the right side is in a register or in direct space or
+ if the left is a pointer register & right is not */
+ else if (AOP_TYPE (right) == AOP_REG ||
+ AOP_TYPE (right) == AOP_DIR ||
+ (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
+ {
+ while (size--)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
+ ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
+ /* PENDING */
+ emit2 ("jp nz,!tlabel", lbl->key + 100);
+ else
+ {
+ emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
+ emit2 ("jp nz,!tlabel", lbl->key + 100);
+ }
+ offset++;
+ }
+ }
+ else
+ {
+ /* right is a pointer reg need both a & b */
+ /* PENDING: is this required? */
+ while (size--)
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
+ emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
+ offset++;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* gencjne - compare and jump if not equal */
+/*-----------------------------------------------------------------*/
+static void
+gencjne (operand * left, operand * right, symbol * lbl)
+{
+ symbol *tlbl = newiTempLabel (NULL);
+
+ gencjneshort (left, right, lbl);
+
+ /* PENDING: ?? */
+ emit2 ("ld a,!one");
+ emit2 ("!shortjp !tlabel", tlbl->key + 100);
+ emitLabel (lbl->key + 100);
+ emit2 ("xor a,a");
+ emitLabel (tlbl->key + 100);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpEq - generates code for equal to */
+/*-----------------------------------------------------------------*/
+static void
+genCmpEq (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
+
+ emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
+
+ /* Swap operands if it makes the operation easier. ie if:
+ 1. Left is a literal.
+ */
+ if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
+ {
+ operand *t = IC_RIGHT (ic);
+ IC_RIGHT (ic) = IC_LEFT (ic);
+ IC_LEFT (ic) = t;
+ }
+
+ if (ifx && !AOP_SIZE (result))
+ {
+ symbol *tlbl;
+ /* if they are both bit variables */
+ if (AOP_TYPE (left) == AOP_CRY &&
+ ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
+ {
+ wassertl (0, "Tried to compare two bits");
+ }
+ else
+ {
+ tlbl = newiTempLabel (NULL);
+ emitDebug(";1");
+ gencjneshort (left, right, tlbl);
+ if (IC_TRUE (ifx))
+ {
+ emitDebug(";2");
+ emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
+ emitLabel (tlbl->key + 100);
+ }
+ else
+ {
+ /* PENDING: do this better */
+ symbol *lbl = newiTempLabel (NULL);
+ emitDebug(";3");
+ emit2 ("!shortjp !tlabel", lbl->key + 100);
+ emitLabel (tlbl->key + 100);
+ emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
+ emitLabel (lbl->key + 100);
+ }
+ }
+ /* mark the icode as generated */
+ ifx->generated = 1;
+ goto release;
+ }
+
+ /* if they are both bit variables */
+ if (AOP_TYPE (left) == AOP_CRY &&
+ ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
+ {
+ wassertl (0, "Tried to compare a bit to either a literal or another bit");
+ }
+ else
+ {
+ emitDebug(";4");
+
+ gencjne (left, right, newiTempLabel (NULL));
+ if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
+ {
+ wassert (0);
+ }
+ if (ifx)
+ {
+ emitDebug(";5");
+ genIfxJump (ifx, "a");
+ goto release;
+ }
+ /* if the result is used in an arithmetic operation
+ then put the result in place */
+ if (AOP_TYPE (result) != AOP_CRY)
+ {
+ emitDebug(";6");
+ outAcc (result);
+ }
+ /* leave the result in acc */
+ }
+
+release:
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* ifxForOp - returns the icode containing the ifx for operand */
+/*-----------------------------------------------------------------*/
+static iCode *
+ifxForOp (operand * op, iCode * ic)
+{
+ /* if true symbol then needs to be assigned */
+ if (IS_TRUE_SYMOP (op))
+ return NULL;
+
+ /* if this has register type condition and
+ the next instruction is ifx with the same operand
+ and live to of the operand is upto the ifx only then */
+ if (ic->next &&
+ ic->next->op == IFX &&
+ IC_COND (ic->next)->key == op->key &&
+ OP_SYMBOL (op)->liveTo <= ic->next->seq)
+ return ic->next;
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAndOp - for && operation */
+/*-----------------------------------------------------------------*/
+static void
+genAndOp (iCode * ic)
+{
+ operand *left, *right, *result;
+ symbol *tlbl;
+
+ /* note here that && operations that are in an if statement are
+ taken away by backPatchLabels only those used in arthmetic
+ operations remain */
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
+ aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
+
+ /* if both are bit variables */
+ if (AOP_TYPE (left) == AOP_CRY &&
+ AOP_TYPE (right) == AOP_CRY)
+ {
+ wassertl (0, "Tried to and two bits");
+ }
+ else
+ {
+ tlbl = newiTempLabel (NULL);
+ _toBoolean (left);
+ emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
+ _toBoolean (right);
+ emitLabel (tlbl->key + 100);
+ outBitAcc (result);
+ }
+
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genOrOp - for || operation */
+/*-----------------------------------------------------------------*/
+static void
+genOrOp (iCode * ic)
+{
+ operand *left, *right, *result;
+ symbol *tlbl;
+
+ /* note here that || operations that are in an
+ if statement are taken away by backPatchLabels
+ only those used in arthmetic operations remain */
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
+ aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
+
+ /* if both are bit variables */
+ if (AOP_TYPE (left) == AOP_CRY &&
+ AOP_TYPE (right) == AOP_CRY)
+ {
+ wassertl (0, "Tried to OR two bits");
+ }
+ else
+ {
+ tlbl = newiTempLabel (NULL);
+ _toBoolean (left);
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ _toBoolean (right);
+ emitLabel (tlbl->key + 100);
+ outBitAcc (result);
+ }
+
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* isLiteralBit - test if lit == 2^n */
+/*-----------------------------------------------------------------*/
+int
+isLiteralBit (unsigned long lit)
+{
+ unsigned long pw[32] =
+ {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
+ 0x100L, 0x200L, 0x400L, 0x800L,
+ 0x1000L, 0x2000L, 0x4000L, 0x8000L,
+ 0x10000L, 0x20000L, 0x40000L, 0x80000L,
+ 0x100000L, 0x200000L, 0x400000L, 0x800000L,
+ 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
+ 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
+ int idx;
+
+ for (idx = 0; idx < 32; idx++)
+ if (lit == pw[idx])
+ return idx + 1;
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* jmpTrueOrFalse - */
+/*-----------------------------------------------------------------*/
+static void
+jmpTrueOrFalse (iCode * ic, symbol * tlbl)
+{
+ // ugly but optimized by peephole
+ if (IC_TRUE (ic))
+ {
+ symbol *nlbl = newiTempLabel (NULL);
+ emit2 ("jp !tlabel", nlbl->key + 100);
+ emitLabel (tlbl->key + 100);
+ emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
+ emitLabel (nlbl->key + 100);
+ }
+ else
+ {
+ emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
+ emitLabel (tlbl->key + 100);
+ }
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAnd - code for and */
+/*-----------------------------------------------------------------*/
+static void
+genAnd (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ int bytelit = 0;
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
+ AOP_NEEDSACC (left))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if (sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY &&
+ AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ size = AOP_SIZE (result);
+
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ wassertl (0, "Tried to perform an AND with a bit as an operand");
+ goto release;
+ }
+
+ // if(val & 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val & 0xZZ - size = 1, ifx = FALSE -
+ if ((AOP_TYPE (right) == AOP_LIT) &&
+ (AOP_TYPE (result) == AOP_CRY) &&
+ (AOP_TYPE (left) != AOP_CRY))
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+ if (size)
+ {
+ /* PENDING: Test case for this. */
+ emit2 ("scf");
+ }
+ while (sizel--)
+ {
+ if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ if (bytelit != 0x0FFL)
+ {
+ emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
+ }
+ else
+ {
+ /* For the flags */
+ emit2 ("or a,a");
+ }
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ }
+ offset++;
+ }
+ // bit = left & literal
+ if (size)
+ {
+ emit2 ("clr c");
+ emit2 ("!tlabeldef", tlbl->key + 100);
+ }
+ // if(left & literal)
+ else
+ {
+ if (ifx)
+ {
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ goto release;
+ }
+ outBitC (result);
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (sameRegs (AOP (result), AOP (left)))
+ {
+ for (; size--; offset++)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
+ continue;
+ else
+ {
+ if (bytelit == 0)
+ aopPut (AOP (result), "!zero", offset);
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("and a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ aopPut (AOP (left), "a", offset);
+ }
+ }
+
+ }
+ else
+ {
+ if (AOP_TYPE (left) == AOP_ACC)
+ {
+ wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
+ }
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("and a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ aopPut (AOP (left), "a", offset);
+ }
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ wassertl (0, "Tried to AND where the result is in carry");
+ }
+ else
+ {
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left & right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
+ {
+ aopPut (AOP (result),
+ aopGet (AOP (left), offset, FALSE),
+ offset);
+ continue;
+ }
+ else if (bytelit == 0)
+ {
+ aopPut (AOP (result), "!zero", offset);
+ continue;
+ }
+ }
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ if (AOP_TYPE (left) == AOP_ACC)
+ emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("and a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ }
+ aopPut (AOP (result), "a", offset);
+ }
+ }
+
+ }
+
+release:
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genOr - code for or */
+/*-----------------------------------------------------------------*/
+static void
+genOr (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ int bytelit = 0;
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
+ AOP_NEEDSACC (left))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if (sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY &&
+ AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ size = AOP_SIZE (result);
+
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ wassertl (0, "Tried to OR where left is a bit");
+ goto release;
+ }
+
+ // if(val | 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val | 0xZZ - size = 1, ifx = FALSE -
+ if ((AOP_TYPE (right) == AOP_LIT) &&
+ (AOP_TYPE (result) == AOP_CRY) &&
+ (AOP_TYPE (left) != AOP_CRY))
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+
+ if (size)
+ {
+ wassertl (0, "Result is assigned to a bit");
+ }
+ /* PENDING: Modeled after the AND code which is inefficent. */
+ while (sizel--)
+ {
+ bytelit = (lit >> (offset * 8)) & 0x0FFL;
+
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ /* OR with any literal is the same as OR with itself. */
+ emit2 ("or a,a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+
+ offset++;
+ }
+ if (ifx)
+ {
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (sameRegs (AOP (result), AOP (left)))
+ {
+ for (; size--; offset++)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+ continue;
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ aopPut (AOP (result), "a", offset);
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (left) == AOP_ACC)
+ emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ aopPut (AOP (result), "a", offset);
+ }
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ wassertl (0, "Result of OR is in a bit");
+ }
+ else
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left & right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+ {
+ aopPut (AOP (result),
+ aopGet (AOP (left), offset, FALSE),
+ offset);
+ continue;
+ }
+ }
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ if (AOP_TYPE (left) == AOP_ACC)
+ emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ }
+ aopPut (AOP (result), "a", offset);
+ /* PENDING: something weird is going on here. Add exception. */
+ if (AOP_TYPE (result) == AOP_ACC)
+ break;
+ }
+ }
+
+release:
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genXor - code for xclusive or */
+/*-----------------------------------------------------------------*/
+static void
+genXor (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
+ AOP_NEEDSACC (left))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if (sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY &&
+ AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ size = AOP_SIZE (result);
+
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ wassertl (0, "Tried to XOR a bit");
+ goto release;
+ }
+
+ // if(val & 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val & 0xZZ - size = 1, ifx = FALSE -
+ if ((AOP_TYPE (right) == AOP_LIT) &&
+ (AOP_TYPE (result) == AOP_CRY) &&
+ (AOP_TYPE (left) != AOP_CRY))
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+
+ if (size)
+ {
+ /* PENDING: Test case for this. */
+ wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
+ }
+ while (sizel--)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ offset++;
+ }
+ if (ifx)
+ {
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ else
+ {
+ wassertl (0, "Result of XOR was destined for a bit");
+ }
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (sameRegs (AOP (result), AOP (left)))
+ {
+ for (; size--; offset++)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+ continue;
+ else
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("xor a,%s",
+ aopGet (AOP (left), offset, FALSE));
+ aopPut (AOP (result), "a", offset);
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (left) == AOP_ACC)
+ {
+ emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+ }
+ else
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("xor a,%s",
+ aopGet (AOP (left), offset, FALSE));
+ aopPut (AOP (result), "a", 0);
+ }
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ wassertl (0, "Result of XOR is in a bit");
+ }
+ else
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left & right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+ {
+ aopPut (AOP (result),
+ aopGet (AOP (left), offset, FALSE),
+ offset);
+ continue;
+ }
+ }
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ if (AOP_TYPE (left) == AOP_ACC)
+ {
+ emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+ }
+ else
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("xor a,%s",
+ aopGet (AOP (left), offset, FALSE));
+ }
+ aopPut (AOP (result), "a", offset);
+ }
+ }
+
+release:
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genInline - write the inline code out */
+/*-----------------------------------------------------------------*/
+static void
+genInline (iCode * ic)
+{
+ char *buffer, *bp, *bp1;
+
+ _G.lines.isInline += (!options.asmpeep);
+
+ buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
+ strcpy (buffer, IC_INLINE (ic));
+
+ /* emit each line as a code */
+ while (*bp)
+ {
+ if (*bp == '\n')
+ {
+ *bp++ = '\0';
+ emit2 (bp1);
+ bp1 = bp;
+ }
+ else
+ {
+ if (*bp == ':')
+ {
+ bp++;
+ *bp = '\0';
+ bp++;
+ emit2 (bp1);
+ bp1 = bp;
+ }
+ else
+ bp++;
+ }
+ }
+ if (bp1 != bp)
+ emit2 (bp1);
+ _G.lines.isInline -= (!options.asmpeep);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genRRC - rotate right with carry */
+/*-----------------------------------------------------------------*/
+static void
+genRRC (iCode * ic)
+{
+ wassert (0);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRLC - generate code for rotate left with carry */
+/*-----------------------------------------------------------------*/
+static void
+genRLC (iCode * ic)
+{
+ wassert (0);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGetHbit - generates code get highest order bit */
+/*-----------------------------------------------------------------*/
+static void
+genGetHbit (iCode * ic)
+{
+ operand *left, *result;
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ /* get the highest order byte into a */
+ emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
+
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ emit2 ("rl a");
+ outBitC (result);
+ }
+ else
+ {
+ emit2 ("rlc a");
+ /* PENDING: For re-target. */
+ emit2 ("and a,#1");
+ outAcc (result);
+ }
+
+
+ freeAsmop (left, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+static void
+emitRsh2 (asmop *aop, int size, int is_signed)
+{
+ int offset = 0;
+
+ while (size--)
+ {
+ const char *l = aopGet (aop, size, FALSE);
+ if (offset == 0)
+ {
+ emit2 ("%s %s", is_signed ? "sra" : "srl", l);
+ }
+ else
+ {
+ emit2 ("rr %s", l);
+ }
+ offset++;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftR2Left2Result - shift right two bytes from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftR2Left2Result (operand * left, int offl,
+ operand * result, int offr,
+ int shCount, int is_signed)
+{
+ int size = 2;
+ symbol *tlbl, *tlbl1;
+
+ movLeft2Result (left, offl, result, offr, 0);
+ movLeft2Result (left, offl + 1, result, offr + 1, 0);
+
+ /* if (AOP(result)->type == AOP_REG) { */
+
+ tlbl = newiTempLabel (NULL);
+ tlbl1 = newiTempLabel (NULL);
+
+ /* Left is already in result - so now do the shift */
+ if (shCount <= 4)
+ {
+ while (shCount--)
+ {
+ emitRsh2 (AOP (result), size, is_signed);
+ }
+ }
+ else
+ {
+ emit2 ("ld a,!immedbyte+1", shCount);
+ emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+ emitLabel (tlbl->key + 100);
+
+ emitRsh2 (AOP (result), size, is_signed);
+
+ emitLabel (tlbl1->key + 100);
+ emit2 ("dec a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftL2Left2Result - shift left two bytes from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftL2Left2Result (operand * left, int offl,
+ operand * result, int offr, int shCount)
+{
+ if (sameRegs (AOP (result), AOP (left)) &&
+ ((offl + MSB16) == offr))
+ {
+ wassert (0);
+ }
+ else
+ {
+ /* Copy left into result */
+ movLeft2Result (left, offl, result, offr, 0);
+ movLeft2Result (left, offl + 1, result, offr + 1, 0);
+ }
+ /* PENDING: for now just see if it'll work. */
+ /*if (AOP(result)->type == AOP_REG) { */
+ {
+ int size = 2;
+ int offset = 0;
+ symbol *tlbl, *tlbl1;
+ const char *l;
+
+ tlbl = newiTempLabel (NULL);
+ tlbl1 = newiTempLabel (NULL);
+
+ /* Left is already in result - so now do the shift */
+ if (shCount > 1)
+ {
+ emit2 ("ld a,!immedbyte+1", shCount);
+ emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+ emitLabel (tlbl->key + 100);
+ }
+
+ while (size--)
+ {
+ l = aopGet (AOP (result), offset, FALSE);
+
+ if (offset == 0)
+ {
+ emit2 ("sla %s", l);
+ }
+ else
+ {
+ emit2 ("rl %s", l);
+ }
+
+ offset++;
+ }
+ if (shCount > 1)
+ {
+ emitLabel (tlbl1->key + 100);
+ emit2 ("dec a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ }
+ }
+}
+