mirror of
https://github.com/cc65/cc65.git
synced 2025-04-11 09:37:10 +00:00
Adjust type of int constants that fit in char
When there is an integral constant like `3` in an expression, it has type `int` according to the C spec, even though it can be represented as an `unsigned char`. Change codegen (`hie_internal` and `typeadjust`) to treat it as `unsigned char` instead of `int` so that faster, unsigned operations can be used. For the test case in #1298, reduces the cycles per iteration from 4311 to 1884. This is a great improvement, but still much worse than the 1053 cycles/iter from `c4698df~`, so more work remains to be done. Further partial fix for #1298 and #1308.
This commit is contained in:
parent
83ac2755fe
commit
060417b0dc
@ -219,6 +219,13 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush)
|
||||
|
||||
/* Generate type adjustment code if needed */
|
||||
ltype = TypeOf (lhst);
|
||||
if (ED_IsConstAbsInt (lhs) && ltype == CF_INT && lhs->IVal >= 0 && lhs->IVal < 256) {
|
||||
/* If the lhs is a int constant that fits in an unsigned char, use unsigned char.
|
||||
** g_typeadjust will either promote this to int or unsigned int as appropriate
|
||||
** based on the other operand. See comment in hie_internal.
|
||||
*/
|
||||
ltype = CF_CHAR | CF_UNSIGNED;
|
||||
}
|
||||
if (ED_IsLocNone (lhs)) {
|
||||
ltype |= CF_CONST;
|
||||
}
|
||||
@ -227,6 +234,9 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush)
|
||||
ltype |= CF_PRIMARY;
|
||||
}
|
||||
rtype = TypeOf (rhst);
|
||||
if (ED_IsConstAbsInt (rhs) && rtype == CF_INT && rhs->IVal >= 0 && rhs->IVal < 256) {
|
||||
rtype = CF_CHAR | CF_UNSIGNED;
|
||||
}
|
||||
if (ED_IsLocNone (rhs)) {
|
||||
rtype |= CF_CONST;
|
||||
}
|
||||
@ -2502,6 +2512,15 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
|
||||
}
|
||||
|
||||
} else if (lconst && (Gen->Flags & GEN_COMM) && !rconst) {
|
||||
/* If the LHS constant is an int that fits into an unsigned char, change the
|
||||
** codegen type to unsigned char. If the RHS is also an unsigned char, then
|
||||
** g_typeadjust will return unsigned int (instead of int, which would be
|
||||
** returned without this modification). This allows more efficient operations,
|
||||
** but does not affect correctness for the same reasons explained in g_typeadjust.
|
||||
*/
|
||||
if (ltype == CF_INT && Expr->IVal >= 0 && Expr->IVal < 256) {
|
||||
ltype = CF_CHAR | CF_UNSIGNED;
|
||||
}
|
||||
|
||||
/* The left side is constant, the right side is not, and the
|
||||
** operator allows swapping the operands. We haven't pushed the
|
||||
@ -2536,6 +2555,10 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
|
||||
unsigned rtype = TypeOf (Expr2.Type);
|
||||
type = 0;
|
||||
if (rconst) {
|
||||
/* As above, but for the RHS. */
|
||||
if (rtype == CF_INT && Expr2.IVal >= 0 && Expr2.IVal < 256) {
|
||||
rtype = CF_CHAR | CF_UNSIGNED;
|
||||
}
|
||||
/* Second value is constant - check for div */
|
||||
type |= CF_CONST;
|
||||
rtype |= CF_CONST;
|
||||
|
Loading…
x
Reference in New Issue
Block a user