@@ -59,6 +59,7 @@ extern bool arm_modes_tieable_p (machine_mode, machine_mode);
extern int const_ok_for_arm (HOST_WIDE_INT);
extern int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
extern int const_ok_for_dimode_op (HOST_WIDE_INT, enum rtx_code);
+extern void thumb1_gen_const_int (rtx, HOST_WIDE_INT);
extern int arm_split_constant (RTX_CODE, machine_mode, rtx,
HOST_WIDE_INT, rtx, rtx, int);
extern int legitimate_pic_operand_p (rtx);
@@ -300,6 +300,12 @@ static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
static unsigned HOST_WIDE_INT arm_asan_shadow_offset (void);
static void arm_sched_fusion_priority (rtx_insn *, int, int *, int*);
+
+static section *arm_function_section (tree decl, enum node_frequency freq,
+ bool startup, bool exit);
+
+static unsigned int arm_section_type_flags (tree, const char *, int);
+
/* Table of machine attributes. */
static const struct attribute_spec arm_attribute_table[] =
@@ -735,6 +741,12 @@ 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_SECTION_TYPE_FLAGS
+#define TARGET_SECTION_TYPE_FLAGS arm_section_type_flags
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Obstack for minipool constant handling. */
@@ -3428,6 +3440,15 @@ arm_option_override (void)
if (target_slow_flash_data)
arm_disable_literal_pool = true;
+ /* We only support -mexecute-only on M-profile targets. */
+ if (target_execute_only && (flag_pic || !(!arm_arch_notm || arm_arch7em)))
+ error ("-mexecute-only only supports non-pic code on M-profile targets");
+
+ /* In execute-only mode we don't want any memory read into text section and
+ so we disable literal pool. */
+ if (target_execute_only)
+ arm_disable_literal_pool = true;
+
/* Disable scheduling fusion by default if it's not armv7 processor
or doesn't prefer ldrd/strd. */
if (flag_schedule_fusion == 2
@@ -3969,6 +3990,36 @@ const_ok_for_dimode_op (HOST_WIDE_INT i, enum rtx_code code)
}
}
+/* Emit a sequence of movs/adds/shift to produce a 32-bit constant.
+ Avoid generating useless code when byte is zero. */
+void
+thumb1_gen_const_int (rtx op0, HOST_WIDE_INT op1)
+{
+ int is_mov_done = 0;
+ int i;
+
+ /* Emit upper 3 bytes if needed. */
+ for (i = 0; i < 3; i++)
+ {
+ int byte = (op1 >> (8 * (3 - i))) & 0xff;
+
+ if (byte)
+ {
+ emit_set_insn (op0, is_mov_done?
+ gen_rtx_PLUS (SImode,op0, GEN_INT (byte)):
+ GEN_INT (byte));
+ is_mov_done = 1;
+ }
+ if (is_mov_done)
+ emit_set_insn (op0, gen_rtx_ASHIFT (SImode, op0, GEN_INT (8)));
+ }
+ /* Emit lower byte if needed. */
+ if (!is_mov_done)
+ emit_set_insn (op0, GEN_INT (op1&0xff));
+ else if (op1&0xff)
+ emit_set_insn (op0, gen_rtx_PLUS (SImode, op0, GEN_INT (op1&0xff)));
+}
+
/* Emit a sequence of insns to handle a large constant.
CODE is the code of the operation required, it can be any of SET, PLUS,
IOR, AND, XOR, MINUS;
@@ -7621,7 +7672,8 @@ thumb1_legitimate_address_p (machine_mode mode, rtx x, int strict_p)
/* This is PC relative data before arm_reorg runs. */
else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
&& GET_CODE (x) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic)
+ && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic
+ && !arm_disable_literal_pool)
return 1;
/* This is PC relative data after arm_reorg runs. */
@@ -7689,6 +7741,7 @@ thumb1_legitimate_address_p (machine_mode mode, rtx x, int strict_p)
&& GET_MODE_SIZE (mode) == 4
&& GET_CODE (x) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (x)
+ && !arm_disable_literal_pool
&& ! (flag_pic
&& symbol_mentioned_p (get_pool_constant (x))
&& ! pcrel_constant_p (get_pool_constant (x))))
@@ -8296,7 +8349,8 @@ thumb1_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
return 0;
if (thumb_shiftable_const (INTVAL (x)))
return COSTS_N_INSNS (2);
- return COSTS_N_INSNS (3);
+ return arm_disable_literal_pool ? COSTS_N_INSNS (8) :\
+ COSTS_N_INSNS (3);
}
else if ((outer == PLUS || outer == COMPARE)
&& INTVAL (x) < 256 && INTVAL (x) > -256)
@@ -9058,7 +9112,8 @@ thumb1_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
/* See split "TARGET_THUMB1 && satisfies_constraint_K". */
if (thumb_shiftable_const (INTVAL (x)))
return COSTS_N_INSNS (2);
- return COSTS_N_INSNS (3);
+ return arm_disable_literal_pool ? COSTS_N_INSNS (8) :\
+ COSTS_N_INSNS (3);
}
else if ((outer == PLUS || outer == COMPARE)
&& INTVAL (x) < 256 && INTVAL (x) > -256)
@@ -26097,14 +26152,36 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
/* push r3 so we can use it as a temporary. */
/* TODO: Omit this save if r3 is not used. */
fputs ("\tpush {r3}\n", file);
- fputs ("\tldr\tr3, ", file);
+ if (target_execute_only)
+ {
+ fputs ("\tmovs\tr3, #:upper8_15:#", file);
+ assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+ fputc ('\n', file);
+ fputs ("\tlsls r3, #8\n", file);
+ fputs ("\tadds\tr3, #:upper0_7:#", file);
+ assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+ fputc ('\n', file);
+ fputs ("\tlsls r3, #8\n", file);
+ fputs ("\tadds\tr3, #:lower8_15:#", file);
+ assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+ fputc ('\n', file);
+ fputs ("\tlsls r3, #8\n", file);
+ fputs ("\tadds\tr3, #:lower0_7:#", file);
+ assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+ fputc ('\n', file);
+ }
+ else
+ fputs ("\tldr\tr3, ", file);
}
else
{
fputs ("\tldr\tr12, ", file);
}
- assemble_name (file, label);
- fputc ('\n', file);
+ if (!target_execute_only)
+ {
+ assemble_name (file, label);
+ fputc ('\n', file);
+ }
if (flag_pic)
{
/* If we are generating PIC, the ldr instruction below loads
@@ -30188,4 +30265,29 @@ arm_sched_fusion_priority (rtx_insn *insn, int max_pri,
return;
}
+/* Implement the TARGET_ASM_FUNCTION_SECTION hook.
+
+ Be sure that code compiled with mexecute-only is not moved in a section
+ name '.text' so SECTION_NOREAD attribute is not removed by assembler. */
+static section *
+arm_function_section (tree decl,
+ enum node_frequency freq,
+ bool startup,
+ bool exit)
+{
+ return target_execute_only ?
+ get_named_text_section (decl, ".text.noread", NULL):
+ default_function_section (decl, freq, startup, exit);
+}
+
+/* Implement the TARGET_SECTION_TYPE_FLAGS hook. */
+
+static unsigned int
+arm_section_type_flags (tree decl, const char *name, int reloc)
+{
+ unsigned int flags = default_section_type_flags (decl, name, reloc);
+
+ return target_execute_only ? flags|SECTION_NOREAD : flags;
+}
+
#include "gt-arm.h"
@@ -8179,7 +8179,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_execute_only"
"
{
enum insn_code code;
@@ -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.
+
+mexecute-only
+Target Report Var(target_execute_only) Init(0)
+Forbid load into text sections.
@@ -41,7 +41,62 @@
;; differently). In particular there is no Thumb1 armv6-m pattern for
;; sbc or adc.
+(define_insn "thumb1_movsi_symbol_ref"
+ [(set (match_operand:SI 0 "register_operand" "=l")
+ (match_operand:SI 1 "general_operand" ""))
+ ]
+ "TARGET_THUMB1
+ && arm_disable_literal_pool
+ && GET_CODE (operands[1]) == SYMBOL_REF"
+ "*
+ output_asm_insn (\"movs\\t%0, #:upper8_15:%1\", operands);
+ output_asm_insn (\"lsls\\t%0, #8\", operands);
+ output_asm_insn (\"adds\\t%0, #:upper0_7:%1\", operands);
+ output_asm_insn (\"lsls\\t%0, #8\", operands);
+ output_asm_insn (\"adds\\t%0, #:lower8_15:%1\", operands);
+ output_asm_insn (\"lsls\\t%0, #8\", operands);
+ output_asm_insn (\"adds\\t%0, #:lower0_7:%1\", operands);
+ return \"\";
+ "
+ [(set_attr "length" "14")
+ (set_attr "conds" "clob")]
+)
+
+(define_insn "*thumb1_movsi_const_int"
+ [(set (match_operand:SI 0 "register_operand" "=l")
+ (match_operand:SI 1 "immediate_operand" "i"))
+ ]
+ "TARGET_THUMB1
+ && arm_disable_literal_pool
+ && GET_CODE (operands[1]) == CONST_INT
+ && !satisfies_constraint_I (operands[1])"
+ "*
+ output_asm_insn (\"movs\\t%0, #(%c1>>24)&0xff\", operands);
+ output_asm_insn (\"lsls\\t%0, #8\", operands);
+ output_asm_insn (\"adds\\t%0, #(%c1>>16)&0xff\", operands);
+ output_asm_insn (\"lsls\\t%0, #8\", operands);
+ output_asm_insn (\"adds\\t%0, #(%c1>>8)&0xff\", operands);
+ output_asm_insn (\"lsls\\t%0, #8\", operands);
+ output_asm_insn (\"adds\\t%0, #%c1&0xff\", operands);
+ return \"\";
+ "
+ [(set_attr "length" "14")
+ (set_attr "conds" "clob")]
+)
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "immediate_operand" ""))]
+ "TARGET_THUMB1
+ && arm_disable_literal_pool
+ && GET_CODE (operands[1]) == CONST_INT
+ && !satisfies_constraint_I (operands[1])"
+ [(clobber (const_int 0))]
+ "
+ thumb1_gen_const_int (operands[0], INTVAL (operands[1]));
+ DONE;
+ "
+)
(define_insn "*thumb1_adddi3"
[(set (match_operand:DI 0 "register_operand" "=l")
@@ -632,8 +687,8 @@
)
(define_insn "*thumb1_movsi_insn"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l, m,*l*h*k")
- (match_operand:SI 1 "general_operand" "l, I,J,K,>,l,mi,l,*l*h*k"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,l, m,*l*h*k")
+ (match_operand:SI 1 "general_operand" "l, I,J,K,>,l,m,mi,l,*l*h*k"))]
"TARGET_THUMB1
&& ( register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode))"
@@ -645,12 +700,14 @@
ldmia\\t%1, {%0}
stmia\\t%0, {%1}
ldr\\t%0, %1
+ ldr\\t%0, %1
str\\t%1, %0
mov\\t%0, %1"
- [(set_attr "length" "2,2,4,4,2,2,2,2,2")
- (set_attr "type" "mov_reg,mov_imm,multiple,multiple,load1,store1,load1,store1,mov_reg")
- (set_attr "pool_range" "*,*,*,*,*,*,1018,*,*")
- (set_attr "conds" "set,clob,*,*,nocond,nocond,nocond,nocond,nocond")])
+ [(set_attr "length" "2,2,4,4,2,2,2,2,2,2")
+ (set_attr "type" "mov_reg,mov_imm,multiple,multiple,load1,store1,load1,load1,store1,mov_reg")
+ (set_attr "pool_range" "*,*,*,*,*,*,1018,1018,*,*")
+ (set_attr "use_literal_pool" "no,no,no,no,no,no,no,yes,no,no")
+ (set_attr "conds" "set,clob,*,*,nocond,nocond,nocond,nocond,nocond,nocond")])
; Split the load of 64-bit constant into two loads for high and low 32-bit parts respectively
; to see if we can load them in fewer instructions or fewer cycles.
@@ -1760,7 +1817,7 @@
(define_expand "tablejump"
[(parallel [(set (pc) (match_operand:SI 0 "register_operand" ""))
(use (label_ref (match_operand 1 "" "")))])]
- "TARGET_THUMB1"
+ "TARGET_THUMB1 && !target_execute_only"
"
if (flag_pic)
{
@@ -630,6 +630,7 @@ Objective-C and Objective-C++ Dialects}.
-munaligned-access @gol
-mneon-for-64bits @gol
-mslow-flash-data @gol
+-mexecute-only @gol
-masm-syntax-unified @gol
-mrestrict-it}
@@ -14139,6 +14140,12 @@ Therefore literal load is minimized for better performance.
This option is only supported when compiling for ARMv7 M-profile and
off by default.
+@item -mexecute-only
+@opindex mexecute-only
+Disable read memory access inside code sections. Only code fetching is
+allowed.
+This option is off by default.
+
@item -masm-syntax-unified
@opindex masm-syntax-unified
Assume inline assembler is using unified asm syntax. The default is
new file mode 100644
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cortex_m } */
+/* { dg-require-effective-target arm_thumb1_ok } */
+/* { dg-options "-O2 -march=armv6s-m -mthumb -mexecute-only" } */
+
+int
+foo (int a)
+{
+ switch (a)
+ {
+ case 0: return 12;
+ case 1: return 2;
+ case 2: return 1231;
+ case 3: return 0xdead;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+/* { dg-final { scan-assembler-not "ldr\[\t \]+r\[0-9\]+, .L" } } */
+
new file mode 100644
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cortex_m } */
+/* { dg-require-effective-target arm_thumb1_ok } */
+/* { dg-options "-O2 -march=armv6s-m -mthumb -mexecute-only" } */
+
+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;
+ 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 "ldr\[\t \]+r\[0-9\]+, .L" } } */
+
new file mode 100644
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cortex_m } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+/* { dg-options "-O2 -march=armv7-m -mthumb -mexecute-only" } */
+
+int
+foo (int a)
+{
+ switch (a)
+ {
+ case 0: return 12;
+ case 1: return 2;
+ case 2: return 1231;
+ case 3: return 0xdead;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+/* { dg-final { scan-assembler-not "ldr\[\t \]+r\[0-9\]+, .L" } } */
+/* { dg-final { scan-assembler-not "ldrls\[\t \]+r\[0-9\]+, .L" } } */
new file mode 100644
@@ -0,0 +1,68 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cortex_m } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+/* { dg-options "-O2 -march=armv7-m -mthumb -mexecute-only" } */
+
+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;
+ 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 "ldr\[\t \]+r\[0-9\]+, .L" } } */