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