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 | |
57 | void 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 | |