+ /* I suppose that the left size >= result size */
+ if (shCount == 0)
+ {
+ wassert (0);
+ }
+
+ else if (shCount >= (size * 8))
+ {
+ while (size--)
+ {
+ aopPut (AOP (result), "!zero", size);
+ }
+ }
+ else
+ {
+ switch (size)
+ {
+ case 1:
+ genlshOne (result, left, shCount);
+ break;
+ case 2:
+ genlshTwo (result, left, shCount);
+ break;
+ case 4:
+ wassertl (0, "Shifting of longs is currently unsupported");
+ break;
+ default:
+ wassert (0);
+ }
+ }
+ freeAsmop (left, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genLeftShift - generates code for left shifting */
+/*-----------------------------------------------------------------*/
+static void
+genLeftShift (iCode * ic)
+{
+ int size, offset;
+ const char *l;
+ symbol *tlbl, *tlbl1;
+ operand *left, *right, *result;
+
+ right = IC_RIGHT (ic);
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (right, ic, FALSE, FALSE);
+
+ /* if the shift count is known then do it
+ as efficiently as possible */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ genLeftShiftLiteral (left, right, result, ic);
+ return;
+ }
+
+ /* shift count is unknown then we have to form a loop get the loop
+ count in B : Note: we take only the lower order byte since
+ shifting more that 32 bits make no sense anyway, ( the largest
+ size of an object can be only 32 bits ) */
+ emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
+ emit2 ("inc a");
+ freeAsmop (right, NULL, ic);
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ /* now move the left to the result if they are not the
+ same */
+
+ if (!sameRegs (AOP (left), AOP (result)))
+ {
+
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ l = aopGet (AOP (left), offset, FALSE);
+ aopPut (AOP (result), l, offset);
+ offset++;
+ }
+ }
+
+ tlbl = newiTempLabel (NULL);
+ size = AOP_SIZE (result);
+ offset = 0;
+ tlbl1 = newiTempLabel (NULL);
+
+ emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+ emitLabel (tlbl->key + 100);
+ l = aopGet (AOP (result), offset, FALSE);
+
+ while (size--)
+ {
+ l = aopGet (AOP (result), offset, FALSE);
+
+ if (offset == 0)
+ {
+ emit2 ("sla %s", l);
+ }
+ else
+ {
+ emit2 ("rl %s", l);
+ }
+ offset++;
+ }
+ emitLabel (tlbl1->key + 100);
+ emit2 ("dec a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+
+ freeAsmop (left, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshOne - left shift two bytes by known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genrshOne (operand * result, operand * left, int shCount, int is_signed)
+{
+ /* Errk */
+ int size = AOP_SIZE (result);
+ const char *l;
+
+ wassert (size == 1);
+ wassert (shCount < 8);
+
+ l = aopGet (AOP (left), 0, FALSE);
+
+ if (AOP (result)->type == AOP_REG)
+ {
+ aopPut (AOP (result), l, 0);
+ l = aopGet (AOP (result), 0, FALSE);
+ while (shCount--)
+ {
+ emit2 ("%s %s", is_signed ? "sra" : "srl", l);
+ }
+ }
+ else
+ {
+ _moveA (l);
+ while (shCount--)
+ {
+ emit2 ("%s a", is_signed ? "sra" : "srl");
+ }
+ aopPut (AOP (result), "a", 0);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccRsh - right shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccRsh (int shCount)
+{
+ static const unsigned char SRMask[] =
+ {
+ 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
+ };
+
+ if (shCount != 0)
+ {
+ /* rotate right accumulator */
+ AccRol (8 - shCount);
+ /* and kill the higher order bits */
+ emit2 ("and a,!immedbyte", SRMask[shCount]);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftR1Left2Result - shift right one byte from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftR1Left2Result (operand * left, int offl,
+ operand * result, int offr,
+ int shCount, int sign)
+{
+ _moveA (aopGet (AOP (left), offl, FALSE));
+ if (sign)
+ {
+ while (shCount--)
+ {
+ emit2 ("%s a", sign ? "sra" : "srl");
+ }
+ }
+ else
+ {
+ AccRsh (shCount);
+ }
+ aopPut (AOP (result), "a", offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshTwo - right shift two bytes by known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genrshTwo (operand * result, operand * left,
+ int shCount, int sign)
+{
+ /* if shCount >= 8 */
+ if (shCount >= 8)
+ {
+ shCount -= 8;
+ if (shCount)
+ {
+ shiftR1Left2Result (left, MSB16, result, LSB,
+ shCount, sign);
+ }
+ else
+ {
+ movLeft2Result (left, MSB16, result, LSB, sign);
+ }
+ if (sign)
+ {
+ /* Sign extend the result */
+ _moveA(aopGet (AOP (result), 0, FALSE));
+ emit2 ("rlc a");
+ emit2 ("sbc a,a");
+
+ aopPut (AOP (result), ACC_NAME, MSB16);
+ }
+ else
+ {
+ aopPut (AOP (result), "!zero", 1);
+ }
+ }
+ /* 1 <= shCount <= 7 */
+ else
+ {
+ shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genRightShiftLiteral - left shifting by known count */
+/*-----------------------------------------------------------------*/
+static void
+genRightShiftLiteral (operand * left,
+ operand * right,
+ operand * result,
+ iCode * ic,
+ int sign)
+{
+ int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+ int size;
+
+ freeAsmop (right, NULL, ic);
+
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ size = getSize (operandType (result));
+
+ /* I suppose that the left size >= result size */
+ if (shCount == 0)
+ {
+ wassert (0);
+ }
+
+ else if (shCount >= (size * 8))
+ while (size--)
+ aopPut (AOP (result), "!zero", size);
+ else
+ {
+ switch (size)
+ {
+ case 1:
+ genrshOne (result, left, shCount, sign);
+ break;
+ case 2:
+ genrshTwo (result, left, shCount, sign);
+ break;
+ case 4:
+ wassertl (0, "Asked to shift right a long which should be a function call");
+ break;
+ default:
+ wassertl (0, "Entered default case in right shift delegate");
+ }
+ }
+ freeAsmop (left, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRightShift - generate code for right shifting */
+/*-----------------------------------------------------------------*/
+static void
+genRightShift (iCode * ic)
+{
+ operand *right, *left, *result;
+ sym_link *retype;
+ int size, offset, first = 1;
+ const char *l;
+ bool is_signed;
+
+ symbol *tlbl, *tlbl1;
+
+ /* if signed then we do it the hard way preserve the
+ sign bit moving it inwards */
+ retype = getSpec (operandType (IC_RESULT (ic)));
+
+ is_signed = !SPEC_USIGN (retype);
+
+ /* signed & unsigned types are treated the same : i.e. the
+ signed is NOT propagated inwards : quoting from the
+ ANSI - standard : "for E1 >> E2, is equivalent to division
+ by 2**E2 if unsigned or if it has a non-negative value,
+ otherwise the result is implementation defined ", MY definition
+ is that the sign does not get propagated */
+
+ right = IC_RIGHT (ic);
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (right, ic, FALSE, FALSE);
+
+ /* if the shift count is known then do it
+ as efficiently as possible */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ genRightShiftLiteral (left, right, result, ic, is_signed);
+ return;
+ }
+
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ /* now move the left to the result if they are not the
+ same */
+ if (!sameRegs (AOP (left), AOP (result)) &&
+ AOP_SIZE (result) > 1)
+ {
+
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ l = aopGet (AOP (left), offset, FALSE);
+ aopPut (AOP (result), l, offset);
+ offset++;
+ }
+ }
+
+ emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
+ emit2 ("inc a");
+ freeAsmop (right, NULL, ic);
+
+ tlbl = newiTempLabel (NULL);
+ tlbl1 = newiTempLabel (NULL);
+ size = AOP_SIZE (result);
+ offset = size - 1;
+
+ emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+ emitLabel (tlbl->key + 100);
+ while (size--)
+ {
+ l = aopGet (AOP (result), offset--, FALSE);
+ if (first)
+ {
+ emit2 ("%s %s", is_signed ? "sra" : "srl", l);
+ first = 0;
+ }
+ else
+ {
+ emit2 ("rr %s", l);
+ }
+ }
+ emitLabel (tlbl1->key + 100);
+ emit2 ("dec a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+
+ freeAsmop (left, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGenPointerGet - get value from generic pointer space */
+/*-----------------------------------------------------------------*/
+static void
+genGenPointerGet (operand * left,
+ operand * result, iCode * ic)
+{
+ int size, offset;
+ sym_link *retype = getSpec (operandType (result));
+ int pair = PAIR_HL;
+
+ if (IS_GB)
+ pair = PAIR_DE;
+
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
+ {
+ /* Just do it */
+ if (isPtrPair (AOP (left)))
+ {
+ tsprintf (buffer, "!*pair", getPairName (AOP (left)));
+ aopPut (AOP (result), buffer, 0);
+ }
+ else
+ {
+ emit2 ("ld a,!*pair", getPairName (AOP (left)));
+ aopPut (AOP (result), "a", 0);
+ }
+ freeAsmop (left, NULL, ic);
+ goto release;
+ }
+
+ /* For now we always load into IY */
+ /* if this is remateriazable */
+ fetchPair (pair, AOP (left));
+
+ /* so iy now contains the address */
+ freeAsmop (left, NULL, ic);
+
+ /* if bit then unpack */
+ if (IS_BITVAR (retype))
+ {
+ wassert (0);
+ }
+ else
+ {
+ size = AOP_SIZE (result);
+ offset = 0;
+
+ while (size--)
+ {
+ /* PENDING: make this better */
+ if (!IS_GB && AOP (result)->type == AOP_REG)
+ {
+ aopPut (AOP (result), "!*hl", offset++);
+ }
+ else
+ {
+ emit2 ("ld a,!*pair", _pairs[pair].name);
+ aopPut (AOP (result), "a", offset++);
+ }
+ if (size)
+ {
+ emit2 ("inc %s", _pairs[pair].name);
+ _G.pairs[pair].offset++;
+ }
+ }
+ }
+
+release:
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPointerGet - generate code for pointer get */
+/*-----------------------------------------------------------------*/
+static void
+genPointerGet (iCode * ic)
+{
+ operand *left, *result;
+ sym_link *type, *etype;
+
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ /* depending on the type of pointer we need to
+ move it to the correct pointer register */
+ type = operandType (left);
+ etype = getSpec (type);
+
+ genGenPointerGet (left, result, ic);
+}
+
+bool
+isRegOrLit (asmop * aop)
+{
+ if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
+ return TRUE;
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* genGenPointerSet - stores the value into a pointer location */
+/*-----------------------------------------------------------------*/
+static void
+genGenPointerSet (operand * right,
+ operand * result, iCode * ic)
+{
+ int size, offset;
+ sym_link *retype = getSpec (operandType (right));
+ PAIR_ID pairId = PAIR_HL;
+
+ aopOp (result, ic, FALSE, FALSE);
+ aopOp (right, ic, FALSE, FALSE);
+
+ if (IS_GB)
+ pairId = PAIR_DE;
+
+ /* Handle the exceptions first */
+ if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
+ {
+ /* Just do it */
+ const char *l = aopGet (AOP (right), 0, FALSE);
+ const char *pair = getPairName (AOP (result));
+ if (canAssignToPtr (l) && isPtr (pair))
+ {
+ emit2 ("ld !*pair,%s", pair, l);
+ }
+ else
+ {
+ _moveA (l);
+ emit2 ("ld !*pair,a", pair);
+ }
+ goto release;
+ }
+
+ /* if the operand is already in dptr
+ then we do nothing else we move the value to dptr */
+ if (AOP_TYPE (result) != AOP_STR)
+ {
+ fetchPair (pairId, AOP (result));
+ }
+ /* so hl know contains the address */
+ freeAsmop (result, NULL, ic);
+
+ /* if bit then unpack */
+ if (IS_BITVAR (retype))
+ {
+ wassert (0);
+ }
+ else
+ {
+ size = AOP_SIZE (right);
+ offset = 0;
+
+ while (size--)
+ {
+ const char *l = aopGet (AOP (right), offset, FALSE);
+ if (isRegOrLit (AOP (right)) && !IS_GB)
+ {
+ emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
+ }
+ else
+ {
+ _moveA (l);
+ emit2 ("ld !*pair,a", _pairs[pairId].name);
+ }
+ if (size)
+ {
+ emit2 ("inc %s", _pairs[pairId].name);
+ _G.pairs[pairId].offset++;
+ }
+ offset++;
+ }
+ }
+release:
+ freeAsmop (right, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPointerSet - stores the value into a pointer location */
+/*-----------------------------------------------------------------*/
+static void
+genPointerSet (iCode * ic)
+{
+ operand *right, *result;
+ sym_link *type, *etype;
+
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ /* depending on the type of pointer we need to
+ move it to the correct pointer register */
+ type = operandType (result);
+ etype = getSpec (type);
+
+ genGenPointerSet (right, result, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genIfx - generate code for Ifx statement */
+/*-----------------------------------------------------------------*/
+static void
+genIfx (iCode * ic, iCode * popIc)
+{
+ operand *cond = IC_COND (ic);
+ int isbit = 0;
+
+ aopOp (cond, ic, FALSE, TRUE);
+
+ /* get the value into acc */
+ if (AOP_TYPE (cond) != AOP_CRY)
+ _toBoolean (cond);
+ else
+ isbit = 1;
+ /* the result is now in the accumulator */
+ freeAsmop (cond, NULL, ic);
+
+ /* if there was something to be popped then do it */
+ if (popIc)
+ genIpop (popIc);
+
+ /* if the condition is a bit variable */
+ if (isbit && IS_ITEMP (cond) &&
+ SPIL_LOC (cond))
+ genIfxJump (ic, SPIL_LOC (cond)->rname);
+ else if (isbit && !IS_ITEMP (cond))
+ genIfxJump (ic, OP_SYMBOL (cond)->rname);
+ else
+ genIfxJump (ic, "a");
+
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAddrOf - generates code for address of */
+/*-----------------------------------------------------------------*/
+static void
+genAddrOf (iCode * ic)
+{
+ symbol *sym = OP_SYMBOL (IC_LEFT (ic));
+
+ aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
+
+ /* if the operand is on the stack then we
+ need to get the stack offset of this
+ variable */
+ if (IS_GB)
+ {
+ if (sym->onStack)
+ {
+ spillCached ();
+ if (sym->stack <= 0)
+ {
+ setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
+ }
+ else
+ {
+ setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
+ }
+ commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
+ }
+ else
+ {
+ emit2 ("ld de,!hashedstr", sym->rname);
+ commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
+ }
+ }
+ else
+ {
+ spillCached ();
+ if (sym->onStack)
+ {
+ /* if it has an offset then we need to compute it */
+ if (sym->stack > 0)
+ emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
+ else
+ emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
+ emit2 ("add hl,sp");
+ }
+ else
+ {
+ emit2 ("ld hl,#%s", sym->rname);
+ }
+ commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
+ }
+ freeAsmop (IC_RESULT (ic), NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genAssign - generate code for assignment */
+/*-----------------------------------------------------------------*/
+static void
+genAssign (iCode * ic)
+{
+ operand *result, *right;
+ int size, offset;
+ unsigned long lit = 0L;
+
+ result = IC_RESULT (ic);
+ right = IC_RIGHT (ic);
+
+ /* Dont bother assigning if they are the same */
+ if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
+ {
+ emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
+ return;
+ }
+
+ aopOp (right, ic, FALSE, FALSE);
+ aopOp (result, ic, TRUE, FALSE);
+
+ /* if they are the same registers */
+ if (sameRegs (AOP (right), AOP (result)))
+ {
+ emitDebug ("; (registers are the same)");
+ goto release;
+ }
+
+ /* if the result is a bit */
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ wassertl (0, "Tried to assign to a bit");
+ }
+
+ /* general case */
+ size = AOP_SIZE (result);
+ offset = 0;
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ if (isPair (AOP (result)))
+ {
+ fetchPair (getPairId (AOP (result)), AOP (right));
+ }
+ else if ((size > 1) &&
+ (AOP_TYPE (result) != AOP_REG) &&
+ (AOP_TYPE (right) == AOP_LIT) &&
+ !IS_FLOAT (operandType (right)) &&
+ (lit < 256L))
+ {
+ bool fXored = FALSE;
+ offset = 0;
+ /* Work from the top down.
+ Done this way so that we can use the cached copy of 0
+ in A for a fast clear */
+ while (size--)
+ {
+ if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
+ {
+ if (!fXored && size > 1)
+ {
+ emit2 ("xor a,a");
+ fXored = TRUE;
+ }
+ if (fXored)
+ {
+ aopPut (AOP (result), "a", offset);
+ }
+ else
+ {
+ aopPut (AOP (result), "!zero", offset);
+ }
+ }
+ else
+ aopPut (AOP (result),
+ aopGet (AOP (right), offset, FALSE),
+ offset);
+ offset++;
+ }
+ }
+ else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
+ {
+ /* Special case. Load into a and d, then load out. */
+ _moveA (aopGet (AOP (right), 0, FALSE));
+ emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
+ aopPut (AOP (result), "a", 0);
+ aopPut (AOP (result), "e", 1);
+ }
+ else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
+ {
+ /* Special case - simple memcpy */
+ aopGet (AOP (right), LSB, FALSE);
+ emit2 ("ld d,h");
+ emit2 ("ld e,l");
+ aopGet (AOP (result), LSB, FALSE);
+
+ while (size--)
+ {
+ emit2 ("ld a,(de)");
+ /* Peephole will optimise this. */
+ emit2 ("ld (hl),a");
+
+ if (size != 0)
+ {
+ emit2 ("inc hl");
+ emit2 ("inc de");
+ }
+ }
+ spillPair (PAIR_HL);
+ }
+ else
+ {
+ while (size--)
+ {
+ /* PENDING: do this check better */
+ if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ aopPut (AOP (result), "a", offset);
+ }
+ else
+ aopPut (AOP (result),
+ aopGet (AOP (right), offset, FALSE),
+ offset);
+ offset++;
+ }