📄 crx.c
字号:
} case REG: if (REGNO (x) + 1 >= FIRST_PSEUDO_REGISTER) abort (); fprintf (file, "%s", reg_names[REGNO (x) + 1]); return; case MEM: /* Adjust memory address to high part. */ { rtx adj_mem = x; adj_mem = adjust_address (adj_mem, GET_MODE (adj_mem), 4); output_memory_reference_mode = GET_MODE (adj_mem); output_address (XEXP (adj_mem, 0)); return; } default: abort (); } case 'L': /* Print low part of a double precision value. */ switch (GET_CODE (x)) { case CONST_DOUBLE: if (GET_MODE (x) == SFmode) abort (); if (GET_MODE (x) == DFmode) { /* High part of a DF const. */ REAL_VALUE_TYPE r; long l[2]; REAL_VALUE_FROM_CONST_DOUBLE (r, x); REAL_VALUE_TO_TARGET_DOUBLE (r, l); fprintf (file, "$0x%lx", l[0]); return; } /* -- Fallthrough to handle DI consts -- */ case CONST_INT: { rtx high, low; split_double (x, &low, &high); putc ('$', file); output_addr_const (file, low); return; } case REG: fprintf (file, "%s", reg_names[REGNO (x)]); return; case MEM: output_memory_reference_mode = GET_MODE (x); output_address (XEXP (x, 0)); return; default: abort (); } case 0 : /* default */ switch (GET_CODE (x)) { case REG: fprintf (file, "%s", reg_names[REGNO (x)]); return; case MEM: output_memory_reference_mode = GET_MODE (x); output_address (XEXP (x, 0)); return; case CONST_DOUBLE: { REAL_VALUE_TYPE r; long l; /* Always use H and L for double precision - see above */ gcc_assert (GET_MODE (x) == SFmode); REAL_VALUE_FROM_CONST_DOUBLE (r, x); REAL_VALUE_TO_TARGET_SINGLE (r, l); fprintf (file, "$0x%lx", l); return; } default: putc ('$', file); output_addr_const (file, x); return; } default: output_operand_lossage ("invalid %%xn code"); } abort ();}/* Implements the macro PRINT_OPERAND_ADDRESS defined in crx.h. */voidcrx_print_operand_address (FILE * file, rtx addr){ enum crx_addrtype addrtype; struct crx_address address; int offset; addrtype = crx_decompose_address (addr, &address); if (address.disp) offset = INTVAL (address.disp); else offset = 0; switch (addrtype) { case CRX_REG_REL: fprintf (file, "%d(%s)", offset, reg_names[REGNO (address.base)]); return; case CRX_POST_INC: switch (GET_CODE (address.side_effect)) { case PLUS: break; case MINUS: offset = -offset; break; case POST_INC: offset = GET_MODE_SIZE (output_memory_reference_mode); break; case POST_DEC: offset = -GET_MODE_SIZE (output_memory_reference_mode); break; default: abort (); } fprintf (file, "%d(%s)+", offset, reg_names[REGNO (address.base)]); return; case CRX_SCALED_INDX: fprintf (file, "%d(%s, %s, %d)", offset, reg_names[REGNO (address.base)], reg_names[REGNO (address.index)], address.scale); return; case CRX_ABSOLUTE: output_addr_const (file, address.disp); return; default: abort (); }}/*****************************************************************************//* MACHINE DESCRIPTION HELPER-FUNCTIONS *//*****************************************************************************/void crx_expand_movmem_single (rtx src, rtx srcbase, rtx dst, rtx dstbase, rtx tmp_reg, unsigned HOST_WIDE_INT *offset_p){ rtx addr, mem; unsigned HOST_WIDE_INT offset = *offset_p; /* Load */ addr = plus_constant (src, offset); mem = adjust_automodify_address (srcbase, SImode, addr, offset); emit_move_insn (tmp_reg, mem); /* Store */ addr = plus_constant (dst, offset); mem = adjust_automodify_address (dstbase, SImode, addr, offset); emit_move_insn (mem, tmp_reg); *offset_p = offset + 4;}intcrx_expand_movmem (rtx dstbase, rtx srcbase, rtx count_exp, rtx align_exp){ unsigned HOST_WIDE_INT count = 0, offset, si_moves, i; HOST_WIDE_INT align = 0; rtx src, dst; rtx tmp_reg; if (GET_CODE (align_exp) == CONST_INT) { /* Only if aligned */ align = INTVAL (align_exp); if (align & 3) return 0; } if (GET_CODE (count_exp) == CONST_INT) { /* No more than 16 SImode moves */ count = INTVAL (count_exp); if (count > 64) return 0; } tmp_reg = gen_reg_rtx (SImode); /* Create psrs for the src and dest pointers */ dst = copy_to_mode_reg (Pmode, XEXP (dstbase, 0)); if (dst != XEXP (dstbase, 0)) dstbase = replace_equiv_address_nv (dstbase, dst); src = copy_to_mode_reg (Pmode, XEXP (srcbase, 0)); if (src != XEXP (srcbase, 0)) srcbase = replace_equiv_address_nv (srcbase, src); offset = 0; /* Emit SImode moves */ si_moves = count >> 2; for (i = 0; i < si_moves; i++) crx_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset); /* Special cases */ if (count & 3) { offset = count - 4; crx_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset); } gcc_assert (offset == count); return 1;}rtxcrx_expand_compare (enum rtx_code code, enum machine_mode mode){ rtx op0, op1, cc_reg, ret; op0 = crx_compare_op0; op1 = crx_compare_op1; /* Emit the compare that writes into CC_REGNUM) */ cc_reg = gen_rtx_REG (CCmode, CC_REGNUM); ret = gen_rtx_COMPARE (CCmode, op0, op1); emit_insn (gen_rtx_SET (VOIDmode, cc_reg, ret)); /* debug_rtx (get_last_insn ()); */ /* Return the rtx for using the result in CC_REGNUM */ return gen_rtx_fmt_ee (code, mode, cc_reg, const0_rtx);}voidcrx_expand_branch (enum rtx_code code, rtx label){ rtx tmp = crx_expand_compare (code, VOIDmode); tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, gen_rtx_LABEL_REF (VOIDmode, label), pc_rtx); emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); /* debug_rtx (get_last_insn ()); */}voidcrx_expand_scond (enum rtx_code code, rtx dest){ rtx tmp = crx_expand_compare (code, GET_MODE (dest)); emit_move_insn (dest, tmp); /* debug_rtx (get_last_insn ()); */}static voidmpushpop_str (char *stringbuffer, const char *mnemonic, char *mask){ if (strlen (mask) > 2 || crx_interrupt_function_p ()) /* needs 2-word instr. */ sprintf (stringbuffer, "\n\t%s\tsp, {%s}", mnemonic, mask); else /* single word instruction */ sprintf (stringbuffer, "\n\t%s\t%s", mnemonic, mask);}/* Called from crx.md. The return value depends on the parameter push_or_pop: * When push_or_pop is zero -> string for push instructions of prologue. * When push_or_pop is nonzero -> string for pop/popret/retx in epilogue. * Relies on the assumptions: * 1. RA is the last register to be saved. * 2. The maximal value of the counter is MAX_COUNT. */char *crx_prepare_push_pop_string (int push_or_pop){ /* j is the number of registers being saved, takes care that there won't be * more than 8 in one push/pop instruction */ /* For the register mask string */ static char mask_str[50]; /* i is the index of save_regs[], going from 0 until last_reg_to_save */ int i = 0; int ra_in_bitmask = 0; char *return_str; /* For reversing on the push instructions if there are more than one. */ char *temp_str; return_str = (char *) xmalloc (120); temp_str = (char *) xmalloc (120); /* Initialize */ memset (return_str, 0, 3); while (i <= last_reg_to_save) { /* Prepare mask for one instruction. */ mask_str[0] = 0; if (i <= SP_REGNUM) { /* Add regs unit full or SP register reached */ int j = 0; while (j < MAX_COUNT && i <= SP_REGNUM) { if (save_regs[i]) { /* TODO to use ra_in_bitmask for detecting last pop is not * smart it prevents things like: popret r5 */ if (i == RETURN_ADDRESS_REGNUM) ra_in_bitmask = 1; if (j > 0) strcat (mask_str, ", "); strcat (mask_str, reg_names[i]); ++j; } ++i; } } else { /* Handle hi/lo savings */ while (i <= last_reg_to_save) { if (save_regs[i]) { strcat (mask_str, "lo, hi"); i = last_reg_to_save + 1; break; } ++i; } } if (strlen (mask_str) == 0) continue; if (push_or_pop == 1) { if (crx_interrupt_function_p ()) mpushpop_str (temp_str, "popx", mask_str); else { if (ra_in_bitmask) { mpushpop_str (temp_str, "popret", mask_str); ra_in_bitmask = 0; } else mpushpop_str (temp_str, "pop", mask_str); } strcat (return_str, temp_str); } else { /* push - We need to reverse the order of the instructions if there * are more than one. (since the pop will not be reversed in the * epilogue */ if (crx_interrupt_function_p ()) mpushpop_str (temp_str, "pushx", mask_str); else mpushpop_str (temp_str, "push", mask_str); strcat (temp_str, return_str); strcpy (strcat (return_str, "\t"), temp_str); } } if (push_or_pop == 1) { /* pop */ if (crx_interrupt_function_p ()) strcat (return_str, "\n\tretx\n"); else if (!FUNC_IS_NORETURN_P (current_function_decl) && !save_regs[RETURN_ADDRESS_REGNUM]) strcat (return_str, "\n\tjump\tra\n"); } /* Skip the newline and the tab in the start of return_str. */ return_str += 2; return return_str;}/* CompactRISC CRX Architecture stack layout: 0 +--------------------- | . . | +==================== Sp(x)=Ap(x+1) A | Args for functions | | called by X and Dynamically | | Dynamic allocations allocated and | | (alloca, variable deallocated Stack | length arrays). grows +-------------------- Fp(x) down| | Local variables of X ward| +-------------------- | | Regs saved for X-1 | +==================== Sp(x-1)=Ap(x) | Args for func X | pushed by X-1 +-------------------- Fp(x-1) | | V*/voidcrx_expand_prologue (void){ crx_compute_frame (); crx_compute_save_regs (); /* If there is no need in push and adjustment to sp, return. */ if (size_for_adjusting_sp + sum_regs == 0) return; if (last_reg_to_save != -1) /* If there are registers to push. */ emit_insn (gen_push_for_prologue (GEN_INT (sum_regs))); if (size_for_adjusting_sp > 0) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-size_for_adjusting_sp))); if (frame_pointer_needed) /* Initialize the frame pointer with the value of the stack pointer * pointing now to the locals. */ emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);}/* Generate insn that updates the stack for local variables and padding for * registers we save. - Generate the appropriate return insn. */voidcrx_expand_epilogue (void){ rtx return_reg; /* Nonzero if we need to return and pop only RA. This will generate a * different insn. This differentiate is for the peepholes for call as last * statement in function. */ int only_popret_RA = (save_regs[RETURN_ADDRESS_REGNUM] && (sum_regs == UNITS_PER_WORD)); /* Return register. */ return_reg = gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM); if (frame_pointer_needed) /* Restore the stack pointer with the frame pointers value */ emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); if (size_for_adjusting_sp > 0) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (size_for_adjusting_sp))); if (crx_interrupt_function_p ()) emit_jump_insn (gen_interrupt_return ()); else if (last_reg_to_save == -1) /* Nothing to pop */ /* Don't output jump for interrupt routine, only retx. */ emit_jump_insn (gen_indirect_jump_return ()); else if (only_popret_RA) emit_jump_insn (gen_popret_RA_return ()); else emit_jump_insn (gen_pop_and_popret_return (GEN_INT (sum_regs)));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -