2 #define INTTMP 0x0100ff00
3 #define INTVAR 0x40ff0000
4 #define FLTTMP 0x000f0ff0
5 #define FLTVAR 0xfff00000
7 #define INTRET 0x00000004
8 #define FLTRET 0x00000003
11 (generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P)
12 #define setsrc(d) ((d) && (d)->x.regnode && \
13 (d)->x.regnode->set == src->x.regnode->set && \
14 (d)->x.regnode->mask&src->x.regnode->mask)
16 #define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b))
19 #define NODEPTR_TYPE Node
20 #define OP_LABEL(p) ((p)->op)
21 #define LEFT_CHILD(p) ((p)->kids[0])
22 #define RIGHT_CHILD(p) ((p)->kids[1])
23 #define STATE_LABEL(p) ((p)->x.state)
24 static void address(Symbol, Symbol, long);
25 static void blkfetch(int, int, int, int);
26 static void blkloop(int, int, int, int, int, int[]);
27 static void blkstore(int, int, int, int);
28 static void defaddress(Symbol);
29 static void defconst(int, int, Value);
30 static void defstring(int, char *);
31 static void defsymbol(Symbol);
32 static void doarg(Node);
33 static void emit2(Node);
34 static void export(Symbol);
35 static void clobber(Node);
36 static void function(Symbol, Symbol [], Symbol [], int);
37 static void global(Symbol);
38 static void import(Symbol);
39 static void local(Symbol);
40 static void progbeg(int, char **);
41 static void progend(void);
42 static void segment(int);
43 static void space(int);
44 static void target(Node);
45 static int bitcount (unsigned);
46 static Symbol argreg (int, int, int, int, int);
48 static Symbol ireg[32], freg2[32], d6;
49 static Symbol iregw, freg2w;
50 static int tmpregs[] = {3, 9, 10};
328 reg: INDIRI1(VREGP) "# read register\n"
329 reg: INDIRU1(VREGP) "# read register\n"
331 reg: INDIRI2(VREGP) "# read register\n"
332 reg: INDIRU2(VREGP) "# read register\n"
334 reg: INDIRF4(VREGP) "# read register\n"
335 reg: INDIRI4(VREGP) "# read register\n"
336 reg: INDIRP4(VREGP) "# read register\n"
337 reg: INDIRU4(VREGP) "# read register\n"
339 reg: INDIRF8(VREGP) "# read register\n"
340 reg: INDIRI8(VREGP) "# read register\n"
341 reg: INDIRP8(VREGP) "# read register\n"
342 reg: INDIRU8(VREGP) "# read register\n"
344 stmt: ASGNI1(VREGP,reg) "# write register\n"
345 stmt: ASGNU1(VREGP,reg) "# write register\n"
347 stmt: ASGNI2(VREGP,reg) "# write register\n"
348 stmt: ASGNU2(VREGP,reg) "# write register\n"
350 stmt: ASGNF4(VREGP,reg) "# write register\n"
351 stmt: ASGNI4(VREGP,reg) "# write register\n"
352 stmt: ASGNP4(VREGP,reg) "# write register\n"
353 stmt: ASGNU4(VREGP,reg) "# write register\n"
355 stmt: ASGNF8(VREGP,reg) "# write register\n"
356 stmt: ASGNI8(VREGP,reg) "# write register\n"
357 stmt: ASGNP8(VREGP,reg) "# write register\n"
358 stmt: ASGNU8(VREGP,reg) "# write register\n"
375 addr: ADDI4(reg,acon) "%1($%0)"
376 addr: ADDU4(reg,acon) "%1($%0)"
377 addr: ADDP4(reg,acon) "%1($%0)"
380 addr: ADDRFP4 "%a+%F($sp)"
381 addr: ADDRLP4 "%a+%F($sp)"
382 reg: addr "la $%c,%0\n" 1
383 reg: CNSTI1 "# reg\n" range(a, 0, 0)
384 reg: CNSTI2 "# reg\n" range(a, 0, 0)
385 reg: CNSTI4 "# reg\n" range(a, 0, 0)
386 reg: CNSTU1 "# reg\n" range(a, 0, 0)
387 reg: CNSTU2 "# reg\n" range(a, 0, 0)
388 reg: CNSTU4 "# reg\n" range(a, 0, 0)
389 reg: CNSTP4 "# reg\n" range(a, 0, 0)
390 stmt: ASGNI1(addr,reg) "sb $%1,%0\n" 1
391 stmt: ASGNU1(addr,reg) "sb $%1,%0\n" 1
392 stmt: ASGNI2(addr,reg) "sh $%1,%0\n" 1
393 stmt: ASGNU2(addr,reg) "sh $%1,%0\n" 1
394 stmt: ASGNI4(addr,reg) "sw $%1,%0\n" 1
395 stmt: ASGNU4(addr,reg) "sw $%1,%0\n" 1
396 stmt: ASGNP4(addr,reg) "sw $%1,%0\n" 1
397 reg: INDIRI1(addr) "lb $%c,%0\n" 1
398 reg: INDIRU1(addr) "lbu $%c,%0\n" 1
399 reg: INDIRI2(addr) "lh $%c,%0\n" 1
400 reg: INDIRU2(addr) "lhu $%c,%0\n" 1
401 reg: INDIRI4(addr) "lw $%c,%0\n" 1
402 reg: INDIRU4(addr) "lw $%c,%0\n" 1
403 reg: INDIRP4(addr) "lw $%c,%0\n" 1
405 reg: CVII4(INDIRI1(addr)) "lb $%c,%0\n" 1
406 reg: CVII4(INDIRI2(addr)) "lh $%c,%0\n" 1
407 reg: CVUU4(INDIRU1(addr)) "lbu $%c,%0\n" 1
408 reg: CVUU4(INDIRU2(addr)) "lhu $%c,%0\n" 1
409 reg: CVUI4(INDIRU1(addr)) "lbu $%c,%0\n" 1
410 reg: CVUI4(INDIRU2(addr)) "lhu $%c,%0\n" 1
411 reg: INDIRF4(addr) "l.s $f%c,%0\n" 1
412 reg: INDIRF8(addr) "l.d $f%c,%0\n" 1
413 stmt: ASGNF4(addr,reg) "s.s $f%1,%0\n" 1
414 stmt: ASGNF8(addr,reg) "s.d $f%1,%0\n" 1
415 reg: DIVI4(reg,reg) "div $%c,$%0,$%1\n" 1
416 reg: DIVU4(reg,reg) "divu $%c,$%0,$%1\n" 1
417 reg: MODI4(reg,reg) "rem $%c,$%0,$%1\n" 1
418 reg: MODU4(reg,reg) "remu $%c,$%0,$%1\n" 1
419 reg: MULI4(reg,reg) "mul $%c,$%0,$%1\n" 1
420 reg: MULU4(reg,reg) "mul $%c,$%0,$%1\n" 1
424 reg: ADDI4(reg,rc) "addu $%c,$%0,%1\n" 1
425 reg: ADDP4(reg,rc) "addu $%c,$%0,%1\n" 1
426 reg: ADDU4(reg,rc) "addu $%c,$%0,%1\n" 1
427 reg: BANDI4(reg,rc) "and $%c,$%0,%1\n" 1
428 reg: BORI4(reg,rc) "or $%c,$%0,%1\n" 1
429 reg: BXORI4(reg,rc) "xor $%c,$%0,%1\n" 1
430 reg: BANDU4(reg,rc) "and $%c,$%0,%1\n" 1
431 reg: BORU4(reg,rc) "or $%c,$%0,%1\n" 1
432 reg: BXORU4(reg,rc) "xor $%c,$%0,%1\n" 1
433 reg: SUBI4(reg,rc) "subu $%c,$%0,%1\n" 1
434 reg: SUBP4(reg,rc) "subu $%c,$%0,%1\n" 1
435 reg: SUBU4(reg,rc) "subu $%c,$%0,%1\n" 1
436 rc5: CNSTI4 "%a" range(a,0,31)
439 reg: LSHI4(reg,rc5) "sll $%c,$%0,%1\n" 1
440 reg: LSHU4(reg,rc5) "sll $%c,$%0,%1\n" 1
441 reg: RSHI4(reg,rc5) "sra $%c,$%0,%1\n" 1
442 reg: RSHU4(reg,rc5) "srl $%c,$%0,%1\n" 1
443 reg: BCOMI4(reg) "not $%c,$%0\n" 1
444 reg: BCOMU4(reg) "not $%c,$%0\n" 1
445 reg: NEGI4(reg) "negu $%c,$%0\n" 1
446 reg: LOADI1(reg) "move $%c,$%0\n" move(a)
447 reg: LOADU1(reg) "move $%c,$%0\n" move(a)
448 reg: LOADI2(reg) "move $%c,$%0\n" move(a)
449 reg: LOADU2(reg) "move $%c,$%0\n" move(a)
450 reg: LOADI4(reg) "move $%c,$%0\n" move(a)
451 reg: LOADP4(reg) "move $%c,$%0\n" move(a)
452 reg: LOADU4(reg) "move $%c,$%0\n" move(a)
453 reg: ADDF4(reg,reg) "add.s $f%c,$f%0,$f%1\n" 1
454 reg: ADDF8(reg,reg) "add.d $f%c,$f%0,$f%1\n" 1
455 reg: DIVF4(reg,reg) "div.s $f%c,$f%0,$f%1\n" 1
456 reg: DIVF8(reg,reg) "div.d $f%c,$f%0,$f%1\n" 1
457 reg: MULF4(reg,reg) "mul.s $f%c,$f%0,$f%1\n" 1
458 reg: MULF8(reg,reg) "mul.d $f%c,$f%0,$f%1\n" 1
459 reg: SUBF4(reg,reg) "sub.s $f%c,$f%0,$f%1\n" 1
460 reg: SUBF8(reg,reg) "sub.d $f%c,$f%0,$f%1\n" 1
461 reg: LOADF4(reg) "mov.s $f%c,$f%0\n" move(a)
462 reg: LOADF8(reg) "mov.d $f%c,$f%0\n" move(a)
463 reg: NEGF4(reg) "neg.s $f%c,$f%0\n" 1
464 reg: NEGF8(reg) "neg.d $f%c,$f%0\n" 1
465 reg: CVII4(reg) "sll $%c,$%0,8*(4-%a); sra $%c,$%c,8*(4-%a)\n" 2
466 reg: CVUI4(reg) "and $%c,$%0,(1<<(8*%a))-1\n" 1
467 reg: CVUU4(reg) "and $%c,$%0,(1<<(8*%a))-1\n" 1
468 reg: CVFF4(reg) "cvt.s.d $f%c,$f%0\n" 1
469 reg: CVFF8(reg) "cvt.d.s $f%c,$f%0\n" 1
470 reg: CVIF4(reg) "mtc1 $%0,$f%c; cvt.s.w $f%c,$f%c\n" 2
471 reg: CVIF8(reg) "mtc1 $%0,$f%c; cvt.d.w $f%c,$f%c\n" 2
472 reg: CVFI4(reg) "trunc.w.s $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i==4?2:LBURG_MAX)
473 reg: CVFI4(reg) "trunc.w.d $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i==8?2:LBURG_MAX)
475 stmt: JUMPV(acon) "b %0\n" 1
476 stmt: JUMPV(reg) ".cpadd $%0\nj $%0\n" !pic
477 stmt: JUMPV(reg) "j $%0\n" pic
478 stmt: EQI4(reg,reg) "beq $%0,$%1,%a\n" 1
479 stmt: EQU4(reg,reg) "beq $%0,$%1,%a\n" 1
480 stmt: GEI4(reg,reg) "bge $%0,$%1,%a\n" 1
481 stmt: GEU4(reg,reg) "bgeu $%0,$%1,%a\n" 1
482 stmt: GTI4(reg,reg) "bgt $%0,$%1,%a\n" 1
483 stmt: GTU4(reg,reg) "bgtu $%0,$%1,%a\n" 1
484 stmt: LEI4(reg,reg) "ble $%0,$%1,%a\n" 1
485 stmt: LEU4(reg,reg) "bleu $%0,$%1,%a\n" 1
486 stmt: LTI4(reg,reg) "blt $%0,$%1,%a\n" 1
487 stmt: LTU4(reg,reg) "bltu $%0,$%1,%a\n" 1
488 stmt: NEI4(reg,reg) "bne $%0,$%1,%a\n" 1
489 stmt: NEU4(reg,reg) "bne $%0,$%1,%a\n" 1
490 stmt: EQF4(reg,reg) "c.eq.s $f%0,$f%1; bc1t %a\n" 2
491 stmt: EQF8(reg,reg) "c.eq.d $f%0,$f%1; bc1t %a\n" 2
492 stmt: LEF4(reg,reg) "c.ule.s $f%0,$f%1; bc1t %a\n" 2
493 stmt: LEF8(reg,reg) "c.ule.d $f%0,$f%1; bc1t %a\n" 2
494 stmt: LTF4(reg,reg) "c.ult.s $f%0,$f%1; bc1t %a\n" 2
495 stmt: LTF8(reg,reg) "c.ult.d $f%0,$f%1; bc1t %a\n" 2
496 stmt: GEF4(reg,reg) "c.lt.s $f%0,$f%1; bc1f %a\n" 2
497 stmt: GEF8(reg,reg) "c.lt.d $f%0,$f%1; bc1f %a\n" 2
498 stmt: GTF4(reg,reg) "c.le.s $f%0,$f%1; bc1f %a\n" 2
499 stmt: GTF8(reg,reg) "c.le.d $f%0,$f%1; bc1f %a\n" 2
500 stmt: NEF4(reg,reg) "c.eq.s $f%0,$f%1; bc1f %a\n" 2
501 stmt: NEF8(reg,reg) "c.eq.d $f%0,$f%1; bc1f %a\n" 2
504 reg: CALLF4(ar) "jal %0\n" 1
505 reg: CALLF8(ar) "jal %0\n" 1
506 reg: CALLI4(ar) "jal %0\n" 1
507 reg: CALLP4(ar) "jal %0\n" 1
508 reg: CALLU4(ar) "jal %0\n" 1
509 stmt: CALLV(ar) "jal %0\n" 1
511 ar: CNSTP4 "%a" range(a, 0, 0x0fffffff)
512 stmt: RETF4(reg) "# ret\n" 1
513 stmt: RETF8(reg) "# ret\n" 1
514 stmt: RETI4(reg) "# ret\n" 1
515 stmt: RETU4(reg) "# ret\n" 1
516 stmt: RETP4(reg) "# ret\n" 1
517 stmt: RETV(reg) "# ret\n" 1
518 stmt: ARGF4(reg) "# arg\n" 1
519 stmt: ARGF8(reg) "# arg\n" 1
520 stmt: ARGI4(reg) "# arg\n" 1
521 stmt: ARGP4(reg) "# arg\n" 1
522 stmt: ARGU4(reg) "# arg\n" 1
524 stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1
525 stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1
527 static void progend(void){}
528 static void progbeg(int argc, char *argv[]) {
538 swap = ((int)(u.i == 1)) != IR->little_endian;
540 print(".set reorder\n");
541 pic = !IR->little_endian;
542 parseflags(argc, argv);
543 for (i = 0; i < argc; i++)
544 if (strncmp(argv[i], "-G", 2) == 0)
545 gnum = atoi(argv[i] + 2);
546 else if (strcmp(argv[i], "-pic=1") == 0
547 || strcmp(argv[i], "-pic=0") == 0)
548 pic = argv[i][5]-'0';
549 for (i = 0; i < 31; i += 2)
550 freg2[i] = mkreg("%d", i, 3, FREG);
551 for (i = 0; i < 32; i++)
552 ireg[i] = mkreg("%d", i, 1, IREG);
553 ireg[29]->x.name = "sp";
554 d6 = mkreg("6", 6, 3, IREG);
555 freg2w = mkwildcard(freg2);
556 iregw = mkwildcard(ireg);
557 tmask[IREG] = INTTMP; tmask[FREG] = FLTTMP;
558 vmask[IREG] = INTVAR; vmask[FREG] = FLTVAR;
559 blkreg = mkreg("8", 8, 7, IREG);
561 static Symbol rmap(int opk) {
562 switch (optype(opk)) {
563 case I: case U: case P: case B:
571 static void target(Node p) {
573 switch (specific(p->op)) {
574 case CNST+I: case CNST+U: case CNST+P:
575 if (range(p, 0, 0) == 0) {
581 rtarget(p, 0, ireg[25]);
584 rtarget(p, 0, ireg[25]);
587 case CALL+I: case CALL+P: case CALL+U:
588 rtarget(p, 0, ireg[25]);
592 rtarget(p, 0, freg2[0]);
594 case RET+I: case RET+U: case RET+P:
595 rtarget(p, 0, ireg[2]);
597 case ARG+F: case ARG+I: case ARG+P: case ARG+U: {
599 int ty = optype(p->op);
602 q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, opsize(p->op), ty0);
606 !(ty == F && q->x.regnode->set == IREG))
610 case ASGN+B: rtarget(p->kids[1], 0, blkreg); break;
611 case ARG+B: rtarget(p->kids[0], 0, blkreg); break;
614 static void clobber(Node p) {
616 switch (specific(p->op)) {
618 spill(INTTMP | INTRET, IREG, p);
619 spill(FLTTMP, FREG, p);
621 case CALL+I: case CALL+P: case CALL+U:
622 spill(INTTMP, IREG, p);
623 spill(FLTTMP | FLTRET, FREG, p);
626 spill(INTTMP | INTRET, IREG, p);
627 spill(FLTTMP | FLTRET, FREG, p);
631 static void emit2(Node p) {
632 int dst, n, src, sz, ty;
636 switch (specific(p->op)) {
637 case ARG+F: case ARG+I: case ARG+P: case ARG+U:
642 q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, sz, ty0);
643 src = getregnum(p->x.kids[0]);
644 if (q == NULL && ty == F && sz == 4)
645 print("s.s $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i);
646 else if (q == NULL && ty == F)
647 print("s.d $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i);
649 print("sw $%d,%d($sp)\n", src, p->syms[2]->u.c.v.i);
650 else if (ty == F && sz == 4 && q->x.regnode->set == IREG)
651 print("mfc1 $%d,$f%d\n", q->x.regnode->number, src);
652 else if (ty == F && q->x.regnode->set == IREG)
653 print("mfc1.d $%d,$f%d\n", q->x.regnode->number, src);
656 dalign = salign = p->syms[1]->u.c.v.i;
657 blkcopy(getregnum(p->x.kids[0]), 0,
658 getregnum(p->x.kids[1]), 0,
659 p->syms[0]->u.c.v.i, tmpregs);
663 salign = p->syms[1]->u.c.v.i;
664 blkcopy(29, p->syms[2]->u.c.v.i,
665 getregnum(p->x.kids[0]), 0,
666 p->syms[0]->u.c.v.i, tmpregs);
667 n = p->syms[2]->u.c.v.i + p->syms[0]->u.c.v.i;
668 dst = p->syms[2]->u.c.v.i;
669 for ( ; dst <= 12 && dst < n; dst += 4)
670 print("lw $%d,%d($sp)\n", (dst/4)+4, dst);
674 static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) {
675 assert((offset&3) == 0);
678 else if (argno == 0 && ty == F)
680 else if (argno == 1 && ty == F && ty0 == F)
682 else if (argno == 1 && ty == F && sz == 8)
683 return d6; /* Pair! */
685 return ireg[(offset/4) + 4];
687 static void doarg(Node p) {
693 p->x.argno = argno++;
694 align = p->syms[1]->u.c.v.i < 4 ? 4 : p->syms[1]->u.c.v.i;
695 p->syms[2] = intconst(mkactual(align,
696 p->syms[0]->u.c.v.i));
698 static void local(Symbol p) {
699 if (askregvar(p, rmap(ttob(p->type))) == 0)
702 static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
703 int i, saved, sizefsave, sizeisave, varargs;
704 Symbol r, argregs[4];
706 usedmask[0] = usedmask[1] = 0;
707 freemask[0] = freemask[1] = ~(unsigned)0;
708 offset = maxoffset = maxargoffset = 0;
709 for (i = 0; callee[i]; i++)
711 varargs = variadic(f->type)
712 || i > 0 && strcmp(callee[i-1]->name, "va_alist") == 0;
713 for (i = 0; callee[i]; i++) {
714 Symbol p = callee[i];
715 Symbol q = caller[i];
717 offset = roundup(offset, q->type->align);
718 p->x.offset = q->x.offset = offset;
719 p->x.name = q->x.name = stringd(offset);
720 r = argreg(i, offset, optype(ttob(q->type)), q->type->size, optype(ttob(caller[0]->type)));
723 offset = roundup(offset + q->type->size, 4);
726 else if (r && ncalls == 0 &&
727 !isstruct(q->type) && !p->addressed &&
728 !(isfloat(q->type) && r->x.regnode->set == IREG)
730 p->sclass = q->sclass = REGISTER;
732 assert(p->x.regnode && p->x.regnode->vbl == p);
736 else if (askregvar(p, rmap(ttob(p->type)))
738 && (isint(p->type) || p->type == q->type)) {
739 assert(q->sclass != REGISTER);
740 p->sclass = q->sclass = REGISTER;
746 gencode(caller, callee);
748 usedmask[IREG] |= ((unsigned)1)<<31;
749 usedmask[IREG] &= 0xc0ff0000;
750 usedmask[FREG] &= 0xfff00000;
752 usedmask[IREG] |= 1<<25;
753 maxargoffset = roundup(maxargoffset, usedmask[FREG] ? 8 : 4);
754 if (ncalls && maxargoffset < 16)
756 sizefsave = 4*bitcount(usedmask[FREG]);
757 sizeisave = 4*bitcount(usedmask[IREG]);
758 framesize = roundup(maxargoffset + sizefsave
759 + sizeisave + maxoffset, 16);
762 print(".ent %s\n", f->x.name);
763 print("%s:\n", f->x.name);
764 i = maxargoffset + sizefsave - framesize;
765 print(".frame $sp,%d,$31\n", framesize);
767 print(".set noreorder\n.cpload $25\n.set reorder\n");
769 print("addu $sp,$sp,%d\n", -framesize);
771 print(".fmask 0x%x,%d\n", usedmask[FREG], i - 8);
773 print(".mask 0x%x,%d\n", usedmask[IREG],
775 saved = maxargoffset;
776 for (i = 20; i <= 30; i += 2)
777 if (usedmask[FREG]&(3<<i)) {
778 print("s.d $f%d,%d($sp)\n", i, saved);
782 for (i = 16; i <= 31; i++)
783 if (usedmask[IREG]&(1<<i)) {
785 print(".cprestore %d\n", saved);
787 print("sw $%d,%d($sp)\n", i, saved);
790 for (i = 0; i < 4 && callee[i]; i++) {
792 if (r && r->x.regnode != callee[i]->x.regnode) {
793 Symbol out = callee[i];
794 Symbol in = caller[i];
795 int rn = r->x.regnode->number;
796 int rs = r->x.regnode->set;
797 int tyin = ttob(in->type);
799 assert(out && in && r && r->x.regnode);
800 assert(out->sclass != REGISTER || out->x.regnode);
801 if (out->sclass == REGISTER
802 && (isint(out->type) || out->type == in->type)) {
803 int outn = out->x.regnode->number;
804 if (rs == FREG && tyin == F+sizeop(8))
805 print("mov.d $f%d,$f%d\n", outn, rn);
806 else if (rs == FREG && tyin == F+sizeop(4))
807 print("mov.s $f%d,$f%d\n", outn, rn);
808 else if (rs == IREG && tyin == F+sizeop(8))
809 print("mtc1.d $%d,$f%d\n", rn, outn);
810 else if (rs == IREG && tyin == F+sizeop(4))
811 print("mtc1 $%d,$f%d\n", rn, outn);
813 print("move $%d,$%d\n", outn, rn);
815 int off = in->x.offset + framesize;
816 if (rs == FREG && tyin == F+sizeop(8))
817 print("s.d $f%d,%d($sp)\n", rn, off);
818 else if (rs == FREG && tyin == F+sizeop(4))
819 print("s.s $f%d,%d($sp)\n", rn, off);
821 int i, n = (in->type->size + 3)/4;
822 for (i = rn; i < rn+n && i <= 7; i++)
823 print("sw $%d,%d($sp)\n", i, off + (i-rn)*4);
828 if (varargs && callee[i-1]) {
829 i = callee[i-1]->x.offset + callee[i-1]->type->size;
830 for (i = roundup(i, 4)/4; i <= 3; i++)
831 print("sw $%d,%d($sp)\n", i + 4, framesize + 4*i);
834 saved = maxargoffset;
835 for (i = 20; i <= 30; i += 2)
836 if (usedmask[FREG]&(3<<i)) {
837 print("l.d $f%d,%d($sp)\n", i, saved);
840 for (i = 16; i <= 31; i++)
841 if (usedmask[IREG]&(1<<i)) {
842 print("lw $%d,%d($sp)\n", i, saved);
846 print("addu $sp,$sp,%d\n", framesize);
848 print(".end %s\n", f->x.name);
850 static void defconst(int suffix, int size, Value v) {
851 if (suffix == F && size == 4) {
853 print(".word 0x%x\n", *(unsigned *)&f);
855 else if (suffix == F && size == 8) {
857 unsigned *p = (unsigned *)&d;
858 print(".word 0x%x\n.word 0x%x\n", p[swap], p[!swap]);
860 else if (suffix == P)
861 print(".word 0x%x\n", (unsigned)v.p);
863 print(".byte 0x%x\n", (unsigned)((unsigned char)(suffix == I ? v.i : v.u)));
865 print(".half 0x%x\n", (unsigned)((unsigned short)(suffix == I ? v.i : v.u)));
867 print(".word 0x%x\n", (unsigned)(suffix == I ? v.i : v.u));
869 static void defaddress(Symbol p) {
870 if (pic && p->scope == LABELS)
871 print(".gpword %s\n", p->x.name);
873 print(".word %s\n", p->x.name);
875 static void defstring(int n, char *str) {
878 for (s = str; s < str + n; s++)
879 print(".byte %d\n", (*s)&0377);
881 static void export(Symbol p) {
882 print(".globl %s\n", p->x.name);
884 static void import(Symbol p) {
885 if (!isfunc(p->type))
886 print(".extern %s %d\n", p->name, p->type->size);
888 static void defsymbol(Symbol p) {
889 if (p->scope >= LOCAL && p->sclass == STATIC)
890 p->x.name = stringf("L.%d", genlabel(1));
891 else if (p->generated)
892 p->x.name = stringf("L.%s", p->name);
894 assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)),
897 static void address(Symbol q, Symbol p, long n) {
898 if (p->scope == GLOBAL
899 || p->sclass == STATIC || p->sclass == EXTERN)
900 q->x.name = stringf("%s%s%D", p->x.name,
901 n >= 0 ? "+" : "", n);
903 assert(n <= INT_MAX && n >= INT_MIN);
904 q->x.offset = p->x.offset + n;
905 q->x.name = stringd(q->x.offset);
908 static void global(Symbol p) {
909 if (p->u.seg == BSS) {
910 if (p->sclass == STATIC || Aflag >= 2)
911 print(".lcomm %s,%d\n", p->x.name, p->type->size);
913 print( ".comm %s,%d\n", p->x.name, p->type->size);
916 && (p->type->size == 0 || p->type->size > gnum))
918 else if (p->u.seg == DATA)
920 print(".align %c\n", ".01.2...3"[p->type->align]);
921 print("%s:\n", p->x.name);
924 static void segment(int n) {
927 case CODE: print(".text\n"); break;
928 case LIT: print(".rdata\n"); break;
931 static void space(int n) {
933 print(".space %d\n", n);
935 static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) {
936 int lab = genlabel(1);
938 print("addu $%d,$%d,%d\n", sreg, sreg, size&~7);
939 print("addu $%d,$%d,%d\n", tmps[2], dreg, size&~7);
940 blkcopy(tmps[2], doff, sreg, soff, size&7, tmps);
941 print("L.%d:\n", lab);
942 print("addu $%d,$%d,%d\n", sreg, sreg, -8);
943 print("addu $%d,$%d,%d\n", tmps[2], tmps[2], -8);
944 blkcopy(tmps[2], doff, sreg, soff, 8, tmps);
945 print("bltu $%d,$%d,L.%d\n", dreg, tmps[2], lab);
947 static void blkfetch(int size, int off, int reg, int tmp) {
948 assert(size == 1 || size == 2 || size == 4);
950 print("lbu $%d,%d($%d)\n", tmp, off, reg);
951 else if (salign >= size && size == 2)
952 print("lhu $%d,%d($%d)\n", tmp, off, reg);
953 else if (salign >= size)
954 print("lw $%d,%d($%d)\n", tmp, off, reg);
956 print("ulhu $%d,%d($%d)\n", tmp, off, reg);
958 print("ulw $%d,%d($%d)\n", tmp, off, reg);
960 static void blkstore(int size, int off, int reg, int tmp) {
962 print("sb $%d,%d($%d)\n", tmp, off, reg);
963 else if (dalign >= size && size == 2)
964 print("sh $%d,%d($%d)\n", tmp, off, reg);
965 else if (dalign >= size)
966 print("sw $%d,%d($%d)\n", tmp, off, reg);
968 print("ush $%d,%d($%d)\n", tmp, off, reg);
970 print("usw $%d,%d($%d)\n", tmp, off, reg);
972 static void stabinit(char *, int, char *[]);
973 static void stabline(Coordinate *);
974 static void stabsym(Symbol);
976 static char *currentfile;
978 static int bitcount(unsigned mask) {
981 for (i = 1; i; i <<= 1)
987 /* stabinit - initialize stab output */
988 static void stabinit(char *file, int argc, char *argv[]) {
990 print(".file 2,\"%s\"\n", file);
995 /* stabline - emit stab entry for source coordinate *cp */
996 static void stabline(Coordinate *cp) {
997 if (cp->file && cp->file != currentfile) {
998 print(".file 2,\"%s\"\n", cp->file);
999 currentfile = cp->file;
1001 print(".loc 2,%d\n", cp->y);
1004 /* stabsym - output a stab entry for symbol p */
1005 static void stabsym(Symbol p) {
1006 if (p == cfunc && IR->stabline)
1007 (*IR->stabline)(&p->src);
1009 Interface mipsebIR = {
1011 2, 2, 0, /* short */
1014 4, 4, 0, /* long long */
1015 4, 4, 1, /* float */
1016 8, 8, 1, /* double */
1017 8, 8, 1, /* long double */
1019 0, 1, 0, /* struct */
1020 0, /* little_endian */
1021 0, /* mulops_calls */
1022 0, /* wants_callb */
1024 1, /* left_to_right */
1026 0, /* unsigned_char */
1045 0, 0, 0, stabinit, stabline, stabsym, 0,
1047 4, /* max_unaligned_load */
1049 blkfetch, blkstore, blkloop,
1066 2, 2, 0, /* short */
1069 4, 4, 0, /* long long */
1070 4, 4, 1, /* float */
1071 8, 8, 1, /* double */
1072 8, 8, 1, /* long double */
1074 0, 1, 0, /* struct */
1075 1, /* little_endian */
1076 0, /* mulops_calls */
1077 0, /* wants_callb */
1079 1, /* left_to_right */
1081 0, /* unsigned_char */
1100 0, 0, 0, stabinit, stabline, stabsym, 0,
1102 4, /* max_unaligned_load */
1104 blkfetch, blkstore, blkloop,
1120 static char rcsid[] = "$Id$";