/* Subroutines for insn-output.c for GNU compiler. Elxsi version. Copyright (C) 1987, 1992, 1998, 1999, 2000 Free Software Foundation, Inc Contributrd by Mike Stump in 1988 and is the first 64 bit port of GNU CC. Based upon the VAX port. This file is part of GNU CC. GNU CC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the 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 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" #include "rtl.h" #include "function.h" #include "output.h" #include "tm_p.h" #include "target.h" #include "target-def.h" extern const char *reg_names[]; rtx cmp_op0=0, cmp_op1=0; /* table of relations for compares and branches */ static const char *const cmp_tab[] = { "gt", "gt", "eq", "eq", "ge", "ge", "lt", "lt", "ne", "ne", "le", "le" }; static void elxsi_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); static void elxsi_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); /* Initialize the GCC target structure. */ #undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE elxsi_output_function_prologue #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE elxsi_output_function_epilogue struct gcc_target targetm = TARGET_INITIALIZER; /* Generate the assembly code for function entry. FILE is a stdio stream to output the code to. SIZE is an int: how many units of temporary storage to allocate. Refer to the array `regs_ever_live' to determine which registers to save; `regs_ever_live[I]' is nonzero if register number I is ever used in the function. This function is responsible for knowing which registers should not be saved even if used. */ static void elxsi_output_function_prologue (file, size) FILE *file; HOST_WIDE_INT size; { register int regno; register int cnt = 0; extern char call_used_regs[]; /* the below two lines are a HACK, and should be deleted, but for now are very much needed (1.35) */ if (frame_pointer_needed) regs_ever_live[14] = 1, call_used_regs[14] = 0; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (regs_ever_live[regno] && !call_used_regs[regno]) cnt += 8; if (size + cnt) fprintf (file, "\tadd.64\t.sp,=%d\n", -size - cnt); cnt = 0; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (regs_ever_live[regno] && !call_used_regs[regno]) fprintf (file, "\tst.64\t.r%d,[.sp]%d\n", regno, (cnt += 8) - 12); if (frame_pointer_needed) fprintf (file, "\tadd.64\t.r14,.sp,=%d\n", size + cnt); } /* This function generates the assembly code for function exit. Args are as for output_function_prologue (). The function epilogue should not depend on the current stack pointer! It should use the frame pointer only. This is mandatory because of alloca; we also take advantage of it to omit stack adjustments before returning. */ static void elxsi_output_function_epilogue (file, size) FILE *file; HOST_WIDE_INT size; { register int regno; register int cnt = 0; extern char call_used_regs[]; /* this conditional is ONLY here because there is a BUG; EXIT_IGNORE_STACK is ignored itself when the first part of the condition is true! (at least in version 1.35) */ /* the 8*10 is for 64 bits of .r5 - .r14 */ if (current_function_calls_alloca || size >= (256 - 8 * 10)) { /* use .r4 as a temporary! Ok for now.... */ fprintf (file, "\tld.64\t.r4,.r14\n"); for (regno = FIRST_PSEUDO_REGISTER-1; regno >= 0; --regno) if (regs_ever_live[regno] && !call_used_regs[regno]) cnt += 8; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) if (regs_ever_live[regno] && !call_used_regs[regno]) fprintf (file, "\tld.64\t.r%d,[.r14]%d\n", regno, -((cnt -= 8) + 8) - 4 - size); fprintf (file, "\tld.64\t.sp,.r4\n\texit\t0\n"); } else { for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) if (regs_ever_live[regno] && !call_used_regs[regno]) fprintf (file, "\tld.64\t.r%d,[.sp]%d\n", regno, (cnt + =8) - 12); fprintf (file, "\texit\t%d\n", size + cnt); } } /* type is the index into the above table */ /* s is "" for signed, or "u" for unsigned */ const char * cmp_jmp (s, type, where) const char *s; int type; rtx where; { rtx br_ops[3]; char template[50]; const char *f = ""; const char *bits = "64"; if (GET_MODE (cmp_op0) == SFmode) f = "f", bits = "32"; if (GET_MODE (cmp_op0) == DFmode) f = "f"; br_ops[0] = where; br_ops[1] = cmp_op0; br_ops[2] = cmp_op1; if (cmp_op1) sprintf(template, "%scmp%s.br.%s\t%%1,%%2:j%s\t%%l0", f, s, bits, cmp_tab[type]); else if (*f) sprintf(template, "fcmp.br.%s\t%%1,=0:j%s\t%%l0", bits, cmp_tab[type]); else if (*s) /* can turn the below in to a jmp ... */ sprintf(template, "cmpu.br.64\t%%1,=0:j%s\t%%l0", s); else sprintf(template, "jmp.%s\t%%1,%%l0", cmp_tab[type+1]); output_asm_insn(template, br_ops); return ""; } const char * cmp_set (s, type, reg) const char *s, *type; rtx reg; { rtx br_ops[3]; char template[50]; const char *f = ""; const char *bits = "64"; if (GET_MODE (cmp_op0) == SFmode) f = "f", bits = "32"; else if (GET_MODE (cmp_op0) == DFmode) f = "f"; else if (GET_MODE (cmp_op0) == SImode) bits = "32"; else if (GET_MODE (cmp_op0) == HImode) bits = "16"; else if (GET_MODE (cmp_op0) == QImode) bits = "8"; br_ops[0] = reg; br_ops[1] = cmp_op0; br_ops[2] = cmp_op1; if (cmp_op1) sprintf(template, "%scmp%s.%s\t%%0,%%1,%%2:%s", f, s, bits, type); else sprintf(template, "%scmp%s.%s\t%%0,%%1,=0:%s", f, s, bits, type); output_asm_insn(template, br_ops); return ""; } void print_operand_address (file, addr) FILE *file; register rtx addr; { register rtx reg1, reg2, breg, ireg; rtx offset; switch (GET_CODE (addr)) { case MEM: if (GET_CODE (XEXP (addr, 0)) == REG) fprintf (file, "%s", reg_names[REGNO (addr)]); else abort(); break; case REG: fprintf (file, "[%s]", reg_names[REGNO (addr)]); break; case PLUS: reg1 = 0; reg2 = 0; ireg = 0; breg = 0; offset = 0; if (GET_CODE (XEXP (addr, 0)) == REG) { offset = XEXP (addr, 1); addr = XEXP (addr, 0); } else if (GET_CODE (XEXP (addr, 1)) == REG) { offset = XEXP (addr, 0); addr = XEXP (addr, 1); } fprintf (file, "[%s]", reg_names[REGNO (addr)]); output_address (offset); break; default: output_addr_const (file, addr); } }