From 3bcfa735cb0f8d78a56dd88d3370d4dfea02f652 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 13 Nov 2022 14:57:48 +0800 Subject: [PATCH] clearer comments on and usage of code generator flags with type conversions in the primary register. --- src/cc65/codegen.c | 117 +++++++++++++++++++++++++++------------------ src/cc65/codegen.h | 18 ++++--- 2 files changed, 81 insertions(+), 54 deletions(-) diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 00a4738e2..c9e71de64 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -1283,34 +1283,49 @@ void g_tosint (unsigned flags) -static void g_regchar (unsigned Flags) -/* Make sure, the value in the primary register is in the range of char. Truncate if necessary */ +static void g_regchar (unsigned to) +/* Treat the value in the primary register as a char with specified signedness +** and convert it to an int (whose representation is irrelevent of signedness). +*/ { - unsigned L; - - AddCodeLine ("ldx #$00"); - - if ((Flags & CF_UNSIGNED) == 0) { - /* Sign extend */ - L = GetLocalLabel(); - AddCodeLine ("cmp #$80"); - AddCodeLine ("bcc %s", LocalLabelName (L)); - AddCodeLine ("dex"); - g_defcodelabel (L); - } + /* Since char is the smallest type supported here, we never need any info + ** about the original type to "promote from it". However, we have to make + ** sure the entire AX contains the correct char value as an int, since we + ** will almost always use the char value as an int in AX directly in code + ** generation (unless CF_FORCECHAR is specified). That is to say, we don't + ** need the original "from" flags for the first conversion to char, but do + ** need the original "to" flags as the new "from" flags for the conversion + ** to int. + */ + g_regint (to | CF_FORCECHAR); } -void g_regint (unsigned Flags) -/* Make sure, the value in the primary register an int. Convert if necessary */ +void g_regint (unsigned from) +/* Convert the value in the primary register to an int (whose representation +** is irrelevent of signedness). +*/ { - switch (Flags & CF_TYPEMASK) { + switch (from & CF_TYPEMASK) { case CF_CHAR: - if (Flags & CF_FORCECHAR) { - /* Conversion is from char */ - g_regchar (Flags); + /* If the original value was forced to use only A, it must be + ** extended from char to fill AX. Otherwise nothing to do here + ** since AX would already have the correct int value. + */ + if (from & CF_FORCECHAR) { + AddCodeLine ("ldx #$00"); + + if ((from & CF_UNSIGNED) == 0) { + /* Sign extend */ + unsigned L = GetLocalLabel(); + AddCodeLine ("cmp #$80"); + AddCodeLine ("bcc %s", LocalLabelName (L)); + AddCodeLine ("dex"); + g_defcodelabel (L); + } + break; } /* FALLTHROUGH */ @@ -1319,21 +1334,27 @@ void g_regint (unsigned Flags) break; default: - typeerror (Flags); + typeerror (from); } } -void g_reglong (unsigned Flags) -/* Make sure, the value in the primary register a long. Convert if necessary */ +void g_reglong (unsigned from) +/* Convert the value in the primary register to a long (whose representation +** is irrelevent of signedness). +*/ { - switch (Flags & CF_TYPEMASK) { + switch (from & CF_TYPEMASK) { case CF_CHAR: - if (Flags & CF_FORCECHAR) { + /* If the original value was forced to use only A, it must be + ** extended from char to long. Otherwise AX would already have + ** the correct int value to be extened to long. + */ + if (from & CF_FORCECHAR) { /* Conversion is from char */ - if (Flags & CF_UNSIGNED) { + if (from & CF_UNSIGNED) { if (IS_Get (&CodeSizeFactor) >= 200) { AddCodeLine ("ldx #$00"); AddCodeLine ("stx sreg"); @@ -1343,18 +1364,19 @@ void g_reglong (unsigned Flags) } } else { if (IS_Get (&CodeSizeFactor) >= 366) { - g_regchar (Flags); + g_regint (from); AddCodeLine ("stx sreg"); AddCodeLine ("stx sreg+1"); } else { AddCodeLine ("jsr along"); } } + break; } /* FALLTHROUGH */ case CF_INT: - if (Flags & CF_UNSIGNED) { + if (from & CF_UNSIGNED) { if (IS_Get (&CodeSizeFactor) >= 200) { AddCodeLine ("ldy #$00"); AddCodeLine ("sty sreg"); @@ -1371,7 +1393,7 @@ void g_reglong (unsigned Flags) break; default: - typeerror (Flags); + typeerror (from); } } @@ -1508,48 +1530,49 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs) -unsigned g_typecast (unsigned lhs, unsigned rhs) -/* Cast the value in the primary register to the operand size that is flagged -** by the lhs value. Return the result value. +unsigned g_typecast (unsigned to, unsigned from) +/* Cast the value in the primary register to the specified operand size and +** signedness. Return the result flags. */ { /* Check if a conversion is needed */ - if ((rhs & CF_CONST) == 0) { - switch (lhs & CF_TYPEMASK) { + if ((from & CF_CONST) == 0) { + switch (to & CF_TYPEMASK) { case CF_LONG: - /* We must promote the primary register to long */ - g_reglong (rhs); + /* We must promote the primary register to long in EAX */ + g_reglong (from); break; case CF_INT: - /* We must promote the primary register to int */ - g_regint (rhs); + /* We must promote the primary register to int in AX */ + g_regint (from); break; case CF_CHAR: - /* We must truncate the primary register to char */ - g_regchar (lhs); + /* We must truncate the primary register to char and then + ** sign-extend it to signed int in AX. + */ + g_regchar (to); break; default: - typeerror (lhs); + /* Since we are switching on "to", report an error on it */ + typeerror (to); } } - /* Do not need any other action. If the left type is int, and the primary + /* Do not need any other action. If the "to" type is int, and the primary ** register is long, it will be automagically truncated. If the right hand ** side is const, it is not located in the primary register and handled by ** the expression parser code. */ /* Result is const if the right hand side was const */ - lhs |= (rhs & CF_CONST); + to |= (from & CF_CONST); - /* The resulting type is that of the left hand side (that's why you called - ** this function :-) - */ - return lhs; + /* The resulting type is "to" (that's why you called this function :-) */ + return to; } diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h index cb62d78bd..8e04b45e4 100644 --- a/src/cc65/codegen.h +++ b/src/cc65/codegen.h @@ -208,11 +208,15 @@ void g_toslong (unsigned flags); void g_tosint (unsigned flags); /* Make sure, the value on TOS is an int. Convert if necessary */ -void g_regint (unsigned Flags); -/* Make sure, the value in the primary register an int. Convert if necessary */ +void g_regint (unsigned from); +/* Convert the value in the primary register to an int (whose representation +** is irrelevent of signedness). +*/ -void g_reglong (unsigned Flags); -/* Make sure, the value in the primary register a long. Convert if necessary */ +void g_reglong (unsigned from); +/* Convert the value in the primary register to a long (whose representation +** is irrelevent of signedness). +*/ unsigned g_typeadjust (unsigned lhs, unsigned rhs); /* Adjust the integer operands before doing a binary operation. lhs is a flags @@ -220,9 +224,9 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs); ** in (e)ax. The return value is the flags value for the resulting type. */ -unsigned g_typecast (unsigned lhs, unsigned rhs); -/* Cast the value in the primary register to the operand size that is flagged -** by the lhs value. Return the result value. +unsigned g_typecast (unsigned to, unsigned from); +/* Cast the value in the primary register to the specified operand size and +** signedness. Return the result flags. */ void g_scale (unsigned flags, long val);