]> gcc.gnu.org Git - gcc.git/blob - gcc/config/vax/vax.c
real.c (struct real_format): Move to real.h.
[gcc.git] / gcc / config / vax / vax.c
1 /* Subroutines for insn-output.c for VAX.
2 Copyright (C) 1987, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002
3 Free Software Foundation, Inc.
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 2, 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 #include "config.h"
23 #include "system.h"
24 #include "rtl.h"
25 #include "tree.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "real.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "function.h"
32 #include "output.h"
33 #include "insn-attr.h"
34 #include "recog.h"
35 #include "expr.h"
36 #include "flags.h"
37 #include "tm_p.h"
38 #include "target.h"
39 #include "target-def.h"
40
41 static int follows_p PARAMS ((rtx, rtx));
42 static void vax_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
43 #if VMS_TARGET
44 static void vms_asm_out_constructor PARAMS ((rtx, int));
45 static void vms_asm_out_destructor PARAMS ((rtx, int));
46 static void vms_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT));
47 static void vms_encode_section_info PARAMS ((tree, int));
48 static void vms_globalize_label PARAMS ((FILE *, const char *));
49 #endif
50 \f
51 /* Initialize the GCC target structure. */
52 #undef TARGET_ASM_ALIGNED_HI_OP
53 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
54
55 #undef TARGET_ASM_FUNCTION_PROLOGUE
56 #define TARGET_ASM_FUNCTION_PROLOGUE vax_output_function_prologue
57
58 #if VMS_TARGET
59 #undef TARGET_ASM_SELECT_SECTION
60 #define TARGET_ASM_SELECT_SECTION vms_select_section
61 #undef TARGET_ENCODE_SECTION_INFO
62 #define TARGET_ENCODE_SECTION_INFO vms_encode_section_info
63 #undef TARGET_ASM_GLOBALIZE_LABEL
64 #define TARGET_ASM_GLOBALIZE_LABEL vms_globalize_label
65 #endif
66
67 struct gcc_target targetm = TARGET_INITIALIZER;
68 \f
69 /* Set global variables as needed for the options enabled. */
70
71 void
72 override_options ()
73 {
74 /* We're VAX floating point, not IEEE floating point. */
75 memset (real_format_for_mode, 0, sizeof real_format_for_mode);
76 real_format_for_mode[SFmode - QFmode] = &vax_f_format;
77 real_format_for_mode[DFmode - QFmode]
78 = (TARGET_G_FLOAT ? &vax_g_format : &vax_d_format);
79 }
80
81 /* Generate the assembly code for function entry. FILE is a stdio
82 stream to output the code to. SIZE is an int: how many units of
83 temporary storage to allocate.
84
85 Refer to the array `regs_ever_live' to determine which registers to
86 save; `regs_ever_live[I]' is nonzero if register number I is ever
87 used in the function. This function is responsible for knowing
88 which registers should not be saved even if used. */
89
90 static void
91 vax_output_function_prologue (file, size)
92 FILE * file;
93 HOST_WIDE_INT size;
94 {
95 register int regno;
96 register int mask = 0;
97
98 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
99 if (regs_ever_live[regno] && !call_used_regs[regno])
100 mask |= 1 << regno;
101
102 fprintf (file, "\t.word 0x%x\n", mask);
103
104 if (VMS_TARGET)
105 {
106 /*
107 * This works for both gcc and g++. It first checks to see if
108 * the current routine is "main", which will only happen for
109 * GCC, and add the jsb if it is. If is not the case then try
110 * and see if __MAIN_NAME is part of current_function_name,
111 * which will only happen if we are running g++, and add the jsb
112 * if it is. In gcc there should never be a paren in the
113 * function name, and in g++ there is always a "(" in the
114 * function name, thus there should never be any confusion.
115 *
116 * Adjusting the stack pointer by 4 before calling C$MAIN_ARGS
117 * is required when linking with the VMS POSIX version of the C
118 * run-time library; using `subl2 $4,r0' is adequate but we use
119 * `clrl -(sp)' instead. The extra 4 bytes could be removed
120 * after the call because STARTING_FRAME_OFFSET's setting of -4
121 * will end up adding them right back again, but don't bother.
122 */
123
124 const char *p = current_function_name;
125 int is_main = strcmp ("main", p) == 0;
126 # define __MAIN_NAME " main("
127
128 while (!is_main && *p != '\0')
129 {
130 if (*p == *__MAIN_NAME
131 && strncmp (p, __MAIN_NAME, sizeof __MAIN_NAME - sizeof "") == 0)
132 is_main = 1;
133 else
134 p++;
135 }
136
137 if (is_main)
138 fprintf (file, "\tclrl -(%ssp)\n\tjsb _C$MAIN_ARGS\n",
139 REGISTER_PREFIX);
140 }
141
142 size -= STARTING_FRAME_OFFSET;
143 if (size >= 64)
144 fprintf (file, "\tmovab %d(%ssp),%ssp\n", -size, REGISTER_PREFIX,
145 REGISTER_PREFIX);
146 else if (size)
147 fprintf (file, "\tsubl2 $%d,%ssp\n", size, REGISTER_PREFIX);
148 }
149
150 /* This is like nonimmediate_operand with a restriction on the type of MEM. */
151
152 void
153 split_quadword_operands (operands, low, n)
154 rtx *operands, *low;
155 int n ATTRIBUTE_UNUSED;
156 {
157 int i;
158 /* Split operands. */
159
160 low[0] = low[1] = low[2] = 0;
161 for (i = 0; i < 3; i++)
162 {
163 if (low[i])
164 /* it's already been figured out */;
165 else if (GET_CODE (operands[i]) == MEM
166 && (GET_CODE (XEXP (operands[i], 0)) == POST_INC))
167 {
168 rtx addr = XEXP (operands[i], 0);
169 operands[i] = low[i] = gen_rtx_MEM (SImode, addr);
170 if (which_alternative == 0 && i == 0)
171 {
172 addr = XEXP (operands[i], 0);
173 operands[i+1] = low[i+1] = gen_rtx_MEM (SImode, addr);
174 }
175 }
176 else
177 {
178 low[i] = operand_subword (operands[i], 0, 0, DImode);
179 operands[i] = operand_subword (operands[i], 1, 0, DImode);
180 }
181 }
182 }
183 \f
184 void
185 print_operand_address (file, addr)
186 FILE *file;
187 register rtx addr;
188 {
189 register rtx reg1, breg, ireg;
190 rtx offset;
191
192 retry:
193 switch (GET_CODE (addr))
194 {
195 case MEM:
196 fprintf (file, "*");
197 addr = XEXP (addr, 0);
198 goto retry;
199
200 case REG:
201 fprintf (file, "(%s)", reg_names[REGNO (addr)]);
202 break;
203
204 case PRE_DEC:
205 fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
206 break;
207
208 case POST_INC:
209 fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
210 break;
211
212 case PLUS:
213 /* There can be either two or three things added here. One must be a
214 REG. One can be either a REG or a MULT of a REG and an appropriate
215 constant, and the third can only be a constant or a MEM.
216
217 We get these two or three things and put the constant or MEM in
218 OFFSET, the MULT or REG in IREG, and the REG in BREG. If we have
219 a register and can't tell yet if it is a base or index register,
220 put it into REG1. */
221
222 reg1 = 0; ireg = 0; breg = 0; offset = 0;
223
224 if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
225 || GET_CODE (XEXP (addr, 0)) == MEM)
226 {
227 offset = XEXP (addr, 0);
228 addr = XEXP (addr, 1);
229 }
230 else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
231 || GET_CODE (XEXP (addr, 1)) == MEM)
232 {
233 offset = XEXP (addr, 1);
234 addr = XEXP (addr, 0);
235 }
236 else if (GET_CODE (XEXP (addr, 1)) == MULT)
237 {
238 ireg = XEXP (addr, 1);
239 addr = XEXP (addr, 0);
240 }
241 else if (GET_CODE (XEXP (addr, 0)) == MULT)
242 {
243 ireg = XEXP (addr, 0);
244 addr = XEXP (addr, 1);
245 }
246 else if (GET_CODE (XEXP (addr, 1)) == REG)
247 {
248 reg1 = XEXP (addr, 1);
249 addr = XEXP (addr, 0);
250 }
251 else if (GET_CODE (XEXP (addr, 0)) == REG)
252 {
253 reg1 = XEXP (addr, 0);
254 addr = XEXP (addr, 1);
255 }
256 else
257 abort ();
258
259 if (GET_CODE (addr) == REG)
260 {
261 if (reg1)
262 ireg = addr;
263 else
264 reg1 = addr;
265 }
266 else if (GET_CODE (addr) == MULT)
267 ireg = addr;
268 else if (GET_CODE (addr) == PLUS)
269 {
270 if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
271 || GET_CODE (XEXP (addr, 0)) == MEM)
272 {
273 if (offset)
274 {
275 if (GET_CODE (offset) == CONST_INT)
276 offset = plus_constant (XEXP (addr, 0), INTVAL (offset));
277 else if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
278 offset = plus_constant (offset, INTVAL (XEXP (addr, 0)));
279 else
280 abort ();
281 }
282 offset = XEXP (addr, 0);
283 }
284 else if (GET_CODE (XEXP (addr, 0)) == REG)
285 {
286 if (reg1)
287 ireg = reg1, breg = XEXP (addr, 0), reg1 = 0;
288 else
289 reg1 = XEXP (addr, 0);
290 }
291 else if (GET_CODE (XEXP (addr, 0)) == MULT)
292 {
293 if (ireg)
294 abort ();
295 ireg = XEXP (addr, 0);
296 }
297 else
298 abort ();
299
300 if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
301 || GET_CODE (XEXP (addr, 1)) == MEM)
302 {
303 if (offset)
304 {
305 if (GET_CODE (offset) == CONST_INT)
306 offset = plus_constant (XEXP (addr, 1), INTVAL (offset));
307 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
308 offset = plus_constant (offset, INTVAL (XEXP (addr, 1)));
309 else
310 abort ();
311 }
312 offset = XEXP (addr, 1);
313 }
314 else if (GET_CODE (XEXP (addr, 1)) == REG)
315 {
316 if (reg1)
317 ireg = reg1, breg = XEXP (addr, 1), reg1 = 0;
318 else
319 reg1 = XEXP (addr, 1);
320 }
321 else if (GET_CODE (XEXP (addr, 1)) == MULT)
322 {
323 if (ireg)
324 abort ();
325 ireg = XEXP (addr, 1);
326 }
327 else
328 abort ();
329 }
330 else
331 abort ();
332
333 /* If REG1 is nonzero, figure out if it is a base or index register. */
334 if (reg1)
335 {
336 if (breg != 0 || (offset && GET_CODE (offset) == MEM))
337 {
338 if (ireg)
339 abort ();
340 ireg = reg1;
341 }
342 else
343 breg = reg1;
344 }
345
346 if (offset != 0)
347 output_address (offset);
348
349 if (breg != 0)
350 fprintf (file, "(%s)", reg_names[REGNO (breg)]);
351
352 if (ireg != 0)
353 {
354 if (GET_CODE (ireg) == MULT)
355 ireg = XEXP (ireg, 0);
356 if (GET_CODE (ireg) != REG)
357 abort ();
358 fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
359 }
360 break;
361
362 default:
363 output_addr_const (file, addr);
364 }
365 }
366 \f
367 const char *
368 rev_cond_name (op)
369 rtx op;
370 {
371 switch (GET_CODE (op))
372 {
373 case EQ:
374 return "neq";
375 case NE:
376 return "eql";
377 case LT:
378 return "geq";
379 case LE:
380 return "gtr";
381 case GT:
382 return "leq";
383 case GE:
384 return "lss";
385 case LTU:
386 return "gequ";
387 case LEU:
388 return "gtru";
389 case GTU:
390 return "lequ";
391 case GEU:
392 return "lssu";
393
394 default:
395 abort ();
396 }
397 }
398
399 int
400 vax_float_literal(c)
401 register rtx c;
402 {
403 register enum machine_mode mode;
404 REAL_VALUE_TYPE r, s;
405 int i;
406
407 if (GET_CODE (c) != CONST_DOUBLE)
408 return 0;
409
410 mode = GET_MODE (c);
411
412 if (c == const_tiny_rtx[(int) mode][0]
413 || c == const_tiny_rtx[(int) mode][1]
414 || c == const_tiny_rtx[(int) mode][2])
415 return 1;
416
417 REAL_VALUE_FROM_CONST_DOUBLE (r, c);
418
419 for (i = 0; i < 7; i++)
420 {
421 int x = 1 << i;
422 REAL_VALUE_FROM_INT (s, x, 0, mode);
423
424 if (REAL_VALUES_EQUAL (r, s))
425 return 1;
426 if (!exact_real_inverse (mode, &s))
427 abort ();
428 if (REAL_VALUES_EQUAL (r, s))
429 return 1;
430 }
431 return 0;
432 }
433
434
435 /* Return the cost in cycles of a memory address, relative to register
436 indirect.
437
438 Each of the following adds the indicated number of cycles:
439
440 1 - symbolic address
441 1 - pre-decrement
442 1 - indexing and/or offset(register)
443 2 - indirect */
444
445
446 int
447 vax_address_cost (addr)
448 register rtx addr;
449 {
450 int reg = 0, indexed = 0, indir = 0, offset = 0, predec = 0;
451 rtx plus_op0 = 0, plus_op1 = 0;
452 restart:
453 switch (GET_CODE (addr))
454 {
455 case PRE_DEC:
456 predec = 1;
457 case REG:
458 case SUBREG:
459 case POST_INC:
460 reg = 1;
461 break;
462 case MULT:
463 indexed = 1; /* 2 on VAX 2 */
464 break;
465 case CONST_INT:
466 /* byte offsets cost nothing (on a VAX 2, they cost 1 cycle) */
467 if (offset == 0)
468 offset = (unsigned)(INTVAL(addr)+128) > 256;
469 break;
470 case CONST:
471 case SYMBOL_REF:
472 offset = 1; /* 2 on VAX 2 */
473 break;
474 case LABEL_REF: /* this is probably a byte offset from the pc */
475 if (offset == 0)
476 offset = 1;
477 break;
478 case PLUS:
479 if (plus_op0)
480 plus_op1 = XEXP (addr, 0);
481 else
482 plus_op0 = XEXP (addr, 0);
483 addr = XEXP (addr, 1);
484 goto restart;
485 case MEM:
486 indir = 2; /* 3 on VAX 2 */
487 addr = XEXP (addr, 0);
488 goto restart;
489 default:
490 break;
491 }
492
493 /* Up to 3 things can be added in an address. They are stored in
494 plus_op0, plus_op1, and addr. */
495
496 if (plus_op0)
497 {
498 addr = plus_op0;
499 plus_op0 = 0;
500 goto restart;
501 }
502 if (plus_op1)
503 {
504 addr = plus_op1;
505 plus_op1 = 0;
506 goto restart;
507 }
508 /* Indexing and register+offset can both be used (except on a VAX 2)
509 without increasing execution time over either one alone. */
510 if (reg && indexed && offset)
511 return reg + indir + offset + predec;
512 return reg + indexed + indir + offset + predec;
513 }
514
515
516 /* Cost of an expression on a VAX. This version has costs tuned for the
517 CVAX chip (found in the VAX 3 series) with comments for variations on
518 other models. */
519
520 int
521 vax_rtx_cost (x)
522 register rtx x;
523 {
524 register enum rtx_code code = GET_CODE (x);
525 enum machine_mode mode = GET_MODE (x);
526 register int c;
527 int i = 0; /* may be modified in switch */
528 const char *fmt = GET_RTX_FORMAT (code); /* may be modified in switch */
529
530 switch (code)
531 {
532 case POST_INC:
533 return 2;
534 case PRE_DEC:
535 return 3;
536 case MULT:
537 switch (mode)
538 {
539 case DFmode:
540 c = 16; /* 4 on VAX 9000 */
541 break;
542 case SFmode:
543 c = 9; /* 4 on VAX 9000, 12 on VAX 2 */
544 break;
545 case DImode:
546 c = 16; /* 6 on VAX 9000, 28 on VAX 2 */
547 break;
548 case SImode:
549 case HImode:
550 case QImode:
551 c = 10; /* 3-4 on VAX 9000, 20-28 on VAX 2 */
552 break;
553 default:
554 return MAX_COST; /* Mode is not supported. */
555 }
556 break;
557 case UDIV:
558 if (mode != SImode)
559 return MAX_COST; /* Mode is not supported. */
560 c = 17;
561 break;
562 case DIV:
563 if (mode == DImode)
564 c = 30; /* highly variable */
565 else if (mode == DFmode)
566 /* divide takes 28 cycles if the result is not zero, 13 otherwise */
567 c = 24;
568 else
569 c = 11; /* 25 on VAX 2 */
570 break;
571 case MOD:
572 c = 23;
573 break;
574 case UMOD:
575 if (mode != SImode)
576 return MAX_COST; /* Mode is not supported. */
577 c = 29;
578 break;
579 case FLOAT:
580 c = 6 + (mode == DFmode) + (GET_MODE (XEXP (x, 0)) != SImode);
581 /* 4 on VAX 9000 */
582 break;
583 case FIX:
584 c = 7; /* 17 on VAX 2 */
585 break;
586 case ASHIFT:
587 case LSHIFTRT:
588 case ASHIFTRT:
589 if (mode == DImode)
590 c = 12;
591 else
592 c = 10; /* 6 on VAX 9000 */
593 break;
594 case ROTATE:
595 case ROTATERT:
596 c = 6; /* 5 on VAX 2, 4 on VAX 9000 */
597 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
598 fmt = "e"; /* all constant rotate counts are short */
599 break;
600 case PLUS:
601 /* Check for small negative integer operand: subl2 can be used with
602 a short positive constant instead. */
603 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
604 if ((unsigned)(INTVAL (XEXP (x, 1)) + 63) < 127)
605 fmt = "e";
606 case MINUS:
607 c = (mode == DFmode) ? 13 : 8; /* 6/8 on VAX 9000, 16/15 on VAX 2 */
608 case IOR:
609 case XOR:
610 c = 3;
611 break;
612 case AND:
613 /* AND is special because the first operand is complemented. */
614 c = 3;
615 if (GET_CODE (XEXP (x, 0)) == CONST_INT)
616 {
617 if ((unsigned)~INTVAL (XEXP (x, 0)) > 63)
618 c = 4;
619 fmt = "e";
620 i = 1;
621 }
622 break;
623 case NEG:
624 if (mode == DFmode)
625 return 9;
626 else if (mode == SFmode)
627 return 6;
628 else if (mode == DImode)
629 return 4;
630 case NOT:
631 return 2;
632 case ZERO_EXTRACT:
633 case SIGN_EXTRACT:
634 c = 15;
635 break;
636 case MEM:
637 if (mode == DImode || mode == DFmode)
638 c = 5; /* 7 on VAX 2 */
639 else
640 c = 3; /* 4 on VAX 2 */
641 x = XEXP (x, 0);
642 if (GET_CODE (x) == REG || GET_CODE (x) == POST_INC)
643 return c;
644 return c + vax_address_cost (x);
645 default:
646 c = 3;
647 break;
648 }
649
650
651 /* Now look inside the expression. Operands which are not registers or
652 short constants add to the cost.
653
654 FMT and I may have been adjusted in the switch above for instructions
655 which require special handling */
656
657 while (*fmt++ == 'e')
658 {
659 register rtx op = XEXP (x, i++);
660 code = GET_CODE (op);
661
662 /* A NOT is likely to be found as the first operand of an AND
663 (in which case the relevant cost is of the operand inside
664 the not) and not likely to be found anywhere else. */
665 if (code == NOT)
666 op = XEXP (op, 0), code = GET_CODE (op);
667
668 switch (code)
669 {
670 case CONST_INT:
671 if ((unsigned)INTVAL (op) > 63 && GET_MODE (x) != QImode)
672 c += 1; /* 2 on VAX 2 */
673 break;
674 case CONST:
675 case LABEL_REF:
676 case SYMBOL_REF:
677 c += 1; /* 2 on VAX 2 */
678 break;
679 case CONST_DOUBLE:
680 if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT)
681 {
682 /* Registers are faster than floating point constants -- even
683 those constants which can be encoded in a single byte. */
684 if (vax_float_literal (op))
685 c++;
686 else
687 c += (GET_MODE (x) == DFmode) ? 3 : 2;
688 }
689 else
690 {
691 if (CONST_DOUBLE_HIGH (op) != 0
692 || (unsigned)CONST_DOUBLE_LOW (op) > 63)
693 c += 2;
694 }
695 break;
696 case MEM:
697 c += 1; /* 2 on VAX 2 */
698 if (GET_CODE (XEXP (op, 0)) != REG)
699 c += vax_address_cost (XEXP (op, 0));
700 break;
701 case REG:
702 case SUBREG:
703 break;
704 default:
705 c += 1;
706 break;
707 }
708 }
709 return c;
710 }
711 \f
712 #if VMS_TARGET
713 /* Additional support code for VMS target. */
714
715 /* Linked list of all externals that are to be emitted when optimizing
716 for the global pointer if they haven't been declared by the end of
717 the program with an appropriate .comm or initialization. */
718
719 static
720 struct extern_list {
721 struct extern_list *next; /* next external */
722 const char *name; /* name of the external */
723 int size; /* external's actual size */
724 int in_const; /* section type flag */
725 } *extern_head = 0, *pending_head = 0;
726
727 /* Check whether NAME is already on the external definition list. If not,
728 add it to either that list or the pending definition list. */
729
730 void
731 vms_check_external (decl, name, pending)
732 tree decl;
733 const char *name;
734 int pending;
735 {
736 register struct extern_list *p, *p0;
737
738 for (p = extern_head; p; p = p->next)
739 if (!strcmp (p->name, name))
740 return;
741
742 for (p = pending_head, p0 = 0; p; p0 = p, p = p->next)
743 if (!strcmp (p->name, name))
744 {
745 if (pending)
746 return;
747
748 /* Was pending, but has now been defined; move it to other list. */
749 if (p == pending_head)
750 pending_head = p->next;
751 else
752 p0->next = p->next;
753 p->next = extern_head;
754 extern_head = p;
755 return;
756 }
757
758 /* Not previously seen; create a new list entry. */
759 p = (struct extern_list *) xmalloc (sizeof (struct extern_list));
760 p->name = name;
761
762 if (pending)
763 {
764 /* Save the size and section type and link to `pending' list. */
765 p->size = (DECL_SIZE (decl) == 0) ? 0 :
766 TREE_INT_CST_LOW (size_binop (CEIL_DIV_EXPR, DECL_SIZE (decl),
767 size_int (BITS_PER_UNIT)));
768 p->in_const = (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl));
769
770 p->next = pending_head;
771 pending_head = p;
772 }
773 else
774 {
775 /* Size and section type don't matter; link to `declared' list. */
776 p->size = p->in_const = 0; /* arbitrary init */
777
778 p->next = extern_head;
779 extern_head = p;
780 }
781 return;
782 }
783
784 void
785 vms_flush_pending_externals (file)
786 FILE *file;
787 {
788 register struct extern_list *p;
789
790 while (pending_head)
791 {
792 /* Move next pending declaration to the "done" list. */
793 p = pending_head;
794 pending_head = p->next;
795 p->next = extern_head;
796 extern_head = p;
797
798 /* Now output the actual declaration. */
799 if (p->in_const)
800 const_section ();
801 else
802 data_section ();
803 fputs (".comm ", file);
804 assemble_name (file, p->name);
805 fprintf (file, ",%d\n", p->size);
806 }
807 }
808
809 static void
810 vms_asm_out_constructor (symbol, priority)
811 rtx symbol;
812 int priority ATTRIBUTE_UNUSED;
813 {
814 fprintf (asm_out_file,".globl $$PsectAttributes_NOOVR$$__gxx_init_1\n");
815 data_section();
816 fprintf (asm_out_file,"$$PsectAttributes_NOOVR$$__gxx_init_1:\n\t.long\t");
817 assemble_name (asm_out_file, XSTR (symbol, 0));
818 fputc ('\n', asm_out_file);
819 }
820
821 static void
822 vms_asm_out_destructor (symbol, priority)
823 rtx symbol;
824 int priority ATTRIBUTE_UNUSED;
825 {
826 fprintf (asm_out_file,".globl $$PsectAttributes_NOOVR$$__gxx_clean_1\n");
827 data_section();
828 fprintf (asm_out_file,"$$PsectAttributes_NOOVR$$__gxx_clean_1:\n\t.long\t");
829 assemble_name (asm_out_file, XSTR (symbol, 0));
830 fputc ('\n', asm_out_file);
831 }
832
833 static void
834 vms_select_section (exp, reloc, align)
835 tree exp;
836 int reloc ATTRIBUTE_UNUSED;
837 unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
838 {
839 if (TREE_CODE (exp) == VAR_DECL)
840 {
841 if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)
842 && DECL_INITIAL (exp)
843 && (DECL_INITIAL (exp) == error_mark_node
844 || TREE_CONSTANT (DECL_INITIAL (exp))))
845 {
846 if (TREE_PUBLIC (exp))
847 const_section ();
848 else
849 text_section ();
850 }
851 else
852 data_section ();
853 }
854 if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c')
855 {
856 if (TREE_CODE (exp) == STRING_CST && flag_writable_strings)
857 data_section ();
858 else
859 text_section ();
860 }
861 }
862
863 /* Make sure that external variables are correctly addressed. Under VMS
864 there is some brain damage in the linker that requires us to do this. */
865
866 static void
867 vms_encode_section_info (decl, first)
868 tree decl;
869 int first ATTRIBUTE_UNUSED;
870 {
871 if (DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
872 SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
873 }
874
875 /* This is how to output a command to make the user-level label named NAME
876 defined for reference from other files. */
877 static void
878 vms_globalize_label (stream, name)
879 FILE *stream;
880 const char *name;
881 {
882 default_globalize_label (stream, name);
883 vms_check_external (NULL_TREE, name, 0);
884 }
885 #endif /* VMS_TARGET */
886 \f
887 /* Additional support code for VMS host. */
888 /* ??? This should really be in libiberty; vax.c is a target file. */
889 #ifdef QSORT_WORKAROUND
890 /*
891 Do not use VAXCRTL's qsort() due to a severe bug: once you've
892 sorted something which has a size that's an exact multiple of 4
893 and is longword aligned, you cannot safely sort anything which
894 is either not a multiple of 4 in size or not longword aligned.
895 A static "move-by-longword" optimization flag inside qsort() is
896 never reset. This is known to affect VMS V4.6 through VMS V5.5-1,
897 and was finally fixed in VMS V5.5-2.
898
899 In this work-around an insertion sort is used for simplicity.
900 The qsort code from glibc should probably be used instead.
901 */
902 void
903 not_qsort (array, count, size, compare)
904 void *array;
905 unsigned count, size;
906 int (*compare)();
907 {
908
909 if (size == sizeof (short))
910 {
911 register int i;
912 register short *next, *prev;
913 short tmp, *base = array;
914
915 for (next = base, i = count - 1; i > 0; i--)
916 {
917 prev = next++;
918 if ((*compare)(next, prev) < 0)
919 {
920 tmp = *next;
921 do *(prev + 1) = *prev;
922 while (--prev >= base ? (*compare)(&tmp, prev) < 0 : 0);
923 *(prev + 1) = tmp;
924 }
925 }
926 }
927 else if (size == sizeof (long))
928 {
929 register int i;
930 register long *next, *prev;
931 long tmp, *base = array;
932
933 for (next = base, i = count - 1; i > 0; i--)
934 {
935 prev = next++;
936 if ((*compare)(next, prev) < 0)
937 {
938 tmp = *next;
939 do *(prev + 1) = *prev;
940 while (--prev >= base ? (*compare)(&tmp, prev) < 0 : 0);
941 *(prev + 1) = tmp;
942 }
943 }
944 }
945 else /* arbitrary size */
946 {
947 register int i;
948 register char *next, *prev, *tmp = alloca (size), *base = array;
949
950 for (next = base, i = count - 1; i > 0; i--)
951 { /* count-1 forward iterations */
952 prev = next, next += size; /* increment front pointer */
953 if ((*compare)(next, prev) < 0)
954 { /* found element out of order; move others up then re-insert */
955 memcpy (tmp, next, size); /* save smaller element */
956 do { memcpy (prev + size, prev, size); /* move larger elem. up */
957 prev -= size; /* decrement back pointer */
958 } while (prev >= base ? (*compare)(tmp, prev) < 0 : 0);
959 memcpy (prev + size, tmp, size); /* restore small element */
960 }
961 }
962 #ifdef USE_C_ALLOCA
963 alloca (0);
964 #endif
965 }
966
967 return;
968 }
969 #endif /* QSORT_WORKAROUND */
970
971 /* Return 1 if insn A follows B. */
972
973 static int
974 follows_p (a, b)
975 rtx a, b;
976 {
977 register rtx p;
978
979 for (p = a; p != b; p = NEXT_INSN (p))
980 if (! p)
981 return 1;
982
983 return 0;
984 }
985
986 /* Returns 1 if we know operand OP was 0 before INSN. */
987
988 int
989 reg_was_0_p (insn, op)
990 rtx insn, op;
991 {
992 rtx link;
993
994 return ((link = find_reg_note (insn, REG_WAS_0, 0))
995 /* Make sure the insn that stored the 0 is still present
996 and doesn't follow INSN in the insn sequence. */
997 && ! INSN_DELETED_P (XEXP (link, 0))
998 && GET_CODE (XEXP (link, 0)) != NOTE
999 && ! follows_p (XEXP (link, 0), insn)
1000 /* Make sure cross jumping didn't happen here. */
1001 && no_labels_between_p (XEXP (link, 0), insn)
1002 /* Make sure the reg hasn't been clobbered. */
1003 && ! reg_set_between_p (op, XEXP (link, 0), insn));
1004 }
This page took 0.079091 seconds and 5 git commands to generate.