OSDN Git Service

3e2a0008ef5c869192b8e4fc728d820aa98c456c
[pf3gnuchains/gcc-fork.git] / gcc / config / darwin.c
1 /* Functions for generic Darwin as target machine for GNU C compiler.
2    Copyright (C) 1989, 1990, 1991, 1992, 1993, 2000, 2001
3    Free Software Foundation, Inc.
4    Contributed by Apple Computer Inc.
5
6 This file is part of GNU CC.
7
8 GNU CC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GNU CC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU CC; see the file COPYING.  If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "real.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-flags.h"
32 #include "output.h"
33 #include "insn-attr.h"
34 #include "flags.h"
35 #include "tree.h"
36 #include "expr.h"
37 #include "reload.h"
38 /* need for IDENTIFIER_GLOBAL_VALUE and IDENTIFIER_LOCAL_VALUE */
39 #include "c-tree.h"
40 #include "function.h"
41 #include "ggc.h"
42
43 #include "darwin-protos.h"
44
45 extern void machopic_output_stub PARAMS ((FILE *, const char *, const char *));
46
47 static int machopic_data_defined_p PARAMS ((const char *));
48 static int func_name_maybe_scoped PARAMS ((const char *));
49
50 /* Make everything that used to go in the text section really go there.  */
51
52 int flag_no_mach_text_sections = 0;
53
54 int
55 name_needs_quotes (name)
56      const char *name;
57 {
58   int c;
59   while ((c = *name++) != '\0')
60     if (!isalnum (c) && c != '_')
61       return 1;
62   return 0;
63 }
64
65 /* 
66  * flag_pic = 1 ... generate only indirections
67  * flag_pic = 2 ... generate indirections and pure code
68  */
69
70 /* This module assumes that (const (symbol_ref "foo")) is a legal pic
71    reference, which will not be changed.  */
72
73 static tree machopic_defined_list;
74
75 enum machopic_addr_class
76 machopic_classify_ident (ident)
77      tree ident;
78 {
79   const char *name = IDENTIFIER_POINTER (ident);
80   int lprefix = (((name[0] == '*' || name[0] == '&')
81                   && (name[1] == 'L' || (name[1] == '"' && name[2] == 'L')))
82                  || (   name[0] == '_' 
83                      && name[1] == 'O' 
84                      && name[2] == 'B' 
85                      && name[3] == 'J'
86                      && name[4] == 'C'
87                      && name[5] == '_'));
88   tree temp, decl = lookup_name_darwin (ident);
89
90   if (!decl)
91     {
92       if (lprefix)
93         {
94           const char *name = IDENTIFIER_POINTER (ident);
95           int len = strlen (name);
96
97           if ((len > 5 && !strcmp (name + len - 5, "$stub"))
98               || (len > 6 && !strcmp (name + len - 6, "$stub\"")))
99             return MACHOPIC_DEFINED_FUNCTION;
100           return MACHOPIC_DEFINED_DATA;
101         }
102
103       for (temp = machopic_defined_list;
104            temp != NULL_TREE;
105            temp = TREE_CHAIN (temp))
106         {
107           if (ident == TREE_VALUE (temp))
108             return MACHOPIC_DEFINED_DATA;
109         }
110
111       if (TREE_ASM_WRITTEN (ident))
112         return MACHOPIC_DEFINED_DATA;
113
114       return MACHOPIC_UNDEFINED;
115     }
116
117   /* variable declarations */
118   else if (TREE_CODE (decl) == VAR_DECL)
119     {
120       if ((DECL_INITIAL (decl)
121            || TREE_STATIC (decl))
122           && ! TREE_PUBLIC (decl))
123         return MACHOPIC_DEFINED_DATA;
124     }
125
126   /* function declarations */
127   else if (TREE_CODE (decl) == FUNCTION_DECL
128            && (!DECL_EXTERNAL (decl)))
129     {
130       if (TREE_STATIC (decl)
131           || TREE_ASM_WRITTEN (decl))
132         return MACHOPIC_DEFINED_FUNCTION;
133     }
134
135   for (temp = machopic_defined_list; temp != NULL_TREE; temp = TREE_CHAIN (temp))
136     {
137       if (ident == TREE_VALUE (temp))
138         {
139           if (TREE_CODE (decl) == FUNCTION_DECL)
140             return MACHOPIC_DEFINED_FUNCTION;
141           else
142             return MACHOPIC_DEFINED_DATA;
143         }
144     }
145   
146   if (TREE_CODE (decl) == FUNCTION_DECL)
147     {
148       if (lprefix)
149         return MACHOPIC_DEFINED_FUNCTION;
150       else
151         return MACHOPIC_UNDEFINED_FUNCTION;
152     }
153   else
154     {
155       if (lprefix)
156         return MACHOPIC_DEFINED_DATA;
157       else
158         return MACHOPIC_UNDEFINED_DATA;
159     }
160 }
161
162      
163 enum machopic_addr_class
164 machopic_classify_name (name)
165      const char *name;
166 {
167   return machopic_classify_ident (get_identifier (name));
168 }
169
170 int
171 machopic_ident_defined_p (ident)
172      tree ident;
173 {
174   switch (machopic_classify_ident (ident))
175     {
176     case MACHOPIC_UNDEFINED:
177     case MACHOPIC_UNDEFINED_DATA:
178     case MACHOPIC_UNDEFINED_FUNCTION:
179       return 0;
180     default:
181       return 1;
182     }
183 }
184
185 static int
186 machopic_data_defined_p (name)
187      const char *name;
188 {
189   switch (machopic_classify_ident (get_identifier (name)))
190     {
191     case MACHOPIC_DEFINED_DATA:
192       return 1;
193     default:
194       return 0;
195     }
196 }
197
198 int
199 machopic_name_defined_p (name)
200      const char *name;
201 {
202   return machopic_ident_defined_p (get_identifier (name));
203 }
204
205 void
206 machopic_define_ident (ident)
207      tree ident;
208 {
209   if (!machopic_ident_defined_p (ident))
210     machopic_defined_list = 
211       tree_cons (NULL_TREE, ident, machopic_defined_list);
212 }
213
214 void
215 machopic_define_name (name)
216      const char *name;
217 {
218   machopic_define_ident (get_identifier (name));
219 }
220
221 tree
222 lookup_name_darwin (name)
223      tree name;
224 {
225   tree val;
226
227   if (!global_bindings_p()
228       && IDENTIFIER_LOCAL_VALUE (name))
229     val = IDENTIFIER_LOCAL_VALUE (name);
230   else
231     val = IDENTIFIER_GLOBAL_VALUE (name);
232   return val;
233 }
234
235 /* This is a static to make inline functions work.  The rtx
236    representing the PIC base symbol always points to here. */
237
238 static char function_base[32];
239
240 static int current_pic_label_num;
241
242 char *
243 machopic_function_base_name ()
244 {
245   static char *name = NULL;
246   static const char *current_name;
247
248   current_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
249
250   if (name != current_name)
251     {
252       current_function_uses_pic_offset_table = 1;
253
254       /* Save mucho space and time.  Some of the C++ mangled names are over
255          700 characters long!  Note that we produce a label containing a '-'
256          if the function we're compiling is an Objective-C method, as evinced
257          by the incredibly scientific test below.  This is because code in
258          rs6000.c makes the same ugly test when loading the PIC reg.  */
259  
260       ++current_pic_label_num;
261       if (*current_name == '+' || *current_name == '-')
262         sprintf (function_base, "*\"L-%d$pb\"", current_pic_label_num);
263       else
264         sprintf (function_base, "*L%d$pb", current_pic_label_num);
265
266       name = current_name;
267     }
268
269   return function_base;
270 }
271
272 static tree machopic_non_lazy_pointers = NULL;
273
274 /* Return a non-lazy pointer name corresponding to the given name,
275    either by finding it in our list of pointer names, or by generating
276    a new one.  */
277
278 char * 
279 machopic_non_lazy_ptr_name (name)
280      const char *name;
281 {
282   tree temp, ident = get_identifier (name);
283   
284   for (temp = machopic_non_lazy_pointers;
285        temp != NULL_TREE; 
286        temp = TREE_CHAIN (temp))
287     {
288       if (ident == TREE_VALUE (temp))
289         return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
290     }
291
292   {
293     char *buffer;
294     tree ptr_name;
295
296     buffer = alloca (strlen (name) + 20);
297
298     strcpy (buffer, "&L");
299     if (name[0] == '*')
300       strcat (buffer, name+1);
301     else
302       {
303         strcat (buffer, "_");
304         strcat (buffer, name);
305       }
306       
307     strcat (buffer, "$non_lazy_ptr");
308     ptr_name = get_identifier (buffer);
309
310     machopic_non_lazy_pointers 
311       = tree_cons (ptr_name, ident, machopic_non_lazy_pointers);
312
313     TREE_USED (machopic_non_lazy_pointers) = 0;
314
315     return IDENTIFIER_POINTER (ptr_name);
316   }
317 }
318
319 static tree machopic_stubs = 0;
320
321 /* Make sure the GC knows about our homemade lists.  */
322
323 void
324 machopic_add_gc_roots ()
325 {
326   ggc_add_tree_root (&machopic_defined_list, 1);
327   ggc_add_tree_root (&machopic_non_lazy_pointers, 1);
328   ggc_add_tree_root (&machopic_stubs, 1);
329 }
330
331 /* Return the name of the stub corresponding to the given name,
332    generating a new stub name if necessary.  */
333
334 char * 
335 machopic_stub_name (name)
336      const char *name;
337 {
338   tree temp, ident = get_identifier (name);
339   
340   for (temp = machopic_stubs;
341        temp != NULL_TREE; 
342        temp = TREE_CHAIN (temp))
343     {
344       if (ident == TREE_VALUE (temp))
345         return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
346     }
347
348   {
349     char *buffer;
350     tree ptr_name;
351     int needs_quotes = name_needs_quotes (name);
352
353     buffer = alloca (strlen (name) + 20);
354
355     if (needs_quotes)
356       strcpy (buffer, "&\"L");
357     else
358       strcpy (buffer, "&L");
359     if (name[0] == '*')
360       {
361         strcat (buffer, name+1);
362       }
363     else
364       {
365         strcat (buffer, "_");
366         strcat (buffer, name);
367       }
368
369     if (needs_quotes)
370       strcat (buffer, "$stub\"");
371     else
372       strcat (buffer, "$stub");
373     ptr_name = get_identifier (buffer);
374
375     machopic_stubs = tree_cons (ptr_name, ident, machopic_stubs);
376     TREE_USED (machopic_stubs) = 0;
377
378     return IDENTIFIER_POINTER (ptr_name);
379   }
380 }
381
382 void
383 machopic_validate_stub_or_non_lazy_ptr (name, validate_stub)
384      const char *name;
385      int validate_stub;
386 {
387     tree temp, ident = get_identifier (name);
388
389     for (temp = (validate_stub ? machopic_stubs : machopic_non_lazy_pointers);
390          temp != NULL_TREE;
391          temp = TREE_CHAIN (temp))
392       if (ident == TREE_PURPOSE (temp))
393         {
394           /* Mark both the stub or non-lazy pointer as well as the
395              original symbol as being referenced.  */
396           TREE_USED (temp) = 1;
397           if (TREE_CODE (TREE_VALUE (temp)) == IDENTIFIER_NODE)
398             TREE_SYMBOL_REFERENCED (TREE_VALUE (temp)) = 1;
399         }
400 }
401
402 /* Transform ORIG, which may be any data source, to the corresponding
403    source using indirections.  */
404
405 rtx
406 machopic_indirect_data_reference (orig, reg)
407      rtx orig, reg;
408 {
409   rtx ptr_ref = orig;
410   
411   if (! MACHOPIC_INDIRECT)
412     return orig;
413
414   if (GET_CODE (orig) == SYMBOL_REF)
415     {
416       const char *name = XSTR (orig, 0);
417
418       if (machopic_data_defined_p (name))
419         {
420           rtx pic_base = gen_rtx (SYMBOL_REF, Pmode, 
421                                   machopic_function_base_name ());
422           rtx offset = gen_rtx (CONST, Pmode,
423                                 gen_rtx (MINUS, Pmode, orig, pic_base));
424
425 #if defined (TARGET_TOC) /* i.e., PowerPC */
426           rtx hi_sum_reg = reg;
427
428           if (reg == NULL)
429             abort ();
430
431           emit_insn (gen_rtx (SET, Pmode, hi_sum_reg,
432                               gen_rtx (PLUS, Pmode, pic_offset_table_rtx,
433                                        gen_rtx (HIGH, Pmode, offset))));
434           emit_insn (gen_rtx (SET, Pmode, reg,
435                               gen_rtx (LO_SUM, Pmode, hi_sum_reg, offset)));
436
437           orig = reg;
438 #else
439 #if defined (HAVE_lo_sum)
440           if (reg == 0) abort ();
441
442           emit_insn (gen_rtx (SET, VOIDmode, reg,
443                               gen_rtx (HIGH, Pmode, offset)));
444           emit_insn (gen_rtx (SET, VOIDmode, reg,
445                               gen_rtx (LO_SUM, Pmode, reg, offset)));
446           emit_insn (gen_rtx (USE, VOIDmode,
447                               gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)));
448
449           orig = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, reg);
450 #endif
451 #endif
452           return orig;
453         }
454
455       ptr_ref = gen_rtx (SYMBOL_REF, Pmode,
456                          machopic_non_lazy_ptr_name (name));
457
458       ptr_ref = gen_rtx_MEM (Pmode, ptr_ref);
459       RTX_UNCHANGING_P (ptr_ref) = 1;
460
461       return ptr_ref;
462     }
463   else if (GET_CODE (orig) == CONST)
464     {
465       rtx base, result;
466
467       /* legitimize both operands of the PLUS */
468       if (GET_CODE (XEXP (orig, 0)) == PLUS)
469         {
470           base = machopic_indirect_data_reference (XEXP (XEXP (orig, 0), 0),
471                                                    reg);
472           orig = machopic_indirect_data_reference (XEXP (XEXP (orig, 0), 1),
473                                                    (base == reg ? 0 : reg));
474         }
475       else 
476         return orig;
477
478       if (MACHOPIC_PURE && GET_CODE (orig) == CONST_INT)
479         {
480           result = plus_constant_for_output (base, INTVAL (orig));
481         }
482       else
483         {
484            result = gen_rtx (PLUS, Pmode, base, orig);
485         }
486
487       if (RTX_UNCHANGING_P (base) && RTX_UNCHANGING_P (orig))
488         RTX_UNCHANGING_P (result) = 1;
489
490       if (MACHOPIC_JUST_INDIRECT && GET_CODE (base) == MEM)
491         {
492           if (reg)
493             {
494               emit_move_insn (reg, result);
495               result = reg;
496             }
497           else
498             {
499               result = force_reg (GET_MODE (result), result);
500             }
501         }
502
503       return result;
504
505     }
506   else if (GET_CODE (orig) == MEM)
507     XEXP (ptr_ref, 0) = machopic_indirect_data_reference (XEXP (orig, 0), reg);
508   /* When the target is i386, this code prevents crashes due to the
509      compiler's ignorance on how to move the PIC base register to
510      other registers.  (The reload phase sometimes introduces such
511      insns.)  */
512   else if (GET_CODE (orig) == PLUS
513            && GET_CODE (XEXP (orig, 0)) == REG
514            && REGNO (XEXP (orig, 0)) == PIC_OFFSET_TABLE_REGNUM
515 #ifdef I386
516            /* Prevent the same register from being erroneously used
517               as both the base and index registers.  */
518            && GET_CODE (XEXP (orig, 1)) == CONST
519 #endif
520            && reg)
521     {
522       emit_move_insn (reg, XEXP (orig, 0));
523       XEXP (ptr_ref, 0) = reg;
524     }
525   return ptr_ref;
526 }
527
528 /* For MACHOPIC_INDIRECT_CALL_TARGET below, we need to beware of:
529
530         extern "C" { int f(); }
531         struct X { int f(); int g(); };
532         int X::f() { ::f(); }
533         int X::g() { ::f(); f();}
534
535   This is hairy.  Both calls to "::f()" need to be indirect (i.e., to
536   appropriate symbol stubs), but since MACHOPIC_NAME_DEFINED_P calls
537   GET_IDENTIFIER which treats "f" as "X::f", and "X::f" is indeed (being)
538   defined somewhere in "X"'s inheritance hierarchy, MACHOPIC_NAME_DEFINED_P
539   returns TRUE when called with "f", which means that
540   MACHOPIC_INDIRECT_CALL_TARGET uses an "internal" call instead of an
541   indirect one as it should.
542
543   Our quick-n-dirty solution to this is to call the following
544   FUNC_NAME_MAYBE_SCOPED routine which (only for C++) checks whether
545   FNAME -- the name of the function which we're calling -- is NOT a
546   mangled C++ name, AND if the current function being compiled is a
547   method, and if so, use an "external" or "indirect" call. 
548
549   Note that this function will be called ONLY when MACHOPIC_INDIRECT_TARGET_P
550   has already indicated that the target is NOT indirect.
551
552   This conservative solution will sometimes make indirect calls where
553   it might have been possible to make direct ones.
554
555   FUNC_NAME_MAYBE_SCOPED returns 1 to indicate a "C" name (not scoped),
556   which in turns means we should create a stub for an indirect call.
557   */
558
559 static int is_cplusplus = -1;
560
561 static int
562 func_name_maybe_scoped (fname)
563      const char *fname;
564 {
565
566   if (is_cplusplus < 0)
567     is_cplusplus = (strcmp (lang_identify (), "cplusplus") == 0);
568
569   if (is_cplusplus)
570     {
571       /* If we have a method, then check whether the function we're trying to
572          call is a "C" function.  If so, we should use an indirect call.
573
574          It turns out to be hard to tell whether "we have a method", since
575          static member functions have a TREE_CODE of FUNCTION_TYPE, as do
576          namespace-level non-member functions.  So here, we always look for
577          an extern-"C"-like name, and make stubs for them no matter the
578          calling context.  This is temporary, and leaves nagging suspicion
579          that improvements should be possible here.  (I.e., I suspect that
580          it can still sometimes make stubs where it needn't.)  */
581
582       /* if (1 || TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE) */
583         {
584           /* If fname is of the form "f__1X" or "f__Fv", it's C++.  */
585           while (*fname == '_') ++fname;        /* skip leading underscores  */
586           while (*fname != 0)
587             {
588               if (fname[0] == '_' && fname[1] == '_'
589                   && (fname[2] == 'F' || (fname[2] >= '0' && fname[2] <= '9')))
590                 return 0;
591               ++fname;
592             }
593           /* Not a C++ mangled name: must be "C", in which case play safe.  */
594           return 1;
595         }
596     }
597   return 0;
598 }
599
600 /* Transform TARGET (a MEM), which is a function call target, to the
601    corresponding symbol_stub if necessary.  Return a new MEM.  */
602
603 rtx
604 machopic_indirect_call_target (target)
605      rtx target;
606 {
607   if (GET_CODE (target) != MEM)
608     return target;
609
610   if (MACHOPIC_INDIRECT && GET_CODE (XEXP (target, 0)) == SYMBOL_REF)
611     { 
612       enum machine_mode mode = GET_MODE (XEXP (target, 0));
613       const char *name = XSTR (XEXP (target, 0), 0);
614
615       if (!machopic_name_defined_p (name) || func_name_maybe_scoped (name)) 
616         {
617           const char *stub_name = machopic_stub_name (name);
618
619           XEXP (target, 0) = gen_rtx (SYMBOL_REF, mode, stub_name);
620           RTX_UNCHANGING_P (target) = 1;
621         } 
622     }
623
624   return target;
625 }
626
627 rtx
628 machopic_legitimize_pic_address (orig, mode, reg)
629      rtx orig, reg;
630      enum machine_mode mode;
631 {
632   rtx pic_ref = orig;
633
634   if (! MACHOPIC_PURE)
635     return orig;
636
637   /* First handle a simple SYMBOL_REF or LABEL_REF */
638   if (GET_CODE (orig) == LABEL_REF
639       || (GET_CODE (orig) == SYMBOL_REF
640           ))
641     {
642       /* addr(foo) = &func+(foo-func) */
643       rtx pic_base;
644
645       orig = machopic_indirect_data_reference (orig, reg);
646
647       if (GET_CODE (orig) == PLUS 
648           && GET_CODE (XEXP (orig, 0)) == REG)
649         {
650           if (reg == 0)
651             return force_reg (mode, orig);
652
653           emit_move_insn (reg, orig);
654           return reg;
655         }  
656
657       pic_base = gen_rtx (SYMBOL_REF, Pmode, machopic_function_base_name ());
658
659       if (GET_CODE (orig) == MEM)
660         {
661           if (reg == 0)
662             {
663               if (reload_in_progress)
664                 abort ();
665               else
666                 reg = gen_reg_rtx (Pmode);
667             }
668         
669 #ifdef HAVE_lo_sum
670           if (GET_CODE (XEXP (orig, 0)) == SYMBOL_REF 
671               || GET_CODE (XEXP (orig, 0)) == LABEL_REF)
672             {
673               rtx offset = gen_rtx (CONST, Pmode,
674                                     gen_rtx (MINUS, Pmode,
675                                              XEXP (orig, 0), pic_base));
676 #if defined (TARGET_TOC) /* i.e., PowerPC */
677               /* Generating a new reg may expose opportunities for
678                  common subexpression elimination.  */
679               rtx hi_sum_reg =
680                 (reload_in_progress ? reg : gen_reg_rtx (SImode));
681
682               emit_insn (gen_rtx (SET, Pmode, hi_sum_reg,
683                                   gen_rtx (PLUS, Pmode,
684                                            pic_offset_table_rtx,
685                                            gen_rtx (HIGH, Pmode, offset))));
686               emit_insn (gen_rtx (SET, VOIDmode, reg,
687                                   gen_rtx (MEM, GET_MODE (orig),
688                                            gen_rtx (LO_SUM, Pmode, 
689                                                     hi_sum_reg, offset))));
690               pic_ref = reg;
691
692 #else
693               emit_insn (gen_rtx (USE, VOIDmode,
694                               gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)));
695
696               emit_insn (gen_rtx (SET, VOIDmode, reg,
697                                   gen_rtx (HIGH, Pmode, 
698                                            gen_rtx (CONST, Pmode, offset))));
699               emit_insn (gen_rtx (SET, VOIDmode, reg,
700                                   gen_rtx (LO_SUM, Pmode, reg, 
701                                            gen_rtx (CONST, Pmode, offset))));
702               pic_ref = gen_rtx (PLUS, Pmode,
703                                  pic_offset_table_rtx, reg);
704 #endif
705             }
706           else
707 #endif  /* HAVE_lo_sum */
708             {
709               rtx pic = pic_offset_table_rtx;
710               if (GET_CODE (pic) != REG)
711                 {
712                   emit_move_insn (reg, pic);
713                   pic = reg;
714                 }
715 #if 0
716               emit_insn (gen_rtx (USE, VOIDmode,
717                                   gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM)));
718 #endif
719
720               pic_ref = gen_rtx (PLUS, Pmode,
721                                  pic, 
722                                  gen_rtx (CONST, Pmode, 
723                                           gen_rtx (MINUS, Pmode,
724                                                    XEXP (orig, 0), 
725                                                    pic_base)));
726             }
727           
728 #if !defined (TARGET_TOC)
729           RTX_UNCHANGING_P (pic_ref) = 1;
730           emit_move_insn (reg, pic_ref);
731           pic_ref = gen_rtx (MEM, GET_MODE (orig), reg);
732 #endif
733         }
734       else
735         {
736
737 #ifdef HAVE_lo_sum
738           if (GET_CODE (orig) == SYMBOL_REF 
739               || GET_CODE (orig) == LABEL_REF)
740             {
741               rtx offset = gen_rtx (CONST, Pmode,
742                                     gen_rtx (MINUS, Pmode, orig, pic_base));
743 #if defined (TARGET_TOC) /* i.e., PowerPC */
744               rtx hi_sum_reg;
745
746               if (reg == 0)
747                 {
748                   if (reload_in_progress)
749                     abort ();
750                   else
751                     reg = gen_reg_rtx (SImode);
752                 }
753         
754               hi_sum_reg = reg;
755
756               emit_insn (gen_rtx (SET, Pmode, hi_sum_reg,
757                                   gen_rtx (PLUS, Pmode,
758                                            pic_offset_table_rtx,
759                                            gen_rtx (HIGH, Pmode, offset))));
760               emit_insn (gen_rtx (SET, VOIDmode, reg,
761                                   gen_rtx (LO_SUM, Pmode,
762                                            hi_sum_reg, offset)));
763               pic_ref = reg;
764 #else
765               emit_insn (gen_rtx (SET, VOIDmode, reg,
766                                   gen_rtx (HIGH, Pmode, offset)));
767               emit_insn (gen_rtx (SET, VOIDmode, reg,
768                                   gen_rtx (LO_SUM, Pmode, reg, offset)));
769               pic_ref = gen_rtx (PLUS, Pmode,
770                                  pic_offset_table_rtx, reg);
771 #endif
772             }
773           else
774 #endif  /*  HAVE_lo_sum  */
775             {
776               if (GET_CODE (orig) == REG)
777                 {
778                   return orig;
779                 }
780               else
781                 {
782                   rtx pic = pic_offset_table_rtx;
783                   if (GET_CODE (pic) != REG)
784                     {
785                       emit_move_insn (reg, pic);
786                       pic = reg;
787                     }
788 #if 0
789                   emit_insn (gen_rtx (USE, VOIDmode,
790                                       pic_offset_table_rtx));
791 #endif
792                   pic_ref = gen_rtx (PLUS, Pmode,
793                                      pic,
794                                      gen_rtx (CONST, Pmode, 
795                                               gen_rtx (MINUS, Pmode,
796                                                        orig, pic_base)));
797                 }
798             }
799         }
800
801       RTX_UNCHANGING_P (pic_ref) = 1;
802
803       if (GET_CODE (pic_ref) != REG)
804         {
805           if (reg != 0)
806             {
807               emit_move_insn (reg, pic_ref);
808               return reg;
809             }
810           else
811             {
812               return force_reg (mode, pic_ref);
813             }
814         }
815       else
816         {
817           return pic_ref;
818         }
819     }
820
821   else if (GET_CODE (orig) == SYMBOL_REF)
822     return orig;
823
824   else if (GET_CODE (orig) == PLUS
825            && (GET_CODE (XEXP (orig, 0)) == MEM
826                || GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
827                || GET_CODE (XEXP (orig, 0)) == LABEL_REF)
828            && XEXP (orig, 0) != pic_offset_table_rtx
829            && GET_CODE (XEXP (orig, 1)) != REG)
830     
831     {
832       rtx base;
833       int is_complex = (GET_CODE (XEXP (orig, 0)) == MEM);
834
835       base = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
836       orig = machopic_legitimize_pic_address (XEXP (orig, 1),
837                                               Pmode, (base == reg ? 0 : reg));
838       if (GET_CODE (orig) == CONST_INT)
839         {
840           pic_ref = plus_constant_for_output (base, INTVAL (orig));
841           is_complex = 1;
842         }
843       else
844         {
845           pic_ref = gen_rtx (PLUS, Pmode, base, orig);
846         }
847
848       if (RTX_UNCHANGING_P (base) && RTX_UNCHANGING_P (orig))
849         RTX_UNCHANGING_P (pic_ref) = 1;
850
851       if (reg && is_complex)
852         {
853           emit_move_insn (reg, pic_ref);
854           pic_ref = reg;
855         }
856       /* Likewise, should we set special REG_NOTEs here?  */
857     }
858
859   else if (GET_CODE (orig) == CONST)
860     {
861       return machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
862     }
863
864   else if (GET_CODE (orig) == MEM
865            && GET_CODE (XEXP (orig, 0)) == SYMBOL_REF)
866     {
867       rtx addr = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
868
869       addr = gen_rtx (MEM, GET_MODE (orig), addr);
870       RTX_UNCHANGING_P (addr) = RTX_UNCHANGING_P (orig);
871       emit_move_insn (reg, addr);
872       pic_ref = reg;
873     }
874
875   return pic_ref;
876 }
877
878
879 void
880 machopic_finish (asm_out_file)
881      FILE *asm_out_file;
882 {
883   tree temp;
884
885   for (temp = machopic_stubs;
886        temp != NULL_TREE;
887        temp = TREE_CHAIN (temp))
888     {
889       char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
890       char *stub_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
891       char *sym;
892       char *stub;
893       tree decl = lookup_name_darwin (TREE_VALUE (temp));
894
895       if (! TREE_USED (temp))
896         continue;
897
898       /* Don't emit stubs for static inline functions which have not
899          been compiled.  */
900       if (decl
901           && TREE_CODE (decl) == FUNCTION_DECL
902           && DECL_INLINE (decl)
903           && ! TREE_PUBLIC (decl)
904           && ! TREE_ASM_WRITTEN (decl))
905         continue;
906
907       sym = alloca (strlen (sym_name) + 2);
908       if (sym_name[0] == '*' || sym_name[0] == '&')
909         strcpy (sym, sym_name + 1);
910       else if (sym_name[0] == '-' || sym_name[0] == '+')
911         strcpy (sym, sym_name);   
912       else
913         sym[0] = '_', strcpy (sym + 1, sym_name);
914
915       stub = alloca (strlen (stub_name) + 2);
916       if (stub_name[0] == '*' || stub_name[0] == '&')
917         strcpy (stub, stub_name + 1);
918       else
919         stub[0] = '_', strcpy (stub + 1, stub_name);
920
921       machopic_output_stub (asm_out_file, sym, stub);
922     }
923
924   for (temp = machopic_non_lazy_pointers;
925        temp != NULL_TREE; 
926        temp = TREE_CHAIN (temp))
927     {
928       char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
929       char *lazy_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
930 #if 0
931       tree decl = lookup_name_darwin (TREE_VALUE (temp));
932 #endif
933
934       if (! TREE_USED (temp))
935         continue;
936
937       if (machopic_ident_defined_p (TREE_VALUE (temp))
938 #if 0 /* add back when we have private externs */
939           || (decl && DECL_PRIVATE_EXTERN (decl))
940 #endif
941           )
942         {
943           data_section ();
944           assemble_align (UNITS_PER_WORD * BITS_PER_UNIT);
945           assemble_label (lazy_name);
946           assemble_integer (gen_rtx (SYMBOL_REF, Pmode, sym_name),
947                             GET_MODE_SIZE (Pmode), 1);
948         }
949       else
950         {
951           machopic_nl_symbol_ptr_section ();
952           assemble_name (asm_out_file, lazy_name); 
953           fprintf (asm_out_file, ":\n");
954
955           fprintf (asm_out_file, "\t.indirect_symbol ");
956           assemble_name (asm_out_file, sym_name); 
957           fprintf (asm_out_file, "\n");
958
959           assemble_integer (const0_rtx, GET_MODE_SIZE (Pmode), 1);
960         }
961     }
962 }
963
964 int 
965 machopic_operand_p (op)
966      rtx op;
967 {
968   if (MACHOPIC_JUST_INDIRECT)
969     {
970       while (GET_CODE (op) == CONST)
971         op = XEXP (op, 0);
972
973       if (GET_CODE (op) == SYMBOL_REF)
974         return machopic_name_defined_p (XSTR (op, 0));
975       else
976         return 0;
977     }
978
979   while (GET_CODE (op) == CONST)
980     op = XEXP (op, 0);
981
982   if (GET_CODE (op) == MINUS
983       && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
984       && GET_CODE (XEXP (op, 1)) == SYMBOL_REF
985       && machopic_name_defined_p (XSTR (XEXP (op, 0), 0))
986       && machopic_name_defined_p (XSTR (XEXP (op, 1), 0)))
987       return 1;
988
989 #if 0 /*def TARGET_TOC*/ /* i.e., PowerPC */
990   /* Without this statement, the compiler crashes while compiling enquire.c
991      when targetting PowerPC.  It is not known why this code is not needed
992      when targetting other processors.  */
993   else if (GET_CODE (op) == SYMBOL_REF
994            && (machopic_classify_name (XSTR (op, 0))
995                == MACHOPIC_DEFINED_FUNCTION))
996     {
997       return 1;
998     }
999 #endif
1000
1001   return 0;
1002 }