📄 h8300.c
字号:
/* Subroutines for insn-output.c for Hitachi H8/300. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 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 <stdio.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 "expr.h"#include "tree.h"#include "obstack.h"/* Forward declarations. */void print_operand_address ();char *index ();static int h8300_interrupt_function_p PROTO ((tree));static int h8300_monitor_function_p PROTO ((tree));static int h8300_os_task_function_p PROTO ((tree));/* 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). */int interrupt_handler;/* True if the current function is an OS Task (via an attribute specification). */int os_task;/* True if the current function is a monitor (via an attribute specification). */int monitor;/* True if a #pragma saveall has been seen for the current function. */int pragma_saveall;static char *names_big[] ={"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7"};static char *names_extended[] ={"er0", "er1", "er2", "er3", "er4", "er5", "er6", "er7"};static char *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. */char **h8_reg_names;/* Various operations needed by the following, indexed by CPU_TYPE. */static char *h8_push_ops[2] ={"push", "push.l"};static char *h8_pop_ops[2] ={"pop", "pop.l"};static char *h8_mov_ops[2] ={"mov.w", "mov.l"};char *h8_push_op, *h8_pop_op, *h8_mov_op;/* Initialize various cpu specific globals at start up. */voidh8300_init_once (){ if (TARGET_H8300) { cpu_type = (int) CPU_H8300; h8_reg_names = names_big; } else { /* For this we treat the H8/300 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];}char *byte_reg (x, b) rtx x; int b;{ static char *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 && \ (interrupt_handler \ || pragma_saveall \ || (regno == FRAME_POINTER_REGNUM && regs_ever_live[regno]) \ || (regs_ever_live[regno] && !call_used_regs[regno])))/* 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; char *op; unsigned int size;{ /* On the h8300h and h8300s, 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. */ if (size > 4 && size <= 8 && (TARGET_H8300H || TARGET_H8300S)) { /* Crank the size down to <= 4 */ fprintf (file, "\t%ss\t#%d,sp\n", op, 4); size -= 4; } switch (size) { case 4: if (TARGET_H8300H || TARGET_H8300S) { fprintf (file, "\t%ss\t#%d,sp\n", op, 4); size = 0; break; } case 3: fprintf (file, "\t%ss\t#%d,sp\n", op, 2); size -= 2; /* Fall through... */ case 2: case 1: fprintf (file, "\t%ss\t#%d,sp\n", op, size); size = 0; break; case 0: break; default: if (TARGET_H8300) { if (current_function_needs_context && strcmp (op, "sub") == 0) { /* Egad. We don't have a temporary to hold the size of the frame in the prologue! Just inline the bastard since this shouldn't happen often. */ while (size >= 2) { fprintf (file, "\tsubs\t#2,sp\n"); size -= 2; } if (size) fprintf (file, "\tsubs\t#1,sp\n"); size = 0; } else fprintf (file, "\tmov.w\t#%d,r3\n\t%s.w\tr3,sp\n", size, op); } else fprintf (file, "\t%s\t#%d,sp\n", op, size); size = 0; break; }}/* Output assembly language code for the function prologue. */static int push_order[FIRST_PSEUDO_REGISTER] ={0, 1, 2, 3, 4, 5, 6, -1, -1, -1};static int pop_order[FIRST_PSEUDO_REGISTER] ={6, 5, 4, 3, 2, 1, 0, -1, -1, -1};/* 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*/voidfunction_prologue (file, size) FILE *file; int size;{ register int mask = 0; int fsize = (size + STACK_BOUNDARY / 8 - 1) & -STACK_BOUNDARY / 8; int idx; /* 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"); fprintf (file, "\tpush\tr0\n"); fprintf (file, "\tstc\tccr,r0l\n"); fprintf (file, "\torc\t#128,ccr\n"); fprintf (file, "\tmov.b\tr0l,@(4,sp)\n"); } else { fprintf (file, "\tpush\ter0\n"); fprintf (file, "\tstc\tccr,r0l\n"); fprintf (file, "\torc\t#128,ccr\n"); fprintf (file, "\tmov.b\tr0l,@(4,sp)\n"); } } if (frame_pointer_needed) { /* Push fp */ fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[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 */ for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) { int regno = push_order[idx]; if (regno >= 0 && WORD_REG_USED (regno) && (!frame_pointer_needed || regno != FRAME_POINTER_REGNUM)) { if (TARGET_H8300S) { /* Try to push multiple registers. */ if (regno == 0 || regno == 4) { int second_regno = push_order[idx + 1]; int third_regno = push_order[idx + 2]; int fourth_regno = push_order[idx + 3]; if (fourth_regno >= 0 && WORD_REG_USED (fourth_regno) && (!frame_pointer_needed || fourth_regno != FRAME_POINTER_REGNUM) && third_regno >= 0 && WORD_REG_USED (third_regno) && (!frame_pointer_needed || third_regno != FRAME_POINTER_REGNUM) && second_regno >= 0 && WORD_REG_USED (second_regno) && (!frame_pointer_needed || second_regno != FRAME_POINTER_REGNUM)) { fprintf (file, "\tstm.l %s-%s,@-sp\n", h8_reg_names[regno], h8_reg_names[fourth_regno]); idx += 3; continue; } } if (regno == 0 || regno == 4) { int second_regno = push_order[idx + 1]; int third_regno = push_order[idx + 2]; if (third_regno >= 0 && WORD_REG_USED (third_regno) && (!frame_pointer_needed || third_regno != FRAME_POINTER_REGNUM) && second_regno >= 0 && WORD_REG_USED (second_regno) && (!frame_pointer_needed || second_regno != FRAME_POINTER_REGNUM)) { fprintf (file, "\tstm.l %s-%s,@-sp\n", h8_reg_names[regno], h8_reg_names[third_regno]); idx += 2; continue; } } if (regno == 0 || regno == 2 || regno == 4 || regno == 6) { int second_regno = push_order[idx + 1]; if (second_regno >= 0 && WORD_REG_USED (second_regno) && (!frame_pointer_needed || second_regno != FRAME_POINTER_REGNUM)) { fprintf (file, "\tstm.l %s-%s,@-sp\n", h8_reg_names[regno], h8_reg_names[second_regno]); idx += 1; continue; } } } fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[regno]); } }}/* Output assembly language code for the function epilogue. */voidfunction_epilogue (file, size) FILE *file; int size;{ register int regno; register int mask = 0; int fsize = (size + STACK_BOUNDARY / 8 - 1) & -STACK_BOUNDARY / 8; int idx; rtx insn = get_last_insn (); 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. */ for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) { int regno = pop_order[idx]; if (regno >= 0 && WORD_REG_USED (regno) && (!frame_pointer_needed || regno != FRAME_POINTER_REGNUM)) { if (TARGET_H8300S) { /* Try to pop multiple registers. */ if (regno == 7 || regno == 3) { int second_regno = pop_order[idx + 1]; int third_regno = pop_order[idx + 2]; int fourth_regno = pop_order[idx + 3]; if (fourth_regno >= 0 && WORD_REG_USED (fourth_regno) && (!frame_pointer_needed || fourth_regno != FRAME_POINTER_REGNUM) && third_regno >= 0 && WORD_REG_USED (third_regno) && (!frame_pointer_needed || third_regno != FRAME_POINTER_REGNUM) && second_regno >= 0 && WORD_REG_USED (second_regno) && (!frame_pointer_needed || second_regno != FRAME_POINTER_REGNUM)) { fprintf (file, "\tldm.l @sp+,%s-%s\n", h8_reg_names[fourth_regno], h8_reg_names[regno]); idx += 3; continue; } } if (regno == 6 || regno == 2) { int second_regno = pop_order[idx + 1]; int third_regno = pop_order[idx + 2]; if (third_regno >= 0 && WORD_REG_USED (third_regno) && (!frame_pointer_needed || third_regno != FRAME_POINTER_REGNUM) && second_regno >= 0 && WORD_REG_USED (second_regno) && (!frame_pointer_needed || second_regno != FRAME_POINTER_REGNUM)) { fprintf (file, "\tldm.l @sp+,%s-%s\n", h8_reg_names[third_regno], h8_reg_names[regno]); idx += 2; continue; } } if (regno == 7 || regno == 5 || regno == 3 || regno == 1) { int second_regno = pop_order[idx + 1]; if (second_regno >= 0 && WORD_REG_USED (second_regno) && (!frame_pointer_needed || second_regno != FRAME_POINTER_REGNUM)) { fprintf (file, "\tldm.l @sp+,%s-%s\n", h8_reg_names[second_regno], h8_reg_names[regno]); idx += 1; continue; } } } fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[regno]); } } /* deallocate locals */ dosize (file, "add", fsize); /* pop frame pointer if we had one. */ if (frame_pointer_needed) fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[FRAME_POINTER_REGNUM]); /* If this is a monitor function, there is one register still left on the stack. */ if (monitor) fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[0]); 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -