]> git.sur5r.net Git - cc65/blob - src/cc65/shiftexpr.c
Move shift expression evaluation into a separate module. More checks and
[cc65] / src / cc65 / shiftexpr.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                shiftexpr.c                                */
4 /*                                                                           */
5 /*                       Parse the << and >> operators                       */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2004      Ullrich von Bassewitz                                       */
10 /*               Römerstraße 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     unsigned ExprBits;                  /* Bits of the lhs operand */
69     unsigned ltype, rtype, flags;
70     int rconst;                         /* Operand is a constant */
71
72
73     /* Evaluate the lhs */
74     ExprWithCheck (hie8, Expr);
75
76     while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
77
78         /* All operators that call this function expect an int on the lhs */
79         if (!IsClassInt (Expr->Type)) {
80             Error ("Integer expression expected");
81             ED_MakeConstAbsInt (Expr, 1);
82         }
83
84         /* Remember the operator token, then skip it */
85         Tok = CurTok.Tok;
86         NextToken ();
87
88         /* Calculate the number of bits the lhs operand has */
89         ExprBits = SizeOf (Expr->Type) * 8;
90
91         /* Get the lhs on stack */
92         Mark1 = GetCodePos ();
93         ltype = TypeOf (Expr->Type);
94         if (ED_IsConstAbs (Expr)) {
95             /* Constant value */
96             Mark2 = GetCodePos ();
97             g_push (ltype | CF_CONST, Expr->IVal);
98         } else {
99             /* Value not constant */
100             LoadExpr (CF_NONE, Expr);
101             Mark2 = GetCodePos ();
102             g_push (ltype, 0);
103         }
104
105         /* Get the right hand side */
106         ExprWithCheck (hie8, &Expr2);
107
108         /* Check the type of the rhs */
109         if (!IsClassInt (Expr2.Type)) {
110             Error ("Integer expression expected");
111             ED_MakeConstAbsInt (&Expr2, 1);
112         }
113
114         /* Check for a constant right side expression */
115         rconst = ED_IsConstAbs (&Expr2);
116         if (!rconst) {
117
118             /* Not constant, load into the primary */
119             LoadExpr (CF_NONE, &Expr2);
120
121         } else {
122
123             /* The rhs is a constant numeric value */
124
125             /* If the shift count is greater or equal than the bit count of
126              * the operand, the behaviour is undefined according to the
127              * standard.
128              */
129             if (Expr2.IVal < 0 || Expr2.IVal >= (long) ExprBits) {
130
131                 Warning ("Shift count too large for operand type");
132                 Expr2.IVal &= ExprBits - 1;
133
134             }
135
136             /* If the shift count is zero, nothing happens */
137             if (Expr2.IVal == 0) {
138
139                 /* Result is already in Expr, remove the generated code */
140                 RemoveCode (Mark1);
141                 pop (ltype);
142
143                 /* Done */
144                 goto Next;
145             }
146
147             /* If the left hand side is a constant, the result is constant */
148             if (ED_IsConstAbs (Expr)) {
149
150                 /* Evaluate the result */
151                 switch (Tok) {
152                     case TOK_SHL: Expr->IVal <<= Expr2.IVal; break;
153                     case TOK_SHR: Expr->IVal >>= Expr2.IVal; break;
154                     default: /* Shutup gcc */                break;
155                 }
156
157                 /* Both operands are constant, remove the generated code */
158                 RemoveCode (Mark1);
159                 pop (ltype);
160
161                 /* Done */
162                 goto Next;
163             }
164
165             /* If we're shifting an integer or unsigned to the right, the
166              * lhs has a const address, and the shift count is larger than 8,
167              * we can load just the high byte as a char with the correct
168              * signedness, and reduce the shift count by 8. If the remaining
169              * shift count is zero, we're done.
170              */
171             if (Tok == TOK_SHR &&
172                 IsTypeInt (Expr->Type) &&
173                 ED_IsLVal (Expr) &&
174                 (ED_IsLocConst (Expr) || ED_IsLocStack (Expr)) &&
175                 Expr2.IVal >= 8) {
176
177                 type* OldType;
178
179                 /* Increase the address by one and decrease the shift count */
180                 ++Expr->IVal;
181                 Expr2.IVal -= 8;
182
183                 /* Replace the type of the expression temporarily by the
184                  * corresponding char type.
185                  */
186                 OldType = Expr->Type;
187                 if (IsSignUnsigned (Expr->Type)) {
188                     Expr->Type = type_uchar;
189                 } else {
190                     Expr->Type = type_schar;
191                 }
192
193                 /* Remove the generated load code */
194                 RemoveCode (Mark1);
195                 pop (ltype);
196
197                 /* Generate again code for the load */
198                 LoadExpr (CF_NONE, Expr);
199
200                 /* Reset the type */
201                 Expr->Type = OldType;
202
203                 /* If the shift count is now zero, we're done */
204                 if (Expr2.IVal == 0) {
205                     /* Be sure to mark the value as in the primary */
206                     goto Loaded;
207                 }
208
209                 /* Otherwise generate code to push the value */
210                 Mark2 = GetCodePos ();
211                 g_push (ltype, 0);
212             }
213
214         }
215
216         /* If the right hand side is a constant, remove the push of the
217          * primary register.
218          */
219         rtype = TypeOf (Expr2.Type);
220         flags = 0;
221         if (rconst) {
222             flags |= CF_CONST;
223             rtype |= CF_CONST;
224             RemoveCode (Mark2);
225             pop (ltype);
226             ltype |= CF_REG;            /* Value is in register */
227         }
228
229         /* Determine the type of the operation result. */
230         flags |= g_typeadjust (ltype, rtype);
231
232         /* Generate code */
233         switch (Tok) {
234             case TOK_SHL: g_asl (flags, Expr2.IVal); break;
235             case TOK_SHR: g_asr (flags, Expr2.IVal); break;
236             default:                                 break;
237         }
238
239 Loaded:
240         /* We have a rvalue in the primary now */
241         ED_MakeRValExpr (Expr);
242
243 Next:
244         /* Get the type of the result */
245         Expr->Type = IntPromotion (Expr->Type);
246     }
247 }
248
249
250