Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20080622152459

Diff

Diff from 1.29 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/pcc/pcc/arch/arm/local2.c

Annotated File View

ragge
1.29
1 /*      $Id: local2.c,v 1.29 2008/06/22 15:24:59 ragge Exp $    */
gmcgarry
1.7
2 /*
3  * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
4  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
gmcgarry
1.1
30 #include <assert.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <stdlib.h>
34
35 #include "pass2.h"
36
ragge
1.10
37 extern void defalign(int);
38
ragge
1.18
39 #define exname(x) x
40
gmcgarry
1.21
41 char *rnames[] = {
42         "r0""r1""r2""r3","r4","r5""r6""r7",
43         "r8""r9""r10""fp""ip""sp""lr""pc",
44         "r0r1""r1r2""r2r3""r3r4""r4r5""r5r6",
45         "r6r7""r7r8""r8r9""r9r10",
46         "f0""f1""f2""f3""f4""f5""f6""f7",
47 };
48
49 /*
50  * Handling of integer constants.  We have 8 bits + an even
51  * number of rotates available as a simple immediate.
52  * If a constant isn't trivially representable, use an ldr
53  * and a subsequent sequence of orr operations.
54  */
55
56 static int
57 trepresent(const unsigned int val)
58 {
59         int i;
60 #define rotate_left(v, n) (v << n | v >> (32 - n))
61
62         for (i = 0i < 32i += 2)
63                 if (rotate_left(vali) <= 0xff)
64                         return 1;
65         return 0;
66 }
67
68 /*
69  * Return values are:
70  * 0 - output constant as is (should be covered by trepresent() above)
71  * 1 - 4 generate 1-4 instructions as needed.
72  */
73 static int
74 encode_constant(int constantint *values)
75 {
76         int tmp = constant;
77         int i = 0;
78         int first_bitvalue;
79
80         while (tmp) {
81                 first_bit = ffs(tmp);
82                 first_bit -= 1/* ffs indexes from 1, not 0 */
83                 first_bit &= ~1/* must use even bit offsets */
84
85                 value = tmp & (0xff << first_bit);
86                 values[i++] = value;
87                 tmp &= ~value;
88         }
89         return i;
90 }
91
92 #if 0
93 static void
94 load_constant(NODE *p)
95 {
96         int v = p->n_lval & 0xffffffff;
97         int reg = DECRA(p->n_reg1);
98
99         load_constant_into_reg(regv);
100 }
101 #endif
102
103 static void
104 load_constant_into_reg(int regint v)
105 {
106         if (trepresent(v))
107                 printf("\tmov %s,#%d\n"rnames[reg], v);
108         else if (trepresent(-v))
109                 printf("\tmvn %s,#%d\n"rnames[reg], -v);
110         else {
111                 int vals[4], nci;
112
113                 nc = encode_constant(vvals);
114                 for (i = 0i < nci++) {
115                         if (i == 0) {
gmcgarry
1.24
116                                 printf("\tmov %s,#%d" COM "load constant %d\n",
117                                     rnames[reg], vals[i], v);
gmcgarry
1.21
118                         } else {
119                                 printf("\torr %s,%s,#%d\n",     
120                                     rnames[reg], rnames[reg], vals[i]);
121                         }
122                 }
123         }
124 }
125
126 static TWORD ftype;
127
128 /*
129  * calculate stack size and offsets
130  */
131 static int
132 offcalc(struct interpass_prolog *ipp)
133 {
134         int addto;
135
136 #ifdef PCC_DEBUG
137         if (x2debug)
138                 printf("offcalc: p2maxautooff=%d\n"p2maxautooff);
139 #endif
140
141         addto = p2maxautooff;
142
143 #if 0
144         addto += 7;
145         addto &= ~7;
146 #endif
147
148 #ifdef PCC_DEBUG
149         if (x2debug)
150                 printf("offcalc: addto=%d\n"addto);
151 #endif
152
153         addto -= AUTOINIT / SZCHAR;
154
155         return addto;
156 }
157
158 void
159 prologue(struct interpass_prolog *ipp)
160 {
161         int addto;
162         int vals[4], nci;
163
164 #ifdef PCC_DEBUG
165         if (x2debug)
166                 printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%x, autos=%d, tmpnum=%d, lblnum=%d\n",
167                         ipp->ipp_ip.type,
168                         ipp->ipp_ip.lineno,
169                         ipp->ipp_name,
170                         ipp->ipp_vis,
171                         ipp->ipp_type,
172                         ipp->ipp_regs,
173                         ipp->ipp_autos,
174                         ipp->ip_tmpnum,
175                         ipp->ip_lblnum);
176 #endif
177
178         ftype = ipp->ipp_type;
179
180 #if 0
181         printf("\t.align 2\n");
182         if (ipp->ipp_vis)
183                 printf("\t.global %s\n"exname(ipp->ipp_name));
184         printf("\t.type %s,%%function\n"exname(ipp->ipp_name));
185 #endif
186         printf("%s:\n"exname(ipp->ipp_name));
187
188         /*
189          * We here know what register to save and how much to 
190          * add to the stack.
191          */
192         addto = offcalc(ipp);
193
194         printf("\tsub %s,%s,#%d\n"rnames[SP], rnames[SP], 16);
195         printf("\tmov %s,%s\n"rnames[IP], rnames[SP]);
196         printf("\tstmfd %s!,{%s,%s,%s,%s}\n"rnames[SP], rnames[FP],
197             rnames[IP], rnames[LR], rnames[PC]);
198         printf("\tsub %s,%s,#4\n"rnames[FP], rnames[IP]);
199
200         if (addto == 0)
201                 return;
202
203         if (trepresent(addto)) {
gmcgarry
1.22
204                 printf("\tsub %s,%s,#%d\n"rnames[SP], rnames[SP], addto);
gmcgarry
1.21
205         } else {
206                 nc = encode_constant(addtovals);
207                 for (i = 0i < nci++)
208                         printf("\tsub %s,%s,#%d\n",
209                             rnames[SP], rnames[SP], vals[i]);
210         }
211 }
212
213 void
214 eoftn(struct interpass_prolog *ipp)
215 {
216         if (ipp->ipp_ip.ip_lbl == 0)
217                 return/* no code needs to be generated */
218
219         /* struct return needs special treatment */
220         if (ftype == STRTY || ftype == UNIONTY) {
221                 assert(0);
222         } else {
223                 printf("\tldmea %s,{%s,%s,%s}\n"rnames[FP], rnames[FP],
224                     rnames[SP], rnames[PC]);
gmcgarry
1.22
225                 printf("\tadd %s,%s,#%d\n"rnames[SP], rnames[SP], 16);
gmcgarry
1.21
226         }
227         printf("\t.size %s,.-%s\n"exname(ipp->ipp_name),
228             exname(ipp->ipp_name));
229 }
230
231
gmcgarry
1.1
232 /*
gmcgarry
1.7
233  * these mnemonics match the order of the preprocessor decls
234  * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT
235  */
236
237 static char *
238 ccbranches[] = {
239         "beq",          /* branch if equal */
240         "bne",          /* branch if not-equal */
241         "ble",          /* branch if less-than-or-equal */
242         "blt",          /* branch if less-than */
243         "bge",          /* branch if greater-than-or-equal */
244         "bgt",          /* branch if greater-than */
245         /* what should these be ? */
246         "bls",          /* branch if lower-than-or-same */
247         "blo",          /* branch if lower-than */
248         "bhs",          /* branch if higher-than-or-same */
249         "bhi",          /* branch if higher-than */
250 };
251
252 /*
gmcgarry
1.1
253  * add/sub/...
254  *
255  * Param given:
256  */
257 void
258 hopcode(int fint o)
259 {
260         char *str;
261
262         switch (o) {
263         case PLUS:
264                 str = "add";
265                 break;
266         case MINUS:
267                 str = "sub";
268                 break;
269         case AND:
270                 str = "and";
271                 break;
272         case OR:
273                 str = "orr";
274                 break;
275         case ER:
276                 str = "eor";
277                 break;
278         default:
279                 comperr("hopcode2: %d"o);
280                 str = 0/* XXX gcc */
281         }
282         printf("%s%c"strf);
283 }
284
285 /*
286  * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
287  */
288 int
289 tlen(NODE *p)
290 {
291         switch(p->n_type) {
292                 case CHAR:
293                 case UCHAR:
294                         return(1);
295
296                 case SHORT:
297                 case USHORT:
298                         return(SZSHORT/SZCHAR);
299
300                 case DOUBLE:
301                         return(SZDOUBLE/SZCHAR);
302
303                 case INT:
304                 case UNSIGNED:
305                 case LONG:
306                 case ULONG:
307                         return(SZINT/SZCHAR);
308
309                 case LONGLONG:
310                 case ULONGLONG:
311                         return SZLONGLONG/SZCHAR;
312
313                 default:
314                         if (!ISPTR(p->n_type))
315                                 comperr("tlen type %d not pointer");
316                         return SZPOINT(p->n_type)/SZCHAR;
317                 }
318 }
319
320 /*
321  * Emit code to compare two longlong numbers.
322  */
323 static void
324 twollcomp(NODE *p)
325 {
326         int o = p->n_op;
327         int s = getlab();
328         int e = p->n_label;
329         int cb1cb2;
330
331         if (o >= ULE)
332                 o -= (ULE-LE);
333         switch (o) {
334         case NE:
335                 cb1 = 0;
336                 cb2 = NE;
337                 break;
338         case EQ:
339                 cb1 = NE;
340                 cb2 = 0;
341                 break;
342         case LE:
343         case LT:
344                 cb1 = GT;
345                 cb2 = LT;
346                 break;
347         case GE:
348         case GT:
349                 cb1 = LT;
350                 cb2 = GT;
351                 break;
352         
353         default:
354                 cb1 = cb2 = 0/* XXX gcc */
355         }
356         if (p->n_op >= ULE)
357                 cb1 += 4cb2 += 4;
gmcgarry
1.19
358         expand(p0"\tcmp UR,UL" COM "compare 64-bit values (upper)\n");
gmcgarry
1.1
359         if (cb1cbgen(cb1s);
360         if (cb2cbgen(cb2e);
gmcgarry
1.19
361         expand(p0"\tcmp AR,AL" COM "(and lower)\n");
gmcgarry
1.1
362         cbgen(p->n_ope);
363         deflab(s);
364 }
365
stefan
1.9
366 int
gmcgarry
1.15
367 fldexpand(NODE *pint cookiechar **cp)
stefan
1.9
368 {
gmcgarry
1.15
369         CONSZ val;
370         int shft;
371
372         if (p->n_op == ASSIGN)
373                 p = p->n_left;
374
375         if (features(FEATURE_BIGENDIAN))
376                 shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval);
377         else
378                 shft = UPKFOFF(p->n_rval);
379
380         switch (**cp) {
381         case 'S':
382                 printf("#%d"UPKFSZ(p->n_rval));
383                 break;
384         case 'H':
385                 printf("#%d"shft);
386                 break;
387         case 'M':
388         case 'N':
389                 val = (CONSZ)1 << UPKFSZ(p->n_rval);
390                 --val;
391                 val <<= shft;
392                 printf("%lld", (**cp == 'M' ? val : ~val)  & 0xffffffff);
393                 break;
394         default:
395                 comperr("fldexpand");
396         }
397         return 1;
stefan
1.9
398 }
399
gmcgarry
1.1
400
401 /*
gmcgarry
1.28
402  * Structure assignment.
gmcgarry
1.1
403  */
404 static void
405 stasg(NODE *p)
406 {
gmcgarry
1.7
407         NODE *l = p->n_left;
gmcgarry
1.24
408         int val = l->n_lval;
gmcgarry
1.7
409
gmcgarry
1.28
410         /* R0 = dest, R1 = src, R2 = len */
gmcgarry
1.24
411         load_constant_into_reg(R2p->n_stsize);
gmcgarry
1.28
412         if (l->n_op == OREG) {
413                 if (R2TEST(regno(l))) {
414                         int r = regno(l);
415                         printf("\tadd %s,%s,lsl #%d\n",
416                             rnames[R0], rnames[R2UPK2(r)], R2UPK3(r));
417                         printf("\tadd %s,%s,%s\n"rnames[R0], rnames[R0],
418                             rnames[R2UPK1(r)]);
419                 } else  {
420                         if (trepresent(val)) {
421                                 printf("\tadd %s,%s,#%d\n",
422                                     rnames[R0], rnames[regno(l)], val);
423                         } else {
424                                 load_constant_into_reg(R0val);
425                                 printf("\tadd %s,%s,%s\n"rnames[R0],
426                                     rnames[R0], rnames[regno(l)]);
427                         }
gmcgarry
1.24
428                 }
gmcgarry
1.28
429         } else if (l->n_op == NAME) {
430                 cerror("not implemented");
gmcgarry
1.24
431         }
gmcgarry
1.28
432
gmcgarry
1.1
433         printf("\tbl %s\n"exname("memcpy"));
434 }
435
436 static void
gmcgarry
1.7
437 shiftop(NODE *p)
gmcgarry
1.1
438 {
gmcgarry
1.7
439         NODE *r = p->n_right;
440         TWORD ty = p->n_type;
ragge
1.16
441         char *shifttype;
gmcgarry
1.7
442
443         if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) {
444                 expand(pINBREG"\tmov A1,AL,lsr ");
gmcgarry
1.19
445                 printf(CONFMT COM "64-bit left-shift\n"32 - r->n_lval);
gmcgarry
1.7
446                 expand(pINBREG"\tmov U1,UL,asl AR\n");
447                 expand(pINBREG"\torr U1,U1,A1\n");
448                 expand(pINBREG"\tmov A1,AL,asl AR\n");
449         } else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) {
gmcgarry
1.21
450                 expand(pINBREG"\tmov A1,#0" COM "64-bit left-shift\n");
ragge
1.16
451                 expand(pINBREG"\tmov U1,AL");
452                 if (r->n_lval - 32 != 0)
453                         printf(",asl " CONFMTr->n_lval - 32);
454                 printf("\n");
gmcgarry
1.7
455         } else if (p->n_op == LS && r->n_op == ICON) {
gmcgarry
1.21
456                 expand(pINBREG"\tmov A1,#0" COM "64-bit left-shift\n");
457                 expand(pINBREG"\tmov U1,#0\n");
gmcgarry
1.7
458         } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) {
459                 expand(pINBREG"\tmov U1,UL,asl ");
gmcgarry
1.19
460                 printf(CONFMT COM "64-bit right-shift\n"32 - r->n_lval);
gmcgarry
1.7
461                 expand(pINBREG"\tmov A1,AL,lsr AR\n");
462                 expand(pINBREG"\torr A1,A1,U1\n");
463                 if (ty == LONGLONG)
464                         expand(pINBREG"\tmov U1,UL,asr AR\n");
465                 else
466                         expand(pINBREG"\tmov U1,UL,lsr AR\n");
467         } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) {
468                 if (ty == LONGLONG) {
gmcgarry
1.21
469                         expand(pINBREG"\tmvn U1,#1" COM "64-bit right-shift\n");
ragge
1.16
470                         expand(pINBREG"\tmov A1,UL");
471                         shifttype = "asr";
gmcgarry
1.7
472                 }else {
gmcgarry
1.21
473                         expand(pINBREG"\tmov U1,#0" COM "64-bit right-shift\n");
ragge
1.16
474                         expand(pINBREG"\tmov A1,UL");
475                         shifttype = "lsr";
gmcgarry
1.7
476                 }
ragge
1.16
477                 if (r->n_lval - 32 != 0)
478                         printf(",%s " CONFMTshifttyper->n_lval - 32);
479                 printf("\n");
gmcgarry
1.26
480         } else if (p->n_op == RS && r->n_op == ICON) {
gmcgarry
1.21
481                 expand(pINBREG"\tmov A1,#0" COM "64-bit right-shift\n");
482                 expand(pINBREG"\tmov U1,#0\n");
gmcgarry
1.1
483         }
484 }
485
486 /*
gmcgarry
1.7
487  * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
gmcgarry
1.1
488  */
489 static void
gmcgarry
1.7
490 fpemul(NODE *p)
gmcgarry
1.1
491 {
gmcgarry
1.7
492         NODE *l = p->n_left;
493         char *ch = NULL;
494
495         if (p->n_op == PLUS && p->n_type == FLOATch = "addsf3";
496         else if (p->n_op == PLUS && p->n_type == DOUBLEch = "adddf3";
gmcgarry
1.21
497         else if (p->n_op == PLUS && p->n_type == LDOUBLEch = "adddf3";
gmcgarry
1.7
498
499         else if (p->n_op == MINUS && p->n_type == FLOATch = "subsf3";
500         else if (p->n_op == MINUS && p->n_type == DOUBLEch = "subdf3";
gmcgarry
1.21
501         else if (p->n_op == MINUS && p->n_type == LDOUBLEch = "subdf3";
gmcgarry
1.7
502
503         else if (p->n_op == MUL && p->n_type == FLOATch = "mulsf3";
504         else if (p->n_op == MUL && p->n_type == DOUBLEch = "muldf3";
gmcgarry
1.21
505         else if (p->n_op == MUL && p->n_type == LDOUBLEch = "muldf3";
gmcgarry
1.7
506
507         else if (p->n_op == DIV && p->n_type == FLOATch = "divsf3";
508         else if (p->n_op == DIV && p->n_type == DOUBLEch = "divdf3";
gmcgarry
1.21
509         else if (p->n_op == DIV && p->n_type == LDOUBLEch = "divdf3";
gmcgarry
1.7
510
511         else if (p->n_op == UMINUS && p->n_type == FLOATch = "negsf2";
512         else if (p->n_op == UMINUS && p->n_type == DOUBLEch = "negdf2";
gmcgarry
1.21
513         else if (p->n_op == UMINUS && p->n_type == LDOUBLEch = "negdf2";
gmcgarry
1.7
514
515         else if (p->n_op == EQ && l->n_type == FLOATch = "eqsf2";
516         else if (p->n_op == EQ && l->n_type == DOUBLEch = "eqdf2";
gmcgarry
1.21
517         else if (p->n_op == EQ && l->n_type == LDOUBLEch = "eqdf2";
gmcgarry
1.7
518
519         else if (p->n_op == NE && l->n_type == FLOATch = "nesf2";
520         else if (p->n_op == NE && l->n_type == DOUBLEch = "nedf2";
gmcgarry
1.21
521         else if (p->n_op == NE && l->n_type == LDOUBLEch = "nedf2";
gmcgarry
1.7
522
523         else if (p->n_op == GE && l->n_type == FLOATch = "gesf2";
524         else if (p->n_op == GE && l->n_type == DOUBLEch = "gedf2";
gmcgarry
1.21
525         else if (p->n_op == GE && l->n_type == LDOUBLEch = "gedf2";
gmcgarry
1.7
526
527         else if (p->n_op == LE && l->n_type == FLOATch = "lesf2";
528         else if (p->n_op == LE && l->n_type == DOUBLEch = "ledf2";
gmcgarry
1.21
529         else if (p->n_op == LE && l->n_type == LDOUBLEch = "ledf2";
gmcgarry
1.7
530
531         else if (p->n_op == GT && l->n_type == FLOATch = "gtsf2";
532         else if (p->n_op == GT && l->n_type == DOUBLEch = "gtdf2";
gmcgarry
1.21
533         else if (p->n_op == GT && l->n_type == LDOUBLEch = "gtdf2";
gmcgarry
1.7
534
535         else if (p->n_op == LT && l->n_type == FLOATch = "ltsf2";
536         else if (p->n_op == LT && l->n_type == DOUBLEch = "ltdf2";
gmcgarry
1.21
537         else if (p->n_op == LT && l->n_type == LDOUBLEch = "ltdf2";
gmcgarry
1.7
538
539         else if (p->n_op == SCONV && p->n_type == FLOAT) {
540                 if (l->n_type == DOUBLEch = "truncdfsf2";
gmcgarry
1.21
541                 else if (l->n_type == LDOUBLEch = "truncdfsf2";
gmcgarry
1.28
542                 else if (l->n_type == ULONGLONGch = "floatunsdisf";
gmcgarry
1.21
543                 else if (l->n_type == LONGLONGch = "floatdisf";
544                 else if (l->n_type == LONGch = "floatsisf";
545                 else if (l->n_type == ULONGch = "floatunsisf";
gmcgarry
1.7
546                 else if (l->n_type == INTch = "floatsisf";
547                 else if (l->n_type == UNSIGNEDch = "floatunsisf";
548         } else if (p->n_op == SCONV && p->n_type == DOUBLE) {
549                 if (l->n_type == FLOATch = "extendsfdf2";
550                 else if (l->n_type == LDOUBLEch = "trunctfdf2";
gmcgarry
1.21
551                 else if (l->n_type == ULONGLONGch = "floatunsdidf";
552                 else if (l->n_type == LONGLONGch = "floatdidf";
553                 else if (l->n_type == LONGch = "floatsidf";
554                 else if (l->n_type == ULONGch = "floatunsidf";
gmcgarry
1.7
555                 else if (l->n_type == INTch = "floatsidf";
556                 else if (l->n_type == UNSIGNEDch = "floatunsidf";
557         } else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
gmcgarry
1.21
558                 if (l->n_type == FLOATch = "extendsfdf2";
559                 else if (l->n_type == DOUBLEch = "extenddftd2";
gmcgarry
1.28
560                 else if (l->n_type == ULONGLONGch = "floatunsdidf";
gmcgarry
1.21
561                 else if (l->n_type == LONGLONGch = "floatdidf";
562                 else if (l->n_type == LONGch = "floatsidf";
563                 else if (l->n_type == ULONGch = "floatunsidf";
564                 else if (l->n_type == INTch = "floatsidf";
565                 else if (l->n_type == UNSIGNEDch = "floatunsidf";
gmcgarry
1.7
566         } else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
gmcgarry
1.21
567                 if (l->n_type == FLOATch = "fixunssfdi";
568                 else if (l->n_type == DOUBLEch = "fixunsdfdi";
569                 else if (l->n_type == LDOUBLEch = "fixunsdfdi";
gmcgarry
1.7
570         } else if (p->n_op == SCONV && p->n_type == LONGLONG) {
571                 if (l->n_type == FLOATch = "fixsfdi";
572                 else if (l->n_type == DOUBLEch = "fixdfdi";
gmcgarry
1.21
573                 else if (l->n_type == LDOUBLEch = "fixdfdi";
574         } else if (p->n_op == SCONV && p->n_type == LONG) {
575                 if (l->n_type == FLOATch = "fixsfsi";
576                 else if (l->n_type == DOUBLEch = "fixdfsi";
577                 else if (l->n_type == LDOUBLEch = "fixdfsi";
gmcgarry
1.7
578         } else if (p->n_op == SCONV && p->n_type == ULONG) {
579                 if (l->n_type == FLOATch = "fixunssfdi";
580                 else if (l->n_type == DOUBLEch = "fixunsdfdi";
gmcgarry
1.21
581                 else if (l->n_type == LDOUBLEch = "fixunsdfdi";
gmcgarry
1.7
582         } else if (p->n_op == SCONV && p->n_type == INT) {
583                 if (l->n_type == FLOATch = "fixsfsi";
584                 else if (l->n_type == DOUBLEch = "fixdfsi";
gmcgarry
1.21
585                 else if (l->n_type == LDOUBLEch = "fixdfsi";
gmcgarry
1.7
586         } else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
587                 if (l->n_type == FLOATch = "fixunssfsi";
588                 else if (l->n_type == DOUBLEch = "fixunsdfsi";
gmcgarry
1.21
589                 else if (l->n_type == LDOUBLEch = "fixunsdfsi";
gmcgarry
1.7
590         }
591
592         if (ch == NULLcomperr("ZF: op=0x%x (%d)\n"p->n_opp->n_op);
593
gmcgarry
1.19
594         printf("\tbl __%s" COM "softfloat operation\n"exname(ch));
gmcgarry
1.7
595
596         if (p->n_op >= EQ && p->n_op <= GT)
597                 printf("\tcmp %s,#0\n"rnames[R0]);
gmcgarry
1.1
598 }
599
gmcgarry
1.7
600
gmcgarry
1.1
601 /*
gmcgarry
1.7
602  * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
gmcgarry
1.1
603  */
gmcgarry
1.7
604
gmcgarry
1.1
605 static void
gmcgarry
1.7
606 emul(NODE *p)
gmcgarry
1.1
607 {
gmcgarry
1.7
608         char *ch = NULL;
609
gmcgarry
1.27
610         if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONGch = "ashldi3";
611         else if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGch = "ashlsi3";
gmcgarry
1.7
612         else if (p->n_op == LS && DEUNSIGN(p->n_type) == INTch = "ashlsi3";
613
gmcgarry
1.27
614         else if (p->n_op == RS && p->n_type == ULONGLONGch = "lshrdi3";
615         else if (p->n_op == RS && p->n_type == ULONGch = "lshrsi3";
gmcgarry
1.7
616         else if (p->n_op == RS && p->n_type == UNSIGNEDch = "lshrsi3";
617
gmcgarry
1.27
618         else if (p->n_op == RS && p->n_type == LONGLONGch = "ashrdi3";
619         else if (p->n_op == RS && p->n_type == LONGch = "ashrsi3";
gmcgarry
1.7
620         else if (p->n_op == RS && p->n_type == INTch = "ashrsi3";
621         
gmcgarry
1.21
622         else if (p->n_op == DIV && p->n_type == LONGLONGch = "divdi3";
gmcgarry
1.27
623         else if (p->n_op == DIV && p->n_type == LONGch = "divsi3";
gmcgarry
1.7
624         else if (p->n_op == DIV && p->n_type == INTch = "divsi3";
625
gmcgarry
1.21
626         else if (p->n_op == DIV && p->n_type == ULONGLONGch = "udivdi3";
gmcgarry
1.27
627         else if (p->n_op == DIV && p->n_type == ULONGch = "udivsi3";
gmcgarry
1.7
628         else if (p->n_op == DIV && p->n_type == UNSIGNEDch = "udivsi3";
629
gmcgarry
1.21
630         else if (p->n_op == MOD && p->n_type == LONGLONGch = "moddi3";
gmcgarry
1.27
631         else if (p->n_op == MOD && p->n_type == LONGch = "modsi3";
gmcgarry
1.7
632         else if (p->n_op == MOD && p->n_type == INTch = "modsi3";
633
gmcgarry
1.21
634         else if (p->n_op == MOD && p->n_type == ULONGLONGch = "umoddi3";
gmcgarry
1.27
635         else if (p->n_op == MOD && p->n_type == ULONGch = "umodsi3";
gmcgarry
1.7
636         else if (p->n_op == MOD && p->n_type == UNSIGNEDch = "umodsi3";
637
gmcgarry
1.21
638         else if (p->n_op == MUL && p->n_type == LONGLONGch = "muldi3";
gmcgarry
1.27
639         else if (p->n_op == MUL && p->n_type == LONGch = "mulsi3";
gmcgarry
1.7
640         else if (p->n_op == MUL && p->n_type == INTch = "mulsi3";
641
gmcgarry
1.27
642         else if (p->n_op == UMINUS && p->n_type == LONGLONGch = "negdi2";
643         else if (p->n_op == UMINUS && p->n_type == LONGch = "negsi2";
644         else if (p->n_op == UMINUS && p->n_type == INTch = "negsi2";
gmcgarry
1.1
645
gmcgarry
1.7
646         else ch = 0comperr("ZE");
gmcgarry
1.19
647         printf("\tbl __%s" COM "emulated operation\n"exname(ch));
gmcgarry
1.1
648 }
649
gmcgarry
1.14
650 static void
651 halfword(NODE *p)
652 {
ragge
1.17
653         NODE *r = getlr(p'R');
654         NODE *l = getlr(p'L');
gmcgarry
1.14
655         int idx0 = 0idx1 = 1;
656
657         if (features(FEATURE_BIGENDIAN)) {
658                 idx0 = 1;
659                 idx1 = 0;
660         }
661
662         if (p->n_op == ASSIGN && r->n_op == OREG) {
663                 /* load */
664                 expand(p0"\tldrb A1,");
665                 printf("[%s," CONFMT "]\n"rnames[r->n_rval], r->n_lval+idx0);
666                 expand(p0"\tldrb AL,");
667                 printf("[%s," CONFMT "]\n"rnames[r->n_rval], r->n_lval+idx1);
668                 expand(p0"\torr AL,A1,AL,asl #8\n");
669         } else if (p->n_op == ASSIGN && l->n_op == OREG) {
670                 /* store */
671                 expand(p0"\tstrb AR,");
672                 printf("[%s," CONFMT "]\n"rnames[l->n_rval], l->n_lval+idx0);
673                 expand(p0"\tmov A1,AR,asr #8\n");
674                 expand(p0"\tstrb A1,");
675                 printf("[%s," CONFMT "]\n"rnames[l->n_rval], l->n_lval+idx1);
676         } else if (p->n_op == SCONV || p->n_op == UMUL) {
677                 /* load */
678                 expand(p0"\tldrb A1,");
ragge
1.17
679                 printf("[%s," CONFMT "]\n"rnames[l->n_rval], l->n_lval+idx0);
680                 expand(p0"\tldrb A2,");
681                 printf("[%s," CONFMT "]\n"rnames[l->n_rval], l->n_lval+idx1);
682                 expand(p0"\torr A1,A1,A2,asl #8\n");
gmcgarry
1.14
683         } else if (p->n_op == NAME || p->n_op == ICON || p->n_op == OREG) {
684                 /* load */
685                 expand(p0"\tldrb A1,");
686                 printf("[%s," CONFMT "]\n"rnames[p->n_rval], p->n_lval+idx0);
687                 expand(p0"\tldrb A2,");
688                 printf("[%s," CONFMT "]\n"rnames[p->n_rval], p->n_lval+idx1);
689                 expand(p0"\torr A1,A1,A2,asl #8\n");
690         } else {
691                 comperr("halfword");
692         }
693 }
694
gmcgarry
1.15
695 static void
696 bfext(NODE *p)
697 {
698         int sz;
699
700         if (ISUNSIGNED(p->n_right->n_type))
701                 return;
702         sz = 32 - UPKFSZ(p->n_left->n_rval);
703
704         expand(p0"\tmov AD,AD,asl ");
705         printf("#%d\n"sz);
706         expand(p0"\tmov AD,AD,asr ");
707         printf("#%d\n"sz);
708 }
709
gmcgarry
1.1
710 static int
711 argsiz(NODE *p)
712 {
713         TWORD t = p->n_type;
714
715         if (t < LONGLONG || t == FLOAT || t > BTMASK)
716                 return 4;
gmcgarry
1.23
717         if (t == LONGLONG || t == ULONGLONG)
718                 return 8;
719         if (t == DOUBLE || t == LDOUBLE)
gmcgarry
1.1
720                 return 8;
721         if (t == STRTY || t == UNIONTY)
722                 return p->n_stsize;
723         comperr("argsiz");
724         return 0;
725 }
726
727 void
728 zzzcode(NODE *pint c)
729 {
730         int pr;
731
732         switch (c) {
733
gmcgarry
1.15
734         case 'B'/* bit-field sign extension */
735                 bfext(p);
gmcgarry
1.7
736                 break;
737
gmcgarry
1.1
738         case 'C':  /* remove from stack after subroutine call */
739                 pr = p->n_qual;
gmcgarry
1.7
740 #if 0
gmcgarry
1.1
741                 if (p->n_op == STCALL || p->n_op == USTCALL)
742                         pr += 4;
gmcgarry
1.7
743 #endif
gmcgarry
1.1
744                 if (p->n_op == UCALL)
745                         return/* XXX remove ZC from UCALL */
746                 if (pr > 0)
747                         printf("\tadd %s,%s,#%d\n"rnames[SP], rnames[SP], pr);
748                 break;
749
750         case 'D'/* Long long comparision */
751                 twollcomp(p);
752                 break;
753
gmcgarry
1.7
754         case 'E'/* print out emulated ops */
755                 emul(p);
756                 break;
gmcgarry
1.1
757
gmcgarry
1.7
758         case 'F'/* print out emulated floating-point ops */
759                 fpemul(p);
gmcgarry
1.1
760                 break;
761
gmcgarry
1.14
762         case 'H':               /* do halfword access */
763                 halfword(p);
764                 break;
765
gmcgarry
1.19
766         case 'I':               /* init constant */
767                 if (p->n_name[0] != '\0')
768                         comperr("named init");
gmcgarry
1.21
769                 load_constant_into_reg(DECRA(p->n_reg1),
770                     p->n_lval & 0xffffffff);
771                 break;
gmcgarry
1.1
772
gmcgarry
1.7
773         case 'J':               /* init longlong constant */
gmcgarry
1.21
774                 load_constant_into_reg(DECRA(p->n_reg1) - R0R1,
gmcgarry
1.7
775                     p->n_lval & 0xffffffff);
gmcgarry
1.21
776                 load_constant_into_reg(DECRA(p->n_reg1) - R0R1 + 1,
777                     (p->n_lval >> 32));
gmcgarry
1.7
778                 break;
gmcgarry
1.1
779
780         case 'O'/* 64-bit left and right shift operators */
gmcgarry
1.7
781                 shiftop(p);
gmcgarry
1.1
782                 break;
783
784         case 'Q'/* emit struct assign */
785                 stasg(p);
786                 break;
787
788         default:
789                 comperr("zzzcode %c"c);
790         }
791 }
792
793 /*ARGSUSED*/
794 int
795 rewfld(NODE *p)
796 {
797         return(1);
798 }
799
800 /*
801  * Does the bitfield shape match?
802  */
803 int
804 flshape(NODE *p)
805 {
806         int o = p->n_op;
807
808         if (o == OREG || o == REG || o == NAME)
809                 return SRDIR/* Direct match */
810         if (o == UMUL && shumul(p->n_left))
811                 return SROREG/* Convert into oreg */
812         return SRREG/* put it into a register */
813 }
814
815 /* INTEMP shapes must not contain any temporary registers */
816 /* XXX should this go away now? */
817 int
818 shtemp(NODE *p)
819 {
820         return 0;
821 #if 0
822         int r;
823
824         if (p->n_op == STARG )
825                 p = p->n_left;
826
827         switch (p->n_op) {
828         case REG:
829                 return (!istreg(p->n_rval));
830
831         case OREG:
832                 r = p->n_rval;
833                 if (R2TEST(r)) {
834                         if (istreg(R2UPK1(r)))
835                                 return(0);
836                         r = R2UPK2(r);
837                 }
838                 return (!istreg(r));
839
840         case UMUL:
841                 p = p->n_left;
842                 return (p->n_op != UMUL && shtemp(p));
843         }
844
845         if (optype(p->n_op) != LTYPE)
846                 return(0);
847         return(1);
848 #endif
849 }
850
851 void
852 adrcon(CONSZ val)
853 {
854         printf(CONFMTval);
855 }
856
857 void
858 conput(FILE *fpNODE *p)
859 {
860         char *s;
861         int val = p->n_lval;
862
863         switch (p->n_op) {
864         case ICON:
865 #if 0
866                 if (p->n_sp)
867                         printf(" [class=%d,level=%d] "p->n_sp->sclassp->n_sp->slevel);
868 #endif
ragge
1.18
869 #ifdef notdef   /* ICON cannot ever use sp here */
870                 /* If it does, it's a giant bug */
gmcgarry
1.1
871                 if (p->n_sp == NULL || (p->n_sp->sclass == ILABEL ||
872                    (p->n_sp->sclass == STATIC && p->n_sp->slevel > 0)))
873                         s = p->n_name;
874                 else
875                         s = exname(p->n_name);
ragge
1.18
876 #else
877                 s = p->n_name;
878 #endif
gmcgarry
1.1
879                         
880                 if (*s != '\0') {
881                         fprintf(fp"%s"s);
882                         if (val > 0)
883                                 fprintf(fp"+%d"val);
884                         else if (val < 0)
885                                 fprintf(fp"-%d", -val);
886                 } else
887                         fprintf(fpCONFMT, (CONSZ)val);
888                 return;
889
890         default:
891                 comperr("illegal conput, p %p"p);
892         }
893 }
894
895 /*ARGSUSED*/
896 void
897 insput(NODE *p)
898 {
899         comperr("insput");
900 }
901
902 /*
903  * Write out the upper address, like the upper register of a 2-register
904  * reference, or the next memory location.
905  */
906 void
907 upput(NODE *pint size)
908 {
909
910         size /= SZCHAR;
911         switch (p->n_op) {
912         case REG:
gmcgarry
1.6
913                 fprintf(stdout"%s"rnames[p->n_rval-R0R1+1]);
gmcgarry
1.1
914                 break;
915
916         case NAME:
917         case OREG:
918                 p->n_lval += size;
919                 adrput(stdoutp);
920                 p->n_lval -= size;
921                 break;
922         case ICON:
923                 fprintf(stdoutCONFMTp->n_lval >> 32);
924                 break;
925         default:
926                 comperr("upput bad op %d size %d"p->n_opsize);
927         }
928 }
929
930 void
931 adrput(FILE *ioNODE *p)
932 {
933         int r;
934         /* output an address, with offsets, from p */
935
936         if (p->n_op == FLD)
937                 p = p->n_left;
938
939         switch (p->n_op) {
940
941         case NAME:
942                 if (p->n_name[0] != '\0') {
943                         fputs(p->n_nameio);
944                         if (p->n_lval != 0)
gmcgarry
1.7
945                                 fprintf(io"+%lld"p->n_lval);
gmcgarry
1.1
946                 } else
947                         fprintf(ioCONFMTp->n_lval);
948                 return;
949
950         case OREG:
951                 r = p->n_rval;
ragge
1.13
952                 if (R2TEST(r))
953                         fprintf(io"[%s, %s, lsl #%d]",
954                                 rnames[R2UPK1(r)],
955                                 rnames[R2UPK2(r)],
956                                 R2UPK3(r));
957                 else
958                         fprintf(io"[%s,#%d]"rnames[p->n_rval], (int)p->n_lval);
gmcgarry
1.1
959                 return;
960
961         case ICON:
962                 /* addressable value of the constant */
963                 conput(iop);
964                 return;
965
966         case REG:
967                 switch (p->n_type) {
gmcgarry
1.7
968                 case DOUBLE:
969                 case LDOUBLE:
gmcgarry
1.20
970                         if (features(FEATURE_HARDFLOAT)) {
971                                 fprintf(io"%s"rnames[p->n_rval]);
972                                 break;
973                         }
974                         /* FALLTHROUGH */
gmcgarry
1.1
975                 case LONGLONG:
976                 case ULONGLONG:
gmcgarry
1.6
977                         fprintf(stdout"%s"rnames[p->n_rval-R0R1]);
gmcgarry
1.1
978                         break;
979                 default:
980                         fprintf(io"%s"rnames[p->n_rval]);
981                 }
982                 return;
983
984         default:
985                 comperr("illegal address, op %d, node %p"p->n_opp);
986                 return;
987
988         }
989 }
990
991 /*   printf conditional and unconditional branches */
992 void
993 cbgen(int oint lab)
994 {
995         if (o < EQ || o > UGT)
996                 comperr("bad conditional branch: %s"opst[o]);
gmcgarry
1.19
997         printf("\t%s " LABFMT COM "conditional branch\n",
gmcgarry
1.7
998             ccbranches[o-EQ], lab);
gmcgarry
1.1
999 }
1000
ragge
1.17
1001 /*
1002  * The arm can only address 4k to get a NAME, so there must be some
1003  * rewriting here.  Strategy:
1004  * For first 1000 nodes found, print out the word directly.
1005  * For the following 1000 nodes, group them together in asm statements
1006  * and create a jump over.
1007  * For the last <1000 statements, print out the words last.
1008  */
gmcgarry
1.1
1009 struct addrsymb {
ragge
1.17
1010         SLIST_ENTRY(addrsymblink;
1011         char *name;     /* symbol name */
1012         int num;        /* symbol offset */
1013         char *str;      /* replace label */
gmcgarry
1.1
1014 };
ragge
1.17
1015 SLIST_HEAD(, addrsymbaslist;
1016 static struct interpass *ipbase;
1017 static int prtnumbernodcntnotfirst;
1018 #define PRTLAB  ".LY%d" /* special for here */
1019
1020 static struct interpass *
1021 anode(char *p)
1022 {
1023         extern int thisline;
1024         struct interpass *ip = tmpalloc(sizeof(struct interpass));
1025
1026         ip->ip_asm = p;
1027         ip->type = IP_ASM;
1028         ip->lineno = thisline;
1029         return ip;
1030 }
1031
1032 static void
1033 flshlab(void)
1034 {
1035         struct interpass *ip;
1036         struct addrsymb *el;
1037         int lab = prtnumber++;
1038         char *c;
1039
1040         if (SLIST_FIRST(&aslist) == NULL)
1041                 return;
1042
1043         snprintf(c = tmpalloc(32), 32"\tb " PRTLAB "\n"lab);
1044         ip = anode(c);
1045         DLIST_INSERT_BEFORE(ipbaseipqelem);
1046
1047         SLIST_FOREACH(el, &aslistlink) {
1048                 /* insert each node as asm */
1049                 int l = 32+strlen(el->name);
1050                 c = tmpalloc(l);
1051                 if (el->num)
1052                         snprintf(cl"%s:\n\t.word %s+%d\n",
1053                             el->strel->nameel->num);
1054                 else
1055                         snprintf(cl"%s:\n\t.word %s\n"el->strel->name);
1056                 ip