Fixed copying structs/unions > 4 bytes.

This commit is contained in:
acqn
2020-08-13 09:27:53 +08:00
committed by Oliver Schmidt
parent 03b37cf712
commit 0fa18886c0

View File

@@ -58,22 +58,23 @@ static int CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr)
/* Copy the struct/union represented by RExpr to the one represented by LExpr */ /* Copy the struct/union represented by RExpr to the one represented by LExpr */
{ {
/* If the size is that of a basic type (char, int, long), we will copy /* If the size is that of a basic type (char, int, long), we will copy
** the struct using the primary register, otherwise we use memcpy. In ** the struct using the primary register, otherwise we will use memcpy.
** the former case, push the address only if really needed.
*/ */
const Type* ltype = LExpr->Type; const Type* ltype = LExpr->Type;
const Type* stype = GetStructReplacementType (ltype); const Type* stype = GetStructReplacementType (ltype);
int UseReg = (stype != ltype); int UseReg = (stype != ltype);
if (UseReg) { if (UseReg) {
/* Back up the address of lhs only if it is in the primary */
PushAddr (LExpr); PushAddr (LExpr);
} else { } else {
ED_MarkExprAsRVal (LExpr); /* Push the address of lhs as the destination of memcpy */
ED_AddrExpr (LExpr);
LoadExpr (CF_NONE, LExpr); LoadExpr (CF_NONE, LExpr);
g_push (CF_PTR | CF_UNSIGNED, 0); g_push (CF_PTR | CF_UNSIGNED, 0);
} }
/* Get the expression on the right of the '=' into the primary */ /* Get the expression on the right of the '=' */
hie1 (RExpr); hie1 (RExpr);
/* Check for equality of the structs */ /* Check for equality of the structs */
@@ -82,28 +83,27 @@ static int CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr)
"Incompatible types in assignment to '%s' from '%s'"); "Incompatible types in assignment to '%s' from '%s'");
} }
/* Do we copy using the primary? */ /* Do we copy the value directly using the primary? */
if (UseReg) { if (UseReg) {
/* Check if the right hand side is an lvalue */ /* Check if the value of the rhs is not in the primary yet */
if (ED_IsLVal (RExpr)) { if (!ED_IsLocPrimary (RExpr)) {
/* Just load the value into the primary as the replacement type. */ /* Just load the value into the primary as the replacement type. */
LoadExpr (TypeOf (stype) | CF_FORCECHAR, RExpr); LoadExpr (TypeOf (stype) | CF_FORCECHAR, RExpr);
} }
/* Store it into the new location */ /* Store it into the location referred in the primary */
Store (LExpr, stype); Store (LExpr, stype);
} else { } else {
/* Check if the right hand side is an lvalue */ /* The only way this can happen is in chained assignments */
if (ED_IsLVal (RExpr)) { if (!ED_IsLocPrimary (RExpr)) {
/* We will use memcpy. Push the address of the rhs */ ED_AddrExpr (RExpr);
ED_MarkExprAsRVal (RExpr);
LoadExpr (CF_NONE, RExpr); LoadExpr (CF_NONE, RExpr);
} }
/* Push the address (or whatever is in ax in case of errors) */ /* Push the address of the rhs as the source of memcpy */
g_push (CF_PTR | CF_UNSIGNED, 0); g_push (CF_PTR | CF_UNSIGNED, 0);
/* Load the size of the struct or union into the primary */ /* Load the size of the struct or union into the primary */
@@ -111,6 +111,9 @@ static int CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr)
/* Call the memcpy function */ /* Call the memcpy function */
g_call (CF_FIXARGC, Func_memcpy, 4); g_call (CF_FIXARGC, Func_memcpy, 4);
/* Restore the indirection level of lhs */
ED_IndExpr (LExpr);
} }
return 1; return 1;
@@ -257,6 +260,6 @@ void Assignment (ExprDesc* Expr)
} }
/* Value is still in primary and not an lvalue */ /* Value might be still in primary and not an lvalue */
ED_FinalizeRValLoad (Expr); ED_FinalizeRValLoad (Expr);
} }