[ARM] Add support for -mpure-code option
authorAndre Vieira <andre.simoesdiasvieira@arm.com>
Thu, 22 Sep 2016 17:02:47 +0000 (17:02 +0000)
committerAndre Vieira <avieira@gcc.gnu.org>
Thu, 22 Sep 2016 17:02:47 +0000 (17:02 +0000)
gcc/ChangeLog:
2016-09-22  Andre Vieira  <andre.simoesdiasvieira@arm.com>
            Terry Guo  <terry.guo@arm.com>

    * target.def (elf_flags_numeric): New target hook.
    * targhooks.h (default_asm_elf_flags_numeric): New.
    * varasm.c (default_asm_elf_flags_numeric): New.
    (default_elf_asm_named_section): Use new target hook.
    * config/arm/arm.opt (mpure-code): New.
    * config/arm/arm.h (SECTION_ARM_PURECODE): New.
    * config/arm/arm.c (arm_asm_init_sections): Add section
    attribute to default text section if -mpure-code.
    (arm_option_check_internal): Diagnose use of option with
    non supported targets and/or options.
    (arm_asm_elf_flags_numeric): New.
    (arm_function_section): New.
    (arm_elf_section_type_flags): New.
    * config/arm/elf.h (JUMP_TABLES_IN_TEXT_SECTION): Disable
    for -mpure-code.
    * gcc/doc/texi (TARGET_ASM_ELF_FLAGS_NUMERIC): New.
    * gcc/doc/texi.in (TARGET_ASM_ELF_FLAGS_NUMERIC): Likewise.

gcc/testsuite/ChangeLog:
2016-09-22  Andre Vieira  <andre.simoesdiasvieira@arm.com>
            Terry Guo  <terry.guo@arm.com>

    * gcc.target/arm/pure-code/ffunction-sections.c: New.
    * gcc.target/arm/pure-code/no-literal-pool.c: New.
    * gcc.target/arm/pure-code/pure-code.exp: New.

Co-Authored-By: Terry Guo <terry.guo@arm.com>
From-SVN: r240379

13 files changed:
gcc/ChangeLog
gcc/config/arm/arm.c
gcc/config/arm/arm.h
gcc/config/arm/arm.md
gcc/config/arm/arm.opt
gcc/config/arm/elf.h
gcc/doc/invoke.texi
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/hooks.c
gcc/target.def
gcc/testsuite/ChangeLog
gcc/varasm.c

index 21284824048ac4bd7ed1d331aeaeb2263770a15d..2fbe852ab54c30641a5c3e4770b920260bf4e75c 100644 (file)
@@ -1,3 +1,24 @@
+2016-09-22  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+           Terry Guo  <terry.guo@arm.com>
+
+       * target.def (elf_flags_numeric): New target hook.
+       * targhooks.h (default_asm_elf_flags_numeric): New.
+       * varasm.c (default_asm_elf_flags_numeric): New.
+       (default_elf_asm_named_section): Use new target hook.
+       * config/arm/arm.opt (mpure-code): New.
+       * config/arm/arm.h (SECTION_ARM_PURECODE): New.
+       * config/arm/arm.c (arm_asm_init_sections): Add section
+       attribute to default text section if -mpure-code.
+       (arm_option_check_internal): Diagnose use of option with
+       non supported targets and/or options.
+       (arm_asm_elf_flags_numeric): New.
+       (arm_function_section): New.
+       (arm_elf_section_type_flags): New.
+       * config/arm/elf.h (JUMP_TABLES_IN_TEXT_SECTION): Disable
+       for -mpure-code.
+       * gcc/doc/texi (TARGET_ASM_ELF_FLAGS_NUMERIC): New.
+       * gcc/doc/texi.in (TARGET_ASM_ELF_FLAGS_NUMERIC): Likewise.
+
 2016-09-22  Jan Hubicka  <hubicka@ucw.cz>
 
        * regcprop.c (copyprop_hardreg_forward_1): Remove noop moves.
