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