📄 stormy16.c
字号:
/* Xstormy16 target functions. Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Red Hat, Inc.This file is part of GCC.GCC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GCC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GCC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */#include "config.h"#include "system.h"#include "coretypes.h"#include "tm.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-flags.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "recog.h"#include "toplev.h"#include "obstack.h"#include "tree.h"#include "expr.h"#include "optabs.h"#include "except.h"#include "function.h"#include "target.h"#include "target-def.h"#include "tm_p.h"#include "langhooks.h"#include "tree-gimple.h"static rtx emit_addhi3_postreload (rtx, rtx, rtx);static void xstormy16_asm_out_constructor (rtx, int);static void xstormy16_asm_out_destructor (rtx, int);static void xstormy16_asm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);static void xstormy16_init_builtins (void);static rtx xstormy16_expand_builtin (tree, rtx, rtx, enum machine_mode, int);static bool xstormy16_rtx_costs (rtx, int, int, int *);static int xstormy16_address_cost (rtx);static bool xstormy16_return_in_memory (tree, tree);/* Define the information needed to generate branch and scc insns. This is stored from the compare operation. */struct rtx_def * xstormy16_compare_op0;struct rtx_def * xstormy16_compare_op1;/* Return 1 if this is a LT, GE, LTU, or GEU operator. */intxstormy16_ineqsi_operator (register rtx op, enum machine_mode mode){ enum rtx_code code = GET_CODE (op); return ((mode == VOIDmode || GET_MODE (op) == mode) && (code == LT || code == GE || code == LTU || code == GEU));}/* Return 1 if this is an EQ or NE operator. */intequality_operator (register rtx op, enum machine_mode mode){ return ((mode == VOIDmode || GET_MODE (op) == mode) && (GET_CODE (op) == EQ || GET_CODE (op) == NE));}/* Return 1 if this is a comparison operator but not an EQ or NE operator. */intinequality_operator (register rtx op, enum machine_mode mode){ return comparison_operator (op, mode) && ! equality_operator (op, mode);}/* Compute a (partial) cost for rtx X. Return true if the complete cost has been computed, and false if subexpressions should be scanned. In either case, *TOTAL contains the cost result. */static boolxstormy16_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total){ switch (code) { case CONST_INT: if (INTVAL (x) < 16 && INTVAL (x) >= 0) *total = COSTS_N_INSNS (1) / 2; else if (INTVAL (x) < 256 && INTVAL (x) >= 0) *total = COSTS_N_INSNS (1); else *total = COSTS_N_INSNS (2); return true; case CONST_DOUBLE: case CONST: case SYMBOL_REF: case LABEL_REF: *total = COSTS_N_INSNS(2); return true; case MULT: *total = COSTS_N_INSNS (35 + 6); return true; case DIV: *total = COSTS_N_INSNS (51 - 6); return true; default: return false; }}static intxstormy16_address_cost (rtx x){ return (GET_CODE (x) == CONST_INT ? 2 : GET_CODE (x) == PLUS ? 7 : 5);}/* Branches are handled as follows: 1. HImode compare-and-branches. The machine supports these natively, so the appropriate pattern is emitted directly. 2. SImode EQ and NE. These are emitted as pairs of HImode compare-and-branches. 3. SImode LT, GE, LTU and GEU. These are emitted as a sequence of a SImode subtract followed by a branch (not a compare-and-branch), like this: sub sbc blt 4. SImode GT, LE, GTU, LEU. These are emitted as a sequence like: sub sbc blt or bne*//* Emit a branch of kind CODE to location LOC. */voidxstormy16_emit_cbranch (enum rtx_code code, rtx loc){ rtx op0 = xstormy16_compare_op0; rtx op1 = xstormy16_compare_op1; rtx condition_rtx, loc_ref, branch, cy_clobber; rtvec vec; enum machine_mode mode; mode = GET_MODE (op0); if (mode != HImode && mode != SImode) abort (); if (mode == SImode && (code == GT || code == LE || code == GTU || code == LEU)) { int unsigned_p = (code == GTU || code == LEU); int gt_p = (code == GT || code == GTU); rtx lab = NULL_RTX; if (gt_p) lab = gen_label_rtx (); xstormy16_emit_cbranch (unsigned_p ? LTU : LT, gt_p ? lab : loc); /* This should be generated as a comparison against the temporary created by the previous insn, but reload can't handle that. */ xstormy16_emit_cbranch (gt_p ? NE : EQ, loc); if (gt_p) emit_label (lab); return; } else if (mode == SImode && (code == NE || code == EQ) && op1 != const0_rtx) { rtx lab = NULL_RTX; int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD; int i; if (code == EQ) lab = gen_label_rtx (); for (i = 0; i < num_words - 1; i++) { xstormy16_compare_op0 = simplify_gen_subreg (word_mode, op0, mode, i * UNITS_PER_WORD); xstormy16_compare_op1 = simplify_gen_subreg (word_mode, op1, mode, i * UNITS_PER_WORD); xstormy16_emit_cbranch (NE, code == EQ ? lab : loc); } xstormy16_compare_op0 = simplify_gen_subreg (word_mode, op0, mode, i * UNITS_PER_WORD); xstormy16_compare_op1 = simplify_gen_subreg (word_mode, op1, mode, i * UNITS_PER_WORD); xstormy16_emit_cbranch (code, loc); if (code == EQ) emit_label (lab); return; } /* We can't allow reload to try to generate any reload after a branch, so when some register must match we must make the temporary ourselves. */ if (mode != HImode) { rtx tmp; tmp = gen_reg_rtx (mode); emit_move_insn (tmp, op0); op0 = tmp; } condition_rtx = gen_rtx_fmt_ee (code, mode, op0, op1); loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); branch = gen_rtx_SET (VOIDmode, pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, loc_ref, pc_rtx)); cy_clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (BImode)); if (mode == HImode) vec = gen_rtvec (2, branch, cy_clobber); else if (code == NE || code == EQ) vec = gen_rtvec (2, branch, gen_rtx_CLOBBER (VOIDmode, op0)); else { rtx sub;#if 0 sub = gen_rtx_SET (VOIDmode, op0, gen_rtx_MINUS (SImode, op0, op1));#else sub = gen_rtx_CLOBBER (SImode, op0);#endif vec = gen_rtvec (3, branch, sub, cy_clobber); } emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));}/* Take a SImode conditional branch, one of GT/LE/GTU/LEU, and split the arithmetic operation. Most of the work is done by xstormy16_expand_arith. */voidxstormy16_split_cbranch (enum machine_mode mode, rtx label, rtx comparison, rtx dest, rtx carry){ rtx op0 = XEXP (comparison, 0); rtx op1 = XEXP (comparison, 1); rtx seq, last_insn; rtx compare; start_sequence (); xstormy16_expand_arith (mode, COMPARE, dest, op0, op1, carry); seq = get_insns (); end_sequence (); if (! INSN_P (seq)) abort (); last_insn = seq; while (NEXT_INSN (last_insn) != NULL_RTX) last_insn = NEXT_INSN (last_insn); compare = SET_SRC (XVECEXP (PATTERN (last_insn), 0, 0)); PUT_CODE (XEXP (compare, 0), GET_CODE (comparison)); XEXP (compare, 1) = gen_rtx_LABEL_REF (VOIDmode, label); emit_insn (seq);}/* Return the string to output a conditional branch to LABEL, which is the operand number of the label. OP is the conditional expression, or NULL for branch-always. REVERSED is nonzero if we should reverse the sense of the comparison. INSN is the insn. */char *xstormy16_output_cbranch_hi (rtx op, const char *label, int reversed, rtx insn){ static char string[64]; int need_longbranch = (op != NULL_RTX ? get_attr_length (insn) == 8 : get_attr_length (insn) == 4); int really_reversed = reversed ^ need_longbranch; const char *ccode; const char *template; const char *operands; enum rtx_code code; if (! op) { if (need_longbranch) ccode = "jmpf"; else ccode = "br"; sprintf (string, "%s %s", ccode, label); return string; } code = GET_CODE (op); if (GET_CODE (XEXP (op, 0)) != REG) { code = swap_condition (code); operands = "%3,%2"; } else operands = "%2,%3"; /* Work out which way this really branches. */ if (really_reversed) code = reverse_condition (code); switch (code) { case EQ: ccode = "z"; break; case NE: ccode = "nz"; break; case GE: ccode = "ge"; break; case LT: ccode = "lt"; break; case GT: ccode = "gt"; break; case LE: ccode = "le"; break; case GEU: ccode = "nc"; break; case LTU: ccode = "c"; break; case GTU: ccode = "hi"; break; case LEU: ccode = "ls"; break; default: abort (); } if (need_longbranch) template = "b%s %s,.+8 | jmpf %s"; else template = "b%s %s,%s"; sprintf (string, template, ccode, operands, label); return string;}/* Return the string to output a conditional branch to LABEL, which is the operand number of the label, but suitable for the tail of a SImode branch. OP is the conditional expression (OP is never NULL_RTX). REVERSED is nonzero if we should reverse the sense of the comparison. INSN is the insn. */char *xstormy16_output_cbranch_si (rtx op, const char *label, int reversed, rtx insn){ static char string[64]; int need_longbranch = get_attr_length (insn) >= 8; int really_reversed = reversed ^ need_longbranch; const char *ccode; const char *template; char prevop[16]; enum rtx_code code; code = GET_CODE (op); /* Work out which way this really branches. */ if (really_reversed) code = reverse_condition (code); switch (code) { case EQ: ccode = "z"; break; case NE: ccode = "nz"; break; case GE: ccode = "ge"; break; case LT: ccode = "lt"; break; case GEU: ccode = "nc"; break; case LTU: ccode = "c"; break; /* The missing codes above should never be generated. */ default: abort (); } switch (code) { case EQ: case NE: { int regnum; if (GET_CODE (XEXP (op, 0)) != REG) abort (); regnum = REGNO (XEXP (op, 0)); sprintf (prevop, "or %s,%s", reg_names[regnum], reg_names[regnum+1]); } break; case GE: case LT: case GEU: case LTU: strcpy (prevop, "sbc %2,%3"); break; default: abort (); } if (need_longbranch) template = "%s | b%s .+6 | jmpf %s"; else template = "%s | b%s %s"; sprintf (string, template, prevop, ccode, label); return string;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -