📄 i960.c
字号:
voidi960_function_epilogue (file, size) FILE *file; unsigned int size;{ if (i960_leaf_ret_reg >= 0) { fprintf (file, "LR%d: ret\n", ret_label); return; } if (*epilogue_string == 0) { register rtx tmp; /* Emit a return insn, but only if control can fall through to here. */ tmp = get_last_insn (); while (tmp) { if (GET_CODE (tmp) == BARRIER) return; if (GET_CODE (tmp) == CODE_LABEL) break; if (GET_CODE (tmp) == JUMP_INSN) { if (GET_CODE (PATTERN (tmp)) == RETURN) return; break; } if (GET_CODE (tmp) == NOTE) { tmp = PREV_INSN (tmp); continue; } break; } fprintf (file, "LR%d: ret\n", ret_label); return; } fprintf (file, "LR%d:\n", ret_label); fprintf (file, "\t#EPILOGUE#\n"); /* Output the string created by the prologue which will restore all registers saved by the prologue. */ if (epilogue_string[0] != '\0') fprintf (file, "%s", epilogue_string); /* Must clear g14 on return. */ if (current_function_args_size != 0) fprintf (file, "\tmov 0,g14\n"); fprintf (file, "\tret\n"); fprintf (file, "\t#End Epilogue#\n");}/* Output code for a call insn. */char *i960_output_call_insn (target, argsize_rtx, arg_pointer, scratch_reg, insn) register rtx target, argsize_rtx, arg_pointer, scratch_reg, insn;{ int argsize = INTVAL (argsize_rtx); rtx nexti = next_real_insn (insn); rtx operands[3]; operands[0] = target; operands[1] = arg_pointer; operands[2] = scratch_reg; if (current_function_args_size != 0) output_asm_insn ("mov g14,%2", operands); if (argsize > 48) output_asm_insn ("lda %a1,g14", operands); else if (current_function_args_size != 0) output_asm_insn ("mov 0,g14", operands); /* The code used to assume that calls to SYMBOL_REFs could not be more than 24 bits away (b vs bx, callj vs callx). This is not true. This feature is now implemented by relaxing in the GNU linker. It can convert bx to b if in range, and callx to calls/call/balx/bal as appropriate. */ /* Nexti could be zero if the called routine is volatile. */ if (optimize && (*epilogue_string == 0) && argsize == 0 && tail_call_ok && (nexti == 0 || GET_CODE (PATTERN (nexti)) == RETURN)) { /* Delete following return insn. */ if (nexti && no_labels_between_p (insn, nexti)) delete_insn (nexti); output_asm_insn ("bx %0", operands); return "# notreached"; } output_asm_insn ("callx %0", operands); if (current_function_args_size != 0) output_asm_insn ("mov %2,g14", operands); return "";}/* Output code for a return insn. */char *i960_output_ret_insn (insn) register rtx insn;{ static char lbuf[20]; if (*epilogue_string != 0) { if (! TARGET_CODE_ALIGN && next_real_insn (insn) == 0) return ""; sprintf (lbuf, "b LR%d", ret_label); return lbuf; } if (current_function_args_size != 0) output_asm_insn ("mov 0,g14", 0); if (i960_leaf_ret_reg >= 0) { sprintf (lbuf, "bx (%s)", reg_names[i960_leaf_ret_reg]); return lbuf; } return "ret";}#if 0/* Return a character string representing the branch prediction opcode to be tacked on an instruction. This must at least return a null string. */char *i960_br_predict_opcode (lab_ref, insn) rtx lab_ref, insn;{ if (TARGET_BRANCH_PREDICT) { unsigned long label_uid; if (GET_CODE (lab_ref) == CODE_LABEL) label_uid = INSN_UID (lab_ref); else if (GET_CODE (lab_ref) == LABEL_REF) label_uid = INSN_UID (XEXP (lab_ref, 0)); else return ".f"; /* If not optimizing, then the insn_addresses array will not be valid. In this case, always return ".t" since most branches are taken. If optimizing, return .t for backward branches and .f for forward branches. */ if (! optimize || insn_addresses[label_uid] < insn_addresses[INSN_UID (insn)]) return ".t"; return ".f"; } return "";}#endif/* Print the operand represented by rtx X formatted by code CODE. */voidi960_print_operand (file, x, code) FILE *file; rtx x; char code;{ enum rtx_code rtxcode = GET_CODE (x); if (rtxcode == REG) { switch (code) { case 'D': /* Second reg of a double. */ fprintf (file, "%s", reg_names[REGNO (x)+1]); break; case 0: fprintf (file, "%s", reg_names[REGNO (x)]); break; default: abort (); } return; } else if (rtxcode == MEM) { output_address (XEXP (x, 0)); return; } else if (rtxcode == CONST_INT) { if (INTVAL (x) > 9999 || INTVAL (x) < -999) fprintf (file, "0x%x", INTVAL (x)); else fprintf (file, "%d", INTVAL (x)); return; } else if (rtxcode == CONST_DOUBLE) { double d; if (x == CONST0_RTX (DFmode) || x == CONST0_RTX (SFmode)) { fprintf (file, "0f0.0"); return; } else if (x == CONST1_RTX (DFmode) || x == CONST1_RTX (SFmode)) { fprintf (file, "0f1.0"); return; } /* This better be a comment. */ REAL_VALUE_FROM_CONST_DOUBLE (d, x); fprintf (file, "%#g", d); return; } switch(code) { case 'B': /* Branch or jump, depending on assembler. */ if (TARGET_ASM_COMPAT) fputs ("j", file); else fputs ("b", file); break; case 'S': /* Sign of condition. */ if ((rtxcode == EQ) || (rtxcode == NE) || (rtxcode == GTU) || (rtxcode == LTU) || (rtxcode == GEU) || (rtxcode == LEU)) fputs ("o", file); else if ((rtxcode == GT) || (rtxcode == LT) || (rtxcode == GE) || (rtxcode == LE)) fputs ("i", file); else abort(); break; case 'I': /* Inverted condition. */ rtxcode = reverse_condition (rtxcode); goto normal; case 'X': /* Inverted condition w/ reversed operands. */ rtxcode = reverse_condition (rtxcode); /* Fallthrough. */ case 'R': /* Reversed operand condition. */ rtxcode = swap_condition (rtxcode); /* Fallthrough. */ case 'C': /* Normal condition. */ normal: if (rtxcode == EQ) { fputs ("e", file); return; } else if (rtxcode == NE) { fputs ("ne", file); return; } else if (rtxcode == GT) { fputs ("g", file); return; } else if (rtxcode == GTU) { fputs ("g", file); return; } else if (rtxcode == LT) { fputs ("l", file); return; } else if (rtxcode == LTU) { fputs ("l", file); return; } else if (rtxcode == GE) { fputs ("ge", file); return; } else if (rtxcode == GEU) { fputs ("ge", file); return; } else if (rtxcode == LE) { fputs ("le", file); return; } else if (rtxcode == LEU) { fputs ("le", file); return; } else abort (); break; case 0: output_addr_const (file, x); break; default: abort (); } return;}/* Print a memory address as an operand to reference that memory location. This is exactly the same as legitimate_address_p, except that it the prints addresses instead of recognizing them. */voidi960_print_operand_addr (file, addr) FILE *file; register rtx addr;{ rtx breg, ireg; rtx scale, offset; ireg = 0; breg = 0; offset = 0; scale = const1_rtx; if (GET_CODE (addr) == REG) breg = addr; else if (CONSTANT_P (addr)) offset = addr; else if (GET_CODE (addr) == PLUS) { rtx op0, op1; op0 = XEXP (addr, 0); op1 = XEXP (addr, 1); if (GET_CODE (op0) == REG) { breg = op0; if (GET_CODE (op1) == REG) ireg = op1; else if (CONSTANT_P (op1)) offset = op1; else abort (); } else if (GET_CODE (op0) == PLUS) { if (GET_CODE (XEXP (op0, 0)) == MULT) { ireg = XEXP (XEXP (op0, 0), 0); scale = XEXP (XEXP (op0, 0), 1); if (GET_CODE (XEXP (op0, 1)) == REG) { breg = XEXP (op0, 1); offset = op1; } else abort (); } else if (GET_CODE (XEXP (op0, 0)) == REG) { breg = XEXP (op0, 0); if (GET_CODE (XEXP (op0, 1)) == REG) { ireg = XEXP (op0, 1); offset = op1; } else abort (); } else abort (); } else if (GET_CODE (op0) == MULT) { ireg = XEXP (op0, 0); scale = XEXP (op0, 1); if (GET_CODE (op1) == REG) breg = op1; else if (CONSTANT_P (op1)) offset = op1; else abort (); } else abort (); } else if (GET_CODE (addr) == MULT) { breg = XEXP (addr, 0); scale = XEXP (addr, 1); } else abort (); if (offset) output_addr_const (file, offset); if (breg) fprintf (file, "(%s)", reg_names[REGNO (breg)]); if (ireg) fprintf (file, "[%s*%d]", reg_names[REGNO (ireg)], INTVAL (scale));}/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a valid memory address for an instruction. The MODE argument is the machine mode for the MEM expression that wants to use this address. On 80960, legitimate addresses are: base ld (g0),r0 disp (12 or 32 bit) ld foo,r0 base + index ld (g0)[g1*1],r0 base + displ ld 0xf00(g0),r0 base + index*scale + displ ld 0xf00(g0)[g1*4],r0 index*scale + base ld (g0)[g1*4],r0 index*scale + displ ld 0xf00[g1*4],r0 index*scale ld [g1*4],r0 index + base + displ ld 0xf00(g0)[g1*1],r0 In each case, scale can be 1, 2, 4, 8, or 16. *//* This is exactly the same as i960_print_operand_addr, except that it recognizes addresses instead of printing them. It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should convert common non-canonical forms to canonical form so that they will be recognized. */intlegitimate_address_p (mode, addr, strict) enum machine_mode mode; register rtx addr; int strict;{ if (GET_CODE (addr) == REG) return (strict ? REG_OK_FOR_BASE_P_STRICT (addr) : REG_OK_FOR_BASE_P (addr)); else if (CONSTANT_P (addr)) return 1; else if (GET_CODE (addr) == PLUS) { rtx op0, op1; if (! TARGET_COMPLEX_ADDR && ! reload_completed) return 0; op0 = XEXP (addr, 0); op1 = XEXP (addr, 1); if (GET_CODE (op0) == REG) { if (! (strict ? REG_OK_FOR_BASE_P_STRICT (op0) : REG_OK_FOR_BASE_P (op0))) return 0; if (GET_CODE (op1) == REG) return (strict ? REG_OK_FOR_INDEX_P_STRICT (op1) : REG_OK_FOR_INDEX_P (op1)); else if (CONSTANT_P (op1)) return 1; else return 0; } else if (GET_CODE (op0) == PLUS) { if (GET_CODE (XEXP (op0, 0)) == MULT) { if (! (GET_CODE (XEXP (XEXP (op0, 0), 0)) == REG && (strict ? REG_OK_FOR_INDEX_P_STRICT (XEXP (XEXP (op0, 0), 0)) : REG_OK_FOR_INDEX_P (XEXP (XEXP (op0, 0), 0))) && SCALE_TERM_P (XEXP (XEXP (op0, 0), 1)))) return 0; if (GET_CODE (XEXP (op0, 1)) == REG) return ((strict ? REG_OK_FOR_BASE_P_STRICT (XEXP (op0, 1)) : REG_OK_FOR_BASE_P (XEXP (op0, 1))) && CONSTANT_P (op1)); else return 0; } else if (GET_CODE (XEXP (op0, 0)) == REG) { if (! (strict ? REG_OK_FOR_BASE_P_STRICT (XEXP (op0, 0)) : REG_OK_FOR_BASE_P (XEXP (op0, 0)))) return 0; if (GET_CODE (XEXP (op0, 1)) == REG) return ((strict ? REG_OK_FOR_INDEX_P_STRICT (XEXP (op0, 1)) : REG_OK_FOR_INDEX_P (XEXP (op0, 1))) && CONSTANT_P (op1)); else return 0; } else return 0; } else if (GET_CODE (op0) == MULT) { if (! (GET_CODE (XEXP (op0, 0)) == REG && (strict ? REG_OK_FOR_INDEX_P_STRICT (XEXP (op0, 0)) : REG_OK_FOR_INDEX_P (XEXP (op0, 0))) && SCALE_TERM_P (XEXP (op0, 1)))) return 0; if (GET_CODE (op1) == REG) return (strict ? REG_OK_FOR_BASE_P_STRICT (op1) : REG_OK_FOR_BASE_P (op1)); else if (CONSTANT_P (op1)) return 1; else return 0; } else return 0; } else if (GET_CODE (addr) == MULT) { if (! TARGET_COMPLEX_ADDR && ! reload_completed) return 0; return (GET_CODE (XEXP (addr, 0)) == REG && (strict ? REG_OK_FOR_INDEX_P_STRICT (XEXP (addr, 0)) : REG_OK_FOR_INDEX_P (XEXP (addr, 0))) && SCALE_TERM_P (XEXP (addr, 1))); } else return 0;}/* Try machine-dependent ways of modifying an illegitimate address to be legitimate. If we find one, return the new, valid address. This macro is used in only one place: `memory_address' in explow.c. This converts some non-canonical addresses to canonical form so they can be recognized. */rtxlegitimize_address (x, oldx, mode) register rtx x; register rtx oldx; enum machine_mode mode;{ if (GET_CODE (x) == SYMBOL_REF) { abort (); x = copy_to_reg (x); } if (! TARGET_COMPLEX_ADDR && ! reload_completed) return x; /* Canonicalize (plus (mult (reg) (const)) (plus (reg) (const))) into (plus (plus (mult (reg) (const)) (reg)) (const)). This can be created by virtual register instantiation, register elimination, and similar optimizations. */ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == PLUS) x = gen_rtx (PLUS, Pmode, gen_rtx (PLUS, Pmode, XEXP (x, 0), XEXP (XEXP (x, 1), 0)), XEXP (XEXP (x, 1), 1)); /* Canonicalize (plus (plus (mult (reg) (const)) (plus (reg) (const))) const) into (plus (plus (mult (reg) (const)) (reg)) (const)). */ else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT && GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS && CONSTANT_P (XEXP (x, 1))) { rtx constant, other; if (GET_CODE (XEXP (x, 1)) == CONST_INT) { constant = XEXP (x, 1); other = XEXP (XEXP (XEXP (x, 0), 1), 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -