996
|
1 /****************************************************************************
|
|
2
|
|
3 Name
|
|
4 dekludge.c -- C-INTERCAL expression and flow optimizers
|
|
5
|
|
6 DESCRIPTION
|
|
7 This file contains optimizations used by the C-INTERCAL compiler.
|
|
8
|
|
9 LICENSE TERMS
|
|
10 Copyright (C) 1996 Eric S. Raymond
|
|
11
|
|
12 This program is free software; you can redistribute it and/or modify
|
|
13 it under the terms of the GNU General Public License as published by
|
|
14 the Free Software Foundation; either version 2 of the License, or
|
|
15 (at your option) any later version.
|
|
16
|
|
17 This program is distributed in the hope that it will be useful,
|
|
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
20 GNU General Public License for more details.
|
|
21
|
|
22 You should have received a copy of the GNU General Public License
|
|
23 along with this program; if not, write to the Free Software
|
|
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
25
|
|
26 ****************************************************************************/
|
|
27 /*LINTLIBRARY */
|
|
28 #include "config.h"
|
|
29 #include <stdio.h>
|
|
30 #include <stdlib.h>
|
|
31 #include <string.h>
|
|
32 #include "sizes.h"
|
|
33 #include "ick.h"
|
|
34 #include "parser.h"
|
|
35 #include "fiddle.h"
|
|
36 #include "ick_lose.h"
|
|
37 #include "feh.h"
|
|
38
|
|
39 extern int emitlineno; /* AIS: From feh2.c */
|
|
40
|
|
41 /* AIS: The following macro produces optimization debug data. I added all
|
|
42 occurences of it in this source file. It also keeps track of whether
|
|
43 optimizations have taken place. */
|
|
44 #define OPTING(x) if(optdebug == 2) {\
|
|
45 explexpr(optdebugnode,stderr);\
|
|
46 putc('\n',stderr); } \
|
|
47 if(optdebug == 3) {\
|
|
48 prexpr(optdebugnode,stderr,0);\
|
|
49 putc('\n',stderr); } \
|
|
50 if(optdebug) fprintf(stderr,"[%s]",#x);\
|
|
51 if(optdebug >= 2) putc('\n',stderr);\
|
|
52 opted = 1;
|
|
53
|
|
54 void checknodeactbits(node *np); /* AIS: This prototype needed early */
|
|
55 extern void prexpr(node *np, FILE* fp, int freenode); /* AIS */
|
|
56
|
|
57 /* By AIS. This function looks remarkably like a C++ copy-constructor to me,
|
|
58 just with extra arrows in. The annotations here show that nulls are allowed
|
|
59 when called recursively, but not otherwise. */
|
|
60 /*@-incondefs@*/
|
|
61 /*@null@*/ node *nodecopy(/*@null@*/ const node* n)
|
|
62 /*@=incondefs@*/
|
|
63 {
|
|
64 node* np;
|
|
65 if(!n) return 0;
|
|
66 np = cons(n->opcode, nodecopy(n->lval), nodecopy(n->rval));
|
|
67 np->constant = n->constant;
|
|
68 np->optdata = n->optdata;
|
|
69 np->width = n->width;
|
|
70 return np;
|
|
71 }
|
|
72
|
|
73 /* This function by AIS. Compares expressions. In C++, I'd call this
|
|
74 node::operator== . */
|
|
75 ick_bool nodessame(/*@observer@*/ const node* n1, /*@observer@*/ const node* n2)
|
|
76 {
|
|
77 if(!n1) return !n2;
|
|
78 if(!n2) return 0;
|
|
79 if(n1->opcode!=n2->opcode)
|
|
80 return (((n1->opcode == MESH && n2->opcode == MESH32) ||
|
|
81 (n1->opcode == MESH32 && n2->opcode == MESH)) &&
|
|
82 n1->constant == n2->constant);
|
|
83 if(!nodessame(n1->lval,n2->lval)) return 0;
|
|
84 if(!nodessame(n1->rval,n2->rval)) return 0;
|
|
85 switch(n1->opcode)
|
|
86 {
|
|
87 case ick_ONESPOT:
|
|
88 case ick_TWOSPOT:
|
|
89 case ick_HYBRID:
|
|
90 case ick_TAIL:
|
|
91 case MESH:
|
|
92 case MESH32:
|
|
93 return n1->constant == n2->constant;
|
|
94 case AND:
|
|
95 case OR:
|
|
96 case XOR:
|
|
97 return n1->width == n2->width;
|
|
98 default:
|
|
99 return 1;
|
|
100 }
|
|
101 }
|
|
102
|
|
103 /* AIS: Checks if an abstention could affect a tuple. */
|
|
104 static int abstainmatch(int npconstant, int tptype)
|
|
105 {
|
|
106 if(npconstant == tptype) return 1;
|
|
107 if(npconstant == ABSTAIN)
|
|
108 if(tptype == FROM || tptype == MANYFROM || tptype == DISABLE) return 1;
|
|
109 if(npconstant == REINSTATE)
|
|
110 if(tptype == ENABLE) return 1;
|
|
111 if(npconstant == GETS)
|
|
112 if(tptype == RESIZE) return 1;
|
|
113 if(npconstant == UNKNOWN) /* JH */
|
|
114 if(tptype == SPLATTERED) return 1;
|
|
115 return 0;
|
|
116 }
|
|
117
|
|
118
|
|
119 /*************************************************************************
|
|
120 *
|
|
121 * AIS: Flow optimizer. (I wrote the whole of optimizef.)
|
|
122 *
|
|
123 * This analyses the flow of the program, checking to see which lines can
|
|
124 * have their guards omitted, which lines can be omitted altogether, which
|
|
125 * variables can never be ignored, etc. The degenerator lower down can take
|
|
126 * this information into account, producing faster and shorter source code.
|
|
127 * In an ideal world, we'd end up with the produced INTERCAL looking like
|
|
128 * proper C code, but somehow I think that's unlikely to happen.
|
|
129 * At the moment, it just checks for unused !ick_abstained[] guards on
|
|
130 * statements and removes them (possibly removing comments altogether).
|
|
131 * This is minor, but should clear up degenerated code substantially.
|
|
132 * It also allows the code for gets to replace ick_assign() with the faster =
|
|
133 * in cases where this doesn't affect the behaviour of the program.
|
|
134 * See the function itself for what I did to NEXT.
|
|
135 *
|
|
136 *************************************************************************/
|
|
137
|
|
138 void optimizef(void)
|
|
139 {
|
|
140 tuple* tp, *tpa, *tpb;
|
|
141 atom* op;
|
|
142 node* np;
|
|
143 if(!flowoptimize) ick_lose(IE778, iyylineno, (const char *) NULL);
|
|
144 for (tp = tuples; tp < tuples + ick_lineno; tp++) tp->abstainable = 0;
|
|
145 /* abstainable holds whether a line's abstention status can change */
|
|
146 for (op = oblist; op != NULL && op < obdex; op++) op->ignorable = 0;
|
|
147 /* ignorable holds whether a variable's ignorance status can change */
|
|
148 for (tp = tuples; tp < tuples + ick_lineno; tp++)
|
|
149 {
|
|
150 /* allow for warnings to be generated during flow optimisations */
|
|
151 /* AIS: I marked tuples as only deliberately, so that it produced warnings
|
|
152 when aliased in an unsafe way. However, tuples isn't realloced during
|
|
153 optimisation, so we can safely ignore the warning for it produced
|
|
154 here. */
|
|
155 /*@-onlytrans@*/
|
|
156 optuple = tp;
|
|
157 /*@=onlytrans@*/
|
|
158 if(tp->maybe) tp->abstainable = 1;
|
|
159 if(tp->exechance < 0) tp->initabstain = 1;
|
|
160 if(tp->exechance != 100 && tp->exechance != -100) tp->abstainable = 1;
|
|
161 if(tp->onceagainflag != onceagain_NORMAL) tp->abstainable = 1;
|
|
162 if(tp->type == ABSTAIN || tp->type == FROM)
|
|
163 {
|
|
164 tpa = tp->u.target - 1 + tuples;
|
|
165 if(tpa->exechance >= 0) tpa->abstainable = 1;
|
|
166 }
|
|
167 if(tp->type == REINSTATE)
|
|
168 {
|
|
169 tpa = tp->u.target - 1 + tuples;
|
|
170 if(tpa->exechance < 0) tpa->abstainable = 1;
|
|
171 }
|
|
172 if(tp->type == DISABLE || tp->type == MANYFROM)
|
|
173 {
|
|
174 for (tpa = tuples; tpa < tuples + ick_lineno; tpa++)
|
|
175 {
|
|
176 np = tp->u.node;
|
|
177 if(tp->type == MANYFROM) np = np->rval;
|
|
178 for(; np; np = np -> rval)
|
|
179 if(abstainmatch((int)np->constant, (int)tpa->type))
|
|
180 if(tpa->exechance >= 0) tpa->abstainable = 1;
|
|
181 }
|
|
182 }
|
|
183 if(tp->type == ENABLE)
|
|
184 {
|
|
185 for (tpa = tuples; tpa < tuples + ick_lineno; tpa++)
|
|
186 {
|
|
187 np = tp->u.node;
|
|
188 for(; np; np = np -> rval)
|
|
189 if(abstainmatch((int)np->constant, (int)tpa->type))
|
|
190 if(tpa->exechance < 0) tpa->abstainable = 1;
|
|
191 }
|
|
192 }
|
|
193 if(tp->type == GETS && ick_Base == 2 && !opoverused)
|
|
194 checknodeactbits(tp->u.node->rval);
|
|
195 /* If optdata shows that the value must always fit in the variable,
|
|
196 and the variable cannot be ignored, ick_assign can be replaced by the
|
|
197 cheaper =. */
|
|
198 if(tp->type == IGNORE)
|
|
199 {
|
|
200 for (np = tp->u.node; np; np = np->rval)
|
|
201 {
|
|
202 for (op = oblist; op != NULL && op < obdex; op++)
|
|
203 {
|
|
204 if(op->type == np->opcode && (unsigned long)op->intindex == np->constant)
|
|
205 op->ignorable = 1;
|
|
206 }
|
|
207 }
|
|
208 }
|
|
209 /* REMEMBERING variables has no effect on this code, because all
|
|
210 variables are initially remembered anyway, and so an IGNORE would
|
|
211 be needed (and caught above) to have an effect. */
|
|
212 }
|
|
213 /* There are some flow idioms that maybe should be optimized. The most
|
|
214 common is the NEXTing idiom for if(), which looks like this:
|
|
215
|
|
216 DO (1) NEXT
|
|
217 block 2
|
|
218 escape via NEXTING or COMEFROM
|
|
219 (1) DO (2) NEXT
|
|
220 DO FORGET #1
|
|
221 block 1
|
|
222
|
|
223 and elsewhere in the program:
|
|
224 (2) DO RESUME <1-or-2-condition>
|
|
225
|
|
226 Recognizing this idiom is quite difficult because there are a number of
|
|
227 problems and common variations.
|
|
228 First, the FORGET might be placed elsewhere, or replaced with a higher
|
|
229 FORGET later or a higher RESUME later. If there is, in fact, a RESUME #1
|
|
230 as the ick_next NEXT-control statement, the idiom won't quite work properly.
|
|
231 So to handle this, we need to push the original return address on the
|
|
232 NEXT stack if block 1 is taken, unless the ick_next statement is a FORGET #1.
|
|
233 Second, there may be abstentions or COME FROMs messing with control flow
|
|
234 in the area. The flow optimizer ought to be able to detect this and not
|
|
235 optimize the statement if true. (This means that a program which uses
|
|
236 gerund abstention on NEXTING or RESUMING, or that uses computed COME FROM,
|
|
237 will probably not benefit from this optimization). Third, how should a
|
|
238 <1-or-2-condition> be detected? Throughout syslib, the most common
|
|
239 condition to use is .5, which isn't inherently 1 or 2. The way round this
|
|
240 seems to be to detect a <1-or-2-assignment> as the previous statement,
|
|
241 again with checks for COME FROM and abstentions. (I treat MAYBE as a sort
|
|
242 of abstention, albeit a temporally undecided one.) So ignorance of the
|
|
243 relevant variable needs to be checked for also. The checks are done partly
|
|
244 in optimizef() and partly in emit().
|
|
245 */
|
|
246 if(compucomesused||ick_Base!=2||opoverused) return;
|
|
247
|
|
248 np = (node*) NULL;
|
|
249 for (tp = tuples; tp < tuples + ick_lineno; tp++)
|
|
250 {
|
|
251 if(tp->type == GETS)
|
|
252 {
|
|
253 /* if(tp->u.node->rval->opcode == C_AND1ADD1 ||
|
|
254 tp->u.node->rval->opcode == C_2SUBAND1 ||
|
|
255 ((tp->u.node->rval->opcode == C_1PLUS ||
|
|
256 tp->u.node->rval->opcode == C_2MINUS) &&
|
|
257 tp->u.node->rval->rval->optdata == 1)) //debug for now */ if(0)
|
|
258 {
|
|
259 /* This won't catch all <1-or-2-expressions>, but will get
|
|
260 most of them. */
|
|
261 if(tp->u.node->lval->opcode != SUB) np = tp->u.node->lval;
|
|
262 }
|
|
263 else if(np != NULL && nodessame(np, tp->u.node->lval)) np = (node*) NULL;
|
|
264 if(tp->nextable) np = (node*) NULL;
|
|
265 if(tp->maybe||tp->abstainable) np = (node*) NULL;
|
|
266 if(tp->ncomefrom&&multithread) np = (node*) NULL;
|
|
267 if(np)
|
|
268 { /* IGNORING np might prevent it getting its <1-or-2-value>. */
|
|
269 atom* op2;
|
|
270 int ignorable = 1;
|
|
271 for(op2 = oblist; op2 != NULL && op2 < obdex; op2++)
|
|
272 {
|
|
273 if(op2->type == np->opcode &&
|
|
274 (unsigned long)op2->intindex == np->constant)
|
|
275 {
|
|
276 ignorable &= op2->ignorable;
|
|
277 }
|
|
278 }
|
|
279 if(ignorable) np = (node*) NULL;
|
|
280 }
|
|
281 /* np will only have a nonnull value if it's a variable that must be
|
|
282 set to a <1-or-2-value> to reach line tp. Regardless of whether
|
|
283 maybes have been parsed or not, either maybe or abstainable or
|
|
284 both will be 1 on a MAYBE line. The last check is a precaution
|
|
285 against MAYBE COME FROM sneakily modifying a variable (although
|
|
286 I think it's unlikely that anyone would deliberately try to fool
|
|
287 -f like this, it is INTERCAL after all!) */
|
|
288 }
|
|
289 if(tp->type == COME_FROM || tp->type == COMPUCOME) np = (node*) NULL;
|
|
290 if(tp->type == NEXT)
|
|
291 {
|
|
292 tpa = tuples + tp->nexttarget - 1;
|
|
293 if(tpa->type == NEXT && !tp->abstainable && !tpa->abstainable
|
|
294 && !tp->ncomefrom && !tpa->ncomefrom)
|
|
295 {
|
|
296 tpb = tuples + tpa->nexttarget - 1;
|
|
297 if(tpb->type == RESUME && (/*(tpb->u.node->opcode == C_AND1ADD1 ||
|
|
298 tpb->u.node->opcode == C_2SUBAND1 ||
|
|
299 ((tpb->u.node->opcode == C_1PLUS ||
|
|
300 tpb->u.node->opcode == C_2MINUS) &&
|
|
301 tpb->u.node->rval->optdata == 1)) ||*/
|
|
302 (np != NULL && nodessame(tpb->u.node,np))) &&
|
|
303 !tpb->abstainable)
|
|
304 /* No COMING FROM a nonabstainable RESUME line! */
|
|
305 {
|
|
306 tp->optversion = ick_TRUE;
|
|
307 free(tp->u.node);
|
|
308 tp->u.node = nodecopy(tpb->u.node);
|
|
309 /* If tp->u.node is 2, then the statement should translate to a
|
|
310 no-op (NEXT...NEXT...RESUME #2). However, if tp->u.node is 1,
|
|
311 the statement should translate to a NEXT to the line after the
|
|
312 one it's aiming for. As it's aiming for a NEXT, the solution is
|
|
313 to NEXT to the return label of the NEXT it's aiming for. This
|
|
314 won't trigger any COME FROMs or ONCE/AGAIN flags, or even MAYBEs,
|
|
315 on the commands missed out, so the code has checked that they
|
|
316 aren't there. */
|
|
317 }
|
|
318 }
|
|
319 np = (node*) NULL;
|
|
320 }
|
|
321 }
|
|
322 /*@-nullstate@*/ /* no tuples->u.node can't be null */
|
|
323 }
|
|
324 /*@=nullstate@*/
|
|
325
|
|
326 /*************************************************************************
|
|
327 *
|
|
328 * Expression optimizer.
|
|
329 *
|
|
330 * It's not a very good optimizer, is it?
|
|
331 *
|
|
332 * AIS: All free'd pointers set to NULL, to help trace memory problems.
|
|
333 * The optimizer can now recognize the majority of syslib's idioms.
|
|
334 * The optimizer will make multiple passes. Although I am now happy
|
|
335 * with the quality of this optimizer, I'll keep the paragraph above
|
|
336 * this one for history's sake. The optimizing functions return 1
|
|
337 * if any optimizations were made, apart from optimize itself, which
|
|
338 * is void.
|
|
339 *
|
|
340 **************************************************************************/
|
|
341
|
|
342 extern int optimize_pass1(node *np); /* Read from idiotism.c */
|
|
343 static void checkforintercaloperators(const node *np);
|
|
344 static void checkW534(const node *np);
|
|
345
|
|
346 node* optdebugnode;
|
|
347
|
|
348 /* This function by AIS */
|
|
349 void optimize(node *np)
|
|
350 {
|
|
351 int optflag;
|
|
352 if(opoverused) return; /* what chance do we have of optimizing this? */
|
|
353 if(ick_Base==2)
|
|
354 {
|
|
355 checknodeactbits(np);
|
|
356 checkW534(np); /* This must be done before optimization, and depends on
|
|
357 checknodeactbits. */
|
|
358 }
|
|
359 if(optdebug == 1) explexpr(np,stderr);
|
|
360 if(optdebug == 1) fprintf(stderr," becomes ");
|
|
361 if(optdebug >= 2) optdebugnode = np;
|
|
362 if(ick_Base==2) (void) optimize_pass1(np); /* Optimize idioms; from idiotism.oil */
|
|
363 if(ick_Base!=2)
|
|
364 {
|
|
365 if(optdebug && optdebug != 3) explexpr(np,stderr);
|
|
366 if(optdebug == 3) prexpr(np,stderr,0);
|
|
367 if(optdebug) fprintf(stderr,"\n");
|
|
368 if(optdebug >= 2) fprintf(stderr,"-----\n");
|
|
369 return;
|
|
370 }
|
|
371 do
|
|
372 {
|
|
373 optflag = optimize_pass1(np);
|
|
374 } while(optflag); /* Keep optimizing until no optimizations are found */
|
|
375 if(optdebug && optdebug != 3) explexpr(np,stderr);
|
|
376 if(optdebug == 3) prexpr(np,stderr,0);
|
|
377 if(optdebug) fprintf(stderr,"\n");
|
|
378 if(optdebug >= 2) fprintf(stderr,"-----\n");
|
|
379 checkforintercaloperators(np);
|
|
380 if(optuple->type == RESUME && !np->optdata) optuple->warn622 = 1;
|
|
381 }
|
|
382
|
|
383 /* By AIS. This relies on free'd pointers being NULLed. The annotations
|
|
384 are basically trying to describe how the function operates. */
|
|
385 void nodefree(/*@keep@*/ /*@null@*/ node *np)
|
|
386 {
|
|
387 if(!np) return;
|
|
388 /*@-mustfreeonly@*/
|
|
389 if(np->nextslat) return; /* don't free, has oo data */
|
|
390 if(np==prevslat) return; /* likewise */
|
|
391 /*@=mustfreeonly@*/
|
|
392 /*@-keeptrans@*/
|
|
393 nodefree(np->lval);
|
|
394 nodefree(np->rval);
|
|
395 free(np);
|
|
396 /*@=keeptrans@*/
|
|
397 }
|
|
398
|
|
399 /* By AIS. This checks W534. */
|
|
400 static void checkW534(const node *np)
|
|
401 {
|
|
402 if(!np) return;
|
|
403 if(np->opcode == AND || np->opcode == OR || np->opcode == XOR)
|
|
404 {
|
|
405 if(np->rval->opcode == SELECT && np->rval->rval->width == 32 &&
|
|
406 !(np->rval->rval->optdata&0xffff0000lu))
|
|
407 {
|
|
408 /* This looks suspicious, in that C-INTERCAL will do an op32,
|
|
409 but INTERCAL-72 would have done an op16. */
|
|
410 optuple->warn534=1;
|
|
411 }
|
|
412 }
|
|
413 checkW534(np->lval);
|
|
414 checkW534(np->rval);
|
|
415 }
|
|
416
|
|
417 /* By AIS. This checks W018. */
|
|
418 static void checkforintercaloperators(const node *np)
|
|
419 {
|
|
420 if(!np) return;
|
|
421 switch(np->opcode)
|
|
422 { /* This only comes up in binary. */
|
|
423 case AND: case OR: case XOR: case MINGLE: case SELECT:
|
|
424 optuple->warn018 = 1;
|
|
425 break;
|
|
426 default:
|
|
427 checkforintercaloperators(np->lval);
|
|
428 checkforintercaloperators(np->rval);
|
|
429 return;
|
|
430 }
|
|
431 }
|
|
432
|
|
433 /* By AIS (with a few code fragments copied from elsewhere in this file)
|
|
434 This generates the values of c used by the OIL idiom file idiotism.oil. */
|
|
435 void checknodeactbits(node *np)
|
|
436 {
|
|
437 int temp;
|
|
438 if (np == (node *)NULL)
|
|
439 return;
|
|
440 else if (np->lval != (node *)NULL)
|
|
441 checknodeactbits(np->lval);
|
|
442 if (np->rval != (node *)NULL)
|
|
443 checknodeactbits(np->rval);
|
|
444
|
|
445 switch (np->opcode)
|
|
446 {
|
|
447 case MINGLE:
|
|
448 /*@-nullderef@*/ /* mingle has two nonnull arguments */
|
|
449 if(np->lval->optdata & 0xffff0000LU) optuple->warn276 = 1;
|
|
450 if(np->rval->optdata & 0xffff0000LU) optuple->warn276 = 1;
|
|
451 np->optdata = ick_mingle((unsigned)(np->lval->optdata & 0xffff),
|
|
452 (unsigned)(np->rval->optdata & 0xffff));
|
|
453 /*@=nullderef@*/
|
|
454 /* The bitmask is needed because the output of ~ might always be 16-bit
|
|
455 at runtime, but appear 32-bit at compile-time. But this is somewhat
|
|
456 suspicious, so we can at least give a warning (W276) if -l is used. */
|
|
457 break;
|
|
458
|
|
459 case SELECT:
|
|
460 /* The result could be the selected optdata, or have a 1 anywhere to the
|
|
461 right of a 1 in the resulting selection if there are 0s in rval where
|
|
462 there could have been 1s */
|
|
463 /*@-nullderef@*/
|
|
464 np->optdata = ick_iselect((unsigned)np->lval->optdata, (unsigned)np->rval->optdata);
|
|
465 /*@=nullderef@*/
|
|
466 temp=16;
|
|
467 while(temp--) np->optdata|=(np->optdata>>1); /* fill in gaps in optdata */
|
|
468 break;
|
|
469
|
|
470 case AND:
|
|
471 if(np->width==16)
|
|
472 np->optdata = ick_and16((unsigned)np->rval->optdata);
|
|
473 else
|
|
474 np->optdata = ick_and32((unsigned)np->rval->optdata);
|
|
475 break;
|
|
476
|
|
477 case OR:
|
|
478 case XOR:
|
|
479 if(np->width==16)
|
|
480 np->optdata = ick_or16((unsigned)np->rval->optdata);
|
|
481 else
|
|
482 np->optdata = ick_or32((unsigned)np->rval->optdata);
|
|
483 /* This is or in both cases. */
|
|
484 break;
|
|
485
|
|
486 case FIN:
|
|
487 case WHIRL:
|
|
488 case WHIRL2:
|
|
489 case WHIRL3:
|
|
490 case WHIRL4:
|
|
491 case WHIRL5: /* We must be in binary to reach this point, so: */
|
|
492 ick_lose(IE997, emitlineno, (const char*) NULL);
|
|
493 /*@-unreachable@*/
|
|
494 break;
|
|
495 /*@=unreachable@*/
|
|
496
|
|
497 case MESH:
|
|
498 case MESH32:
|
|
499 np->optdata = np->constant; /* It's trivial to tell which bits
|
|
500 can be nonzero! */
|
|
501 break;
|
|
502
|
|
503 case ick_ONESPOT:
|
|
504 case ick_TWOSPOT:
|
|
505 case ick_TAIL:
|
|
506 case ick_HYBRID:
|
|
507 case SUB:
|
|
508 np->optdata = np->width == 16 ? 0xffffLU : 0xffffffffLU;
|
|
509 break;
|
|
510
|
|
511 /* cases from here down are generated by optimize_pass1 */
|
|
512 case C_AND:
|
|
513 /*@-nullderef@*/
|
|
514 np->optdata = np->lval->optdata & np->rval->optdata;
|
|
515 /*@=nullderef@*/
|
|
516 break;
|
|
517
|
|
518 case C_OR:
|
|
519 case C_XOR:
|
|
520 /*@-nullderef@*/
|
|
521 np->optdata = np->lval->optdata | np->rval->optdata;
|
|
522 /*@=nullderef@*/
|
|
523 /* bitwise-or is correct in both cases */
|
|
524 break;
|
|
525
|
|
526 case C_NOT:
|
|
527 np->optdata = np->width == 16 ? 0xffffLU : 0xffffffffLU;
|
|
528 break;
|
|
529
|
|
530 case C_A:
|
|
531 np->optdata = 0xffffffffLU;
|
|
532 break;
|
|
533
|
|
534 case C_NOTEQUAL:
|
|
535 case C_ISEQUAL:
|
|
536 case C_LOGICALNOT:
|
|
537 case C_LOGICALAND:
|
|
538 case C_LOGICALOR:
|
|
539 case C_GREATER:
|
|
540 case C_LESS:
|
|
541 np->optdata = 1; /* this is a logical function */
|
|
542 break;
|
|
543
|
|
544 case C_RSHIFTBY:
|
|
545 /*@-nullderef@*/
|
|
546 if(np->rval->opcode == MESH || np->rval->opcode == MESH32)
|
|
547 np->optdata = np->lval->optdata >> np->rval->constant;
|
|
548 else np->optdata = (np->width == 16 ? 0xffffLU : 0xffffffffLU);
|
|
549 /*@=nullderef@*/
|
|
550 /* Play safe if the RHS isn't a constant */
|
|
551 break;
|
|
552
|
|
553 case C_LSHIFTBY:
|
|
554 /*@-nullderef@*/
|
|
555 if(np->rval->opcode == MESH || np->rval->opcode == MESH32)
|
|
556 np->optdata = np->lval->optdata << np->rval->constant;
|
|
557 else np->optdata = (np->width == 16 ? 0xffffLU : 0xffffffffLU);
|
|
558 /*@=nullderef@*/
|
|
559 /* Play safe if the RHS isn't a constant */
|
|
560 break;
|
|
561
|
|
562 case C_PLUS:
|
|
563 /* A bit could be set if it's set in either of the numbers, or if it's set
|
|
564 by a carry; so OR together the two numbers and their sum. */
|
|
565 /*@-nullderef@*/
|
|
566 np->optdata = np->lval->optdata | np->rval->optdata |
|
|
567 (np->lval->optdata + np->rval->optdata);
|
|
568 /*@=nullderef@*/
|
|
569 break;
|
|
570
|
|
571 case C_MINUS:
|
|
572 case C_DIVIDEBY:
|
|
573 /* The optimizer shouldn't be able to generate negative answers or
|
|
574 divisions by 0, so just fill in all bits from lval rightwards */
|
|
575 /*@-nullderef@*/
|
|
576 np->optdata = np->lval->optdata;
|
|
577 np->optdata |= np->optdata >> 1;
|
|
578 np->optdata |= np->optdata >> 2;
|
|
579 np->optdata |= np->optdata >> 4;
|
|
580 np->optdata |= np->optdata >> 8;
|
|
581 np->optdata |= np->optdata >> 16;
|
|
582 /*@=nullderef@*/
|
|
583 break;
|
|
584
|
|
585 case C_MODULUS:
|
|
586 /* The answer must be smaller than both inputs, but we can't tell anything
|
|
587 else */
|
|
588 /*@-nullderef@*/
|
|
589 np->optdata = np->lval->optdata;
|
|
590 if(np->rval->optdata < np->optdata) np->optdata = np->rval->optdata;
|
|
591 np->optdata |= np->optdata >> 1;
|
|
592 np->optdata |= np->optdata >> 2;
|
|
593 np->optdata |= np->optdata >> 4;
|
|
594 np->optdata |= np->optdata >> 8;
|
|
595 np->optdata |= np->optdata >> 16;
|
|
596 /*@=nullderef@*/
|
|
597 break;
|
|
598
|
|
599 case C_TIMES:
|
|
600 /* Convolve one set of active bits with the other, ORadding the results */
|
|
601 np->optdata=0;
|
|
602 temp=32;
|
|
603 /*@-nullderef@*/ /*@-shiftnegative@*/
|
|
604 while(temp--)
|
|
605 if(np->lval->optdata & (1LU << temp))
|
|
606 np->optdata = np->optdata | (np->rval->optdata << temp) |
|
|
607 ((np->rval->optdata << temp) + np->optdata);
|
|
608 /*@=nullderef@*/ /*@=shiftnegative@*/
|
|
609 break;
|
|
610
|
|
611 case GETS:
|
|
612 /* Of course, this doesn't return a value. So this uses the default
|
|
613 code just below it, which is why it doesn't end in break;. This
|
|
614 has its own case so that W276 can be given on an assignment. */
|
|
615 /*@-nullderef@*/
|
|
616 if(np->lval->optdata == 0xffff &&
|
|
617 np->rval->optdata & 0xffff0000lu) optuple->warn276 = 1;
|
|
618 /*@=nullderef@*/
|
|
619 /*@fallthrough@*/
|
|
620
|
|
621 case UNKNOWNOP:
|
|
622 default:
|
|
623 /*@-nullderef@*/
|
|
624 if(np->opcode == BY && !np->lval->optdata) optuple->warn239 = 1;
|
|
625 /*@=nullderef@*/
|
|
626 np->optdata = (np->width == 16 ? 0xffffLU : 0xffffffffLU);
|
|
627 /* Some values of opcode are used as placeholders, to save more than 1
|
|
628 piece of information in a node. The optdata for these is probably
|
|
629 irrelevant, but just in case, we mark all possible bits as active. */
|
|
630 break;
|
|
631 }
|
|
632 }
|