📄 fr30.c
字号:
/* Print an operand. */voidfr30_print_operand (FILE *file, rtx x, int code){ rtx x0; switch (code) { case '#': /* Output a :D if this instruction is delayed. */ if (dbr_sequence_length () != 0) fputs (":D", file); return; case 'p': /* Compute the register name of the second register in a hi/lo register pair. */ if (GET_CODE (x) != REG) output_operand_lossage ("fr30_print_operand: unrecognized %%p code"); else fprintf (file, "r%d", REGNO (x) + 1); return; case 'b': /* Convert GCC's comparison operators into FR30 comparison codes. */ switch (GET_CODE (x)) { case EQ: fprintf (file, "eq"); break; case NE: fprintf (file, "ne"); break; case LT: fprintf (file, "lt"); break; case LE: fprintf (file, "le"); break; case GT: fprintf (file, "gt"); break; case GE: fprintf (file, "ge"); break; case LTU: fprintf (file, "c"); break; case LEU: fprintf (file, "ls"); break; case GTU: fprintf (file, "hi"); break; case GEU: fprintf (file, "nc"); break; default: output_operand_lossage ("fr30_print_operand: unrecognized %%b code"); break; } return; case 'B': /* Convert GCC's comparison operators into the complimentary FR30 comparison codes. */ switch (GET_CODE (x)) { case EQ: fprintf (file, "ne"); break; case NE: fprintf (file, "eq"); break; case LT: fprintf (file, "ge"); break; case LE: fprintf (file, "gt"); break; case GT: fprintf (file, "le"); break; case GE: fprintf (file, "lt"); break; case LTU: fprintf (file, "nc"); break; case LEU: fprintf (file, "hi"); break; case GTU: fprintf (file, "ls"); break; case GEU: fprintf (file, "c"); break; default: output_operand_lossage ("fr30_print_operand: unrecognized %%B code"); break; } return; case 'A': /* Print a signed byte value as an unsigned value. */ if (GET_CODE (x) != CONST_INT) output_operand_lossage ("fr30_print_operand: invalid operand to %%A code"); else { HOST_WIDE_INT val; val = INTVAL (x); val &= 0xff; fprintf (file, HOST_WIDE_INT_PRINT_DEC, val); } return; case 'x': if (GET_CODE (x) != CONST_INT || INTVAL (x) < 16 || INTVAL (x) > 32) output_operand_lossage ("fr30_print_operand: invalid %%x code"); else fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) - 16); return; case 'F': if (GET_CODE (x) != CONST_DOUBLE) output_operand_lossage ("fr30_print_operand: invalid %%F code"); else { char str[30]; real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x), sizeof (str), 0, 1); fputs (str, file); } return; case 0: /* Handled below. */ break; default: fprintf (stderr, "unknown code = %x\n", code); output_operand_lossage ("fr30_print_operand: unknown code"); return; } switch (GET_CODE (x)) { case REG: fputs (reg_names [REGNO (x)], file); break; case MEM: x0 = XEXP (x,0); switch (GET_CODE (x0)) { case REG: gcc_assert ((unsigned) REGNO (x0) < ARRAY_SIZE (reg_names)); fprintf (file, "@%s", reg_names [REGNO (x0)]); break; case PLUS: if (GET_CODE (XEXP (x0, 0)) != REG || REGNO (XEXP (x0, 0)) < FRAME_POINTER_REGNUM || REGNO (XEXP (x0, 0)) > STACK_POINTER_REGNUM || GET_CODE (XEXP (x0, 1)) != CONST_INT) { fprintf (stderr, "bad INDEXed address:"); debug_rtx (x); output_operand_lossage ("fr30_print_operand: unhandled MEM"); } else if (REGNO (XEXP (x0, 0)) == FRAME_POINTER_REGNUM) { HOST_WIDE_INT val = INTVAL (XEXP (x0, 1)); if (val < -(1 << 9) || val > ((1 << 9) - 4)) { fprintf (stderr, "frame INDEX out of range:"); debug_rtx (x); output_operand_lossage ("fr30_print_operand: unhandled MEM"); } fprintf (file, "@(r14, #" HOST_WIDE_INT_PRINT_DEC ")", val); } else { HOST_WIDE_INT val = INTVAL (XEXP (x0, 1)); if (val < 0 || val > ((1 << 6) - 4)) { fprintf (stderr, "stack INDEX out of range:"); debug_rtx (x); output_operand_lossage ("fr30_print_operand: unhandled MEM"); } fprintf (file, "@(r15, #" HOST_WIDE_INT_PRINT_DEC ")", val); } break; case SYMBOL_REF: output_address (x0); break; default: fprintf (stderr, "bad MEM code = %x\n", GET_CODE (x0)); debug_rtx (x); output_operand_lossage ("fr30_print_operand: unhandled MEM"); break; } break; case CONST_DOUBLE : /* We handle SFmode constants here as output_addr_const doesn't. */ if (GET_MODE (x) == SFmode) { REAL_VALUE_TYPE d; long l; REAL_VALUE_FROM_CONST_DOUBLE (d, x); REAL_VALUE_TO_TARGET_SINGLE (d, l); fprintf (file, "0x%08lx", l); break; } /* Fall through. Let output_addr_const deal with it. */ default: output_addr_const (file, x); break; } return;}/*}}}*//*{{{ Function arguments */ /* Return true if we should pass an argument on the stack rather than in registers. */static boolfr30_must_pass_in_stack (enum machine_mode mode, tree type){ if (mode == BLKmode) return true; if (type == NULL) return false; return AGGREGATE_TYPE_P (type);}/* Compute the number of word sized registers needed to hold a function argument of mode INT_MODE and tree type TYPE. */intfr30_num_arg_regs (enum machine_mode mode, tree type){ int size; if (targetm.calls.must_pass_in_stack (mode, type)) return 0; if (type && mode == BLKmode) size = int_size_in_bytes (type); else size = GET_MODE_SIZE (mode); return (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;}/* Returns the number of bytes in which *part* of a parameter of machine mode MODE and tree type TYPE (which may be NULL if the type is not known). If the argument fits entirely in the argument registers, or entirely on the stack, then 0 is returned. CUM is the number of argument registers already used by earlier parameters to the function. */static intfr30_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, bool named){ /* Unnamed arguments, i.e. those that are prototyped as ... are always passed on the stack. Also check here to see if all the argument registers are full. */ if (named == 0 || *cum >= FR30_NUM_ARG_REGS) return 0; /* Work out how many argument registers would be needed if this parameter were to be passed entirely in registers. If there are sufficient argument registers available (or if no registers are needed because the parameter must be passed on the stack) then return zero, as this parameter does not require partial register, partial stack stack space. */ if (*cum + fr30_num_arg_regs (mode, type) <= FR30_NUM_ARG_REGS) return 0; return (FR30_NUM_ARG_REGS - *cum) * UNITS_PER_WORD;}/*}}}*//*{{{ Operand predicates */ #ifndef Mmode#define Mmode enum machine_mode#endif/* Returns true iff all the registers in the operands array are in descending or ascending order. */intfr30_check_multiple_regs (rtx *operands, int num_operands, int descending){ if (descending) { unsigned int prev_regno = 0; while (num_operands --) { if (GET_CODE (operands [num_operands]) != REG) return 0; if (REGNO (operands [num_operands]) < prev_regno) return 0; prev_regno = REGNO (operands [num_operands]); } } else { unsigned int prev_regno = CONDITION_CODE_REGNUM; while (num_operands --) { if (GET_CODE (operands [num_operands]) != REG) return 0; if (REGNO (operands [num_operands]) > prev_regno) return 0; prev_regno = REGNO (operands [num_operands]); } } return 1;}intfr30_const_double_is_zero (rtx operand){ REAL_VALUE_TYPE d; if (operand == NULL || GET_CODE (operand) != CONST_DOUBLE) return 0; REAL_VALUE_FROM_CONST_DOUBLE (d, operand); return REAL_VALUES_EQUAL (d, dconst0);}/*}}}*//*{{{ Instruction Output Routines *//* Output a double word move. It must be REG<-REG, REG<-MEM, MEM<-REG or REG<-CONST. On the FR30 we are constrained by the fact that it does not support offsetable addresses, and so we have to load the address of the secnd word into the second destination register before we can use it. */rtxfr30_move_double (rtx * operands){ rtx src = operands[1]; rtx dest = operands[0]; enum rtx_code src_code = GET_CODE (src); enum rtx_code dest_code = GET_CODE (dest); enum machine_mode mode = GET_MODE (dest); rtx val; start_sequence (); if (dest_code == REG) { if (src_code == REG) { int reverse = (REGNO (dest) == REGNO (src) + 1); /* We normally copy the low-numbered register first. However, if the first register of operand 0 is the same as the second register of operand 1, we must copy in the opposite order. */ emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, reverse, TRUE, mode), operand_subword (src, reverse, TRUE, mode))); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, !reverse, TRUE, mode), operand_subword (src, !reverse, TRUE, mode))); } else if (src_code == MEM) { rtx addr = XEXP (src, 0); int dregno = REGNO (dest); rtx dest0; rtx dest1; rtx new_mem; /* If the high-address word is used in the address, we must load it last. Otherwise, load it first. */ int reverse = (refers_to_regno_p (dregno, dregno + 1, addr, 0) != 0); gcc_assert (GET_CODE (addr) == REG); dest0 = operand_subword (dest, reverse, TRUE, mode); dest1 = operand_subword (dest, !reverse, TRUE, mode); if (reverse) { emit_insn (gen_rtx_SET (VOIDmode, dest1, adjust_address (src, SImode, 0))); emit_insn (gen_rtx_SET (SImode, dest0, gen_rtx_REG (SImode, REGNO (addr)))); emit_insn (gen_rtx_SET (SImode, dest0, plus_constant (dest0, UNITS_PER_WORD))); new_mem = gen_rtx_MEM (SImode, dest0); MEM_COPY_ATTRIBUTES (new_mem, src); emit_insn (gen_rtx_SET (VOIDmode, dest0, new_mem)); } else { emit_insn (gen_rtx_SET (VOIDmode, dest0, adjust_address (src, SImode, 0))); emit_insn (gen_rtx_SET (SImode, dest1, gen_rtx_REG (SImode, REGNO (addr)))); emit_insn (gen_rtx_SET (SImode, dest1, plus_constant (dest1, UNITS_PER_WORD))); new_mem = gen_rtx_MEM (SImode, dest1); MEM_COPY_ATTRIBUTES (new_mem, src); emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem)); } } else if (src_code == CONST_INT || src_code == CONST_DOUBLE) { rtx words[2]; split_double (src, &words[0], &words[1]); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, 0, TRUE, mode), words[0])); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, 1, TRUE, mode), words[1])); } } else if (src_code == REG && dest_code == MEM) { rtx addr = XEXP (dest, 0); rtx src0; rtx src1; gcc_assert (GET_CODE (addr) == REG); src0 = operand_subword (src, 0, TRUE, mode); src1 = operand_subword (src, 1, TRUE, mode); emit_insn (gen_rtx_SET (VOIDmode, adjust_address (dest, SImode, 0), src0)); if (REGNO (addr) == STACK_POINTER_REGNUM || REGNO (addr) == FRAME_POINTER_REGNUM) emit_insn (gen_rtx_SET (VOIDmode, adjust_address (dest, SImode, UNITS_PER_WORD), src1)); else { rtx new_mem; /* We need a scratch register to hold the value of 'address + 4'. We ought to allow gcc to find one for us, but for now, just push one of the source registers. */ emit_insn (gen_movsi_push (src0)); emit_insn (gen_movsi_internal (src0, addr)); emit_insn (gen_addsi_small_int (src0, src0, GEN_INT (UNITS_PER_WORD))); new_mem = gen_rtx_MEM (SImode, src0); MEM_COPY_ATTRIBUTES (new_mem, dest); emit_insn (gen_rtx_SET (VOIDmode, new_mem, src1)); emit_insn (gen_movsi_pop (src0)); } } else /* This should have been prevented by the constraints on movdi_insn. */ gcc_unreachable (); val = get_insns (); end_sequence (); return val;}/*}}}*//* Local Variables: *//* folded-file: t *//* End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -