* target.h (asm_out.byte_op, asm_out.aligned_op, asm_out.unaligned_op,
[official-gcc.git] / gcc / config / vax / vax.c
blobccaee768bb07a97d37b10ac01a274ce1039fa75d
1 /* Subroutines for insn-output.c for VAX.
2 Copyright (C) 1987, 1994, 1995, 1997, 1998, 1999, 2000
3 Free Software Foundation, Inc.
5 This file is part of GNU CC.
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 2, or (at your option)
10 any later version.
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.
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. */
22 #include "config.h"
23 #include "system.h"
24 #include "rtl.h"
25 #include "regs.h"
26 #include "hard-reg-set.h"
27 #include "real.h"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "function.h"
31 #include "output.h"
32 #include "insn-attr.h"
33 #include "tree.h"
34 #include "recog.h"
35 #include "expr.h"
36 #include "tm_p.h"
37 #include "target.h"
38 #include "target-def.h"
40 static int follows_p PARAMS ((rtx, rtx));
41 static void vax_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
42 #if VMS_TARGET
43 static void vms_asm_out_constructor PARAMS ((rtx, int));
44 static void vms_asm_out_destructor PARAMS ((rtx, int));
45 #endif
47 /* Initialize the GCC target structure. */
48 #undef TARGET_ASM_ALIGNED_HI_OP
49 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
51 #undef TARGET_ASM_FUNCTION_PROLOGUE
52 #define TARGET_ASM_FUNCTION_PROLOGUE vax_output_function_prologue
54 struct gcc_target targetm = TARGET_INITIALIZER;
56 /* Generate the assembly code for function entry. FILE is a stdio
57 stream to output the code to. SIZE is an int: how many units of
58 temporary storage to allocate.
60 Refer to the array `regs_ever_live' to determine which registers to
61 save; `regs_ever_live[I]' is nonzero if register number I is ever
62 used in the function. This function is responsible for knowing
63 which registers should not be saved even if used. */
65 static void
66 vax_output_function_prologue (file, size)
67 FILE * file;
68 HOST_WIDE_INT size;
70 register int regno;
71 register int mask = 0;
72 extern char call_used_regs[];
74 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
75 if (regs_ever_live[regno] && !call_used_regs[regno])
76 mask |= 1 << regno;
78 fprintf (file, "\t.word 0x%x\n", mask);
80 if (VMS_TARGET)
83 * This works for both gcc and g++. It first checks to see if
84 * the current routine is "main", which will only happen for
85 * GCC, and add the jsb if it is. If is not the case then try
86 * and see if __MAIN_NAME is part of current_function_name,
87 * which will only happen if we are running g++, and add the jsb
88 * if it is. In gcc there should never be a paren in the
89 * function name, and in g++ there is always a "(" in the
90 * function name, thus there should never be any confusion.
92 * Adjusting the stack pointer by 4 before calling C$MAIN_ARGS
93 * is required when linking with the VMS POSIX version of the C
94 * run-time library; using `subl2 $4,r0' is adequate but we use
95 * `clrl -(sp)' instead. The extra 4 bytes could be removed
96 * after the call because STARTING_FRAME_OFFSET's setting of -4
97 * will end up adding them right back again, but don't bother.
100 const char *p = current_function_name;
101 int is_main = strcmp ("main", p) == 0;
102 # define __MAIN_NAME " main("
104 while (!is_main && *p != '\0')
106 if (*p == *__MAIN_NAME
107 && strncmp (p, __MAIN_NAME, sizeof __MAIN_NAME - sizeof "") == 0)
108 is_main = 1;
109 else
110 p++;
113 if (is_main)
114 fprintf (file, "\t%s\n\t%s\n", "clrl -(sp)", "jsb _C$MAIN_ARGS");
117 size -= STARTING_FRAME_OFFSET;
118 if (size >= 64)
119 fprintf (file, "\tmovab %d(sp),sp\n", -size);
120 else if (size)
121 fprintf (file, "\tsubl2 $%d,sp\n", size);
124 /* This is like nonimmediate_operand with a restriction on the type of MEM. */
126 void
127 split_quadword_operands (operands, low, n)
128 rtx *operands, *low;
129 int n ATTRIBUTE_UNUSED;
131 int i;
132 /* Split operands. */
134 low[0] = low[1] = low[2] = 0;
135 for (i = 0; i < 3; i++)
137 if (low[i])
138 /* it's already been figured out */;
139 else if (GET_CODE (operands[i]) == MEM
140 && (GET_CODE (XEXP (operands[i], 0)) == POST_INC))
142 rtx addr = XEXP (operands[i], 0);
143 operands[i] = low[i] = gen_rtx_MEM (SImode, addr);
144 if (which_alternative == 0 && i == 0)
146 addr = XEXP (operands[i], 0);
147 operands[i+1] = low[i+1] = gen_rtx_MEM (SImode, addr);
150 else
152 low[i] = operand_subword (operands[i], 0, 0, DImode);
153 operands[i] = operand_subword (operands[i], 1, 0, DImode);
158 void
159 print_operand_address (file, addr)
160 FILE *file;
161 register rtx addr;
163 register rtx reg1, breg, ireg;
164 rtx offset;
166 retry:
167 switch (GET_CODE (addr))
169 case MEM:
170 fprintf (file, "*");
171 addr = XEXP (addr, 0);
172 goto retry;
174 case REG:
175 fprintf (file, "(%s)", reg_names[REGNO (addr)]);
176 break;
178 case PRE_DEC:
179 fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
180 break;
182 case POST_INC:
183 fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
184 break;
186 case PLUS:
187 /* There can be either two or three things added here. One must be a
188 REG. One can be either a REG or a MULT of a REG and an appropriate
189 constant, and the third can only be a constant or a MEM.
191 We get these two or three things and put the constant or MEM in
192 OFFSET, the MULT or REG in IREG, and the REG in BREG. If we have
193 a register and can't tell yet if it is a base or index register,
194 put it into REG1. */
196 reg1 = 0; ireg = 0; breg = 0; offset = 0;
198 if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
199 || GET_CODE (XEXP (addr, 0)) == MEM)
201 offset = XEXP (addr, 0);
202 addr = XEXP (addr, 1);
204 else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
205 || GET_CODE (XEXP (addr, 1)) == MEM)
207 offset = XEXP (addr, 1);
208 addr = XEXP (addr, 0);
210 else if (GET_CODE (XEXP (addr, 1)) == MULT)
212 ireg = XEXP (addr, 1);
213 addr = XEXP (addr, 0);
215 else if (GET_CODE (XEXP (addr, 0)) == MULT)
217 ireg = XEXP (addr, 0);
218 addr = XEXP (addr, 1);
220 else if (GET_CODE (XEXP (addr, 1)) == REG)
222 reg1 = XEXP (addr, 1);
223 addr = XEXP (addr, 0);
225 else if (GET_CODE (XEXP (addr, 0)) == REG)
227 reg1 = XEXP (addr, 0);
228 addr = XEXP (addr, 1);
230 else
231 abort ();
233 if (GET_CODE (addr) == REG)
235 if (reg1)
236 ireg = addr;
237 else
238 reg1 = addr;
240 else if (GET_CODE (addr) == MULT)
241 ireg = addr;
242 else if (GET_CODE (addr) == PLUS)
244 if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
245 || GET_CODE (XEXP (addr, 0)) == MEM)
247 if (offset)
249 if (GET_CODE (offset) == CONST_INT)
250 offset = plus_constant (XEXP (addr, 0), INTVAL (offset));
251 else if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
252 offset = plus_constant (offset, INTVAL (XEXP (addr, 0)));
253 else
254 abort ();
256 offset = XEXP (addr, 0);
258 else if (GET_CODE (XEXP (addr, 0)) == REG)
260 if (reg1)
261 ireg = reg1, breg = XEXP (addr, 0), reg1 = 0;
262 else
263 reg1 = XEXP (addr, 0);
265 else if (GET_CODE (XEXP (addr, 0)) == MULT)
267 if (ireg)
268 abort ();
269 ireg = XEXP (addr, 0);
271 else
272 abort ();
274 if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
275 || GET_CODE (XEXP (addr, 1)) == MEM)
277 if (offset)
279 if (GET_CODE (offset) == CONST_INT)
280 offset = plus_constant (XEXP (addr, 1), INTVAL (offset));
281 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
282 offset = plus_constant (offset, INTVAL (XEXP (addr, 1)));
283 else
284 abort ();
286 offset = XEXP (addr, 1);
288 else if (GET_CODE (XEXP (addr, 1)) == REG)
290 if (reg1)
291 ireg = reg1, breg = XEXP (addr, 1), reg1 = 0;
292 else
293 reg1 = XEXP (addr, 1);
295 else if (GET_CODE (XEXP (addr, 1)) == MULT)
297 if (ireg)
298 abort ();
299 ireg = XEXP (addr, 1);
301 else
302 abort ();
304 else
305 abort ();
307 /* If REG1 is non-zero, figure out if it is a base or index register. */
308 if (reg1)
310 if (breg != 0 || (offset && GET_CODE (offset) == MEM))
312 if (ireg)
313 abort ();
314 ireg = reg1;
316 else
317 breg = reg1;
320 if (offset != 0)
321 output_address (offset);
323 if (breg != 0)
324 fprintf (file, "(%s)", reg_names[REGNO (breg)]);
326 if (ireg != 0)
328 if (GET_CODE (ireg) == MULT)
329 ireg = XEXP (ireg, 0);
330 if (GET_CODE (ireg) != REG)
331 abort ();
332 fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
334 break;
336 default:
337 output_addr_const (file, addr);
341 const char *
342 rev_cond_name (op)
343 rtx op;
345 switch (GET_CODE (op))
347 case EQ:
348 return "neq";
349 case NE:
350 return "eql";
351 case LT:
352 return "geq";
353 case LE:
354 return "gtr";
355 case GT:
356 return "leq";
357 case GE:
358 return "lss";
359 case LTU:
360 return "gequ";
361 case LEU:
362 return "gtru";
363 case GTU:
364 return "lequ";
365 case GEU:
366 return "lssu";
368 default:
369 abort ();
374 vax_float_literal(c)
375 register rtx c;
377 register enum machine_mode mode;
378 #if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
379 int i;
380 union {double d; int i[2];} val;
381 #endif
383 if (GET_CODE (c) != CONST_DOUBLE)
384 return 0;
386 mode = GET_MODE (c);
388 if (c == const_tiny_rtx[(int) mode][0]
389 || c == const_tiny_rtx[(int) mode][1]
390 || c == const_tiny_rtx[(int) mode][2])
391 return 1;
393 #if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
395 val.i[0] = CONST_DOUBLE_LOW (c);
396 val.i[1] = CONST_DOUBLE_HIGH (c);
398 for (i = 0; i < 7; i ++)
399 if (val.d == 1 << i || val.d == 1 / (1 << i))
400 return 1;
401 #endif
402 return 0;
406 /* Return the cost in cycles of a memory address, relative to register
407 indirect.
409 Each of the following adds the indicated number of cycles:
411 1 - symbolic address
412 1 - pre-decrement
413 1 - indexing and/or offset(register)
414 2 - indirect */
418 vax_address_cost (addr)
419 register rtx addr;
421 int reg = 0, indexed = 0, indir = 0, offset = 0, predec = 0;
422 rtx plus_op0 = 0, plus_op1 = 0;
423 restart:
424 switch (GET_CODE (addr))
426 case PRE_DEC:
427 predec = 1;
428 case REG:
429 case SUBREG:
430 case POST_INC:
431 reg = 1;
432 break;
433 case MULT:
434 indexed = 1; /* 2 on VAX 2 */
435 break;
436 case CONST_INT:
437 /* byte offsets cost nothing (on a VAX 2, they cost 1 cycle) */
438 if (offset == 0)
439 offset = (unsigned)(INTVAL(addr)+128) > 256;
440 break;
441 case CONST:
442 case SYMBOL_REF:
443 offset = 1; /* 2 on VAX 2 */
444 break;
445 case LABEL_REF: /* this is probably a byte offset from the pc */
446 if (offset == 0)
447 offset = 1;
448 break;
449 case PLUS:
450 if (plus_op0)
451 plus_op1 = XEXP (addr, 0);
452 else
453 plus_op0 = XEXP (addr, 0);
454 addr = XEXP (addr, 1);
455 goto restart;
456 case MEM:
457 indir = 2; /* 3 on VAX 2 */
458 addr = XEXP (addr, 0);
459 goto restart;
460 default:
461 break;
464 /* Up to 3 things can be added in an address. They are stored in
465 plus_op0, plus_op1, and addr. */
467 if (plus_op0)
469 addr = plus_op0;
470 plus_op0 = 0;
471 goto restart;
473 if (plus_op1)
475 addr = plus_op1;
476 plus_op1 = 0;
477 goto restart;
479 /* Indexing and register+offset can both be used (except on a VAX 2)
480 without increasing execution time over either one alone. */
481 if (reg && indexed && offset)
482 return reg + indir + offset + predec;
483 return reg + indexed + indir + offset + predec;
487 /* Cost of an expression on a VAX. This version has costs tuned for the
488 CVAX chip (found in the VAX 3 series) with comments for variations on
489 other models. */
492 vax_rtx_cost (x)
493 register rtx x;
495 register enum rtx_code code = GET_CODE (x);
496 enum machine_mode mode = GET_MODE (x);
497 register int c;
498 int i = 0; /* may be modified in switch */
499 const char *fmt = GET_RTX_FORMAT (code); /* may be modified in switch */
501 switch (code)
503 case POST_INC:
504 return 2;
505 case PRE_DEC:
506 return 3;
507 case MULT:
508 switch (mode)
510 case DFmode:
511 c = 16; /* 4 on VAX 9000 */
512 break;
513 case SFmode:
514 c = 9; /* 4 on VAX 9000, 12 on VAX 2 */
515 break;
516 case DImode:
517 c = 16; /* 6 on VAX 9000, 28 on VAX 2 */
518 break;
519 case SImode:
520 case HImode:
521 case QImode:
522 c = 10; /* 3-4 on VAX 9000, 20-28 on VAX 2 */
523 break;
524 default:
525 abort ();
527 break;
528 case UDIV:
529 c = 17;
530 break;
531 case DIV:
532 if (mode == DImode)
533 c = 30; /* highly variable */
534 else if (mode == DFmode)
535 /* divide takes 28 cycles if the result is not zero, 13 otherwise */
536 c = 24;
537 else
538 c = 11; /* 25 on VAX 2 */
539 break;
540 case MOD:
541 c = 23;
542 break;
543 case UMOD:
544 c = 29;
545 break;
546 case FLOAT:
547 c = 6 + (mode == DFmode) + (GET_MODE (XEXP (x, 0)) != SImode);
548 /* 4 on VAX 9000 */
549 break;
550 case FIX:
551 c = 7; /* 17 on VAX 2 */
552 break;
553 case ASHIFT:
554 case LSHIFTRT:
555 case ASHIFTRT:
556 if (mode == DImode)
557 c = 12;
558 else
559 c = 10; /* 6 on VAX 9000 */
560 break;
561 case ROTATE:
562 case ROTATERT:
563 c = 6; /* 5 on VAX 2, 4 on VAX 9000 */
564 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
565 fmt = "e"; /* all constant rotate counts are short */
566 break;
567 case PLUS:
568 /* Check for small negative integer operand: subl2 can be used with
569 a short positive constant instead. */
570 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
571 if ((unsigned)(INTVAL (XEXP (x, 1)) + 63) < 127)
572 fmt = "e";
573 case MINUS:
574 c = (mode == DFmode) ? 13 : 8; /* 6/8 on VAX 9000, 16/15 on VAX 2 */
575 case IOR:
576 case XOR:
577 c = 3;
578 break;
579 case AND:
580 /* AND is special because the first operand is complemented. */
581 c = 3;
582 if (GET_CODE (XEXP (x, 0)) == CONST_INT)
584 if ((unsigned)~INTVAL (XEXP (x, 0)) > 63)
585 c = 4;
586 fmt = "e";
587 i = 1;
589 break;
590 case NEG:
591 if (mode == DFmode)
592 return 9;
593 else if (mode == SFmode)
594 return 6;
595 else if (mode == DImode)
596 return 4;
597 case NOT:
598 return 2;
599 case ZERO_EXTRACT:
600 case SIGN_EXTRACT:
601 c = 15;
602 break;
603 case MEM:
604 if (mode == DImode || mode == DFmode)
605 c = 5; /* 7 on VAX 2 */
606 else
607 c = 3; /* 4 on VAX 2 */
608 x = XEXP (x, 0);
609 if (GET_CODE (x) == REG || GET_CODE (x) == POST_INC)
610 return c;
611 return c + vax_address_cost (x);
612 default:
613 c = 3;
614 break;
618 /* Now look inside the expression. Operands which are not registers or
619 short constants add to the cost.
621 FMT and I may have been adjusted in the switch above for instructions
622 which require special handling */
624 while (*fmt++ == 'e')
626 register rtx op = XEXP (x, i++);
627 code = GET_CODE (op);
629 /* A NOT is likely to be found as the first operand of an AND
630 (in which case the relevant cost is of the operand inside
631 the not) and not likely to be found anywhere else. */
632 if (code == NOT)
633 op = XEXP (op, 0), code = GET_CODE (op);
635 switch (code)
637 case CONST_INT:
638 if ((unsigned)INTVAL (op) > 63 && GET_MODE (x) != QImode)
639 c += 1; /* 2 on VAX 2 */
640 break;
641 case CONST:
642 case LABEL_REF:
643 case SYMBOL_REF:
644 c += 1; /* 2 on VAX 2 */
645 break;
646 case CONST_DOUBLE:
647 if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT)
649 /* Registers are faster than floating point constants -- even
650 those constants which can be encoded in a single byte. */
651 if (vax_float_literal (op))
652 c++;
653 else
654 c += (GET_MODE (x) == DFmode) ? 3 : 2;
656 else
658 if (CONST_DOUBLE_HIGH (op) != 0
659 || (unsigned)CONST_DOUBLE_LOW (op) > 63)
660 c += 2;
662 break;
663 case MEM:
664 c += 1; /* 2 on VAX 2 */
665 if (GET_CODE (XEXP (op, 0)) != REG)
666 c += vax_address_cost (XEXP (op, 0));
667 break;
668 case REG:
669 case SUBREG:
670 break;
671 default:
672 c += 1;
673 break;
676 return c;
679 /* Check a `double' value for validity for a particular machine mode. */
681 static const char *const float_strings[] =
683 "1.70141173319264430e+38", /* 2^127 (2^24 - 1) / 2^24 */
684 "-1.70141173319264430e+38",
685 "2.93873587705571877e-39", /* 2^-128 */
686 "-2.93873587705571877e-39"
689 static REAL_VALUE_TYPE float_values[4];
691 static int inited_float_values = 0;
695 check_float_value (mode, d, overflow)
696 enum machine_mode mode;
697 REAL_VALUE_TYPE *d;
698 int overflow;
700 if (inited_float_values == 0)
702 int i;
703 for (i = 0; i < 4; i++)
705 float_values[i] = REAL_VALUE_ATOF (float_strings[i], DFmode);
708 inited_float_values = 1;
711 if (overflow)
713 memcpy (d, &float_values[0], sizeof (REAL_VALUE_TYPE));
714 return 1;
717 if ((mode) == SFmode)
719 REAL_VALUE_TYPE r;
720 memcpy (&r, d, sizeof (REAL_VALUE_TYPE));
721 if (REAL_VALUES_LESS (float_values[0], r))
723 memcpy (d, &float_values[0], sizeof (REAL_VALUE_TYPE));
724 return 1;
726 else if (REAL_VALUES_LESS (r, float_values[1]))
728 memcpy (d, &float_values[1], sizeof (REAL_VALUE_TYPE));
729 return 1;
731 else if (REAL_VALUES_LESS (dconst0, r)
732 && REAL_VALUES_LESS (r, float_values[2]))
734 memcpy (d, &dconst0, sizeof (REAL_VALUE_TYPE));
735 return 1;
737 else if (REAL_VALUES_LESS (r, dconst0)
738 && REAL_VALUES_LESS (float_values[3], r))
740 memcpy (d, &dconst0, sizeof (REAL_VALUE_TYPE));
741 return 1;
745 return 0;
748 #if VMS_TARGET
749 /* Additional support code for VMS target. */
751 /* Linked list of all externals that are to be emitted when optimizing
752 for the global pointer if they haven't been declared by the end of
753 the program with an appropriate .comm or initialization. */
755 static
756 struct extern_list {
757 struct extern_list *next; /* next external */
758 const char *name; /* name of the external */
759 int size; /* external's actual size */
760 int in_const; /* section type flag */
761 } *extern_head = 0, *pending_head = 0;
763 /* Check whether NAME is already on the external definition list. If not,
764 add it to either that list or the pending definition list. */
766 void
767 vms_check_external (decl, name, pending)
768 tree decl;
769 const char *name;
770 int pending;
772 register struct extern_list *p, *p0;
774 for (p = extern_head; p; p = p->next)
775 if (!strcmp (p->name, name))
776 return;
778 for (p = pending_head, p0 = 0; p; p0 = p, p = p->next)
779 if (!strcmp (p->name, name))
781 if (pending)
782 return;
784 /* Was pending, but has now been defined; move it to other list. */
785 if (p == pending_head)
786 pending_head = p->next;
787 else
788 p0->next = p->next;
789 p->next = extern_head;
790 extern_head = p;
791 return;
794 /* Not previously seen; create a new list entry. */
795 p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list));
796 p->name = name;
798 if (pending)
800 /* Save the size and section type and link to `pending' list. */
801 p->size = (DECL_SIZE (decl) == 0) ? 0 :
802 TREE_INT_CST_LOW (size_binop (CEIL_DIV_EXPR, DECL_SIZE (decl),
803 size_int (BITS_PER_UNIT)));
804 p->in_const = (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl));
806 p->next = pending_head;
807 pending_head = p;
809 else
811 /* Size and section type don't matter; link to `declared' list. */
812 p->size = p->in_const = 0; /* arbitrary init */
814 p->next = extern_head;
815 extern_head = p;
817 return;
820 void
821 vms_flush_pending_externals (file)
822 FILE *file;
824 register struct extern_list *p;
826 while (pending_head)
828 /* Move next pending declaration to the "done" list. */
829 p = pending_head;
830 pending_head = p->next;
831 p->next = extern_head;
832 extern_head = p;
834 /* Now output the actual declaration. */
835 if (p->in_const)
836 const_section ();
837 else
838 data_section ();
839 fputs (".comm ", file);
840 assemble_name (file, p->name);
841 fprintf (file, ",%d\n", p->size);
845 static void
846 vms_asm_out_constructor (symbol, priority)
847 rtx symbol;
848 int priority ATTRIBUTE_UNUSED;
850 fprintf (asm_out_file,".globl $$PsectAttributes_NOOVR$$__gxx_init_1\n");
851 data_section();
852 fprintf (asm_out_file,"$$PsectAttributes_NOOVR$$__gxx_init_1:\n\t.long\t");
853 assemble_name (asm_out_file, XSTR (symbol, 0));
854 fputc ('\n', asm_out_file);
857 static void
858 vms_asm_out_destructor (symbol, priority)
859 rtx symbol;
860 int priority ATTRIBUTE_UNUSED;
862 fprintf (asm_out_file,".globl $$PsectAttributes_NOOVR$$__gxx_clean_1\n");
863 data_section();
864 fprintf (asm_out_file,"$$PsectAttributes_NOOVR$$__gxx_clean_1:\n\t.long\t");
865 assemble_name (asm_out_file, XSTR (symbol, 0));
866 fputc ('\n', asm_out_file);
868 #endif /* VMS_TARGET */
870 /* Additional support code for VMS host. */
871 /* ??? This should really be in libiberty; vax.c is a target file. */
872 #ifdef QSORT_WORKAROUND
874 Do not use VAXCRTL's qsort() due to a severe bug: once you've
875 sorted something which has a size that's an exact multiple of 4
876 and is longword aligned, you cannot safely sort anything which
877 is either not a multiple of 4 in size or not longword aligned.
878 A static "move-by-longword" optimization flag inside qsort() is
879 never reset. This is known to affect VMS V4.6 through VMS V5.5-1,
880 and was finally fixed in VMS V5.5-2.
882 In this work-around an insertion sort is used for simplicity.
883 The qsort code from glibc should probably be used instead.
885 void
886 not_qsort (array, count, size, compare)
887 void *array;
888 unsigned count, size;
889 int (*compare)();
892 if (size == sizeof (short))
894 register int i;
895 register short *next, *prev;
896 short tmp, *base = array;
898 for (next = base, i = count - 1; i > 0; i--)
900 prev = next++;
901 if ((*compare)(next, prev) < 0)
903 tmp = *next;
904 do *(prev + 1) = *prev;
905 while (--prev >= base ? (*compare)(&tmp, prev) < 0 : 0);
906 *(prev + 1) = tmp;
910 else if (size == sizeof (long))
912 register int i;
913 register long *next, *prev;
914 long tmp, *base = array;
916 for (next = base, i = count - 1; i > 0; i--)
918 prev = next++;
919 if ((*compare)(next, prev) < 0)
921 tmp = *next;
922 do *(prev + 1) = *prev;
923 while (--prev >= base ? (*compare)(&tmp, prev) < 0 : 0);
924 *(prev + 1) = tmp;
928 else /* arbitrary size */
930 register int i;
931 register char *next, *prev, *tmp = alloca (size), *base = array;
933 for (next = base, i = count - 1; i > 0; i--)
934 { /* count-1 forward iterations */
935 prev = next, next += size; /* increment front pointer */
936 if ((*compare)(next, prev) < 0)
937 { /* found element out of order; move others up then re-insert */
938 memcpy (tmp, next, size); /* save smaller element */
939 do { memcpy (prev + size, prev, size); /* move larger elem. up */
940 prev -= size; /* decrement back pointer */
941 } while (prev >= base ? (*compare)(tmp, prev) < 0 : 0);
942 memcpy (prev + size, tmp, size); /* restore small element */
945 #ifdef USE_C_ALLOCA
946 alloca (0);
947 #endif
950 return;
952 #endif /* QSORT_WORKAROUND */
954 /* Return 1 if insn A follows B. */
956 static int
957 follows_p (a, b)
958 rtx a, b;
960 register rtx p;
962 for (p = a; p != b; p = NEXT_INSN (p))
963 if (! p)
964 return 1;
966 return 0;
969 /* Returns 1 if we know operand OP was 0 before INSN. */
972 reg_was_0_p (insn, op)
973 rtx insn, op;
975 rtx link;
977 return ((link = find_reg_note (insn, REG_WAS_0, 0))
978 /* Make sure the insn that stored the 0 is still present
979 and doesn't follow INSN in the insn sequence. */
980 && ! INSN_DELETED_P (XEXP (link, 0))
981 && GET_CODE (XEXP (link, 0)) != NOTE
982 && ! follows_p (XEXP (link, 0), insn)
983 /* Make sure cross jumping didn't happen here. */
984 && no_labels_between_p (XEXP (link, 0), insn)
985 /* Make sure the reg hasn't been clobbered. */
986 && ! reg_set_between_p (op, XEXP (link, 0), insn));