diff mbox

[objc] maintenance, make Obj{C,C++} LTO-friendly.

Message ID E9D3411F-D1F2-4253-A0CA-E5558813F0CE@sandoe-acoustics.co.uk
State New
Headers show

Commit Message

Iain Sandoe July 10, 2010, 12:25 a.m. UTC
On 9 Jul 2010, at 06:59, Mike Stump wrote:

> On Jul 2, 2010, at 12:19 PM, IainS wrote:
>> This patch is intended to maintain the 'status-quo' in the presence  
>> of LTO.
>
>> OK for trunk?
>
> [ after more thought and some more offline email... ]
>
> Ok with the:

Well, I found the cause of our section hassles and fixed it as obvious  
(I hope that doesn't exceed the approval).
In doing so it meant that I was able to make pretty much all the  
changes you asked for.

I have checked in gdb at O1 that the items hanging off _OBJC_MODULES  
are marked as used (without needing to force that).

AFAICT,  all the necessary top level stuff is marked DECL_PRESERVE_P  
and that the rest is being correctly marked by the varpool/cgraph  
mechanisms.

Iain

This is what I checked in as r162030:

gcc/
	PR objc/44140
	* config/darwin.c (output_objc_section_asm_op): Save and restore
	section when outputting ObjC section list.

testsuite/

	PR objc/44140
	* objc.dg/lto/trivial-1_0.m: New.
	* objc.dg/lto/lto.exp: New.
	* obj-c++.dg/lto/trivial-1_0.mm: New.
	* obj-c++.dg/lto/lto.exp: New.
	* objc.dg/symtab-1.m: Adjust sizes.
	* objc.dg/image-info.m: Do not run for gnu-runtime.

gcc/objc/

	PR objc/44140
	* objc-act.c: build_objc_string_decl() remove declaration.
	(finish_var_decl): Remove forcing of var output and marking
	as "Used".
	(init_def_list): Use integer_zero_node.
	(init_objc_symtab): Use integer_zero_node, make the short
	integer type specific on relevant nodes.
	(generate_objc_symtab_decl): Remove call to
	forward_declare_categories().  Use null_pointer_node where
	appropriate.
	(build_module_descriptor): Comment and mark this item as
	DECL_PRESERVE_P.
	(generate_static_references): Use gcc_unreachable instead of
	abort ().
	(diagnose_missing_method): New.
	(build_next_selector_translation_table): New.
	(build_gnu_selector_translation_table): New.
	(add_objc_string): Merge code from build_objc_string_decl...
	... and delete build_objc_string_decl().
	(generate_dispatch_table): Make integer types explicit.
	(generate_category): Pass implent and arrange for the data
	to be extracted within the routine.  Do not start new vars,
	but finish the ones collcted during parsing.
	(generate_shared_structures): Likewise.
	(finish_objc):  Reorder code so that we finish variables before
	referencing them.  Save the global data before calling meta-data
	creation routines, and pass the current reference to the two
	main routines.  Only call generate_objc_image_info () for the
	NeXT runtime.
	(generate_classref_translation_entry): Comment on and make this
	item DECL_PRESERVE_P.
	(handle_class_ref): Use varpool interfaces, comment on and make
	this item DECL_PRESERVE_P.
	(handle_impent): Likewise.
	(generate_objc_image_info): Only generate when the content is
	non-zero.  Make integer types explict.

Comments

Mike Stump July 10, 2010, 6:55 a.m. UTC | #1
On Jul 9, 2010, at 5:25 PM, IainS wrote:
> On 9 Jul 2010, at 06:59, Mike Stump wrote:
>> On Jul 2, 2010, at 12:19 PM, IainS wrote:
>>> This patch is intended to maintain the 'status-quo' in the presence of LTO.
>> 
>>> OK for trunk?
>> 
>> [ after more thought and some more offline email... ]
>> 
>> Ok with the:
> 
> Well, I found the cause of our section hassles and fixed it as obvious (I hope that doesn't exceed the approval).

Yeah, I do like this version better...  If we wanted to bullet proof this, we could assert that bss_initializer_p isn't true on the things that can't tolerate switching sections.  For those that can be zero, we'd have to select the section earlier as you had in the previous version.  I'd like to think the code cleverly avoids those issue, but not certain.

As always, thanks for working on this.
Iain Sandoe July 11, 2010, 9:58 a.m. UTC | #2
On 10 Jul 2010, at 07:55, Mike Stump wrote:

> On Jul 9, 2010, at 5:25 PM, IainS wrote:
>> On 9 Jul 2010, at 06:59, Mike Stump wrote:
>>> On Jul 2, 2010, at 12:19 PM, IainS wrote:
>>>> This patch is intended to maintain the 'status-quo' in the  
>>>> presence of LTO.
>>>
>>>> OK for trunk?
>>>
>>> [ after more thought and some more offline email... ]
>>>
>>> Ok with the:
>>
>> Well, I found the cause of our section hassles and fixed it as  
>> obvious (I hope that doesn't exceed the approval).
>
> Yeah, I do like this version better...  If we wanted to bullet proof  
> this, we could assert that bss_initializer_p isn't true on the  
> things that can't tolerate switching

given that this fixes a regression present on the introduction of LTO,  
and that LTO has been back-ported to 4.5
Is this eligible for backport to 4.5 with/without Nathan's VEC changes?

Iain
Richard Biener July 11, 2010, 10 a.m. UTC | #3
On Sun, Jul 11, 2010 at 11:58 AM, IainS
<developer@sandoe-acoustics.co.uk> wrote:
>
> On 10 Jul 2010, at 07:55, Mike Stump wrote:
>
>> On Jul 9, 2010, at 5:25 PM, IainS wrote:
>>>
>>> On 9 Jul 2010, at 06:59, Mike Stump wrote:
>>>>
>>>> On Jul 2, 2010, at 12:19 PM, IainS wrote:
>>>>>
>>>>> This patch is intended to maintain the 'status-quo' in the presence of
>>>>> LTO.
>>>>
>>>>> OK for trunk?
>>>>
>>>> [ after more thought and some more offline email... ]
>>>>
>>>> Ok with the:
>>>
>>> Well, I found the cause of our section hassles and fixed it as obvious (I
>>> hope that doesn't exceed the approval).
>>
>> Yeah, I do like this version better...  If we wanted to bullet proof this,
>> we could assert that bss_initializer_p isn't true on the things that can't
>> tolerate switching
>
> given that this fixes a regression present on the introduction of LTO, and
> that LTO has been back-ported to 4.5
> Is this eligible for backport to 4.5 with/without Nathan's VEC changes?

Please no.  It is not a regression at all.

Thanks,
Richard.

> Iain
>
>
Iain Sandoe July 11, 2010, 11:14 a.m. UTC | #4
On 11 Jul 2010, at 11:00, Richard Guenther wrote:

> On Sun, Jul 11, 2010 at 11:58 AM, IainS
> <developer@sandoe-acoustics.co.uk> wrote:
>>
>> On 10 Jul 2010, at 07:55, Mike Stump wrote:
>>
>>> On Jul 9, 2010, at 5:25 PM, IainS wrote:
>>>>
>>>> On 9 Jul 2010, at 06:59, Mike Stump wrote:
>>>>>
>>>>> On Jul 2, 2010, at 12:19 PM, IainS wrote:
>>>>>>
>>>>>> This patch is intended to maintain the 'status-quo' in the  
>>>>>> presence of
>>>>>> LTO.
>>>>>
>>>>>> OK for trunk?
>>>>>
>>>>> [ after more thought and some more offline email... ]
>>>>>
>>>>> Ok with the:
>>>>
>>>> Well, I found the cause of our section hassles and fixed it as  
>>>> obvious (I
>>>> hope that doesn't exceed the approval).
>>>
>>> Yeah, I do like this version better...  If we wanted to bullet  
>>> proof this,
>>> we could assert that bss_initializer_p isn't true on the things  
>>> that can't
>>> tolerate switching
>>
>> given that this fixes a regression present on the introduction of  
>> LTO, and
>> that LTO has been back-ported to 4.5
>> Is this eligible for backport to 4.5 with/without Nathan's VEC  
>> changes?
>
> Please no.  It is not a regression at all.

saves me work ;-)

I guess it's technically a fix for bug(s) that pre-date 4.5 branch but  
are revealed by the addition of LTO.

perhaps we might reconsider during 4.5.2?
Iain
Richard Biener July 11, 2010, 11:43 a.m. UTC | #5
On Sun, Jul 11, 2010 at 1:14 PM, IainS <developer@sandoe-acoustics.co.uk> wrote:
>
> On 11 Jul 2010, at 11:00, Richard Guenther wrote:
>
>> On Sun, Jul 11, 2010 at 11:58 AM, IainS
>> <developer@sandoe-acoustics.co.uk> wrote:
>>>
>>> On 10 Jul 2010, at 07:55, Mike Stump wrote:
>>>
>>>> On Jul 9, 2010, at 5:25 PM, IainS wrote:
>>>>>
>>>>> On 9 Jul 2010, at 06:59, Mike Stump wrote:
>>>>>>
>>>>>> On Jul 2, 2010, at 12:19 PM, IainS wrote:
>>>>>>>
>>>>>>> This patch is intended to maintain the 'status-quo' in the presence
>>>>>>> of
>>>>>>> LTO.
>>>>>>
>>>>>>> OK for trunk?
>>>>>>
>>>>>> [ after more thought and some more offline email... ]
>>>>>>
>>>>>> Ok with the:
>>>>>
>>>>> Well, I found the cause of our section hassles and fixed it as obvious
>>>>> (I
>>>>> hope that doesn't exceed the approval).
>>>>
>>>> Yeah, I do like this version better...  If we wanted to bullet proof
>>>> this,
>>>> we could assert that bss_initializer_p isn't true on the things that
>>>> can't
>>>> tolerate switching
>>>
>>> given that this fixes a regression present on the introduction of LTO,
>>> and
>>> that LTO has been back-ported to 4.5
>>> Is this eligible for backport to 4.5 with/without Nathan's VEC changes?
>>
>> Please no.  It is not a regression at all.
>
> saves me work ;-)
>
> I guess it's technically a fix for bug(s) that pre-date 4.5 branch but are
> revealed by the addition of LTO.

Something is a regression if an invocation of gcc on a testcase
works on an earlier release but fails with a later release.  As -flto isn't
supported by earlier releases I doubt you'd find one.

> perhaps we might reconsider during 4.5.2?

No, these patches are way to invasive.

Richard.

> Iain
>
>
Mike Stump July 11, 2010, 8:29 p.m. UTC | #6
On Jul 11, 2010, at 2:58 AM, IainS wrote:
> Is this eligible for backport to 4.5 with/without Nathan's VEC changes

I'd take a cue from the LTO people and/or the release manager for the branch...  If LTO is meant to be a big new important feature for gcc-4.5, but ObjC just wasn't dusted off in time, I think it could be reasonable to just finish it off. If just a minor thing that doesn't matter much, we can push it out.  I'm not involved enough in the LTO work to have a take.  As for the ObjC changes for it, they make me a little nervous, so that raises the bar for the back port a little bit.
Iain Sandoe July 11, 2010, 10:41 p.m. UTC | #7
On 11 Jul 2010, at 21:29, Mike Stump wrote:

> On Jul 11, 2010, at 2:58 AM, IainS wrote:
>> Is this eligible for backport to 4.5 with/without Nathan's VEC  
>> changes
>
> I'd take a cue from the LTO people and/or the release manager for  
> the branch...  If LTO is meant to be a big new important feature for  
> gcc-4.5, but ObjC just wasn't dusted off in time, I think it could  
> be reasonable to just finish it off. If just a minor thing that  
> doesn't matter much, we can push it out.  I'm not involved enough in  
> the LTO work to have a take.

Well, Richard has made his view clear, and whilst I was initially  
surprised that the changes to objc-act.c are considered "way too  
invasive" ....

>  As for the ObjC changes for it, they make me a little nervous, so  
> that raises the bar for the back port a little bit.

.... it would seem that you share his view, at least in part, on that.

I guess that it is more important to me that we should dispel these  
feelings of nervousness ;-)
...  therefore to work on whatever is needed to be sure that the  
solution is transparent and robust.

In the end my interest is in a working, bug-free, ObjC FE that  
supports NeXT runtime for both m32 & m64 ...
...  and  the changes for LTO are trivial c.f. what will be needed to  
achieve that.

--

Whilst doing this work, I drew out the relationship between the NeXT  
ObjC meta-data items (on paper) in order to figure out which needed to  
be specially marked.
When I have a chance I will attempt to transcribe that diagram in some  
way (perhaps a wiki entry) so that we can apply some joint scrutiny.

I'm also tempted to make a more rigorous set of test-suite entries for  
each permutation of source content and meta-data (and per runtime).

cheers,
Iain
Mike Stump July 15, 2010, 4:08 p.m. UTC | #8
On Jul 11, 2010, at 3:41 PM, IainS wrote:
>> I'd take a cue from the LTO people and/or the release manager for the branch...  If LTO is meant to be a big new important feature for gcc-4.5, but ObjC just wasn't dusted off in time, I think it could be reasonable to just finish it off. If just a minor thing that doesn't matter much, we can push it out.  I'm not involved enough in the LTO work to have a take.
> 
> Well, Richard has made his view clear

Well, if he was weighing in as LTO and RM, I'd look to that guidance...  If you want to press further, you can have the RMs for the release huddle and see if they have any addressable concerns or a different opinion.

> .... it would seem that you share his view, at least in part, on that.

I don't share in the way too invasive.  With no opposition from LTO and RM people, I'd probably approve, if you wanted to babysit the quality in the 4.5.x branch.  I don't think the risk is all that great.  Also, since LTO was in 4.5.x, it makes sense to me from a RM point of view to allow it.  All that said, since the LTO and RM people spoke up, I think the decision rests there.  My guidance would be to let you put it in, if you want to press for it.

> I guess that it is more important to me that we should dispel these feelings of nervousness ;-)
> ...  therefore to work on whatever is needed to be sure that the solution is transparent and robust.

Ah, but here is where I think the art of RM comes into play, it is the experience of things past and a strive to have each release be a great release, even if it means that sometimes specific work gets left behind.  For me, there weren't any addressable concerns, or additional explanation that would change my valuation.  Now, as to why I'd let you put it in, well, the way one gets to learn, is to push things into a release, have some unexpected fallout and learn from that process.
Jack Howarth July 15, 2010, 4:19 p.m. UTC | #9
On Thu, Jul 15, 2010 at 09:08:56AM -0700, Mike Stump wrote:
> On Jul 11, 2010, at 3:41 PM, IainS wrote:
> >> I'd take a cue from the LTO people and/or the release manager for the branch...  If LTO is meant to be a big new important feature for gcc-4.5, but ObjC just wasn't dusted off in time, I think it could be reasonable to just finish it off. If just a minor thing that doesn't matter much, we can push it out.  I'm not involved enough in the LTO work to have a take.
> > 
> > Well, Richard has made his view clear
> 
> Well, if he was weighing in as LTO and RM, I'd look to that guidance...  If you want to press further, you can have the RMs for the release huddle and see if they have any addressable concerns or a different opinion.
> 
> > .... it would seem that you share his view, at least in part, on that.
> 
> I don't share in the way too invasive.  With no opposition from LTO and RM people, I'd probably approve, if you wanted to babysit the quality in the 4.5.x branch.  I don't think the risk is all that great.  Also, since LTO was in 4.5.x, it makes sense to me from a RM point of view to allow it.  All that said, since the LTO and RM people spoke up, I think the decision rests there.  My guidance would be to let you put it in, if you want to press for it.
> 
> > I guess that it is more important to me that we should dispel these feelings of nervousness ;-)
> > ...  therefore to work on whatever is needed to be sure that the solution is transparent and robust.
> 
> Ah, but here is where I think the art of RM comes into play, it is the experience of things past and a strive to have each release be a great release, even if it means that sometimes specific work gets left behind.  For me, there weren't any addressable concerns, or additional explanation that would change my valuation.  Now, as to why I'd let you put it in, well, the way one gets to learn, is to push things into a release, have some unexpected fallout and learn from that process.

Mike,
   I've come around to the view that lto in gcc 4.5.x will be of preview quality
at best. I've built some large projects with -flto -fwhole-program and found run-time
errors in the code generated by gcc-4_5-branch but not with gcc trunk. Couple that
with the fact that -fwhopr isn't really usable in gcc-4_5-branch (and probably
should be disabled there).
                   Jack
diff mbox

Patch

Index: gcc/config/darwin.c
===================================================================
--- gcc/config/darwin.c	(revision 162024)
+++ gcc/config/darwin.c	(working copy)
@@ -99,6 +99,7 @@  output_objc_section_asm_op (const void *directive)
      section is requested.  */
   if (! been_here)
     {
+      section *saved_in_section = in_section;
       static const enum darwin_section_enum tomark[] =
 	{
 	  /* written, cold -> hot */
@@ -129,6 +130,7 @@  output_objc_section_asm_op (const void *directive)
       been_here = true;
       for (i = 0; i < ARRAY_SIZE (tomark); i++)
 	switch_to_section (darwin_sections[tomark[i]]);
+      switch_to_section (saved_in_section);
     }
   output_section_asm_op (directive);
 }
Index: gcc/objc/objc-act.c
===================================================================
--- gcc/objc/objc-act.c	(revision 162024)
+++ gcc/objc/objc-act.c	(working copy)
@@ -214,7 +214,6 @@  enum string_section
 };
 
 static tree add_objc_string (tree, enum string_section);
-static tree build_objc_string_decl (enum string_section);
 static void build_selector_table_decl (void);
 
 /* Protocol additions.  */
@@ -1541,14 +1540,6 @@  static void
 finish_var_decl (tree var, tree initializer)
 {
   finish_decl (var, input_location, initializer, NULL_TREE, NULL_TREE);
-  /* Ensure that the variable actually gets output.  */
-  mark_decl_referenced (var);
-  /* Mark the decl to avoid "defined but not used" warning.  */
-  TREE_USED (var) = 1;
-  DECL_READ_P (var) = 1;
-  /* We reserve the right for the runtime to use/modify these variables
-     in ways that are opaque to us.  */
-  DECL_PRESERVE_P (var) = 1;
 }
 
 /* Find the decl for the constant string class reference.  This is only
@@ -2188,7 +2179,7 @@  init_def_list (tree type)
 	expr = build_unary_op (input_location,
 			       ADDR_EXPR, static_instances_decl, 0);
       else
-	expr = build_int_cst (NULL_TREE, 0);
+	expr = integer_zero_node;
 
       CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr);
     }
@@ -2211,7 +2202,9 @@  init_objc_symtab (tree type)
   /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */
 
   if (flag_next_runtime || ! sel_ref_chain)
-    CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0));
+    CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, convert (
+					build_pointer_type (objc_selector_type),
+							integer_zero_node));
   else
     {
       tree expr = build_unary_op (input_location, ADDR_EXPR,
@@ -2224,11 +2217,13 @@  init_objc_symtab (tree type)
 
   /* cls_def_cnt = { ..., 5, ... } */
 
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, imp_count));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, 
+			  build_int_cst (short_integer_type_node, imp_count));
 
   /* cat_def_cnt = { ..., 5, ... } */
 
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, cat_count));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, 
+			  build_int_cst (short_integer_type_node, cat_count));
 
   /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */
 
@@ -2289,10 +2284,7 @@  forward_declare_categories (void)
 static void
 generate_objc_symtab_decl (void)
 {
-  /* forward declare categories */
-  if (cat_count)
-    forward_declare_categories ();
-
+ 
   build_objc_symtab_template ();
   UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_SYMBOLS");
   finish_var_decl (UOBJC_SYMBOLS_decl,
@@ -2328,7 +2320,7 @@  init_module_descriptor (tree type)
     expr = build_unary_op (input_location,
 			   ADDR_EXPR, UOBJC_SYMBOLS_decl, 0);
   else
-    expr = build_int_cst (NULL_TREE, 0);
+    expr = null_pointer_node;
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr);
 
   return objc_build_constructor (type, v);
@@ -2367,6 +2359,9 @@  build_module_descriptor (void)
 
   /* Create an instance of "_objc_module".  */
   UOBJC_MODULES_decl = start_var_decl (objc_module_template, "_OBJC_MODULES");
+  /* This is the root of the metadata for defined classes and categories, it
+     is referenced by the runtime and, therefore, needed.  */
+  DECL_PRESERVE_P (UOBJC_MODULES_decl) = 1;
   finish_var_decl (UOBJC_MODULES_decl,
 		   init_module_descriptor (TREE_TYPE (UOBJC_MODULES_decl)));
 
@@ -2490,7 +2485,7 @@  generate_static_references (void)
   VEC(constructor_elt,gc) *decls = NULL;
 
   if (flag_next_runtime)
-    abort ();
+    gcc_unreachable ();
 
   for (cl_chain = objc_static_instances, num_class = 0;
        cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++)
@@ -2574,12 +2569,65 @@  build_selector (tree ident)
 		  add_objc_string (ident, meth_var_names));
 }
 
+/* Used only by build_*_selector_translation_table (). */
 static void
-build_selector_translation_table (void)
+diagnose_missing_method (tree meth, location_t here)
 {
+  tree method_chain;
+  bool found = false;
+  for (method_chain = meth_var_names_chain;
+       method_chain;
+       method_chain = TREE_CHAIN (method_chain))
+    {
+      if (TREE_VALUE (method_chain) == meth)
+	{
+	  found = true;
+	  break;
+	}
+     }
+
+  if (!found)
+    warning_at (here, 0, "creating selector for nonexistent method %qE",
+			meth);
+}
+
+static void
+build_next_selector_translation_table (void)
+{
   tree chain;
-  int offset = 0;
-  tree decl = NULL_TREE;
+  for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
+    {
+      tree expr;
+      tree decl = TREE_PURPOSE (chain);
+      if (warn_selector && objc_implementation_context)
+      	{
+	  location_t loc;
+      	  if (decl) 
+      	    loc = DECL_SOURCE_LOCATION (decl);
+      	  else
+      	    loc = input_location;
+	  diagnose_missing_method (TREE_VALUE (chain), loc);
+	}
+
+      expr = build_selector (TREE_VALUE (chain));
+
+      if (decl)
+	{
+	  /* Entries of this form are used for references to methods.
+	  The runtime re-writes these on start-up, but the compiler can't see 
+	  that and optimizes it away unless we force it.  */
+	  DECL_PRESERVE_P (decl) = 1;
+	  finish_var_decl (decl, expr);
+	}
+    }
+}
+
+static void
+build_gnu_selector_translation_table (void)
+{
+  tree chain;
+/*  int offset = 0;
+  tree decl = NULL_TREE;*/
   VEC(constructor_elt,gc) *inits = NULL;
 
   for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
@@ -2587,42 +2635,13 @@  static void
       tree expr;
 
       if (warn_selector && objc_implementation_context)
-      {
-        tree method_chain;
-        bool found = false;
-        for (method_chain = meth_var_names_chain;
-             method_chain;
-             method_chain = TREE_CHAIN (method_chain))
-          {
-            if (TREE_VALUE (method_chain) == TREE_VALUE (chain))
-              {
-                found = true;
-                break;
-              }
-          }
-        if (!found)
-	  {
-	    location_t loc;
-	    if (flag_next_runtime && TREE_PURPOSE (chain))
-	      loc = DECL_SOURCE_LOCATION (TREE_PURPOSE (chain));
-	    else
-	      loc = input_location;
-	    warning_at (loc, 0, "creating selector for nonexistent method %qE",
-			TREE_VALUE (chain));
-	  }
-      }
+	diagnose_missing_method (TREE_VALUE (chain), input_location);
 
       expr = build_selector (TREE_VALUE (chain));
-      /* add one for the '\0' character */
-      offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;
+      /* add one for the '\0' character 
+      offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;*/
 
-      if (flag_next_runtime)
 	{
-	  decl = TREE_PURPOSE (chain);
-	  finish_var_decl (decl, expr);
-	}
-      else
-	{
 	  if (flag_typed_selectors)
 	    {
 	      VEC(constructor_elt,gc) *v = NULL;
@@ -2634,9 +2653,8 @@  static void
 
 	  CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr);
 	}
-    }
+    } /* each element in the chain */
 
