h8300.c
来自「gcc3.2.1源代码」· C语言 代码 · 共 2,420 行 · 第 1/5 页
C
2,420 行
/* Subroutines for insn-output.c for Hitachi H8/300. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Steve Chamberlain (sac@cygnus.com), Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).This file is part of GNU CC.GNU CC 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.GNU CC 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 GNU CC; 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 "rtl.h"#include "tree.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "recog.h"#include "expr.h"#include "function.h"#include "toplev.h"#include "c-pragma.h"#include "tm_p.h"#include "ggc.h"#include "target.h"#include "target-def.h"/* Forward declarations. */static const char *byte_reg PARAMS ((rtx, int));static int h8300_interrupt_function_p PARAMS ((tree));static int h8300_monitor_function_p PARAMS ((tree));static int h8300_os_task_function_p PARAMS ((tree));static void dosize PARAMS ((FILE *, const char *, unsigned int));static int round_frame_size PARAMS ((int));static unsigned int compute_saved_regs PARAMS ((void));static void push PARAMS ((FILE *, int));static void pop PARAMS ((FILE *, int));static const char *cond_string PARAMS ((enum rtx_code));const struct attribute_spec h8300_attribute_table[];static tree h8300_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));static tree h8300_handle_eightbit_data_attribute PARAMS ((tree *, tree, tree, int, bool *));static tree h8300_handle_tiny_data_attribute PARAMS ((tree *, tree, tree, int, bool *));static void h8300_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void h8300_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));#ifndef OBJECT_FORMAT_ELFstatic void h8300_asm_named_section PARAMS ((const char *, unsigned int));#endif/* CPU_TYPE, says what cpu we're compiling for. */int cpu_type;/* True if the current function is an interrupt handler (either via #pragma or an attribute specification). */static int interrupt_handler;/* True if the current function is an OS Task (via an attribute specification). */static int os_task;/* True if the current function is a monitor (via an attribute specification). */static int monitor;/* True if a #pragma saveall has been seen for the current function. */static int pragma_saveall;static const char *const names_big[] ={ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" };static const char *const names_extended[] ={ "er0", "er1", "er2", "er3", "er4", "er5", "er6", "er7" };static const char *const names_upper_extended[] ={ "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7" };/* Points to one of the above. *//* ??? The above could be put in an array indexed by CPU_TYPE. */const char * const *h8_reg_names;/* Various operations needed by the following, indexed by CPU_TYPE. */const char *h8_push_op, *h8_pop_op, *h8_mov_op;/* Initialize the GCC target structure. */#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE h8300_attribute_table#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE h8300_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE h8300_output_function_epiloguestruct gcc_target targetm = TARGET_INITIALIZER;/* Initialize various cpu specific globals at start up. */voidh8300_init_once (){ static const char *const h8_push_ops[2] = { "push" , "push.l" }; static const char *const h8_pop_ops[2] = { "pop" , "pop.l" }; static const char *const h8_mov_ops[2] = { "mov.w", "mov.l" }; if (TARGET_H8300) { cpu_type = (int) CPU_H8300; h8_reg_names = names_big; } else { /* For this we treat the H8/300H and H8/S the same. */ cpu_type = (int) CPU_H8300H; h8_reg_names = names_extended; } h8_push_op = h8_push_ops[cpu_type]; h8_pop_op = h8_pop_ops[cpu_type]; h8_mov_op = h8_mov_ops[cpu_type]; if (!TARGET_H8300S && TARGET_MAC) { error ("-ms2600 is used without -ms"); target_flags |= 1; }}static const char *byte_reg (x, b) rtx x; int b;{ static const char *const names_small[] = { "r0l", "r0h", "r1l", "r1h", "r2l", "r2h", "r3l", "r3h", "r4l", "r4h", "r5l", "r5h", "r6l", "r6h", "r7l", "r7h" }; return names_small[REGNO (x) * 2 + b];}/* REGNO must be saved/restored across calls if this macro is true. */#define WORD_REG_USED(regno) \ (regno < 7 \ /* No need to save registers if this function will not return. */ \ && ! TREE_THIS_VOLATILE (current_function_decl) \ && (pragma_saveall \ /* Save any call saved register that was used. */ \ || (regs_ever_live[regno] && !call_used_regs[regno]) \ /* Save the frame pointer if it was used. */ \ || (regno == FRAME_POINTER_REGNUM && regs_ever_live[regno]) \ /* Save any register used in an interrupt handler. */ \ || (interrupt_handler && regs_ever_live[regno]) \ /* Save call clobbered registers in non-leaf interrupt \ handlers. */ \ || (interrupt_handler \ && call_used_regs[regno] \ && !current_function_is_leaf)))/* Output assembly language to FILE for the operation OP with operand size SIZE to adjust the stack pointer. */static voiddosize (file, op, size) FILE *file; const char *op; unsigned int size;{ /* On the H8/300H and H8/S, for sizes <= 8 bytes, it is as good or better to use adds/subs insns rather than add.l/sub.l with an immediate value. Also, on the H8/300, if we don't have a temporary to hold the size of the frame in the prologue, we simply emit a sequence of subs since this shouldn't happen often. */ if ((TARGET_H8300 && size <= 4) || ((TARGET_H8300H || TARGET_H8300S) && size <= 8) || (TARGET_H8300 && interrupt_handler) || (TARGET_H8300 && current_function_needs_context && ! strcmp (op, "sub"))) { unsigned HOST_WIDE_INT amount; /* Try different amounts in descending order. */ for (amount = (TARGET_H8300H || TARGET_H8300S) ? 4 : 2; amount > 0; amount /= 2) { for (; size >= amount; size -= amount) fprintf (file, "\t%ss\t#%d,sp\n", op, amount); } } else { if (TARGET_H8300) fprintf (file, "\tmov.w\t#%d,r3\n\t%s.w\tr3,sp\n", size, op); else fprintf (file, "\t%s.l\t#%d,sp\n", op, size); }}/* Round up frame size SIZE. */static intround_frame_size (size) int size;{ return (size + STACK_BOUNDARY / 8 - 1) & -STACK_BOUNDARY / 8;}/* Compute which registers to push/pop. Return a bit vector of registers. */static unsigned intcompute_saved_regs (){ unsigned int saved_regs = 0; int regno; /* Construct a bit vector of registers to be pushed/popped. */ for (regno = 0; regno <= 6; regno++) { if (WORD_REG_USED (regno)) saved_regs |= 1 << regno; } /* Don't push/pop the frame pointer as it is treated separately. */ if (frame_pointer_needed) saved_regs &= ~(1 << FRAME_POINTER_REGNUM); return saved_regs;}/* Output assembly language code to push register RN. */static voidpush (file, rn) FILE *file; int rn;{ fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[rn]);}/* Output assembly language code to pop register RN. */static voidpop (file, rn) FILE *file; int rn;{ fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[rn]);}/* This is what the stack looks like after the prolog of a function with a frame has been set up: <args> PC FP <- fp <locals> <saved registers> <- sp This is what the stack looks like after the prolog of a function which doesn't have a frame: <args> PC <locals> <saved registers> <- sp*//* Output assembly language code for the function prologue. */static voidh8300_output_function_prologue (file, size) FILE *file; HOST_WIDE_INT size;{ int fsize = round_frame_size (size); int idx; int saved_regs; int n_regs; /* Note a function with the interrupt attribute and set interrupt_handler accordingly. */ if (h8300_interrupt_function_p (current_function_decl)) interrupt_handler = 1; /* If the current function has the OS_Task attribute set, then we have a naked prologue. */ if (h8300_os_task_function_p (current_function_decl)) { fprintf (file, ";OS_Task prologue\n"); os_task = 1; return; } if (h8300_monitor_function_p (current_function_decl)) { /* My understanding of monitor functions is they act just like interrupt functions, except the prologue must mask interrupts. */ fprintf (file, ";monitor prologue\n"); interrupt_handler = 1; monitor = 1; if (TARGET_H8300) { fprintf (file, "\tsubs\t#2,sp\n"); push (file, 0); fprintf (file, "\tstc\tccr,r0l\n"); fprintf (file, "\tmov.b\tr0l,@(2,sp)\n"); pop (file, 0); fprintf (file, "\torc\t#128,ccr\n"); } else if (TARGET_H8300H) { push (file, 0); fprintf (file, "\tstc\tccr,r0l\n"); fprintf (file, "\tmov.b\tr0l,@(4,sp)\n"); pop (file, 0); fprintf (file, "\torc\t#128,ccr\n"); } else if (TARGET_H8300S) { fprintf (file, "\tstc\texr,@-sp\n"); push (file, 0); fprintf (file, "\tstc\tccr,r0l\n"); fprintf (file, "\tmov.b\tr0l,@(6,sp)\n"); pop (file, 0); fprintf (file, "\torc\t#128,ccr\n"); } else abort (); } if (frame_pointer_needed) { /* Push fp. */ push (file, FRAME_POINTER_REGNUM); fprintf (file, "\t%s\t%s,%s\n", h8_mov_op, h8_reg_names[STACK_POINTER_REGNUM], h8_reg_names[FRAME_POINTER_REGNUM]); } /* Leave room for locals. */ dosize (file, "sub", fsize); /* Push the rest of the registers in ascending order. */ saved_regs = compute_saved_regs (); for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx += n_regs) { int regno = idx; n_regs = 1; if (saved_regs & (1 << regno)) { if (TARGET_H8300S) { /* See how many registers we can push at the same time. */ if ((regno == 0 || regno == 4) && ((saved_regs >> regno) & 0x0f) == 0x0f) n_regs = 4; else if ((regno == 0 || regno == 4) && ((saved_regs >> regno) & 0x07) == 0x07) n_regs = 3; else if ((regno == 0 || regno == 2 || regno == 4 || regno == 6) && ((saved_regs >> regno) & 0x03) == 0x03) n_regs = 2; } if (n_regs == 1) push (file, regno); else fprintf (file, "\tstm.l\t%s-%s,@-sp\n", h8_reg_names[regno], h8_reg_names[regno + (n_regs - 1)]); } }}/* Output assembly language code for the function epilogue. */static voidh8300_output_function_epilogue (file, size) FILE *file; HOST_WIDE_INT size;{ int fsize = round_frame_size (size); int idx; rtx insn = get_last_insn (); int saved_regs; int n_regs; if (os_task) { /* OS_Task epilogues are nearly naked -- they just have an rts instruction. */ fprintf (file, ";OS_task epilogue\n"); fprintf (file, "\trts\n"); goto out; } /* Monitor epilogues are the same as interrupt function epilogues. Just make a note that we're in an monitor epilogue. */ if (monitor) fprintf (file, ";monitor epilogue\n"); /* If the last insn was a BARRIER, we don't have to write any code. */ if (GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn && GET_CODE (insn) == BARRIER) goto out; /* Pop the saved registers in descending order. */ saved_regs = compute_saved_regs (); for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx += n_regs) { int regno = (FIRST_PSEUDO_REGISTER - 1) - idx; n_regs = 1; if (saved_regs & (1 << regno)) { if (TARGET_H8300S) { /* See how many registers we can pop at the same time. */ if ((regno == 7 || regno == 3) && ((saved_regs >> (regno - 3)) & 0x0f) == 0x0f) n_regs = 4; else if ((regno == 6 || regno == 2) && ((saved_regs >> (regno - 2)) & 0x07) == 0x07) n_regs = 3; else if ((regno == 7 || regno == 5 || regno == 3 || regno == 1) && ((saved_regs >> (regno - 1)) & 0x03) == 0x03) n_regs = 2; } if (n_regs == 1) pop (file, regno); else fprintf (file, "\tldm.l\t@sp+,%s-%s\n", h8_reg_names[regno - (n_regs - 1)], h8_reg_names[regno]); } } /* Deallocate locals. */ dosize (file, "add", fsize); /* Pop frame pointer if we had one. */ if (frame_pointer_needed) pop (file, FRAME_POINTER_REGNUM); if (interrupt_handler) fprintf (file, "\trte\n"); else fprintf (file, "\trts\n"); out: interrupt_handler = 0; os_task = 0; monitor = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?