index 594dc1756e03d7376981cadcedae050852d64690..b68e0056d7697de82861cc0f342db6f78c732fae 100644 (file)
@@ -214,8 +214,8 @@ static bool arm_return_in_memory (const_tree, const_tree);
 static void arm_unwind_emit (FILE *, rtx_insn *);
 static bool arm_output_ttype (rtx);
 static void arm_asm_emit_except_personality (rtx);
-static void arm_asm_init_sections (void);
 #endif
+static void arm_asm_init_sections (void);
 static rtx arm_dwarf_register_span (rtx);
 
 static tree arm_cxx_guard_type (void);
@@ -299,7 +299,10 @@ static unsigned HOST_WIDE_INT arm_asan_shadow_offset (void);
 static void arm_sched_fusion_priority (rtx_insn *, int, int *, int*);
 static bool arm_can_output_mi_thunk (const_tree, HOST_WIDE_INT, HOST_WIDE_INT,
                                     const_tree);
-
+static section *arm_function_section (tree, enum node_frequency, bool, bool);
+static bool arm_asm_elf_flags_numeric (unsigned int flags, unsigned int *num);
+static unsigned int arm_elf_section_type_flags (tree decl, const char *name,
+                                               int reloc);
 \f
 /* Table of machine attributes.  */
 static const struct attribute_spec arm_attribute_table[] =
@@ -584,8 +587,8 @@ static const struct attribute_spec arm_attribute_table[] =
 #define TARGET_ASM_EMIT_EXCEPT_PERSONALITY arm_asm_emit_except_personality
 
 #undef TARGET_ASM_INIT_SECTIONS
-#define TARGET_ASM_INIT_SECTIONS arm_asm_init_sections
 #endif /* ARM_UNWIND_INFO */
+#define TARGET_ASM_INIT_SECTIONS arm_asm_init_sections
 
 #undef TARGET_DWARF_REGISTER_SPAN
 #define TARGET_DWARF_REGISTER_SPAN arm_dwarf_register_span
@@ -726,6 +729,15 @@ static const struct attribute_spec arm_attribute_table[] =
 #undef TARGET_SCHED_FUSION_PRIORITY
 #define TARGET_SCHED_FUSION_PRIORITY arm_sched_fusion_priority
 
+#undef  TARGET_ASM_FUNCTION_SECTION
+#define TARGET_ASM_FUNCTION_SECTION arm_function_section
+
+#undef TARGET_ASM_ELF_FLAGS_NUMERIC
+#define TARGET_ASM_ELF_FLAGS_NUMERIC arm_asm_elf_flags_numeric
+
+#undef TARGET_SECTION_TYPE_FLAGS
+#define TARGET_SECTION_TYPE_FLAGS arm_elf_section_type_flags
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Obstack for minipool constant handling.  */
@@ -2837,6 +2849,12 @@ arm_option_check_internal (struct gcc_options *opts)
       && ((!(arm_arch7 && !arm_arch_notm) && !arm_arch7em)
          || (TARGET_THUMB1_P (flags) || flag_pic || TARGET_NEON)))
     error ("-mslow-flash-data only supports non-pic code on armv7-m targets");
+
+  /* We only support pure-code on Thumb-2 M-profile targets.  */
+  if (target_pure_code
+      && (!arm_arch_thumb2 || arm_arch_notm || flag_pic || TARGET_NEON))
+    error ("-mpure-code only supports non-pic code on armv7-m targets");
+
 }
 
 /* Recompute the global settings depending on target attribute options.  */
@@ -3487,8 +3505,9 @@ arm_option_override (void)
                         global_options.x_param_values,
                         global_options_set.x_param_values);
 
-  /* Currently, for slow flash data, we just disable literal pools.  */
-  if (target_slow_flash_data)
+  /* Currently, for slow flash data, we just disable literal pools.  We also
+     disable it for pure-code.  */
+  if (target_slow_flash_data || target_pure_code)
     arm_disable_literal_pool = true;
 
   /* Disable scheduling fusion by default if it's not armv7 processor
@@ -27262,17 +27281,24 @@ arm_asm_emit_except_personality (rtx personality)
   output_addr_const (asm_out_file, personality);
   fputc ('\n', asm_out_file);
 }
+#endif /* ARM_UNWIND_INFO */
 
 /* Implement TARGET_ASM_INITIALIZE_SECTIONS.  */
 
 static void
 arm_asm_init_sections (void)
 {
+#if ARM_UNWIND_INFO
   exception_section = get_unnamed_section (0, output_section_asm_op,
                                           "\t.handlerdata");
-}
 #endif /* ARM_UNWIND_INFO */
 
+#ifdef OBJECT_FORMAT_ELF
+  if (target_pure_code)
+    text_section->unnamed.data = "\t.section .text,\"0x20000006\",%progbits";
+#endif
+}
+
 /* Output unwind directives for the start/end of a function.  */
 
 void
@@ -30613,4 +30639,111 @@ arm_gen_unlikely_cbranch (enum rtx_code code, machine_mode cc_mode,
   emit_unlikely_jump (gen_rtx_SET (pc_rtx, x));
 }
 
+/* Implement the TARGET_ASM_ELF_FLAGS_NUMERIC hook.
+
+   For pure-code sections there is no letter code for this attribute, so
+   output all the section flags numerically when this is needed.  */
+
+static bool
+arm_asm_elf_flags_numeric (unsigned int flags, unsigned int *num)
+{
+
+  if (flags & SECTION_ARM_PURECODE)
+    {
+      *num = 0x20000000;
+
+      if (!(flags & SECTION_DEBUG))
+       *num |= 0x2;
+      if (flags & SECTION_EXCLUDE)
+       *num |= 0x80000000;
+      if (flags & SECTION_WRITE)
+       *num |= 0x1;
+      if (flags & SECTION_CODE)
+       *num |= 0x4;
+      if (flags & SECTION_MERGE)
+       *num |= 0x10;
+      if (flags & SECTION_STRINGS)
+       *num |= 0x20;
+      if (flags & SECTION_TLS)
+       *num |= 0x400;
+      if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+       *num |= 0x200;
+
+       return true;
+    }
+
+  return false;
+}
+
+/* Implement the TARGET_ASM_FUNCTION_SECTION hook.
+
+   If pure-code is passed as an option, make sure all functions are in
+   sections that have the SHF_ARM_PURECODE attribute.  */
+
+static section *
+arm_function_section (tree decl, enum node_frequency freq,
+                     bool startup, bool exit)
+{
+  const char * section_name;
+  section * sec;
+
+  if (!decl || TREE_CODE (decl) != FUNCTION_DECL)
+    return default_function_section (decl, freq, startup, exit);
+
+  if (!target_pure_code)
+    return default_function_section (decl, freq, startup, exit);
+
+
+  section_name = DECL_SECTION_NAME (decl);
+
+  /* If a function is not in a named section then it falls under the 'default'
+     text section, also known as '.text'.  We can preserve previous behavior as
+     the default text section already has the SHF_ARM_PURECODE section
+     attribute.  */
+  if (!section_name)
+    {
+      section *default_sec = default_function_section (decl, freq, startup,
+                                                      exit);
+
+      /* If default_sec is not null, then it must be a special section like for
+        example .text.startup.  We set the pure-code attribute and return the
+        same section to preserve existing behavior.  */
+      if (default_sec)
+         default_sec->common.flags |= SECTION_ARM_PURECODE;
+      return default_sec;
+    }
+
+  /* Otherwise look whether a section has already been created with
+     'section_name'.  */
+  sec = get_named_section (decl, section_name, 0);
+  if (!sec)
+    /* If that is not the case passing NULL as the section's name to
+       'get_named_section' will create a section with the declaration's
+       section name.  */
+    sec = get_named_section (decl, NULL, 0);
+
+  /* Set the SHF_ARM_PURECODE attribute.  */
+  sec->common.flags |= SECTION_ARM_PURECODE;
+
+  return sec;
+}
+
+/* Implements the TARGET_SECTION_FLAGS hook.
+
+   If DECL is a function declaration and pure-code is passed as an option
+   then add the SFH_ARM_PURECODE attribute to the section flags.  NAME is the
+   section's name and RELOC indicates whether the declarations initializer may
+   contain runtime relocations.  */
+
+static unsigned int
+arm_elf_section_type_flags (tree decl, const char *name, int reloc)
+{
+  unsigned int flags = default_section_type_flags (decl, name, reloc);
+
+  if (decl && TREE_CODE (decl) == FUNCTION_DECL && target_pure_code)
+    flags |= SECTION_ARM_PURECODE;
+
+  return flags;
+}
+
 #include "gt-arm.h"
