aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYvan Roux <yvan.roux@linaro.org>2017-05-05 10:45:30 +0200
committerYvan Roux <yvan.roux@linaro.org>2017-05-09 14:05:39 +0000
commit731974e96e270a16c3c11dad45e6ef2e3dfee532 (patch)
tree00e7fe20f3731eb9081828c464f26a86b2bdbb2a
parent68ee4ed72e710ac0e4c55582b850b35cf3b8532d (diff)
gcc/
Backport from trunk r240379. 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/ Backport from trunk r240379, r240746. 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. gcc/ Backport from trunk r240389. 2016-09-23 Richard Biener <rguenther@suse.de> * hooks.h (hook_uint_uintp_false): Declare. gcc/ Backport from trunk r240417. 2016-09-23 Uros Bizjak <ubizjak@gmail.com> Jakub Jelinek <jakub@redhat.com> * hooks.h (hook_uint_uintp_false): Rename to... (hook_bool_uint_uintp_false): ... this. * hooks.c (hook_uint_uintp_false): Rename to... (hook_bool_uint_uintp_false): ... this. * target.def (elf_flags_numeric): Use hook_bool_uint_uintp_false instead of hook_uint_uintp_false. gcc/ Backport from trunk r240490. 2016-09-26 Andre Vieira <andre.simoesdiasvieira@arm.com> * target.def(elf_flags_numeric): Change documentation to present tense. * doc/tm.texi: Regenerate. gcc/testsuite/ Backport from trunk r241396. 2016-10-21 Andre Vieira <andre.simoesdiasvieira@arm.com> * gcc.target/arm/pure-code/pure-code.exp: Require arm_cortex_m effective target. gcc/testsuite/ Backport from trunk r241466. 2016-10-24 Andre Vieira <andre.simoesdiasvieira@arm.com> * gcc.target/arm/pure-code/pure-code.exp: Restore saved globals. gcc/ Backport from trunk r243240. 2016-12-025 Andre Vieira <andre.simoesdiasvieira@arm.com> * config/arm/arm.c (TARGET_ASM_INIT_SECTIONS): Fix wrong undef location. gcc/ Backport from trunk r247585. 2017-05-04 Prakhar Bahuguna <prakhar.bahuguna@arm.com> Andre Simoes Dias Vieira <andre.simoesdiasvieira@arm.com> * config/arm/arm.md (movsi): Change TARGET_32BIT to TARGET_HAVE_MOVT. (movt splitter): Likewise. * config/arm/arm.c (arm_option_check_internal): Change arm_arch_thumb2 to TARGET_HAVE_MOVT, and merge with -mslow-flash-data check. (const_ok_for_arm): Change else to else if (TARGET_THUMB2) and add else block for Thumb-1 with MOVT. (thumb2_legitimate_address_p): Move code block ... (can_avoid_literal_pool_for_label_p): ... into this new function. (thumb1_legitimate_address_p): Add check for TARGET_HAVE_MOVT and literal pool. (thumb_legitimate_constant_p): Add conditional on TARGET_HAVE_MOVT * doc/invoke.texi (-mpure-code): Change "ARMv7-M targets" for "M-profile targets with the MOVT instruction". gcc/testsuite/ Backport from trunk r247585. 2017-05-04 Prakhar Bahuguna <prakhar.bahuguna@arm.com> Andre Simoes Dias Vieira <andre.simoesdiasvieira@arm.com> * gcc.target/arm/pure-code/pure-code.exp: Add conditional for check_effective_target_arm_thumb1_movt_ok. Change-Id: I1ccf796809007db36bb46bd2c35f973d7766e49b
-rw-r--r--gcc/config/arm/arm.c214
-rw-r--r--gcc/config/arm/arm.h4
-rw-r--r--gcc/config/arm/arm.md8
-rw-r--r--gcc/config/arm/arm.opt4
-rw-r--r--gcc/config/arm/elf.h3
-rw-r--r--gcc/doc/invoke.texi9
-rw-r--r--gcc/doc/tm.texi12
-rw-r--r--gcc/doc/tm.texi.in2
-rw-r--r--gcc/hooks.c9
-rw-r--r--gcc/hooks.h1
-rw-r--r--gcc/target.def16
-rw-r--r--gcc/testsuite/gcc.target/arm/pure-code/ffunction-sections.c17
-rw-r--r--gcc/testsuite/gcc.target/arm/pure-code/no-casesi.c29
-rw-r--r--gcc/testsuite/gcc.target/arm/pure-code/no-literal-pool.c68
-rw-r--r--gcc/testsuite/gcc.target/arm/pure-code/pure-code.exp59
-rw-r--r--gcc/varasm.c46
16 files changed, 448 insertions, 53 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index f709d8a4770..7e18e896ce0 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -212,8 +212,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);
@@ -297,7 +297,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);
/* Table of machine attributes. */
static const struct attribute_spec arm_attribute_table[] =
@@ -589,9 +592,10 @@ static const struct attribute_spec arm_attribute_table[] =
#undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY arm_asm_emit_except_personality
+#endif /* ARM_UNWIND_INFO */
+
#undef TARGET_ASM_INIT_SECTIONS
#define TARGET_ASM_INIT_SECTIONS arm_asm_init_sections
-#endif /* ARM_UNWIND_INFO */
#undef TARGET_DWARF_REGISTER_SPAN
#define TARGET_DWARF_REGISTER_SPAN arm_dwarf_register_span
@@ -732,6 +736,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;
/* Obstack for minipool constant handling. */
@@ -2824,11 +2837,17 @@ arm_option_check_internal (struct gcc_options *opts)
flag_pic = 0;
}
- /* We only support -mslow-flash-data on armv7-m targets. */
- if (target_slow_flash_data
- && ((!(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 -mpure-code and -mslow-flash-data on M-profile targets
+ with MOVT. */
+ if ((target_pure_code || target_slow_flash_data)
+ && (!TARGET_HAVE_MOVT || arm_arch_notm || flag_pic || TARGET_NEON))
+ {
+ const char *flag = (target_pure_code ? "-mpure-code" :
+ "-mslow-flash-data");
+ error ("%s only supports non-pic code on M-profile targets with the "
+ "MOVT instruction", flag);
+ }
+
}
/* Recompute the global settings depending on target attribute options. */
@@ -3482,8 +3501,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;
if (use_cmse && !arm_arch_cmse)
@@ -3929,7 +3949,7 @@ const_ok_for_arm (HOST_WIDE_INT i)
|| (i & ~0xfc000003) == 0))
return TRUE;
}
- else
+ else if (TARGET_THUMB2)
{
HOST_WIDE_INT v;
@@ -3945,6 +3965,14 @@ const_ok_for_arm (HOST_WIDE_INT i)
if (i == v)
return TRUE;
}
+ else if (TARGET_HAVE_MOVT)
+ {
+ /* Thumb-1 Targets with MOVT. */
+ if (i > 0xffff)
+ return FALSE;
+ else
+ return TRUE;
+ }
return FALSE;
}
@@ -7530,6 +7558,32 @@ arm_legitimate_address_outer_p (machine_mode mode, rtx x, RTX_CODE outer,
return 0;
}
+/* Return true if we can avoid creating a constant pool entry for x. */
+static bool
+can_avoid_literal_pool_for_label_p (rtx x)
+{
+ /* Normally we can assign constant values to target registers without
+ the help of constant pool. But there are cases we have to use constant
+ pool like:
+ 1) assign a label to register.
+ 2) sign-extend a 8bit value to 32bit and then assign to register.
+
+ Constant pool access in format:
+ (set (reg r0) (mem (symbol_ref (".LC0"))))
+ will cause the use of literal pool (later in function arm_reorg).
+ So here we mark such format as an invalid format, then the compiler
+ will adjust it into:
+ (set (reg r0) (symbol_ref (".LC0")))
+ (set (reg r0) (mem (reg r0))).
+ No extra register is required, and (mem (reg r0)) won't cause the use
+ of literal pools. */
+ if (arm_disable_literal_pool && GET_CODE (x) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (x))
+ return 1;
+ return 0;
+}
+
+
/* Return nonzero if X is a valid Thumb-2 address operand. */
static int
thumb2_legitimate_address_p (machine_mode mode, rtx x, int strict_p)
@@ -7593,23 +7647,7 @@ thumb2_legitimate_address_p (machine_mode mode, rtx x, int strict_p)
&& thumb2_legitimate_index_p (mode, xop0, strict_p)));
}
- /* Normally we can assign constant values to target registers without
- the help of constant pool. But there are cases we have to use constant
- pool like:
- 1) assign a label to register.
- 2) sign-extend a 8bit value to 32bit and then assign to register.
-
- Constant pool access in format:
- (set (reg r0) (mem (symbol_ref (".LC0"))))
- will cause the use of literal pool (later in function arm_reorg).
- So here we mark such format as an invalid format, then the compiler
- will adjust it into:
- (set (reg r0) (symbol_ref (".LC0")))
- (set (reg r0) (mem (reg r0))).
- No extra register is required, and (mem (reg r0)) won't cause the use
- of literal pools. */
- else if (arm_disable_literal_pool && code == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (x))
+ else if (can_avoid_literal_pool_for_label_p (x))
return 0;
else if (GET_MODE_CLASS (mode) != MODE_FLOAT
@@ -7888,6 +7926,9 @@ thumb1_index_register_rtx_p (rtx x, int strict_p)
int
thumb1_legitimate_address_p (machine_mode mode, rtx x, int strict_p)
{
+ if (TARGET_HAVE_MOVT && can_avoid_literal_pool_for_label_p (x))
+ return 0;
+
/* ??? Not clear if this is right. Experiment. */
if (GET_MODE_SIZE (mode) < 4
&& !(reload_in_progress || reload_completed)
@@ -8499,6 +8540,7 @@ thumb_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
return (CONST_INT_P (x)
|| CONST_DOUBLE_P (x)
|| CONSTANT_ADDRESS_P (x)
+ || (TARGET_HAVE_MOVT && GET_CODE (x) == SYMBOL_REF)
|| flag_pic);
}
@@ -27081,17 +27123,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
@@ -30510,4 +30559,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"
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index dea77200560..cfab76f29d2 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -2309,4 +2309,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 */
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index b097f48d7f6..187ac367e17 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -5961,7 +5961,7 @@
{
rtx base, offset, tmp;
- if (TARGET_32BIT)
+ if (TARGET_HAVE_MOVT)
{
/* Everything except mem = const or mem = mem can be done easily. */
if (MEM_P (operands[0]))
@@ -5985,7 +5985,7 @@
}
}
}
- else /* TARGET_THUMB1... */
+ else /* Target doesn't have MOVT... */
{
if (can_create_pseudo_p ())
{
@@ -6085,7 +6085,7 @@
(define_split
[(set (match_operand:SI 0 "arm_general_register_operand" "")
(match_operand:SI 1 "const_int_operand" ""))]
- "TARGET_32BIT
+ "TARGET_HAVE_MOVT
&& (!(const_ok_for_arm (INTVAL (operands[1]))
|| const_ok_for_arm (~INTVAL (operands[1]))))"
[(clobber (const_int 0))]
@@ -8660,7 +8660,7 @@
(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;
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index 1ce247c3082..4c5ea9bbba9 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -273,3 +273,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.
diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h
index fd8fc1cb0e6..03931eee739 100644
--- a/gcc/config/arm/elf.h
+++ b/gcc/config/arm/elf.h
@@ -95,7 +95,8 @@
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"
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ace8f63544e..bb929e954c9 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -634,6 +634,7 @@ Objective-C and Objective-C++ Dialects}.
-mslow-flash-data @gol
-masm-syntax-unified @gol
-mrestrict-it @gol
+-mpure-code @gol
-mcmse}
@emph{AVR Options}
@@ -14374,6 +14375,14 @@ 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 M-profile targets with the
+MOVT instruction.
+
@item -mcmse
@opindex mcmse
Generate secure code as per the "ARMv8-M Security Extensions: Requirements on
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 745910f9a33..7bdde758c4f 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -7510,6 +7510,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 is printed out instead of the
+normal sequence of letter codes. If the hook is not defined, or if it
+returns false, then @var{num} is ignored and the traditional letter sequence
+is 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
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index f31c763991c..db0d75fbe89 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -5209,6 +5209,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
diff --git a/gcc/hooks.c b/gcc/hooks.c
index 99ec4014adb..0d18ef699dc 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -481,3 +481,12 @@ 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_bool_uint_uintp_false (unsigned int, unsigned int *)
+{
+ return false;
+}
diff --git a/gcc/hooks.h b/gcc/hooks.h
index 2dc59baeadd..0cdfc81ca42 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -76,6 +76,7 @@ extern void hook_void_tree (tree);
extern void hook_void_tree_treeptr (tree, tree *);
extern void hook_void_int_int (int, int);
extern void hook_void_gcc_optionsp (struct gcc_options *);
+extern bool hook_bool_uint_uintp_false (unsigned int, unsigned int *);
extern int hook_int_uint_mode_1 (unsigned int, machine_mode);
extern int hook_int_const_tree_0 (const_tree);
diff --git a/gcc/target.def b/gcc/target.def
index 20f2b32da1e..dbe6a2cb730 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -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 is printed out instead of the\n\
+normal sequence of letter codes. If the hook is not defined, or if it\n\
+returns false, then @var{num} is ignored and the traditional letter sequence\n\
+is emitted.",
+ bool, (unsigned int flags, unsigned int *num),
+ hook_bool_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
diff --git a/gcc/testsuite/gcc.target/arm/pure-code/ffunction-sections.c b/gcc/testsuite/gcc.target/arm/pure-code/ffunction-sections.c
new file mode 100644
index 00000000000..26fe38c0529
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pure-code/ffunction-sections.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fpic" "-fPIC" } { "" } } */
+/* { dg-options "-ffunction-sections -mpure-code" } */
+#include <limits.h>
+
+char * foo (void)
+{
+ return "foo";
+}
+
+unsigned int bar (unsigned int b)
+{
+ return UINT_MAX - b;
+}
+
+/* { dg-final { scan-assembler {\.section\t\.text\.foo[^\n]*\"0x20000006\"} } } */
+/* { dg-final { scan-assembler {\.section\t\.text\.bar[^\n]*\"0x20000006\"} } } */
diff --git a/gcc/testsuite/gcc.target/arm/pure-code/no-casesi.c b/gcc/testsuite/gcc.target/arm/pure-code/no-casesi.c
new file mode 100644
index 00000000000..ba116a8261b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pure-code/no-casesi.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-mpure-code" } */
+/* { dg-skip-if "" { *-*-* } { "-g" "-fpic" "-fPIC" } { "" } } */
+
+extern int foo (void);
+extern int bar (void);
+extern int baz (void);
+extern int fooz (void);
+
+int caller (unsigned int reg_type)
+{
+ switch (reg_type)
+ {
+ case 0x80000000:
+ return (int) foo ();
+
+ case 0x80000003:
+ return (int) bar ();
+
+ case 0x80000001:
+ return (int) baz ();
+
+ case 0x80000004:
+ return (int) fooz ();
+ }
+}
+
+/* { dg-final { scan-assembler-not "\\.(float|l\\?double|\d?byte|short|int|long|quad|word)\\s+\[^.\]" } } */
+/* { dg-final { scan-assembler "text,\"0x20000006\"" } } */
diff --git a/gcc/testsuite/gcc.target/arm/pure-code/no-literal-pool.c b/gcc/testsuite/gcc.target/arm/pure-code/no-literal-pool.c
new file mode 100644
index 00000000000..4b893fd32f7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pure-code/no-literal-pool.c
@@ -0,0 +1,68 @@
+/* { dg-do compile } */
+/* { dg-options "-mpure-code" } */
+/* { dg-skip-if "" { *-*-* } { "-g" "-fpic" "-fPIC" } { "" } } */
+
+float sf;
+double df;
+long long l;
+static char *p = "Hello World";
+
+float
+testsf (float *p)
+{
+ if (*p > 1.1234f)
+ return 2.1234f;
+ else
+ return 3.1234f;
+}
+
+double
+testdf (double *p)
+{
+ if (*p > 4.1234)
+ return 2.1234;
+ else
+ return 3.1234;
+}
+
+long long
+testll (long long *p)
+{
+ if (*p > 0x123456789ABCDEFll)
+ return 0x111111111ll;
+ else
+ return 0x222222222ll;
+}
+
+char *
+testchar ()
+{
+ return p + 4;
+}
+
+int
+foo (int a, int b)
+{
+ int i;
+ volatile int *labelref = &&label1;
+
+ if (a > b)
+ {
+ while (i < b)
+ {
+ a += *labelref;
+ i += 1;
+ }
+ goto *labelref;
+ }
+ else
+ b = b + 3;
+
+ a = a * b;
+
+label1:
+ return a + b;
+}
+
+/* { dg-final { scan-assembler-not "\\.(float|l\\?double|\d?byte|short|int|long|quad|word)\\s+\[^.\]" } } */
+/* { dg-final { scan-assembler "text,\"0x20000006\"" } } */
diff --git a/gcc/testsuite/gcc.target/arm/pure-code/pure-code.exp b/gcc/testsuite/gcc.target/arm/pure-code/pure-code.exp
new file mode 100644
index 00000000000..f3818039169
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pure-code/pure-code.exp
@@ -0,0 +1,59 @@
+# Copyright (C) 1997-2016 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/>.
+
+# GCC testsuite for ARM's -mpure-code option, using the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+ set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# The -mpure-code option is only available for M-profile targets that support
+# the MOVT instruction.
+if {([check_effective_target_arm_thumb2_ok]
+ || [check_effective_target_arm_thumb1_movt_ok])
+ && [check_effective_target_arm_cortex_m]} then {
+# Initialize `dg'.
+dg-init
+
+set saved-dg-do-what-default ${dg-do-what-default}
+set dg-do-what-default "assemble"
+
+set saved-lto_torture_options ${LTO_TORTURE_OPTIONS}
+
+# Add -ffat-lto-objects option to all LTO options such that we can do assembly
+# scans.
+proc add_fat_objects { list } {
+ set res {}
+ foreach el $list {set res [lappend res [concat $el " -ffat-lto-objects"]]}
+ return $res
+};
+set LTO_TORTURE_OPTIONS [add_fat_objects ${LTO_TORTURE_OPTIONS}]
+
+gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
+ "" $DEFAULT_CFLAGS
+
+# Restore global values
+set dg-do-what-default ${saved-dg-do-what-default}
+set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
+
+# All done.
+dg-finish
+}
diff --git a/gcc/varasm.c b/gcc/varasm.c
index d766aea9cb1..ffce7116db6 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -6243,6 +6243,7 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
tree decl)
{
char flagchars[10], *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
@@ -6255,27 +6256,34 @@ 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';
- *f = '\0';
+ 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';
+ *f = '\0';
+ }
fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);