📄 i960.c
字号:
sprintf (lbuf, "b LR%d", ret_label); return lbuf; } /* Must clear g14 on return if this function set it. Only varargs/stdarg functions modify g14. */ if (VARARGS_STDARG_FUNCTION (current_function_decl)) 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 or quad. */ fprintf (file, "%s", reg_names[REGNO (x)+1]); break; case 'E': /* Third reg of a quad. */ fprintf (file, "%s", reg_names[REGNO (x)+2]); break; case 'F': /* Fourth reg of a quad. */ fprintf (file, "%s", reg_names[REGNO (x)+3]); 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) { REAL_VALUE_TYPE d; char dstr[30]; if (x == CONST0_RTX (GET_MODE (x))) { fprintf (file, "0f0.0"); return; } else if (x == CONST1_RTX (GET_MODE (x))) { fprintf (file, "0f1.0"); return; } REAL_VALUE_FROM_CONST_DOUBLE (d, x); REAL_VALUE_TO_DECIMAL (d, "%#g", dstr); fprintf (file, "0f%s", dstr); 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) { ireg = 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. *//* These two macros allow us to accept either a REG or a SUBREG anyplace where a register is valid. */#define RTX_OK_FOR_BASE_P(X, STRICT) \ ((GET_CODE (X) == REG \ && (STRICT ? REG_OK_FOR_BASE_P_STRICT (X) : REG_OK_FOR_BASE_P (X))) \ || (GET_CODE (X) == SUBREG \ && GET_CODE (SUBREG_REG (X)) == REG \ && (STRICT ? REG_OK_FOR_BASE_P_STRICT (SUBREG_REG (X)) \ : REG_OK_FOR_BASE_P (SUBREG_REG (X)))))#define RTX_OK_FOR_INDEX_P(X, STRICT) \ ((GET_CODE (X) == REG \ && (STRICT ? REG_OK_FOR_INDEX_P_STRICT (X) : REG_OK_FOR_INDEX_P (X)))\ || (GET_CODE (X) == SUBREG \ && GET_CODE (SUBREG_REG (X)) == REG \ && (STRICT ? REG_OK_FOR_INDEX_P_STRICT (SUBREG_REG (X)) \ : REG_OK_FOR_INDEX_P (SUBREG_REG (X)))))intlegitimate_address_p (mode, addr, strict) enum machine_mode mode; register rtx addr; int strict;{ if (RTX_OK_FOR_BASE_P (addr, strict)) return 1; 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 (RTX_OK_FOR_BASE_P (op0, strict)) { if (RTX_OK_FOR_INDEX_P (op1, strict)) return 1; else if (CONSTANT_P (op1)) return 1; else return 0; } else if (GET_CODE (op0) == PLUS) { if (GET_CODE (XEXP (op0, 0)) == MULT) { if (! (RTX_OK_FOR_INDEX_P (XEXP (XEXP (op0, 0), 0), strict) && SCALE_TERM_P (XEXP (XEXP (op0, 0), 1)))) return 0; if (RTX_OK_FOR_BASE_P (XEXP (op0, 1), strict) && CONSTANT_P (op1)) return 1; else return 0; } else if (RTX_OK_FOR_BASE_P (XEXP (op0, 0), strict)) { if (RTX_OK_FOR_INDEX_P (XEXP (op0, 1), strict) && CONSTANT_P (op1)) return 1; else return 0; } else return 0; } else if (GET_CODE (op0) == MULT) { if (! (RTX_OK_FOR_INDEX_P (XEXP (op0, 0), strict) && SCALE_TERM_P (XEXP (op0, 1)))) return 0; if (RTX_OK_FOR_BASE_P (op1, strict)) return 1; 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 (RTX_OK_FOR_INDEX_P (XEXP (addr, 0), strict) && 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); } else if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 1)) == CONST_INT) { constant = XEXP (XEXP (XEXP (x, 0), 1), 1); other = XEXP (x, 1); } else constant = 0; if (constant) x = gen_rtx (PLUS, Pmode, gen_rtx (PLUS, Pmode, XEXP (XEXP (x, 0), 0), XEXP (XEXP (XEXP (x, 0), 1), 0)), plus_constant (other, INTVAL (constant))); } return x;}#if 0/* Return the most stringent alignment that we are willing to consider objects of size SIZE and known alignment ALIGN as having. */ inti960_alignment (size, align) int size; int align;{ int i; if (! TARGET_STRICT_ALIGN) if (TARGET_IC_COMPAT2_0 || align >= 4) { i = i960_object_bytes_bitalign (size) / BITS_PER_UNIT; if (i > align) align = i; } return align;}#endif/* Modes for condition codes. */#define C_MODES \ ((1 << (int) CCmode) | (1 << (int) CC_UNSmode) | (1<< (int) CC_CHKmode))/* Modes for single-word (and smaller) quantities. */#define S_MODES \ (~C_MODES \ & ~ ((1 << (int) DImode) | (1 << (int) TImode) \ | (1 << (int) DFmode) | (1 << (int) XFmode)))/* Modes for double-word (and smaller) quantities. */#define D_MODES \ (~C_MODES \ & ~ ((1 << (int) TImode) | (1 << (int) XFmode)))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -