1
0
mirror of https://github.com/cc65/cc65.git synced 2025-08-15 21:27:43 +00:00

clearer comments on and usage of code generator flags with type conversions in the primary register.

This commit is contained in:
acqn
2022-11-13 14:57:48 +08:00
parent 6924d44564
commit 3bcfa735cb
2 changed files with 81 additions and 54 deletions

View File

@@ -1283,34 +1283,49 @@ void g_tosint (unsigned flags)
static void g_regchar (unsigned Flags) static void g_regchar (unsigned to)
/* Make sure, the value in the primary register is in the range of char. Truncate if necessary */ /* 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; /* 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
AddCodeLine ("ldx #$00"); ** 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
if ((Flags & CF_UNSIGNED) == 0) { ** generation (unless CF_FORCECHAR is specified). That is to say, we don't
/* Sign extend */ ** need the original "from" flags for the first conversion to char, but do
L = GetLocalLabel(); ** need the original "to" flags as the new "from" flags for the conversion
AddCodeLine ("cmp #$80"); ** to int.
AddCodeLine ("bcc %s", LocalLabelName (L)); */
AddCodeLine ("dex"); g_regint (to | CF_FORCECHAR);
g_defcodelabel (L);
}
} }
void g_regint (unsigned Flags) void g_regint (unsigned from)
/* Make sure, the value in the primary register an int. Convert if necessary */ /* 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: case CF_CHAR:
if (Flags & CF_FORCECHAR) { /* If the original value was forced to use only A, it must be
/* Conversion is from char */ ** extended from char to fill AX. Otherwise nothing to do here
g_regchar (Flags); ** 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 */ /* FALLTHROUGH */
@@ -1319,21 +1334,27 @@ void g_regint (unsigned Flags)
break; break;
default: default:
typeerror (Flags); typeerror (from);
} }
} }
void g_reglong (unsigned Flags) void g_reglong (unsigned from)
/* Make sure, the value in the primary register a long. Convert if necessary */ /* 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: 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 */ /* Conversion is from char */
if (Flags & CF_UNSIGNED) { if (from & CF_UNSIGNED) {
if (IS_Get (&CodeSizeFactor) >= 200) { if (IS_Get (&CodeSizeFactor) >= 200) {
AddCodeLine ("ldx #$00"); AddCodeLine ("ldx #$00");
AddCodeLine ("stx sreg"); AddCodeLine ("stx sreg");
@@ -1343,18 +1364,19 @@ void g_reglong (unsigned Flags)
} }
} else { } else {
if (IS_Get (&CodeSizeFactor) >= 366) { if (IS_Get (&CodeSizeFactor) >= 366) {
g_regchar (Flags); g_regint (from);
AddCodeLine ("stx sreg"); AddCodeLine ("stx sreg");
AddCodeLine ("stx sreg+1"); AddCodeLine ("stx sreg+1");
} else { } else {
AddCodeLine ("jsr along"); AddCodeLine ("jsr along");
} }
} }
break;
} }
/* FALLTHROUGH */ /* FALLTHROUGH */
case CF_INT: case CF_INT:
if (Flags & CF_UNSIGNED) { if (from & CF_UNSIGNED) {
if (IS_Get (&CodeSizeFactor) >= 200) { if (IS_Get (&CodeSizeFactor) >= 200) {
AddCodeLine ("ldy #$00"); AddCodeLine ("ldy #$00");
AddCodeLine ("sty sreg"); AddCodeLine ("sty sreg");
@@ -1371,7 +1393,7 @@ void g_reglong (unsigned Flags)
break; break;
default: default:
typeerror (Flags); typeerror (from);
} }
} }
@@ -1508,48 +1530,49 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs)
unsigned g_typecast (unsigned lhs, unsigned rhs) unsigned g_typecast (unsigned to, unsigned from)
/* Cast the value in the primary register to the operand size that is flagged /* Cast the value in the primary register to the specified operand size and
** by the lhs value. Return the result value. ** signedness. Return the result flags.
*/ */
{ {
/* Check if a conversion is needed */ /* Check if a conversion is needed */
if ((rhs & CF_CONST) == 0) { if ((from & CF_CONST) == 0) {
switch (lhs & CF_TYPEMASK) { switch (to & CF_TYPEMASK) {
case CF_LONG: case CF_LONG:
/* We must promote the primary register to long */ /* We must promote the primary register to long in EAX */
g_reglong (rhs); g_reglong (from);
break; break;
case CF_INT: case CF_INT:
/* We must promote the primary register to int */ /* We must promote the primary register to int in AX */
g_regint (rhs); g_regint (from);
break; break;
case CF_CHAR: case CF_CHAR:
/* We must truncate the primary register to char */ /* We must truncate the primary register to char and then
g_regchar (lhs); ** sign-extend it to signed int in AX.
*/
g_regchar (to);
break; break;
default: 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 ** 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 ** side is const, it is not located in the primary register and handled by
** the expression parser code. ** the expression parser code.
*/ */
/* Result is const if the right hand side was const */ /* 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 /* The resulting type is "to" (that's why you called this function :-) */
** this function :-) return to;
*/
return lhs;
} }

View File

@@ -208,11 +208,15 @@ void g_toslong (unsigned flags);
void g_tosint (unsigned flags); void g_tosint (unsigned flags);
/* Make sure, the value on TOS is an int. Convert if necessary */ /* Make sure, the value on TOS is an int. Convert if necessary */
void g_regint (unsigned Flags); void g_regint (unsigned from);
/* Make sure, the value in the primary register an int. Convert if necessary */ /* Convert the value in the primary register to an int (whose representation
** is irrelevent of signedness).
*/
void g_reglong (unsigned Flags); void g_reglong (unsigned from);
/* Make sure, the value in the primary register a long. Convert if necessary */ /* Convert the value in the primary register to a long (whose representation
** is irrelevent of signedness).
*/
unsigned g_typeadjust (unsigned lhs, unsigned rhs); unsigned g_typeadjust (unsigned lhs, unsigned rhs);
/* Adjust the integer operands before doing a binary operation. lhs is a flags /* 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. ** in (e)ax. The return value is the flags value for the resulting type.
*/ */
unsigned g_typecast (unsigned lhs, unsigned rhs); unsigned g_typecast (unsigned to, unsigned from);
/* Cast the value in the primary register to the operand size that is flagged /* Cast the value in the primary register to the specified operand size and
** by the lhs value. Return the result value. ** signedness. Return the result flags.
*/ */
void g_scale (unsigned flags, long val); void g_scale (unsigned flags, long val);