-  if (! flag_next_runtime)
     {
       /* Cause the selector table (previously forward-declared)
 	 to be actually output.	 */
@@ -2645,12 +2663,12 @@  static void
       if (flag_typed_selectors)
 	{
 	  VEC(constructor_elt,gc) *v = NULL;
-	  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0));
-	  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0));
+	  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node);
+	  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node);
 	  expr = objc_build_constructor (objc_selector_template, v);
 	}
       else
-	expr = build_int_cst (NULL_TREE, 0);
+	expr = integer_zero_node;
 
       CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr);
       expr = objc_build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl),
@@ -2854,19 +2872,34 @@  objc_get_class_reference (tree ident)
 /* For each string section we have a chain which maps identifier nodes
    to decls for the strings.  */
 
+static GTY(()) int class_names_idx;
+static GTY(()) int meth_var_names_idx;
+static GTY(()) int meth_var_types_idx;
+
 static tree
 add_objc_string (tree ident, enum string_section section)
 {
   tree *chain, decl, type, string_expr;
-
+  char buf[256];
+  
+  buf[0] = 0;
   if (section == class_names)
-    chain = &class_names_chain;
+    {
+      chain = &class_names_chain;
+      sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++);
+    }
   else if (section == meth_var_names)
-    chain = &meth_var_names_chain;
+    {
+      chain = &meth_var_names_chain;
+      sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++);
+    }
   else if (section == meth_var_types)
-    chain = &meth_var_types_chain;
+    {
+      chain = &meth_var_types_chain;
+      sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++);
+    }
   else
-    abort ();
+    gcc_unreachable ();
 
   while (*chain)
     {
@@ -2878,12 +2911,11 @@  add_objc_string (tree ident, enum string_section s
       chain = &TREE_CHAIN (*chain);
     }
 
-  decl = build_objc_string_decl (section);
-
   type = build_sized_array_type (char_type_node, IDENTIFIER_LENGTH (ident) + 1);
-  decl = start_var_decl (type, IDENTIFIER_POINTER (DECL_NAME (decl)));
+  decl = start_var_decl (type, buf);
   string_expr = my_build_string (IDENTIFIER_LENGTH (ident) + 1,
 				 IDENTIFIER_POINTER (ident));
+  TREE_CONSTANT (decl) = 1;
   finish_var_decl (decl, string_expr);
 
   *chain = tree_cons (decl, ident, NULL_TREE);
@@ -2892,44 +2924,6 @@  add_objc_string (tree ident, enum string_section s
 						    ADDR_EXPR, decl, 1));
 }
 
-static GTY(()) int class_names_idx;
-static GTY(()) int meth_var_names_idx;
-static GTY(()) int meth_var_types_idx;
-
-static tree
-build_objc_string_decl (enum string_section section)
-{
-  tree decl, ident;
-  char buf[256];
-
-  if (section == class_names)
-    sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++);
-  else if (section == meth_var_names)
-    sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++);
-  else if (section == meth_var_types)
-    sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++);
-
-  ident = get_identifier (buf);
-
-  decl = build_decl (input_location,
-		     VAR_DECL, ident, build_array_type (char_type_node, 0));
-  DECL_EXTERNAL (decl) = 1;
-  TREE_PUBLIC (decl) = 0;
-  TREE_USED (decl) = 1;
-  TREE_CONSTANT (decl) = 1;
-  DECL_CONTEXT (decl) = 0;
-  DECL_ARTIFICIAL (decl) = 1;
-#ifdef OBJCPLUS
-  DECL_THIS_STATIC (decl) = 1; /* squash redeclaration errors */
-#endif
-
-  make_decl_rtl (decl);
-  pushdecl_top_level (decl);
-
-  return decl;
-}
-
-
 void
 objc_declare_alias (tree alias_ident, tree class_ident)
 {
@@ -5334,8 +5328,8 @@  generate_dispatch_table (tree type, const char *na
   decl = start_var_decl (type, synth_id_with_class_suffix
 			       (name, objc_implementation_context));
 
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0));
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size));
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node);
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (integer_type_node, size));
   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, list);
 
   finish_var_decl (decl,
@@ -5658,12 +5652,16 @@  lookup_category (tree klass, tree cat_name)
 /* static struct objc_category _OBJC_CATEGORY_<name> = { ... };  */
 
 static void
-generate_category (tree cat)
+generate_category (struct imp_entry *impent)
 {
-  tree decl;
   tree initlist, cat_name_expr, class_name_expr;
   tree protocol_decl, category;
+  tree cat = impent->imp_context;
 
+  implementation_template = impent->imp_template;
+  UOBJC_CLASS_decl = impent->class_decl;
+  UOBJC_METACLASS_decl = impent->meta_decl;
+
   add_class_reference (CLASS_NAME (cat));
   cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names);
 
@@ -5680,30 +5678,32 @@  static void
   else
     protocol_decl = 0;
 
-  decl = start_var_decl (objc_category_template,
-			 synth_id_with_class_suffix
-			 ("_OBJC_CATEGORY", objc_implementation_context));
-
-  initlist = build_category_initializer (TREE_TYPE (decl),
+  initlist = build_category_initializer (TREE_TYPE (UOBJC_CLASS_decl),
 					 cat_name_expr, class_name_expr,
 					 UOBJC_INSTANCE_METHODS_decl,
 					 UOBJC_CLASS_METHODS_decl,
 					 protocol_decl);
-
-  finish_var_decl (decl, initlist);
+  /* Finish and initialize the forward decl.  */
+  finish_var_decl (UOBJC_CLASS_decl, initlist);
 }
 
 /* static struct objc_class _OBJC_METACLASS_Foo={ ... };
    static struct objc_class _OBJC_CLASS_Foo={ ... };  */
 
 static void
-generate_shared_structures (int cls_flags)
+generate_shared_structures (struct imp_entry *impent)
 {
-  tree decl;
   tree name_expr, super_expr, root_expr;
-  tree my_root_id = NULL_TREE, my_super_id = NULL_TREE;
+  tree my_root_id, my_super_id;
   tree cast_type, initlist, protocol_decl;
-
+  int cls_flags;
+  
+  objc_implementation_context = impent->imp_context;
+  implementation_template = impent->imp_template;
+  UOBJC_CLASS_decl = impent->class_decl;
+  UOBJC_METACLASS_decl = impent->meta_decl;
+  cls_flags = impent->has_cxx_cdtors ? CLS_HAS_CXX_STRUCTORS : 0 ;
+  
   my_super_id = CLASS_SUPER_NAME (implementation_template);
   if (my_super_id)
     {
@@ -5734,13 +5734,12 @@  static void
 
   /* Install class `isa' and `super' pointers at runtime.  */
   if (my_super_id)
-    {
-      super_expr = add_objc_string (my_super_id, class_names);
-      super_expr = build_c_cast (input_location,
+    super_expr = add_objc_string (my_super_id, class_names);
+  else
+    super_expr = integer_zero_node;
+    
+  super_expr = build_c_cast (input_location,
 				 cast_type, super_expr); /* cast! */
-    }
-  else
-    super_expr = build_int_cst (NULL_TREE, 0);
 
   root_expr = add_objc_string (my_root_id, class_names);
   root_expr = build_c_cast (input_location, cast_type, root_expr); /* cast! */
@@ -5756,13 +5755,9 @@  static void
 
   /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */
 
-  decl = start_var_decl (objc_class_template,
-			 IDENTIFIER_POINTER
-			 (DECL_NAME (UOBJC_METACLASS_decl)));
-
   initlist
     = build_shared_structure_initializer
-      (TREE_TYPE (decl),
+      (TREE_TYPE (UOBJC_METACLASS_decl),
        root_expr, super_expr, name_expr,
        convert (integer_type_node, TYPE_SIZE_UNIT (objc_class_template)),
        2 /*CLS_META*/,
@@ -5770,17 +5765,13 @@  static void
        UOBJC_CLASS_VARIABLES_decl,
        protocol_decl);
 
-  finish_var_decl (decl, initlist);
+  finish_var_decl (UOBJC_METACLASS_decl, initlist);
 
   /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */
 
-  decl = start_var_decl (objc_class_template,
-			 IDENTIFIER_POINTER
-			 (DECL_NAME (UOBJC_CLASS_decl)));
-
   initlist
     = build_shared_structure_initializer
-      (TREE_TYPE (decl),
+      (TREE_TYPE (UOBJC_CLASS_decl),
        build_unary_op (input_location, ADDR_EXPR, UOBJC_METACLASS_decl, 0),
        super_expr, name_expr,
        convert (integer_type_node,
@@ -5791,7 +5782,7 @@  static void
        UOBJC_INSTANCE_VARIABLES_decl,
        protocol_decl);
 
-  finish_var_decl (decl, initlist);
+  finish_var_decl (UOBJC_CLASS_decl, initlist);
 }
 
 
@@ -9176,15 +9167,17 @@  finish_objc (void)
   if (objc_static_instances)
     generate_static_references ();
 
-  if (imp_list || class_names_chain
-      || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
-    generate_objc_symtab_decl ();
+  /* forward declare categories */
+  if (cat_count)
+    forward_declare_categories ();
 
   for (impent = imp_list; impent; impent = impent->next)
     {
       objc_implementation_context = impent->imp_context;
       implementation_template = impent->imp_template;
 
+      /* FIXME: This needs reworking to be more obvious.  */
+
       UOBJC_CLASS_decl = impent->class_decl;
       UOBJC_METACLASS_decl = impent->meta_decl;
 
@@ -9202,28 +9195,35 @@  finish_objc (void)
 	  /* all of the following reference the string pool...  */
 	  generate_ivar_lists ();
 	  generate_dispatch_tables ();
-	  generate_shared_structures (impent->has_cxx_cdtors
-				      ? CLS_HAS_CXX_STRUCTORS
-				      : 0);
+	  generate_shared_structures (impent);
 	}
       else
 	{
 	  generate_dispatch_tables ();
-	  generate_category (objc_implementation_context);
+	  generate_category (impent);
 	}
+
+      impent->class_decl = UOBJC_CLASS_decl;
+      impent->meta_decl = UOBJC_METACLASS_decl;
     }
 
   /* If we are using an array of selectors, we must always
      finish up the array decl even if no selectors were used.  */
-  if (! flag_next_runtime || sel_ref_chain)
-    build_selector_translation_table ();
+  if (flag_next_runtime)
+    build_next_selector_translation_table ();
+  else
+    build_gnu_selector_translation_table ();
 
   if (protocol_chain)
     generate_protocols ();
 
-  if ((flag_replace_objc_classes && imp_list) || flag_objc_gc)
+  if (flag_next_runtime)
     generate_objc_image_info ();
 
+  if (imp_list || class_names_chain
+      || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
+    generate_objc_symtab_decl ();
+
   /* Arrange for ObjC data structures to be initialized at run time.  */
   if (objc_implementation_context || class_names_chain || objc_static_instances
       || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
@@ -9282,8 +9282,9 @@  generate_classref_translation_entry (tree chain)
   expr = add_objc_string (TREE_VALUE (chain), class_names);
   expr = convert (type, expr); /* cast! */
 
-  /* The decl that is the one that we
-     forward declared in build_class_reference.  */
+  /* This is a class reference.  It is re-written by the runtime,
+     but will be optimized away unless we force it.  */
+  DECL_PRESERVE_P (decl) = 1;
   finish_var_decl (decl, expr);
   return;
 }
@@ -9309,12 +9310,11 @@  handle_class_ref (tree chain)
 
   /* Make a decl for this name, so we can use its address in a tree.  */
   decl = build_decl (input_location,
-		     VAR_DECL, get_identifier (string), char_type_node);
+		     VAR_DECL, get_identifier (string), TREE_TYPE (integer_zero_node));
   DECL_EXTERNAL (decl) = 1;
   TREE_PUBLIC (decl) = 1;
-
   pushdecl (decl);
-  rest_of_decl_compilation (decl, 0, 0);
+  finish_var_decl (decl, 0);
 
   /* Make a decl for the address.  */
   sprintf (string, "%sobjc_class_ref_%s",
@@ -9322,15 +9322,17 @@  handle_class_ref (tree chain)
   exp = build1 (ADDR_EXPR, string_type_node, decl);
   decl = build_decl (input_location,
 		     VAR_DECL, get_identifier (string), string_type_node);
-  DECL_INITIAL (decl) = exp;
   TREE_STATIC (decl) = 1;
   TREE_USED (decl) = 1;
   DECL_READ_P (decl) = 1;
-  /* Force the output of the decl as this forces the reference of the class.  */
-  mark_decl_referenced (decl);
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_INITIAL (decl) = error_mark_node;
+ 
+  /* We must force the reference.  */
+  DECL_PRESERVE_P (decl) = 1;
 
   pushdecl (decl);
-  rest_of_decl_compilation (decl, 0, 0);
+  finish_var_decl (decl, exp);
 }
 
 static void
@@ -9381,17 +9383,21 @@  handle_impent (struct imp_entry *impent)
     {
       tree decl, init;
 
-      init = build_int_cst (c_common_type_for_size (BITS_PER_WORD, 1), 0);
+      init = integer_zero_node;
       decl = build_decl (input_location,
 			 VAR_DECL, get_identifier (string), TREE_TYPE (init));
       TREE_PUBLIC (decl) = 1;
       TREE_READONLY (decl) = 1;
       TREE_USED (decl) = 1;
       TREE_CONSTANT (decl) = 1;
-      DECL_CONTEXT (decl) = 0;
+      DECL_CONTEXT (decl) = NULL_TREE;
       DECL_ARTIFICIAL (decl) = 1;
-      DECL_INITIAL (decl) = init;
-      assemble_variable (decl, 1, 0, 0);
+      TREE_STATIC (decl) = 1;
+      DECL_INITIAL (decl) = error_mark_node; /* A real initializer is coming... */
+      /* We must force the reference.  */
+      DECL_PRESERVE_P (decl) = 1;
+
+      finish_var_decl(decl, init) ;
     }
 }
 
@@ -9406,16 +9412,24 @@  generate_objc_image_info (void)
 {
   tree decl;
   int flags
-    = ((flag_replace_objc_classes && imp_list ? 1 : 0)
+    = ((flag_replace_objc_classes && imp_count ? 1 : 0)
        | (flag_objc_gc ? 2 : 0));
   VEC(constructor_elt,gc) *v = NULL;
-  tree array_type = build_sized_array_type (integer_type_node, 2);
+  tree array_type;
+  
+   if (!flags)
+    return; /* No need for an image_info entry.  */
+  
+  array_type  = build_sized_array_type (integer_type_node, 2);
 
   decl = start_var_decl (array_type, "_OBJC_IMAGE_INFO");
 
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0));
-  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, flags));
-
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node);
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (integer_type_node, flags));
+  /* If we need this (determined above) it is because the runtime wants to
+     refer to it in a manner hidden from the compiler.  So we must force the 
+     output.  */
+  DECL_PRESERVE_P (decl) = 1;
   finish_var_decl (decl, objc_build_constructor (TREE_TYPE (decl), v));
 }
 
Index: gcc/testsuite/objc.dg/lto/trivial-1_0.m
===================================================================
--- gcc/testsuite/objc.dg/lto/trivial-1_0.m	(revision 0)
+++ gcc/testsuite/objc.dg/lto/trivial-1_0.m	(revision 0)
@@ -0,0 +1,37 @@ 
+/* { dg-lto-do run } */
+/* { dg-skip-if "" { "*-*-darwin*" && lp64 } { "*" } { "" } } */
+extern int printf (char *,...) ;
+
+typedef struct objc_class *Class;
+
+struct objc_class {
+    Class isa;
+    /* other stuff... */
+}  ;
+
+@interface myRootObject {
+@public
+     Class isa;
+}
++initialize;
++(Class)class;
+
+@end
+
+@implementation myRootObject
++initialize {
+     return self;
+}
+
++(Class)class {
+     return (Class)self;
+}
+
+@end
+
+int main(void)
+{
+  [myRootObject class];
+  printf("trivial OK\n");
+  return 0;
+}
Index: gcc/testsuite/objc.dg/lto/lto.exp
===================================================================
--- gcc/testsuite/objc.dg/lto/lto.exp	(revision 0)
+++ gcc/testsuite/objc.dg/lto/lto.exp	(revision 0)
@@ -0,0 +1,84 @@ 
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+# Based on gcc/testsuite/gcc.dg/lto/lto.exp.
+
+# Test link-time optimization across multiple files.
+#
+# Programs are broken into multiple files.  Each one is compiled
+# separately with LTO information.  The final executable is generated
+# by collecting all the generated object files using regular LTO or WHOPR.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# Load procedures from common libraries. 
+load_lib standard.exp
+load_lib objc-dg.exp
+
+# Load the language-independent compabibility support procedures.
+load_lib lto.exp
+
+# If LTO has not been enabled, bail.
+if { ![check_effective_target_lto] } {
+    return
+}
+
+global LTO_OPTIONS
+
+set LTO_OPTIONS [list	\
+  {-O0 -fwhopr -fgnu-runtime}	\
+  {-O2 -fwhopr -fgnu-runtime}	\
+  {-O0 -flto -fgnu-runtime} 	\
+  {-O2 -flto -fgnu-runtime}	\
+]
+
+objc_init
+lto_init no-mathlib
+
+# Define an identifier for use with this suite to avoid name conflicts
+# with other lto tests running at the same time.
+set sid "objc_lto"
+set tests [lsort [glob -nocomplain $srcdir/$subdir/*_0.m]]
+
+# Main loop.
+foreach src $tests {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $src] then {
+	continue
+    }
+    lto-execute $src $sid
+}
+
+# darwin targets can also run code with the NeXT runtime.
+if [istarget "*-*-darwin*" ] {
+set LTO_OPTIONS [list	\
+  {-O0 -fwhopr -fnext-runtime}	\
+  {-O2 -fwhopr -fnext-runtime}	\
+  {-O0 -flto -fnext-runtime} 	\
+  {-O2 -flto -fnext-runtime}	\
+]
+  foreach src $tests {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $src] then {
+	continue
+    }
+    lto-execute $src $sid
+  }
+}
+
+lto_finish
Index: gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm	(revision 0)
@@ -0,0 +1,43 @@ 
+/* { dg-lto-do run } */
+/* { dg-skip-if "Needs OBJC2 ABI" { "*-*-darwin*" && lp64 } { "*" } { "" } } */
+extern "C" {
+extern int printf (char *,...) ;
+extern void abort (void) ;
+} 
+
+typedef struct objc_class *Class;
+
+struct objc_class {
+    Class isa;
+    /* other stuff... */
+}  ;
+
+@interface myRootObject {
+@public
+     Class isa; 
+}
++initialize;
++(Class)class;
+
+@end
+
+@implementation myRootObject
++initialize {
+     return self;
+}
+
++(Class)class {
+     return (Class)self;
+}
+
+@end
+
+int main(void)
+{
+  Class cl = [myRootObject class];
+  if (cl != (Class)0) {
+    printf((char *)"trivial OK\n");
+    return 0;
+  }
+  abort () ;
+}
Index: gcc/testsuite/obj-c++.dg/lto/lto.exp
===================================================================
--- gcc/testsuite/obj-c++.dg/lto/lto.exp	(revision 0)
+++ gcc/testsuite/obj-c++.dg/lto/lto.exp	(revision 0)
@@ -0,0 +1,84 @@ 
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+# Based on gcc/testsuite/gcc.dg/lto/lto.exp.
+
+# Test link-time optimization across multiple files.
+#
+# Programs are broken into multiple files.  Each one is compiled
+# separately with LTO information.  The final executable is generated
+# by collecting all the generated object files using regular LTO or WHOPR.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# Load procedures from common libraries. 
+load_lib standard.exp
+load_lib obj-c++-dg.exp
+
+# Load the language-independent compabibility support procedures.
+load_lib lto.exp
+
+# If LTO has not been enabled, bail.
+if { ![check_effective_target_lto] } {
+    return
+}
+
+global LTO_OPTIONS
+
+set LTO_OPTIONS [list	\
+  {-O0 -fwhopr -fgnu-runtime}	\
+  {-O2 -fwhopr -fgnu-runtime}	\
+  {-O0 -flto -fgnu-runtime} 	\
+  {-O2 -flto -fgnu-runtime}	\
+]
+
+obj-c++_init
+lto_init no-mathlib
+
+# Define an identifier for use with this suite to avoid name conflicts
+# with other lto tests running at the same time.
+set sid "obj_cpp_lto"
+set tests [lsort [glob -nocomplain $srcdir/$subdir/*_0.mm]]
+
+# Main loop.
+foreach src $tests {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $src] then {
+	continue
+    }
+    lto-execute $src $sid
+}
+
+# darwin targets can also run code with the NeXT runtime.
+if [istarget "*-*-darwin*" ] {
+set LTO_OPTIONS [list	\
+  {-O0 -fwhopr -fnext-runtime}	\
+  {-O2 -fwhopr -fnext-runtime}	\
+  {-O0 -flto -fnext-runtime} 	\
+  {-O2 -flto -fnext-runtime}	\
+]
+  foreach src $tests {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $src] then {
+	continue
+    }
+    lto-execute $src $sid
+  }
+}
+
+lto_finish
Index: gcc/testsuite/objc.dg/symtab-1.m
===================================================================
--- gcc/testsuite/objc.dg/symtab-1.m	(revision 162024)
+++ gcc/testsuite/objc.dg/symtab-1.m	(working copy)
@@ -22,6 +22,7 @@ 
 -(void)checkValues { }
 @end
 
-/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.long\t0\n\t.long\t0\n\t.word\t2\n\t.word\t0\n\t.long\tL_OBJC_CLASS_Derived.*\n\t.long\tL_OBJC_CLASS_Base.*\n" { target { i?86-*-darwin* && { ! lp64 } } } } } */
-/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.long\t0\n\t.long\t0\n\t.short\t2\n\t.short\t0\n\t.long\tL_OBJC_CLASS_Derived.*\n\t.long\tL_OBJC_CLASS_Base.*\n" { target { powerpc-*-darwin* && { ! lp64 } } } } } */
-/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.quad\t0\n\t.long\t0\n\t.space 4\n\t.word\t2\n\t.word\t0\n\t.space 4\n\t.quad\tL_OBJC_CLASS_Derived.*\n\t.quad\tL_OBJC_CLASS_Base.*\n" { target { *-*-darwin* && { lp64 } } } } } */
+/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.long\t0\n\t.long\t0\n\t.word\t2\n\t.word\t0\n\t.long\tL_OBJC_CLASS_Derived.*\n\t.long\tL_OBJC_CLASS_Base.*\n" { target { *86*-*-darwin* && { ! lp64 } } } } } */
+/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.long\t0\n\t.long\t0\n\t.short\t2\n\t.short\t0\n\t.long\tL_OBJC_CLASS_Derived.*\n\t.long\tL_OBJC_CLASS_Base.*\n" { target { powerpc*-*-darwin* && { ! lp64 } } } } } */
+/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.quad\t0\n\t.quad\t0\n\t.word\t2\n\t.word\t0\n\t.space 4\n\t.quad\tL_OBJC_CLASS_Derived.*\n\t.quad\tL_OBJC_CLASS_Base.*\n" { target { *86*-*-darwin* && { lp64 } } } } } */
+/* { dg-final { scan-assembler "L_OBJC_SYMBOLS.*:\n\t.quad\t0\n\t.quad\t0\n\t.short\t2\n\t.short\t0\n\t.space 4\n\t.quad\tL_OBJC_CLASS_Derived.*\n\t.quad\tL_OBJC_CLASS_Base.*\n" { target { powerpc*-*-darwin* && { lp64 } } } } } */
Index: gcc/testsuite/objc.dg/image-info.m
===================================================================
--- gcc/testsuite/objc.dg/image-info.m	(revision 162024)
+++ gcc/testsuite/objc.dg/image-info.m	(working copy)
@@ -4,6 +4,7 @@ 
 /* Contributed by Ziemowit Laski <zlaski@apple.com>.  */
 
 /* { dg-do compile { target { *-*-darwin* } } } */
+/* { dg-skip-if "NeXT-only" { *-*-* } { "-fgnu-runtime" } { "" } } */
 /* { dg-options "-freplace-objc-classes" } */
 
 #include "../objc-obj-c++-shared/Object1.h"