📄 romp.c
字号:
noperands = 1 + (op1 != 0) + (op2 != 0); /* Compute hash code for entire expression and see if operation block already exists. */ hash = ((int) code << 13) + (hash0 << 2) + (hash1 << 1) + hash2; hash %= FP_HASH_SIZE; for (fpop = fp_hash_table[hash], last_fpop = 0; fpop; last_fpop = fpop, fpop = fpop->next_same_hash) if (fpop->opcode == code && noperands == fpop->noperands && (op0 == 0 || rtx_equal_p (op0, fpop->ops[0])) && (op1 == 0 || rtx_equal_p (op1, fpop->ops[1])) && (op2 == 0 || rtx_equal_p (op2, fpop->ops[2]))) goto win; /* We have never seen this operation before. */ fpop = (struct fp_op *) oballoc (sizeof (struct fp_op)); fpop->mem_offset = data_offset; fpop->opcode = code; fpop->noperands = noperands; fpop->ops[0] = op0; fpop->ops[1] = op1; fpop->ops[2] = op2; /* Compute the size using the rules in Appendix A of the RT Linkage Convention (4.3/RT-PSD:5) manual. These rules are a bit ambiguous, but if we guess wrong, it will effect only efficiency, not correctness. */ /* Size = 24 + 32 for each non-fp (or fr7) */ size = 24; if (op0 && (GET_CODE (op0) != REG || ! FP_REGNO_P (REGNO (op0)) || REGNO (op0) == 23)) size += 32; if (op1 && (GET_CODE (op1) != REG || ! FP_REGNO_P (REGNO (op1)) || REGNO (op1) == 23)) size += 32; if (op2 && (GET_CODE (op2) != REG || ! FP_REGNO_P (REGNO (op2)) || REGNO (op2) == 23)) size += 32; /* Size + 12 for each conversion. First get operation mode. */ if ((op0 && GET_MODE (op0) == DFmode) || (op1 && GET_MODE (op1) == DFmode) || (op2 && GET_MODE (op2) == DFmode)) opmode = DFmode; else opmode = SFmode; if (op0 && GET_MODE (op0) != opmode) size += 12; if (op1 && GET_MODE (op1) != opmode) size += 12; if (op2 && GET_MODE (op2) != opmode) size += 12; /* 12 more if first and third operand types not the same. */ if (op2 && GET_MODE (op0) != GET_MODE (op2)) size += 12; /* CMP and CMPT need additional. Also, compute size of save/restore here. */ if (code == EQ) size += 32; else if (code == GE) size += 64; else if (code == USE || code == CLOBBER) { /* 34 + 24 for each additional register plus 8 if fr7 saved. (We call it 36 because we need to keep the block length a multiple of four. */ size = 36 - 24; for (i = 0; i <= 7; i++) if (INTVAL (op0) & (1 << (7-i))) size += 24 + 8 * (i == 7); } /* We provide no general-purpose scratch registers. */ size +=16; /* No floating-point scratch registers are provided. Compute extra length due to this. This logic is that shown in the referenced appendix. */ i = 0; if (op0 && GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0))) i++; if (op1 && GET_CODE (op1) == REG && FP_REGNO_P (REGNO (op1))) i++; if (op2 && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2))) i++; if ((op0 == 0 || GET_CODE (op0) != REG || REGNO(op0) != 17) && (op1 == 0 || GET_CODE (op1) != REG || REGNO(op1) != 17) && (op2 == 0 || GET_CODE (op2) != REG || REGNO(op2) != 17)) fr0_avail = 1; if (dyadic) { if (i == 0) size += fr0_avail ? 64 : 112; else if (fpop->noperands == 2 && i == 1) size += fr0_avail ? 0 : 64; else if (fpop->noperands == 3) { if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0)) && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2))) { if (REGNO (op0) == REGNO (op2))#if 1 /* This triggers a bug on the RT. */ abort ();#else size += fr0_avail ? 0 : 64;#endif } else { i = 0; if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0))) i++; if (GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2))) i++; if (i == 0) size += fr0_avail ? 64 : 112; else if (i == 1) size += fr0_avail ? 0 : 64; } } } else if (code != USE && code != CLOBBER && (GET_CODE (op0) != REG || ! FP_REGNO_P (REGNO (op0)))) size += 64; if (! TARGET_FULL_FP_BLOCKS) { /* If we are not to pad the blocks, just compute its actual length. */ size = 12; /* Header + opcode */ if (code == USE || code == CLOBBER) size += 2; else { if (op0) size += 2; if (op1) size += 2; if (op2) size += 2; } /* If in the middle of a word, round. */ if (size % UNITS_PER_WORD) size += 2; /* Handle any immediates. */ if (code != USE && code != CLOBBER && op0 && GET_CODE (op0) != REG) size += 4; if (op1 && GET_CODE (op1) != REG) size += 4; if (op2 && GET_CODE (op2) != REG) size += 4; if (code != USE && code != CLOBBER && op0 && GET_CODE (op0) == CONST_DOUBLE && GET_MODE (op0) == DFmode) size += 4; if (op1 && GET_CODE (op1) == CONST_DOUBLE && GET_MODE (op1) == DFmode) size += 4; if (op2 && GET_CODE (op2) == CONST_DOUBLE && GET_MODE (op2) == DFmode) size += 4; } /* Done with size computation! Chain this in. */ fpop->size = size; data_offset += size / UNITS_PER_WORD; fpop->next_in_mem = 0; fpop->next_same_hash = 0; if (last_fpop_in_mem) last_fpop_in_mem->next_in_mem = fpop; else first_fpop = fpop; last_fpop_in_mem = fpop; if (last_fpop) last_fpop->next_same_hash = fpop; else fp_hash_table[hash] = fpop;win: /* FPOP describes the operation to be performed. Return a string to branch to it. */ if (fpop->mem_offset < 32768 / UNITS_PER_WORD) sprintf (outbuf, "cal r15,%d(r14)\n\tbalr%s r15,r15", fpop->mem_offset * UNITS_PER_WORD, dbr_sequence_length () ? "x" : ""); else sprintf (outbuf, "get r15,$L%dF%d\n\tbalr%s r15,r15", subr_number, fpop->mem_offset * UNITS_PER_WORD, dbr_sequence_length () ? "x" : ""); return outbuf;}/* If necessary, output a floating-point operation to save or restore all floating-point registers. file is the file to write the operation to, CODE is USE for save, CLOBBER for restore, and ADDR is the address of the same area, as RTL. */static voidoutput_loadsave_fpregs (file, code, addr) FILE *file; enum rtx_code code; rtx addr;{ register int i; register int mask = 0; for (i = 2 + (TARGET_FP_REGS != 0); i <= 7; i++) if (regs_ever_live[i + 17]) mask |= 1 << (7 - i); if (mask) fprintf (file, "\t%s\n", output_fpop (code, gen_rtx (CONST_INT, VOIDmode, mask), gen_rtx (MEM, Pmode, addr), 0, const0_rtx));}/* Output any floating-point operations at the end of the routine. */static voidoutput_fpops (file) FILE *file;{ register struct fp_op *fpop; register int size_so_far; register int i; rtx immed[3]; if (first_fpop == 0) return; data_section (); ASM_OUTPUT_ALIGN (file, 2); for (fpop = first_fpop; fpop; fpop = fpop->next_in_mem) { if (fpop->mem_offset < 32768 / UNITS_PER_WORD) fprintf (file, "# data area offset = %d\n", fpop->mem_offset * UNITS_PER_WORD); else fprintf (file, "L%dF%d:\n", subr_number, fpop->mem_offset * UNITS_PER_WORD); fprintf (file, "\tcas r0,r15,r0\n"); fprintf (file, "\t.long FPGLUE\n"); switch (fpop->opcode) { case USE: fprintf (file, "\t.byte 0x1d\t# STOREM\n"); break; case CLOBBER: fprintf (file, "\t.byte 0x0f\t# LOADM\n"); break; case ABS: fprintf (file, "\t.byte 0x00\t# ABS\n"); break; case PLUS: fprintf (file, "\t.byte 0x02\t# ADD\n"); break; case EQ: fprintf (file, "\t.byte 0x07\t# CMP\n"); break; case GE: fprintf (file, "\t.byte 0x08\t# CMPT\n"); break; case DIV: fprintf (file, "\t.byte 0x0c\t# DIV\n"); break; case SET: fprintf (file, "\t.byte 0x14\t# MOVE\n"); break; case MULT: fprintf (file, "\t.byte 0x15\t# MUL\n"); break; case NEG: fprintf (file, "\t.byte 0x16\t# NEG\n"); break; case SQRT: fprintf (file, "\t.byte 0x1c\t# SQRT\n"); break; case MINUS: fprintf (file, "\t.byte 0x1e\t# SUB\n"); break; default: abort (); } fprintf (file, "\t.byte %d\n", fpop->noperands); fprintf (file, "\t.short 0x8001\n"); if ((fpop->ops[0] == 0 || GET_CODE (fpop->ops[0]) != REG || REGNO(fpop->ops[0]) != 17) && (fpop->ops[1] == 0 || GET_CODE (fpop->ops[1]) != REG || REGNO(fpop->ops[1]) != 17) && (fpop->ops[2] == 0 || GET_CODE (fpop->ops[2]) != REG || REGNO(fpop->ops[2]) != 17)) fprintf (file, "\t.byte %d, 0x80\n", fpop->size); else fprintf (file, "\t.byte %d, 0\n", fpop->size); size_so_far = 12; for (i = 0; i < fpop->noperands; i++) { register int type; register int opbyte; register char *desc0; char desc1[50]; immed[i] = 0; switch (GET_MODE (fpop->ops[i])) { case SImode: case VOIDmode: desc0 = "int"; type = 0; break; case SFmode: desc0 = "float"; type = 2; break; case DFmode: desc0 = "double"; type = 3; break; default: abort (); } switch (GET_CODE (fpop->ops[i])) { case REG: strcpy(desc1, reg_names[REGNO (fpop->ops[i])]); if (FP_REGNO_P (REGNO (fpop->ops[i]))) { type += 0x10; opbyte = REGNO (fpop->ops[i]) - 17; } else { type += 0x00; opbyte = REGNO (fpop->ops[i]); if (type == 3) opbyte = (opbyte << 4) + opbyte + 1; } break; case MEM: type += 0x30; if (GET_CODE (XEXP (fpop->ops[i], 0)) == PLUS) { immed[i] = XEXP (XEXP (fpop->ops[i], 0), 1); opbyte = REGNO (XEXP (XEXP (fpop->ops[i], 0), 0)); if (GET_CODE (immed[i]) == CONST_INT) sprintf (desc1, "%d(%s)", INTVAL (immed[i]), reg_names[opbyte]); else sprintf (desc1, "<memory> (%s)", reg_names[opbyte]); } else if (GET_CODE (XEXP (fpop->ops[i], 0)) == REG) { opbyte = REGNO (XEXP (fpop->ops[i], 0)); immed[i] = const0_rtx; sprintf (desc1, "(%s)", reg_names[opbyte]); } else { immed[i] = XEXP (fpop->ops[i], 0); opbyte = 0; sprintf(desc1, "<memory>"); } break; case CONST_INT: case CONST_DOUBLE: case CONST: case SYMBOL_REF: case LABEL_REF: type += 0x20; opbyte = 0; immed[i] = fpop->ops[i]; desc1[0] = '$'; desc1[1] = '\0'; break; default: abort (); } /* Save/restore is special. */ if (i == 0 && (fpop->opcode == USE || fpop->opcode == CLOBBER)) type = 0xff, opbyte = INTVAL (fpop->ops[0]), immed[i] = 0; fprintf (file, "\t.byte 0x%x,0x%x # (%s) %s\n", type, opbyte, desc0, desc1); size_so_far += 2; } /* If in the middle of a word, round. */ if (size_so_far % UNITS_PER_WORD) { fprintf (file, "\t.space 2\n"); size_so_far += 2; } for (i = 0; i < fpop->noperands; i++) if (immed[i]) switch (GET_MODE (immed[i])) { case SImode: case VOIDmode: size_so_far += 4; fprintf (file, "\t.long "); output_addr_const (file, immed[i]); fprintf (file, "\n"); break; case DFmode: size_so_far += 4; case SFmode: size_so_far += 4; if (GET_CODE (immed[i]) == CONST_DOUBLE) { union real_extract u; bcopy (&CONST_DOUBLE_LOW (immed[i]), &u, sizeof u); if (GET_MODE (immed[i]) == DFmode) ASM_OUTPUT_DOUBLE (file, u.d); else ASM_OUTPUT_FLOAT (file, u.d); } else abort (); break; default: abort (); } if (size_so_far != fpop->size) { if (TARGET_FULL_FP_BLOCKS) fprintf (file, "\t.space %d\n", fpop->size - size_so_far); else abort (); } } /* Update for next subroutine. */ subr_number++; text_section ();} /* Initialize floating-point operation table. */static voidinit_fpops(){ register int i; first_fpop = last_fpop_in_mem = 0; for (i = 0; i < FP_HASH_SIZE; i++) fp_hash_table[i] = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -