1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* loadexpr.c */ |
4 | /* */ |
5 | /* Load an expression into the primary register */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2004-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 "codegen.h" |
38 | #include "error.h" |
39 | #include "exprdesc.h" |
40 | #include "global.h" |
41 | #include "loadexpr.h" |
42 | |
43 | |
44 | |
45 | /*****************************************************************************/ |
46 | /* Code */ |
47 | /*****************************************************************************/ |
48 | |
49 | |
50 | |
51 | static void LoadConstant (unsigned Flags, ExprDesc* Expr) |
52 | /* Load the primary register with some constant value. */ |
53 | { |
54 | switch (ED_GetLoc (Expr)) { |
55 | |
56 | case E_LOC_ABS: |
57 | /* Number constant */ |
58 | g_getimmed (Flags | TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); |
59 | break; |
60 | |
61 | case E_LOC_GLOBAL: |
62 | /* Global symbol, load address */ |
63 | g_getimmed ((Flags | CF_EXTERNAL) & ~CF_CONST, Expr->Name, Expr->IVal); |
64 | break; |
65 | |
66 | case E_LOC_STATIC: |
67 | case E_LOC_LITERAL: |
68 | /* Static symbol or literal, load address */ |
69 | g_getimmed ((Flags | CF_STATIC) & ~CF_CONST, Expr->Name, Expr->IVal); |
70 | break; |
71 | |
72 | case E_LOC_REGISTER: |
73 | /* Register variable. Taking the address is usually not |
74 | ** allowed. |
75 | */ |
76 | if (IS_Get (&AllowRegVarAddr) == 0) { |
77 | Error ("Cannot take the address of a register variable" ); |
78 | } |
79 | g_getimmed ((Flags | CF_REGVAR) & ~CF_CONST, Expr->Name, Expr->IVal); |
80 | break; |
81 | |
82 | case E_LOC_STACK: |
83 | g_leasp (Expr->IVal); |
84 | break; |
85 | |
86 | default: |
87 | Internal ("Unknown constant type: %04X" , Expr->Flags); |
88 | } |
89 | } |
90 | |
91 | |
92 | |
93 | void LoadExpr (unsigned Flags, struct ExprDesc* Expr) |
94 | /* Load an expression into the primary register if it is not already there. */ |
95 | { |
96 | if (ED_IsLVal (Expr)) { |
97 | |
98 | /* Dereferenced lvalue. If this is a bit field its type is unsigned. |
99 | ** But if the field is completely contained in the lower byte, we will |
100 | ** throw away the high byte anyway and may therefore load just the |
101 | ** low byte. |
102 | */ |
103 | if (ED_IsBitField (Expr)) { |
104 | Flags |= (Expr->BitOffs + Expr->BitWidth <= CHAR_BITS)? CF_CHAR : CF_INT; |
105 | Flags |= CF_UNSIGNED; |
106 | } else { |
107 | Flags |= TypeOf (Expr->Type); |
108 | } |
109 | if (ED_NeedsTest (Expr)) { |
110 | Flags |= CF_TEST; |
111 | } |
112 | |
113 | switch (ED_GetLoc (Expr)) { |
114 | |
115 | case E_LOC_ABS: |
116 | /* Absolute: numeric address or const */ |
117 | g_getstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0); |
118 | break; |
119 | |
120 | case E_LOC_GLOBAL: |
121 | /* Global variable */ |
122 | g_getstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal); |
123 | break; |
124 | |
125 | case E_LOC_STATIC: |
126 | case E_LOC_LITERAL: |
127 | /* Static variable or literal in the literal pool */ |
128 | g_getstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal); |
129 | break; |
130 | |
131 | case E_LOC_REGISTER: |
132 | /* Register variable */ |
133 | g_getstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal); |
134 | break; |
135 | |
136 | case E_LOC_STACK: |
137 | /* Value on the stack */ |
138 | g_getlocal (Flags, Expr->IVal); |
139 | break; |
140 | |
141 | case E_LOC_PRIMARY: |
142 | /* The primary register - just test if necessary */ |
143 | if (Flags & CF_TEST) { |
144 | g_test (Flags); |
145 | } |
146 | break; |
147 | |
148 | case E_LOC_EXPR: |
149 | /* Reference to address in primary with offset in Expr */ |
150 | g_getind (Flags, Expr->IVal); |
151 | break; |
152 | |
153 | default: |
154 | Internal ("Invalid location in LoadExpr: 0x%04X" , ED_GetLoc (Expr)); |
155 | } |
156 | |
157 | /* Handle bit fields. The actual type may have been casted or |
158 | ** converted, so be sure to always use unsigned ints for the |
159 | ** operations. |
160 | */ |
161 | if (ED_IsBitField (Expr)) { |
162 | unsigned F = CF_INT | CF_UNSIGNED | CF_CONST | (Flags & CF_TEST); |
163 | /* Shift right by the bit offset */ |
164 | g_asr (F, Expr->BitOffs); |
165 | /* And by the width if the field doesn't end on an int boundary */ |
166 | if (Expr->BitOffs + Expr->BitWidth != CHAR_BITS && |
167 | Expr->BitOffs + Expr->BitWidth != INT_BITS) { |
168 | g_and (F, (0x0001U << Expr->BitWidth) - 1U); |
169 | } |
170 | } |
171 | |
172 | /* Expression was tested */ |
173 | ED_TestDone (Expr); |
174 | |
175 | } else { |
176 | /* An rvalue */ |
177 | if (ED_IsLocExpr (Expr)) { |
178 | if (Expr->IVal != 0) { |
179 | /* We have an expression in the primary plus a constant |
180 | ** offset. Adjust the value in the primary accordingly. |
181 | */ |
182 | Flags |= TypeOf (Expr->Type); |
183 | g_inc (Flags | CF_CONST, Expr->IVal); |
184 | } |
185 | } else { |
186 | /* Constant of some sort, load it into the primary */ |
187 | LoadConstant (Flags, Expr); |
188 | } |
189 | |
190 | /* Are we testing this value? */ |
191 | if (ED_NeedsTest (Expr)) { |
192 | /* Yes, force a test */ |
193 | Flags |= TypeOf (Expr->Type); |
194 | g_test (Flags); |
195 | ED_TestDone (Expr); |
196 | } |
197 | } |
198 | |
199 | } |
200 | |