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