]> git.sur5r.net Git - cc65/blob - src/cc65/shiftexpr.c
Removed (pretty inconsistently used) tab chars from source code base.
[cc65] / src / cc65 / shiftexpr.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                shiftexpr.c                                */
4 /*                                                                           */
5 /*                       Parse the << and >> operators                       */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2004-2006 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     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
239
240