📄 cris.c
字号:
putc (INTVAL (x) >= -128 && INTVAL (x) <= 255 ? 'b' : 'w', file); return; case '#': /* Output a 'nop' if there's nothing for the delay slot. This method stolen from the sparc files. */ if (dbr_sequence_length () == 0) fputs ("\n\tnop", file); return; case 'H': /* Print high (most significant) part of something. */ switch (GET_CODE (operand)) { case CONST_INT: if (HOST_BITS_PER_WIDE_INT == 32) /* Sign-extension from a normal int to a long long. */ fprintf (file, INTVAL (operand) < 0 ? "-1" : "0"); else fprintf (file, "0x%x", (unsigned int)(INTVAL (x) >> 31 >> 1)); return; case CONST_DOUBLE: /* High part of a long long constant. */ if (GET_MODE (operand) == VOIDmode) { fprintf (file, "0x%x", CONST_DOUBLE_HIGH (x)); return; } else LOSE_AND_RETURN ("invalid operand for 'H' modifier", x); case REG: /* Print reg + 1. Check that there's not an attempt to print high-parts of registers like stack-pointer or higher. */ if (REGNO (operand) > STACK_POINTER_REGNUM - 2) LOSE_AND_RETURN ("bad register", operand); fprintf (file, "$%s", reg_names[REGNO (operand) + 1]); return; case MEM: /* Adjust memory address to high part. */ { rtx adj_mem = operand; int size = GET_MODE_BITSIZE (GET_MODE (operand)) / BITS_PER_UNIT; /* Adjust so we can use two SImode in DImode. Calling adj_offsettable_operand will make sure it is an offsettable address. Don't do this for a postincrement though; it should remain as it was. */ if (GET_CODE (XEXP (adj_mem, 0)) != POST_INC) adj_mem = adjust_address (adj_mem, GET_MODE (adj_mem), size / 2); output_address (XEXP (adj_mem, 0)); return; } default: LOSE_AND_RETURN ("invalid operand for 'H' modifier", x); } case 'L': /* Strip the MEM expression. */ operand = XEXP (operand, 0); break; case 'e': /* Print 's' if operand is SIGN_EXTEND or 'u' if ZERO_EXTEND unless cris_output_insn_is_bound is nonzero. */ if (GET_CODE (operand) != SIGN_EXTEND && GET_CODE (operand) != ZERO_EXTEND && GET_CODE (operand) != CONST_INT) LOSE_AND_RETURN ("invalid operand for 'e' modifier", x); if (cris_output_insn_is_bound) { cris_output_insn_is_bound = 0; return; } putc (GET_CODE (operand) == SIGN_EXTEND || (GET_CODE (operand) == CONST_INT && INTVAL (operand) < 0) ? 's' : 'u', file); return; case 'm': /* Print the size letter of the inner element. We can do it by calling ourselves with the 's' modifier. */ if (GET_CODE (operand) != SIGN_EXTEND && GET_CODE (operand) != ZERO_EXTEND) LOSE_AND_RETURN ("invalid operand for 'm' modifier", x); cris_print_operand (file, XEXP (operand, 0), 's'); return; case 'M': /* Print the least significant part of operand. */ if (GET_CODE (operand) == CONST_DOUBLE) { fprintf (file, "0x%x", CONST_DOUBLE_LOW (x)); return; } else if (HOST_BITS_PER_WIDE_INT > 32 && GET_CODE (operand) == CONST_INT) { fprintf (file, "0x%x", INTVAL (x) & ((unsigned int) 0x7fffffff * 2 + 1)); return; } /* Otherwise the least significant part equals the normal part, so handle it normally. */ break; case 'A': /* When emitting an add for the high part of a DImode constant, we want to use addq for 0 and adds.w for -1. */ if (GET_CODE (operand) != CONST_INT) LOSE_AND_RETURN ("invalid operand for 'A' modifier", x); fprintf (file, INTVAL (operand) < 0 ? "adds.w" : "addq"); return; case 'D': /* When emitting an sub for the high part of a DImode constant, we want to use subq for 0 and subs.w for -1. */ if (GET_CODE (operand) != CONST_INT) LOSE_AND_RETURN ("invalid operand for 'D' modifier", x); fprintf (file, INTVAL (operand) < 0 ? "subs.w" : "subq"); return; case 'S': /* Print the operand as the index-part of an address. Easiest way out is to use cris_print_index. */ cris_print_index (operand, file); return; case 'T': /* Print the size letter for an operand to a MULT, which must be a const_int with a suitable value. */ if (GET_CODE (operand) != CONST_INT || INTVAL (operand) > 4) LOSE_AND_RETURN ("invalid operand for 'T' modifier", x); fprintf (file, "%s", mults[INTVAL (operand)]); return; case 0: /* No code, print as usual. */ break; default: LOSE_AND_RETURN ("invalid operand modifier letter", x); } /* Print an operand as without a modifier letter. */ switch (GET_CODE (operand)) { case REG: if (REGNO (operand) > 15) internal_error ("internal error: bad register: %d", REGNO (operand)); fprintf (file, "$%s", reg_names[REGNO (operand)]); return; case MEM: output_address (XEXP (operand, 0)); return; case CONST_DOUBLE: if (GET_MODE (operand) == VOIDmode) /* A long long constant. */ output_addr_const (file, operand); else { /* Only single precision is allowed as plain operands the moment. FIXME: REAL_VALUE_FROM_CONST_DOUBLE isn't documented. */ REAL_VALUE_TYPE r; long l; /* FIXME: Perhaps check overflow of the "single". */ REAL_VALUE_FROM_CONST_DOUBLE (r, operand); REAL_VALUE_TO_TARGET_SINGLE (r, l); fprintf (file, "0x%lx", l); } return; case UNSPEC: ASSERT_PLT_UNSPEC (operand); /* Fall through. */ case CONST: cris_output_addr_const (file, operand); return; case MULT: case ASHIFT: { /* For a (MULT (reg X) const_int) we output "rX.S". */ int i = GET_CODE (XEXP (operand, 1)) == CONST_INT ? INTVAL (XEXP (operand, 1)) : INTVAL (XEXP (operand, 0)); rtx reg = GET_CODE (XEXP (operand, 1)) == CONST_INT ? XEXP (operand, 0) : XEXP (operand, 1); if (GET_CODE (reg) != REG || (GET_CODE (XEXP (operand, 0)) != CONST_INT && GET_CODE (XEXP (operand, 1)) != CONST_INT)) LOSE_AND_RETURN ("unexpected multiplicative operand", x); cris_print_base (reg, file); fprintf (file, ".%c", i == 0 || (i == 1 && GET_CODE (operand) == MULT) ? 'b' : i == 4 ? 'd' : (i == 2 && GET_CODE (operand) == MULT) || i == 1 ? 'w' : 'd'); return; } default: /* No need to handle all strange variants, let output_addr_const do it for us. */ if (CONSTANT_P (operand)) { cris_output_addr_const (file, operand); return; } LOSE_AND_RETURN ("unexpected operand", x); }}/* The PRINT_OPERAND_ADDRESS worker. */voidcris_print_operand_address (file, x) FILE *file; rtx x;{ /* All these were inside MEM:s so output indirection characters. */ putc ('[', file); if (CONSTANT_ADDRESS_P (x)) cris_output_addr_const (file, x); else if (BASE_OR_AUTOINCR_P (x)) cris_print_base (x, file); else if (GET_CODE (x) == PLUS) { rtx x1, x2; x1 = XEXP (x, 0); x2 = XEXP (x, 1); if (BASE_P (x1)) { cris_print_base (x1, file); cris_print_index (x2, file); } else if (BASE_P (x2)) { cris_print_base (x2, file); cris_print_index (x1, file); } else LOSE_AND_RETURN ("unrecognized address", x); } else if (GET_CODE (x) == MEM) { /* A DIP. Output more indirection characters. */ putc ('[', file); cris_print_base (XEXP (x, 0), file); putc (']', file); } else LOSE_AND_RETURN ("unrecognized address", x); putc (']', file);}/* The RETURN_ADDR_RTX worker. We mark that the return address is used, either by EH or __builtin_return_address, for use by the function prologue and epilogue. FIXME: This isn't optimal; we just use the mark in the prologue and epilogue to say that the return address is to be stored in the stack frame. We could return SRP for leaf-functions and use the initial-value machinery. */rtxcris_return_addr_rtx (count, frameaddr) int count; rtx frameaddr ATTRIBUTE_UNUSED;{ cfun->machine->needs_return_address_on_stack = 1; /* The return-address is stored just above the saved frame-pointer (if present). Apparently we can't eliminate from the frame-pointer in that direction, so use the incoming args (maybe pretended) pointer. */ return count == 0 ? gen_rtx_MEM (Pmode, plus_constant (virtual_incoming_args_rtx, -4)) : NULL_RTX;}/* This used to be the INITIAL_FRAME_POINTER_OFFSET worker; now only handles FP -> SP elimination offset. */static intcris_initial_frame_pointer_offset (){ int regno; /* Initial offset is 0 if we don't have a frame pointer. */ int offs = 0; /* And 4 for each register pushed. */ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if ((((regs_ever_live[regno] && !call_used_regs[regno]) || (regno == (int) PIC_OFFSET_TABLE_REGNUM && (current_function_uses_pic_offset_table /* It is saved anyway, if there would be a gap. */ || (flag_pic && regs_ever_live[regno + 1] && !call_used_regs[regno + 1])))) && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed) && regno != CRIS_SRP_REGNUM) || (current_function_calls_eh_return && (regno == EH_RETURN_DATA_REGNO (0) || regno == EH_RETURN_DATA_REGNO (1) || regno == EH_RETURN_DATA_REGNO (2) || regno == EH_RETURN_DATA_REGNO (3)))) offs += 4; /* And then, last, we add the locals allocated. */ offs += get_frame_size (); /* And more; the accumulated args size. */ offs += current_function_outgoing_args_size; /* Then round it off, in case we use aligned stack. */ if (TARGET_STACK_ALIGN) offs = TARGET_ALIGN_BY_32 ? (offs + 3) & ~3 : (offs + 1) & ~1; return offs;}/* The INITIAL_ELIMINATION_OFFSET worker. Calculate the difference between imaginary registers such as frame pointer and the stack pointer. Used to eliminate the frame pointer and imaginary arg pointer. */intcris_initial_elimination_offset (fromreg, toreg) int fromreg; int toreg;{ int fp_sp_offset = cris_initial_frame_pointer_offset (); /* We should be able to use regs_ever_live and related prologue information here, or alpha should not as well. */ int return_address_on_stack = regs_ever_live[CRIS_SRP_REGNUM] || cfun->machine->needs_return_address_on_stack != 0; /* Here we act as if the frame-pointer is needed. */ int ap_fp_offset = 4 + (return_address_on_stack ? 4 : 0); if (fromreg == ARG_POINTER_REGNUM && toreg == FRAME_POINTER_REGNUM) return ap_fp_offset; /* Between the frame pointer and the stack are only "normal" stack variables and saved registers. */ if (fromreg == FRAME_POINTER_REGNUM && toreg == STACK_POINTER_REGNUM) return fp_sp_offset; /* We need to balance out the frame pointer here. */ if (fromreg == ARG_POINTER_REGNUM && toreg == STACK_POINTER_REGNUM) return ap_fp_offset + fp_sp_offset - 4; abort ();}/* This function looks into the pattern to see how this insn affects condition codes. Used when to eliminate test insns before a condition-code user, such as a "scc" insn or a conditional branch. This includes checking if the entities that cc was updated by, are changed by the operation. Currently a jumble of the old peek-inside-the-insn and the newer check-cc-attribute methods. */voidcris_notice_update_cc (exp, insn) rtx exp; rtx insn;{ /* Check if user specified "-mcc-init" as a bug-workaround. FIXME: TARGET_CCINIT does not work; we must set CC_REVERSED as below. Several test-cases will otherwise fail, for example gcc.c-torture/execute/20000217-1.c -O0 and -O1. */ if (TARGET_CCINIT) { CC_STATUS_INIT; return; } /* Slowly, we're converting to using attributes to control the setting of condition-code status. */ switch (get_attr_cc (insn)) { case CC_NONE: /* Even if it is "none", a setting may clobber a previous cc-value, so check. */ if (GET_CODE (exp) == SET) { if (cc_status.value1 && cris_reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)) cc_status.value1 = 0; if (cc_status.value2 && cris_reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)) cc_status.value2 = 0; } return; case CC_CLOBBER: CC_STATUS_INIT; break; case CC_NORMAL: /* Which means, for: (set (cc0) (...)): CC is (...). (set (reg) (...)): CC is (reg) and (...) - unless (...) is 0, then CC does not change. CC_NO_OVERFLOW unless (...) is reg or mem. (set (mem) (...)): CC does not change. (set (pc) (...)): CC does not change. (parallel (set (reg1) (mem (bdap/biap))) (set (reg2) (bdap/biap))): CC is (reg1) and (mem (reg2)) (parallel (set (mem (bdap/biap)) (reg1)) [or 0] (set (reg2) (bdap/biap))): CC does not change. (where reg and mem includes strict_low_parts variants thereof) For all others, assume CC is clobbered. Note that we do not have to care about setting CC_NO_OVERFLOW, since the overflow flag is set to 0 (i.e. right) for
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -