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
51static 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
93void 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