@@ -498,6 +498,9 @@ static int mips_base_target_flags;
/* The default compression mode. */
unsigned int mips_base_compression_flags;
+/* The default code readable setting. */
+enum mips_code_readable_setting mips_base_code_readable;
+
/* The ambient values of other global variables. */
static int mips_base_schedule_insns; /* flag_schedule_insns */
static int mips_base_reorder_blocks_and_partition; /* flag_reorder... */
@@ -602,6 +605,7 @@ const enum reg_class mips_regno_to_class[FIRST_PSEUDO_REGISTER] = {
ALL_REGS, ALL_REGS, ALL_REGS, ALL_REGS
};
+static tree mips_handle_code_readable_attr (tree *, tree, tree, int, bool *);
static tree mips_handle_interrupt_attr (tree *, tree, tree, int, bool *);
static tree mips_handle_use_shadow_register_set_attr (tree *, tree, tree, int,
bool *);
@@ -623,6 +627,8 @@ static const struct attribute_spec mips_attribute_table[] = {
{ "micromips", 0, 0, true, false, false, false, NULL, NULL },
{ "nomicromips", 0, 0, true, false, false, false, NULL, NULL },
{ "nocompression", 0, 0, true, false, false, false, NULL, NULL },
+ { "code_readable", 0, 1, true, false, false, false,
+ mips_handle_code_readable_attr, NULL },
/* Allow functions to be specified as interrupt handlers */
{ "interrupt", 0, 1, false, true, true, false, mips_handle_interrupt_attr,
NULL },
@@ -1310,6 +1316,81 @@ mips_use_debug_exception_return_p (tree type)
TYPE_ATTRIBUTES (type)) != NULL;
}
+
+/* Verify the arguments to a code_readable attribute. */
+
+static tree
+mips_handle_code_readable_attr (tree *node ATTRIBUTE_UNUSED, tree name,
+ tree args, int flags ATTRIBUTE_UNUSED,
+ bool *no_add_attrs)
+{
+ if (!is_attribute_p ("code_readable", name) || args == NULL)
+ return NULL_TREE;
+
+ if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute requires a string argument", name);
+ *no_add_attrs = true;
+ }
+ else if (strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "no") != 0
+ && strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "pcrel") != 0
+ && strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "yes") != 0)
+ {
+ warning (OPT_Wattributes,
+ "argument to %qE attribute is neither no, pcrel nor yes", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Determine the code_readable setting for a function if it has one. Set
+ *valid to true if we have a properly formed argument and
+ return the result. If there's no argument, return GCC's default.
+ Otherwise, leave valid false and return mips_base_code_readable. In
+ that case the result should be unused anyway. */
+
+static enum mips_code_readable_setting
+mips_get_code_readable_attr (tree decl)
+{
+ tree attr;
+
+ if (decl == NULL)
+ return mips_base_code_readable;
+
+ attr = lookup_attribute ("code_readable", DECL_ATTRIBUTES (decl));
+
+ if (attr != NULL)
+ {
+ if (TREE_VALUE (attr) != NULL_TREE)
+ {
+ const char * str;
+
+ str = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
+ if (strcmp (str, "no") == 0)
+ return CODE_READABLE_NO;
+ else if (strcmp (str, "pcrel") == 0)
+ return CODE_READABLE_PCREL;
+ else if (strcmp (str, "yes") == 0)
+ return CODE_READABLE_YES;
+
+ /* mips_handle_code_readable_attr will have verified the
+ arguments are correct before adding the attribute. */
+ gcc_unreachable ();
+ }
+
+ /* Just like GCC's default -mcode-readable= setting, the
+ presence of the code_readable attribute implies that a
+ function can read data from the instruction stream by
+ default. */
+ return CODE_READABLE_YES;
+ }
+
+ return mips_base_code_readable;
+}
+
+
/* Return the set of compression modes that are explicitly required
by the attributes in ATTRIBUTES. */
@@ -19905,12 +19986,25 @@ mips_set_compression_mode (unsigned int compression_mode)
/* Implement TARGET_SET_CURRENT_FUNCTION. Decide whether the current
function should use the MIPS16 or microMIPS ISA and switch modes
- accordingly. */
+ accordingly. Also set the current code_readable mode. */
static void
mips_set_current_function (tree fndecl)
{
+ enum mips_code_readable_setting old_code_readable = mips_code_readable;
+
mips_set_compression_mode (mips_get_compress_mode (fndecl));
+
+ mips_code_readable = mips_get_code_readable_attr (fndecl);
+
+ /* Since the mips_code_readable setting has potentially changed, the
+ relocation tables must be reinitialized. Otherwise GCC will not
+ split symbols for functions that are code_readable ("no") when others
+ are code_readable ("yes") and ICE later on in places such as
+ mips_emit_move. Ditto for similar paired cases. It must be restored
+ to its previous state as well. */
+ if (old_code_readable != mips_code_readable)
+ mips_init_relocs ();
}
/* Allocate a chunk of memory for per-function machine-dependent data. */
@@ -20042,6 +20136,7 @@ mips_option_override (void)
were generating uncompressed code. */
mips_base_compression_flags = TARGET_COMPRESSION;
target_flags &= ~TARGET_COMPRESSION;
+ mips_base_code_readable = mips_code_readable;
/* -mno-float overrides -mhard-float and -msoft-float. */
if (TARGET_NO_FLOAT)
@@ -5670,6 +5670,23 @@ command line (@pxref{MIPS Options}).
This function attribute instructs the compiler to generate a hazard barrier
return that clears all execution and instruction hazards while returning,
instead of generating a normal return instruction.
+
+@item code_readable
+@cindex @code{code_readable} function attribute, MIPS
+For MIPS targets that support PC-relative addressing modes, this attribute
+can be used to control how an object is addressed. The attribute takes
+a single optional argument:
+
+@table @samp
+@item no
+The function should not read the instruction stream as data.
+@item yes
+The function can read the instruction stream as data.
+@item pcrel
+The function can read the instruction stream in a pc-relative mode.
+@end table
+
+If there is no argument supplied, the default of @code{"yes"} applies.
@end table
@node MSP430 Function Attributes
new file mode 100644
@@ -0,0 +1,51 @@
+/* { dg-options "(-mips16) -mgp32 addressing=absolute" } */
+/* { dg-skip-if ".half requires -O" { *-*-* } { "-O0" } { "" } } */
+
+volatile int x1;
+volatile int x2;
+volatile int x3;
+volatile int x4;
+volatile int x5;
+volatile int x6;
+volatile int x7;
+volatile int x8;
+volatile int x9;
+volatile int x10;
+volatile int x11;
+
+MIPS16 __attribute__ ((code_readable)) int
+foo (int i, volatile int *x)
+{
+ switch (i)
+ {
+ case 1: return x1 + x[0];
+ case 2: return x2 + x[1];
+ case 3: return x3 + x[2];
+ case 4: return x4 + x[3];
+ case 5: return x5 + x[4];
+ case 6: return x6 + x[5];
+ case 7: return x7 + x[6];
+ case 8: return x8 + x[7];
+ case 9: return x9 + x[8];
+ case 10: return x10 + x[9];
+ case 11: return x11 + x[10];
+ default: return 0;
+ }
+}
+
+extern int k[];
+
+MIPS16 __attribute__ ((code_readable)) int *
+bar (void)
+{
+ return k;
+}
+
+/* { dg-final { scan-assembler "\tla\t" } } */
+/* { dg-final { scan-assembler "\t\\.half\t" } } */
+/* { dg-final { scan-assembler-not "%hi\\(\[^)\]*L" } } */
+/* { dg-final { scan-assembler-not "%lo\\(\[^)\]*L" } } */
+
+/* { dg-final { scan-assembler "\t\\.word\tk\n" } } */
+/* { dg-final { scan-assembler-not "%hi\\(k\\)" } } */
+/* { dg-final { scan-assembler-not "%lo\\(k\\)" } } */
new file mode 100644
@@ -0,0 +1,49 @@
+/* { dg-options "(-mips16) -mgp32 addressing=absolute" } */
+
+volatile int x1;
+volatile int x2;
+volatile int x3;
+volatile int x4;
+volatile int x5;
+volatile int x6;
+volatile int x7;
+volatile int x8;
+volatile int x9;
+volatile int x10;
+volatile int x11;
+
+MIPS16 __attribute__((code_readable ("pcrel"))) int
+foo (int i, volatile int *x)
+{
+ switch (i)
+ {
+ case 1: return x1 + x[0];
+ case 2: return x2 + x[1];
+ case 3: return x3 + x[2];
+ case 4: return x4 + x[3];
+ case 5: return x5 + x[4];
+ case 6: return x6 + x[5];
+ case 7: return x7 + x[6];
+ case 8: return x8 + x[7];
+ case 9: return x9 + x[8];
+ case 10: return x10 + x[9];
+ case 11: return x11 + x[10];
+ default: return 0;
+ }
+}
+
+extern int k[];
+
+MIPS16 __attribute__((code_readable ("pcrel"))) int *
+bar (void)
+{
+ return k;
+}
+
+/* { dg-final { scan-assembler-not "\tla\t" } } */
+/* { dg-final { scan-assembler-not "\t\\.half\t" } } */
+/* { dg-final { scan-assembler "\t\\.word\t\[^\n\]*L" } } */
+
+/* { dg-final { scan-assembler "\t\\.word\tk\n" } } */
+/* { dg-final { scan-assembler-not "%hi\\(k\\)" } } */
+/* { dg-final { scan-assembler-not "%lo\\(k\\)" } } */
new file mode 100644
@@ -0,0 +1,50 @@
+/* { dg-options "(-mips16) -mgp32 addressing=absolute" } */
+
+volatile int x1;
+volatile int x2;
+volatile int x3;
+volatile int x4;
+volatile int x5;
+volatile int x6;
+volatile int x7;
+volatile int x8;
+volatile int x9;
+volatile int x10;
+volatile int x11;
+
+MIPS16 __attribute__((code_readable ("no"))) int
+foo (int i, volatile int *x)
+{
+ switch (i)
+ {
+ case 1: return x1 + x[0];
+ case 2: return x2 + x[1];
+ case 3: return x3 + x[2];
+ case 4: return x4 + x[3];
+ case 5: return x5 + x[4];
+ case 6: return x6 + x[5];
+ case 7: return x7 + x[6];
+ case 8: return x8 + x[7];
+ case 9: return x9 + x[8];
+ case 10: return x10 + x[9];
+ case 11: return x11 + x[10];
+ default: return 0;
+ }
+}
+
+extern int k[];
+
+MIPS16 __attribute__((code_readable ("no"))) int *
+bar (void)
+{
+ return k;
+}
+
+/* { dg-final { scan-assembler-not "\tla\t" } } */
+/* { dg-final { scan-assembler-not "\t\\.half\t" } } */
+/* { dg-final { scan-assembler "%hi\\(\[^)\]*L" } } */
+/* { dg-final { scan-assembler "%lo\\(\[^)\]*L" } } */
+
+/* { dg-final { scan-assembler-not "\t\\.word\tk\n" } } */
+/* { dg-final { scan-assembler "%hi\\(k\\)" } } */
+/* { dg-final { scan-assembler "%lo\\(k\\)" } } */
new file mode 100644
@@ -0,0 +1,51 @@
+/* { dg-options "(-mips16) -mabi=eabi -mgp64" } */
+/* { dg-skip-if ".half requires -O" { *-*-* } { "-O0" } { "" } } */
+
+volatile int x1;
+volatile int x2;
+volatile int x3;
+volatile int x4;
+volatile int x5;
+volatile int x6;
+volatile int x7;
+volatile int x8;
+volatile int x9;
+volatile int x10;
+volatile int x11;
+
+MIPS16 __attribute__((code_readable ("yes"))) int
+foo (int i, volatile int *x)
+{
+ switch (i)
+ {
+ case 1: return x1 + x[0];
+ case 2: return x2 + x[1];
+ case 3: return x3 + x[2];
+ case 4: return x4 + x[3];
+ case 5: return x5 + x[4];
+ case 6: return x6 + x[5];
+ case 7: return x7 + x[6];
+ case 8: return x8 + x[7];
+ case 9: return x9 + x[8];
+ case 10: return x10 + x[9];
+ case 11: return x11 + x[10];
+ default: return 0;
+ }
+}
+
+extern int k[];
+
+MIPS16 __attribute__((code_readable ("yes"))) int *
+bar (void)
+{
+ return k;
+}
+
+/* { dg-final { scan-assembler "\tdla\t" } } */
+/* { dg-final { scan-assembler "\t\\.half\t" } } */
+/* { dg-final { scan-assembler-not "%hi\\(\[^)\]*L" } } */
+/* { dg-final { scan-assembler-not "%lo\\(\[^)\]*L" } } */
+
+/* { dg-final { scan-assembler "\t\\.dword\tk\n" } } */
+/* { dg-final { scan-assembler-not "%hi\\(k\\)" } } */
+/* { dg-final { scan-assembler-not "%lo\\(k\\)" } } */
new file mode 100644
@@ -0,0 +1,5 @@
+/* { dg-options "(-mips16) isa_rev<=5" } */
+
+ __attribute__((code_readable ("magic"))) int foo () {} /* { dg-warning "argument to 'code_readable' attribute is neither no, pcrel nor yes" } */
+
+ __attribute__((code_readable (1))) int * bar () {} /* { dg-warning "'code_readable' attribute requires a string argument" } */