summaryrefslogtreecommitdiff
path: root/gcc/config/1750a/1750a.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/1750a/1750a.c')
-rwxr-xr-xgcc/config/1750a/1750a.c734
1 files changed, 734 insertions, 0 deletions
diff --git a/gcc/config/1750a/1750a.c b/gcc/config/1750a/1750a.c
new file mode 100755
index 0000000..134f69d
--- /dev/null
+++ b/gcc/config/1750a/1750a.c
@@ -0,0 +1,734 @@
+/* Subroutines for insn-output.c for MIL-STD-1750.
+ Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Contributed by O.M.Kellogg, DASA (kellogg@space.otn.dasa.de)
+
+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, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#define __datalbl
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include "rtl.h"
+#include "tree.h"
+#include "expr.h"
+#define HAVE_cc0
+#include "conditions.h"
+#include "real.h"
+#include "regs.h"
+
+struct datalabel_array datalbl[DATALBL_ARRSIZ];
+int datalbl_ndx = -1;
+struct jumplabel_array jmplbl[JMPLBL_ARRSIZ];
+int jmplbl_ndx = -1;
+int label_pending = 0, program_counter = 0;
+enum section current_section = Normal;
+char *sectname[4] =
+{"Init", "Normal", "Konst", "Static"};
+
+int
+notice_update_cc (exp)
+ rtx exp;
+{
+ if (GET_CODE (exp) == SET)
+ {
+ enum rtx_code src_code = GET_CODE (SET_SRC (exp));
+ /* Jumps do not alter the cc's. */
+ if (SET_DEST (exp) == pc_rtx)
+ return;
+ /* Moving a register or constant into memory doesn't alter the cc's. */
+ if (GET_CODE (SET_DEST (exp)) == MEM
+ && (src_code == REG || src_code == CONST_INT))
+ return;
+ /* Function calls clobber the cc's. */
+ if (src_code == CALL)
+ {
+ CC_STATUS_INIT;
+ return;
+ }
+ /* Emulated longword bit-ops leave cc's incorrect */
+ if (GET_MODE (SET_DEST (exp)) == HImode ?
+ src_code == AND || src_code == IOR ||
+ src_code == XOR || src_code == NOT : 0)
+ {
+ CC_STATUS_INIT;
+ return;
+ }
+ /* Tests and compares set the cc's in predictable ways. */
+ if (SET_DEST (exp) == cc0_rtx)
+ {
+ CC_STATUS_INIT;
+ cc_status.value1 = SET_SRC (exp);
+ return;
+ }
+ /* Anything else will set cc_status. */
+ cc_status.flags = CC_NO_OVERFLOW;
+ cc_status.value1 = SET_SRC (exp);
+ cc_status.value2 = SET_DEST (exp);
+ return;
+ }
+ else if (GET_CODE (exp) == PARALLEL
+ && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
+ {
+ if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
+ return;
+ if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
+ {
+ CC_STATUS_INIT;
+ cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
+ return;
+ }
+ CC_STATUS_INIT;
+ }
+ else
+ {
+ CC_STATUS_INIT;
+ }
+}
+
+
+rtx
+function_arg (cum, mode, type, named)
+ int cum;
+ enum machine_mode mode;
+ tree type;
+ int named;
+{
+ int size;
+
+ if (MUST_PASS_IN_STACK (mode, type))
+ return (rtx) 0;
+ if (mode == BLKmode)
+ size = int_size_in_bytes (type);
+ else
+ size = GET_MODE_SIZE (mode);
+ if (cum + size < 12)
+ return gen_rtx (REG, mode, cum);
+ else
+ return (rtx) 0;
+}
+
+
+double
+get_double (x)
+ rtx x;
+{
+ union
+ {
+ double d;
+ long i[2];
+ }
+ du;
+
+ du.i[0] = CONST_DOUBLE_LOW (x);
+ du.i[1] = CONST_DOUBLE_HIGH (x);
+ return du.d;
+}
+
+char *
+float_label (code, value)
+ char code;
+ double value;
+{
+ int i = 1;
+ static char label[32];
+ char *p;
+
+ label[0] = code;
+ p = label + 1;
+ sprintf (p, "%lf", value);
+ while (*p)
+ {
+ *p = (*p == '+') ? 'p' :
+ (*p == '-') ? 'm' : *p;
+ p++;
+ }
+ return xstrdup (label);
+}
+
+
+char *
+movcnt_regno_adjust (op)
+ rtx *op;
+{
+ static char outstr[80];
+ int op0r = REGNO (op[0]), op1r = REGNO (op[1]), op2r = REGNO (op[2]);
+#define dstreg op0r
+#define srcreg op1r
+#define cntreg op2r
+#define cntreg_1750 (op0r + 1)
+
+ if (cntreg == cntreg_1750)
+ sprintf (outstr, "mov r%d,r%d", op0r, op1r);
+ else if (dstreg + 1 == srcreg && cntreg > srcreg)
+ sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d", op2r, op1r, op0r, op2r);
+ else if (dstreg == cntreg + 1)
+ sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d", op0r, op2r, op2r, op1r);
+ else if (dstreg == srcreg + 1)
+ sprintf (outstr, "xwr r%d,r%d\n\txwr r%d,r%d\n\tmov r%d,r%d",
+ op0r, op1r, op0r, op2r, op1r, op2r);
+ else if (cntreg + 1 == srcreg)
+ sprintf (outstr, "xwr r%d,r%d\n\txwr r%d,r%d\n\tmov r%d,r%d",
+ op2r, op1r, op0r, op2r, op2r, op0r);
+ else if (cntreg == srcreg + 1)
+ sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d", op0r, op1r, op1r, op0r);
+ else
+ sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d\n\txwr r%d,r%d",
+ op2r, cntreg_1750, op0r, op1r, op2r, cntreg_1750);
+ return outstr;
+}
+
+char *
+mod_regno_adjust (instr, op)
+ char *instr;
+ rtx *op;
+{
+ static char outstr[40];
+ char *r = (!strncmp (instr, "dvr", 3) ? "r" : "");
+ int modregno_gcc = REGNO (op[3]), modregno_1750 = REGNO (op[0]) + 1;
+
+ if (modregno_gcc == modregno_1750
+ || (reg_renumber != NULL
+ && reg_renumber[modregno_gcc] >= 0
+ && reg_renumber[modregno_gcc] == reg_renumber[modregno_1750]))
+ sprintf (outstr, "%s r%%0,%s%%2", instr, r);
+ else
+ sprintf (outstr, "lr r%d,r%d\n\t%s r%%0,%s%%2\n\txwr r%d,r%d",
+ modregno_gcc, modregno_1750, instr, r, modregno_1750,
+ modregno_gcc);
+ return outstr;
+}
+
+
+/* Check if op is a valid memory operand for 1750A Load/Store instructions
+ (memory indirection permitted.) */
+
+int
+memop_valid (op)
+ rtx op;
+{
+ static int recurred = 0;
+ int valid;
+
+ if (GET_MODE (op) != Pmode && GET_MODE (op) != VOIDmode
+ && GET_MODE (op) != QImode)
+ return 0;
+ switch (GET_CODE (op))
+ {
+ case MEM:
+ if (!recurred && GET_CODE (XEXP (op, 0)) == REG)
+ return 1;
+ case MINUS:
+ case MULT:
+ case DIV:
+ return 0;
+ case PLUS:
+ recurred = 1;
+ valid = memop_valid (XEXP (op, 0));
+ if (valid)
+ valid = memop_valid (XEXP (op, 1));
+ recurred = 0;
+ return valid;
+ case REG:
+ if (REGNO (op) > 0)
+ return 1;
+ return 0;
+ case CONST:
+ case CONST_INT:
+ case SYMBOL_REF:
+ case SUBREG:
+ return 1;
+ default:
+ printf ("memop_valid: code=%d\n", (int) GET_CODE (op));
+ return 1;
+ }
+}
+
+
+/* predicate for the MOV instruction: */
+int
+mov_memory_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == REG);
+}
+
+/* predicate for the STC instruction: */
+int
+small_nonneg_const (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) <= 15)
+ return 1;
+ return 0;
+}
+
+/* predicate for constant zero: */
+int
+zero_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return op == CONST0_RTX (mode);
+}
+
+
+/* predicate for 1750 `B' addressing mode (Base Register with Offset)
+ memory operand */
+int
+b_mode_operand (op)
+ rtx op;
+{
+ if (GET_CODE (op) == MEM)
+ {
+ rtx inner = XEXP (op, 0);
+ if (GET_CODE (inner) == REG && REG_OK_FOR_INDEX_P (inner))
+ return 1;
+ if (GET_CODE (inner) == PLUS)
+ {
+ rtx plus_op0 = XEXP (inner, 0);
+ if (GET_CODE (plus_op0) == REG && REG_OK_FOR_INDEX_P (plus_op0))
+ {
+ rtx plus_op1 = XEXP (inner, 1);
+ if (GET_CODE (plus_op1) == CONST_INT
+ && INTVAL (plus_op1) >= 0
+ && INTVAL (plus_op1) <= 255)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/* Decide whether to output a conditional jump as a "Jump Conditional"
+ or as a "Branch Conditional": */
+
+int
+find_jmplbl (labelnum)
+ int labelnum;
+{
+ int i, found = 0;
+
+ for (i = 0; i <= jmplbl_ndx; i++)
+ if (labelnum == jmplbl[i].num)
+ {
+ found = 1;
+ break;
+ }
+ if (found)
+ return i;
+ return -1;
+}
+
+char *
+branch_or_jump (condition, targetlabel_number)
+ char *condition;
+ int targetlabel_number;
+{
+ static char buf[30];
+ int index;
+
+ if ((index = find_jmplbl (targetlabel_number)) >= 0)
+ if (program_counter - jmplbl[index].pc < 128)
+ {
+ sprintf (buf, "b%s %%l0", condition);
+ return buf;
+ }
+ sprintf (buf, "jc %s,%%l0", condition);
+ return buf;
+}
+
+
+int
+unsigned_comparison_operator (insn)
+ rtx insn;
+{
+ switch (GET_CODE (insn))
+ {
+ case GEU:
+ case GTU:
+ case LEU:
+ case LTU:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int
+next_cc_user_is_unsigned (insn)
+ rtx insn;
+{
+ if ( !(insn = next_cc0_user (insn)))
+ abort ();
+ else if (GET_CODE (insn) == JUMP_INSN
+ && GET_CODE (PATTERN (insn)) == SET
+ && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
+ return unsigned_comparison_operator (XEXP (SET_SRC (PATTERN (insn)), 0));
+ else if (GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == SET)
+ return unsigned_comparison_operator (SET_SRC (PATTERN (insn)));
+ else
+ abort ();
+}
+
+
+static int addr_inc;
+
+/* A C compound statement to output to stdio stream STREAM the
+ assembler syntax for an instruction operand X. X is an RTL
+ expression.
+
+ CODE is a value that can be used to specify one of several ways
+ of printing the operand. It is used when identical operands
+ must be printed differently depending on the context. CODE
+ comes from the `%' specification that was used to request
+ printing of the operand. If the specification was just `%DIGIT'
+ then CODE is 0; if the specification was `%LTR DIGIT' then CODE
+ is the ASCII code for LTR.
+
+ If X is a register, this macro should print the register's name.
+ The names can be found in an array `reg_names' whose type is
+ `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
+
+ When the machine description has a specification `%PUNCT' (a `%'
+ followed by a punctuation character), this macro is called with
+ a null pointer for X and the punctuation character for CODE.
+
+ The 1750 specific codes are:
+ 'J' for the negative of a constant
+ 'Q' for printing addresses in B mode syntax
+ 'd' for the second register in a pair
+ 't' for the third register in a triple
+ 'b' for the bit number (using 1750 test bit convention)
+ 'B' for the bit number of the 1's complement (for bit clear)
+ 'w' for int - 16
+*/
+
+print_operand (file, x, letter)
+ FILE *file;
+ rtx x;
+ int letter;
+{
+ switch (GET_CODE (x))
+ {
+ case REG:
+ if (letter == 'd')
+ fprintf (file, "%d", REGNO (x) + 1);
+ else if (letter == 't')
+ fprintf (file, "%d", REGNO (x) + 2);
+ else
+ fprintf (file, "%d", REGNO (x));
+ break;
+
+ case SYMBOL_REF:
+ fprintf (file, "%s", XSTR (x, 0));
+ if (letter == 'A')
+ fprintf (file, "+1");
+ break;
+
+ case LABEL_REF:
+ case CONST:
+ case MEM:
+ if (letter == 'Q')
+ {
+ rtx inner = XEXP (x, 0);
+ switch (GET_CODE (inner))
+ {
+ case REG:
+ fprintf (file, "r%d,0", REGNO (inner));
+ break;
+ case PLUS:
+ fprintf (file, "r%d,%d", REGNO (XEXP (inner, 0)),
+ INTVAL (XEXP (inner, 1)));
+ break;
+ default:
+ fprintf (file, "[ill Q code=%d]", GET_CODE (inner));
+ }
+ }
+ else
+ {
+ addr_inc = (letter == 'A' ? 1 : 0);
+ output_address (XEXP (x, 0));
+ }
+ break;
+
+ case CONST_DOUBLE:
+/* {
+ double value = get_double (x);
+ char fltstr[32];
+ sprintf (fltstr, "%lf", value);
+
+ if (letter == 'D' || letter == 'E')
+ {
+ int i, found = 0;
+ for (i = 0; i <= datalbl_ndx; i++)
+ if (strcmp (fltstr, datalbl[i].value) == 0)
+ {
+ found = 1;
+ break;
+ }
+ if (!found)
+ {
+ strcpy (datalbl[i = ++datalbl_ndx].value, fltstr);
+ datalbl[i].name = float_label (letter, value);
+ datalbl[i].size = (letter == 'E') ? 3 : 2;
+ check_section (Konst);
+ fprintf (file, "K%s \tdata%s %s ;p_o\n", datalbl[i].name,
+ (letter == 'E' ? "ef" : "f"), fltstr);
+ check_section (Normal);
+ }
+ }
+ else if (letter == 'F' || letter == 'G')
+ {
+ int i, found = 0;
+ for (i = 0; i <= datalbl_ndx; i++)
+ if (strcmp (fltstr, datalbl[i].value) == 0)
+ {
+ found = 1;
+ break;
+ }
+ if (!found)
+ {
+ fprintf (stderr,
+ "float value %lfnot found upon label reference\n", value);
+ strcpy (datalbl[i = ++datalbl_ndx].value, fltstr);
+ datalbl[i].name = float_label (letter, value);
+ datalbl[i].size = (letter == 'G') ? 3 : 2;
+ check_section (Konst);
+ fprintf (file, "K%s \tdata%s %s ;p_o\n", datalbl[i].name,
+ (letter == 'G' ? "ef" : "f"), fltstr);
+ check_section (Normal);
+ }
+ fprintf (file, "%s ;P_O 'F'", datalbl[i].name);
+ }
+ else
+ fprintf (file, " %s ;P_O cst_dbl ", fltstr);
+ }
+ */
+ fprintf (file, "%lf", get_double (x));
+ break;
+
+ case CONST_INT:
+ if (letter == 'J')
+ fprintf (file, "%d", -INTVAL (x));
+ else if (letter == 'b')
+ fprintf (file, "%d", which_bit (INTVAL (x)));
+ else if (letter == 'B')
+ fprintf (file, "%d", which_bit (~INTVAL (x)));
+ else if (letter == 'w')
+ fprintf (file, "%d", INTVAL (x) - 16);
+ else
+ fprintf (file, "%d", INTVAL (x));
+ break;
+
+ case CODE_LABEL:
+ fprintf (file, "L%d", XINT (x, 3));
+ break;
+
+ case CALL:
+ fprintf (file, "CALL nargs=%d, func is either '%s' or '%s'",
+ XEXP (x, 1), XSTR (XEXP (XEXP (x, 0), 1), 0), XSTR (XEXP (x, 0), 1));
+ break;
+
+ case PLUS:
+ {
+ rtx op0 = XEXP (x, 0), op1 = XEXP (x, 1);
+ int op0code = GET_CODE (op0), op1code = GET_CODE (op1);
+ if (op1code == CONST_INT)
+ switch (op0code)
+ {
+ case REG:
+ fprintf (file, "%d,r%d ; p_o_PLUS for REG and CONST_INT",
+ INTVAL (op1), REGNO (op0));
+ break;
+ case SYMBOL_REF:
+ fprintf (file, "%d+%s", INTVAL (op1), XSTR (op0, 0));
+ break;
+ case MEM:
+ fprintf (file, "%d,[mem:", INTVAL (op1));
+ output_address (XEXP (op0, 0));
+ fprintf (file, "] ;P_O plus");
+ break;
+ default:
+ fprintf (file, "p_o_PLUS UFO, code=%d, with CONST=%d",
+ (int) op0code, INTVAL (op1));
+ }
+ else if (op1code == SYMBOL_REF && op0code == REG)
+ fprintf (file, "%s,r%d ; P_O: (plus reg sym)",
+ XSTR (op1, 0), REGNO (op0));
+ else
+ fprintf (file, "p_o_+: op0code=%d, op1code=%d", op0code, op1code);
+ }
+ break;
+
+ default:
+ fprintf (file, "p_o_UFO code=%d", GET_CODE (x));
+ }
+
+ addr_inc = 0;
+}
+
+print_operand_address (file, addr)
+ FILE *file;
+ rtx addr;
+{
+ switch (GET_CODE (addr))
+ {
+ case REG:
+ fprintf (file, "%d,r%d ; P_O_A", addr_inc, REGNO (addr));
+ break;
+ case PLUS:
+ {
+ register rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
+ switch (GET_CODE (x))
+ {
+ case REG:
+ switch (GET_CODE (y))
+ {
+ case CONST:
+ output_address (XEXP (y, 0));
+ fprintf (file, ",r%d ;P_O_A reg + const expr", REGNO (x));
+ break;
+ case CONST_INT:
+ fprintf (file, "%d,r%d", INTVAL (y) + addr_inc, REGNO (x));
+ break;
+ case SYMBOL_REF:
+ fprintf (file, "%s", XSTR (y, 0));
+ if (addr_inc)
+ fprintf (file, "+%d", addr_inc);
+ fprintf (file, ",r%d ; P_O_A reg + sym", REGNO (x));
+ break;
+ case LABEL_REF:
+ output_address (XEXP (y, 0));
+ fprintf (file, ",r%d ; P_O_A reg + label", REGNO (x));
+ break;
+ default:
+ fprintf (file, "[P_O_A reg%d+UFO code=%d]",
+ REGNO (x), GET_CODE (y));
+ }
+ break;
+ case LABEL_REF:
+ output_address (XEXP (x, 0));
+ break;
+ case SYMBOL_REF:
+ switch (GET_CODE (y))
+ {
+ case CONST_INT:
+ fprintf (file, "%d+%s", INTVAL (y) + addr_inc, XSTR (x, 0));
+ break;
+ case REG:
+ fprintf (file, "%s,r%d ;P_O_A sym + reg",
+ XSTR (x, 0), REGNO (y));
+ break;
+ default:
+ fprintf (file, "P_O_A sym/lab+UFO[sym=%s,code(y)=%d]",
+ XSTR (x, 0), GET_CODE (y));
+ }
+ break;
+ case CONST:
+ output_address (XEXP (x, 0));
+ if (GET_CODE (y) == REG)
+ fprintf (file, ",r%d ;P_O_A const + reg", REGNO (x));
+ else
+ fprintf (file, "P_O_A const+UFO code(y)=%d]", GET_CODE (y));
+ break;
+ case MEM:
+ output_address (y);
+ fprintf (file, ",[mem:");
+ output_address (XEXP (x, 0));
+ fprintf (file, "] ;P_O_A plus");
+ break;
+ default:
+ fprintf (file, "P_O_A plus op1_UFO[code1=%d,code2=%d]",
+ GET_CODE (x), GET_CODE (y));
+ }
+ }
+ break;
+ case CONST_INT:
+ if (INTVAL (addr) < 0x10000 && INTVAL (addr) >= -0x10000)
+ fprintf (file, "%d ; p_o_a const addr?!", INTVAL (addr));
+ else
+ {
+ fprintf (file, "[p_o_a=ILLEGAL_CONST]");
+ output_addr_const (file, addr);
+ }
+ break;
+ case LABEL_REF:
+ case SYMBOL_REF:
+ fprintf (file, "%s", XSTR (addr, 0));
+ if (addr_inc)
+ fprintf (file, "+%d", addr_inc);
+ break;
+ case MEM:
+ fprintf (file, "[memUFO:");
+ output_address (XEXP (addr, 0));
+ fprintf (file, "]");
+ break;
+ case CONST:
+ output_address (XEXP (addr, 0));
+ fprintf (file, " ;P_O_A const");
+ break;
+ case CODE_LABEL:
+ fprintf (file, "L%d", XINT (addr, 3));
+ break;
+ default:
+ fprintf (file, " p_o_a UFO, code=%d val=0x%x",
+ (int) GET_CODE (addr), INTVAL (addr));
+ break;
+ }
+ addr_inc = 0;
+}
+
+
+/*
+ * Return non zero if the LS 16 bits of the given value has just one bit set,
+ * otherwise return zero. Note this function may be used to detect one
+ * bit clear by inverting the param.
+ */
+int
+one_bit_set_p (x)
+ int x;
+{
+ x &= 0xffff;
+ return x && (x & (x - 1)) == 0;
+}
+
+
+/*
+ * Return the number of the least significant bit set, using the same
+ * convention for bit numbering as in the MIL-STD-1750 sb instruction.
+ */
+int
+which_bit (x)
+ int x;
+{
+ int b = 15;
+
+ while (b > 0 && (x & 1) == 0)
+ {
+ b--;
+ x >>= 1;
+ }
+
+ return b;
+}
+
+