diff options
| author | Andrew Lee <alee14498@protonmail.com> | 2021-08-15 00:34:05 -0400 |
|---|---|---|
| committer | Andrew Lee <alee14498@protonmail.com> | 2021-08-15 00:34:05 -0400 |
| commit | 60cc83bf91bfc9bb02f6304b5d6c8234ba6d210f (patch) | |
| tree | fdc0be85a1ca35e34c3ae2c805fe9b718e3c1091 /gcc-1.40/config/out-ns32k.c | |
| parent | dd8dfab51b832a654365ed00c06bf802ff628bfa (diff) | |
| download | linux-0.01-distro-60cc83bf91bfc9bb02f6304b5d6c8234ba6d210f.tar.gz linux-0.01-distro-60cc83bf91bfc9bb02f6304b5d6c8234ba6d210f.tar.bz2 linux-0.01-distro-60cc83bf91bfc9bb02f6304b5d6c8234ba6d210f.zip | |
Diffstat (limited to 'gcc-1.40/config/out-ns32k.c')
| -rw-r--r-- | gcc-1.40/config/out-ns32k.c | 575 |
1 files changed, 575 insertions, 0 deletions
diff --git a/gcc-1.40/config/out-ns32k.c b/gcc-1.40/config/out-ns32k.c new file mode 100644 index 0000000..e3df4fe --- /dev/null +++ b/gcc-1.40/config/out-ns32k.c @@ -0,0 +1,575 @@ +/* Subroutines for assembler code output on the NS32000. + Copyright (C) 1988 Free Software Foundation, Inc. + +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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Some output-actions in ns32k.md need these. */ +#include <stdio.h> +extern FILE *asm_out_file; + +#define FP_REG_P(X) (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16) + +/* Generate the rtx that comes from an address expression in the md file */ +/* The expression to be build is BASE[INDEX:SCALE]. To recognize this, + scale must be converted from an exponent (from ASHIFT) to a + muliplier (for MULT). */ +rtx +gen_indexed_expr (base, index, scale) + rtx base, index, scale; +{ + rtx addr; + + /* This generates an illegal addressing mode, if BASE is + fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */ + if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT) + base = gen_rtx (MEM, SImode, base); + addr = gen_rtx (MULT, SImode, index, + gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale))); + addr = gen_rtx (PLUS, SImode, base, addr); + return addr; +} + +/* Return 1 if OP is a valid constant int. These can be modeless + (void mode), so we do not mess with their modes. + + The main use of this function is as a predicate in match_operand + expressions in the machine description. */ + +int +const_int (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT); +} + +/* Return 1 if OP is a valid operand of mode MODE. This + predicate rejects operands which do not have a mode + (such as CONST_INT which are VOIDmode). */ +int +reg_or_mem_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_MODE (op) == mode + && (GET_CODE (op) == REG + || GET_CODE (op) == SUBREG + || GET_CODE (op) == MEM)); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) <= 7 + && INTVAL (operands[1]) >= -8) + return "movqd %1,%0"; + return "movd %1,%0"; +} + +char * +output_move_double (operands) + rtx *operands; +{ + enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = POPOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_ADDRESS_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = POPOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_ADDRESS_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + + if (optype0 == POPOP || optype1 == POPOP) + { + output_asm_insn (singlemove_string (latehalf), latehalf); + return singlemove_string (operands); + } + + /* Not autodecrementing. Do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + operands[0] = latehalf[0]; + operands[1] = latehalf[1]; + return singlemove_string (operands); +} + +int +check_reg (oper, reg) + rtx oper; + int reg; +{ + register int i; + + if (oper == 0) + return 0; + switch (GET_CODE(oper)) + { + case REG: + return (REGNO(oper) == reg) ? 1 : 0; + case MEM: + return check_reg(XEXP(oper, 0), reg); + case PLUS: + case MULT: + return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg); + } + return 0; +} + +/* PRINT_OPERAND_ADDRESS is defined to call this function, + which is easier to debug than putting all the code in + a macro definition in tm-ns32k.h . */ + +/* Nonzero if we have printed a base register. + If zero, on some systems, it means `(sb)' must be printed. */ +int paren_base_reg_printed = 0; + +print_operand_address (file, addr) + register FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + static char scales[] = { 'b', 'w', 'd', 0, 'q', }; + + retry: + switch (GET_CODE (addr)) + { + case MEM: + addr = XEXP (addr, 0); + if (GET_CODE (addr) == REG) + if (REGNO (addr) == STACK_POINTER_REGNUM) + { fprintf (file, "tos"); break; } + else + { fprintf (file, "%s", reg_names[REGNO (addr)]); break; } + else if (CONSTANT_P (addr)) + { output_addr_const (file, addr); break; } + else if (GET_CODE (addr) == MULT) + { fprintf (file, "@0"); ireg = addr; goto print_index; } + else if (GET_CODE (addr) == MEM) + { + addr = XEXP (addr, 0); + if (GET_CODE (addr) == PLUS) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else + { + offset = const0_rtx; + } + output_addr_const (file, offset); + fprintf (file, "(%s)", reg_names[REGNO (addr)]); + break; + } + + if (GET_CODE (addr) != PLUS) + abort (); + + goto retry; + + case REG: + if (REGNO (addr) == STACK_POINTER_REGNUM) + fprintf (file, "tos"); + else + fprintf (file, "0(%s)", reg_names[REGNO (addr)]); + break; + + case PRE_DEC: + case POST_INC: + fprintf (file, "tos"); + break; + + case MULT: + fprintf (file, "@0"); + ireg = addr; /* [rX:Y] */ + goto print_index; + break; + + case PLUS: + reg1 = 0; reg2 = 0; + ireg = 0; breg = 0; + offset = const0_rtx; + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) != PLUS) ; + else if (GET_CODE (XEXP (addr, 0)) == MULT) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == MULT) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + /* The case for memory is somewhat tricky: to get + a MEM here, the only RTX formats that could + get here are either (modulo commutativity) + (PLUS (PLUS (REG *MEM)) CONST) -or- + (PLUS (PLUS (CONST REG/MULT)) *MEM) + We take advantage of that knowledge here. */ + else if (GET_CODE (XEXP (addr, 0)) == MEM + || GET_CODE (XEXP (addr, 1)) == MEM) + { + rtx temp; + + if (GET_CODE (XEXP (addr, 0)) == MEM) + { + temp = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else + { + temp = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + + if (GET_CODE (temp) == REG) + { + reg1 = temp; + } + else + { + if (GET_CODE (temp) != PLUS) + abort (); + + if (GET_CODE (XEXP (temp, 0)) == MULT) + { + reg1 = XEXP (temp, 0); + offset = XEXP (temp, 1); + } + if (GET_CODE (XEXP (temp, 1)) == MULT) + { + reg1 = XEXP (temp, 1); + offset = XEXP (temp, 0); + } + else + abort (); + } + } + else if (GET_CODE (XEXP (addr, 0)) == REG + || GET_CODE (XEXP (addr, 1)) == REG) + { + rtx temp; + + if (GET_CODE (XEXP (addr, 0)) == REG) + { + temp = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else + { + temp = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + + if (GET_CODE (addr) == REG) + { + if (REGNO (temp) >= FRAME_POINTER_REGNUM) + { reg1 = addr; addr = temp; } + else + { reg1 = temp; } + } + else if (CONSTANT_P (addr)) + { + if (GET_CODE (offset) == CONST_INT + && INTVAL (offset)) + offset = plus_constant (addr, INTVAL (offset)); + addr = temp; + } + else if (GET_CODE (addr) != PLUS) + abort (); + else + { + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else abort (); + + if (GET_CODE (addr) == REG) + { + if (REGNO (temp) >= FRAME_POINTER_REGNUM) + { reg1 = addr; addr = temp; } + else + { reg1 = temp; } + } + else + reg1 = temp; + } + } + + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } + if (addr != 0) + { + if (CONSTANT_P (addr) && reg1) + { + /* OFFSET comes second, to prevent outputting + operands of the form INT+SYMBOL+INT. + The Genix assembler dies on them. */ + output_addr_const (file, addr); + if (offset != const0_rtx) + { + putc ('+', file); + output_addr_const (file, offset); + } + ireg = reg1; + goto print_index; + } + else if (GET_CODE (addr) != MEM) + abort (); + + output_addr_const (file, offset); +#ifndef SEQUENT_ADDRESS_BUG + putc ('(', file); + paren_base_reg_printed = 0; + output_address (addr); +#ifdef SEQUENT_BASE_REGS + if (!paren_base_reg_printed) + fprintf (file, "(sb)"); +#endif + putc (')', file); +#else /* SEQUENT_ADDRESS_BUG */ + if ((GET_CODE (offset) == SYMBOL_REF + || GET_CODE (offset) == CONST) + && GET_CODE (addr) == REG) + { + if (reg1) abort (); + fprintf (file, "[%s:b]", reg_names[REGNO (addr)]); + } + else + { + putc ('(', file); + paren_base_reg_printed = 0; + output_address (addr); +#ifdef SEQUENT_BASE_REGS + if (!paren_base_reg_printed) + fprintf (file, "(sb)"); +#endif + putc (')', file); + } +#endif /* SEQUENT_ADDRESS_BUG */ + ireg = reg1; + goto print_index; + } + else addr = offset; + if (reg1 && GET_CODE (reg1) == MULT) + { breg = reg2; ireg = reg1; } + else if (reg2 && GET_CODE (reg2) == MULT) + { breg = reg1; ireg = reg2; } + else if (reg2 || GET_CODE (addr) == MEM) + { breg = reg2; ireg = reg1; } + else + { breg = reg1; ireg = reg2; } + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) + { + int scale; + if (GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)) >> 1; + ireg = XEXP (ireg, 0); + } + else scale = 0; + output_asm_label (addr); + fprintf (file, "[%s:%c]", + reg_names[REGNO (ireg)], scales[scale]); + break; + } + if (ireg && breg && offset == const0_rtx) + fprintf (file, "0(%s)", reg_names[REGNO (breg)]); + else + { + if (addr != 0) + { + if (ireg != 0 && breg == 0 + && GET_CODE (offset) == CONST_INT) putc('@', file); + output_addr_const (file, offset); + } + if (breg != 0) + { + if (GET_CODE (breg) != REG) abort (); +#ifndef SEQUENT_ADDRESS_BUG + fprintf (file, "(%s)", reg_names[REGNO (breg)]); + paren_base_reg_printed = -1; +#else + if (GET_CODE (offset) == SYMBOL_REF || GET_CODE (offset) == CONST) + { + if (ireg) abort (); + fprintf (file, "[%s:b]", reg_names[REGNO (breg)]); + } + else + { + fprintf (file, "(%s)", reg_names[REGNO (breg)]); + paren_base_reg_printed = -1; + } +#endif + } + } + print_index: + if (ireg != 0) + { + int scale; + if (GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)) >> 1; + ireg = XEXP (ireg, 0); + } + else scale = 0; + if (GET_CODE (ireg) != REG) abort (); + fprintf (file, "[%s:%c]", + reg_names[REGNO (ireg)], + scales[scale]); + } + break; + default: + output_addr_const (file, addr); + } +} + +/* National 32032 shifting is so bad that we can get + better performance in many common cases by using other + techniques. */ +char * +output_shift_insn (operands) + rtx *operands; +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 3) + if (GET_CODE (operands[0]) == REG) + { + if (GET_CODE (operands[1]) == REG) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + { + if (operands[2] == const1_rtx) + return "addd %0,%0"; + else if (INTVAL (operands[2]) == 2) + return "addd %0,%0\n\taddd %0,%0"; + } + if (operands[2] == const1_rtx) + return "movd %1,%0\n\taddd %0,%0"; + + operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); + return "addr %a1,%0"; + } + if (operands[2] == const1_rtx) + return "movd %1,%0\n\taddd %0,%0"; + } + else if (GET_CODE (operands[1]) == REG) + { + operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); + return "addr %a1,%0"; + } + else if (INTVAL (operands[2]) == 1 + && GET_CODE (operands[1]) == MEM + && rtx_equal_p (operands [0], operands[1])) + { + rtx temp = XEXP (operands[1], 0); + + if (GET_CODE (temp) == REG + || (GET_CODE (temp) == PLUS + && GET_CODE (XEXP (temp, 0)) == REG + && GET_CODE (XEXP (temp, 1)) == CONST_INT)) + return "addd %0,%0"; + } + else return "ashd %2,%0"; + return "ashd %2,%0"; +} |
