mirror of
https://github.com/cc65/cc65.git
synced 2025-01-26 17:36:57 +00:00
Addresses in constant subtraction expressions now work.
Fixed codegen for cast type subtraction in constant expressions.
This commit is contained in:
parent
c4a2620e29
commit
aa6fdf58b8
211
src/cc65/expr.c
211
src/cc65/expr.c
@ -3287,7 +3287,8 @@ static void parsesub (ExprDesc* Expr)
|
||||
Type* rhst; /* Type of right hand side */
|
||||
CodeMark Mark1; /* Save position of output queue */
|
||||
CodeMark Mark2; /* Another position in the queue */
|
||||
int rscale; /* Scale factor for the result */
|
||||
int rscale; /* Scale factor for pointer arithmetics */
|
||||
int SubDone; /* No need to generate runtime code */
|
||||
|
||||
ED_Init (&Expr2);
|
||||
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||
@ -3304,7 +3305,9 @@ static void parsesub (ExprDesc* Expr)
|
||||
|
||||
/* Get the left hand side type, initialize operation flags */
|
||||
lhst = Expr->Type;
|
||||
flags = CF_INT; /* Default result type */
|
||||
rscale = 1; /* Scale by 1, that is, don't scale */
|
||||
SubDone = 0; /* Generate runtime code by default */
|
||||
|
||||
/* Remember the output queue position, then bring the value onto the stack */
|
||||
GetCodePos (&Mark1);
|
||||
@ -3322,67 +3325,148 @@ static void parsesub (ExprDesc* Expr)
|
||||
Expr2.Type = type_uchar;
|
||||
}
|
||||
|
||||
/* Check for a constant rhs expression */
|
||||
if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
|
||||
/* Get the rhs type */
|
||||
rhst = Expr2.Type;
|
||||
|
||||
/* The right hand side is constant. Get the rhs type. */
|
||||
rhst = Expr2.Type;
|
||||
/* We can only do constant expressions for:
|
||||
** - integer subtraction:
|
||||
** - numeric - numeric
|
||||
** - (integer)(base + offset) - numeric
|
||||
** - (integer)(same_base + offset) - (integer)(same_base + offset)
|
||||
** - pointer offset:
|
||||
** - (pointer)numeric - numeric * scale
|
||||
** - (base + offset) - numeric * scale
|
||||
** - (same_base + offset) - (integer)(same_base + offset) * 1
|
||||
** - pointer diff:
|
||||
** - (numeric - numeric) / scale
|
||||
** - ((same_base + offset) - (same_base + offset)) / scale
|
||||
** - ((base + offset) - (pointer)numeric) / 1
|
||||
*/
|
||||
if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
||||
|
||||
/* Check left hand side */
|
||||
if (ED_IsConstAbs (Expr)) {
|
||||
/* Pointer diff */
|
||||
if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
|
||||
Error ("Incompatible pointer types");
|
||||
}
|
||||
|
||||
/* Both sides are constant, remove generated code */
|
||||
/* Operate on pointers, result type is an integer */
|
||||
flags = CF_PTR;
|
||||
Expr->Type = type_int;
|
||||
|
||||
/* We'll have to scale the result */
|
||||
rscale = CheckedPSizeOf (lhst);
|
||||
|
||||
/* Check for a constant rhs expression */
|
||||
if (ED_IsQuasiConst (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
|
||||
/* The right hand side is constant. Check left hand side. */
|
||||
if (ED_IsQuasiConst (Expr)) {
|
||||
/* We can't do all 'ptr1 - ptr2' constantly at the moment */
|
||||
if (Expr->Sym == Expr2.Sym) {
|
||||
Expr->IVal = (Expr->IVal - Expr2.IVal) / rscale;
|
||||
/* Get rid of unneeded flags etc. */
|
||||
ED_MakeConstAbsInt (Expr, Expr->IVal);
|
||||
/* No runtime code */
|
||||
SubDone = 1;
|
||||
} else if (rscale == 1 && ED_IsConstAbs (&Expr2)) {
|
||||
Expr->IVal = (Expr->IVal - Expr2.IVal) / rscale;
|
||||
/* No runtime code */
|
||||
SubDone = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!SubDone) {
|
||||
/* We'll do runtime code */
|
||||
if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
|
||||
/* Remove pushed value from stack */
|
||||
RemoveCode (&Mark2);
|
||||
/* Do the subtraction */
|
||||
g_dec (CF_INT | CF_CONST, Expr2.IVal);
|
||||
} else {
|
||||
/* load into the primary */
|
||||
LoadExpr (CF_NONE, &Expr2);
|
||||
/* Generate code for the sub */
|
||||
g_sub (CF_INT, 0);
|
||||
}
|
||||
/* We must scale the result */
|
||||
if (rscale != 1) {
|
||||
g_scale (CF_INT, -rscale);
|
||||
}
|
||||
/* Result is an rvalue in the primary register */
|
||||
ED_FinalizeRValLoad (Expr);
|
||||
} else {
|
||||
/* Remove pushed value from stack */
|
||||
RemoveCode (&Mark1);
|
||||
/* The result is always an rvalue */
|
||||
ED_MarkExprAsRVal (Expr);
|
||||
}
|
||||
|
||||
/* Check for pointer arithmetic */
|
||||
} else if (ED_IsQuasiConst (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
|
||||
|
||||
/* Right hand side is constant. Check left hand side. */
|
||||
if (ED_IsQuasiConst (Expr)) {
|
||||
|
||||
/* Both sides are constant. Check for pointer arithmetic */
|
||||
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
|
||||
/* Left is pointer, right is int, must scale rhs */
|
||||
Expr->IVal -= Expr2.IVal * CheckedPSizeOf (lhst);
|
||||
rscale = CheckedPSizeOf (lhst);
|
||||
/* Operate on pointers, result type is a pointer */
|
||||
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
||||
/* Left is pointer, right is pointer, must scale result */
|
||||
if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
|
||||
Error ("Incompatible pointer types");
|
||||
} else {
|
||||
Expr->IVal = (Expr->IVal - Expr2.IVal) /
|
||||
(long)CheckedPSizeOf (lhst);
|
||||
}
|
||||
/* Operate on pointers, result type is an integer */
|
||||
Expr->Type = type_int;
|
||||
flags = CF_PTR;
|
||||
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
|
||||
/* Integer subtraction */
|
||||
typeadjust (Expr, &Expr2, 1);
|
||||
Expr->IVal -= Expr2.IVal;
|
||||
|
||||
/* Limit the calculated value to the range of its type */
|
||||
LimitExprValue (Expr);
|
||||
flags = typeadjust (Expr, &Expr2, 1);
|
||||
} else {
|
||||
/* OOPS */
|
||||
Error ("Invalid operands for binary operator '-'");
|
||||
}
|
||||
|
||||
/* We can't make all subtraction expressions constant */
|
||||
if (ED_IsConstAbs (&Expr2)) {
|
||||
Expr->IVal -= Expr2.IVal * rscale;
|
||||
/* No runtime code */
|
||||
SubDone = 1;
|
||||
} else if (rscale == 1 && Expr->Sym == Expr2.Sym) {
|
||||
/* The result is the diff of the offsets */
|
||||
Expr->IVal -= Expr2.IVal;
|
||||
/* Get rid of unneeded bases and flags etc. */
|
||||
ED_MakeConstAbs (Expr, Expr->IVal, Expr->Type);
|
||||
/* No runtime code */
|
||||
SubDone = 1;
|
||||
}
|
||||
|
||||
if (SubDone) {
|
||||
/* Remove pushed value from stack */
|
||||
RemoveCode (&Mark1);
|
||||
if (IsClassInt (lhst)) {
|
||||
/* Limit the calculated value to the range of its type */
|
||||
LimitExprValue (Expr);
|
||||
}
|
||||
/* The result is always an rvalue */
|
||||
ED_MarkExprAsRVal (Expr);
|
||||
} else {
|
||||
if (ED_IsConstAbs (&Expr2)) {
|
||||
/* Remove pushed value from stack */
|
||||
RemoveCode (&Mark2);
|
||||
/* Do the subtraction */
|
||||
g_dec (flags | CF_CONST, Expr2.IVal);
|
||||
} else {
|
||||
/* Load into the primary */
|
||||
LoadExpr (CF_NONE, &Expr2);
|
||||
/* Generate code for the sub (the & is a hack here) */
|
||||
g_sub (flags & ~CF_CONST, 0);
|
||||
}
|
||||
/* Result is an rvalue in the primary register */
|
||||
ED_FinalizeRValLoad (Expr);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Left hand side is not constant, right hand side is.
|
||||
** Remove pushed value from stack.
|
||||
*/
|
||||
RemoveCode (&Mark2);
|
||||
|
||||
/* Left hand side is not constant, right hand side is */
|
||||
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
|
||||
/* Left is pointer, right is int, must scale rhs */
|
||||
Expr2.IVal *= CheckedPSizeOf (lhst);
|
||||
/* Operate on pointers, result type is a pointer */
|
||||
flags = CF_PTR;
|
||||
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
||||
/* Left is pointer, right is pointer, must scale result */
|
||||
if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
|
||||
Error ("Incompatible pointer types");
|
||||
} else {
|
||||
rscale = CheckedPSizeOf (lhst);
|
||||
}
|
||||
/* Operate on pointers, result type is an integer */
|
||||
flags = CF_PTR;
|
||||
Expr->Type = type_int;
|
||||
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
|
||||
/* Integer subtraction */
|
||||
flags = typeadjust (Expr, &Expr2, 1);
|
||||
@ -3392,12 +3476,16 @@ static void parsesub (ExprDesc* Expr)
|
||||
flags = CF_INT;
|
||||
}
|
||||
|
||||
/* Do the subtraction */
|
||||
g_dec (flags | CF_CONST, Expr2.IVal);
|
||||
|
||||
/* If this was a pointer subtraction, we must scale the result */
|
||||
if (rscale != 1) {
|
||||
g_scale (flags, -rscale);
|
||||
if (ED_IsConstAbs (&Expr2)) {
|
||||
/* Remove pushed value from stack */
|
||||
RemoveCode (&Mark2);
|
||||
/* Do the subtraction */
|
||||
g_dec (flags | CF_CONST, Expr2.IVal);
|
||||
} else {
|
||||
/* Rhs is not numeric, load into the primary */
|
||||
LoadExpr (CF_NONE, &Expr2);
|
||||
/* Generate code for the sub (the & is a hack here) */
|
||||
g_sub (flags & ~CF_CONST, 0);
|
||||
}
|
||||
|
||||
/* Result is an rvalue in the primary register */
|
||||
@ -3406,56 +3494,33 @@ static void parsesub (ExprDesc* Expr)
|
||||
|
||||
} else {
|
||||
|
||||
/* Not constant, load into the primary */
|
||||
/* Right hand side is not constant, load into the primary */
|
||||
LoadExpr (CF_NONE, &Expr2);
|
||||
|
||||
/* Right hand side is not constant. Get the rhs type. */
|
||||
rhst = Expr2.Type;
|
||||
|
||||
/* Check for pointer arithmetic */
|
||||
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
|
||||
/* Left is pointer, right is int, must scale rhs */
|
||||
g_scale (CF_INT, CheckedPSizeOf (lhst));
|
||||
/* Operate on pointers, result type is a pointer */
|
||||
flags = CF_PTR;
|
||||
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
||||
/* Left is pointer, right is pointer, must scale result */
|
||||
if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
|
||||
Error ("Incompatible pointer types");
|
||||
} else {
|
||||
rscale = CheckedPSizeOf (lhst);
|
||||
}
|
||||
/* Operate on pointers, result type is an integer */
|
||||
flags = CF_PTR;
|
||||
Expr->Type = type_int;
|
||||
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
|
||||
/* Integer subtraction. If the left hand side descriptor says that
|
||||
** the lhs is const, we have to remove this mark, since this is no
|
||||
** longer true, lhs is on stack instead.
|
||||
*/
|
||||
if (ED_IsLocNone (Expr)) {
|
||||
ED_FinalizeRValLoad (Expr);
|
||||
}
|
||||
/* Adjust operand types */
|
||||
flags = typeadjust (Expr, &Expr2, 0);
|
||||
} else {
|
||||
/* OOPS */
|
||||
Error ("Invalid operands for binary operator '-'");
|
||||
flags = CF_INT;
|
||||
}
|
||||
|
||||
/* Generate code for the sub (the & is a hack here) */
|
||||
g_sub (flags & ~CF_CONST, 0);
|
||||
|
||||
/* If this was a pointer subtraction, we must scale the result */
|
||||
if (rscale != 1) {
|
||||
g_scale (flags, -rscale);
|
||||
}
|
||||
|
||||
/* Result is an rvalue in the primary register */
|
||||
ED_FinalizeRValLoad (Expr);
|
||||
}
|
||||
|
||||
/* Result type is either a pointer or an integer */
|
||||
Expr->Type = PtrConversion (Expr->Type);
|
||||
|
||||
/* Condition code not set */
|
||||
ED_MarkAsUntested (Expr);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user