1/*****************************************************************************/
2/* */
3/* assignment.c */
4/* */
5/* Parse assignments */
6/* */
7/* */
8/* */
9/* (C) 2002-2009, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
15/* This software is provided 'as-is', without any expressed or implied */
16/* warranty. In no event will the authors be held liable for any damages */
17/* arising from the use of this software. */
18/* */
19/* Permission is granted to anyone to use this software for any purpose, */
20/* including commercial applications, and to alter it and redistribute it */
21/* freely, subject to the following restrictions: */
22/* */
23/* 1. The origin of this software must not be misrepresented; you must not */
24/* claim that you wrote the original software. If you use this software */
25/* in a product, an acknowledgment in the product documentation would be */
26/* appreciated but is not required. */
27/* 2. Altered source versions must be plainly marked as such, and must not */
28/* be misrepresented as being the original software. */
29/* 3. This notice may not be removed or altered from any source */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36/* cc65 */
37#include "asmcode.h"
38#include "assignment.h"
39#include "codegen.h"
40#include "datatype.h"
41#include "error.h"
42#include "expr.h"
43#include "loadexpr.h"
44#include "scanner.h"
45#include "stdnames.h"
46#include "typecmp.h"
47#include "typeconv.h"
48
49
50
51/*****************************************************************************/
52/* Code */
53/*****************************************************************************/
54
55
56
57void Assignment (ExprDesc* Expr)
58/* Parse an assignment */
59{
60 ExprDesc Expr2;
61 Type* ltype = Expr->Type;
62
63
64 /* We must have an lvalue for an assignment */
65 if (ED_IsRVal (Expr)) {
66 Error ("Invalid lvalue in assignment");
67 }
68
69 /* Check for assignment to const */
70 if (IsQualConst (ltype)) {
71 Error ("Assignment to const");
72 }
73
74 /* Skip the '=' token */
75 NextToken ();
76
77 /* cc65 does not have full support for handling structs by value. Since
78 ** assigning structs is one of the more useful operations from this
79 ** family, allow it here.
80 */
81 if (IsClassStruct (ltype)) {
82
83 /* Get the size of the left hand side. */
84 unsigned Size = SizeOf (ltype);
85
86 /* If the size is that of a basic type (char, int, long), we will copy
87 ** the struct using the primary register, otherwise we use memcpy. In
88 ** the former case, push the address only if really needed.
89 */
90 int UseReg = 1;
91 Type* stype;
92 switch (Size) {
93 case SIZEOF_CHAR: stype = type_uchar; break;
94 case SIZEOF_INT: stype = type_uint; break;
95 case SIZEOF_LONG: stype = type_ulong; break;
96 default: stype = ltype; UseReg = 0; break;
97 }
98 if (UseReg) {
99 PushAddr (Expr);
100 } else {
101 ED_MakeRVal (Expr);
102 LoadExpr (CF_NONE, Expr);
103 g_push (CF_PTR | CF_UNSIGNED, 0);
104 }
105
106 /* Get the expression on the right of the '=' into the primary */
107 hie1 (&Expr2);
108
109 /* Check for equality of the structs */
110 if (TypeCmp (ltype, Expr2.Type) < TC_STRICT_COMPATIBLE) {
111 Error ("Incompatible types");
112 }
113
114 /* Check if the right hand side is an lvalue */
115 if (ED_IsLVal (&Expr2)) {
116 /* We have an lvalue. Do we copy using the primary? */
117 if (UseReg) {
118 /* Just use the replacement type */
119 Expr2.Type = stype;
120
121 /* Load the value into the primary */
122 LoadExpr (CF_FORCECHAR, &Expr2);
123
124 /* Store it into the new location */
125 Store (Expr, stype);
126
127 } else {
128
129 /* We will use memcpy. Push the address of the rhs */
130 ED_MakeRVal (&Expr2);
131 LoadExpr (CF_NONE, &Expr2);
132
133 /* Push the address (or whatever is in ax in case of errors) */
134 g_push (CF_PTR | CF_UNSIGNED, 0);
135
136 /* Load the size of the struct into the primary */
137 g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, CheckedSizeOf (ltype), 0);
138
139 /* Call the memcpy function */
140 g_call (CF_FIXARGC, Func_memcpy, 4);
141 }
142
143 } else {
144
145 /* We have an rvalue. This can only happen if a function returns
146 ** a struct, since there is no other way to generate an expression
147 ** that has a struct as an rvalue result. We allow only 1, 2, and 4
148 ** byte sized structs, and do direct assignment.
149 */
150 if (UseReg) {
151 /* Do the store */
152 Store (Expr, stype);
153 } else {
154 /* Print a diagnostic */
155 Error ("Structs of this size are not supported");
156 /* Adjust the stack so we won't run in an internal error later */
157 pop (CF_PTR);
158 }
159
160 }
161
162 } else if (ED_IsBitField (Expr)) {
163
164 CodeMark AndPos;
165 CodeMark PushPos;
166
167 unsigned Mask;
168 unsigned Flags;
169
170 /* If the bit-field fits within one byte, do the following operations
171 ** with bytes.
172 */
173 if (Expr->BitOffs / CHAR_BITS == (Expr->BitOffs + Expr->BitWidth - 1) / CHAR_BITS) {
174 Expr->Type = type_uchar;
175 }
176
177 /* Determine code generator flags */
178 Flags = TypeOf (Expr->Type);
179
180 /* Assignment to a bit field. Get the address on stack for the store. */
181 PushAddr (Expr);
182
183 /* Load the value from the location */
184 Expr->Flags &= ~E_BITFIELD;
185 LoadExpr (CF_NONE, Expr);
186
187 /* Mask unwanted bits */
188 Mask = (0x0001U << Expr->BitWidth) - 1U;
189 GetCodePos (&AndPos);
190 g_and (Flags | CF_CONST, ~(Mask << Expr->BitOffs));
191
192 /* Push it on stack */
193 GetCodePos (&PushPos);
194 g_push (Flags, 0);
195
196 /* Read the expression on the right side of the '=' */
197 MarkedExprWithCheck (hie1, &Expr2);
198
199 /* Do type conversion if necessary. Beware: Do not use char type
200 ** here!
201 */
202 TypeConversion (&Expr2, ltype);
203
204 /* Special treatment if the value is constant. */
205 /* Beware: Expr2 may contain side effects, so there must not be
206 ** code generated for Expr2.
207 */
208 if (ED_IsConstAbsInt (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
209
210 /* Get the value and apply the mask */
211 unsigned Val = (unsigned) (Expr2.IVal & Mask);
212
213 /* Since we will do the OR with a constant, we can remove the push */
214 RemoveCode (&PushPos);
215
216 /* If the value is equal to the mask now, all bits are one, and we
217 ** can remove the mask operation from above.
218 */
219 if (Val == Mask) {
220 RemoveCode (&AndPos);
221 }
222
223 /* Generate the or operation */
224 g_or (Flags | CF_CONST, Val << Expr->BitOffs);
225
226 } else {
227
228 /* If necessary, load the value into the primary register */
229 LoadExpr (CF_NONE, &Expr2);
230
231 /* Apply the mask */
232 g_and (Flags | CF_CONST, Mask);
233
234 /* Shift it into the right position */
235 g_asl (Flags | CF_CONST, Expr->BitOffs);
236
237 /* Or both values */
238 g_or (Flags, 0);
239 }
240
241 /* Generate a store instruction */
242 Store (Expr, 0);
243
244 /* Restore the expression type */
245 Expr->Type = ltype;
246
247 } else {
248
249 /* Get the address on stack if needed */
250 PushAddr (Expr);
251
252 /* Read the expression on the right side of the '=' */
253 hie1 (&Expr2);
254
255 /* Do type conversion if necessary */
256 TypeConversion (&Expr2, ltype);
257
258 /* If necessary, load the value into the primary register */
259 LoadExpr (CF_NONE, &Expr2);
260
261 /* Generate a store instruction */
262 Store (Expr, 0);
263
264 }
265
266 /* Value is still in primary and not an lvalue */
267 ED_MakeRValExpr (Expr);
268}
269