1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* shiftexpr.c */ |
4 | /* */ |
5 | /* Parse the << and >> operators */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2004-2006 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 "codegen.h" |
39 | #include "datatype.h" |
40 | #include "error.h" |
41 | #include "expr.h" |
42 | #include "exprdesc.h" |
43 | #include "loadexpr.h" |
44 | #include "scanner.h" |
45 | #include "shiftexpr.h" |
46 | |
47 | |
48 | |
49 | /*****************************************************************************/ |
50 | /* Data */ |
51 | /*****************************************************************************/ |
52 | |
53 | |
54 | |
55 | /*****************************************************************************/ |
56 | /* Code */ |
57 | /*****************************************************************************/ |
58 | |
59 | |
60 | |
61 | void ShiftExpr (struct ExprDesc* Expr) |
62 | /* Parse the << and >> operators. */ |
63 | { |
64 | ExprDesc Expr2; |
65 | CodeMark Mark1; |
66 | CodeMark Mark2; |
67 | token_t Tok; /* The operator token */ |
68 | Type* EffType; /* Effective lhs type */ |
69 | Type* ResultType; /* Type of the result */ |
70 | unsigned ExprBits; /* Bits of the lhs operand */ |
71 | unsigned GenFlags; /* Generator flags */ |
72 | unsigned ltype; |
73 | int rconst; /* Operand is a constant */ |
74 | |
75 | |
76 | /* Evaluate the lhs */ |
77 | ExprWithCheck (hie8, Expr); |
78 | |
79 | while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) { |
80 | |
81 | /* All operators that call this function expect an int on the lhs */ |
82 | if (!IsClassInt (Expr->Type)) { |
83 | Error ("Integer expression expected" ); |
84 | ED_MakeConstAbsInt (Expr, 1); |
85 | } |
86 | |
87 | /* Remember the operator token, then skip it */ |
88 | Tok = CurTok.Tok; |
89 | NextToken (); |
90 | |
91 | /* Get the type of the result */ |
92 | ResultType = EffType = IntPromotion (Expr->Type); |
93 | |
94 | /* Prepare the code generator flags */ |
95 | GenFlags = TypeOf (ResultType); |
96 | |
97 | /* Calculate the number of bits the lhs operand has */ |
98 | ExprBits = SizeOf (ResultType) * 8; |
99 | |
100 | /* Get the lhs on stack */ |
101 | GetCodePos (&Mark1); |
102 | ltype = TypeOf (Expr->Type); |
103 | if (ED_IsConstAbs (Expr)) { |
104 | /* Constant value */ |
105 | GetCodePos (&Mark2); |
106 | g_push (ltype | CF_CONST, Expr->IVal); |
107 | } else { |
108 | /* Value not constant */ |
109 | LoadExpr (CF_NONE, Expr); |
110 | GetCodePos (&Mark2); |
111 | g_push (ltype, 0); |
112 | } |
113 | |
114 | /* Get the right hand side */ |
115 | ExprWithCheck (hie8, &Expr2); |
116 | |
117 | /* Check the type of the rhs */ |
118 | if (!IsClassInt (Expr2.Type)) { |
119 | Error ("Integer expression expected" ); |
120 | ED_MakeConstAbsInt (&Expr2, 1); |
121 | } |
122 | |
123 | /* Check for a constant right side expression */ |
124 | rconst = ED_IsConstAbs (&Expr2); |
125 | if (!rconst) { |
126 | |
127 | /* Not constant, load into the primary */ |
128 | LoadExpr (CF_NONE, &Expr2); |
129 | |
130 | } else { |
131 | |
132 | /* The rhs is a constant numeric value. */ |
133 | GenFlags |= CF_CONST; |
134 | |
135 | /* Remove the code that pushes the rhs onto the stack. */ |
136 | RemoveCode (&Mark2); |
137 | |
138 | /* If the shift count is greater or equal than the bit count of |
139 | ** the operand, the behaviour is undefined according to the |
140 | ** standard. |
141 | */ |
142 | if (Expr2.IVal < 0 || Expr2.IVal >= (long) ExprBits) { |
143 | |
144 | Warning ("Shift count too large for operand type" ); |
145 | Expr2.IVal &= ExprBits - 1; |
146 | |
147 | } |
148 | |
149 | /* If the shift count is zero, nothing happens */ |
150 | if (Expr2.IVal == 0) { |
151 | |
152 | /* Result is already in Expr, remove the generated code */ |
153 | RemoveCode (&Mark1); |
154 | |
155 | /* Done */ |
156 | goto Next; |
157 | } |
158 | |
159 | /* If the left hand side is a constant, the result is constant */ |
160 | if (ED_IsConstAbs (Expr)) { |
161 | |
162 | /* Evaluate the result */ |
163 | switch (Tok) { |
164 | case TOK_SHL: Expr->IVal <<= Expr2.IVal; break; |
165 | case TOK_SHR: Expr->IVal >>= Expr2.IVal; break; |
166 | default: /* Shutup gcc */ break; |
167 | } |
168 | |
169 | /* Both operands are constant, remove the generated code */ |
170 | RemoveCode (&Mark1); |
171 | |
172 | /* Done */ |
173 | goto Next; |
174 | } |
175 | |
176 | /* If we're shifting an integer or unsigned to the right, the |
177 | ** lhs has a const address, and the shift count is larger than 8, |
178 | ** we can load just the high byte as a char with the correct |
179 | ** signedness, and reduce the shift count by 8. If the remaining |
180 | ** shift count is zero, we're done. |
181 | */ |
182 | if (Tok == TOK_SHR && |
183 | IsTypeInt (Expr->Type) && |
184 | ED_IsLVal (Expr) && |
185 | (ED_IsLocConst (Expr) || ED_IsLocStack (Expr)) && |
186 | Expr2.IVal >= 8) { |
187 | |
188 | Type* OldType; |
189 | |
190 | /* Increase the address by one and decrease the shift count */ |
191 | ++Expr->IVal; |
192 | Expr2.IVal -= 8; |
193 | |
194 | /* Replace the type of the expression temporarily by the |
195 | ** corresponding char type. |
196 | */ |
197 | OldType = Expr->Type; |
198 | if (IsSignUnsigned (Expr->Type)) { |
199 | Expr->Type = type_uchar; |
200 | } else { |
201 | Expr->Type = type_schar; |
202 | } |
203 | |
204 | /* Remove the generated load code */ |
205 | RemoveCode (&Mark1); |
206 | |
207 | /* Generate again code for the load, this time with the new type */ |
208 | LoadExpr (CF_NONE, Expr); |
209 | |
210 | /* Reset the type */ |
211 | Expr->Type = OldType; |
212 | |
213 | /* If the shift count is now zero, we're done */ |
214 | if (Expr2.IVal == 0) { |
215 | /* Be sure to mark the value as in the primary */ |
216 | goto MakeRVal; |
217 | } |
218 | } |
219 | |
220 | } |
221 | |
222 | /* Generate code */ |
223 | switch (Tok) { |
224 | case TOK_SHL: g_asl (GenFlags, Expr2.IVal); break; |
225 | case TOK_SHR: g_asr (GenFlags, Expr2.IVal); break; |
226 | default: break; |
227 | } |
228 | |
229 | MakeRVal: |
230 | /* We have a rvalue in the primary now */ |
231 | ED_MakeRValExpr (Expr); |
232 | |
233 | Next: |
234 | /* Set the type of the result */ |
235 | Expr->Type = ResultType; |
236 | } |
237 | } |
238 | |