xref: /openbsd/gnu/usr.bin/gcc/gcc/config/vax/vax.c (revision 481cd436)
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