1 /* Id: local2.c,v 1.25 2008/12/03 22:23:38 gmcgarry Exp */ 2 /* $NetBSD: local2.c,v 1.1.1.3 2010/06/03 18:57:19 plunky Exp $ */ 3 /* 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 30 /* 31 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and 32 * Simon Olsson (simols-1@student.ltu.se) 2005. 33 */ 34 35 #include <ctype.h> 36 #include <string.h> 37 #include <stdlib.h> 38 #include <assert.h> 39 40 #include "pass1.h" 41 #include "pass2.h" 42 43 #ifdef TARGET_BIG_ENDIAN 44 int bigendian = 1; 45 #else 46 int bigendian = 0; 47 #endif 48 49 int nargregs = MIPS_O32_NARGREGS; 50 51 static int argsiz(NODE *p); 52 53 void 54 deflab(int label) 55 { 56 printf(LABFMT ":\n", label); 57 } 58 59 static int regoff[32]; 60 static TWORD ftype; 61 62 /* 63 * calculate stack size and offsets 64 */ 65 static int 66 offcalc(struct interpass_prolog * ipp) 67 { 68 int i, j, addto; 69 70 addto = p2maxautooff; 71 72 for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) { 73 if (i & 1) { 74 addto += SZINT / SZCHAR; 75 regoff[j] = addto; 76 } 77 } 78 79 /* round to 8-byte boundary */ 80 addto += 7; 81 addto &= ~7; 82 83 return addto; 84 } 85 86 /* 87 * Print out the prolog assembler. 88 */ 89 void 90 prologue(struct interpass_prolog * ipp) 91 { 92 int addto; 93 int i, j; 94 95 ftype = ipp->ipp_type; 96 printf("\t.align 2\n"); 97 if (ipp->ipp_vis) 98 printf("\t.globl %s\n", ipp->ipp_name); 99 printf("\t.ent %s\n", ipp->ipp_name); 100 printf("%s:\n", ipp->ipp_name); 101 102 addto = offcalc(ipp); 103 104 /* for the moment, just emit this PIC stuff - NetBSD does it */ 105 printf("\t.frame %s,%d,%s\n", rnames[FP], ARGINIT/SZCHAR, rnames[RA]); 106 printf("\t.set noreorder\n"); 107 printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n"); 108 printf("\t.set reorder\n"); 109 110 printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], ARGINIT/SZCHAR); 111 /* for the moment, just emit PIC stuff - NetBSD does it */ 112 printf("\t.cprestore 8\t# pseudo-op to store GOT ptr at 8(sp)\n"); 113 114 printf("\tsw %s,4(%s)\n", rnames[RA], rnames[SP]); 115 printf("\tsw %s,(%s)\n", rnames[FP], rnames[SP]); 116 printf("\tmove %s,%s\n", rnames[FP], rnames[SP]); 117 118 #ifdef notyet 119 /* profiling */ 120 if (pflag) { 121 printf("\t.set noat\n"); 122 printf("\tmove %s,%s\t# save current return address\n", 123 rnames[AT], rnames[RA]); 124 printf("\tsubu %s,%s,8\t# _mcount pops 2 words from stack\n", 125 rnames[SP], rnames[SP]); 126 printf("\tjal %s\n", exname("_mcount")); 127 printf("\tnop\n"); 128 printf("\t.set at\n"); 129 } 130 #endif 131 132 if (addto) 133 printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], addto); 134 135 for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) 136 if (i & 1) 137 fprintf(stdout, "\tsw %s,-%d(%s) # save permanent\n", 138 rnames[j], regoff[j], rnames[FP]); 139 140 } 141 142 void 143 eoftn(struct interpass_prolog * ipp) 144 { 145 int i, j; 146 int addto; 147 148 addto = offcalc(ipp); 149 150 if (ipp->ipp_ip.ip_lbl == 0) 151 return; /* no code needs to be generated */ 152 153 /* return from function code */ 154 for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) { 155 if (i & 1) 156 fprintf(stdout, "\tlw %s,-%d(%s)\n\tnop\n", 157 rnames[j], regoff[j], rnames[FP]); 158 } 159 160 printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[FP], ARGINIT/SZCHAR); 161 printf("\tlw %s,%d(%s)\n", rnames[RA], 4-ARGINIT/SZCHAR, rnames[SP]); 162 printf("\tlw %s,%d(%s)\n", rnames[FP], 0-ARGINIT/SZCHAR, rnames[SP]); 163 164 printf("\tjr %s\n", rnames[RA]); 165 printf("\tnop\n"); 166 167 #ifdef USE_GAS 168 printf("\t.end %s\n", ipp->ipp_name); 169 printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name); 170 #endif 171 } 172 173 /* 174 * add/sub/... 175 * 176 * Param given: 177 */ 178 void 179 hopcode(int f, int o) 180 { 181 char *str; 182 183 switch (o) { 184 case EQ: 185 str = "beqz"; /* pseudo-op */ 186 break; 187 case NE: 188 str = "bnez"; /* pseudo-op */ 189 break; 190 case ULE: 191 case LE: 192 str = "blez"; 193 break; 194 case ULT: 195 case LT: 196 str = "bltz"; 197 break; 198 case UGE: 199 case GE: 200 str = "bgez"; 201 break; 202 case UGT: 203 case GT: 204 str = "bgtz"; 205 break; 206 case PLUS: 207 str = "add"; 208 break; 209 case MINUS: 210 str = "sub"; 211 break; 212 case AND: 213 str = "and"; 214 break; 215 case OR: 216 str = "or"; 217 break; 218 case ER: 219 str = "xor"; 220 break; 221 default: 222 comperr("hopcode2: %d", o); 223 str = 0; /* XXX gcc */ 224 } 225 226 printf("%s%c", str, f); 227 } 228 229 char * 230 rnames[] = { 231 #ifdef USE_GAS 232 /* gnu assembler */ 233 "$zero", "$at", "$2", "$3", "$4", "$5", "$6", "$7", 234 "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", 235 "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", 236 "$24", "$25", 237 "$kt0", "$kt1", "$gp", "$sp", "$fp", "$ra", 238 "$2!!$3!!", 239 "$4!!$5!!", "$5!!$6!!", "$6!!$7!!", "$7!!$8!!", 240 "$8!!$9!!", "$9!!$10!", "$10!$11!", "$11!$12!", 241 "$12!$13!", "$13!$14!", "$14!$15!", "$15!$24!", "$24!$25!", 242 "$16!$17!", "$17!$18!", "$18!$19!", "$19!$20!", 243 "$20!$21!", "$21!$22!", "$22!$23!", 244 #else 245 /* mips assembler */ 246 "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", 247 "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", 248 "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", 249 "$t8", "$t9", 250 "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", 251 "$v0!$v1!", 252 "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$t0!", 253 "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t4!", 254 "$t4!$t5!", "$t5!$t6!", "$t6!$t7!", "$t7!$t8!", "$t8!$t9!", 255 "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!", 256 "$s4!$s5!", "$s5!$s6!", "$s6!$s7!", 257 #endif 258 "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!", 259 "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15", 260 "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23", 261 "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31", 262 }; 263 264 char * 265 rnames_n32[] = { 266 /* mips assembler */ 267 "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", 268 "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3", 269 "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", 270 "$t8", "$t9", 271 "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", 272 "$v0!$v1!", 273 "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$a4!", 274 "$a4!$a5!", "$a5!$a6!", "$a6!$a7!", "$a7!$t0!", 275 "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t8!", "$t8!$t9!", 276 "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!", 277 "$s4!$s5!", "$s5!$s6!", "$s6!$s7!", 278 "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!", 279 "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15", 280 "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23", 281 "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31", 282 }; 283 284 int 285 tlen(NODE *p) 286 { 287 switch (p->n_type) { 288 case CHAR: 289 case UCHAR: 290 return (1); 291 292 case SHORT: 293 case USHORT: 294 return (SZSHORT / SZCHAR); 295 296 case DOUBLE: 297 return (SZDOUBLE / SZCHAR); 298 299 case INT: 300 case UNSIGNED: 301 case LONG: 302 case ULONG: 303 return (SZINT / SZCHAR); 304 305 case LONGLONG: 306 case ULONGLONG: 307 return SZLONGLONG / SZCHAR; 308 309 default: 310 if (!ISPTR(p->n_type)) 311 comperr("tlen type %d not pointer"); 312 return SZPOINT(p->n_type) / SZCHAR; 313 } 314 } 315 316 317 /* 318 * Push a structure on stack as argument. 319 */ 320 static void 321 starg(NODE *p) 322 { 323 //assert(p->n_rval == A1); 324 printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], p->n_stsize); 325 /* A0 = dest, A1 = src, A2 = len */ 326 printf("\tmove %s,%s\n", rnames[A0], rnames[SP]); 327 printf("\tli %s,%d\t# structure size\n", rnames[A2], p->n_stsize); 328 printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); 329 printf("\tjal %s\t# structure copy\n", exname("memcpy")); 330 printf("\tnop\n"); 331 printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); 332 } 333 334 /* 335 * Structure assignment. 336 */ 337 static void 338 stasg(NODE *p) 339 { 340 assert(p->n_right->n_rval == A1); 341 /* A0 = dest, A1 = src, A2 = len */ 342 printf("\tli %s,%d\t# structure size\n", rnames[A2], p->n_stsize); 343 if (p->n_left->n_op == OREG) { 344 printf("\taddiu %s,%s," CONFMT "\t# dest address\n", 345 rnames[A0], rnames[p->n_left->n_rval], 346 p->n_left->n_lval); 347 } else if (p->n_left->n_op == NAME) { 348 printf("\tla %s,", rnames[A0]); 349 adrput(stdout, p->n_left); 350 printf("\n"); 351 } 352 printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); 353 printf("\tjal %s\t# structure copy\n", exname("memcpy")); 354 printf("\tnop\n"); 355 printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); 356 } 357 358 static void 359 shiftop(NODE *p) 360 { 361 NODE *r = p->n_right; 362 TWORD ty = p->n_type; 363 364 if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) { 365 expand(p, INBREG, "\tsrl A1,AL,"); 366 printf(CONFMT "\t# 64-bit left-shift\n", 32 - r->n_lval); 367 expand(p, INBREG, "\tsll U1,UL,AR\n"); 368 expand(p, INBREG, "\tor U1,U1,A1\n"); 369 expand(p, INBREG, "\tsll A1,AL,AR\n"); 370 } else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) { 371 expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n"); 372 expand(p, INBREG, "\tsll U1,AL,"); 373 printf(CONFMT "\n", r->n_lval - 32); 374 } else if (p->n_op == LS && r->n_op == ICON) { 375 expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n"); 376 expand(p, INBREG, "\tli U1,0\n"); 377 } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) { 378 expand(p, INBREG, "\tsll U1,UL,"); 379 printf(CONFMT "\t# 64-bit right-shift\n", 32 - r->n_lval); 380 expand(p, INBREG, "\tsrl A1,AL,AR\n"); 381 expand(p, INBREG, "\tor A1,A1,U1\n"); 382 if (ty == LONGLONG) 383 expand(p, INBREG, "\tsra U1,UL,AR\n"); 384 else 385 expand(p, INBREG, "\tsrl U1,UL,AR\n"); 386 } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) { 387 if (ty == LONGLONG) { 388 expand(p, INBREG, "\tsra U1,UL,31\t# 64-bit right-shift\n"); 389 expand(p, INBREG, "\tsra A1,UL,"); 390 }else { 391 expand(p, INBREG, "\tli U1,0\t# 64-bit right-shift\n"); 392 expand(p, INBREG, "\tsrl A1,UL,"); 393 } 394 printf(CONFMT "\n", r->n_lval - 32); 395 } else if (p->n_op == LS && r->n_op == ICON) { 396 expand(p, INBREG, "\tli A1,0\t# 64-bit right-shift\n"); 397 expand(p, INBREG, "\tli U1,0\n"); 398 } else { 399 comperr("shiftop"); 400 } 401 } 402 403 /* 404 * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines 405 */ 406 static void 407 fpemulop(NODE *p) 408 { 409 NODE *l = p->n_left; 410 char *ch = NULL; 411 412 if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3"; 413 else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3"; 414 else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3"; 415 416 else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3"; 417 else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3"; 418 else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3"; 419 420 else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3"; 421 else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3"; 422 else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3"; 423 424 else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3"; 425 else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3"; 426 else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3"; 427 428 else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2"; 429 else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2"; 430 else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2"; 431 432 else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2"; 433 else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2"; 434 else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2"; 435 436 else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2"; 437 else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2"; 438 else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2"; 439 440 else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2"; 441 else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2"; 442 else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2"; 443 444 else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2"; 445 else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2"; 446 else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2"; 447 448 else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2"; 449 else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2"; 450 else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2"; 451 452 else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2"; 453 else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2"; 454 else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2"; 455 456 else if (p->n_op == SCONV && p->n_type == FLOAT) { 457 if (l->n_type == DOUBLE) ch = "truncdfsf2"; 458 else if (l->n_type == LDOUBLE) ch = "trunctfsf2"; 459 else if (l->n_type == ULONGLONG) ch = "floatdisf"; /**/ 460 else if (l->n_type == LONGLONG) ch = "floatdisf"; 461 else if (l->n_type == LONG) ch = "floatsisf"; 462 else if (l->n_type == ULONG) ch = "floatunsisf"; 463 else if (l->n_type == INT) ch = "floatsisf"; 464 else if (l->n_type == UNSIGNED) ch = "floatunsisf"; 465 } else if (p->n_op == SCONV && p->n_type == DOUBLE) { 466 if (l->n_type == FLOAT) ch = "extendsfdf2"; 467 else if (l->n_type == LDOUBLE) ch = "trunctfdf2"; 468 else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; 469 else if (l->n_type == LONGLONG) ch = "floatdidf"; 470 else if (l->n_type == LONG) ch = "floatsidf"; 471 else if (l->n_type == ULONG) ch = "floatunsidf"; 472 else if (l->n_type == INT) ch = "floatsidf"; 473 else if (l->n_type == UNSIGNED) ch = "floatunsidf"; 474 } else if (p->n_op == SCONV && p->n_type == LDOUBLE) { 475 if (l->n_type == FLOAT) ch = "extendsftf2"; 476 else if (l->n_type == DOUBLE) ch = "extenddfdf2"; 477 else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; 478 else if (l->n_type == LONGLONG) ch = "floatdidf"; 479 else if (l->n_type == LONG) ch = "floatsidf"; 480 else if (l->n_type == ULONG) ch = "floatunssidf"; 481 else if (l->n_type == INT) ch = "floatsidf"; 482 else if (l->n_type == UNSIGNED) ch = "floatunsidf"; 483 } else if (p->n_op == SCONV && p->n_type == ULONGLONG) { 484 if (l->n_type == FLOAT) ch = "fixunssfdi"; 485 else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; 486 else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; 487 } else if (p->n_op == SCONV && p->n_type == LONGLONG) { 488 if (l->n_type == FLOAT) ch = "fixsfdi"; 489 else if (l->n_type == DOUBLE) ch = "fixdfdi"; 490 else if (l->n_type == LDOUBLE) ch = "fixdfdi"; 491 } else if (p->n_op == SCONV && p->n_type == LONG) { 492 if (l->n_type == FLOAT) ch = "fixsfsi"; 493 else if (l->n_type == DOUBLE) ch = "fixdfsi"; 494 else if (l->n_type == LDOUBLE) ch = "fixdfsi"; 495 } else if (p->n_op == SCONV && p->n_type == ULONG) { 496 if (l->n_type == FLOAT) ch = "fixunssfsi"; 497 else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; 498 else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; 499 } else if (p->n_op == SCONV && p->n_type == INT) { 500 if (l->n_type == FLOAT) ch = "fixsfsi"; 501 else if (l->n_type == DOUBLE) ch = "fixdfsi"; 502 else if (l->n_type == LDOUBLE) ch = "fixdfsi"; 503 } else if (p->n_op == SCONV && p->n_type == UNSIGNED) { 504 if (l->n_type == FLOAT) ch = "fixunssfsi"; 505 else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; 506 else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; 507 } 508 509 if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op); 510 511 if (p->n_op == SCONV) { 512 if (l->n_type == FLOAT) { 513 printf("\tmfc1 %s,", rnames[A0]); 514 adrput(stdout, l); 515 printf("\n\tnop\n"); 516 } else if (l->n_type == DOUBLE || l->n_type == LDOUBLE) { 517 printf("\tmfc1 %s,", rnames[A1]); 518 upput(l, 0); 519 printf("\n\tnop\n"); 520 printf("\tmfc1 %s,", rnames[A0]); 521 adrput(stdout, l); 522 printf("\n\tnop\n"); 523 } 524 } else { 525 comperr("ZF: incomplete softfloat - put args in registers"); 526 } 527 528 printf("\tjal __%s\t# softfloat operation\n", exname(ch)); 529 printf("\tnop\n"); 530 531 if (p->n_op >= EQ && p->n_op <= GT) 532 printf("\tcmp %s,0\n", rnames[V0]); 533 } 534 535 /* 536 * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines 537 */ 538 static void 539 emulop(NODE *p) 540 { 541 char *ch = NULL; 542 543 if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3"; 544 else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG || 545 DEUNSIGN(p->n_type) == INT)) 546 ch = "ashlsi3"; 547 548 else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3"; 549 else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT)) 550 ch = "lshrsi3"; 551 552 else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3"; 553 else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT)) 554 ch = "ashrsi3"; 555 556 else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3"; 557 else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT)) 558 ch = "divsi3"; 559 560 else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3"; 561 else if (p->n_op == DIV && (p->n_type == ULONG || 562 p->n_type == UNSIGNED)) 563 ch = "udivsi3"; 564 565 else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3"; 566 else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT)) 567 ch = "modsi3"; 568 569 else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3"; 570 else if (p->n_op == MOD && (p->n_type == ULONG || 571 p->n_type == UNSIGNED)) 572 ch = "umodsi3"; 573 574 else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3"; 575 else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT)) 576 ch = "mulsi3"; 577 578 else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2"; 579 else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2"; 580 581 else ch = 0, comperr("ZE"); 582 printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); 583 printf("\tjal __%s\t# emulated operation\n", exname(ch)); 584 printf("\tnop\n"); 585 printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); 586 } 587 588 /* 589 * Emit code to compare two longlong numbers. 590 */ 591 static void 592 twollcomp(NODE *p) 593 { 594 int o = p->n_op; 595 int s = getlab2(); 596 int e = p->n_label; 597 int cb1, cb2; 598 599 if (o >= ULE) 600 o -= (ULE-LE); 601 switch (o) { 602 case NE: 603 cb1 = 0; 604 cb2 = NE; 605 break; 606 case EQ: 607 cb1 = NE; 608 cb2 = 0; 609 break; 610 case LE: 611 case LT: 612 cb1 = GT; 613 cb2 = LT; 614 break; 615 case GE: 616 case GT: 617 cb1 = LT; 618 cb2 = GT; 619 break; 620 621 default: 622 cb1 = cb2 = 0; /* XXX gcc */ 623 } 624 if (p->n_op >= ULE) 625 cb1 += 4, cb2 += 4; 626 expand(p, 0, "\tsub A1,UL,UR\t# compare 64-bit values (upper)\n"); 627 if (cb1) { 628 printf("\t"); 629 hopcode(' ', cb1); 630 expand(p, 0, "A1"); 631 printf("," LABFMT "\n", s); 632 printf("\tnop\n"); 633 } 634 if (cb2) { 635 printf("\t"); 636 hopcode(' ', cb2); 637 expand(p, 0, "A1"); 638 printf("," LABFMT "\n", e); 639 printf("\tnop\n"); 640 } 641 expand(p, 0, "\tsub A1,AL,AR\t# (and lower)\n"); 642 printf("\t"); 643 hopcode(' ', o); 644 expand(p, 0, "A1"); 645 printf("," LABFMT "\n", e); 646 printf("\tnop\n"); 647 deflab(s); 648 } 649 650 static void 651 fpcmpops(NODE *p) 652 { 653 NODE *l = p->n_left; 654 655 switch (p->n_op) { 656 case EQ: 657 if (l->n_type == FLOAT) 658 expand(p, 0, "\tc.eq.s AL,AR\n"); 659 else 660 expand(p, 0, "\tc.eq.d AL,AR\n"); 661 expand(p, 0, "\tnop\n\tbc1t LC\n"); 662 break; 663 case NE: 664 if (l->n_type == FLOAT) 665 expand(p, 0, "\tc.eq.s AL,AR\n"); 666 else 667 expand(p, 0, "\tc.eq.d AL,AR\n"); 668 expand(p, 0, "\tnop\n\tbc1f LC\n"); 669 break; 670 case LT: 671 if (l->n_type == FLOAT) 672 expand(p, 0, "\tc.lt.s AL,AR\n"); 673 else 674 expand(p, 0, "\tc.lt.d AL,AR\n"); 675 expand(p, 0, "\tnop\n\tbc1t LC\n"); 676 break; 677 case GE: 678 if (l->n_type == FLOAT) 679 expand(p, 0, "\tc.lt.s AL,AR\n"); 680 else 681 expand(p, 0, "\tc.lt.d AL,AR\n"); 682 expand(p, 0, "\tnop\n\tbc1f LC\n"); 683 break; 684 case LE: 685 if (l->n_type == FLOAT) 686 expand(p, 0, "\tc.le.s AL,AR\n"); 687 else 688 expand(p, 0, "\tc.le.d AL,AR\n"); 689 expand(p, 0, "\tnop\n\tbc1t LC\n"); 690 break; 691 case GT: 692 if (l->n_type == FLOAT) 693 expand(p, 0, "\tc.le.s AL,AR\n"); 694 else 695 expand(p, 0, "\tc.le.d AL,AR\n"); 696 expand(p, 0, "\tnop\n\tbc1f LC\n"); 697 break; 698 } 699 printf("\tnop\n\tnop\n"); 700 } 701 702 void 703 zzzcode(NODE * p, int c) 704 { 705 int sz; 706 707 switch (c) { 708 709 case 'C': /* remove arguments from stack after subroutine call */ 710 sz = p->n_qual > 16 ? p->n_qual : 16; 711 printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[SP], sz); 712 break; 713 714 case 'D': /* long long comparison */ 715 twollcomp(p); 716 break; 717 718 case 'E': /* emit emulated ops */ 719 emulop(p); 720 break; 721 722 case 'F': /* emit emulate floating point ops */ 723 fpemulop(p); 724 break; 725 726 case 'G': /* emit hardware floating-point compare op */ 727 fpcmpops(p); 728 break; 729 730 case 'H': /* structure argument */ 731 starg(p); 732 break; 733 734 case 'I': /* high part of init constant */ 735 if (p->n_name[0] != '\0') 736 comperr("named highword"); 737 fprintf(stdout, CONFMT, (p->n_lval >> 32) & 0xffffffff); 738 break; 739 740 case 'O': /* 64-bit left and right shift operators */ 741 shiftop(p); 742 break; 743 744 case 'Q': /* emit struct assign */ 745 stasg(p); 746 break; 747 748 default: 749 comperr("zzzcode %c", c); 750 } 751 } 752 753 /* ARGSUSED */ 754 int 755 rewfld(NODE * p) 756 { 757 return (1); 758 } 759 760 int 761 fldexpand(NODE *p, int cookie, char **cp) 762 { 763 CONSZ val; 764 765 if (p->n_op == ASSIGN) 766 p = p->n_left; 767 switch (**cp) { 768 case 'S': 769 printf("%d", UPKFSZ(p->n_rval)); 770 break; 771 case 'H': 772 printf("%d", UPKFOFF(p->n_rval)); 773 break; 774 case 'M': 775 case 'N': 776 val = (CONSZ)1 << UPKFSZ(p->n_rval); 777 --val; 778 val <<= UPKFOFF(p->n_rval); 779 printf("0x%llx", (**cp == 'M' ? val : ~val) & 0xffffffff); 780 break; 781 default: 782 comperr("fldexpand"); 783 } 784 return 1; 785 } 786 787 /* 788 * Does the bitfield shape match? 789 */ 790 int 791 flshape(NODE * p) 792 { 793 int o = p->n_op; 794 795 if (o == OREG || o == REG || o == NAME) 796 return SRDIR; /* Direct match */ 797 if (o == UMUL && shumul(p->n_left, SOREG)) 798 return SROREG; /* Convert into oreg */ 799 return SRREG; /* put it into a register */ 800 } 801 802 /* INTEMP shapes must not contain any temporary registers */ 803 /* XXX should this go away now? */ 804 int 805 shtemp(NODE * p) 806 { 807 return 0; 808 #if 0 809 int r; 810 811 if (p->n_op == STARG) 812 p = p->n_left; 813 814 switch (p->n_op) { 815 case REG: 816 return (!istreg(p->n_rval)); 817 818 case OREG: 819 r = p->n_rval; 820 if (R2TEST(r)) { 821 if (istreg(R2UPK1(r))) 822 return (0); 823 r = R2UPK2(r); 824 } 825 return (!istreg(r)); 826 827 case UMUL: 828 p = p->n_left; 829 return (p->n_op != UMUL && shtemp(p)); 830 } 831 832 if (optype(p->n_op) != LTYPE) 833 return (0); 834 return (1); 835 #endif 836 } 837 838 void 839 adrcon(CONSZ val) 840 { 841 printf(CONFMT, val); 842 } 843 844 void 845 conput(FILE *fp, NODE *p) 846 { 847 int val = p->n_lval; 848 849 switch (p->n_op) { 850 case ICON: 851 if (p->n_name[0] != '\0') { 852 fprintf(fp, "%s", p->n_name); 853 if (p->n_lval) 854 fprintf(fp, "+%d", val); 855 } else 856 fprintf(fp, "%d", val); 857 return; 858 859 default: 860 comperr("illegal conput"); 861 } 862 } 863 864 /* ARGSUSED */ 865 void 866 insput(NODE * p) 867 { 868 comperr("insput"); 869 } 870 871 /* 872 * Print lower or upper name of 64-bit register. 873 */ 874 static void 875 print_reg64name(FILE *fp, int rval, int hi) 876 { 877 int off = 4 * (hi != 0); 878 char *regname = rnames[rval]; 879 880 fprintf(fp, "%c%c", 881 regname[off], 882 regname[off + 1]); 883 if (regname[off + 2] != '!') 884 fputc(regname[off + 2], fp); 885 if (regname[off + 3] != '!') 886 fputc(regname[off + 3], fp); 887 } 888 889 /* 890 * Write out the upper address, like the upper register of a 2-register 891 * reference, or the next memory location. 892 */ 893 void 894 upput(NODE * p, int size) 895 { 896 897 size /= SZCHAR; 898 switch (p->n_op) { 899 case REG: 900 if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) 901 print_reg64name(stdout, p->n_rval, 1); 902 else 903 fputs(rnames[p->n_rval], stdout); 904 break; 905 906 case NAME: 907 case OREG: 908 p->n_lval += size; 909 adrput(stdout, p); 910 p->n_lval -= size; 911 break; 912 case ICON: 913 fprintf(stdout, CONFMT, p->n_lval >> 32); 914 break; 915 default: 916 comperr("upput bad op %d size %d", p->n_op, size); 917 } 918 } 919 920 void 921 adrput(FILE * io, NODE * p) 922 { 923 int r; 924 /* output an address, with offsets, from p */ 925 926 if (p->n_op == FLD) 927 p = p->n_left; 928 929 switch (p->n_op) { 930 931 case NAME: 932 if (p->n_name[0] != '\0') 933 fputs(p->n_name, io); 934 if (p->n_lval != 0) 935 fprintf(io, "+" CONFMT, p->n_lval); 936 return; 937 938 case OREG: 939 r = p->n_rval; 940 941 if (p->n_lval) 942 fprintf(io, "%d", (int) p->n_lval); 943 944 fprintf(io, "(%s)", rnames[p->n_rval]); 945 return; 946 case ICON: 947 /* addressable value of the constant */ 948 conput(io, p); 949 return; 950 951 case REG: 952 if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) 953 print_reg64name(io, p->n_rval, 0); 954 else 955 fputs(rnames[p->n_rval], io); 956 return; 957 958 default: 959 comperr("illegal address, op %d, node %p", p->n_op, p); 960 return; 961 962 } 963 } 964 965 /* printf conditional and unconditional branches */ 966 void 967 cbgen(int o, int lab) 968 { 969 } 970 971 void 972 myreader(struct interpass * ipole) 973 { 974 } 975 976 #if 0 977 /* 978 * Calculate the stack size for arguments 979 */ 980 static int stacksize; 981 982 static void 983 calcstacksize(NODE *p, void *arg) 984 { 985 int sz; 986 987 printf("op=%d\n", p->n_op); 988 989 if (p->n_op != CALL && p->n_op != STCALL) 990 return; 991 992 sz = argsiz(p->n_right); 993 if (sz > stacksize) 994 stacksize = sz; 995 996 #ifdef PCC_DEBUG 997 if (x2debug) 998 printf("stacksize: %d\n", stacksize); 999 #endif 1000 } 1001 #endif 1002 1003 /* 1004 * If we're big endian, then all OREG loads of a type 1005 * larger than the destination, must have the 1006 * offset changed to point to the correct bytes in memory. 1007 */ 1008 static void 1009 offchg(NODE *p, void *arg) 1010 { 1011 NODE *l; 1012 1013 if (p->n_op != SCONV) 1014 return; 1015 1016 l = p->n_left; 1017 1018 if (l->n_op != OREG) 1019 return; 1020 1021 switch (l->n_type) { 1022 case SHORT: 1023 case USHORT: 1024 if (DEUNSIGN(p->n_type) == CHAR) 1025 l->n_lval += 1; 1026 break; 1027 case LONG: 1028 case ULONG: 1029 case INT: 1030 case UNSIGNED: 1031 if (DEUNSIGN(p->n_type) == CHAR) 1032 l->n_lval += 3; 1033 else if (DEUNSIGN(p->n_type) == SHORT) 1034 l->n_lval += 2; 1035 break; 1036 case LONGLONG: 1037 case ULONGLONG: 1038 if (DEUNSIGN(p->n_type) == CHAR) 1039 l->n_lval += 7; 1040 else if (DEUNSIGN(p->n_type) == SHORT) 1041 l->n_lval += 6; 1042 else if (DEUNSIGN(p->n_type) == INT || 1043 DEUNSIGN(p->n_type) == LONG) 1044 l->n_lval += 4; 1045 break; 1046 default: 1047 comperr("offchg: unknown type"); 1048 break; 1049 } 1050 } 1051 1052 /* 1053 * Remove some PCONVs after OREGs are created. 1054 */ 1055 static void 1056 pconv2(NODE * p, void *arg) 1057 { 1058 NODE *q; 1059 1060 if (p->n_op == PLUS) { 1061 if (p->n_type == (PTR | SHORT) || p->n_type == (PTR | USHORT)) { 1062 if (p->n_right->n_op != ICON) 1063 return; 1064 if (p->n_left->n_op != PCONV) 1065 return; 1066 if (p->n_left->n_left->n_op != OREG) 1067 return; 1068 q = p->n_left->n_left; 1069 nfree(p->n_left); 1070 p->n_left = q; 1071 /* 1072 * This will be converted to another OREG later. 1073 */ 1074 } 1075 } 1076 } 1077 1078 void 1079 mycanon(NODE * p) 1080 { 1081 walkf(p, pconv2, 0); 1082 } 1083 1084 void 1085 myoptim(struct interpass * ipole) 1086 { 1087 struct interpass *ip; 1088 1089 #ifdef PCC_DEBUG 1090 if (x2debug) 1091 printf("myoptim:\n"); 1092 #endif 1093 1094 #if 0 1095 stacksize = 0; 1096 #endif 1097 1098 DLIST_FOREACH(ip, ipole, qelem) { 1099 if (ip->type != IP_NODE) 1100 continue; 1101 if (bigendian) 1102 walkf(ip->ip_node, offchg, 0); 1103 #if 0 1104 walkf(ip->ip_node, calcstacksize, 0); 1105 #endif 1106 } 1107 } 1108 1109 /* 1110 * Move data between registers. While basic registers aren't a problem, 1111 * we have to handle the special case of overlapping composite registers. 1112 */ 1113 void 1114 rmove(int s, int d, TWORD t) 1115 { 1116 switch (t) { 1117 case LONGLONG: 1118 case ULONGLONG: 1119 if (s == d+1) { 1120 /* dh = sl, copy low word first */ 1121 printf("\tmove "); 1122 print_reg64name(stdout, d, 0); 1123 printf(","); 1124 print_reg64name(stdout, s, 0); 1125 printf("\t# 64-bit rmove\n"); 1126 printf("\tmove "); 1127 print_reg64name(stdout, d, 1); 1128 printf(","); 1129 print_reg64name(stdout, s, 1); 1130 printf("\n"); 1131 } else { 1132 /* copy high word first */ 1133 printf("\tmove "); 1134 print_reg64name(stdout, d, 1); 1135 printf(","); 1136 print_reg64name(stdout, s, 1); 1137 printf(" # 64-bit rmove\n"); 1138 printf("\tmove "); 1139 print_reg64name(stdout, d, 0); 1140 printf(","); 1141 print_reg64name(stdout, s, 0); 1142 printf("\n"); 1143 } 1144 break; 1145 case FLOAT: 1146 case DOUBLE: 1147 case LDOUBLE: 1148 if (t == FLOAT) 1149 printf("\tmov.s "); 1150 else 1151 printf("\tmov.d "); 1152 print_reg64name(stdout, d, 0); 1153 printf(","); 1154 print_reg64name(stdout, s, 0); 1155 printf("\t# float/double rmove\n"); 1156 break; 1157 default: 1158 printf("\tmove %s,%s\t# default rmove\n", rnames[d], rnames[s]); 1159 } 1160 } 1161 1162 1163 /* 1164 * For class c, find worst-case displacement of the number of 1165 * registers in the array r[] indexed by class. 1166 * 1167 * On MIPS, we have: 1168 * 1169 * 32 32-bit registers (8 reserved) 1170 * 26 64-bit pseudo registers (1 unavailable) 1171 * 16 floating-point register pairs 1172 */ 1173 int 1174 COLORMAP(int c, int *r) 1175 { 1176 int num = 0; 1177 1178 switch (c) { 1179 case CLASSA: 1180 num += r[CLASSA]; 1181 num += 2*r[CLASSB]; 1182 return num < 24; 1183 case CLASSB: 1184 num += 2*r[CLASSB]; 1185 num += r[CLASSA]; 1186 return num < 25; 1187 case CLASSC: 1188 num += r[CLASSC]; 1189 return num < 6; 1190 } 1191 comperr("COLORMAP"); 1192 return 0; /* XXX gcc */ 1193 } 1194 1195 /* 1196 * Return a class suitable for a specific type. 1197 */ 1198 int 1199 gclass(TWORD t) 1200 { 1201 if (t == LONGLONG || t == ULONGLONG) 1202 return CLASSB; 1203 if (t >= FLOAT && t <= LDOUBLE) 1204 return CLASSC; 1205 return CLASSA; 1206 } 1207 1208 /* 1209 * Calculate argument sizes. 1210 */ 1211 void 1212 lastcall(NODE *p) 1213 { 1214 int sz; 1215 1216 #ifdef PCC_DEBUG 1217 if (x2debug) 1218 printf("lastcall:\n"); 1219 #endif 1220 1221 p->n_qual = 0; 1222 if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) 1223 return; 1224 1225 sz = argsiz(p->n_right); 1226 1227 if ((sz > 4*nargregs) && (sz & 7) != 0) { 1228 printf("\tsubu %s,%s,4\t# align stack\n", 1229 rnames[SP], rnames[SP]); 1230 sz += 4; 1231 assert((sz & 7) == 0); 1232 } 1233 1234 p->n_qual = sz; /* XXX */ 1235 } 1236 1237 static int 1238 argsiz(NODE *p) 1239 { 1240 TWORD t; 1241 int size = 0; 1242 int sz = 0; 1243 1244 if (p->n_op == CM) { 1245 size = argsiz(p->n_left); 1246 p = p->n_right; 1247 } 1248 1249 t = p->n_type; 1250 if (t < LONGLONG || t > BTMASK) 1251 sz = 4; 1252 else if (DEUNSIGN(t) == LONGLONG) 1253 sz = 8; 1254 else if (t == DOUBLE || t == LDOUBLE) 1255 sz = 8; 1256 else if (t == FLOAT) 1257 sz = 4; 1258 else if (t == STRTY || t == UNIONTY) 1259 sz = p->n_stsize; 1260 1261 if (p->n_type == STRTY || p->n_type == UNIONTY) { 1262 return (size + sz); 1263 } 1264 1265 /* alignment */ 1266 if (sz == 8 && (size & 7) != 0) 1267 sz += 4; 1268 1269 // printf("size=%d, sz=%d -> %d\n", size, sz, size + sz); 1270 return (size + sz); 1271 } 1272 1273 /* 1274 * Special shapes. 1275 */ 1276 int 1277 special(NODE *p, int shape) 1278 { 1279 int o = p->n_op; 1280 switch(shape) { 1281 case SPCON: 1282 if (o == ICON && p->n_name[0] == 0 && 1283 (p->n_lval & ~0xffff) == 0) 1284 return SRDIR; 1285 break; 1286 } 1287 1288 return SRNOPE; 1289 } 1290 1291 /* 1292 * Target-dependent command-line options. 1293 */ 1294 void 1295 mflags(char *str) 1296 { 1297 if (strcasecmp(str, "big-endian") == 0) { 1298 bigendian = 1; 1299 } else if (strcasecmp(str, "little-endian") == 0) { 1300 bigendian = 0; 1301 } else { 1302 fprintf(stderr, "unknown m option '%s'\n", str); 1303 exit(1); 1304 } 1305 1306 #if 0 1307 else if (strcasecmp(str, "ips2")) { 1308 } else if (strcasecmp(str, "ips2")) { 1309 } else if (strcasecmp(str, "ips3")) { 1310 } else if (strcasecmp(str, "ips4")) { 1311 } else if (strcasecmp(str, "hard-float")) { 1312 } else if (strcasecmp(str, "soft-float")) { 1313 } else if (strcasecmp(str, "abi=32")) { 1314 nargregs = MIPS_O32_NARGREGS; 1315 } else if (strcasecmp(str, "abi=n32")) { 1316 nargregs = MIPS_N32_NARGREGS; 1317 } else if (strcasecmp(str, "abi=64")) { 1318 nargregs = MIPS_N32_NARGREGS; 1319 } 1320 #endif 1321 } 1322 /* 1323 * Do something target-dependent for xasm arguments. 1324 * Supposed to find target-specific constraints and rewrite them. 1325 */ 1326 int 1327 myxasm(struct interpass *ip, NODE *p) 1328 { 1329 return 0; 1330 } 1331