* arm.cc (Target_arm::attributes_accept_div): New function.
authorIan Lance Taylor <ian@airs.com>
Wed, 9 Jan 2013 15:27:24 +0000 (15:27 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 9 Jan 2013 15:27:24 +0000 (15:27 +0000)
(Target_arm::attributes_forbid_div): New function.
(Target_arm::merge_object_attributes): Merge the Tag_DIV_use
attribute using the same new functions as what bfd/elf32_arm.c
does.

gold/ChangeLog
gold/arm.cc

index 9d48cd0f0264a4195f3425b67c11b4b44860da53..1ee71dd6b8443857d92646f92af0839c15c5a5df 100644 (file)
@@ -1,3 +1,11 @@
+2013-01-09  Ben Cheng  <bccheng@google.com>
+
+       * arm.cc (Target_arm::attributes_accept_div): New function.
+       (Target_arm::attributes_forbid_div): New function.
+       (Target_arm::merge_object_attributes): Merge the Tag_DIV_use
+       attribute using the same new functions as what bfd/elf32_arm.c
+       does.
+
 2013-01-07  Cary Coutant  <ccoutant@google.com>
 
        PR gold/14993
index 736a4ae4dc43bfa7023f8172bc5cfaae5d6ed238..e9db6f9e76651e309fdd6c323d3584d748f17ad4 100644 (file)
@@ -1,6 +1,6 @@
 // arm.cc -- arm target support for gold.
 
-// Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+// Copyright 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
 // Written by Doug Kwan <dougkwan@google.com> based on the i386 code
 // by Ian Lance Taylor <iant@google.com>.
 // This file also contains borrowed and adapted code from
@@ -2798,6 +2798,18 @@ class Target_arm : public Sized_target<32, big_endian>
   static std::string
   tag_cpu_name_value(unsigned int);
 
+  // Query attributes object to see if integer divide instructions may be
+  // present in an object.
+  static bool
+  attributes_accept_div(int arch, int profile,
+                       const Object_attribute* div_attr);
+
+  // Query attributes object to see if integer divide instructions are
+  // forbidden to be in the object.  This is not the inverse of
+  // attributes_accept_div.
+  static bool
+  attributes_forbid_div(const Object_attribute* div_attr);
+
   // Merge object attributes from input object and those in the output.
   void
   merge_object_attributes(const char*, const Attributes_section_data*);
@@ -10382,6 +10394,49 @@ Target_arm<big_endian>::tag_cpu_name_value(unsigned int value)
     }
 }
 
+// Query attributes object to see if integer divide instructions may be
+// present in an object.
+
+template<bool big_endian>
+bool
+Target_arm<big_endian>::attributes_accept_div(int arch, int profile,
+    const Object_attribute* div_attr)
+{
+  switch (div_attr->int_value())
+    {
+    case 0:
+      // Integer divide allowed if instruction contained in
+      // archetecture.
+      if (arch == elfcpp::TAG_CPU_ARCH_V7 && (profile == 'R' || profile == 'M'))
+        return true;
+      else if (arch >= elfcpp::TAG_CPU_ARCH_V7E_M)
+        return true;
+      else
+        return false;
+
+    case 1:
+      // Integer divide explicitly prohibited.
+      return false;
+
+    default:
+      // Unrecognised case - treat as allowing divide everywhere.
+    case 2:
+      // Integer divide allowed in ARM state.
+      return true;
+    }
+}
+
+// Query attributes object to see if integer divide instructions are
+// forbidden to be in the object.  This is not the inverse of
+// attributes_accept_div.
+
+template<bool big_endian>
+bool
+Target_arm<big_endian>::attributes_forbid_div(const Object_attribute* div_attr)
+{
+  return div_attr->int_value() == 1;
+}
+
 // Merge object attributes from input file called NAME with those of the
 // output.  The input object attributes are in the object pointed by PASD.
 
@@ -10751,27 +10806,33 @@ Target_arm<big_endian>::merge_object_attributes(
          break;
 
        case elfcpp::Tag_DIV_use:
-         // This tag is set to zero if we can use UDIV and SDIV in Thumb
-         // mode on a v7-M or v7-R CPU; to one if we can not use UDIV or
-         // SDIV at all; and to two if we can use UDIV or SDIV on a v7-A
-         // CPU.  We will merge as follows: If the input attribute's value
-         // is one then the output attribute's value remains unchanged.  If
-         // the input attribute's value is zero or two then if the output
-         // attribute's value is one the output value is set to the input
-         // value, otherwise the output value must be the same as the
-         // inputs.  */
-         if (in_attr[i].int_value() != 1 && out_attr[i].int_value() != 1)
-           {
-             if (in_attr[i].int_value() != out_attr[i].int_value())
-               {
-                 gold_error(_("DIV usage mismatch between %s and output"),
-                            name);
-               }
-           }
-
-         if (in_attr[i].int_value() != 1)
-           out_attr[i].set_int_value(in_attr[i].int_value());
-
+         {
+           // A value of zero on input means that the divide
+           // instruction may be used if available in the base
+           // architecture as specified via Tag_CPU_arch and
+           // Tag_CPU_arch_profile.  A value of 1 means that the user
+           // did not want divide instructions.  A value of 2
+           // explicitly means that divide instructions were allowed
+           // in ARM and Thumb state.
+           int arch = this->
+             get_aeabi_object_attribute(elfcpp::Tag_CPU_arch)->
+             int_value();
+           int profile = this->
+             get_aeabi_object_attribute(elfcpp::Tag_CPU_arch_profile)->
+             int_value();
+           if (in_attr[i].int_value() == out_attr[i].int_value())
+             {
+               // Do nothing.
+             }
+           else if (attributes_forbid_div(&in_attr[i])
+                    && !attributes_accept_div(arch, profile, &out_attr[i])) 
+             out_attr[i].set_int_value(1);
+           else if (attributes_forbid_div(&out_attr[i])
+                    && attributes_accept_div(arch, profile, &in_attr[i]))
+             out_attr[i].set_int_value(in_attr[i].int_value());
+           else if (in_attr[i].int_value() == 2)
+             out_attr[i].set_int_value(in_attr[i].int_value());
+         }
          break;
 
        case elfcpp::Tag_MPextension_use_legacy: