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-m88k.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-m88k.c')
| -rw-r--r-- | gcc-1.40/config/out-m88k.c | 605 |
1 files changed, 605 insertions, 0 deletions
diff --git a/gcc-1.40/config/out-m88k.c b/gcc-1.40/config/out-m88k.c new file mode 100644 index 0000000..d02ac86 --- /dev/null +++ b/gcc-1.40/config/out-m88k.c @@ -0,0 +1,605 @@ +/* Subroutines for insn-output.c for Motorola 88000. + Copyright (C) 1987 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) + +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. */ + +#ifndef FILE +#include <stdio.h> +#endif + +/* This is where the condition code register lives. */ +rtx cc0_reg_rtx; + +static rtx find_addr_reg (); + +#if 0 +char * +output_compare (operands, opcode, exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; +{ + static char buf[40]; + rtx op1, op2; + + if (GET_CODE (cc_prev_status.value2) == COMPARE) + { + op1 = XEXP (cc_prev_status.value2, 0); + op2 = XEXP (cc_prev_status.value2, 1); + } + else + { + op1 = cc_prev_status.value2; + op2 = const0_rtx; + } + if (GET_CODE (op1) == CONST_INT) + { + operands[2] = op1; + operands[1] = op2; + opcode = exchange_opcode; + } + else + { + operands[1] = op1; + operands[2] = op2; + } + sprintf (buf, "cmp r25,%%1,%%2\n\tbcnd %s,r25,%%l0", opcode); + return buf; +} + +char * +output_fcompare (operands, opcode, exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; +{ + static char buf[40]; + + rtx op1, op2; + + if (GET_CODE (cc_prev_status.value2) == COMPARE) + { + op1 = XEXP (cc_prev_status.value2, 0); + op2 = XEXP (cc_prev_status.value2, 1); + } + else + { + op1 = cc_prev_status.value2; + op2 = const0_rtx; + } + if (GET_CODE (op1) == CONST_DOUBLE) + { + operands[2] = op1; + operands[1] = op2; + opcode = exchange_opcode; + } + else + { + operands[1] = op1; + operands[2] = op2; + } + sprintf (buf, "cmp r25,%%1,%%2\n\tbcnd %s,r25,%%l0", opcode); + return buf; +} + +char * +output_store (operands, opcode, exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; +{ + static char buf[40]; + rtx op1, op2; + + if (GET_CODE (cc_prev_status.value2) == COMPARE) + { + op1 = XEXP (cc_prev_status.value2, 0); + op2 = XEXP (cc_prev_status.value2, 1); + } + else + { + op1 = cc_prev_status.value2; + op2 = const0_rtx; + } + + if (GET_CODE (op1) == CONST_INT) + { + operands[2] = op1; + operands[1] = op2; + opcode = exchange_opcode; + } + else + { + operands[1] = op1; + operands[2] = op2; + } + + sprintf (buf, "cmp r25,%%1,%%2\n\textu %%0,r25,1<%s>", opcode); + return buf; +} +#endif + +/* Nonzero if OP is a valid second operand for an arithmetic insn. */ + +int +arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT + && (unsigned) INTVAL (op) < 0x10000)); +} + +int +arith32_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); +} + +int +int5_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x20); +} + +/* 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[0]) == MEM) + return "st %r1,%0"; + if (GET_CODE (operands[1]) == MEM) + return "ld %0,%1"; + return "or %0,r0,%1"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + 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 (); + + /* If an operand is an unoffsettable memory ref, find a register + we can increment temporarily to make it refer to the second word. */ + + if (optype0 == MEMOP) + addreg0 = find_addr_reg (operands[0]); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (operands[1]); + + /* 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_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 the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("addu %0,%0,4", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("subu %0,%0,4", &addreg0); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("addu %0,%0,4", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("subu %0,%0,4", &addreg1); + + return ""; +} + +/* Return a REG that occurs in ADDR with coefficient 1. + ADDR can be effectively incremented by incrementing REG. */ + +static rtx +find_addr_reg (addr) + rtx addr; +{ + while (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + if (GET_CODE (XEXP (addr, 1)) == REG) + addr = XEXP (addr, 1); + if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) == REG) + return addr; + return 0; +} + +/* Output an ascii string. */ +output_ascii (file, p, size) + FILE *file; + char *p; + int size; +{ + int i; + + fprintf (file, "\tstring \""); + + for (i = 0; i < size; i++) + { + register int c = p[i]; + if (c == '\"' || c == '\\') + putc ('\\', file); + if (c >= ' ' && c < 0177) + putc (c, file); + else + { + fprintf (file, "\\%03o", c); + /* After an octal-escape, if a digit follows, + terminate one string constant and start another. + The Vax assembler fails to stop reading the escape + after three digits, so this is the only way we + can get it to parse the data properly. */ + if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9') + fprintf (file, "\"\n\tstring \""); + } + } + fprintf (file, "\"\n"); +} + +void +output_load_address (operands) + rtx *operands; +{ + rtx base, offset; + + if (CONSTANT_P (operands[3])) + { + output_asm_insn ("lda %0,%3", operands); + return; + } + + if (REG_P (operands[3])) + { + if (REGNO (operands[0]) != REGNO (operands[3])) + output_asm_insn ("or %0,r0,%3", operands); + return; + } + + base = XEXP (operands[3], 0); + offset = XEXP (operands[3], 1); + + if (GET_CODE (base) == CONST_INT) + { + rtx tmp = base; + base = offset; + offset = tmp; + } + + if (GET_CODE (offset) != CONST_INT) + abort (); + + operands[6] = base; + operands[7] = offset; + + if (REG_P (base)) + if (FITS_16_BITS (offset)) + output_asm_insn ("addu %0,%6,%7", operands); + else if (INT_FITS_16_BITS (- INTVAL (offset))) + output_asm_insn ("subu %0,%6,%7", operands); + else + output_asm_insn ("or.h %0,r0,hi16(%7)\n\tor %0,%0,lo16(%7)\n\tadd %0,%6,%0", operands); + else + { + if (GET_CODE (base) == MULT) + if (GET_MODE (base) == QImode) + output_asm_insn ("lda.b %0,%6"); + else if (GET_MODE (base) == HImode) + output_asm_insn ("lda.h %0,%6"); + else if (GET_MODE (base) == SImode) + output_asm_insn ("lda %0,%6"); + else + output_asm_insn ("lda.d %0,%6"); + else + output_asm_insn ("lda %0,%6"); + + if (FITS_16_BITS (offset)) + output_asm_insn ("addu %0,%7,%0", operands); + else if (INT_FITS_16_BITS (- INTVAL (offset))) + output_asm_insn ("subu %0,%7,%0", operands); + else + output_asm_insn ("or.h r25,r0,hi16(%7)\n\tor r25,r0,lo16(%7)\n\taddu %0,%0r25", operands); + } +} + +char * +output_block_move (operands) + rtx *operands; +{ + static int movstrsi_label = 0; + int align = 4; + + rtx xoperands[9]; + int available[3]; + int i, j; + + /* Since we clobber untold things, nix the condition codes. */ + CC_STATUS_INIT; + + /* Get past the MEMs. */ + operands[0] = XEXP (operands[0], 0); + operands[1] = XEXP (operands[1], 0); + + xoperands[0] = 0; + xoperands[1] = 0; + xoperands[2] = 0; + + available[0] = 1; + available[1] = 1; + available[2] = 1; +#if 1 + /* Prepare to juggle registers if necessary. */ + if (REG_P (operands[0]) && (unsigned) (REGNO (operands[0]) - 10) < 3) + { + xoperands[0] = operands[0]; + available[REGNO (operands[0]) - 10] = 0; + } + if (REG_P (operands[1]) && (unsigned) (REGNO (operands[1]) - 10) < 3) + { + xoperands[1] = operands[1]; + available[REGNO (operands[1]) - 10] = 0; + } + if (REG_P (operands[2]) && (unsigned) (REGNO (operands[2]) - 10) < 3) + { + xoperands[2] = operands[2]; + available[REGNO (operands[2]) - 10] = 0; + } + for (i = 0; i < 3; i++) + { + if (xoperands[i]) + continue; + if (available[0]) + { + xoperands[i] = gen_rtx (REG, SImode, 10); + available[0] = 0; + continue; + } + if (available[1]) + { + xoperands[i] = gen_rtx (REG, SImode, 11); + available[1] = 0; + continue; + } + xoperands[i] = gen_rtx (REG, SImode, 12); + available[2] = 0; + } +#endif + + /* First, figure out best alignment we may assume. */ + if (REG_P (operands[2])) + { + xoperands[5] = operands[2]; + output_asm_insn ("sub %5,%2,1", xoperands); + align = 1; + } + else + { + int i = INTVAL (operands[2]); + + if (i & 1) + align = 1; + else if (i & 3) + { + align = 2; + i >>= 1; + } + else + i >>= 2; + + /* predecrement count. */ + i -= 1; + if (i < 0) abort (); + + xoperands[5] = gen_rtx (CONST_INT, VOIDmode, i); + + if (INT_FITS_16_BITS (i)) + output_asm_insn ("addu %2,r0,%5", xoperands); + else if (INT_FITS_16_BITS (-i)) + { + xoperands[5] = gen_rtx (CONST_INT, VOIDmode, -i); + output_asm_insn ("subu %2,r0,%5", xoperands); + } + else + output_asm_insn ("or.u %2,r0,hi16(%5)\n\tor %2,%2,lo16(%5)", xoperands); + } + /* Now, set up for pipelined operation: dest must contain + a pre-incremented address, because its index is pre-decremented. */ + + xoperands[3] = plus_constant (operands[0], align); + output_load_address (xoperands); + + xoperands[4] = operands[1]; + output_load_address (xoperands+1); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + if (align == 4) + output_asm_insn ("\n@Lm%3:\n\tld r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst r25,%0[%2]", xoperands); + else if (align == 2) + output_asm_insn ("\n@Lm%3:\n\tld.h r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst.h r25,%0[%2]", xoperands); + else + output_asm_insn ("\n@Lm%3:\n\tld.b r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst.b r25,%0[%2]", xoperands); + return ""; +} + +char * +output_store_const_int (mode, operands) + enum machine_mode mode; + rtx *operands; +{ + int i = INTVAL (operands[1]); + if (INT_FITS_16_BITS (i)) + return "addu %0,r0,%1"; + if (INT_FITS_16_BITS (-i)) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, -i); + return "subu %0,r0,%1"; + } + if ((i & 0xffff) == 0) + return "or.u %0,r0,hi16(%1)"; + /* Could check to see if number is a contiguous field + of 1's. Then we could use the SET instruction. */ + if (mode == HImode) + { + warning ("truncating constant `%d' to fit in half-word", INTVAL (operands[1])); + return "or %0,r0,lo16(%1)"; + } + if (mode == QImode) + { + warning ("truncating constant `%d' to fit in byte"); + operands[1] = gen_rtx (CONST_INT, VOIDmode, i & 0xff); + return "or %0,r0,%1"; + } + + return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)"; +} + +/* This routine assumes that floating point numbers are represented + in a manner which is consistent between host and target machines. */ +char * +output_store_const_float (mode, operands) + enum machine_mode mode; + rtx *operands; +{ + int i = INTVAL (operands[1]); + if (INT_FITS_16_BITS (i)) + return "addu %0,r0,%1"; + if (INT_FITS_16_BITS (-i)) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, -i); + return "subu %0,r0,%1"; + } + if ((i & 0xffff) == 0) + return "or.u %0,r0,hi16(%1)"; + /* Could check to see if number is a contiguous field + of 1's. Then we could use the SET instruction. */ + return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)"; +} |
