From: bernhardheld Date: Wed, 11 Feb 2004 21:30:33 +0000 (+0000) Subject: * device/lib/_modsint.c, X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=2b768f4d1d91642a8e7ffdddafd545d286ae1fbc;p=fw%2Fsdcc * 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 git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@3192 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/ChangeLog b/ChangeLog index dbce719b..1c8a3a10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2004-02-11 Bernhard Held + + * 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 * gen.c (genInline): reverted to old code for assemnling inline @@ -127,28 +152,28 @@ * 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 diff --git a/device/lib/_modsint.c b/device/lib/_modsint.c index abf270b0..a46268a3 100644 --- a/device/lib/_modsint.c +++ b/device/lib/_modsint.c @@ -90,8 +90,6 @@ _modsint_dummy (void) _naked mov a,b1 jnb acc.7,b_not_negative - cpl F0 - clr a clr c subb a,b0 diff --git a/device/lib/_modslong.c b/device/lib/_modslong.c index 99c3f8d9..22140ee1 100644 --- a/device/lib/_modslong.c +++ b/device/lib/_modslong.c @@ -101,8 +101,6 @@ _modslong_dummy (void) _naked mov a,b3 jnb acc.7,b_not_negative - cpl F0 - clr a ; b = -b; clr c subb a,b0 diff --git a/src/SDCCast.c b/src/SDCCast.c index 62efaa6d..57435e5d 100644 --- a/src/SDCCast.c +++ b/src/SDCCast.c @@ -2084,6 +2084,7 @@ addCast (ast *tree, RESULT_TYPE resultType, bool upcast) } 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) @@ -2104,6 +2105,10 @@ resultTypePropagate (ast *tree, RESULT_TYPE resultType) case ':': case '|': case '^': + case '*': + case '+': + case '-': + case LABEL: return resultType; case '&': if (!tree->right) @@ -2111,6 +2116,8 @@ resultTypePropagate (ast *tree, RESULT_TYPE resultType) return RESULT_TYPE_NONE; else return resultType; + case IFX: + return RESULT_TYPE_IFX; default: return RESULT_TYPE_NONE; } @@ -2792,10 +2799,11 @@ decorateType (ast * tree, RESULT_TYPE resultType) } 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 */ @@ -2861,7 +2869,7 @@ decorateType (ast * tree, RESULT_TYPE resultType) 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; /*------------------------------------------------------------------*/ @@ -2977,7 +2985,7 @@ decorateType (ast * tree, RESULT_TYPE resultType) computeType (LTYPE (tree), RTYPE (tree), resultType == RESULT_TYPE_CHAR ? FALSE : TRUE)); - + return tree; /*------------------------------------------------------------------*/ @@ -3363,7 +3371,7 @@ decorateType (ast * tree, RESULT_TYPE resultType) 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 */ @@ -3685,8 +3693,14 @@ decorateType (ast * tree, RESULT_TYPE resultType) } 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")), diff --git a/src/SDCCast.h b/src/SDCCast.h index be782aae..04211fa9 100644 --- a/src/SDCCast.h +++ b/src/SDCCast.h @@ -177,7 +177,8 @@ typedef enum 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 */ diff --git a/src/SDCCicode.c b/src/SDCCicode.c index 381a2bcb..e65e7d5d 100644 --- a/src/SDCCicode.c +++ b/src/SDCCicode.c @@ -45,7 +45,7 @@ symbol *entryLabel; /* function entry label */ /*-----------------------------------------------------------------*/ /* 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 *); @@ -1753,36 +1753,90 @@ usualUnaryConversions (operand * op) /*-----------------------------------------------------------------*/ /* 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; } @@ -2007,7 +2061,7 @@ geniCodeGoto (symbol * label) /* 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; @@ -2023,7 +2077,7 @@ geniCodeMultiply (operand * left, operand * right, int resultIsInt) 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); @@ -2066,7 +2120,7 @@ geniCodeMultiply (operand * left, operand * right, int resultIsInt) /* geniCodeDivision - gen intermediate code for division */ /*-----------------------------------------------------------------*/ operand * -geniCodeDivision (operand * left, operand * right) +geniCodeDivision (operand * left, operand * right, bool resultIsInt) { iCode *ic; int p2 = 0; @@ -2076,9 +2130,7 @@ geniCodeDivision (operand * left, operand * right) 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 @@ -2106,7 +2158,7 @@ geniCodeDivision (operand * left, operand * right) /* geniCodeModulus - gen intermediate code for modulus */ /*-----------------------------------------------------------------*/ operand * -geniCodeModulus (operand * left, operand * right) +geniCodeModulus (operand * left, operand * right, bool resultIsInt) { iCode *ic; sym_link *resType; @@ -2117,9 +2169,7 @@ geniCodeModulus (operand * left, operand * right) 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); @@ -2163,7 +2213,8 @@ subtractExit: // should we really do this? is this ANSI? return geniCodeDivision (result, - operandFromLit (getSize (ltype->next))); + operandFromLit (getSize (ltype->next)), + FALSE); } /*-----------------------------------------------------------------*/ @@ -2198,7 +2249,7 @@ geniCodeSubtract (operand * left, operand * right) } else { /* make them the same size */ - resType = usualBinaryConversions (&left, &right, FALSE, FALSE); + resType = usualBinaryConversions (&left, &right, FALSE, '-'); } ic = newiCode ('-', left, right); @@ -2257,7 +2308,7 @@ geniCodeAdd (operand * left, operand * right, int lvl) } 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 */ @@ -2847,7 +2898,7 @@ geniCodeLogic (operand * left, operand * right, int op) } } - ctype = usualBinaryConversions (&left, &right, FALSE, FALSE); + ctype = usualBinaryConversions (&left, &right, FALSE, ' '); ic = newiCode (op, left, right); IC_RESULT (ic) = newiTempOperand (newCharLink (), 1); @@ -3803,15 +3854,18 @@ ast2iCode (ast * tree,int lvl) 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); @@ -3923,13 +3977,17 @@ ast2iCode (ast * tree,int 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); diff --git a/src/SDCCsymt.c b/src/SDCCsymt.c index 88df7feb..19c88b17 100644 --- a/src/SDCCsymt.c +++ b/src/SDCCsymt.c @@ -1519,7 +1519,9 @@ computeType (sym_link * type1, sym_link * type2, bool promoteCharToInt) 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 */ @@ -1554,18 +1556,25 @@ computeType (sym_link * type1, sym_link * type2, bool promoteCharToInt) 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; diff --git a/src/SDCCval.c b/src/SDCCval.c index e72baee3..542ca575 100644 --- a/src/SDCCval.c +++ b/src/SDCCval.c @@ -1143,7 +1143,7 @@ valDiv (value * lval, value * rval) 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); diff --git a/src/ds390/gen.c b/src/ds390/gen.c index 1d70bcf3..315f0642 100644 --- a/src/ds390/gen.c +++ b/src/ds390/gen.c @@ -4615,9 +4615,11 @@ genMultOneByte (operand * left, 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 */ @@ -4629,105 +4631,197 @@ genMultOneByte (operand * left, 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); - } } /*-----------------------------------------------------------------*/ @@ -4966,94 +5060,182 @@ genDivOneByte (operand * left, 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--; } @@ -5249,70 +5431,146 @@ genModOneByte (operand * left, 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--; } diff --git a/src/hc08/gen.c b/src/hc08/gen.c index e9b718cb..97748e37 100644 --- a/src/hc08/gen.c +++ b/src/hc08/gen.c @@ -3451,7 +3451,7 @@ genMultOneByte (operand * left, //emitcode (";", "swapped left and right"); } - if (SPEC_USIGN(opetype) + if (size == 1 || (SPEC_USIGN(operandType(left)) && SPEC_USIGN(operandType(right)))) { diff --git a/src/mcs51/gen.c b/src/mcs51/gen.c index cb4dea5c..c9f3132d 100644 --- a/src/mcs51/gen.c +++ b/src/mcs51/gen.c @@ -273,14 +273,14 @@ getTempRegs(regs **tempRegs, int size, iCode *ic) 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); @@ -288,7 +288,7 @@ getTempRegs(regs **tempRegs, int size, iCode *ic) bitVectSetBit (freeRegs, R5_IDX); bitVectSetBit (freeRegs, R6_IDX); bitVectSetBit (freeRegs, R7_IDX); - + if (IFFUNC_CALLEESAVES(_G.currentFunc->type)) { bitVect * newfreeRegs; @@ -297,8 +297,8 @@ getTempRegs(regs **tempRegs, int size, iCode *ic) freeRegs = newfreeRegs; } freeRegs = bitVectCplAnd (freeRegs, ic->rMask); - - offset = 0; + + offset = 0; for (i=0; isize; i++) { if (bitVectBitValue(freeRegs,i)) @@ -350,7 +350,7 @@ leftRightUseAcc(iCode *ic) int size; int accuseSize = 0; int accuse = 0; - + if (!ic) { werror (E_INTERNAL_ERROR, __FILE__, __LINE__, @@ -399,7 +399,7 @@ leftRightUseAcc(iCode *ic) accuseSize = size; } } - + if (accuseSize) return accuseSize; else @@ -777,7 +777,7 @@ aopOp (operand * op, iCode * ic, bool result) 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); @@ -965,7 +965,7 @@ aopGet (asmop * aop, int offset, bool bit16, bool dname) { case AOP_DUMMY: return zero; - + case AOP_R0: case AOP_R1: /* if we need to increment it */ @@ -1107,7 +1107,7 @@ aopPut (asmop * aop, const char *s, int offset, bool bvolatile) case AOP_DUMMY: MOVA (s); /* read s in case it was volatile */ break; - + case AOP_DIR: if (offset) sprintf (d, "(%s + %d)", @@ -1681,10 +1681,10 @@ saveRegisters (iCode * lic) (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; @@ -1728,7 +1728,7 @@ unsaveRegisters (iCode * ic) /* 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) @@ -1948,16 +1948,16 @@ unsaveRBank (int bank, iCode * ic, bool popPsw) 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) @@ -1991,11 +1991,11 @@ unsaveRBank (int bank, iCode * ic, bool popPsw) { emitcode ("mov", "_spx,%s", r->name); } - + if (aop) { - freeAsmop (NULL, aop, ic, TRUE); - } + freeAsmop (NULL, aop, ic, TRUE); + } } /*-----------------------------------------------------------------*/ @@ -2061,7 +2061,7 @@ saveRBank (int bank, iCode * ic, bool pushPsw) } if (ic) - { + { ic->bankSaved = 1; } } @@ -2094,7 +2094,7 @@ static void genSend(set *sendSet) emitcode ("mov","b1_%d,%s",rb1_count++, aopGet (AOP (IC_LEFT (sic)), offset++,FALSE, FALSE)); } - } + } freeAsmop (IC_LEFT (sic), NULL, sic, TRUE); } } @@ -2251,7 +2251,7 @@ genPcall (iCode * ic) if (swapBanks) { - emitcode ("mov", "psw,#0x%02x", + emitcode ("mov", "psw,#0x%02x", ((FUNC_REGBANK(dtype)) << 3) & 0xff); } @@ -2262,7 +2262,7 @@ genPcall (iCode * ic) if (swapBanks) { - emitcode ("mov", "psw,#0x%02x", + emitcode ("mov", "psw,#0x%02x", ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff); } @@ -2444,7 +2444,7 @@ genFunction (iCode * ic) } else { - + /* this function has a function call cannot determines register usage so we will have to push the entire bank */ @@ -2468,7 +2468,7 @@ genFunction (iCode * ic) * other bank, we must save that bank entirely. */ unsigned long banksToSave = 0; - + if (IFFUNC_HASFCALL(sym->type)) { @@ -2484,11 +2484,11 @@ genFunction (iCode * ic) /* 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)) @@ -2502,8 +2502,8 @@ genFunction (iCode * ic) { 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; @@ -2518,24 +2518,24 @@ genFunction (iCode * ic) * 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)) @@ -2658,7 +2658,7 @@ genFunction (iCode * ic) emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff)); emitcode ("mov", "_spx,a"); } - + /* if critical function then turn interrupts off */ if (IFFUNC_ISCRITICAL (ftype)) { @@ -2685,7 +2685,7 @@ genEndFunction (iCode * ic) emitcode(";", "naked function: no epilogue."); return; } - + if (IFFUNC_ISCRITICAL (sym->type)) { emitcode ("pop", "psw"); /* restore ea via c in psw */ @@ -2769,7 +2769,7 @@ genEndFunction (iCode * ic) { if (options.parms_in_bank1) { int i; - for (i = 7 ; i >= 0 ; i-- ) { + for (i = 7 ; i >= 0 ; i-- ) { emitcode ("pop","%s",rb1regs[i]); } } @@ -2788,7 +2788,7 @@ genEndFunction (iCode * ic) */ unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype); int ix; - + for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--) { if (savedBanks & (1 << ix)) @@ -2796,7 +2796,7 @@ genEndFunction (iCode * ic) unsaveRBank(ix, NULL, FALSE); } } - + if (options.useXstack) { /* Restore bank AFTER calling unsaveRBank, @@ -2972,7 +2972,7 @@ findLabelBackwards (iCode * ic, int key) 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; @@ -3011,7 +3011,7 @@ genPlusIncr (iCode * ic) /* 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)) { @@ -3391,7 +3391,7 @@ genPlus (iCode * ic) } 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 */ @@ -3669,8 +3669,8 @@ genMinus (iCode * ic) aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE)); } } - - + + adjustArithmeticResult (ic); release: @@ -3695,7 +3695,6 @@ genMultbits (operand * left, outBitC (result); } - /*-----------------------------------------------------------------*/ /* genMultOneByte : 8*8=8/16 bit multiplication */ /*-----------------------------------------------------------------*/ @@ -3704,18 +3703,20 @@ genMultOneByte (operand * left, 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 */ @@ -3724,91 +3725,171 @@ genMultOneByte (operand * left, 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)); - } } /*-----------------------------------------------------------------*/ @@ -3892,84 +3973,189 @@ genDivOneByte (operand * left, 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)); + } } /*-----------------------------------------------------------------*/ @@ -4047,73 +4233,133 @@ genModOneByte (operand * left, 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)); + } } /*-----------------------------------------------------------------*/ @@ -4399,7 +4645,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl) right = left; left = t; } - + if (AOP_TYPE (right) == AOP_LIT) lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit); @@ -4671,7 +4917,7 @@ hasInc (operand *op, iCode *ic,int osize) 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; @@ -4682,7 +4928,7 @@ hasInc (operand *op, iCode *ic,int osize) while (lic) { /* if operand of the form op = 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; @@ -5900,7 +6146,7 @@ genSwap (iCode * ic) result = IC_RESULT (ic); aopOp (left, ic, FALSE); aopOp (result, ic, FALSE); - + switch (AOP_SIZE (left)) { case 1: /* swap nibbles in byte */ @@ -5940,12 +6186,12 @@ genSwap (iCode * ic) default: wassertl(FALSE, "unsupported SWAP operand size"); } - + freeAsmop (left, NULL, ic, TRUE); freeAsmop (result, NULL, ic, TRUE); } - + /*-----------------------------------------------------------------*/ /* AccRol - rotate left accumulator by known count */ /*-----------------------------------------------------------------*/ @@ -6225,16 +6471,16 @@ AccAXLsh (char *x, int shCount) 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 @@ -6958,7 +7204,7 @@ shiftRLong (operand * left, int offl, } MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE)); - + if (offl==MSB16) { // shift is > 8 if (sign) { @@ -7394,7 +7640,7 @@ emitPtrByteGet (char *rname, int p_type, bool preserveAinB) emitcode ("mov", "b,a"); emitcode ("movx", "a,@%s", rname); break; - + case FPOINTER: if (preserveAinB) emitcode ("mov", "b,a"); @@ -7445,7 +7691,7 @@ emitPtrByteSet (char *rname, int p_type, char *src) MOVA (src); emitcode ("movx", "@%s,a", rname); break; - + case FPOINTER: MOVA (src); emitcode ("movx", "@dptr,a"); @@ -7787,7 +8033,7 @@ loadDptrFromOperand (operand *op, bool loadBToo) 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 { @@ -7847,7 +8093,7 @@ genFarPointerGet (operand * left, aopOp (left, ic, FALSE); loadDptrFromOperand (left, FALSE); - + /* so dptr now contains the address */ aopOp (result, ic, FALSE); @@ -7867,7 +8113,7 @@ genFarPointerGet (operand * left, 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)); @@ -7891,7 +8137,7 @@ genCodePointerGet (operand * left, aopOp (left, ic, FALSE); loadDptrFromOperand (left, FALSE); - + /* so dptr now contains the address */ aopOp (result, ic, FALSE); @@ -7913,7 +8159,7 @@ genCodePointerGet (operand * left, emitcode ("inc", "dptr"); } else - { + { emitcode ("mov", "a,#0x%02x", offset); emitcode ("movc", "a,@a+dptr"); aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE)); @@ -7944,7 +8190,7 @@ genGenPointerGet (operand * left, aopOp (left, ic, FALSE); loadDptrFromOperand (left, TRUE); - + /* so dptr know contains the address */ aopOp (result, ic, FALSE); @@ -8122,7 +8368,7 @@ genPackBits (sym_link * etype, /* 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); @@ -8132,7 +8378,7 @@ genPackBits (sym_link * etype, if (rlen) { mask = (((unsigned char) -1 << rlen) & 0xff); - + if (AOP_TYPE (right) == AOP_LIT) { /* Case with partial byte and literal source @@ -8437,7 +8683,7 @@ genFarPointerSet (operand * right, aopOp (result, ic, FALSE); loadDptrFromOperand (result, FALSE); - + /* so dptr know contains the address */ aopOp (right, ic, FALSE); @@ -8482,7 +8728,7 @@ genGenPointerSet (operand * right, aopOp (result, ic, FALSE); loadDptrFromOperand (result, TRUE); - + /* so dptr know contains the address */ aopOp (right, ic, FALSE); @@ -8573,7 +8819,7 @@ genPointerSet (iCode * ic, iCode *pi) break; default: - werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "genPointerSet: illegal pointer type"); } @@ -8972,16 +9218,16 @@ genCast (iCode * ic) { 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; } @@ -9085,7 +9331,7 @@ genDjnz (iCode * ic, iCode * ifx) * it back after the decrement. */ char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE); - + if (strcmp(rByte, "a")) { /* Something is hopelessly wrong */ @@ -9141,11 +9387,11 @@ genReceive (iCode * ic) regs *tempRegs[4]; int receivingA = 0; int roffset = 0; - + for (offset = 0; offsetnext) { _G.current_iCode = ic; - + if (ic->lineno && cln != ic->lineno) { if (options.debug) @@ -9378,7 +9624,7 @@ gen51Code (iCode * lic) _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; @@ -9389,7 +9635,7 @@ gen51Code (iCode * lic) for (i=0; i<8; i++) { sprintf (®sInUse[i], - "%c", ic->riu & (1<riu & (1<seq, printILine(ic)); diff --git a/support/regression/tests/onebyte.c b/support/regression/tests/onebyte.c new file mode 100644 index 00000000..a5fb515d --- /dev/null +++ b/support/regression/tests/onebyte.c @@ -0,0 +1,123 @@ +/** test one byte mul/div/mod operations. + + attrL: volatile, + attrR: volatile, +*/ +#include + +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); +}