index c7149d1f49738f9f01232cdcb610caca0e5f7e5d..31eb45a05b0a168c9f27c7c4984b5e9a2718f62f 100644 (file)
@@ -2276,4 +2276,8 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
 /* For switching between functions with different target attributes.  */
 #define SWITCHABLE_TARGET 1
 
+/* Define SECTION_ARM_PURECODE as the ARM specific section attribute
+   representation for SHF_ARM_PURECODE in GCC.  */
+#define SECTION_ARM_PURECODE SECTION_MACH_DEP
+
 #endif /* ! GCC_ARM_H */
index 318db75ece9615412b48943ba197aae364a78a54..4df856a98d7934befdd6f9c942763f998c9f0f26 100644 (file)
    (match_operand:SI 2 "const_int_operand" "") ; total range
    (match_operand:SI 3 "" "")                  ; table label
    (match_operand:SI 4 "" "")]                 ; Out of range label
-  "TARGET_32BIT || optimize_size || flag_pic"
+  "(TARGET_32BIT || optimize_size || flag_pic) && !target_pure_code"
   "
   {
     enum insn_code code;
index 0ebe0174390167b79a64583c35a3f8fb018f6538..35f047e2de1659c2b426cf42dbbdae5be62cbfef 100644 (file)
@@ -281,3 +281,7 @@ Assume loading data from flash is slower than fetching instructions.
 masm-syntax-unified
 Target Report Var(inline_asm_unified) Init(0) Save
 Assume unified syntax for inline assembly code.
+
+mpure-code
+Target Report Var(target_pure_code) Init(0)
+Do not allow constant data to be placed in code sections.
index 246de5492665ba2a0292736a9c53fbaaef184d72..bc4eb86f1da5beabf32647637eb87a3fc17a6c6a 100644 (file)
    the code more efficient, but for Thumb-1 it's better to put them out of
    band unless we are generating compressed tables.  */
 #define JUMP_TABLES_IN_TEXT_SECTION                                    \
-   (TARGET_32BIT || (TARGET_THUMB && (optimize_size || flag_pic)))
+   ((TARGET_32BIT || (TARGET_THUMB && (optimize_size || flag_pic))) \
+    && !target_pure_code)
 
 #ifndef LINK_SPEC
 #define LINK_SPEC "%{mbig-endian:-EB} %{mlittle-endian:-EL} -X"
index cfba069cf2bb416479de565e429ee7a258ad6f3e..d474da6a39de52f729ccb9887ab9ee00c48e6b5a 100644 (file)
@@ -641,7 +641,8 @@ Objective-C and Objective-C++ Dialects}.
 -mneon-for-64bits @gol
 -mslow-flash-data @gol
 -masm-syntax-unified @gol
--mrestrict-it}
+-mrestrict-it @gol
+-mpure-code}
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu} -maccumulate-args -mbranch-cost=@var{cost} @gol
@@ -14844,6 +14845,14 @@ Print CPU tuning information as comment in assembler file.  This is
 an option used only for regression testing of the compiler and not
 intended for ordinary use in compiling code.  This option is disabled
 by default.
+
+@item -mpure-code
+@opindex mpure-code
+Do not allow constant data to be placed in code sections.
+Additionally, when compiling for ELF object format give all text sections the
+ELF processor-specific section attribute @code{SHF_ARM_PURECODE}.  This option
+is only available when generating non-pic code for ARMv7-M targets.
+
 @end table
 
 @node AVR Options
index 61d3a67c88eee412f28cd9da77aa08c1bb47923b..68a77e81aa1e2abcc15bc9088011295df699c4d0 100644 (file)
@@ -7568,6 +7568,18 @@ is non-NULL, it is the @code{VAR_DECL} or @code{FUNCTION_DECL} with which
 this section is associated.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_ASM_ELF_FLAGS_NUMERIC (unsigned int @var{flags}, unsigned int *@var{num})
+This hook can be used to encode ELF section flags for which no letter
+code has been defined in the assembler.  It is called by
+@code{default_asm_named_section} whenever the section flags need to be
+emitted in the assembler output.  If the hook returns true, then the
+numerical value for ELF section flags should be calculated from
+@var{flags} and saved in @var{*num}; the value will be printed out
+instead of the normal sequence of letter codes.  If the hook is not
+defined, or if it returns false, then @var{num} will be ignored and the
+traditional letter sequence will be emitted.
+@end deftypefn
+
 @deftypefn {Target Hook} {section *} TARGET_ASM_FUNCTION_SECTION (tree @var{decl}, enum node_frequency @var{freq}, bool @var{startup}, bool @var{exit})
 Return preferred text (sub)section for function @var{decl}.
 Main purpose of this function is to separate cold, normal and hot
index fd3d65dcf3e24ef5cc288474048f6ac6fd5550b4..f1cfc863f30d25c5ef3d0bba055205d5280b305d 100644 (file)
@@ -5219,6 +5219,8 @@ of the filename using this macro.
 
 @hook TARGET_ASM_NAMED_SECTION
 
+@hook TARGET_ASM_ELF_FLAGS_NUMERIC
+
 @hook TARGET_ASM_FUNCTION_SECTION
 
 @hook TARGET_ASM_FUNCTION_SWITCHED_TEXT_SECTIONS
index 99ec4014adb6fcbb073bf538dd00fe8695ee6cb2..1e925645c3173f8d97e104b9b2f480fca2ede438 100644 (file)
@@ -481,3 +481,13 @@ void
 hook_void_gcc_optionsp (struct gcc_options *opts ATTRIBUTE_UNUSED)
 {
 }
+
+/* Generic hook that takes an unsigned int, an unsigned int pointer and
+   returns false.  */
+
+bool
+hook_uint_uintp_false (unsigned int, unsigned int *)
+{
+  return false;
+}
+
index 33acc79d5ed24f24293158bf69dcc2fb46631ad0..ac693318adaaa230ea300f10bc37282881d9da6f 100644 (file)
@@ -432,6 +432,22 @@ this section is associated.",
  void, (const char *name, unsigned int flags, tree decl),
  default_no_named_section)
 
+/* Tell assembler what section attributes to assign this elf section
+   declaration, using their numerical value.  */
+DEFHOOK
+(elf_flags_numeric,
+ "This hook can be used to encode ELF section flags for which no letter\n\
+code has been defined in the assembler.  It is called by\n\
+@code{default_asm_named_section} whenever the section flags need to be\n\
+emitted in the assembler output.  If the hook returns true, then the\n\
+numerical value for ELF section flags should be calculated from\n\
+@var{flags} and saved in @var{*num}; the value will be printed out\n\
+instead of the normal sequence of letter codes.  If the hook is not\n\
+defined, or if it returns false, then @var{num} will be ignored and the\n\
+traditional letter sequence will be emitted.",
+ bool, (unsigned int flags, unsigned int *num),
+ hook_uint_uintp_false)
+
 /* Return preferred text (sub)section for function DECL.
    Main purpose of this function is to separate cold, normal and hot
    functions. STARTUP is true when function is known to be used only 
index 86d80258f2c145a35a2ec77e8284ae69df0e5c2d..37e220db058ddb8ddcbb37a0a43b45e3051486f1 100644 (file)
@@ -1,3 +1,10 @@
+2016-09-22  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+           Terry Guo  <terry.guo@arm.com>
+
+       * gcc.target/arm/pure-code/ffunction-sections.c: New.
+       * gcc.target/arm/pure-code/no-literal-pool.c: New.
+       * gcc.target/arm/pure-code/pure-code.exp: New.
+
 2016-09-22  Uros Bizjak  <ubizjak@gmail.com>
 
        * gcc.dg/debug/dwarf2/const-2b.c: Also compile for x86_64-*-*.
index ba866ce8044c9a9ffd9d16000aaedea815605bb0..72cba8678709f2568372120523a2db4dabf7130d 100644 (file)
@@ -6256,6 +6256,7 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
                               tree decl)
 {
   char flagchars[11], *f = flagchars;
+  unsigned int numeric_value = 0;
 
   /* If we have already declared this section, we can use an
      abbreviated form to switch back to it -- unless this section is
@@ -6268,31 +6269,38 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
       return;
     }
 
-  if (!(flags & SECTION_DEBUG))
-    *f++ = 'a';
+  /* If we have a machine specific flag, then use the numeric value to pass
+     this on to GAS.  */
+  if (targetm.asm_out.elf_flags_numeric (flags, &numeric_value))
+      snprintf (f, sizeof (flagchars), "0x%08x", numeric_value);
+  else
+    {
+      if (!(flags & SECTION_DEBUG))
+       *f++ = 'a';
 #if defined (HAVE_GAS_SECTION_EXCLUDE) && HAVE_GAS_SECTION_EXCLUDE == 1
-  if (flags & SECTION_EXCLUDE)
-    *f++ = 'e';
+      if (flags & SECTION_EXCLUDE)
+       *f++ = 'e';
 #endif
-  if (flags & SECTION_WRITE)
-    *f++ = 'w';
-  if (flags & SECTION_CODE)
-    *f++ = 'x';
-  if (flags & SECTION_SMALL)
-    *f++ = 's';
-  if (flags & SECTION_MERGE)
-    *f++ = 'M';
-  if (flags & SECTION_STRINGS)
-    *f++ = 'S';
-  if (flags & SECTION_TLS)
-    *f++ = TLS_SECTION_ASM_FLAG;
-  if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
-    *f++ = 'G';
+      if (flags & SECTION_WRITE)
+       *f++ = 'w';
+      if (flags & SECTION_CODE)
+       *f++ = 'x';
+      if (flags & SECTION_SMALL)
+       *f++ = 's';
+      if (flags & SECTION_MERGE)
+       *f++ = 'M';
+      if (flags & SECTION_STRINGS)
+       *f++ = 'S';
+      if (flags & SECTION_TLS)
+       *f++ = TLS_SECTION_ASM_FLAG;
+      if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+       *f++ = 'G';
 #ifdef MACH_DEP_SECTION_ASM_FLAG
-  if (flags & SECTION_MACH_DEP)
-    *f++ = MACH_DEP_SECTION_ASM_FLAG;
+      if (flags & SECTION_MACH_DEP)
+       *f++ = MACH_DEP_SECTION_ASM_FLAG;
 #endif
-  *f = '\0';
+      *f = '\0';
+    }
 
   fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);