Don't activate -funit-at-a-time with -O2 and higher by default, when
[dragonfly.git] / gnu / usr.bin / cc34 / cc_prep / protector.c
1 /* $DragonFly: src/gnu/usr.bin/cc34/cc_prep/protector.c,v 1.1 2004/06/19 10:34:17 joerg Exp $ */
2 /* RTL buffer overflow protection function for GNU C compiler
3    Copyright (C) 2003 Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.  */
21
22 /* This file contains several memory arrangement functions to protect
23    the return address and the frame pointer of the stack
24    from a stack-smashing attack. It also
25    provides the function that protects pointer variables.  */
26
27 #include "config.h"
28 #include "system.h"
29 #include "coretypes.h"
30 #include "tm.h"
31 #include "machmode.h"
32 #include "real.h"
33 #include "rtl.h"
34 #include "tree.h"
35 #include "regs.h"
36 #include "flags.h"
37 #include "insn-config.h"
38 #include "insn-flags.h"
39 #include "expr.h"
40 #include "output.h"
41 #include "recog.h"
42 #include "hard-reg-set.h"
43 #include "except.h"
44 #include "function.h"
45 #include "toplev.h"
46 #include "tm_p.h"
47 #include "conditions.h"
48 #include "insn-attr.h"
49 #include "optabs.h"
50 #include "reload.h"
51 #include "protector.h"
52
53
54 /* Round a value to the lowest integer less than it that is a multiple of
55    the required alignment.  Avoid using division in case the value is
56    negative.  Assume the alignment is a power of two.  */
57 #define FLOOR_ROUND(VALUE,ALIGN) ((VALUE) & ~((ALIGN) - 1))
58
59 /* Similar, but round to the next highest integer that meets the
60    alignment.  */
61 #define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))
62
63
64 /* Nonzero if function being compiled can define string buffers that may be
65    damaged by the stack-smash attack.  */
66 static int current_function_defines_vulnerable_string;
67 static int current_function_defines_short_string;
68 static int current_function_has_variable_string;
69 static int current_function_defines_vsized_array;
70 static int current_function_is_inlinable;
71 static int is_array;
72
73 static rtx guard_area, _guard;
74 static rtx function_first_insn, prologue_insert_point;
75
76 /* Offset to end of sweeped area for gathering character arrays.  */
77 static HOST_WIDE_INT sweep_frame_offset;
78
79 /* Offset to end of allocated area for instantiating pseudo registers.  */
80 static HOST_WIDE_INT push_allocated_offset = 0;
81
82 /* Offset to end of assigned area for instantiating pseudo registers.  */
83 static HOST_WIDE_INT push_frame_offset = 0;
84
85 /* Set to 1 after cse_not_expected becomes nonzero. it is used to identify
86    which stage assign_stack_local_for_pseudo_reg is called from.  */
87 static int saved_cse_not_expected = 0;
88
89 static int search_string_from_argsandvars (int);
90 static int search_string_from_local_vars (tree);
91 static int search_pointer_def (tree);
92 static int search_func_pointer (tree);
93 static int check_used_flag (rtx);
94 static void reset_used_flags_for_insns (rtx);
95 static void reset_used_flags_for_decls (tree);
96 static void reset_used_flags_of_plus (rtx);
97 static void rtl_prologue (rtx);
98 static void rtl_epilogue (rtx);
99 static void arrange_var_order (tree);
100 static void copy_args_for_protection (void);
101 static void sweep_string_variable (rtx, HOST_WIDE_INT);
102 static void sweep_string_in_decls (tree, HOST_WIDE_INT, HOST_WIDE_INT);
103 static void sweep_string_in_args (tree, HOST_WIDE_INT, HOST_WIDE_INT);
104 static void sweep_string_use_of_insns (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
105 static void sweep_string_in_operand (rtx, rtx *, HOST_WIDE_INT, HOST_WIDE_INT);
106 static void move_arg_location (rtx, rtx, rtx, HOST_WIDE_INT);
107 static void change_arg_use_of_insns (rtx, rtx, rtx *, HOST_WIDE_INT);
108 static void change_arg_use_in_operand (rtx, rtx, rtx, rtx *, HOST_WIDE_INT);
109 static void validate_insns_of_varrefs (rtx);
110 static void validate_operand_of_varrefs (rtx, rtx *);
111
112 /* Specify which size of buffers should be protected from a stack smashing
113    attack. Because small buffers are not used in situations which may
114    overflow buffer, the default size sets to the size of 64 bit register.  */
115 #ifndef SUSPICIOUS_BUF_SIZE
116 #define SUSPICIOUS_BUF_SIZE 8
117 #endif
118
119 #define AUTO_BASEPTR(X) \
120   (GET_CODE (X) == PLUS ? XEXP (X, 0) : X)
121 #define AUTO_OFFSET(X) \
122   (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0)
123 #undef PARM_PASSED_IN_MEMORY
124 #define PARM_PASSED_IN_MEMORY(PARM) \
125  (GET_CODE (DECL_INCOMING_RTL (PARM)) == MEM)
126 #define TREE_VISITED(NODE) ((NODE)->common.unused_0)
127
128 /* Argument values for calling search_string_from_argsandvars.  */
129 #define CALL_FROM_PREPARE_STACK_PROTECTION      0
130 #define CALL_FROM_PUSH_FRAME                    1
131
132
133 /* Prepare several stack protection instruments for the current function
134    if the function has an array as a local variable, which may be vulnerable
135    from a stack smashing attack, and it is not inlinable.
136
137    The overall steps are as follows;
138    (1)search an array,
139    (2)insert guard_area on the stack,
140    (3)duplicate pointer arguments into local variables, and
141    (4)arrange the location of local variables.  */
142 void
143 prepare_stack_protection (int inlinable)
144 {
145   tree blocks = DECL_INITIAL (current_function_decl);
146   current_function_is_inlinable = inlinable && !flag_no_inline;
147   push_frame_offset = push_allocated_offset = 0;
148   saved_cse_not_expected = 0;
149
150   /* Skip the protection if the function has no block
151     or it is an inline function.  */
152   if (current_function_is_inlinable)
153     validate_insns_of_varrefs (get_insns ());
154   if (! blocks || current_function_is_inlinable)
155     return;
156
157   current_function_defines_vulnerable_string
158     = search_string_from_argsandvars (CALL_FROM_PREPARE_STACK_PROTECTION);
159
160   if (current_function_defines_vulnerable_string
161       || flag_stack_protection)
162     {
163       function_first_insn = get_insns ();
164
165       if (current_function_contains_functions)
166         {
167           if (warn_stack_protector)
168             warning ("not protecting function: it contains functions");
169           return;
170         }
171
172       /* Initialize recognition, indicating that volatile is OK.  */
173       init_recog ();
174
175       sweep_frame_offset = 0;
176         
177 #ifdef STACK_GROWS_DOWNWARD
178       /* frame_offset: offset to end of allocated area of stack frame.
179          It is defined in the function.c.  */
180
181       /* the location must be before buffers.  */
182       guard_area = assign_stack_local (BLKmode, UNITS_PER_GUARD, -1);
183       PUT_MODE (guard_area, GUARD_m);
184       MEM_VOLATILE_P (guard_area) = 1;
185
186 #ifndef FRAME_GROWS_DOWNWARD
187       sweep_frame_offset = frame_offset;
188 #endif
189
190       /* For making room for guard value, scan all insns and fix the offset
191          address of the variable that is based on frame pointer.
192          Scan all declarations of variables and fix the offset address
193          of the variable that is based on the frame pointer.  */
194       sweep_string_variable (guard_area, UNITS_PER_GUARD);
195
196         
197       /* the location of guard area moves to the beginning of stack frame.  */
198       if (AUTO_OFFSET(XEXP (guard_area, 0)))
199         XEXP (XEXP (guard_area, 0), 1)
200           = gen_rtx_CONST_INT (VOIDmode, sweep_frame_offset);
201
202
203       /* Insert prologue rtl instructions.  */
204       rtl_prologue (function_first_insn);
205
206       if (! current_function_has_variable_string)
207         {
208           /* Generate argument saving instruction.  */
209           copy_args_for_protection ();
210
211 #ifndef FRAME_GROWS_DOWNWARD
212           /* If frame grows upward, character arrays for protecting args
213              may copy to the top of the guard variable.
214              So sweep the guard variable again.  */
215           sweep_frame_offset = CEIL_ROUND (frame_offset,
216                                            BIGGEST_ALIGNMENT / BITS_PER_UNIT);
217           sweep_string_variable (guard_area, UNITS_PER_GUARD);
218 #endif
219         }
220       /* Variable can't be protected from the overflow of variable length
221          buffer. But variable reordering is still effective against
222          the overflow of fixed size character arrays.  */
223       else if (warn_stack_protector)
224         warning ("not protecting variables: it has a variable length buffer");
225 #endif
226 #ifndef FRAME_GROWS_DOWNWARD
227       if (STARTING_FRAME_OFFSET == 0)
228         {
229           /* This part may be only for alpha.  */
230           push_allocated_offset = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
231           assign_stack_local (BLKmode, push_allocated_offset, -1);
232           sweep_frame_offset = frame_offset;
233           sweep_string_variable (const0_rtx, -push_allocated_offset);
234           sweep_frame_offset = AUTO_OFFSET (XEXP (guard_area, 0));
235         }
236 #endif
237
238       /* Arrange the order of local variables.  */
239       arrange_var_order (blocks);
240
241 #ifdef STACK_GROWS_DOWNWARD
242       /* Insert epilogue rtl instructions.  */
243       rtl_epilogue (get_last_insn ());
244 #endif
245       init_recog_no_volatile ();
246     }
247   else if (current_function_defines_short_string
248            && warn_stack_protector)
249     warning ("not protecting function: buffer is less than %d bytes long",
250              SUSPICIOUS_BUF_SIZE);
251 }
252
253 /*
254   Search string from arguments and local variables.
255    caller: CALL_FROM_PREPARE_STACK_PROTECTION (0)
256            CALL_FROM_PUSH_FRAME (1)
257 */
258 static int
259 search_string_from_argsandvars (int caller)
260 {
261   tree blocks, parms;
262   int string_p;
263
264   /* Saves a latest search result as a cached infomation.  */
265   static tree __latest_search_decl = 0;
266   static int  __latest_search_result = FALSE;
267
268   if (__latest_search_decl == current_function_decl)
269     return __latest_search_result;
270   else
271     if (caller == CALL_FROM_PUSH_FRAME)
272       return FALSE;
273
274   __latest_search_decl = current_function_decl;
275   __latest_search_result = TRUE;
276   
277   current_function_defines_short_string = FALSE;
278   current_function_has_variable_string = FALSE;
279   current_function_defines_vsized_array = FALSE;
280
281   /* Search a string variable from local variables.  */
282   blocks = DECL_INITIAL (current_function_decl);
283   string_p = search_string_from_local_vars (blocks);
284
285   if (! current_function_defines_vsized_array && current_function_calls_alloca)
286     {
287       current_function_has_variable_string = TRUE;
288       return TRUE;
289     }
290
291   if (string_p)
292     return TRUE;
293
294 #ifdef STACK_GROWS_DOWNWARD
295   /* Search a string variable from arguments.  */
296   parms = DECL_ARGUMENTS (current_function_decl);
297
298   for (; parms; parms = TREE_CHAIN (parms))
299     if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
300       {
301         if (PARM_PASSED_IN_MEMORY (parms))
302           {
303             string_p = search_string_def (TREE_TYPE(parms));
304             if (string_p)
305               return TRUE;
306           }
307       }
308 #endif
309
310   __latest_search_result = FALSE;
311   return FALSE;
312 }
313
314
315 /* Search string from local variables in the specified scope.  */
316 static int
317 search_string_from_local_vars (tree block)
318 {
319   tree types;
320   int found = FALSE;
321
322   while (block && TREE_CODE(block)==BLOCK)
323     {
324       for (types = BLOCK_VARS(block); types; types = TREE_CHAIN(types))
325         {
326           /* Skip the declaration that refers an external variable.  */
327           /* name: types.decl.name.identifier.id                     */
328           if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)
329               && TREE_CODE (types) == VAR_DECL
330               && ! DECL_ARTIFICIAL (types)
331               && DECL_RTL_SET_P (types)
332               && GET_CODE (DECL_RTL (types)) == MEM
333
334               && search_string_def (TREE_TYPE (types)))
335             {
336               rtx home = DECL_RTL (types);
337
338               if (GET_CODE (home) == MEM
339                   && (GET_CODE (XEXP (home, 0)) == MEM
340                       || (GET_CODE (XEXP (home, 0)) == REG
341                           && XEXP (home, 0) != virtual_stack_vars_rtx
342                           && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM
343                           && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM
344 #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
345                           && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM
346 #endif
347                           )))
348                 /* If the value is indirect by memory or by a register
349                    that isn't the frame pointer then it means the object is
350                    variable-sized and address through
351                    that register or stack slot.
352                    The protection has no way to hide pointer variables
353                    behind the array, so all we can do is staying
354                    the order of variables and arguments.  */
355                 {
356                   current_function_has_variable_string = TRUE;
357                 }
358             
359               /* Found character array.  */
360               found = TRUE;
361             }
362         }
363
364       if (search_string_from_local_vars (BLOCK_SUBBLOCKS (block)))
365         {
366           found = TRUE;
367         }
368
369       block = BLOCK_CHAIN (block);
370     }
371     
372   return found;
373 }
374
375
376 /* Search a character array from the specified type tree.  */
377 int
378 search_string_def (tree type)
379 {
380   tree tem;
381     
382   if (! type)
383     return FALSE;
384
385   switch (TREE_CODE (type))
386     {
387     case ARRAY_TYPE:
388       /* Check if the array is a variable-sized array.  */
389       if (TYPE_DOMAIN (type) == 0
390           || (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0
391               && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR))
392         current_function_defines_vsized_array = TRUE;
393
394       /* Check if the array is related to char array.  */
395       if (TYPE_MAIN_VARIANT (TREE_TYPE(type)) == char_type_node
396           || TYPE_MAIN_VARIANT (TREE_TYPE(type)) == signed_char_type_node
397           || TYPE_MAIN_VARIANT (TREE_TYPE(type)) == unsigned_char_type_node)
398         {
399           /* Check if the string is a variable string.  */
400           if (TYPE_DOMAIN (type) == 0
401               || (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0
402                   && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR))
403             return TRUE;
404
405           /* Check if the string size is greater than SUSPICIOUS_BUF_SIZE.  */
406           if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0
407               && (TREE_INT_CST_LOW(TYPE_MAX_VALUE(TYPE_DOMAIN(type)))+1
408                   >= SUSPICIOUS_BUF_SIZE))
409             return TRUE;
410
411           current_function_defines_short_string = TRUE;
412         }
413       
414       /* to protect every functions, sweep any arrays to the frame top.  */
415       is_array = TRUE;
416
417       return search_string_def(TREE_TYPE(type));
418         
419     case UNION_TYPE:
420     case QUAL_UNION_TYPE:
421     case RECORD_TYPE:
422       /* Check if each field has character arrays.  */
423       for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
424         {
425           /* Omit here local type decls until we know how to support them. */
426           if ((TREE_CODE (tem) == TYPE_DECL)
427               || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem)))
428             continue;
429
430           if (search_string_def(TREE_TYPE(tem)))
431             return TRUE;
432         }
433       break;
434         
435     case POINTER_TYPE:
436     case REFERENCE_TYPE:
437     case OFFSET_TYPE:
438     default:
439       break;
440     }
441
442   return FALSE;
443 }
444
445
446 /* Examine whether the input contains frame pointer addressing.  */
447 int
448 contains_fp (rtx op)
449 {
450   enum rtx_code code;
451   rtx x;
452   int i, j;
453   const char *fmt;
454
455   x = op;
456   if (x == 0)
457     return FALSE;
458
459   code = GET_CODE (x);
460
461   switch (code)
462     {
463     case CONST_INT:
464     case CONST_DOUBLE:
465     case CONST:
466     case SYMBOL_REF:
467     case CODE_LABEL:
468     case REG:
469     case ADDRESSOF:
470       return FALSE;
471
472     case MEM:
473       /* This case is not generated at the stack protection.
474          see plus_constant_wide and simplify_plus_minus function.  */
475       if (XEXP (x, 0) == virtual_stack_vars_rtx)
476         abort ();
477       
478     case PLUS:
479       if (XEXP (x, 0) == virtual_stack_vars_rtx
480           && GET_CODE (XEXP (x, 1)) == CONST_INT)
481         return TRUE;
482
483     default:
484       break;
485     }
486
487   /* Scan all subexpressions.  */
488   fmt = GET_RTX_FORMAT (code);
489   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
490     if (*fmt == 'e')
491       {
492         if (contains_fp (XEXP (x, i)))
493           return TRUE;
494       }
495     else if (*fmt == 'E')
496       for (j = 0; j < XVECLEN (x, i); j++)
497         if (contains_fp (XVECEXP (x, i, j)))
498           return TRUE;
499
500   return FALSE;
501 }
502
503
504 /* Examine whether the input contains any pointer.  */
505 static int
506 search_pointer_def (tree type)
507 {
508   tree tem;
509     
510   if (! type)
511     return FALSE;
512
513   switch (TREE_CODE (type))
514     {
515     case UNION_TYPE:
516     case QUAL_UNION_TYPE:
517     case RECORD_TYPE:
518       /* Check if each field has a pointer.  */
519       for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
520         {
521           if ((TREE_CODE (tem) == TYPE_DECL)
522               || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem)))
523             continue;
524
525           if (search_pointer_def (TREE_TYPE(tem)))
526             return TRUE;
527         }
528       break;
529
530     case ARRAY_TYPE:
531       return search_pointer_def (TREE_TYPE(type));
532         
533     case POINTER_TYPE:
534     case REFERENCE_TYPE:
535     case OFFSET_TYPE:
536       if (TYPE_READONLY (TREE_TYPE (type)))
537         {
538           /* If this pointer contains function pointer,
539              it should be protected.  */
540           return search_func_pointer (TREE_TYPE (type));
541         }
542       return TRUE;
543         
544     default:
545       break;
546     }
547
548   return FALSE;
549 }
550
551
552 /* Examine whether the input contains function pointer.  */
553 static int
554 search_func_pointer (tree type)
555 {
556   tree tem;
557     
558   if (! type)
559     return FALSE;
560
561   switch (TREE_CODE (type))
562     {
563     case UNION_TYPE:
564     case QUAL_UNION_TYPE:
565     case RECORD_TYPE:
566         if (! TREE_VISITED (type))
567           {
568             /* Mark the type as having been visited already.  */
569             TREE_VISITED (type) = 1;
570
571             /* Check if each field has a function pointer.  */
572             for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
573               {
574                 if (TREE_CODE (tem) == FIELD_DECL
575                     && search_func_pointer (TREE_TYPE(tem)))
576                   {
577                     TREE_VISITED (type) = 0;
578                     return TRUE;
579                   }
580               }
581             
582             TREE_VISITED (type) = 0;
583           }
584         break;
585
586     case ARRAY_TYPE:
587       return search_func_pointer (TREE_TYPE(type));
588         
589     case POINTER_TYPE:
590     case REFERENCE_TYPE:
591     case OFFSET_TYPE:
592       if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
593         return TRUE;
594       return search_func_pointer (TREE_TYPE(type));
595         
596     default:
597       break;
598     }
599
600   return FALSE;
601 }
602
603
604 /* Check whether the specified rtx contains PLUS rtx with used flag.  */
605 static int
606 check_used_flag (rtx x)
607 {
608   register int i, j;
609   register enum rtx_code code;
610   register const char *format_ptr;
611
612   if (x == 0)
613     return FALSE;
614
615   code = GET_CODE (x);
616
617   switch (code)
618     {
619     case REG:
620     case QUEUED:
621     case CONST_INT:
622     case CONST_DOUBLE:
623     case SYMBOL_REF:
624     case CODE_LABEL:
625     case PC:
626     case CC0:
627       return FALSE;
628
629     case PLUS:
630       if (x->used)
631         return TRUE;
632
633     default:
634       break;
635     }
636
637   format_ptr = GET_RTX_FORMAT (code);
638   for (i = 0; i < GET_RTX_LENGTH (code); i++)
639     {
640       switch (*format_ptr++)
641         {
642         case 'e':
643           if (check_used_flag (XEXP (x, i)))
644             return TRUE;
645           break;
646
647         case 'E':
648           for (j = 0; j < XVECLEN (x, i); j++)
649             if (check_used_flag (XVECEXP (x, i, j)))
650               return TRUE;
651           break;
652         }
653     }
654
655   return FALSE;
656 }
657
658
659 /* Reset used flag of every insns after the spcecified insn.  */
660 static void
661 reset_used_flags_for_insns (rtx insn)
662 {
663   int i, j;
664   enum rtx_code code;
665   const char *format_ptr;
666
667   for (; insn; insn = NEXT_INSN (insn))
668     if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
669         || GET_CODE (insn) == CALL_INSN)
670       {
671         code = GET_CODE (insn);
672         insn->used = 0;
673         format_ptr = GET_RTX_FORMAT (code);
674
675         for (i = 0; i < GET_RTX_LENGTH (code); i++)
676           {
677             switch (*format_ptr++)
678               {
679               case 'e':
680                 reset_used_flags_of_plus (XEXP (insn, i));
681                 break;
682                         
683               case 'E':
684                 for (j = 0; j < XVECLEN (insn, i); j++)
685                   reset_used_flags_of_plus (XVECEXP (insn, i, j));
686                 break;
687               }
688           }
689       }
690 }
691
692
693 /* Reset used flag of every variables in the specified block.  */
694 static void
695 reset_used_flags_for_decls (tree block)
696 {
697   tree types;
698   rtx home;
699
700   while (block && TREE_CODE(block)==BLOCK)
701     {
702       types = BLOCK_VARS(block);
703         
704       for (types= BLOCK_VARS(block); types; types = TREE_CHAIN(types))
705         {
706           /* Skip the declaration that refers an external variable and
707              also skip an global variable.  */
708           if (! DECL_EXTERNAL (types))
709             {
710               if (! DECL_RTL_SET_P (types))
711                 continue;
712               home = DECL_RTL (types);
713
714               if (GET_CODE (home) == MEM
715                   && GET_CODE (XEXP (home, 0)) == PLUS
716                   && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
717                 {
718                   XEXP (home, 0)->used = 0;
719                 }
720             }
721         }
722
723       reset_used_flags_for_decls (BLOCK_SUBBLOCKS (block));
724
725       block = BLOCK_CHAIN (block);
726     }
727 }
728
729
730 /* Reset the used flag of every PLUS rtx derived from the specified rtx.  */
731 static void
732 reset_used_flags_of_plus (rtx x)
733 {
734   int i, j;
735   enum rtx_code code;
736   const char *format_ptr;
737
738   if (x == 0)
739     return;
740
741   code = GET_CODE (x);
742
743   switch (code)
744     {
745       /* These types may be freely shared so we needn't do any resetting
746          for them.  */
747     case REG:
748     case QUEUED:
749     case CONST_INT:
750     case CONST_DOUBLE:
751     case SYMBOL_REF:
752     case CODE_LABEL:
753     case PC:
754     case CC0:
755       return;
756
757     case INSN:
758     case JUMP_INSN:
759     case CALL_INSN:
760     case NOTE:
761     case LABEL_REF:
762     case BARRIER:
763       /* The chain of insns is not being copied.  */
764       return;
765       
766     case PLUS:
767       x->used = 0;
768       break;
769
770     case CALL_PLACEHOLDER:
771       reset_used_flags_for_insns (XEXP (x, 0));
772       reset_used_flags_for_insns (XEXP (x, 1));
773       reset_used_flags_for_insns (XEXP (x, 2));
774       break;
775
776     default:
777       break;
778     }
779
780   format_ptr = GET_RTX_FORMAT (code);
781   for (i = 0; i < GET_RTX_LENGTH (code); i++)
782     {
783       switch (*format_ptr++)
784         {
785         case 'e':
786           reset_used_flags_of_plus (XEXP (x, i));
787           break;
788
789         case 'E':
790           for (j = 0; j < XVECLEN (x, i); j++)
791             reset_used_flags_of_plus (XVECEXP (x, i, j));
792           break;
793         }
794     }
795 }
796
797
798 /* Generate the prologue insns of the protector into the specified insn.  */
799 static void
800 rtl_prologue (rtx insn)
801 {
802 #if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main)
803 #undef HAS_INIT_SECTION
804 #define HAS_INIT_SECTION
805 #endif
806
807   rtx _val;
808
809   for (; insn; insn = NEXT_INSN (insn))
810     if (GET_CODE (insn) == NOTE
811         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
812       break;
813   
814 #if !defined (HAS_INIT_SECTION)
815   /* If this function is `main', skip a call to `__main'
816      to run guard instruments after global initializers, etc.  */
817   if (DECL_NAME (current_function_decl)
818       && MAIN_NAME_P (DECL_NAME (current_function_decl))
819       && DECL_CONTEXT (current_function_decl) == NULL_TREE)
820     {
821       rtx fbinsn = insn;
822       for (; insn; insn = NEXT_INSN (insn))
823         if (GET_CODE (insn) == NOTE
824             && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
825           break;
826       if (insn == 0)
827         insn = fbinsn;
828     }
829 #endif
830
831   /* Mark the next insn of FUNCTION_BEG insn.  */
832   prologue_insert_point = NEXT_INSN (insn);
833                 
834   start_sequence ();
835
836   _guard = gen_rtx_MEM (GUARD_m, gen_rtx_SYMBOL_REF (Pmode, "__guard"));
837   emit_move_insn ( guard_area, _guard);
838
839   _val = get_insns ();
840   end_sequence ();
841
842   emit_insn_before (_val, prologue_insert_point);
843 }
844
845
846 /* Generate the epilogue insns of the protector into the specified insn.  */
847 static void
848 rtl_epilogue (rtx insn)
849 {
850   rtx if_false_label;
851   rtx _val;
852   rtx funcname;
853   tree funcstr;
854   int  flag_have_return = FALSE;
855                 
856   start_sequence ();
857
858 #ifdef HAVE_return
859   if (HAVE_return)
860     {
861       rtx insn;
862       return_label = gen_label_rtx ();
863       
864       for (insn = prologue_insert_point; insn; insn = NEXT_INSN (insn))
865         if (GET_CODE (insn) == JUMP_INSN
866             && GET_CODE (PATTERN (insn)) == RETURN
867             && GET_MODE (PATTERN (insn)) == VOIDmode)
868           {
869             rtx pat = gen_rtx_SET (VOIDmode,
870                                    pc_rtx,
871                                    gen_rtx_LABEL_REF (VOIDmode,
872                                                       return_label));
873             PATTERN (insn) = pat;
874             flag_have_return = TRUE;
875           }
876
877
878       emit_label (return_label);
879     }
880 #endif
881
882   /*                                          if (guard_area != _guard) */
883   compare_from_rtx (guard_area, _guard, NE, 0, GUARD_m, NULL_RTX);
884
885   if_false_label = gen_label_rtx ();            /* { */
886   emit_jump_insn ( gen_beq(if_false_label));
887
888   /* generate string for the current function name */
889   funcstr = build_string (strlen(current_function_name ())+1,
890                           current_function_name ());
891   TREE_TYPE (funcstr) = build_array_type (char_type_node, 0);
892   funcname = output_constant_def (funcstr, 1);
893
894   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__stack_smash_handler"),
895                      0, VOIDmode, 2,
896                      XEXP (funcname, 0), Pmode, guard_area, GUARD_m);
897
898   /* generate RTL to return from the current function */
899                 
900   emit_barrier ();                              /* } */
901   emit_label (if_false_label);
902
903   /* generate RTL to return from the current function */
904   if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl)))
905     use_return_register ();
906
907 #ifdef HAVE_return
908   if (HAVE_return && flag_have_return)
909     {
910       emit_jump_insn (gen_return ());
911       emit_barrier ();
912     }
913 #endif
914   
915   _val = get_insns ();
916   end_sequence ();
917
918   emit_insn_after (_val, insn);
919 }
920
921
922 /* For every variable which type is character array, moves its location
923    in the stack frame to the sweep_frame_offset position.  */
924 static void
925 arrange_var_order (tree block)
926 {
927   tree types;
928   HOST_WIDE_INT offset;
929     
930   while (block && TREE_CODE(block)==BLOCK)
931     {
932       /* arrange the location of character arrays in depth first.  */
933       arrange_var_order (BLOCK_SUBBLOCKS (block));
934       
935       for (types = BLOCK_VARS (block); types; types = TREE_CHAIN(types))
936         {
937           /* Skip the declaration that refers an external variable.  */
938           if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)
939               && TREE_CODE (types) == VAR_DECL
940               && ! DECL_ARTIFICIAL (types)
941               /* && ! DECL_COPIED (types): gcc3.4 can sweep inlined string.  */
942               && DECL_RTL_SET_P (types)
943               && GET_CODE (DECL_RTL (types)) == MEM
944               && GET_MODE (DECL_RTL (types)) == BLKmode
945
946               && (is_array=0,
947                   search_string_def (TREE_TYPE (types))
948                   || (! current_function_defines_vulnerable_string && is_array)))
949             {
950               rtx home = DECL_RTL (types);
951
952               if (!(GET_CODE (home) == MEM
953                     && (GET_CODE (XEXP (home, 0)) == MEM
954                         || (GET_CODE (XEXP (home, 0)) == REG
955                             && XEXP (home, 0) != virtual_stack_vars_rtx
956                             && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM
957                             && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM
958 #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
959                             && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM
960 #endif
961                             ))))
962                 {
963                   /* Found a string variable.  */
964                   HOST_WIDE_INT var_size =
965                     ((TREE_INT_CST_LOW (DECL_SIZE (types)) + BITS_PER_UNIT - 1)
966                      / BITS_PER_UNIT);
967
968                   /* Confirmed it is BLKmode.  */
969                   int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
970                   var_size = CEIL_ROUND (var_size, alignment);
971
972                   /* Skip the variable if it is top of the region
973                      specified by sweep_frame_offset.  */
974                   offset = AUTO_OFFSET (XEXP (DECL_RTL (types), 0));
975                   if (offset == sweep_frame_offset - var_size)
976                     sweep_frame_offset -= var_size;
977                       
978                   else if (offset < sweep_frame_offset - var_size)
979                     sweep_string_variable (DECL_RTL (types), var_size);
980                 }
981             }
982         }
983
984       block = BLOCK_CHAIN (block);
985     }
986 }
987
988
989 /* To protect every pointer argument and move character arrays in the argument,
990    Copy those variables to the top of the stack frame and move the location of
991    character arrays to the posion of sweep_frame_offset.  */
992 static void
993 copy_args_for_protection (void)
994 {
995   tree parms = DECL_ARGUMENTS (current_function_decl);
996   rtx temp_rtx;
997
998   parms = DECL_ARGUMENTS (current_function_decl);
999   for (; parms; parms = TREE_CHAIN (parms))
1000     if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
1001       {
1002         if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
1003           {
1004             int string_p;
1005             rtx seq;
1006
1007             string_p = search_string_def (TREE_TYPE(parms));
1008
1009             /* Check if it is a candidate to move.  */
1010             if (string_p || search_pointer_def (TREE_TYPE (parms)))
1011               {
1012                 int arg_size
1013                   = ((TREE_INT_CST_LOW (DECL_SIZE (parms)) + BITS_PER_UNIT - 1)
1014                      / BITS_PER_UNIT);
1015                 tree passed_type = DECL_ARG_TYPE (parms);
1016                 tree nominal_type = TREE_TYPE (parms);
1017                 
1018                 start_sequence ();
1019
1020                 if (GET_CODE (DECL_RTL (parms)) == REG)
1021                   {
1022                     rtx safe = 0;
1023                     
1024                     change_arg_use_of_insns (prologue_insert_point,
1025                                              DECL_RTL (parms), &safe, 0);
1026                     if (safe)
1027                       {
1028                         /* Generate codes for copying the content.  */
1029                         rtx movinsn = emit_move_insn (safe, DECL_RTL (parms));
1030                     
1031                         /* Avoid register elimination in gcse.c.  */
1032                         PATTERN (movinsn)->volatil = 1;
1033                         
1034                         /* Save debugger info.  */
1035                         SET_DECL_RTL (parms, safe);
1036                       }
1037                   }
1038                 else if (GET_CODE (DECL_RTL (parms)) == MEM
1039                          && GET_CODE (XEXP (DECL_RTL (parms), 0)) == ADDRESSOF)
1040                   {
1041                     rtx movinsn;
1042                     rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms)));
1043
1044                     /* Generate codes for copying the content.  */
1045                     movinsn = emit_move_insn (safe, DECL_INCOMING_RTL (parms));
1046                     /* Avoid register elimination in gcse.c.  */
1047                     PATTERN (movinsn)->volatil = 1;
1048
1049                     /* Change the addressof information to the newly
1050                        allocated pseudo register.  */
1051                     emit_move_insn (DECL_RTL (parms), safe);
1052
1053                     /* Save debugger info.  */
1054                     SET_DECL_RTL (parms, safe);
1055                   }
1056                         
1057                 /* See if the frontend wants to pass this by invisible
1058                    reference.  */
1059                 else if (passed_type != nominal_type
1060                          && POINTER_TYPE_P (passed_type)
1061                          && TREE_TYPE (passed_type) == nominal_type)
1062                   {
1063                     rtx safe = 0, orig = XEXP (DECL_RTL (parms), 0);
1064
1065                     change_arg_use_of_insns (prologue_insert_point,
1066                                              orig, &safe, 0);
1067                     if (safe)
1068                       {
1069                         /* Generate codes for copying the content.  */
1070                         rtx movinsn = emit_move_insn (safe, orig);
1071                     
1072                         /* Avoid register elimination in gcse.c  */
1073                         PATTERN (movinsn)->volatil = 1;
1074                         
1075                         /* Save debugger info.  */
1076                         SET_DECL_RTL (parms, safe);
1077                       }
1078                   }
1079
1080                 else
1081                   {
1082                     /* Declare temporary local variable for parms.  */
1083                     temp_rtx
1084                       = assign_stack_local (DECL_MODE (parms), arg_size,
1085                                             DECL_MODE (parms) == BLKmode ?
1086                                             -1 : 0);
1087                     
1088                     MEM_IN_STRUCT_P (temp_rtx)
1089                       = AGGREGATE_TYPE_P (TREE_TYPE (parms));
1090                     set_mem_alias_set (temp_rtx, get_alias_set (parms));
1091
1092                     /* Generate codes for copying the content.  */
1093                     store_expr (parms, temp_rtx, 0);
1094
1095                     /* Change the reference for each instructions.  */
1096                     move_arg_location (prologue_insert_point, DECL_RTL (parms),
1097                                        temp_rtx, arg_size);
1098
1099                     /* Change the location of parms variable.  */
1100                     SET_DECL_RTL (parms, temp_rtx);
1101                   }
1102
1103                 seq = get_insns ();
1104                 end_sequence ();
1105                 emit_insn_before (seq, prologue_insert_point);
1106
1107 #ifdef FRAME_GROWS_DOWNWARD
1108                 /* Process the string argument.  */
1109                 if (string_p && DECL_MODE (parms) == BLKmode)
1110                   {
1111                     int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
1112                     arg_size = CEIL_ROUND (arg_size, alignment);
1113                         
1114                     /* Change the reference for each instructions.  */
1115                     sweep_string_variable (DECL_RTL (parms), arg_size);
1116                   }
1117 #endif
1118               }
1119           }
1120       }
1121 }
1122
1123
1124 /* Sweep a string variable to the positon of sweep_frame_offset in the 
1125    stack frame, that is a last position of string variables.  */
1126 static void
1127 sweep_string_variable (rtx sweep_var, HOST_WIDE_INT var_size)
1128 {
1129   HOST_WIDE_INT sweep_offset;
1130
1131   switch (GET_CODE (sweep_var))
1132     {
1133     case MEM:
1134       if (GET_CODE (XEXP (sweep_var, 0)) == ADDRESSOF
1135           && GET_CODE (XEXP (XEXP (sweep_var, 0), 0)) == REG)
1136         return;
1137       sweep_offset = AUTO_OFFSET(XEXP (sweep_var, 0));
1138       break;
1139     case CONST_INT:
1140       sweep_offset = INTVAL (sweep_var);
1141       break;
1142     default:
1143       abort ();
1144     }
1145
1146   /* Scan all declarations of variables and fix the offset address of
1147      the variable based on the frame pointer.  */
1148   sweep_string_in_decls (DECL_INITIAL (current_function_decl),
1149                          sweep_offset, var_size);
1150
1151   /* Scan all argument variable and fix the offset address based on
1152      the frame pointer.  */
1153   sweep_string_in_args (DECL_ARGUMENTS (current_function_decl),
1154                         sweep_offset, var_size);
1155
1156   /* For making room for sweep variable, scan all insns and
1157      fix the offset address of the variable that is based on frame pointer.  */
1158   sweep_string_use_of_insns (function_first_insn, sweep_offset, var_size);
1159
1160
1161   /* Clear all the USED bits in operands of all insns and declarations of
1162      local variables.  */
1163   reset_used_flags_for_decls (DECL_INITIAL (current_function_decl));
1164   reset_used_flags_for_insns (function_first_insn);
1165
1166   sweep_frame_offset -= var_size;
1167 }
1168
1169
1170
1171 /* Move an argument to the local variable addressed by frame_offset.  */
1172 static void
1173 move_arg_location (rtx insn, rtx orig, rtx new, HOST_WIDE_INT var_size)
1174 {
1175   /* For making room for sweep variable, scan all insns and
1176      fix the offset address of the variable that is based on frame pointer.  */
1177   change_arg_use_of_insns (insn, orig, &new, var_size);
1178
1179
1180   /* Clear all the USED bits in operands of all insns and declarations
1181      of local variables.  */
1182   reset_used_flags_for_insns (insn);
1183 }
1184
1185
1186 /* Sweep character arrays declared as local variable.  */
1187 static void
1188 sweep_string_in_decls (tree block, HOST_WIDE_INT sweep_offset,
1189                        HOST_WIDE_INT sweep_size)
1190 {
1191   tree types;
1192   HOST_WIDE_INT offset;
1193   rtx home;
1194
1195   while (block && TREE_CODE(block)==BLOCK)
1196     {
1197       for (types = BLOCK_VARS(block); types; types = TREE_CHAIN(types))
1198         {
1199           /* Skip the declaration that refers an external variable and
1200              also skip an global variable.  */
1201           if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)) {
1202             
1203             if (! DECL_RTL_SET_P (types))
1204               continue;
1205
1206             home = DECL_RTL (types);
1207
1208             /* Process for static local variable.  */
1209             if (GET_CODE (home) == MEM
1210                 && GET_CODE (XEXP (home, 0)) == SYMBOL_REF)
1211               continue;
1212
1213             if (GET_CODE (home) == MEM
1214                 && XEXP (home, 0) == virtual_stack_vars_rtx)
1215               {
1216                 offset = 0;
1217                 
1218                 /* the operand related to the sweep variable.  */
1219                 if (sweep_offset <= offset
1220                     && offset < sweep_offset + sweep_size)
1221                   {
1222                     offset = sweep_frame_offset - sweep_size - sweep_offset;
1223
1224                     XEXP (home, 0) = plus_constant (virtual_stack_vars_rtx,
1225                                                     offset);
1226                     XEXP (home, 0)->used = 1;
1227                   }
1228                 else if (sweep_offset <= offset
1229                          && offset < sweep_frame_offset)
1230                   {
1231                     /* the rest of variables under sweep_frame_offset,
1232                        shift the location.  */
1233                     XEXP (home, 0) = plus_constant (virtual_stack_vars_rtx,
1234                                                     -sweep_size);
1235                     XEXP (home, 0)->used = 1;
1236                   }
1237               }
1238                 
1239             if (GET_CODE (home) == MEM
1240                 && GET_CODE (XEXP (home, 0)) == MEM)
1241               {
1242                 /* Process for dynamically allocated array.  */
1243                 home = XEXP (home, 0);
1244               }
1245                 
1246             if (GET_CODE (home) == MEM
1247                 && GET_CODE (XEXP (home, 0)) == PLUS
1248                 && XEXP (XEXP (home, 0), 0) == virtual_stack_vars_rtx
1249                 && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
1250               {
1251                 if (! XEXP (home, 0)->used)
1252                   {
1253                     offset = AUTO_OFFSET(XEXP (home, 0));
1254
1255                     /* the operand related to the sweep variable.  */
1256                     if (sweep_offset <= offset
1257                         && offset < sweep_offset + sweep_size)
1258                       {
1259
1260                         offset
1261                           += sweep_frame_offset - sweep_size - sweep_offset;
1262                         XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode,
1263                                                                       offset);
1264
1265                         /* mark */
1266                         XEXP (home, 0)->used = 1;
1267                       }
1268                     else if (sweep_offset <= offset
1269                              && offset < sweep_frame_offset)
1270                       {
1271                         /* the rest of variables under sweep_frame_offset,
1272                            so shift the location.  */
1273
1274                         XEXP (XEXP (home, 0), 1)
1275                           = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);
1276
1277                         /* mark */
1278                         XEXP (home, 0)->used = 1;
1279                       }
1280                   }
1281               }
1282           }
1283         }
1284
1285       sweep_string_in_decls (BLOCK_SUBBLOCKS (block),
1286                              sweep_offset, sweep_size);
1287
1288       block = BLOCK_CHAIN (block);
1289     }
1290 }
1291
1292
1293 /* Sweep character arrays declared as argument.  */
1294 static void
1295 sweep_string_in_args (tree parms, HOST_WIDE_INT sweep_offset,
1296                       HOST_WIDE_INT sweep_size)
1297 {
1298   rtx home;
1299   HOST_WIDE_INT offset;
1300     
1301   for (; parms; parms = TREE_CHAIN (parms))
1302     if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
1303       {
1304         if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
1305           {
1306             home = DECL_INCOMING_RTL (parms);
1307
1308             if (XEXP (home, 0)->used)
1309               continue;
1310
1311             offset = AUTO_OFFSET(XEXP (home, 0));
1312
1313             /* the operand related to the sweep variable.  */
1314             if (AUTO_BASEPTR (XEXP (home, 0)) == virtual_stack_vars_rtx)
1315               {
1316                 if (sweep_offset <= offset
1317                     && offset < sweep_offset + sweep_size)
1318                   {
1319                     offset += sweep_frame_offset - sweep_size - sweep_offset;
1320                     XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode,
1321                                                                   offset);
1322
1323                     /* mark */
1324                     XEXP (home, 0)->used = 1;
1325                   }
1326                 else if (sweep_offset <= offset
1327                          && offset < sweep_frame_offset)
1328                   {
1329                     /* the rest of variables under sweep_frame_offset,
1330                        shift the location.  */
1331                     XEXP (XEXP (home, 0), 1)
1332                       = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);
1333
1334                     /* mark */
1335                     XEXP (home, 0)->used = 1;
1336                   }
1337               }
1338           }
1339       }
1340 }
1341
1342
1343 /* Set to 1 when the instruction contains virtual registers.  */
1344 static int has_virtual_reg;
1345
1346 /* Sweep the specified character array for every insns. The array starts from
1347    the sweep_offset and its size is sweep_size.  */
1348 static void
1349 sweep_string_use_of_insns (rtx insn, HOST_WIDE_INT sweep_offset,
1350                            HOST_WIDE_INT sweep_size)
1351 {
1352   for (; insn; insn = NEXT_INSN (insn))
1353     if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
1354         || GET_CODE (insn) == CALL_INSN)
1355       {
1356         has_virtual_reg = FALSE;
1357         sweep_string_in_operand (insn, &PATTERN (insn),
1358                                  sweep_offset, sweep_size);
1359         sweep_string_in_operand (insn, &REG_NOTES (insn),
1360                                  sweep_offset, sweep_size);
1361       }
1362 }
1363
1364
1365 /* Sweep the specified character array, which starts from the sweep_offset and
1366    its size is sweep_size.
1367
1368    When a pointer is given,
1369    if it points the address higher than the array, it stays.
1370    if it points the address inside the array, it changes to point inside
1371    the sweeped array.
1372    if it points the address lower than the array, it shifts higher address by
1373    the sweep_size.  */
1374 static void
1375 sweep_string_in_operand (rtx insn, rtx *loc,
1376                          HOST_WIDE_INT sweep_offset, HOST_WIDE_INT sweep_size)
1377 {
1378   rtx x = *loc;
1379   enum rtx_code code;
1380   int i, j, k = 0;
1381   HOST_WIDE_INT offset;
1382   const char *fmt;
1383
1384   if (x == 0)
1385     return;
1386
1387   code = GET_CODE (x);
1388
1389   switch (code)
1390     {
1391     case CONST_INT:
1392     case CONST_DOUBLE:
1393     case CONST:
1394     case SYMBOL_REF:
1395     case CODE_LABEL:
1396     case PC:
1397     case CC0:
1398     case ASM_INPUT:
1399     case ADDR_VEC:
1400     case ADDR_DIFF_VEC:
1401     case RETURN:
1402     case ADDRESSOF:
1403       return;
1404             
1405     case REG:
1406       if (x == virtual_incoming_args_rtx
1407           || x == virtual_stack_vars_rtx
1408           || x == virtual_stack_dynamic_rtx
1409           || x == virtual_outgoing_args_rtx
1410           || x == virtual_cfa_rtx)
1411         has_virtual_reg = TRUE;
1412       return;
1413       
1414     case SET:
1415       /*
1416         skip setjmp setup insn and setjmp restore insn
1417         Example:
1418         (set (MEM (reg:SI xx)) (virtual_stack_vars_rtx)))
1419         (set (virtual_stack_vars_rtx) (REG))
1420       */
1421       if (GET_CODE (XEXP (x, 0)) == MEM
1422           && XEXP (x, 1) == virtual_stack_vars_rtx)
1423         return;
1424       if (XEXP (x, 0) == virtual_stack_vars_rtx
1425           && GET_CODE (XEXP (x, 1)) == REG)
1426         return;
1427       break;
1428             
1429     case PLUS:
1430       /* Handle typical case of frame register plus constant.  */
1431       if (XEXP (x, 0) == virtual_stack_vars_rtx
1432           && GET_CODE (XEXP (x, 1)) == CONST_INT)
1433         {
1434           if (x->used)
1435             goto single_use_of_virtual_reg;
1436           
1437           offset = AUTO_OFFSET(x);
1438
1439           /* When arguments grow downward, the virtual incoming
1440              args pointer points to the top of the argument block,
1441              so block is identified by the pointer - 1.
1442              The flag is set at the copy_rtx_and_substitute in integrate.c  */
1443           if (RTX_INTEGRATED_P (x))
1444             k = -1;
1445
1446           /* the operand related to the sweep variable.  */
1447           if (sweep_offset <= offset + k
1448               && offset + k < sweep_offset + sweep_size)
1449             {
1450               offset += sweep_frame_offset - sweep_size - sweep_offset;
1451
1452               XEXP (x, 0) = virtual_stack_vars_rtx;
1453               XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
1454               x->used = 1;
1455             }
1456           else if (sweep_offset <= offset + k
1457                    && offset + k < sweep_frame_offset)
1458             {
1459               /* the rest of variables under sweep_frame_offset,
1460                  shift the location.  */
1461               XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);
1462               x->used = 1;
1463             }
1464           
1465         single_use_of_virtual_reg:
1466           if (has_virtual_reg) {
1467             /* excerpt from insn_invalid_p in recog.c  */
1468             int icode = recog_memoized (insn);
1469
1470             if (icode < 0 && asm_noperands (PATTERN (insn)) < 0)
1471               {
1472                 rtx temp, seq;
1473                 
1474                 start_sequence ();
1475                 temp = force_operand (x, NULL_RTX);
1476                 seq = get_insns ();
1477                 end_sequence ();
1478                 
1479                 emit_insn_before (seq, insn);
1480                 if (! validate_change (insn, loc, temp, 0)
1481                     && !validate_replace_rtx (x, temp, insn))
1482                   fatal_insn ("sweep_string_in_operand", insn);
1483               }
1484           }
1485
1486           has_virtual_reg = TRUE;
1487           return;
1488         }
1489
1490 #ifdef FRAME_GROWS_DOWNWARD
1491       /* Alert the case of frame register plus constant given by reg.  */
1492       else if (XEXP (x, 0) == virtual_stack_vars_rtx
1493                && GET_CODE (XEXP (x, 1)) == REG)
1494         fatal_insn ("sweep_string_in_operand: unknown addressing", insn);
1495 #endif
1496
1497       /*
1498         process further subtree:
1499         Example:  (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
1500         (const_int 5))
1501       */
1502       break;
1503
1504     case CALL_PLACEHOLDER:
1505       for (i = 0; i < 3; i++)
1506         {
1507           rtx seq = XEXP (x, i);
1508           if (seq)
1509             {
1510               push_to_sequence (seq);
1511               sweep_string_use_of_insns (XEXP (x, i),
1512                                          sweep_offset, sweep_size);
1513               XEXP (x, i) = get_insns ();
1514               end_sequence ();
1515             }
1516         }
1517       break;
1518
1519     default:
1520       break;
1521     }
1522
1523   /* Scan all subexpressions.  */
1524   fmt = GET_RTX_FORMAT (code);
1525   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
1526     if (*fmt == 'e')
1527       {
1528         /*
1529           virtual_stack_vars_rtx without offset
1530           Example:
1531             (set (reg:SI xx) (reg:SI 78))
1532             (set (reg:SI xx) (MEM (reg:SI 78)))
1533         */
1534         if (XEXP (x, i) == virtual_stack_vars_rtx)
1535           fatal_insn ("sweep_string_in_operand: unknown fp usage", insn);
1536         sweep_string_in_operand (insn, &XEXP (x, i), sweep_offset, sweep_size);
1537       }
1538     else if (*fmt == 'E')
1539       for (j = 0; j < XVECLEN (x, i); j++)
1540         sweep_string_in_operand (insn, &XVECEXP (x, i, j), sweep_offset, sweep_size);
1541 }   
1542
1543
1544 /* Change the use of an argument to the use of the duplicated variable for
1545    every insns, The variable is addressed by new rtx.  */
1546 static void
1547 change_arg_use_of_insns (rtx insn, rtx orig, rtx *new, HOST_WIDE_INT size)
1548 {
1549   for (; insn; insn = NEXT_INSN (insn))
1550     if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
1551         || GET_CODE (insn) == CALL_INSN)
1552       {
1553         rtx seq;
1554         
1555         start_sequence ();
1556         change_arg_use_in_operand (insn, PATTERN (insn), orig, new, size);
1557
1558         seq = get_insns ();
1559         end_sequence ();
1560         emit_insn_before (seq, insn);
1561
1562         /* load_multiple insn from virtual_incoming_args_rtx have several
1563            load insns. If every insn change the load address of arg
1564            to frame region, those insns are moved before the PARALLEL insn
1565            and remove the PARALLEL insn.  */
1566         if (GET_CODE (PATTERN (insn)) == PARALLEL
1567             && XVECLEN (PATTERN (insn), 0) == 0)
1568           delete_insn (insn);
1569       }
1570 }
1571
1572
1573 /* Change the use of an argument to the use of the duplicated variable for
1574    every rtx derived from the x.  */
1575 static void
1576 change_arg_use_in_operand (rtx insn, rtx x, rtx orig, rtx *new, HOST_WIDE_INT size)
1577 {
1578   enum rtx_code code;
1579   int i, j;
1580   HOST_WIDE_INT offset;
1581   const char *fmt;
1582
1583   if (x == 0)
1584     return;
1585
1586   code = GET_CODE (x);
1587
1588   switch (code)
1589     {
1590     case CONST_INT:
1591     case CONST_DOUBLE:
1592     case CONST:
1593     case SYMBOL_REF:
1594     case CODE_LABEL:
1595     case PC:
1596     case CC0:
1597     case ASM_INPUT:
1598     case ADDR_VEC:
1599     case ADDR_DIFF_VEC:
1600     case RETURN:
1601     case REG:
1602     case ADDRESSOF:
1603       return;
1604
1605     case MEM:
1606       /* Handle special case of MEM (incoming_args).  */
1607       if (GET_CODE (orig) == MEM
1608           && XEXP (x, 0) == virtual_incoming_args_rtx)
1609         {
1610           offset = 0;
1611
1612           /* the operand related to the sweep variable.  */
1613           if (AUTO_OFFSET(XEXP (orig, 0)) <= offset &&
1614               offset < AUTO_OFFSET(XEXP (orig, 0)) + size) {
1615
1616             offset = AUTO_OFFSET(XEXP (*new, 0))
1617               + (offset - AUTO_OFFSET(XEXP (orig, 0)));
1618
1619             XEXP (x, 0) = plus_constant (virtual_stack_vars_rtx, offset);
1620             XEXP (x, 0)->used = 1;
1621
1622             return;
1623           }
1624         }
1625       break;
1626       
1627     case PLUS:
1628       /* Handle special case of frame register plus constant.  */
1629       if (GET_CODE (orig) == MEM
1630           && XEXP (x, 0) == virtual_incoming_args_rtx
1631           && GET_CODE (XEXP (x, 1)) == CONST_INT
1632           && ! x->used)
1633         {
1634           offset = AUTO_OFFSET(x);
1635
1636           /* the operand related to the sweep variable.  */
1637           if (AUTO_OFFSET(XEXP (orig, 0)) <= offset &&
1638               offset < AUTO_OFFSET(XEXP (orig, 0)) + size)
1639             {
1640
1641               offset = (AUTO_OFFSET(XEXP (*new, 0))
1642                         + (offset - AUTO_OFFSET(XEXP (orig, 0))));
1643
1644               XEXP (x, 0) = virtual_stack_vars_rtx;
1645               XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
1646               x->used = 1;
1647
1648               return;
1649             }
1650
1651           /*
1652             process further subtree:
1653             Example:  (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
1654             (const_int 5))
1655           */
1656         }
1657       break;
1658
1659     case SET:
1660       /* Handle special case of "set (REG or MEM) (incoming_args)".
1661          It means that the the address of the 1st argument is stored.  */
1662       if (GET_CODE (orig) == MEM
1663           && XEXP (x, 1) == virtual_incoming_args_rtx)
1664         {
1665           offset = 0;
1666
1667           /* the operand related to the sweep variable.  */
1668           if (AUTO_OFFSET(XEXP (orig, 0)) <= offset &&
1669               offset < AUTO_OFFSET(XEXP (orig, 0)) + size)
1670             {
1671               offset = (AUTO_OFFSET(XEXP (*new, 0))
1672                         + (offset - AUTO_OFFSET(XEXP (orig, 0))));
1673
1674               XEXP (x, 1) = force_operand (plus_constant (virtual_stack_vars_rtx,
1675                                                           offset), NULL_RTX);
1676               XEXP (x, 1)->used = 1;
1677
1678               return;
1679             }
1680         }
1681       break;
1682
1683     case CALL_PLACEHOLDER:
1684       for (i = 0; i < 3; i++)
1685         {
1686           rtx seq = XEXP (x, i);
1687           if (seq)
1688             {
1689               push_to_sequence (seq);
1690               change_arg_use_of_insns (XEXP (x, i), orig, new, size);
1691               XEXP (x, i) = get_insns ();
1692               end_sequence ();
1693             }
1694         }
1695       break;
1696
1697     case PARALLEL:
1698       for (j = 0; j < XVECLEN (x, 0); j++)
1699         {
1700           change_arg_use_in_operand (insn, XVECEXP (x, 0, j), orig, new, size);
1701         }
1702       if (recog_memoized (insn) < 0)
1703         {
1704           for (i = 0, j = 0; j < XVECLEN (x, 0); j++)
1705             {
1706               /* if parallel insn has a insn used virtual_incoming_args_rtx,
1707                  the insn is removed from this PARALLEL insn.  */
1708               if (check_used_flag (XVECEXP (x, 0, j)))
1709                 {
1710                   emit_insn (XVECEXP (x, 0, j));
1711                   XVECEXP (x, 0, j) = NULL;
1712                 }
1713               else
1714                 XVECEXP (x, 0, i++) = XVECEXP (x, 0, j);
1715             }
1716           PUT_NUM_ELEM (XVEC (x, 0), i);
1717         }
1718       return;
1719
1720     default:
1721       break;
1722     }
1723
1724   /* Scan all subexpressions.  */
1725   fmt = GET_RTX_FORMAT (code);
1726   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
1727     if (*fmt == 'e')
1728       {
1729         if (XEXP (x, i) == orig)
1730           {
1731             if (*new == 0)
1732               *new = gen_reg_rtx (GET_MODE (orig));
1733             XEXP (x, i) = *new;
1734             continue;
1735           }
1736         change_arg_use_in_operand (insn, XEXP (x, i), orig, new, size);
1737       }
1738     else if (*fmt == 'E')
1739       for (j = 0; j < XVECLEN (x, i); j++)
1740         {
1741           if (XVECEXP (x, i, j) == orig)
1742             {
1743               if (*new == 0)
1744                 *new = gen_reg_rtx (GET_MODE (orig));
1745               XVECEXP (x, i, j) = *new;
1746               continue;
1747             }
1748           change_arg_use_in_operand (insn, XVECEXP (x, i, j), orig, new, size);
1749         }
1750 }   
1751
1752
1753 /* Validate every instructions from the specified instruction.
1754    
1755    The stack protector prohibits to generate machine specific frame addressing
1756    for the first rtl generation. The prepare_stack_protection must convert
1757    machine independent frame addressing to machine specific frame addressing,
1758    so instructions for inline functions, which skip the conversion of
1759    the stack protection, validate every instructions.  */
1760 static void
1761 validate_insns_of_varrefs (rtx insn)
1762 {
1763   rtx next;
1764
1765   /* Initialize recognition, indicating that volatile is OK.  */
1766   init_recog ();
1767
1768   for (; insn; insn = next)
1769     {
1770       next = NEXT_INSN (insn);
1771       if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
1772           || GET_CODE (insn) == CALL_INSN)
1773         {
1774           /* excerpt from insn_invalid_p in recog.c  */
1775           int icode = recog_memoized (insn);
1776
1777           if (icode < 0 && asm_noperands (PATTERN (insn)) < 0)
1778             validate_operand_of_varrefs (insn, &PATTERN (insn));
1779         }
1780     }
1781
1782   init_recog_no_volatile ();
1783 }
1784
1785
1786 /* Validate frame addressing of the rtx and covert it to machine specific one.  */
1787 static void
1788 validate_operand_of_varrefs (rtx insn, rtx *loc)
1789 {
1790   enum rtx_code code;
1791   rtx x, temp, seq;
1792   int i, j;
1793   const char *fmt;
1794
1795   x = *loc;
1796   if (x == 0)
1797     return;
1798
1799   code = GET_CODE (x);
1800
1801   switch (code)
1802     {
1803     case USE:
1804     case CONST_INT:
1805     case CONST_DOUBLE:
1806     case CONST:
1807     case SYMBOL_REF:
1808     case CODE_LABEL:
1809     case PC:
1810     case CC0:
1811     case ASM_INPUT:
1812     case ADDR_VEC:
1813     case ADDR_DIFF_VEC:
1814     case RETURN:
1815     case REG:
1816     case ADDRESSOF:
1817       return;
1818
1819     case PLUS:
1820       /* validate insn of frame register plus constant.  */
1821       if (GET_CODE (x) == PLUS
1822           && XEXP (x, 0) == virtual_stack_vars_rtx
1823           && GET_CODE (XEXP (x, 1)) == CONST_INT)
1824         {
1825           start_sequence ();
1826
1827           { /* excerpt from expand_binop in optabs.c  */
1828             optab binoptab = add_optab;
1829             enum machine_mode mode = GET_MODE (x);
1830             int icode = (int) binoptab->handlers[(int) mode].insn_code;
1831             enum machine_mode mode1 = insn_data[icode].operand[2].mode;
1832             rtx pat;
1833             rtx xop0 = XEXP (x, 0), xop1 = XEXP (x, 1);
1834             temp = gen_reg_rtx (mode);
1835
1836             /* Now, if insn's predicates don't allow offset operands,
1837                put them into pseudo regs.  */
1838
1839             if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)
1840                 && mode1 != VOIDmode)
1841               xop1 = copy_to_mode_reg (mode1, xop1);
1842
1843             pat = GEN_FCN (icode) (temp, xop0, xop1);
1844             if (pat)
1845               emit_insn (pat);
1846             else
1847               abort (); /* there must be add_optab handler.  */
1848           }           
1849           seq = get_insns ();
1850           end_sequence ();
1851           
1852           emit_insn_before (seq, insn);
1853           if (! validate_change (insn, loc, temp, 0))
1854             abort ();
1855           return;
1856         }
1857         break;
1858       
1859
1860     case CALL_PLACEHOLDER:
1861       for (i = 0; i < 3; i++)
1862         {
1863           rtx seq = XEXP (x, i);
1864           if (seq)
1865             {
1866               push_to_sequence (seq);
1867               validate_insns_of_varrefs (XEXP (x, i));
1868               XEXP (x, i) = get_insns ();
1869               end_sequence ();
1870             }
1871         }
1872       break;
1873
1874     default:
1875       break;
1876     }
1877
1878   /* Scan all subexpressions.  */
1879   fmt = GET_RTX_FORMAT (code);
1880   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
1881     if (*fmt == 'e')
1882       validate_operand_of_varrefs (insn, &XEXP (x, i));
1883     else if (*fmt == 'E')
1884       for (j = 0; j < XVECLEN (x, i); j++)
1885         validate_operand_of_varrefs (insn, &XVECEXP (x, i, j));
1886 }
1887
1888
1889
1890 /* Return size that is not allocated for stack frame. It will be allocated
1891    to modify the home of pseudo registers called from global_alloc.  */
1892 HOST_WIDE_INT
1893 get_frame_free_size (void)
1894 {
1895   if (! flag_propolice_protection)
1896     return 0;
1897
1898   return push_allocated_offset - push_frame_offset;
1899 }
1900
1901
1902 /* The following codes are invoked after the instantiation of pseudo registers.
1903
1904    Reorder local variables to place a peudo register after buffers to avoid
1905    the corruption of local variables that could be used to further corrupt
1906    arbitrary memory locations.  */
1907 #if !defined(FRAME_GROWS_DOWNWARD) && defined(STACK_GROWS_DOWNWARD)
1908 static void push_frame (HOST_WIDE_INT, HOST_WIDE_INT);
1909 static void push_frame_in_decls (tree, HOST_WIDE_INT, HOST_WIDE_INT);
1910 static void push_frame_in_args (tree, HOST_WIDE_INT, HOST_WIDE_INT);
1911 static void push_frame_of_insns (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
1912 static void push_frame_in_operand (rtx, rtx, HOST_WIDE_INT, HOST_WIDE_INT);
1913 static void push_frame_of_reg_equiv_memory_loc (HOST_WIDE_INT, HOST_WIDE_INT);
1914 static void push_frame_of_reg_equiv_constant (HOST_WIDE_INT, HOST_WIDE_INT);
1915 static void reset_used_flags_for_push_frame (void);
1916 static int check_out_of_frame_access (rtx, HOST_WIDE_INT);
1917 static int check_out_of_frame_access_in_operand (rtx, HOST_WIDE_INT);
1918 #endif
1919
1920
1921 /* Assign stack local at the stage of register allocater. if a pseudo reg is
1922    spilled out from such an allocation, it is allocated on the stack.
1923    The protector keep the location be lower stack region than the location of
1924    sweeped arrays.  */
1925 rtx
1926 assign_stack_local_for_pseudo_reg (enum machine_mode mode,
1927                                    HOST_WIDE_INT size, int align)
1928 {
1929 #if defined(FRAME_GROWS_DOWNWARD) || !defined(STACK_GROWS_DOWNWARD)
1930   return assign_stack_local (mode, size, align);
1931 #else
1932   tree blocks = DECL_INITIAL (current_function_decl);
1933   rtx new;
1934   HOST_WIDE_INT saved_frame_offset, units_per_push, starting_frame;
1935   int first_call_from_purge_addressof, first_call_from_global_alloc;
1936
1937   if (! flag_propolice_protection
1938       || size == 0
1939       || ! blocks
1940       || current_function_is_inlinable
1941       || ! search_string_from_argsandvars (CALL_FROM_PUSH_FRAME)
1942       || current_function_contains_functions)
1943     return assign_stack_local (mode, size, align);
1944
1945   first_call_from_purge_addressof = !push_frame_offset && !cse_not_expected;
1946   first_call_from_global_alloc = !saved_cse_not_expected && cse_not_expected;
1947   saved_cse_not_expected = cse_not_expected;
1948
1949   starting_frame = ((STARTING_FRAME_OFFSET)
1950                     ? STARTING_FRAME_OFFSET : BIGGEST_ALIGNMENT / BITS_PER_UNIT);
1951   units_per_push = MAX (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
1952                         GET_MODE_SIZE (mode));
1953     
1954   if (first_call_from_purge_addressof)
1955     {
1956       push_frame_offset = push_allocated_offset;
1957       if (check_out_of_frame_access (get_insns (), starting_frame))
1958         {
1959           /* After the purge_addressof stage, there may be an instruction which
1960              have the pointer less than the starting_frame. 
1961              if there is an access below frame, push dummy region to seperate
1962              the address of instantiated variables.  */
1963           push_frame (GET_MODE_SIZE (DImode), 0);
1964           assign_stack_local (BLKmode, GET_MODE_SIZE (DImode), -1);
1965         }
1966     }
1967
1968   if (first_call_from_global_alloc)
1969     {
1970       push_frame_offset = push_allocated_offset = 0;
1971       if (check_out_of_frame_access (get_insns (), starting_frame))
1972         {
1973           if (STARTING_FRAME_OFFSET)
1974             {
1975               /* if there is an access below frame, push dummy region 
1976                  to seperate the address of instantiated variables.  */
1977               push_frame (GET_MODE_SIZE (DImode), 0);
1978               assign_stack_local (BLKmode, GET_MODE_SIZE (DImode), -1);
1979             }
1980           else
1981             push_allocated_offset = starting_frame;
1982         }
1983     }
1984
1985   saved_frame_offset = frame_offset;
1986   frame_offset = push_frame_offset;
1987
1988   new = assign_stack_local (mode, size, align);
1989
1990   push_frame_offset = frame_offset;
1991   frame_offset = saved_frame_offset;
1992   
1993   if (push_frame_offset > push_allocated_offset)
1994     {
1995       push_frame (units_per_push,
1996                   push_allocated_offset + STARTING_FRAME_OFFSET);
1997
1998       assign_stack_local (BLKmode, units_per_push, -1);
1999       push_allocated_offset += units_per_push;
2000     }
2001
2002   /* At the second call from global alloc, alpha push frame and assign
2003      a local variable to the top of the stack.  */
2004   if (first_call_from_global_alloc && STARTING_FRAME_OFFSET == 0)
2005     push_frame_offset = push_allocated_offset = 0;
2006
2007   return new;
2008 #endif
2009 }
2010
2011
2012 #if !defined(FRAME_GROWS_DOWNWARD) && defined(STACK_GROWS_DOWNWARD)
2013
2014 /* push frame infomation for instantiating pseudo register at the top of stack.
2015    This is only for the "frame grows upward", it means FRAME_GROWS_DOWNWARD is 
2016    not defined.
2017
2018    It is called by purge_addressof function and global_alloc (or reload)
2019    function.  */
2020 static void
2021 push_frame (HOST_WIDE_INT var_size, HOST_WIDE_INT boundary)
2022 {
2023   reset_used_flags_for_push_frame();
2024
2025   /* Scan all declarations of variables and fix the offset address of
2026      the variable based on the frame pointer.  */
2027   push_frame_in_decls (DECL_INITIAL (current_function_decl),
2028                        var_size, boundary);
2029
2030   /* Scan all argument variable and fix the offset address based on
2031      the frame pointer.  */
2032   push_frame_in_args (DECL_ARGUMENTS (current_function_decl),
2033                       var_size, boundary);
2034
2035   /* Scan all operands of all insns and fix the offset address
2036      based on the frame pointer.  */
2037   push_frame_of_insns (get_insns (), var_size, boundary);
2038
2039   /* Scan all reg_equiv_memory_loc and reg_equiv_constant.  */
2040   push_frame_of_reg_equiv_memory_loc (var_size, boundary);
2041   push_frame_of_reg_equiv_constant (var_size, boundary);
2042
2043   reset_used_flags_for_push_frame();
2044 }
2045
2046
2047 /* Reset used flag of every insns, reg_equiv_memory_loc,
2048    and reg_equiv_constant.  */
2049 static void
2050 reset_used_flags_for_push_frame(void)
2051 {
2052   int i;
2053   extern rtx *reg_equiv_memory_loc;
2054   extern rtx *reg_equiv_constant;
2055
2056   /* Clear all the USED bits in operands of all insns and declarations of
2057      local vars.  */
2058   reset_used_flags_for_decls (DECL_INITIAL (current_function_decl));
2059   reset_used_flags_for_insns (get_insns ());
2060
2061
2062   /* The following codes are processed if the push_frame is called from 
2063      global_alloc (or reload) function.  */
2064   if (reg_equiv_memory_loc == 0)
2065     return;
2066
2067   for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
2068     if (reg_equiv_memory_loc[i])
2069       {
2070         rtx x = reg_equiv_memory_loc[i];
2071
2072         if (GET_CODE (x) == MEM
2073             && GET_CODE (XEXP (x, 0)) == PLUS
2074             && AUTO_BASEPTR (XEXP (x, 0)) == frame_pointer_rtx)
2075           {
2076             /* reset */
2077             XEXP (x, 0)->used = 0;
2078           }
2079       }
2080
2081   
2082   if (reg_equiv_constant == 0)
2083     return;
2084
2085   for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
2086     if (reg_equiv_constant[i])
2087       {
2088         rtx x = reg_equiv_constant[i];
2089
2090         if (GET_CODE (x) == PLUS
2091             && AUTO_BASEPTR (x) == frame_pointer_rtx)
2092           {
2093             /* reset */
2094             x->used = 0;
2095           }
2096       }
2097 }
2098
2099
2100 /* Push every variables declared as a local variable and make a room for
2101    instantiated register.  */
2102 static void
2103 push_frame_in_decls (tree block, HOST_WIDE_INT push_size,
2104                      HOST_WIDE_INT boundary)
2105 {
2106   tree types;
2107   HOST_WIDE_INT offset;
2108   rtx home;
2109
2110   while (block && TREE_CODE(block)==BLOCK)
2111     {
2112       for (types = BLOCK_VARS(block); types; types = TREE_CHAIN(types))
2113         {
2114           /* Skip the declaration that refers an external variable and
2115              also skip an global variable.  */
2116           if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types))
2117             {
2118               if (! DECL_RTL_SET_P (types))
2119                 continue;
2120
2121               home = DECL_RTL (types);
2122
2123               /* Process for static local variable.  */
2124               if (GET_CODE (home) == MEM
2125                   && GET_CODE (XEXP (home, 0)) == SYMBOL_REF)
2126                 continue;
2127
2128               if (GET_CODE (home) == MEM
2129                   && GET_CODE (XEXP (home, 0)) == REG)
2130                 {
2131                   if (XEXP (home, 0) != frame_pointer_rtx
2132                       || boundary != 0)
2133                     continue;
2134
2135                   XEXP (home, 0) = plus_constant (frame_pointer_rtx,
2136                                                   push_size);
2137
2138                   /* mark */
2139                   XEXP (home, 0)->used = 1;
2140                 }
2141                 
2142               if (GET_CODE (home) == MEM
2143                   && GET_CODE (XEXP (home, 0)) == MEM)
2144                 {
2145                   /* Process for dynamically allocated array.  */
2146                   home = XEXP (home, 0);
2147                 }
2148                 
2149               if (GET_CODE (home) == MEM
2150                   && GET_CODE (XEXP (home, 0)) == PLUS
2151                   && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
2152                 {
2153                   offset = AUTO_OFFSET(XEXP (home, 0));
2154
2155                   if (! XEXP (home, 0)->used
2156                       && offset >= boundary)
2157                     {
2158                       offset += push_size;
2159                       XEXP (XEXP (home, 0), 1)
2160                         = gen_rtx_CONST_INT (VOIDmode, offset);
2161                       
2162                       /* mark */
2163                       XEXP (home, 0)->used = 1;
2164                     }
2165                 }
2166             }
2167         }
2168
2169       push_frame_in_decls (BLOCK_SUBBLOCKS (block), push_size, boundary);
2170       block = BLOCK_CHAIN (block);
2171     }
2172 }
2173
2174
2175 /* Push every variables declared as an argument and make a room for
2176    instantiated register.  */
2177 static void
2178 push_frame_in_args (tree parms, HOST_WIDE_INT push_size,
2179                     HOST_WIDE_INT boundary)
2180 {
2181   rtx home;
2182   HOST_WIDE_INT offset;
2183     
2184   for (; parms; parms = TREE_CHAIN (parms))
2185     if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
2186       {
2187         if (PARM_PASSED_IN_MEMORY (parms))
2188           {
2189             home = DECL_INCOMING_RTL (parms);
2190             offset = AUTO_OFFSET(XEXP (home, 0));
2191
2192             if (XEXP (home, 0)->used || offset < boundary)
2193               continue;
2194
2195             /* the operand related to the sweep variable.  */
2196             if (AUTO_BASEPTR (XEXP (home, 0)) == frame_pointer_rtx)
2197               {
2198                 if (XEXP (home, 0) == frame_pointer_rtx)
2199                   XEXP (home, 0) = plus_constant (frame_pointer_rtx,
2200                                                   push_size);
2201                 else {
2202                   offset += push_size;
2203                   XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode,
2204                                                                 offset);
2205                 }
2206
2207                 /* mark */
2208                 XEXP (home, 0)->used = 1;
2209               }
2210           }
2211       }
2212 }
2213
2214
2215 /* Set to 1 when the instruction has the reference to be pushed.  */
2216 static int insn_pushed;
2217
2218 /* Tables of equivalent registers with frame pointer.  */
2219 static int *fp_equiv = 0;
2220
2221
2222 /* Push the frame region to make a room for allocated local variable.  */
2223 static void
2224 push_frame_of_insns (rtx insn, HOST_WIDE_INT push_size, HOST_WIDE_INT boundary)
2225 {
2226   /* init fp_equiv */
2227   fp_equiv = (int *) xcalloc (max_reg_num (), sizeof (int));
2228                 
2229   for (; insn; insn = NEXT_INSN (insn))
2230     if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
2231         || GET_CODE (insn) == CALL_INSN)
2232       {
2233         rtx last;
2234         
2235         insn_pushed = FALSE;
2236
2237         /* Push frame in INSN operation.  */
2238         push_frame_in_operand (insn, PATTERN (insn), push_size, boundary);
2239
2240         /* Push frame in NOTE.  */
2241         push_frame_in_operand (insn, REG_NOTES (insn), push_size, boundary);
2242
2243         /* Push frame in CALL EXPR_LIST.  */
2244         if (GET_CODE (insn) == CALL_INSN)
2245           push_frame_in_operand (insn, CALL_INSN_FUNCTION_USAGE (insn),
2246                                  push_size, boundary);
2247
2248         /* Pushed frame addressing style may not be machine specific one.
2249            so the instruction should be converted to use the machine specific
2250            frame addressing.  */
2251         if (insn_pushed
2252             && (last = try_split (PATTERN (insn), insn, 1)) != insn)
2253           {
2254             rtx first = NEXT_INSN (insn);
2255             rtx trial = NEXT_INSN (first);
2256             rtx pattern = PATTERN (trial);
2257             rtx set;
2258
2259             /* Update REG_EQUIV info to the first splitted insn.  */
2260             if ((set = single_set (insn))
2261                 && find_reg_note (insn, REG_EQUIV, SET_SRC (set))
2262                 && GET_CODE (PATTERN (first)) == SET)
2263               {
2264                 REG_NOTES (first)
2265                   = gen_rtx_EXPR_LIST (REG_EQUIV,
2266                                        SET_SRC (PATTERN (first)),
2267                                        REG_NOTES (first));
2268               }
2269
2270             /* copy the first insn of splitted insns to the original insn and
2271                delete the first insn,
2272                because the original insn is pointed from records:
2273                insn_chain, reg_equiv_init, used for global_alloc.  */
2274             if (cse_not_expected)
2275               {
2276                 add_insn_before (insn, first);
2277                 
2278                 /* Copy the various flags, and other information.  */
2279                 memcpy (insn, first, sizeof (struct rtx_def) - sizeof (rtunion));
2280                 PATTERN (insn) = PATTERN (first);
2281                 REG_NOTES (insn) = REG_NOTES (first);
2282
2283                 /* then remove the first insn of splitted insns.  */
2284                 remove_insn (first);
2285                 INSN_DELETED_P (first) = 1;
2286               }
2287
2288             if (GET_CODE (pattern) == SET
2289                 && GET_CODE (XEXP (pattern, 0)) == REG
2290                 && GET_CODE (XEXP (pattern, 1)) == PLUS
2291                 && XEXP (pattern, 0) == XEXP (XEXP (pattern, 1), 0)
2292                 && GET_CODE (XEXP (XEXP (pattern, 1), 1)) == CONST_INT)
2293               {
2294                 rtx offset = XEXP (XEXP (pattern, 1), 1);
2295                 fp_equiv[REGNO (XEXP (pattern, 0))] = INTVAL (offset);
2296
2297                 delete_insn (trial);
2298               }
2299
2300             insn = last;
2301           }
2302       }
2303
2304   /* Clean up.  */
2305   free (fp_equiv);
2306 }
2307
2308
2309 /* Push the frame region by changing the operand that points the frame.  */
2310 static void
2311 push_frame_in_operand (rtx insn, rtx orig,
2312                        HOST_WIDE_INT push_size, HOST_WIDE_INT boundary)
2313 {
2314   rtx x = orig;
2315   enum rtx_code code;
2316   int i, j;
2317   HOST_WIDE_INT offset;
2318   const char *fmt;
2319
2320   if (x == 0)
2321     return;
2322
2323   code = GET_CODE (x);
2324
2325   switch (code)
2326     {
2327     case CONST_INT:
2328     case CONST_DOUBLE:
2329     case CONST:
2330     case SYMBOL_REF:
2331     case CODE_LABEL:
2332     case PC:
2333     case CC0:
2334     case ASM_INPUT:
2335     case ADDR_VEC:
2336     case ADDR_DIFF_VEC:
2337     case RETURN:
2338     case REG:
2339     case ADDRESSOF:
2340     case USE:
2341       return;
2342             
2343     case SET:
2344       /*
2345         Skip setjmp setup insn and setjmp restore insn
2346         alpha case:
2347         (set (MEM (reg:SI xx)) (frame_pointer_rtx)))
2348         (set (frame_pointer_rtx) (REG))
2349       */
2350       if (GET_CODE (XEXP (x, 0)) == MEM
2351           && XEXP (x, 1) == frame_pointer_rtx)
2352         return;
2353       if (XEXP (x, 0) == frame_pointer_rtx
2354           && GET_CODE (XEXP (x, 1)) == REG)
2355         return;
2356
2357       /*
2358         powerpc case: restores setjmp address
2359         (set (frame_pointer_rtx) (plus frame_pointer_rtx const_int -n))
2360         or
2361         (set (reg) (plus frame_pointer_rtx const_int -n))
2362         (set (frame_pointer_rtx) (reg))
2363       */
2364       if (GET_CODE (XEXP (x, 0)) == REG
2365           && GET_CODE (XEXP (x, 1)) == PLUS
2366           && XEXP (XEXP (x, 1), 0) == frame_pointer_rtx
2367           && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
2368           && INTVAL (XEXP (XEXP (x, 1), 1)) < 0)
2369         {
2370           x = XEXP (x, 1);
2371           offset = AUTO_OFFSET(x);
2372           if (x->used || -offset < boundary)
2373             return;
2374
2375           XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset - push_size);
2376           x->used = 1; insn_pushed = TRUE;
2377           return;
2378         }
2379
2380       /* Reset fp_equiv register.  */
2381       else if (GET_CODE (XEXP (x, 0)) == REG
2382           && fp_equiv[REGNO (XEXP (x, 0))])
2383         fp_equiv[REGNO (XEXP (x, 0))] = 0;
2384
2385       /* Propagete fp_equiv register.  */
2386       else if (GET_CODE (XEXP (x, 0)) == REG
2387                && GET_CODE (XEXP (x, 1)) == REG
2388                && fp_equiv[REGNO (XEXP (x, 1))])
2389         if (REGNO (XEXP (x, 0)) <= LAST_VIRTUAL_REGISTER
2390             || reg_renumber[REGNO (XEXP (x, 0))] > 0)
2391           fp_equiv[REGNO (XEXP (x, 0))] = fp_equiv[REGNO (XEXP (x, 1))];
2392       break;
2393
2394     case MEM:
2395       if (XEXP (x, 0) == frame_pointer_rtx
2396           && boundary == 0)
2397         {
2398           XEXP (x, 0) = plus_constant (frame_pointer_rtx, push_size);
2399           XEXP (x, 0)->used = 1; insn_pushed = TRUE;
2400           return;
2401         }
2402       break;
2403       
2404     case PLUS:
2405       /* Handle special case of frame register plus constant.  */
2406       if (GET_CODE (XEXP (x, 1)) == CONST_INT
2407           && XEXP (x, 0) == frame_pointer_rtx)
2408         {
2409           offset = AUTO_OFFSET(x);
2410
2411           if (x->used || offset < boundary)
2412             return;
2413
2414           XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset + push_size);
2415           x->used = 1; insn_pushed = TRUE;
2416
2417           return;
2418         }
2419       /*
2420         Handle alpha case:
2421          (plus:SI (subreg:SI (reg:DI 63 FP) 0) (const_int 64 [0x40]))
2422       */
2423       if (GET_CODE (XEXP (x, 1)) == CONST_INT
2424           && GET_CODE (XEXP (x, 0)) == SUBREG
2425           && SUBREG_REG (XEXP (x, 0)) == frame_pointer_rtx)
2426         {
2427           offset = AUTO_OFFSET(x);
2428
2429           if (x->used || offset < boundary)
2430             return;
2431
2432           XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset + push_size);
2433           x->used = 1; insn_pushed = TRUE;
2434
2435           return;
2436         }
2437       /*
2438         Handle powerpc case:
2439          (set (reg x) (plus fp const))
2440          (set (.....) (... (plus (reg x) (const B))))
2441       */
2442       else if (GET_CODE (XEXP (x, 1)) == CONST_INT
2443                && GET_CODE (XEXP (x, 0)) == REG
2444                && fp_equiv[REGNO (XEXP (x, 0))])
2445         {
2446           offset = AUTO_OFFSET(x);
2447
2448           if (x->used)
2449             return;
2450
2451           offset += fp_equiv[REGNO (XEXP (x, 0))];
2452
2453           XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
2454           x->used = 1; insn_pushed = TRUE;
2455
2456           return;
2457         }
2458       /*
2459         Handle special case of frame register plus reg (constant).
2460          (set (reg x) (const B))
2461          (set (....) (...(plus fp (reg x))))
2462       */
2463       else if (XEXP (x, 0) == frame_pointer_rtx
2464                && GET_CODE (XEXP (x, 1)) == REG
2465                && PREV_INSN (insn)
2466                && PATTERN (PREV_INSN (insn))
2467                && SET_DEST (PATTERN (PREV_INSN (insn))) == XEXP (x, 1)
2468                && GET_CODE (SET_SRC (PATTERN (PREV_INSN (insn)))) == CONST_INT)
2469         {
2470           offset = INTVAL (SET_SRC (PATTERN (PREV_INSN (insn))));
2471
2472           if (x->used || offset < boundary)
2473             return;
2474           
2475           SET_SRC (PATTERN (PREV_INSN (insn)))
2476             = gen_rtx_CONST_INT (VOIDmode, offset + push_size);
2477           x->used = 1;
2478           XEXP (x, 1)->used = 1;
2479
2480           return;
2481         }
2482       /*
2483         Handle special case of frame register plus reg (used).
2484         The register already have a pushed offset, just mark this frame
2485         addressing.
2486       */
2487       else if (XEXP (x, 0) == frame_pointer_rtx
2488                && XEXP (x, 1)->used)
2489         {
2490           x->used = 1;
2491           return;
2492         }
2493       /*
2494         Process further subtree:
2495         Example:  (plus:SI (mem/s:SI (plus:SI (FP) (const_int 8)))
2496         (const_int 5))
2497       */
2498       break;
2499
2500     case CALL_PLACEHOLDER:
2501       push_frame_of_insns (XEXP (x, 0), push_size, boundary);
2502       push_frame_of_insns (XEXP (x, 1), push_size, boundary);
2503       push_frame_of_insns (XEXP (x, 2), push_size, boundary);
2504       break;
2505
2506     default:
2507       break;
2508     }
2509
2510   /* Scan all subexpressions.  */
2511   fmt = GET_RTX_FORMAT (code);
2512   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
2513     if (*fmt == 'e')
2514       {
2515         if (XEXP (x, i) == frame_pointer_rtx && boundary == 0)
2516           fatal_insn ("push_frame_in_operand", insn);
2517         push_frame_in_operand (insn, XEXP (x, i), push_size, boundary);
2518       }
2519     else if (*fmt == 'E')
2520       for (j = 0; j < XVECLEN (x, i); j++)
2521         push_frame_in_operand (insn, XVECEXP (x, i, j), push_size, boundary);
2522 }   
2523
2524
2525 /* Change the location pointed in reg_equiv_memory_loc.  */
2526 static void
2527 push_frame_of_reg_equiv_memory_loc (HOST_WIDE_INT push_size,
2528                                     HOST_WIDE_INT boundary)
2529 {
2530   int i;
2531   extern rtx *reg_equiv_memory_loc;
2532
2533   /* This function is processed if the push_frame is called from 
2534      global_alloc (or reload) function.  */
2535   if (reg_equiv_memory_loc == 0)
2536     return;
2537
2538   for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
2539     if (reg_equiv_memory_loc[i])
2540       {
2541         rtx x = reg_equiv_memory_loc[i];
2542         int offset;
2543
2544         if (GET_CODE (x) == MEM
2545             && GET_CODE (XEXP (x, 0)) == PLUS
2546             && XEXP (XEXP (x, 0), 0) == frame_pointer_rtx)
2547           {
2548             offset = AUTO_OFFSET(XEXP (x, 0));
2549             
2550             if (! XEXP (x, 0)->used
2551                 && offset >= boundary)
2552               {
2553                 offset += push_size;
2554                 XEXP (XEXP (x, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);
2555
2556                 /* mark */
2557                 XEXP (x, 0)->used = 1;
2558               }
2559           }
2560         else if (GET_CODE (x) == MEM
2561                  && XEXP (x, 0) == frame_pointer_rtx
2562                  && boundary == 0)
2563           {
2564             XEXP (x, 0) = plus_constant (frame_pointer_rtx, push_size);
2565             XEXP (x, 0)->used = 1; insn_pushed = TRUE;
2566           }
2567       }
2568 }
2569
2570
2571 /* Change the location pointed in reg_equiv_constant.  */
2572 static void
2573 push_frame_of_reg_equiv_constant (HOST_WIDE_INT push_size,
2574                                   HOST_WIDE_INT boundary)
2575 {
2576   int i;
2577   extern rtx *reg_equiv_constant;
2578
2579   /* This function is processed if the push_frame is called from 
2580      global_alloc (or reload) function.  */
2581   if (reg_equiv_constant == 0)
2582     return;
2583
2584   for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
2585     if (reg_equiv_constant[i])
2586       {
2587         rtx x = reg_equiv_constant[i];
2588         int offset;
2589
2590         if (GET_CODE (x) == PLUS
2591             && XEXP (x, 0) == frame_pointer_rtx)
2592           {
2593             offset = AUTO_OFFSET(x);
2594             
2595             if (! x->used
2596                 && offset >= boundary)
2597               {
2598                 offset += push_size;
2599                 XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
2600
2601                 /* mark */
2602                 x->used = 1;
2603               }
2604           }
2605         else if (x == frame_pointer_rtx
2606                  && boundary == 0)
2607           {
2608             reg_equiv_constant[i]
2609               = plus_constant (frame_pointer_rtx, push_size);
2610             reg_equiv_constant[i]->used = 1; insn_pushed = TRUE;
2611           }
2612       }
2613 }
2614
2615
2616 /* Check every instructions if insn's memory reference is out of frame.  */
2617 static int
2618 check_out_of_frame_access (rtx insn, HOST_WIDE_INT boundary)
2619 {
2620   for (; insn; insn = NEXT_INSN (insn))
2621     if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
2622         || GET_CODE (insn) == CALL_INSN)
2623       {
2624         if (check_out_of_frame_access_in_operand (PATTERN (insn), boundary))
2625           return TRUE;
2626       }
2627   return FALSE;
2628 }
2629
2630
2631 /* Check every operands if the reference is out of frame.  */
2632 static int
2633 check_out_of_frame_access_in_operand (rtx orig, HOST_WIDE_INT boundary)
2634 {
2635   rtx x = orig;
2636   enum rtx_code code;
2637   int i, j;
2638   const char *fmt;
2639
2640   if (x == 0)
2641     return FALSE;
2642
2643   code = GET_CODE (x);
2644
2645   switch (code)
2646     {
2647     case CONST_INT:
2648     case CONST_DOUBLE:
2649     case CONST:
2650     case SYMBOL_REF:
2651     case CODE_LABEL:
2652     case PC:
2653     case CC0:
2654     case ASM_INPUT:
2655     case ADDR_VEC:
2656     case ADDR_DIFF_VEC:
2657     case RETURN:
2658     case REG:
2659     case ADDRESSOF:
2660       return FALSE;
2661             
2662     case MEM:
2663       if (XEXP (x, 0) == frame_pointer_rtx)
2664         if (0 < boundary)
2665           return TRUE;
2666       break;
2667       
2668     case PLUS:
2669       /* Handle special case of frame register plus constant.  */
2670       if (GET_CODE (XEXP (x, 1)) == CONST_INT
2671           && XEXP (x, 0) == frame_pointer_rtx)
2672         {
2673           if (0 <= AUTO_OFFSET(x)
2674               && AUTO_OFFSET(x) < boundary)
2675             return TRUE;
2676           return FALSE;
2677         }
2678       /*
2679         Process further subtree:
2680         Example:  (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
2681         (const_int 5))
2682       */
2683       break;
2684
2685     case CALL_PLACEHOLDER:
2686       if (check_out_of_frame_access (XEXP (x, 0), boundary))
2687         return TRUE;
2688       if (check_out_of_frame_access (XEXP (x, 1), boundary))
2689         return TRUE;
2690       if (check_out_of_frame_access (XEXP (x, 2), boundary))
2691         return TRUE;
2692       break;
2693
2694     default:
2695       break;
2696     }
2697
2698   /* Scan all subexpressions.  */
2699   fmt = GET_RTX_FORMAT (code);
2700   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
2701     if (*fmt == 'e')
2702       {
2703         if (check_out_of_frame_access_in_operand (XEXP (x, i), boundary))
2704           return TRUE;
2705       }
2706     else if (*fmt == 'E')
2707       for (j = 0; j < XVECLEN (x, i); j++)
2708         if (check_out_of_frame_access_in_operand (XVECEXP (x, i, j), boundary))
2709           return TRUE;
2710
2711   return FALSE;
2712 }
2713 #endif