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