📄 romp.c
字号:
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_INT (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 const 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) { REAL_VALUE_TYPE r; REAL_VALUE_FROM_CONST_DOUBLE (r, immed[i]); assemble_real (r, GET_MODE (immed[i]), GET_MODE_ALIGNMENT (GET_MODE (immed[i]))); } 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;}/* Return the offset value of an automatic variable (N_LSYM) having the given offset. Basically, we correct by going from a frame pointer to stack pointer value.*/intromp_debugger_auto_correction(offset) int offset;{ int fp_to_sp; /* We really want to go from STACK_POINTER_REGNUM to FRAME_POINTER_REGNUM, but this isn't defined. So go the other direction and negate. */ INITIAL_ELIMINATION_OFFSET (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM, fp_to_sp); /* The offset value points somewhere between the frame pointer and the stack pointer. What is up from the frame pointer is down from the stack pointer. Therefore the negation in the offset value too. */ return -(offset+fp_to_sp+4);}/* Return the offset value of an argument having the given offset. Basically, we correct by going from an arg pointer to stack pointer value. */intromp_debugger_arg_correction (offset) int offset;{ int fp_to_argp; INITIAL_ELIMINATION_OFFSET (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM, fp_to_argp); /* Actually, something different happens if offset is from a floating-point register argument, but we don't handle it here. */ return (offset - fp_to_argp);}voidromp_initialize_trampoline (tramp, fnaddr, cxt) rtx tramp, fnaddr, cxt;{ rtx addr, temp, val; temp = expand_simple_binop (SImode, PLUS, tramp, GEN_INT (4), 0, 1, OPTAB_LIB_WIDEN); emit_move_insn (gen_rtx_MEM (SImode, memory_address (SImode, tramp)), temp); val = force_reg (SImode, cxt); addr = memory_address (HImode, plus_constant (tramp, 10)); emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, val)); temp = expand_shift (RSHIFT_EXPR, SImode, val, build_int_2 (16, 0), 0, 1); addr = memory_address (HImode, plus_constant (tramp, 6)); emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, temp)); val = force_reg (SImode, fnaddr); addr = memory_address (HImode, plus_constant (tramp, 24)); emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, val)); temp = expand_shift (RSHIFT_EXPR, SImode, val, build_int_2 (16, 0), 0, 1); addr = memory_address (HImode, plus_constant (tramp, 20)); emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, temp));}/* On ROMP, all constants are in the data area. */static voidromp_select_rtx_section (mode, x, align) enum machine_mode mode ATTRIBUTE_UNUSED; rtx x ATTRIBUTE_UNUSED; unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;{ data section ();}/* For no good reason, we do the same as the other RT compilers and load the addresses of data areas for a function from our data area. That means that we need to mark such SYMBOL_REFs. We do so here. */static voidromp_encode_section_info (decl, first) tree decl; int first ATTRIBUTE_UNUSED;{ if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE) SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -