diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 539309283..7a25594b6 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -1432,6 +1432,19 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs) /* Note that this logic is largely duplicated by ArithmeticConvert. */ + /* Before we apply the integral promotions, we check if both types are unsigned char. + ** If so, we return unsigned int, rather than int, which would be returned by the standard + ** rules. This is only a performance optimization and does not affect correctness, as + ** the flags are only used for code generation, and not to determine types of other + ** expressions containing this one. All unsigned char bit-patterns are valid as both int + ** and unsigned int and represent the same value, so either signed or unsigned int operations + ** can be used. This special case part is not duplicated by ArithmeticConvert. + */ + if ((lhs & CF_TYPEMASK) == CF_CHAR && (lhs & CF_UNSIGNED) && + (rhs & CF_TYPEMASK) == CF_CHAR && (rhs & CF_UNSIGNED)) { + return const_flag | CF_UNSIGNED | CF_INT; + } + /* Apply integral promotions for types char/short. */ lhs = g_intpromotion (lhs); rhs = g_intpromotion (rhs); diff --git a/test/val/char-promote.c b/test/val/char-promote.c index 1d6360d45..380a13378 100644 --- a/test/val/char-promote.c +++ b/test/val/char-promote.c @@ -68,7 +68,8 @@ void test_mul (void) #endif /* The unsigned chars get promoted to int, so this is -511. - ** We should also be able to observe that the generated code uses mul, not umul. + ** We should also be able to observe that, due to optimizations from #1315, the generated code + ** uses umul, not mul. */ if (two_fifty_five * two_fifty_five != -511) { fprintf (stderr, "Expected two_fifty_five * two_fifty_five == -511\n"); @@ -89,7 +90,9 @@ void test_div (void) const u8 seventeen = 17; const u8 three = 3; - /* We should also be able to observe that the generated code uses div, not udiv. */ + /* We should also be able to observe that, due to optimizations from #1315, the generated code + ** uses udiv, not div. + */ if (seventeen / three != 5) { fprintf (stderr, "Expected seventeen / three == 5, got: %d\n", seventeen / three); failures++; @@ -105,7 +108,9 @@ void test_shr (void) const unsigned int forty_two = 42; const unsigned int two = 2; - /* We should also be able to observe that the generated code uses asr, not shr. */ + /* We should also be able to observe that, due to optimizations from #1315, the generated code + ** uses shr, not asr. + */ if (forty_two >> two != 10) { fprintf (stderr, "Expected forty_two / two == 10, got: %d\n", forty_two >> two); failures++;