+2004-02-11 Bernhard Held <bernhard AT bernhardheld.de>
+
+ * device/lib/_modsint.c,
+ * device/lib/_modslong.c: sign follows divisor only
+ * src/hc08/gen.c (genMultOneByte): if result size is 1,
+ signs or signedness can be ignored
+ * src/SDCCast.c (addCast): cosmetic - added lineno to CAST
+ * src/SDCCast.c (resultTypePropagate): added even more ops: +, - and *,
+ added optimization for IFX,
+ (decorateType): Mult/Div/ModOneByte ops can handle all kind of signed
+ arguments;
+ reenabled optimization for IFX, which was removed on 2004-01-11
+ * src/SDCCast.h: added return type IFX
+ * src/SDCCicode.c: Mult/Div/ModOneByte ops can handle all kind of signed
+ arguments with 8 or 16 bit results; pic14 and pic16 ports use old
+ promotion behaviour; env. var. SDCC_NEWONEBYTEOPS selects the new,
+ SDCC_OLDONEBYTEOPS selects the old behaviour
+ * src/SDCCsymt.c (computeType): type2 can be NULL (for LEFT_OP);
+ changed again and commented promotion rule (it's still not perfect)
+ * src/SDCCval.c (valDiv): promotion no longer necessary
+ * src/ds390/gen.c (genMultOneByte) (genDivOneByte) (genModOneByte),
+ * src/mcs51/gen.c (genMultOneByte) (genDivOneByte) (genModOneByte):
+ rewritten
+ * support/regression/tests/onebyte.c: added
+
2004-02-11 Vangelis Rokas <vrokas AT otenet.gr>
* gen.c (genInline): reverted to old code for assemnling inline
* pcode.c (pic16initMnemonics): fixed typo in assignment to PCOP_RLNCF
PCOP_RLCF was overwritten!
- * gen.c (genSkip) commented out calls to pic16_emitcode,
- * (genCmpEQ) fixed "long" compares, only high word did get compared,
+ * gen.c (genSkip): commented out calls to pic16_emitcode,
+ * (genCmpEQ): fixed "long" compares, only high word did get compared,
* (genlshTwo),
- * (genRRC) added debugging info,
- * (shiftL2Left2Result) Fixed bug, if offr > offl. Result got
+ * (genRRC): added debugging info,
+ * (shiftL2Left2Result): Fixed bug, if offr > offl. Result got
overwritten while shifting,
- * (shiftR2Left2Result) Fixed bug, if offr < offl. Result got
+ * (shiftR2Left2Result): Fixed bug, if offr < offl. Result got
overwritten while shifting,
* (AccLsh),
* (AccRsh),
* (shiftLLeftOrResult),
* (shiftRLeftOrResult),
* (shiftRLong),
- * (shiftLLong) Implemented with pic16_emitpcode
- * (genlshFour) Replaced pic16_aopPut with pic16_emitpcode,
- * (genLeftShift) Fixed bug, operand for shift by variable always
+ * (shiftLLong): Implemented with pic16_emitpcode
+ * (genlshFour): Replaced pic16_aopPut with pic16_emitpcode,
+ * (genLeftShift): Fixed bug, operand for shift by variable always
was "and"ed with 0x0f,
* (genLeftShiftLiteral),
* (genrshTwo),
- * (genRightShiftLiteral) added debugging info,
- * (genrshFour) added comment,
- * (genRightShift) determined signedness from operand "left"
+ * (genRightShiftLiteral): added debugging info,
+ * (genrshFour): added comment,
+ * (genRightShift): determined signedness from operand "left"
instead of "result"
2004-02-04 Erik Petrich <epetrich AT ivorytower.norman.ok.us>
mov a,b1
jnb acc.7,b_not_negative
- cpl F0
-
clr a
clr c
subb a,b0
mov a,b3
jnb acc.7,b_not_negative
- cpl F0
-
clr a ; b = -b;
clr c
subb a,b0
}
tree->decorated = 0;
tree = newNode (CAST, newAst_LINK (newLink), tree);
+ tree->lineno = tree->right->lineno;
/* keep unsigned type during cast to smaller type,
but not when promoting from char to int */
if (!upCasted)
case ':':
case '|':
case '^':
+ case '*':
+ case '+':
+ case '-':
+ case LABEL:
return resultType;
case '&':
if (!tree->right)
return RESULT_TYPE_NONE;
else
return resultType;
+ case IFX:
+ return RESULT_TYPE_IFX;
default:
return RESULT_TYPE_NONE;
}
}
LRVAL (tree) = RRVAL (tree) = 1;
+
TETYPE (tree) = getSpec (TTYPE (tree) =
computeType (LTYPE (tree),
RTYPE (tree),
- ! (IS_UNSIGNED (LTYPE (tree)) && IS_UNSIGNED (RTYPE (tree)))));
+ resultType == RESULT_TYPE_CHAR ? FALSE : TRUE));
/* if right is a literal and */
/* left is also a division by a literal then */
TETYPE (tree) = getSpec (TTYPE (tree) =
computeType (LTYPE (tree),
RTYPE (tree),
- ! (IS_UNSIGNED (LTYPE (tree)) && IS_UNSIGNED (RTYPE (tree)))));
+ resultType == RESULT_TYPE_CHAR ? FALSE : TRUE));
return tree;
/*------------------------------------------------------------------*/
computeType (LTYPE (tree),
RTYPE (tree),
resultType == RESULT_TYPE_CHAR ? FALSE : TRUE));
-
+
return tree;
/*------------------------------------------------------------------*/
tree->left = addCast (tree->left, resultType, TRUE);
TETYPE (tree) = getSpec (TTYPE (tree) =
computeType (LTYPE (tree),
- RTYPE (tree),
+ NULL,
resultType == RESULT_TYPE_CHAR ? FALSE : TRUE));
}
else /* RIGHT_OP */
}
if (tree->opval.op == '>')
{
- /* if the parent is an ifx, then we could do */
- /* return tree->left; */
+ if (resultType == RESULT_TYPE_IFX)
+ {
+ /* the parent is an ifx: */
+ /* if (unsigned value) */
+ return tree->left;
+ }
+
+ /* (unsigned value) ? 1 : 0 */
tree->opval.op = '?';
tree->right = newNode (':',
newAst_VALUE (constVal ("1")),
RESULT_TYPE_BIT,
RESULT_TYPE_CHAR,
RESULT_TYPE_INT,
- RESULT_TYPE_OTHER
+ RESULT_TYPE_OTHER,
+ RESULT_TYPE_IFX,
} RESULT_TYPE;
/* forward declarations for global variables */
/*-----------------------------------------------------------------*/
/* forward definition of some functions */
-operand *geniCodeDivision (operand *, operand *);
+operand *geniCodeDivision (operand *, operand *, bool);
operand *geniCodeAssign (operand *, operand *, int);
static operand *geniCodeArray (operand *, operand *,int);
static operand *geniCodeArray2Ptr (operand *);
/*-----------------------------------------------------------------*/
/* perform "usual binary conversions" */
/*-----------------------------------------------------------------*/
+
static sym_link *
usualBinaryConversions (operand ** op1, operand ** op2,
- bool promoteCharToInt, bool isMul)
+ bool resultIsInt, char op)
{
sym_link *ctype;
sym_link *rtype = operandType (*op2);
sym_link *ltype = operandType (*op1);
- ctype = computeType (ltype, rtype, promoteCharToInt);
+#define OLDONEBYTEOPS 1
- /* special for multiplication:
- This if for 'mul a,b', which takes two chars and returns an int */
- if ( isMul
- /* && promoteCharToInt superfluous, already handled by computeType() */
- && IS_INT (getSpec (ctype)))
+#ifdef OLDONEBYTEOPS
+ bool oldOneByteOps = FALSE;
+ static bool saidHello = FALSE;
+
+ if ( strcmp (port->target, "pic14") == 0
+ || strcmp (port->target, "pic16") == 0)
+ oldOneByteOps = TRUE;
+ if (getenv ("SDCC_NEWONEBYTEOPS"))
{
- sym_link *retype = getSpec (rtype);
- sym_link *letype = getSpec (ltype);
-
- if ( IS_CHAR (letype)
- && IS_CHAR (retype)
- && IS_UNSIGNED (letype)
- && IS_UNSIGNED (retype))
- {
- return ctype;
+ if (!saidHello)
+ {
+ fprintf (stderr, "Override: oldOneByteOps = FALSE\n");
+ saidHello = TRUE;
+ }
+ oldOneByteOps = FALSE;
+ }
+ else if (getenv ("SDCC_OLDONEBYTEOPS"))
+ {
+ if (!saidHello)
+ {
+ fprintf (stderr, "Override: oldOneByteOps = TRUE\n");
+ saidHello = TRUE;
}
+ oldOneByteOps = TRUE;
+ }
+
+
+ if ( oldOneByteOps
+ && ( (IS_CHAR (getSpec (ltype)) && !IS_UNSIGNED (getSpec (ltype)))
+ || (IS_CHAR (getSpec (rtype)) && !IS_UNSIGNED (getSpec (rtype)))))
+ /* one or two signed char operands: promote to int */
+ resultIsInt = TRUE;
+#endif
+
+ ctype = computeType (ltype, rtype, resultIsInt);
+
+#ifdef OLDONEBYTEOPS
+
+ if (oldOneByteOps)
+ {
+ if ( op == '*'
+ && IS_CHAR (getSpec (ltype)) && IS_UNSIGNED (getSpec (ltype))
+ && IS_CHAR (getSpec (rtype)) && IS_UNSIGNED (getSpec (rtype)))
+ {
+ /* two unsigned char operands and Mult: no promotion */
+ return ctype;
+ }
+ *op1 = geniCodeCast (ctype, *op1, TRUE);
+ *op2 = geniCodeCast (ctype, *op2, TRUE);
+
+ return ctype;
}
+
+#endif
+
+ switch (op)
+ {
+ case '*':
+ case '/':
+ case '%':
+ if (IS_CHAR (getSpec (ltype)) && IS_CHAR (getSpec (rtype)))
+ {
+ /* one byte operations: keep signedness for code generator */
+ return ctype;
+ }
+ break;
+ default:
+ break;
+ }
+
*op1 = geniCodeCast (ctype, *op1, TRUE);
*op2 = geniCodeCast (ctype, *op2, TRUE);
-
+
return ctype;
}
/* geniCodeMultiply - gen intermediate code for multiplication */
/*-----------------------------------------------------------------*/
operand *
-geniCodeMultiply (operand * left, operand * right, int resultIsInt)
+geniCodeMultiply (operand * left, operand * right, bool resultIsInt)
{
iCode *ic;
int p2 = 0;
p2 = powof2 ((TYPE_UDWORD) floatFromVal (right->operand.valOperand));
}
- resType = usualBinaryConversions (&left, &right, resultIsInt, TRUE);
+ resType = usualBinaryConversions (&left, &right, resultIsInt, '*');
#if 1
rtype = operandType (right);
retype = getSpec (rtype);
/* geniCodeDivision - gen intermediate code for division */
/*-----------------------------------------------------------------*/
operand *
-geniCodeDivision (operand * left, operand * right)
+geniCodeDivision (operand * left, operand * right, bool resultIsInt)
{
iCode *ic;
int p2 = 0;
sym_link *ltype = operandType (left);
sym_link *letype = getSpec (ltype);
- resType = usualBinaryConversions (&left, &right,
- (IS_UNSIGNED (retype) && IS_UNSIGNED (letype)) ? FALSE : TRUE,
- FALSE);
+ resType = usualBinaryConversions (&left, &right, resultIsInt, '/');
/* if the right is a literal & power of 2
and left is unsigned then make it a
/* geniCodeModulus - gen intermediate code for modulus */
/*-----------------------------------------------------------------*/
operand *
-geniCodeModulus (operand * left, operand * right)
+geniCodeModulus (operand * left, operand * right, bool resultIsInt)
{
iCode *ic;
sym_link *resType;
return operandFromValue (valMod (left->operand.valOperand,
right->operand.valOperand));
- resType = usualBinaryConversions (&left, &right,
- (IS_UNSIGNED (retype) && IS_UNSIGNED (letype)) ? FALSE : TRUE,
- FALSE);
+ resType = usualBinaryConversions (&left, &right, resultIsInt, '%');
/* now they are the same size */
ic = newiCode ('%', left, right);
// should we really do this? is this ANSI?
return geniCodeDivision (result,
- operandFromLit (getSize (ltype->next)));
+ operandFromLit (getSize (ltype->next)),
+ FALSE);
}
/*-----------------------------------------------------------------*/
}
else
{ /* make them the same size */
- resType = usualBinaryConversions (&left, &right, FALSE, FALSE);
+ resType = usualBinaryConversions (&left, &right, FALSE, '-');
}
ic = newiCode ('-', left, right);
}
else
{ // make them the same size
- resType = usualBinaryConversions (&left, &right, FALSE, FALSE);
+ resType = usualBinaryConversions (&left, &right, FALSE, '+');
}
/* if they are both literals then we know */
}
}
- ctype = usualBinaryConversions (&left, &right, FALSE, FALSE);
+ ctype = usualBinaryConversions (&left, &right, FALSE, ' ');
ic = newiCode (op, left, right);
IC_RESULT (ic) = newiTempOperand (newCharLink (), 1);
case '/':
return geniCodeDivision (geniCodeRValue (left, FALSE),
- geniCodeRValue (right, FALSE));
+ geniCodeRValue (right, FALSE),
+ IS_INT (tree->ftype));
case '%':
return geniCodeModulus (geniCodeRValue (left, FALSE),
- geniCodeRValue (right, FALSE));
+ geniCodeRValue (right, FALSE),
+ IS_INT (tree->ftype));
case '*':
if (right)
return geniCodeMultiply (geniCodeRValue (left, FALSE),
- geniCodeRValue (right, FALSE),IS_INT(tree->ftype));
+ geniCodeRValue (right, FALSE),
+ IS_INT (tree->ftype));
else
return geniCodeDerefPtr (geniCodeRValue (left, FALSE),lvl);
geniCodeAssign (left,
geniCodeDivision (geniCodeRValue (operandFromOperand (left),
FALSE),
- geniCodeRValue (right, FALSE)), 0);
+ geniCodeRValue (right, FALSE),
+ IS_INT (tree->ftype)),
+ 0);
case MOD_ASSIGN:
return
geniCodeAssign (left,
geniCodeModulus (geniCodeRValue (operandFromOperand (left),
FALSE),
- geniCodeRValue (right, FALSE)), 0);
+ geniCodeRValue (right, FALSE),
+ IS_INT (tree->ftype)),
+ 0);
case ADD_ASSIGN:
{
sym_link *rtype = operandType (right);
sym_link *rType;
sym_link *reType;
sym_link *etype1 = getSpec (type1);
- sym_link *etype2 = getSpec (type2);
+ sym_link *etype2;
+
+ etype2 = type2 ? getSpec (type2) : type1;
/* if one of them is a float then result is a float */
/* here we assume that the types passed are okay */
if (IS_CHAR (reType) && promoteCharToInt)
SPEC_NOUN (reType) = V_INT;
- if ( ( ( SPEC_USIGN (etype1)
+ if (!IS_FLOAT (reType)
+ && ( ( SPEC_USIGN (etype1)
/* if this operand is promoted to a larger
type don't check it's signedness */
&& (getSize (etype1) >= getSize (reType))
- /* We store signed literals in the range 0...255 as
- 'unsigned char'. If there was no promotion to 'signed int'
- they must not force an unsigned operation: */
- && !(IS_CHAR (etype1) && IS_LITERAL (etype1)))
+ /* char has to handled as it would have
+ been promoted to int */
+ && !IS_CHAR (etype1))
+ /* same for 2nd operand */
|| ( SPEC_USIGN (etype2)
&& (getSize (etype2) >= getSize (reType))
- && !(IS_CHAR (etype2) && IS_LITERAL (etype2))))
- && !IS_FLOAT (reType))
+ && !IS_CHAR (etype2))
+ /* if both are unsigned char and not promoted
+ let the result be unsigned too */
+ || ( SPEC_USIGN (etype1)
+ && SPEC_USIGN (etype2)
+ && IS_CHAR (etype1)
+ && IS_CHAR (etype2)
+ && !promoteCharToInt)))
SPEC_USIGN (reType) = 1;
else
SPEC_USIGN (reType) = 0;
SPEC_LONG (val->type) = (SPEC_LONG (lval->etype) | SPEC_LONG (rval->etype));
SPEC_USIGN (val->type) = SPEC_USIGN (computeType (lval->etype,
rval->etype,
- TRUE));
+ FALSE));
if (IS_FLOAT (val->type))
SPEC_CVAL (val->type).v_float = floatFromVal (lval) / floatFromVal (rval);
operand * result,
iCode * ic)
{
- sym_link *opetype = operandType (result);
+ int size;
symbol *lbl;
-
+ bool runtimeSign, compiletimeSign;
+ bool lUnsigned, rUnsigned;
+
/* (if two literals: the value is computed before) */
/* if one literal, literal on the right */
emitcode (";", "swapped left and right");
}
- if (SPEC_USIGN(opetype)
- // ignore the sign of left and right, what else can we do?
- || (SPEC_USIGN(operandType(left)) &&
- SPEC_USIGN(operandType(right)))) {
- // just an unsigned 8*8=8/16 multiply
- //emitcode (";","unsigned");
- emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
- MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
- emitcode ("mul", "ab");
-
- _G.accInUse++; _G.bInUse++;
- aopOp(result, ic, TRUE, FALSE);
-
- if (AOP_SIZE(result)<1 || AOP_SIZE(result)>2)
- {
- // this should never happen
- fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
- AOP_SIZE(result), __FILE__, lineno);
- exit (1);
- }
-
- aopPut (AOP (result), "a", 0);
- _G.accInUse--; _G.bInUse--;
- if (AOP_SIZE(result)==2)
+ /* (if two literals: the value is computed before) */
+ /* if one literal, literal on the right */
+ if (AOP_TYPE (left) == AOP_LIT)
{
- aopPut (AOP (result), "b", 1);
+ operand *t = right;
+ right = left;
+ left = t;
+ /* emitcode (";", "swapped left and right"); */
+ }
+ /* if no literal, unsigned on the right: shorter code */
+ if ( AOP_TYPE (right) != AOP_LIT
+ && SPEC_USIGN (getSpec (operandType (left))))
+ {
+ operand *t = right;
+ right = left;
+ left = t;
+ }
+
+ lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+ rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
+ if ((lUnsigned && rUnsigned)
+/* sorry, I don't know how to get size
+ without calling aopOp (result,...);
+ see Feature Request */
+ /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
+ no need to take care about the signedness! */
+ {
+ /* just an unsigned 8 * 8 = 8 multiply
+ or 8u * 8u = 16u */
+ /* emitcode (";","unsigned"); */
+ emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+ emitcode ("mul", "ab");
+
+ _G.accInUse++; _G.bInUse++;
+ aopOp (result, ic, TRUE, FALSE);
+ size = AOP_SIZE (result);
+
+ if (size < 1 || size > 2)
+ {
+ /* this should never happen */
+ fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
+ size, __FILE__, lineno);
+ exit (1);
+ }
+
+ aopPut (AOP (result), "a", 0);
+ _G.accInUse--; _G.bInUse--;
+ if (size == 2)
+ aopPut (AOP (result), "b", 1);
+ return;
}
- return;
- }
- // we have to do a signed multiply
+ /* we have to do a signed multiply */
+ /* emitcode (";", "signed"); */
+
+ /* now sign adjust for both left & right */
- emitcode (";", "signed");
- emitcode ("clr", "F0"); // reset sign flag
- MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+ /* let's see what's needed: */
+ /* apply negative sign during runtime */
+ runtimeSign = FALSE;
+ /* negative sign from literals */
+ compiletimeSign = FALSE;
- lbl=newiTempLabel(NULL);
- emitcode ("jnb", "acc.7,!tlabel", lbl->key+100);
- // left side is negative, 8-bit two's complement, this fails for -128
- emitcode ("setb", "F0"); // set sign flag
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
+ if (!lUnsigned)
+ {
+ if (AOP_TYPE(left) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign = TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
+ }
- emitcode ("", "!tlabeldef", lbl->key+100);
+ if (!rUnsigned)
+ {
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign ^= TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
+ }
- /* if literal */
- if (AOP_TYPE(right)==AOP_LIT) {
- signed char val=(signed char)floatFromVal (AOP (right)->aopu.aop_lit);
- /* AND literal negative */
- if ((int) val < 0) {
- emitcode ("cpl", "F0"); // complement sign flag
- emitcode ("mov", "b,#!constbyte", -val);
- } else {
- emitcode ("mov", "b,#!constbyte", val);
+ /* initialize F0, which stores the runtime sign */
+ if (runtimeSign)
+ {
+ if (compiletimeSign)
+ emitcode ("setb", "F0"); /* set sign flag */
+ else
+ emitcode ("clr", "F0"); /* reset sign flag */
}
- } else {
- lbl=newiTempLabel(NULL);
- emitcode ("mov", "b,a");
- emitcode ("mov", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
- emitcode ("jnb", "acc.7,!tlabel", lbl->key+100);
- // right side is negative, 8-bit two's complement
- emitcode ("cpl", "F0"); // complement sign flag
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
- emitcode ("", "!tlabeldef", lbl->key+100);
- }
+
+ /* save the signs of the operands */
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ if (!rUnsigned && val < 0)
+ emitcode ("mov", "b,#!constbyte", -val);
+ else
+ emitcode ("mov", "b,#!constbyte", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ if (rUnsigned) /* emitcode (";", "signed"); */
+ emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+ else
+ {
+ MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "!tlabeldef", lbl->key + 100);
+ emitcode ("mov", "b,a");
+ }
+ }
+
+ if (AOP_TYPE(left) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+
+ if (!lUnsigned && val < 0)
+ emitcode ("mov", "a,#!constbyte", -val);
+ else
+ emitcode ("mov", "a,#!constbyte", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ if (lUnsigned) /* emitcode (";", "signed"); */
+
+ emitcode ("mov", "a,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+ else
+ {
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "!tlabeldef", lbl->key + 100);
+ }
+ }
+
+ /* now the multiplication */
emitcode ("mul", "ab");
-
_G.accInUse++;_G.bInUse++;
aopOp(result, ic, TRUE, FALSE);
-
- if (AOP_SIZE(result)<1 || AOP_SIZE(result)>2)
- {
- // this should never happen
+ size = AOP_SIZE (result);
+
+ if (size < 1 || size > 2)
+ {
+ /* this should never happen */
fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
- AOP_SIZE(result), __FILE__, lineno);
+ size, __FILE__, lineno);
exit (1);
- }
+ }
- lbl=newiTempLabel(NULL);
- emitcode ("jnb", "F0,!tlabel", lbl->key+100);
- // only ONE op was negative, we have to do a 8/16-bit two's complement
- emitcode ("cpl", "a"); // lsb
- if (AOP_SIZE(result)==1) {
- emitcode ("inc", "a");
- } else {
- emitcode ("add", "a,#1");
- emitcode ("xch", "a,b");
- emitcode ("cpl", "a"); // msb
- emitcode ("addc", "a,#0");
- emitcode ("xch", "a,b");
- }
-
- emitcode ("", "!tlabeldef", lbl->key+100);
+ if (runtimeSign || compiletimeSign)
+ {
+ lbl = newiTempLabel (NULL);
+ if (runtimeSign)
+ emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
+ emitcode ("cpl", "a"); /* lsb 2's complement */
+ if (size != 2)
+ emitcode ("inc", "a"); /* inc doesn't set carry flag */
+ else
+ {
+ emitcode ("add", "a,#1"); /* this sets carry flag */
+ emitcode ("xch", "a,b");
+ emitcode ("cpl", "a"); /* msb 2's complement */
+ emitcode ("addc", "a,#0");
+ emitcode ("xch", "a,b");
+ }
+ emitcode ("", "!tlabeldef", lbl->key + 100);
+ }
aopPut (AOP (result), "a", 0);
_G.accInUse--;_G.bInUse--;
- if (AOP_SIZE(result)==2) {
+ if (size == 2)
aopPut (AOP (result), "b", 1);
- }
}
/*-----------------------------------------------------------------*/
operand * result,
iCode * ic)
{
- sym_link *opetype = operandType (result);
+ bool lUnsigned, rUnsigned;
+ bool runtimeSign, compiletimeSign;
char *l;
symbol *lbl;
int size, offset;
offset = 1;
+ lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+ rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
/* signed or unsigned */
- if (SPEC_USIGN (opetype))
+ if (lUnsigned && rUnsigned)
{
- /* unsigned is easy */
- LOAD_AB_FOR_DIV (left, right, l);
- emitcode ("div", "ab");
+ /* unsigned is easy */
+ LOAD_AB_FOR_DIV (left, right, l);
+ emitcode ("div", "ab");
- _G.accInUse++;
- aopOp(result, ic, TRUE, FALSE);
- aopPut (AOP (result), "a", 0);
- _G.accInUse--;
+ _G.accInUse++;
+ aopOp (result, ic, TRUE, FALSE);
+ aopPut (AOP (result), "a", 0);
+ _G.accInUse--;
- size = AOP_SIZE (result) - 1;
-
- while (size--)
- {
- aopPut (AOP (result), zero, offset++);
- }
+ size = AOP_SIZE (result) - 1;
+
+ while (size--)
+ aopPut (AOP (result), zero, offset++);
return;
}
/* signed is a little bit more difficult */
- /* save the signs of the operands */
- MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
- emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, TRUE, FALSE));
- emitcode ("push", "acc"); /* save it on the stack */
-
/* now sign adjust for both left & right */
- MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
- lbl = newiTempLabel (NULL);
- emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
- emitcode ("", "!tlabeldef", (lbl->key + 100));
- emitcode ("mov", "b,a");
- /* sign adjust left side */
- MOVA( aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+ /* let's see what's needed: */
+ /* apply negative sign during runtime */
+ runtimeSign = FALSE;
+ /* negative sign from literals */
+ compiletimeSign = FALSE;
- lbl = newiTempLabel (NULL);
- emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
- emitcode ("", "!tlabeldef", (lbl->key + 100));
+ if (!lUnsigned)
+ {
+ if (AOP_TYPE(left) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign = TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
+ }
+ if (!rUnsigned)
+ {
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign ^= TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
+ }
+
+ /* initialize F0, which stores the runtime sign */
+ if (runtimeSign)
+ {
+ if (compiletimeSign)
+ emitcode ("setb", "F0"); /* set sign flag */
+ else
+ emitcode ("clr", "F0"); /* reset sign flag */
+ }
+
+ /* save the signs of the operands */
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ if (!rUnsigned && val < 0)
+ emitcode ("mov", "b,#0x%02x", -val);
+ else
+ emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ if (rUnsigned)
+ emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+ else
+ {
+ MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "!tlabeldef", lbl->key + 100);
+ emitcode ("mov", "b,a");
+ }
+ }
+
+ if (AOP_TYPE(left) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+
+ if (!lUnsigned && val < 0)
+ emitcode ("mov", "a,#0x%02x", -val);
+ else
+ emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ if (lUnsigned)
+ emitcode ("mov", "a,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+ else
+ {
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "!tlabeldef", lbl->key + 100);
+ }
+ }
+
/* now the division */
emitcode ("nop", "; workaround for DS80C390 div bug.");
emitcode ("div", "ab");
- /* we are interested in the lower order
- only */
- emitcode ("mov", "b,a");
- lbl = newiTempLabel (NULL);
- emitcode ("pop", "acc");
- /* if there was an over flow we don't
- adjust the sign of the result */
- emitcode ("jb", "ov,!tlabel", (lbl->key + 100));
- emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
- CLRC;
- emitcode ("clr", "a");
- emitcode ("subb", "a,b");
- emitcode ("mov", "b,a");
- emitcode ("", "!tlabeldef", (lbl->key + 100));
-
- /* now we are done */
- _G.accInUse++; _G.bInUse++;
- aopOp(result, ic, TRUE, FALSE);
-
- aopPut (AOP (result), "b", 0);
-
- size = AOP_SIZE (result) - 1;
-
- if (size > 0)
+
+ if (runtimeSign || compiletimeSign)
{
- emitcode ("mov", "c,b.7");
- emitcode ("subb", "a,acc");
+ lbl = newiTempLabel (NULL);
+ if (runtimeSign)
+ emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
+ emitcode ("cpl", "a"); /* lsb 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "!tlabeldef", lbl->key + 100);
+
+ _G.accInUse++; _G.bInUse++;
+ aopOp (result, ic, TRUE, FALSE);
+ size = AOP_SIZE (result) - 1;
+
+ if (size > 0)
+ {
+ /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
+ then the result will be in b, a */
+ emitcode ("mov", "b,a"); /* 1 */
+ /* msb is 0x00 or 0xff depending on the sign */
+ if (runtimeSign)
+ {
+ emitcode ("mov", "c,F0");
+ emitcode ("subb", "a,acc");
+ emitcode ("xch", "a,b"); /* 2 */
+ while (size--)
+ aopPut (AOP (result), "b", offset++); /* write msb's */
+ }
+ else /* compiletimeSign */
+ while (size--)
+ aopPut (AOP (result), "#0xff", offset++); /* write msb's */
+ }
+ aopPut (AOP (result), "a", 0); /* 3: write lsb */
}
- while (size--)
+ else
{
- aopPut (AOP (result), "a", offset++);
+ _G.accInUse++; _G.bInUse++;
+ aopOp(result, ic, TRUE, FALSE);
+ size = AOP_SIZE (result) - 1;
+
+ aopPut (AOP (result), "a", 0);
+ while (size--)
+ aopPut (AOP (result), zero, offset++);
}
- _G.accInUse--; _G.bInUse--;
+ _G.accInUse--; _G.bInUse--;
}
operand * result,
iCode * ic)
{
- sym_link *opetype = operandType (result);
+ bool lUnsigned, rUnsigned;
+ bool runtimeSign, compiletimeSign;
char *l;
symbol *lbl;
+ int size, offset;
+ offset = 1;
+ lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+ rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
/* signed or unsigned */
- if (SPEC_USIGN (opetype))
+ if (lUnsigned && rUnsigned)
{
/* unsigned is easy */
LOAD_AB_FOR_DIV (left, right, l);
emitcode ("div", "ab");
- aopOp(result, ic, TRUE, FALSE);
+ aopOp (result, ic, TRUE, FALSE);
aopPut (AOP (result), "b", 0);
+
+ for (size = AOP_SIZE (result) - 1; size--;)
+ aopPut (AOP (result), zero, offset++);
return;
}
/* signed is a little bit more difficult */
- /* save the signs of the operands */
- MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
-
- emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
- emitcode ("push", "acc"); /* save it on the stack */
-
/* now sign adjust for both left & right */
- MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
- lbl = newiTempLabel (NULL);
- emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
- emitcode ("", "!tlabeldef", (lbl->key + 100));
- emitcode ("mov", "b,a");
+ /* modulus: sign of the right operand has no influence on the result! */
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
- /* sign adjust left side */
- MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+ if (!rUnsigned && val < 0)
+ emitcode ("mov", "b,#0x%02x", -val);
+ else
+ emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ if (rUnsigned)
+ emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+ else
+ {
+ MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "!tlabeldef", lbl->key + 100);
+ emitcode ("mov", "b,a");
+ }
+ }
+
+ /* let's see what's needed: */
+ /* apply negative sign during runtime */
+ runtimeSign = FALSE;
+ /* negative sign from literals */
+ compiletimeSign = FALSE;
- lbl = newiTempLabel (NULL);
- emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
- emitcode ("", "!tlabeldef", (lbl->key + 100));
+ /* sign adjust left side */
+ if (AOP_TYPE(left) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
- /* now the multiplication */
+ if (!lUnsigned && val < 0)
+ {
+ compiletimeSign = TRUE; /* set sign flag */
+ emitcode ("mov", "a,#0x%02x", -val);
+ }
+ else
+ emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+
+ if (!lUnsigned)
+ {
+ runtimeSign = TRUE;
+ emitcode ("clr", "F0"); /* clear sign flag */
+
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+ emitcode ("setb", "F0"); /* set sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "!tlabeldef", lbl->key + 100);
+ }
+ }
+
+ /* now the modulus */
emitcode ("nop", "; workaround for DS80C390 div bug.");
emitcode ("div", "ab");
- /* we are interested in the lower order
- only */
- lbl = newiTempLabel (NULL);
- emitcode ("pop", "acc");
- /* if there was an over flow we don't
- adjust the sign of the result */
- emitcode ("jb", "ov,!tlabel", (lbl->key + 100));
- emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
- CLRC;
- emitcode ("clr", "a");
- emitcode ("subb", "a,b");
- emitcode ("mov", "b,a");
- emitcode ("", "!tlabeldef", (lbl->key + 100));
- _G.bInUse++;
- /* now we are done */
- aopOp(result, ic, TRUE, FALSE);
- aopPut (AOP (result), "b", 0);
- _G.bInUse--;
+ if (runtimeSign || compiletimeSign)
+ {
+ emitcode ("mov", "a,b");
+ lbl = newiTempLabel (NULL);
+ if (runtimeSign)
+ emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
+ emitcode ("cpl", "a"); /* lsb 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "!tlabeldef", lbl->key + 100);
+
+ _G.accInUse++; _G.bInUse++;
+ aopOp (result, ic, TRUE, FALSE);
+ size = AOP_SIZE (result) - 1;
+
+ if (size > 0)
+ {
+ /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
+ then the result will be in b, a */
+ emitcode ("mov", "b,a"); /* 1 */
+ /* msb is 0x00 or 0xff depending on the sign */
+ if (runtimeSign)
+ {
+ emitcode ("mov", "c,F0");
+ emitcode ("subb", "a,acc");
+ emitcode ("xch", "a,b"); /* 2 */
+ while (size--)
+ aopPut (AOP (result), "b", offset++); /* write msb's */
+ }
+ else /* compiletimeSign */
+ while (size--)
+ aopPut (AOP (result), "#0xff", offset++); /* write msb's */
+ }
+ aopPut (AOP (result), "a", 0); /* 3: write lsb */
+ }
+ else
+ {
+ _G.accInUse++; _G.bInUse++;
+ aopOp(result, ic, TRUE, FALSE);
+ size = AOP_SIZE (result) - 1;
+
+ aopPut (AOP (result), "b", 0);
+ while (size--)
+ aopPut (AOP (result), zero, offset++);
+ }
+ _G.accInUse--; _G.bInUse--;
}
//emitcode (";", "swapped left and right");
}
- if (SPEC_USIGN(opetype)
+ if (size == 1
|| (SPEC_USIGN(operandType(left)) &&
SPEC_USIGN(operandType(right))))
{
bitVect * freeRegs;
int i;
int offset;
-
+
if (!ic)
ic = _G.current_iCode;
if (!ic)
return 0;
if (!_G.currentFunc)
return 0;
-
+
freeRegs = newBitVect(8);
bitVectSetBit (freeRegs, R2_IDX);
bitVectSetBit (freeRegs, R3_IDX);
bitVectSetBit (freeRegs, R5_IDX);
bitVectSetBit (freeRegs, R6_IDX);
bitVectSetBit (freeRegs, R7_IDX);
-
+
if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
{
bitVect * newfreeRegs;
freeRegs = newfreeRegs;
}
freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
-
- offset = 0;
+
+ offset = 0;
for (i=0; i<freeRegs->size; i++)
{
if (bitVectBitValue(freeRegs,i))
int size;
int accuseSize = 0;
int accuse = 0;
-
+
if (!ic)
{
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
accuseSize = size;
}
}
-
+
if (accuseSize)
return accuseSize;
else
aop->size = getSize (sym->type);
return;
}
-
+
/* else must be a dummy iTemp */
sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
aop->size = getSize (sym->type);
{
case AOP_DUMMY:
return zero;
-
+
case AOP_R0:
case AOP_R1:
/* if we need to increment it */
case AOP_DUMMY:
MOVA (s); /* read s in case it was volatile */
break;
-
+
case AOP_DIR:
if (offset)
sprintf (d, "(%s + %d)",
(IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
return;
-
+
/* safe the registers in use at this time but skip the
ones for the result */
- rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
+ rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
mcs51_rUmaskForOp (IC_RESULT(ic)));
ic->regsSaved = 1;
/* restore the registers in use at this time but skip the
ones for the result */
- rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
+ rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
mcs51_rUmaskForOp (IC_RESULT(ic)));
if (options.useXstack)
if (!ic)
{
/* Assume r0 is available for use. */
- r = mcs51_regWithIdx (R0_IDX);;
- }
+ r = mcs51_regWithIdx (R0_IDX);;
+ }
else
{
aop = newAsmop (0);
r = getFreePtr (ic, &aop, FALSE);
}
- emitcode ("mov", "%s,_spx", r->name);
+ emitcode ("mov", "%s,_spx", r->name);
}
-
+
if (popPsw)
{
if (options.useXstack)
{
emitcode ("mov", "_spx,%s", r->name);
}
-
+
if (aop)
{
- freeAsmop (NULL, aop, ic, TRUE);
- }
+ freeAsmop (NULL, aop, ic, TRUE);
+ }
}
/*-----------------------------------------------------------------*/
}
if (ic)
- {
+ {
ic->bankSaved = 1;
}
}
emitcode ("mov","b1_%d,%s",rb1_count++,
aopGet (AOP (IC_LEFT (sic)), offset++,FALSE, FALSE));
}
- }
+ }
freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
}
}
if (swapBanks)
{
- emitcode ("mov", "psw,#0x%02x",
+ emitcode ("mov", "psw,#0x%02x",
((FUNC_REGBANK(dtype)) << 3) & 0xff);
}
if (swapBanks)
{
- emitcode ("mov", "psw,#0x%02x",
+ emitcode ("mov", "psw,#0x%02x",
((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
}
}
else
{
-
+
/* this function has a function call cannot
determines register usage so we will have to push the
entire bank */
* other bank, we must save that bank entirely.
*/
unsigned long banksToSave = 0;
-
+
if (IFFUNC_HASFCALL(sym->type))
{
/* we got to the end OK. */
break;
}
-
+
if (i->op == CALL)
{
sym_link *dtype;
-
+
dtype = operandType (IC_LEFT(i));
if (dtype
&& FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
{
banksToSave |= (1 << FUNC_REGBANK(dtype));
}
-
- /* And note that we don't need to do it in
+
+ /* And note that we don't need to do it in
* genCall.
*/
i->bankSaved = 1;
* The only thing I can think of to do is
* throw a warning and hope.
*/
- werror(W_FUNCPTR_IN_USING_ISR);
+ werror(W_FUNCPTR_IN_USING_ISR);
}
}
if (banksToSave && options.useXstack)
{
- /* Since we aren't passing it an ic,
+ /* Since we aren't passing it an ic,
* saveRBank will assume r0 is available to abuse.
*
* So switch to our (trashable) bank now, so
* the caller's R0 isn't trashed.
*/
emitcode ("push", "psw");
- emitcode ("mov", "psw,#0x%02x",
+ emitcode ("mov", "psw,#0x%02x",
(FUNC_REGBANK (sym->type) << 3) & 0x00ff);
switchedPSW = TRUE;
}
-
+
for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
{
if (banksToSave & (1 << ix))
emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff));
emitcode ("mov", "_spx,a");
}
-
+
/* if critical function then turn interrupts off */
if (IFFUNC_ISCRITICAL (ftype))
{
emitcode(";", "naked function: no epilogue.");
return;
}
-
+
if (IFFUNC_ISCRITICAL (sym->type))
{
emitcode ("pop", "psw"); /* restore ea via c in psw */
{
if (options.parms_in_bank1) {
int i;
- for (i = 7 ; i >= 0 ; i-- ) {
+ for (i = 7 ; i >= 0 ; i-- ) {
emitcode ("pop","%s",rb1regs[i]);
}
}
*/
unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
int ix;
-
+
for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
{
if (savedBanks & (1 << ix))
unsaveRBank(ix, NULL, FALSE);
}
}
-
+
if (options.useXstack)
{
/* Restore bank AFTER calling unsaveRBank,
count++;
/* If we have any pushes or pops, we cannot predict the distance.
- I don't like this at all, this should be dealt with in the
+ I don't like this at all, this should be dealt with in the
back-end */
if (ic->op == IPUSH || ic->op == IPOP) {
return 0;
/* if increment >=16 bits in register or direct space */
if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
- sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
+ sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
(size > 1) &&
(icount == 1))
{
}
else
{
- if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
+ if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
isOperandVolatile (IC_RESULT (ic), FALSE))
{
/* just move */
aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
}
}
-
-
+
+
adjustArithmeticResult (ic);
release:
outBitC (result);
}
-
/*-----------------------------------------------------------------*/
/* genMultOneByte : 8*8=8/16 bit multiplication */
/*-----------------------------------------------------------------*/
operand * right,
operand * result)
{
- sym_link *opetype = operandType (result);
symbol *lbl;
- int size=AOP_SIZE(result);
+ int size = AOP_SIZE (result);
+ bool runtimeSign, compiletimeSign;
+ bool lUnsigned, rUnsigned;
D(emitcode ("; genMultOneByte",""));
- if (size<1 || size>2) {
- // this should never happen
+ if (size < 1 || size > 2)
+ {
+ /* this should never happen */
fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
AOP_SIZE(result), __FILE__, lineno);
exit (1);
- }
+ }
/* (if two literals: the value is computed before) */
/* if one literal, literal on the right */
operand *t = right;
right = left;
left = t;
- //emitcode (";", "swapped left and right");
+ /* emitcode (";", "swapped left and right"); */
+ }
+ /* if no literal, unsigned on the right: shorter code */
+ if ( AOP_TYPE (right) != AOP_LIT
+ && SPEC_USIGN (getSpec (operandType (left))))
+ {
+ operand *t = right;
+ right = left;
+ left = t;
}
- if (SPEC_USIGN(opetype)
- // ignore the sign of left and right, what else can we do?
- || (SPEC_USIGN(operandType(left)) &&
- SPEC_USIGN(operandType(right)))) {
- // just an unsigned 8*8=8/16 multiply
- //emitcode (";","unsigned");
- // TODO: check for accumulator clash between left & right aops?
-
- if( AOP_TYPE(right)==AOP_LIT ){
- // moving to accumulator first helps peepholes
- MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
- emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
- } else {
- emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
- MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+ lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+ rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
+ if (size == 1 /* no, this is not a bug; with a 1 byte result there's
+ no need to take care about the signedness! */
+ || (lUnsigned && rUnsigned))
+ {
+ /* just an unsigned 8 * 8 = 8 multiply
+ or 8u * 8u = 16u */
+ /* emitcode (";","unsigned"); */
+ /* TODO: check for accumulator clash between left & right aops? */
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* moving to accumulator first helps peepholes */
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+ emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+ }
+ else
+ {
+ emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+ }
+
+ emitcode ("mul", "ab");
+ aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
+ if (size == 2)
+ aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
+ return;
+ }
+
+ /* we have to do a signed multiply */
+ /* emitcode (";", "signed"); */
+
+ /* now sign adjust for both left & right */
+
+ /* let's see what's needed: */
+ /* apply negative sign during runtime */
+ runtimeSign = FALSE;
+ /* negative sign from literals */
+ compiletimeSign = FALSE;
+
+ if (!lUnsigned)
+ {
+ if (AOP_TYPE(left) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign = TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
}
-
- emitcode ("mul", "ab");
- aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
- if (size==2) {
- aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
+
+ if (!rUnsigned)
+ {
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign ^= TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
}
- return;
- }
- // we have to do a signed multiply
+ /* initialize F0, which stores the runtime sign */
+ if (runtimeSign)
+ {
+ if (compiletimeSign)
+ emitcode ("setb", "F0"); /* set sign flag */
+ else
+ emitcode ("clr", "F0"); /* reset sign flag */
+ }
- //emitcode (";", "signed");
- emitcode ("clr", "F0"); // reset sign flag
- MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+ /* save the signs of the operands */
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
- lbl=newiTempLabel(NULL);
- emitcode ("jnb", "acc.7,%05d$", lbl->key+100);
- // left side is negative, 8-bit two's complement, this fails for -128
- emitcode ("setb", "F0"); // set sign flag
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
+ if (!rUnsigned && val < 0)
+ emitcode ("mov", "b,#0x%02x", -val);
+ else
+ emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ if (rUnsigned) /* emitcode (";", "signed"); */
+
+ emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+ else
+ {
+ MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "%05d$:", (lbl->key + 100));
+ emitcode ("mov", "b,a");
+ }
+ }
- emitcode ("", "%05d$:", lbl->key+100);
+ if (AOP_TYPE(left) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
- /* if literal */
- if (AOP_TYPE(right)==AOP_LIT) {
- signed char val=(signed char)floatFromVal (AOP (right)->aopu.aop_lit);
- /* AND literal negative */
- if (val < 0) {
- emitcode ("cpl", "F0"); // complement sign flag
- emitcode ("mov", "b,#0x%02x", -val);
- } else {
- emitcode ("mov", "b,#0x%02x", val);
+ if (!lUnsigned && val < 0)
+ emitcode ("mov", "a,#0x%02x", -val);
+ else
+ emitcode ("mov", "a,#0x%02x", (unsigned char) val);
}
- } else {
- lbl=newiTempLabel(NULL);
- emitcode ("mov", "b,a");
- emitcode ("mov", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE));
- emitcode ("jnb", "acc.7,%05d$", lbl->key+100);
- // right side is negative, 8-bit two's complement
- emitcode ("cpl", "F0"); // complement sign flag
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
- emitcode ("", "%05d$:", lbl->key+100);
- }
- emitcode ("mul", "ab");
+ else /* ! literal */
+ {
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
- lbl=newiTempLabel(NULL);
- emitcode ("jnb", "F0,%05d$", lbl->key+100);
- // only ONE op was negative, we have to do a 8/16-bit two's complement
- emitcode ("cpl", "a"); // lsb
- if (size==1) {
- emitcode ("inc", "a");
- } else {
- emitcode ("add", "a,#1");
- emitcode ("xch", "a,b");
- emitcode ("cpl", "a"); // msb
- emitcode ("addc", "a,#0");
- emitcode ("xch", "a,b");
- }
+ if (!lUnsigned)
+ {
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "%05d$:", (lbl->key + 100));
+ }
+ }
- emitcode ("", "%05d$:", lbl->key+100);
+ /* now the multiplication */
+ emitcode ("mul", "ab");
+ if (runtimeSign || compiletimeSign)
+ {
+ lbl = newiTempLabel (NULL);
+ if (runtimeSign)
+ emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
+ emitcode ("cpl", "a"); /* lsb 2's complement */
+ if (size != 2)
+ emitcode ("inc", "a"); /* inc doesn't set carry flag */
+ else
+ {
+ emitcode ("add", "a,#1"); /* this sets carry flag */
+ emitcode ("xch", "a,b");
+ emitcode ("cpl", "a"); /* msb 2's complement */
+ emitcode ("addc", "a,#0");
+ emitcode ("xch", "a,b");
+ }
+ emitcode ("", "%05d$:", (lbl->key + 100));
+ }
aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
- if (size==2) {
+ if (size == 2)
aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
- }
}
/*-----------------------------------------------------------------*/
operand * right,
operand * result)
{
- sym_link *opetype = operandType (result);
- char *l;
+ bool lUnsigned, rUnsigned;
+ bool runtimeSign, compiletimeSign;
symbol *lbl;
int size, offset;
D(emitcode ("; genDivOneByte",""));
+ /* Why is it necessary that genDivOneByte() can return an int result?
+ Have a look at:
+
+ volatile unsigned char uc;
+ volatile signed char sc1, sc2;
+ volatile int i;
+
+ uc = 255;
+ sc1 = -1;
+ i = uc / sc1;
+
+ Or:
+
+ sc1 = -128;
+ sc2 = -1;
+ i = sc1 / sc2;
+
+ In all cases a one byte result would overflow, the following cast to int
+ would return the wrong result.
+
+ Two possible solution:
+ a) cast operands to int, if ((unsigned) / (signed)) or
+ ((signed) / (signed))
+ b) return an 16 bit signed int; this is what we're doing here!
+ */
+
size = AOP_SIZE (result) - 1;
offset = 1;
+ lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+ rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
/* signed or unsigned */
- if (SPEC_USIGN (opetype))
+ if (lUnsigned && rUnsigned)
{
/* unsigned is easy */
emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
- l = aopGet (AOP (left), 0, FALSE, FALSE);
- MOVA (l);
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
emitcode ("div", "ab");
aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
while (size--)
aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
return;
}
-
+
/* signed is a little bit more difficult */
+ /* now sign adjust for both left & right */
+
+ /* let's see what's needed: */
+ /* apply negative sign during runtime */
+ runtimeSign = FALSE;
+ /* negative sign from literals */
+ compiletimeSign = FALSE;
+
+ if (!lUnsigned)
+ {
+ if (AOP_TYPE(left) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign = TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
+ }
+
+ if (!rUnsigned)
+ {
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign ^= TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
+ }
+
+ /* initialize F0, which stores the runtime sign */
+ if (runtimeSign)
+ {
+ if (compiletimeSign)
+ emitcode ("setb", "F0"); /* set sign flag */
+ else
+ emitcode ("clr", "F0"); /* reset sign flag */
+ }
+
/* save the signs of the operands */
- l = aopGet (AOP (left), 0, FALSE, FALSE);
- MOVA (l);
- emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, TRUE));
- emitcode ("push", "acc"); /* save it on the stack */
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
- /* now sign adjust for both left & right */
- l = aopGet (AOP (right), 0, FALSE, FALSE);
- MOVA (l);
- lbl = newiTempLabel (NULL);
- emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
- emitcode ("", "%05d$:", (lbl->key + 100));
- emitcode ("mov", "b,a");
+ if (!rUnsigned && val < 0)
+ emitcode ("mov", "b,#0x%02x", -val);
+ else
+ emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ if (rUnsigned)
+ emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+ else
+ {
+ MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "%05d$:", (lbl->key + 100));
+ emitcode ("mov", "b,a");
+ }
+ }
- /* sign adjust left side */
- l = aopGet (AOP (left), 0, FALSE, FALSE);
- MOVA (l);
+ if (AOP_TYPE(left) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
- lbl = newiTempLabel (NULL);
- emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
- emitcode ("", "%05d$:", (lbl->key + 100));
+ if (!lUnsigned && val < 0)
+ emitcode ("mov", "a,#0x%02x", -val);
+ else
+ emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+
+ if (!lUnsigned)
+ {
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "%05d$:", (lbl->key + 100));
+ }
+ }
/* now the division */
emitcode ("div", "ab");
- /* we are interested in the lower order
- only */
- emitcode ("mov", "b,a");
- lbl = newiTempLabel (NULL);
- emitcode ("pop", "acc");
- /* if there was an over flow we don't
- adjust the sign of the result */
- emitcode ("jb", "ov,%05d$", (lbl->key + 100));
- emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
- CLRC;
- emitcode ("clr", "a");
- emitcode ("subb", "a,b");
- emitcode ("mov", "b,a");
- emitcode ("", "%05d$:", (lbl->key + 100));
- /* now we are done */
- aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
- if (size > 0)
+ if (runtimeSign || compiletimeSign)
{
- emitcode ("mov", "c,b.7");
- emitcode ("subb", "a,acc");
- }
- while (size--)
- aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
+ lbl = newiTempLabel (NULL);
+ if (runtimeSign)
+ emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
+ emitcode ("cpl", "a"); /* lsb 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "%05d$:", (lbl->key + 100));
+ aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
+ if (size > 0)
+ {
+ /* msb is 0x00 or 0xff depending on the sign */
+ if (runtimeSign)
+ {
+ emitcode ("mov", "c,F0");
+ emitcode ("subb", "a,acc");
+ while (size--)
+ aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
+ }
+ else /* compiletimeSign */
+ while (size--)
+ aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
+ }
+ }
+ else
+ {
+ aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
+ while (size--)
+ aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
+ }
}
/*-----------------------------------------------------------------*/
operand * right,
operand * result)
{
- sym_link *opetype = operandType (result);
- char *l;
+ bool lUnsigned, rUnsigned;
+ bool runtimeSign, compiletimeSign;
symbol *lbl;
+ int size, offset;
D(emitcode ("; genModOneByte",""));
+ size = AOP_SIZE (result) - 1;
+ offset = 1;
+ lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+ rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
/* signed or unsigned */
- if (SPEC_USIGN (opetype))
+ if (lUnsigned && rUnsigned)
{
/* unsigned is easy */
emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
- l = aopGet (AOP (left), 0, FALSE, FALSE);
- MOVA (l);
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
emitcode ("div", "ab");
aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
+ while (size--)
+ aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
return;
}
/* signed is a little bit more difficult */
- /* save the signs of the operands */
- l = aopGet (AOP (left), 0, FALSE, FALSE);
- MOVA (l);
-
- emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE));
- emitcode ("push", "acc"); /* save it on the stack */
-
/* now sign adjust for both left & right */
- l = aopGet (AOP (right), 0, FALSE, FALSE);
- MOVA (l);
- lbl = newiTempLabel (NULL);
- emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
- emitcode ("", "%05d$:", (lbl->key + 100));
- emitcode ("mov", "b,a");
+ /* modulus: sign of the right operand has no influence on the result! */
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
- /* sign adjust left side */
- l = aopGet (AOP (left), 0, FALSE, FALSE);
- MOVA (l);
+ if (!rUnsigned && val < 0)
+ emitcode ("mov", "b,#0x%02x", -val);
+ else
+ emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+ }
+ else /* not literal */
+ {
+ if (rUnsigned)
+ emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+ else
+ {
+ MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "%05d$:", (lbl->key + 100));
+ emitcode ("mov", "b,a");
+ }
+ }
- lbl = newiTempLabel (NULL);
- emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
- emitcode ("cpl", "a");
- emitcode ("inc", "a");
- emitcode ("", "%05d$:", (lbl->key + 100));
+ /* let's see what's needed: */
+ /* apply negative sign during runtime */
+ runtimeSign = FALSE;
+ /* negative sign from literals */
+ compiletimeSign = FALSE;
+
+ /* sign adjust left side */
+ if (AOP_TYPE(left) == AOP_LIT)
+ {
+ signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
- /* now the multiplication */
- emitcode ("div", "ab");
- /* we are interested in the lower order
- only */
- lbl = newiTempLabel (NULL);
- emitcode ("pop", "acc");
- /* if there was an over flow we don't
- adjust the sign of the result */
- emitcode ("jb", "ov,%05d$", (lbl->key + 100));
- emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
- CLRC;
- emitcode ("clr", "a");
- emitcode ("subb", "a,b");
- emitcode ("mov", "b,a");
- emitcode ("", "%05d$:", (lbl->key + 100));
+ if (!lUnsigned && val < 0)
+ {
+ compiletimeSign = TRUE; /* set sign flag */
+ emitcode ("mov", "a,#0x%02x", -val);
+ }
+ else
+ emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
- /* now we are done */
- aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
+ if (!lUnsigned)
+ {
+ runtimeSign = TRUE;
+ emitcode ("clr", "F0"); /* clear sign flag */
+
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+ emitcode ("setb", "F0"); /* set sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "%05d$:", (lbl->key + 100));
+ }
+ }
+ /* now the modulus */
+ emitcode ("div", "ab");
+
+ if (runtimeSign || compiletimeSign)
+ {
+ emitcode ("mov", "a,b");
+ lbl = newiTempLabel (NULL);
+ if (runtimeSign)
+ emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitcode ("", "%05d$:", (lbl->key + 100));
+
+ aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
+ if (size > 0)
+ {
+ /* msb is 0x00 or 0xff depending on the sign */
+ if (runtimeSign)
+ {
+ emitcode ("mov", "c,F0");
+ emitcode ("subb", "a,acc");
+ while (size--)
+ aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
+ }
+ else /* compiletimeSign */
+ while (size--)
+ aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
+ }
+ }
+ else
+ {
+ aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
+ while (size--)
+ aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
+ }
}
/*-----------------------------------------------------------------*/
right = left;
left = t;
}
-
+
if (AOP_TYPE (right) == AOP_LIT)
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
sym_link *retype = getSpec (type);
iCode *lic = ic->next;
int isize ;
-
+
/* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
if (!IS_SYMOP(op)) return NULL;
while (lic) {
/* if operand of the form op = op + <sizeof *op> */
if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
- isOperandEqual(IC_RESULT(lic),op) &&
+ isOperandEqual(IC_RESULT(lic),op) &&
isOperandLiteral(IC_RIGHT(lic)) &&
operandLitValue(IC_RIGHT(lic)) == isize) {
return lic;
result = IC_RESULT (ic);
aopOp (left, ic, FALSE);
aopOp (result, ic, FALSE);
-
+
switch (AOP_SIZE (left))
{
case 1: /* swap nibbles in byte */
default:
wassertl(FALSE, "unsupported SWAP operand size");
}
-
+
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
-
+
/*-----------------------------------------------------------------*/
/* AccRol - rotate left accumulator by known count */
/*-----------------------------------------------------------------*/
AccAXRrl1 (x); // BCCCCCCD:D000000B
AccAXRrl1 (x); // BBCCCCCC:DD000000
#else
- emitcode("rrc","a");
- emitcode("xch","a,%s", x);
- emitcode("rrc","a");
- emitcode("mov","c,acc.0"); //<< get correct bit
- emitcode("xch","a,%s", x);
-
- emitcode("rrc","a");
- emitcode("xch","a,%s", x);
- emitcode("rrc","a");
- emitcode("xch","a,%s", x);
+ emitcode("rrc","a");
+ emitcode("xch","a,%s", x);
+ emitcode("rrc","a");
+ emitcode("mov","c,acc.0"); //<< get correct bit
+ emitcode("xch","a,%s", x);
+
+ emitcode("rrc","a");
+ emitcode("xch","a,%s", x);
+ emitcode("rrc","a");
+ emitcode("xch","a,%s", x);
#endif
break;
case 7: // a:x <<= 7
}
MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
-
+
if (offl==MSB16) {
// shift is > 8
if (sign) {
emitcode ("mov", "b,a");
emitcode ("movx", "a,@%s", rname);
break;
-
+
case FPOINTER:
if (preserveAinB)
emitcode ("mov", "b,a");
MOVA (src);
emitcode ("movx", "@%s,a", rname);
break;
-
+
case FPOINTER:
MOVA (src);
emitcode ("movx", "@dptr,a");
emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
if (loadBToo)
{
- if (AOP(op)->aopu.aop_immd.from_cast_remat)
+ if (AOP(op)->aopu.aop_immd.from_cast_remat)
emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
else
{
aopOp (left, ic, FALSE);
loadDptrFromOperand (left, FALSE);
-
+
/* so dptr now contains the address */
aopOp (result, ic, FALSE);
emitcode ("inc", "dptr");
}
}
-
+
if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
aopOp (left, ic, FALSE);
loadDptrFromOperand (left, FALSE);
-
+
/* so dptr now contains the address */
aopOp (result, ic, FALSE);
emitcode ("inc", "dptr");
}
else
- {
+ {
emitcode ("mov", "a,#0x%02x", offset);
emitcode ("movc", "a,@a+dptr");
aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
aopOp (left, ic, FALSE);
loadDptrFromOperand (left, TRUE);
-
+
/* so dptr know contains the address */
aopOp (result, ic, FALSE);
/* all except the partial byte at the end */
for (rlen=blen;rlen>=8;rlen-=8)
{
- emitPtrByteSet (rname, p_type,
+ emitPtrByteSet (rname, p_type,
aopGet (AOP (right), offset++, FALSE, TRUE) );
if (rlen>8)
emitcode ("inc", "%s", rname);
if (rlen)
{
mask = (((unsigned char) -1 << rlen) & 0xff);
-
+
if (AOP_TYPE (right) == AOP_LIT)
{
/* Case with partial byte and literal source
aopOp (result, ic, FALSE);
loadDptrFromOperand (result, FALSE);
-
+
/* so dptr know contains the address */
aopOp (right, ic, FALSE);
aopOp (result, ic, FALSE);
loadDptrFromOperand (result, TRUE);
-
+
/* so dptr know contains the address */
aopOp (right, ic, FALSE);
break;
default:
- werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"genPointerSet: illegal pointer type");
}
{
int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
char gpValStr[10];
-
+
if (gpVal == -1)
{
// pointerTypeToGPByte will have bitched.
exit(1);
}
-
+
sprintf(gpValStr, "#0x%d", gpVal);
aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
- }
+ }
goto release;
}
* it back after the decrement.
*/
char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
-
+
if (strcmp(rByte, "a"))
{
/* Something is hopelessly wrong */
regs *tempRegs[4];
int receivingA = 0;
int roffset = 0;
-
+
for (offset = 0; offset<size; offset++)
if (!strcmp (fReturn[offset], "a"))
receivingA = 1;
-
+
if (!receivingA)
{
if (size==1 || getTempRegs(tempRegs, size-1, ic))
}
}
-release:
+release:
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
symbol *tlbl = newiTempLabel (NULL);
D(emitcode("; genCritical",""));
-
+
if (IC_RESULT (ic))
aopOp (IC_RESULT (ic), ic, TRUE);
genEndCritical (iCode *ic)
{
D(emitcode("; genEndCritical",""));
-
+
if (IC_RIGHT (ic))
{
aopOp (IC_RIGHT (ic), ic, FALSE);
for (ic = lic; ic; ic = ic->next)
{
_G.current_iCode = ic;
-
+
if (ic->lineno && cln != ic->lineno)
{
if (options.debug)
_G.debugLine = 0;
}
if (!options.noCcodeInAsm) {
- emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
+ emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
printCLine(ic->filename, ic->lineno));
}
cln = ic->lineno;
for (i=0; i<8; i++) {
sprintf (®sInUse[i],
- "%c", ic->riu & (1<<i) ? i+'0' : '-');
+ "%c", ic->riu & (1<<i) ? i+'0' : '-');
}
regsInUse[i]=0;
emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
--- /dev/null
+/** test one byte mul/div/mod operations.
+
+ attrL: volatile,
+ attrR: volatile,
+*/
+#include <testfwk.h>
+
+void
+testMul(void)
+{
+ {attrL} char cL;
+ {attrL} unsigned char ucL;
+ {attrR} char cR;
+ {attrR} unsigned char ucR;
+ volatile char r8 , r8b;
+ volatile unsigned char ur8, ur8b;
+ volatile short r16, r16b;
+
+ cL = -127; cR = -5; r16 = cL * cR; r16b = cR * cL; ASSERT(r16 == 635); ASSERT(r16b == 635);
+ cL = 127; cR = -5; r16 = cL * cR; r16b = cR * cL; ASSERT(r16 == -635); ASSERT(r16b == -635);
+ cL = -127; cR = 5; r16 = cL * cR; r16b = cR * cL; ASSERT(r16 == -635); ASSERT(r16b == -635);
+ cL = 127; cR = 5; r16 = cL * cR; r16b = cR * cL; ASSERT(r16 == 635); ASSERT(r16b == 635);
+
+ cL = -128; cR = -1; ur8 = cL * cR; ur8b = cR * cL; ASSERT(ur8 == 128); ASSERT(ur8b == 128);
+ cL = 128; cR = -1; r8 = cL * cR; r8b = cR * cL; ASSERT( r8 == -128); ASSERT( r8b == -128);
+ cL = -128; cR = 1; r8 = cL * cR; r8b = cR * cL; ASSERT( r8 == -128); ASSERT( r8b == -128);
+ cL = 128; cR = 1; ur8 = cL * cR; ur8b = cR * cL; ASSERT(ur8 == 128); ASSERT(ur8b == 128);
+
+#ifndef SDCC_z80
+ ucL = 128; cR = -5; r16 = ucL * cR; r16b = cR * ucL; ASSERT(r16 == -640); ASSERT(r16b == -640);
+ ucL = 128; cR = 5; r16 = ucL * cR; r16b = cR * ucL; ASSERT(r16 == 640); ASSERT(r16b == 640);
+#endif
+
+ ucL = 127; cR = -1; r8 = ucL * cR; r8b = cR * ucL; ASSERT( r8 == -127); ASSERT( r8b == -127);
+ ucL = 128; cR = 1; ur8 = ucL * cR; ur8b = cR * ucL; ASSERT(ur8 == 128); ASSERT(ur8b == 128);
+ ucL = 128; ucR = 5; r16 = ucL * ucR; r16b = ucR * ucL; ASSERT(r16 == 640); ASSERT(r16b == 640);
+ ucL = 128; ucR = 1; ur8 = ucL * ucR; ur8b = ucR * ucL; ASSERT(ur8 == 128); ASSERT(ur8b == 128);
+}
+
+void
+testDiv(void)
+{
+ {attrL} char cL;
+ {attrL} unsigned char ucL;
+ {attrR} char cR;
+ {attrR} unsigned char ucR;
+ volatile char r8;
+ volatile unsigned char ur8;
+ volatile short r16;
+
+ cL = -128; cR = -2; r8 = cL / cR; ASSERT(r8 == 64);
+ cL = -128; cR = -2; r16 = cL / cR; ASSERT(r16 == 64);
+
+ ucL = 255; ucR = 3; r8 = ucL / ucR; ASSERT(r8 == 85);
+ ucL = 255; ucR = 255; r8 = ucL / ucR; ASSERT(r8 == 1);
+ ucL = 3; ucR = 255; r8 = ucL / ucR; ASSERT(r8 == 0);
+
+ cL = 127; cR = 3; r8 = cL / cR; ASSERT(r8 == 42);
+ cL = -127; cR = 3; r8 = cL / cR; ASSERT(r8 == -42);
+ cL = 127; cR = -3; r8 = cL / cR; ASSERT(r8 == -42);
+ cL = -127; cR = -3; r8 = cL / cR; ASSERT(r8 == 42);
+
+ ucL = 127; cR = 3; r8 = ucL / cR; ASSERT(r8 == 42);
+ ucL = 255; cR = 3; r8 = ucL / cR; ASSERT(r8 == 85);
+#ifndef SDCC_z80
+ ucL = 127; cR = -3; r8 = ucL / cR; ASSERT(r8 == -42);
+ ucL = 255; cR = -3; r8 = ucL / cR; ASSERT(r8 == -85);
+#endif
+
+ cL = 127; ucR = 3; r8 = cL / ucR; ASSERT(r8 == 42);
+ cL = -127; ucR = 3; r8 = cL / ucR; ASSERT(r8 == -42);
+ cL = 127; ucR = 128; r8 = cL / ucR; ASSERT(r8 == 0);
+ cL = -127; ucR = 128; r8 = cL / ucR; ASSERT(r8 == 0);
+
+ cL = 127; cR = 1; r8 = cL / cR; ASSERT(r8 == 127);
+ cL = 127; cR = 1; r16 = cL / cR; ASSERT(r16 == 127);
+
+ ucL = 251; cR = 1; ur8 = ucL / cR; ASSERT(ur8 == 251);
+ ucL = 251; cR = 1; r16 = ucL / cR; ASSERT(r16 == 251);
+
+#ifndef SDCC_z80
+ ucL = 253; cR = -3; r8 = ucL / cR; ASSERT(r8 == -84);
+ ucL = 253; cR = -3; r16 = ucL / cR; ASSERT(r16 == -84);
+
+ ucL = 254; cR = -1; r16 = ucL / cR; ASSERT(r16 == -254);
+#endif
+ cL = -128; cR = -1; r16 = cL / cR; ASSERT(r16 == 128);
+}
+
+void
+testMod(void)
+{
+ {attrL} char cL;
+ {attrL} unsigned char ucL;
+ {attrR} char cR;
+ {attrR} unsigned char ucR;
+ volatile char r8;
+ volatile unsigned char ur8;
+ volatile short r16;
+
+ ucL = 128; cR = 5; r16 = ucL % cR; ASSERT(r16 == 3);
+#ifndef SDCC_z80
+ ucL = 128; cR = -5; r16 = ucL % cR; ASSERT(r16 == 3);
+#endif
+ ucL = 128; ucR = 5; r16 = ucL % ucR; ASSERT(r16 == 3);
+
+ ucL = 128; ucR = 255; ur8 = ucL % ucR; ASSERT(ur8 == 128);
+ ucL = 128; ucR = 255; r16 = ucL % ucR; ASSERT(r16 == 128);
+
+ ucL = 128; cR = 127; r8 = ucL % cR; ASSERT(r8 == 1);
+
+ cL = 127; cR = 5; r16 = cL % cR; ASSERT(r16 == 2);
+ r16 = -1;
+ cL = 127; cR = -5; r16 = cL % cR; ASSERT(r16 == 2);
+ r16 = -1;
+ cL = 127; ucR = 5; r16 = cL % ucR; ASSERT(r16 == 2);
+
+ cL = -128; cR = 5; r16 = cL % cR; ASSERT(r16 == -3);
+ r16 = 0;
+ cL = -128; cR = -5; r16 = cL % cR; ASSERT(r16 == -3);
+ r16 = 0;
+ cL = -128; ucR = 5; r16 = cL % ucR; ASSERT(r16 == -3);
+}