]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/1750a/1750a.c
789eedb6c589cca3f5b87217927f1d8a5c3af6cb
[thirdparty/gcc.git] / gcc / config / 1750a / 1750a.c
1 /* Subroutines for insn-output.c for MIL-STD-1750.
2 Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
3 Contributed by O.M.Kellogg, DASA (kellogg@space.otn.dasa.de)
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 1, or (at your option)
10 any later version.
11
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #define __datalbl
23 #include "config.h"
24 #include <stdio.h>
25 #include <string.h>
26 #include "rtl.h"
27 #include "tree.h"
28 #include "function.h"
29 #include "expr.h"
30 #define HAVE_cc0
31 #include "conditions.h"
32 #include "real.h"
33 #include "regs.h"
34
35 struct datalabel_array datalbl[DATALBL_ARRSIZ];
36 int datalbl_ndx = -1;
37 struct jumplabel_array jmplbl[JMPLBL_ARRSIZ];
38 int jmplbl_ndx = -1;
39 int label_pending = 0, program_counter = 0;
40 enum section current_section = Normal;
41 char *sectname[4] =
42 {"Init", "Normal", "Konst", "Static"};
43
44 int
45 notice_update_cc (exp)
46 rtx exp;
47 {
48 if (GET_CODE (exp) == SET)
49 {
50 enum rtx_code src_code = GET_CODE (SET_SRC (exp));
51 /* Jumps do not alter the cc's. */
52 if (SET_DEST (exp) == pc_rtx)
53 return;
54 /* Moving a register or constant into memory doesn't alter the cc's. */
55 if (GET_CODE (SET_DEST (exp)) == MEM
56 && (src_code == REG || src_code == CONST_INT))
57 return;
58 /* Function calls clobber the cc's. */
59 if (src_code == CALL)
60 {
61 CC_STATUS_INIT;
62 return;
63 }
64 /* Emulated longword bit-ops leave cc's incorrect */
65 if (GET_MODE (SET_DEST (exp)) == HImode ?
66 src_code == AND || src_code == IOR ||
67 src_code == XOR || src_code == NOT : 0)
68 {
69 CC_STATUS_INIT;
70 return;
71 }
72 /* Tests and compares set the cc's in predictable ways. */
73 if (SET_DEST (exp) == cc0_rtx)
74 {
75 CC_STATUS_INIT;
76 cc_status.value1 = SET_SRC (exp);
77 return;
78 }
79 /* Anything else will set cc_status. */
80 cc_status.flags = CC_NO_OVERFLOW;
81 cc_status.value1 = SET_SRC (exp);
82 cc_status.value2 = SET_DEST (exp);
83 return;
84 }
85 else if (GET_CODE (exp) == PARALLEL
86 && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
87 {
88 if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
89 return;
90 if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
91 {
92 CC_STATUS_INIT;
93 cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
94 return;
95 }
96 CC_STATUS_INIT;
97 }
98 else
99 {
100 CC_STATUS_INIT;
101 }
102 }
103
104
105 rtx
106 function_arg (cum, mode, type, named)
107 int cum;
108 enum machine_mode mode;
109 tree type;
110 int named;
111 {
112 int size;
113
114 if (MUST_PASS_IN_STACK (mode, type))
115 return (rtx) 0;
116 if (mode == BLKmode)
117 size = int_size_in_bytes (type);
118 else
119 size = GET_MODE_SIZE (mode);
120 if (cum + size < 12)
121 return gen_rtx (REG, mode, cum);
122 else
123 return (rtx) 0;
124 }
125
126
127 double
128 get_double (x)
129 rtx x;
130 {
131 union
132 {
133 double d;
134 long i[2];
135 }
136 du;
137
138 du.i[0] = CONST_DOUBLE_LOW (x);
139 du.i[1] = CONST_DOUBLE_HIGH (x);
140 return du.d;
141 }
142
143 char *
144 float_label (code, value)
145 char code;
146 double value;
147 {
148 int i = 1;
149 static char label[32];
150 char *p;
151
152 label[0] = code;
153 p = label + 1;
154 sprintf (p, "%lf", value);
155 while (*p)
156 {
157 *p = (*p == '+') ? 'p' :
158 (*p == '-') ? 'm' : *p;
159 p++;
160 }
161 return xstrdup (label);
162 }
163
164
165 char *
166 movcnt_regno_adjust (op)
167 rtx *op;
168 {
169 static char outstr[80];
170 int op0r = REGNO (op[0]), op1r = REGNO (op[1]), op2r = REGNO (op[2]);
171 #define dstreg op0r
172 #define srcreg op1r
173 #define cntreg op2r
174 #define cntreg_1750 (op0r + 1)
175
176 if (cntreg == cntreg_1750)
177 sprintf (outstr, "mov r%d,r%d", op0r, op1r);
178 else if (dstreg + 1 == srcreg && cntreg > srcreg)
179 sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d", op2r, op1r, op0r, op2r);
180 else if (dstreg == cntreg + 1)
181 sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d", op0r, op2r, op2r, op1r);
182 else if (dstreg == srcreg + 1)
183 sprintf (outstr, "xwr r%d,r%d\n\txwr r%d,r%d\n\tmov r%d,r%d",
184 op0r, op1r, op0r, op2r, op1r, op2r);
185 else if (cntreg + 1 == srcreg)
186 sprintf (outstr, "xwr r%d,r%d\n\txwr r%d,r%d\n\tmov r%d,r%d",
187 op2r, op1r, op0r, op2r, op2r, op0r);
188 else if (cntreg == srcreg + 1)
189 sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d", op0r, op1r, op1r, op0r);
190 else
191 sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d\n\txwr r%d,r%d",
192 op2r, cntreg_1750, op0r, op1r, op2r, cntreg_1750);
193 return outstr;
194 }
195
196 char *
197 mod_regno_adjust (instr, op)
198 char *instr;
199 rtx *op;
200 {
201 static char outstr[40];
202 char *r = (!strncmp (instr, "dvr", 3) ? "r" : "");
203 int modregno_gcc = REGNO (op[3]), modregno_1750 = REGNO (op[0]) + 1;
204
205 if (modregno_gcc == modregno_1750
206 || (reg_renumber != NULL
207 && reg_renumber[modregno_gcc] >= 0
208 && reg_renumber[modregno_gcc] == reg_renumber[modregno_1750]))
209 sprintf (outstr, "%s r%%0,%s%%2", instr, r);
210 else
211 sprintf (outstr, "lr r%d,r%d\n\t%s r%%0,%s%%2\n\txwr r%d,r%d",
212 modregno_gcc, modregno_1750, instr, r, modregno_1750,
213 modregno_gcc);
214 return outstr;
215 }
216
217
218 /* Check if op is a valid memory operand for 1750A Load/Store instructions
219 (memory indirection permitted.) */
220
221 int
222 memop_valid (op)
223 rtx op;
224 {
225 static int recurred = 0;
226 int valid_operand;
227
228 if (GET_MODE (op) != Pmode && GET_MODE (op) != VOIDmode
229 && GET_MODE (op) != QImode)
230 return 0;
231 switch (GET_CODE (op))
232 {
233 case MEM:
234 if (!recurred && GET_CODE (XEXP (op, 0)) == REG)
235 return 1;
236 case MINUS:
237 case MULT:
238 case DIV:
239 return 0;
240 case PLUS:
241 recurred = 1;
242 valid_operand = memop_valid (XEXP (op, 0));
243 if (valid_operand)
244 valid_operand = memop_valid (XEXP (op, 1));
245 recurred = 0;
246 return valid_operand;
247 case REG:
248 if (REGNO (op) > 0)
249 return 1;
250 return 0;
251 case CONST:
252 case CONST_INT:
253 case SYMBOL_REF:
254 case SUBREG:
255 return 1;
256 default:
257 printf ("memop_valid: code=%d\n", (int) GET_CODE (op));
258 return 1;
259 }
260 }
261
262
263 /* predicate for the MOV instruction: */
264 int
265 mov_memory_operand (op, mode)
266 rtx op;
267 enum machine_mode mode;
268 {
269 return (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == REG);
270 }
271
272 /* predicate for the STC instruction: */
273 int
274 small_nonneg_const (op, mode)
275 rtx op;
276 enum machine_mode mode;
277 {
278 if (GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) <= 15)
279 return 1;
280 return 0;
281 }
282
283 /* predicate for constant zero: */
284 int
285 zero_operand (op, mode)
286 rtx op;
287 enum machine_mode mode;
288 {
289 return op == CONST0_RTX (mode);
290 }
291
292
293 /* predicate for 1750 `B' addressing mode (Base Register with Offset)
294 memory operand */
295 int
296 b_mode_operand (op)
297 rtx op;
298 {
299 if (GET_CODE (op) == MEM)
300 {
301 rtx inner = XEXP (op, 0);
302 if (GET_CODE (inner) == REG && REG_OK_FOR_INDEX_P (inner))
303 return 1;
304 if (GET_CODE (inner) == PLUS)
305 {
306 rtx plus_op0 = XEXP (inner, 0);
307 if (GET_CODE (plus_op0) == REG && REG_OK_FOR_INDEX_P (plus_op0))
308 {
309 rtx plus_op1 = XEXP (inner, 1);
310 if (GET_CODE (plus_op1) == CONST_INT
311 && INTVAL (plus_op1) >= 0
312 && INTVAL (plus_op1) <= 255)
313 return 1;
314 }
315 }
316 }
317 return 0;
318 }
319
320
321 /* Decide whether to output a conditional jump as a "Jump Conditional"
322 or as a "Branch Conditional": */
323
324 int
325 find_jmplbl (labelnum)
326 int labelnum;
327 {
328 int i, found = 0;
329
330 for (i = 0; i <= jmplbl_ndx; i++)
331 if (labelnum == jmplbl[i].num)
332 {
333 found = 1;
334 break;
335 }
336 if (found)
337 return i;
338 return -1;
339 }
340
341 char *
342 branch_or_jump (condition, targetlabel_number)
343 char *condition;
344 int targetlabel_number;
345 {
346 static char buf[30];
347 int index;
348
349 if ((index = find_jmplbl (targetlabel_number)) >= 0)
350 if (program_counter - jmplbl[index].pc < 128)
351 {
352 sprintf (buf, "b%s %%l0", condition);
353 return buf;
354 }
355 sprintf (buf, "jc %s,%%l0", condition);
356 return buf;
357 }
358
359
360 int
361 unsigned_comparison_operator (insn)
362 rtx insn;
363 {
364 switch (GET_CODE (insn))
365 {
366 case GEU:
367 case GTU:
368 case LEU:
369 case LTU:
370 return 1;
371 default:
372 return 0;
373 }
374 }
375
376 int
377 next_cc_user_is_unsigned (insn)
378 rtx insn;
379 {
380 if ( !(insn = next_cc0_user (insn)))
381 abort ();
382 else if (GET_CODE (insn) == JUMP_INSN
383 && GET_CODE (PATTERN (insn)) == SET
384 && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
385 return unsigned_comparison_operator (XEXP (SET_SRC (PATTERN (insn)), 0));
386 else if (GET_CODE (insn) == INSN
387 && GET_CODE (PATTERN (insn)) == SET)
388 return unsigned_comparison_operator (SET_SRC (PATTERN (insn)));
389 else
390 abort ();
391 }
392
393
394 static int addr_inc;
395
396 /* A C compound statement to output to stdio stream STREAM the
397 assembler syntax for an instruction operand X. X is an RTL
398 expression.
399
400 CODE is a value that can be used to specify one of several ways
401 of printing the operand. It is used when identical operands
402 must be printed differently depending on the context. CODE
403 comes from the `%' specification that was used to request
404 printing of the operand. If the specification was just `%DIGIT'
405 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
406 is the ASCII code for LTR.
407
408 If X is a register, this macro should print the register's name.
409 The names can be found in an array `reg_names' whose type is
410 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
411
412 When the machine description has a specification `%PUNCT' (a `%'
413 followed by a punctuation character), this macro is called with
414 a null pointer for X and the punctuation character for CODE.
415
416 The 1750 specific codes are:
417 'J' for the negative of a constant
418 'Q' for printing addresses in B mode syntax
419 'd' for the second register in a pair
420 't' for the third register in a triple
421 'b' for the bit number (using 1750 test bit convention)
422 'B' for the bit number of the 1's complement (for bit clear)
423 'w' for int - 16
424 */
425
426 print_operand (file, x, letter)
427 FILE *file;
428 rtx x;
429 int letter;
430 {
431 switch (GET_CODE (x))
432 {
433 case REG:
434 if (letter == 'd')
435 fprintf (file, "%d", REGNO (x) + 1);
436 else if (letter == 't')
437 fprintf (file, "%d", REGNO (x) + 2);
438 else
439 fprintf (file, "%d", REGNO (x));
440 break;
441
442 case SYMBOL_REF:
443 fprintf (file, "%s", XSTR (x, 0));
444 if (letter == 'A')
445 fprintf (file, "+1");
446 break;
447
448 case LABEL_REF:
449 case CONST:
450 case MEM:
451 if (letter == 'Q')
452 {
453 rtx inner = XEXP (x, 0);
454 switch (GET_CODE (inner))
455 {
456 case REG:
457 fprintf (file, "r%d,0", REGNO (inner));
458 break;
459 case PLUS:
460 fprintf (file, "r%d,%d", REGNO (XEXP (inner, 0)),
461 INTVAL (XEXP (inner, 1)));
462 break;
463 default:
464 fprintf (file, "[ill Q code=%d]", GET_CODE (inner));
465 }
466 }
467 else
468 {
469 addr_inc = (letter == 'A' ? 1 : 0);
470 output_address (XEXP (x, 0));
471 }
472 break;
473
474 case CONST_DOUBLE:
475 /* {
476 double value = get_double (x);
477 char fltstr[32];
478 sprintf (fltstr, "%lf", value);
479
480 if (letter == 'D' || letter == 'E')
481 {
482 int i, found = 0;
483 for (i = 0; i <= datalbl_ndx; i++)
484 if (strcmp (fltstr, datalbl[i].value) == 0)
485 {
486 found = 1;
487 break;
488 }
489 if (!found)
490 {
491 strcpy (datalbl[i = ++datalbl_ndx].value, fltstr);
492 datalbl[i].name = float_label (letter, value);
493 datalbl[i].size = (letter == 'E') ? 3 : 2;
494 check_section (Konst);
495 fprintf (file, "K%s \tdata%s %s ;p_o\n", datalbl[i].name,
496 (letter == 'E' ? "ef" : "f"), fltstr);
497 check_section (Normal);
498 }
499 }
500 else if (letter == 'F' || letter == 'G')
501 {
502 int i, found = 0;
503 for (i = 0; i <= datalbl_ndx; i++)
504 if (strcmp (fltstr, datalbl[i].value) == 0)
505 {
506 found = 1;
507 break;
508 }
509 if (!found)
510 {
511 fprintf (stderr,
512 "float value %lfnot found upon label reference\n", value);
513 strcpy (datalbl[i = ++datalbl_ndx].value, fltstr);
514 datalbl[i].name = float_label (letter, value);
515 datalbl[i].size = (letter == 'G') ? 3 : 2;
516 check_section (Konst);
517 fprintf (file, "K%s \tdata%s %s ;p_o\n", datalbl[i].name,
518 (letter == 'G' ? "ef" : "f"), fltstr);
519 check_section (Normal);
520 }
521 fprintf (file, "%s ;P_O 'F'", datalbl[i].name);
522 }
523 else
524 fprintf (file, " %s ;P_O cst_dbl ", fltstr);
525 }
526 */
527 fprintf (file, "%lf", get_double (x));
528 break;
529
530 case CONST_INT:
531 if (letter == 'J')
532 fprintf (file, "%d", -INTVAL (x));
533 else if (letter == 'b')
534 fprintf (file, "%d", which_bit (INTVAL (x)));
535 else if (letter == 'B')
536 fprintf (file, "%d", which_bit (~INTVAL (x)));
537 else if (letter == 'w')
538 fprintf (file, "%d", INTVAL (x) - 16);
539 else
540 fprintf (file, "%d", INTVAL (x));
541 break;
542
543 case CODE_LABEL:
544 fprintf (file, "L%d", XINT (x, 3));
545 break;
546
547 case CALL:
548 fprintf (file, "CALL nargs=%d, func is either '%s' or '%s'",
549 XEXP (x, 1), XSTR (XEXP (XEXP (x, 0), 1), 0), XSTR (XEXP (x, 0), 1));
550 break;
551
552 case PLUS:
553 {
554 rtx op0 = XEXP (x, 0), op1 = XEXP (x, 1);
555 int op0code = GET_CODE (op0), op1code = GET_CODE (op1);
556 if (op1code == CONST_INT)
557 switch (op0code)
558 {
559 case REG:
560 fprintf (file, "%d,r%d ; p_o_PLUS for REG and CONST_INT",
561 INTVAL (op1), REGNO (op0));
562 break;
563 case SYMBOL_REF:
564 fprintf (file, "%d+%s", INTVAL (op1), XSTR (op0, 0));
565 break;
566 case MEM:
567 fprintf (file, "%d,[mem:", INTVAL (op1));
568 output_address (XEXP (op0, 0));
569 fprintf (file, "] ;P_O plus");
570 break;
571 default:
572 fprintf (file, "p_o_PLUS UFO, code=%d, with CONST=%d",
573 (int) op0code, INTVAL (op1));
574 }
575 else if (op1code == SYMBOL_REF && op0code == REG)
576 fprintf (file, "%s,r%d ; P_O: (plus reg sym)",
577 XSTR (op1, 0), REGNO (op0));
578 else
579 fprintf (file, "p_o_+: op0code=%d, op1code=%d", op0code, op1code);
580 }
581 break;
582
583 default:
584 fprintf (file, "p_o_UFO code=%d", GET_CODE (x));
585 }
586
587 addr_inc = 0;
588 }
589
590 print_operand_address (file, addr)
591 FILE *file;
592 rtx addr;
593 {
594 switch (GET_CODE (addr))
595 {
596 case REG:
597 fprintf (file, "%d,r%d ; P_O_A", addr_inc, REGNO (addr));
598 break;
599 case PLUS:
600 {
601 register rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
602 switch (GET_CODE (x))
603 {
604 case REG:
605 switch (GET_CODE (y))
606 {
607 case CONST:
608 output_address (XEXP (y, 0));
609 fprintf (file, ",r%d ;P_O_A reg + const expr", REGNO (x));
610 break;
611 case CONST_INT:
612 fprintf (file, "%d,r%d", INTVAL (y) + addr_inc, REGNO (x));
613 break;
614 case SYMBOL_REF:
615 fprintf (file, "%s", XSTR (y, 0));
616 if (addr_inc)
617 fprintf (file, "+%d", addr_inc);
618 fprintf (file, ",r%d ; P_O_A reg + sym", REGNO (x));
619 break;
620 case LABEL_REF:
621 output_address (XEXP (y, 0));
622 fprintf (file, ",r%d ; P_O_A reg + label", REGNO (x));
623 break;
624 default:
625 fprintf (file, "[P_O_A reg%d+UFO code=%d]",
626 REGNO (x), GET_CODE (y));
627 }
628 break;
629 case LABEL_REF:
630 output_address (XEXP (x, 0));
631 break;
632 case SYMBOL_REF:
633 switch (GET_CODE (y))
634 {
635 case CONST_INT:
636 fprintf (file, "%d+%s", INTVAL (y) + addr_inc, XSTR (x, 0));
637 break;
638 case REG:
639 fprintf (file, "%s,r%d ;P_O_A sym + reg",
640 XSTR (x, 0), REGNO (y));
641 break;
642 default:
643 fprintf (file, "P_O_A sym/lab+UFO[sym=%s,code(y)=%d]",
644 XSTR (x, 0), GET_CODE (y));
645 }
646 break;
647 case CONST:
648 output_address (XEXP (x, 0));
649 if (GET_CODE (y) == REG)
650 fprintf (file, ",r%d ;P_O_A const + reg", REGNO (x));
651 else
652 fprintf (file, "P_O_A const+UFO code(y)=%d]", GET_CODE (y));
653 break;
654 case MEM:
655 output_address (y);
656 fprintf (file, ",[mem:");
657 output_address (XEXP (x, 0));
658 fprintf (file, "] ;P_O_A plus");
659 break;
660 default:
661 fprintf (file, "P_O_A plus op1_UFO[code1=%d,code2=%d]",
662 GET_CODE (x), GET_CODE (y));
663 }
664 }
665 break;
666 case CONST_INT:
667 if (INTVAL (addr) < 0x10000 && INTVAL (addr) >= -0x10000)
668 fprintf (file, "%d ; p_o_a const addr?!", INTVAL (addr));
669 else
670 {
671 fprintf (file, "[p_o_a=ILLEGAL_CONST]");
672 output_addr_const (file, addr);
673 }
674 break;
675 case LABEL_REF:
676 case SYMBOL_REF:
677 fprintf (file, "%s", XSTR (addr, 0));
678 if (addr_inc)
679 fprintf (file, "+%d", addr_inc);
680 break;
681 case MEM:
682 fprintf (file, "[memUFO:");
683 output_address (XEXP (addr, 0));
684 fprintf (file, "]");
685 break;
686 case CONST:
687 output_address (XEXP (addr, 0));
688 fprintf (file, " ;P_O_A const");
689 break;
690 case CODE_LABEL:
691 fprintf (file, "L%d", XINT (addr, 3));
692 break;
693 default:
694 fprintf (file, " p_o_a UFO, code=%d val=0x%x",
695 (int) GET_CODE (addr), INTVAL (addr));
696 break;
697 }
698 addr_inc = 0;
699 }
700
701
702 /*
703 * Return non zero if the LS 16 bits of the given value has just one bit set,
704 * otherwise return zero. Note this function may be used to detect one
705 * bit clear by inverting the param.
706 */
707 int
708 one_bit_set_p (x)
709 int x;
710 {
711 x &= 0xffff;
712 return x && (x & (x - 1)) == 0;
713 }
714
715
716 /*
717 * Return the number of the least significant bit set, using the same
718 * convention for bit numbering as in the MIL-STD-1750 sb instruction.
719 */
720 int
721 which_bit (x)
722 int x;
723 {
724 int b = 15;
725
726 while (b > 0 && (x & 1) == 0)
727 {
728 b--;
729 x >>= 1;
730 }
731
732 return b;
733 }
734
735