+ else if (IS_BITVAR (etype2) && !IS_BITVAR (etype1))
+ {
+ rType = copyLinkChain (type1);
+ /* bitfield can have up to 16 bits */
+ if (getSize (etype2) > 1)
+ SPEC_NOUN (getSpec (rType)) = V_INT;
+ }
+ /* if one of them is a pointer or array then that
+ prevails */
+ else if (IS_PTR (type1) || IS_ARRAY (type1))
+ rType = copyLinkChain (type1);
+ else if (IS_PTR (type2) || IS_ARRAY (type2))
+ rType = copyLinkChain (type2);
+ else if (getSize (type1) > getSize (type2))
+ rType = copyLinkChain (type1);
+ else
+ rType = copyLinkChain (type2);
+
+ reType = getSpec (rType);
+
+ /* avoid conflicting types */
+ reType->select.s.b_signed = 0;
+
+ /* if result is a literal then make not so */
+ if (IS_LITERAL (reType))
+ SPEC_SCLS (reType) = S_REGISTER;
+
+ switch (resultType)
+ {
+ case RESULT_TYPE_CHAR:
+ if (IS_BITVAR (reType))
+ {
+ SPEC_NOUN (reType) = V_CHAR;
+ SPEC_SCLS (reType) = 0;
+ SPEC_USIGN (reType) = 0;
+ return rType;
+ }
+ break;
+ case RESULT_TYPE_INT:
+ case RESULT_TYPE_NONE:
+ case RESULT_TYPE_OTHER:
+ if (IS_BIT (reType))
+ {
+ SPEC_NOUN (reType) = V_CHAR;
+ SPEC_SCLS (reType) = 0;
+ SPEC_USIGN (reType) = 0;
+ return rType;
+ }
+ else if (IS_BITFIELD (reType))
+ {
+ /* could be smarter, but it depends on the op */
+ /* this is for the worst case: a multiplication of 4 * 4 bit */
+ SPEC_NOUN (reType) = SPEC_BLEN (reType) <= 4 ? V_CHAR : V_INT;
+ SPEC_SCLS (reType) = 0;
+ SPEC_USIGN (reType) = 0;
+ return rType;
+ }
+ else if (IS_CHAR (reType))
+ {
+ if (op == '|' || op == '^')
+ return computeTypeOr (etype1, etype2, reType);
+ else if ( op == '&'
+ && SPEC_USIGN (etype1) != SPEC_USIGN (etype2))
+ {
+ SPEC_USIGN (reType) = 1;
+ return rType;
+ }
+ else if (op == '*')
+ {
+ SPEC_NOUN (reType) = V_INT;
+ SPEC_USIGN (reType) = 0;
+ return rType;
+ }
+ /* TODO: should be in SDCCast.c */
+ else if ( op == '/'
+ && ( !SPEC_USIGN (etype1)
+ || !SPEC_USIGN (etype2)))
+ {
+ SPEC_NOUN (reType) = V_INT;
+ SPEC_USIGN (reType) = 0;
+ return rType;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* SDCC's sign promotion:
+ - if one or both operands are unsigned, the resultant type will be unsigned
+ (except char, see below)
+ - if an operand is promoted to a larger type (char -> int, int -> long),
+ the larger type will be signed
+
+ SDCC tries hard to avoid promotion to int and does 8 bit calculation as
+ much as possible. We're leaving ISO IEC 9899 here and have to extrapolate
+ the standard. The standard demands, that the result has to be the same
+ "as if" the promotion would have been performed:
+
+ - if the result of an operation with two char's is promoted to a
+ larger type, the result will be signed.
+
+ More sophisticated are these:
+ - if the result of an operation with two char's is a char again,
+ the result will only then be unsigned, if both operands are
+ unsigned. In all other cases the result will be signed.
+
+ This seems to be contradictionary to the first two rules, but it makes
+ real sense (all types are char's):
+
+ A signed char can be negative; this must be preserved in the result
+ -1 * 100 = -100;
+
+ Only if both operands are unsigned it's safe to make the result
+ unsigned; this helps to avoid overflow:
+ 2 * 100 = 200;
+
+ - ToDo: document '|', '^' and '&'
+
+ Homework: - why is (200 * 200 < 0) true?
+ - why is { char l = 200, r = 200; (r * l > 0) } true?
+ */
+
+ if (!IS_FLOAT (reType)
+ && ( (SPEC_USIGN (etype1)
+ /* if this operand is promoted to a larger type,
+ then it will be promoted to a signed type */
+ && !(getSize (etype1) < getSize (reType))
+ /* char require special handling */
+ && !IS_CHAR (etype1))
+ || /* same for 2nd operand */
+ (SPEC_USIGN (etype2)
+ && !(getSize (etype2) < getSize (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)
+ && IS_CHAR (reType))))
+ SPEC_USIGN (reType) = 1;
+ else
+ SPEC_USIGN (reType) = 0;
+
+ return rType;
+}
+
+/*--------------------------------------------------------------------*/
+/* compareType - will do type check return 1 if match, -1 if castable */
+/*--------------------------------------------------------------------*/
+int
+compareType (sym_link * dest, sym_link * src)
+{
+ if (!dest && !src)
+ return 1;
+
+ if (dest && !src)
+ return 0;
+
+ if (src && !dest)
+ return 0;
+
+ /* if dest is a declarator then */
+ if (IS_DECL (dest))
+ {
+ if (IS_DECL (src))
+ {
+ /* banked function pointer */
+ if (IS_GENPTR (dest) && IS_GENPTR (src))
+ {
+ if (IS_FUNC (src->next) && IS_VOID(dest->next))
+ return -1;
+ if (IS_FUNC (dest->next) && IS_VOID(src->next))
+ return -1;
+ return compareType (dest->next, src->next);
+ }
+
+ if (DCL_TYPE (src) == DCL_TYPE (dest)) {
+ if (IS_FUNC(src)) {
+ //checkFunction(src,dest);
+ }
+ return compareType (dest->next, src->next);
+ }
+ if (IS_PTR (dest) && IS_GENPTR (src) && IS_VOID(src->next)) {
+ return -1;
+ }
+ if (IS_PTR (src) &&
+ (IS_GENPTR (dest) ||
+ ((DCL_TYPE(src) == POINTER) && (DCL_TYPE(dest) == IPOINTER))
+ ))
+ return -1;
+ if (IS_PTR (dest) && IS_ARRAY (src)) {
+ value *val=aggregateToPointer (valFromType(src));
+ int res=compareType (dest, val->type);
+ Safe_free(val->type);
+ Safe_free(val);
+ return res;
+ }
+ if (IS_PTR (dest) && IS_FUNC (dest->next) && IS_FUNC (src))
+ return compareType (dest->next, src);
+ return 0;
+ }
+ else if (IS_PTR (dest) && IS_INTEGRAL (src))
+ return -1;
+ else
+ return 0;
+ }
+
+ /* if one is a specifier and the other is not */
+ if ((IS_SPEC (src) && !IS_SPEC (dest)) ||
+ (IS_SPEC (dest) && !IS_SPEC (src)))
+ return 0;
+
+ /* if one of them is a void then ok */
+ if (SPEC_NOUN (dest) == V_VOID &&
+ SPEC_NOUN (src) != V_VOID)
+ return -1;
+
+ if (SPEC_NOUN (dest) != V_VOID &&
+ SPEC_NOUN (src) == V_VOID)
+ return -1;
+
+ /* if they are both bitfields then if the lengths
+ and starts don't match */
+ if (IS_BITFIELD (dest) && IS_BITFIELD (src) &&
+ (SPEC_BLEN (dest) != SPEC_BLEN (src) ||
+ SPEC_BSTR (dest) != SPEC_BSTR (src)))
+ return -1;
+
+ /* it is a specifier */
+ if (SPEC_NOUN (dest) != SPEC_NOUN (src))
+ {
+ if (SPEC_USIGN (dest) == SPEC_USIGN (src) &&
+ IS_INTEGRAL (dest) && IS_INTEGRAL (src) &&
+ /* I would prefer
+ bitsForType (dest) == bitsForType (src))
+ instead of the next two lines, but the regression tests fail with
+ them; I guess it's a problem with replaceCheaperOp */
+ getSize (dest) == getSize (src) &&
+ !(!IS_BIT (dest) && IS_BIT (src)))
+ return 1;
+ else if (IS_ARITHMETIC (dest) && IS_ARITHMETIC (src))
+ return -1;
+ else
+ return 0;
+ }
+ else if (IS_STRUCT (dest))
+ {
+ if (SPEC_STRUCT (dest) != SPEC_STRUCT (src))
+ return 0;
+ else
+ return 1;
+ }
+ if (SPEC_LONG (dest) != SPEC_LONG (src))
+ return -1;
+
+ if (SPEC_USIGN (dest) != SPEC_USIGN (src))
+ return -1;
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------*/
+/* compareTypeExact - will do type check return 1 if match exactly */
+/*--------------------------------------------------------------------*/
+int
+compareTypeExact (sym_link * dest, sym_link * src, int level)
+{
+ STORAGE_CLASS srcScls, destScls;
+
+ if (!dest && !src)
+ return 1;
+
+ if (dest && !src)
+ return 0;
+
+ if (src && !dest)
+ return 0;
+
+ /* if dest is a declarator then */
+ if (IS_DECL (dest))
+ {
+ if (IS_DECL (src))
+ {
+ if (DCL_TYPE (src) == DCL_TYPE (dest)) {
+ if ((DCL_TYPE (src) == ARRAY) && (DCL_ELEM (src) != DCL_ELEM (dest)))
+ return 0;
+ if (DCL_PTR_CONST (src) != DCL_PTR_CONST (dest))
+ return 0;
+ if (DCL_PTR_VOLATILE (src) != DCL_PTR_VOLATILE (dest))
+ return 0;
+ if (IS_FUNC(src))
+ {
+ value *exargs, *acargs, *checkValue;
+
+ /* verify function return type */
+ if (!compareTypeExact (dest->next, src->next, -1))
+ return 0;
+ if (FUNC_ISISR (dest) != FUNC_ISISR (src))
+ return 0;
+ if (FUNC_REGBANK (dest) != FUNC_REGBANK (src))
+ return 0;
+ if (IFFUNC_ISNAKED (dest) != IFFUNC_ISNAKED (src))
+ return 0;
+ #if 0
+ if (IFFUNC_ISREENT (dest) != IFFUNC_ISREENT (src) && argCnt>1)
+ return 0;
+ #endif
+
+ /* compare expected args with actual args */
+ exargs = FUNC_ARGS(dest);
+ acargs = FUNC_ARGS(src);
+
+ /* for all the expected args do */
+ for (; exargs && acargs; exargs = exargs->next, acargs = acargs->next)
+ {
+ //checkTypeSanity(acargs->etype, acargs->name);
+
+ if (IS_AGGREGATE (acargs->type))
+ {
+ checkValue = copyValue (acargs);
+ aggregateToPointer (checkValue);
+ }
+ else
+ checkValue = acargs;
+
+ #if 0
+ if (!compareTypeExact (exargs->type, checkValue->type, -1))
+ return 0;
+ #endif
+ }
+
+ /* if one them ended we have a problem */
+ if ((exargs && !acargs && !IS_VOID (exargs->type)) ||
+ (!exargs && acargs && !IS_VOID (acargs->type)))
+ return 0;
+ return 1;
+ }
+ return compareTypeExact (dest->next, src->next, level);
+ }
+ return 0;
+ }
+ return 0;
+ }
+
+ /* if one is a specifier and the other is not */
+ if ((IS_SPEC (src) && !IS_SPEC (dest)) ||
+ (IS_SPEC (dest) && !IS_SPEC (src)))
+ return 0;
+
+ /* if one of them is a void then ok */
+ if (SPEC_NOUN (dest) != SPEC_NOUN (src))
+ return 0;
+
+ /* if they are both bitfields then if the lengths
+ and starts don't match */
+ if (IS_BITFIELD (dest) && IS_BITFIELD (src) &&
+ (SPEC_BLEN (dest) != SPEC_BLEN (src) ||
+ SPEC_BSTR (dest) != SPEC_BSTR (src)))
+ return 0;
+
+ if (IS_INTEGRAL (dest))
+ {
+ /* signedness must match */
+ if (SPEC_USIGN (dest) != SPEC_USIGN (src))
+ return 0;
+ /* size must match */
+ if (SPEC_LONG (dest) != SPEC_LONG (src))
+ return 0;
+ if (SPEC_SHORT (dest) != SPEC_SHORT (src))
+ return 0;
+ }
+
+ if (IS_STRUCT (dest))
+ {
+ if (SPEC_STRUCT (dest) != SPEC_STRUCT (src))
+ return 0;
+ }
+
+ if (SPEC_CONST (dest) != SPEC_CONST (src))
+ return 0;
+ if (SPEC_VOLATILE (dest) != SPEC_VOLATILE (src))
+ return 0;
+ if (SPEC_STAT (dest) != SPEC_STAT (src))
+ return 0;
+ if (SPEC_ABSA (dest) != SPEC_ABSA (src))
+ return 0;
+ if (SPEC_ABSA (dest) && SPEC_ADDR (dest) != SPEC_ADDR (src))
+ return 0;
+
+ destScls = SPEC_SCLS (dest);
+ srcScls = SPEC_SCLS (src);
+
+ /* Compensate for const to const code change in checkSClass() */
+ if (!level & port->mem.code_ro && SPEC_CONST (dest))
+ {
+ if (srcScls == S_CODE && destScls == S_FIXED)
+ destScls = S_CODE;
+ if (destScls == S_CODE && srcScls == S_FIXED)
+ srcScls = S_CODE;
+ }
+
+ /* compensate for allocGlobal() */
+ if ((srcScls == S_FIXED || srcScls == S_AUTO)
+ && port->mem.default_globl_map == xdata
+ && !level)
+ srcScls = S_XDATA;
+
+ if (level>0 && !SPEC_STAT (dest))
+ {
+ /* Compensate for hack-o-matic in checkSClass() */
+ if (options.stackAuto || (currFunc && IFFUNC_ISREENT (currFunc->type)))
+ {
+ if (destScls == S_FIXED)
+ destScls = (options.useXstack ? S_XSTACK : S_STACK);
+ if (srcScls == S_FIXED)
+ srcScls = (options.useXstack ? S_XSTACK : S_STACK);
+ }
+ else if (TARGET_IS_DS390 || TARGET_IS_DS400 || options.useXstack)
+ {
+ if (destScls == S_FIXED)
+ destScls = S_XDATA;
+ if (srcScls == S_FIXED)
+ srcScls = S_XDATA;
+ }
+ }
+
+ if (srcScls != destScls)
+ {
+ #if 0
+ printf ("level = %d\n", level);
+ printf ("SPEC_SCLS (src) = %d, SPEC_SCLS (dest) = %d\n",
+ SPEC_SCLS (src), SPEC_SCLS (dest));
+ printf ("srcScls = %d, destScls = %d\n",srcScls, destScls);
+ #endif
+ return 0;
+ }
+
+ return 1;