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