From: Trevor Saunders <tbsaunde+...@tbsaunde.org> Hi,
$subject. To avoid regressions I kept the checks when generating rtl, but I believe its impossible for those to trigger now and we can remove the checks. bootstrapped + regtested on x86_64-linux-gnu, ok? Trev gcc/c/ChangeLog: 2016-01-25 Trevor Saunders <tbsaunde+...@tbsaunde.org> * c-decl.c (finish_decl): Check if asm register is valid. gcc/ChangeLog: 2016-01-25 Trevor Saunders <tbsaunde+...@tbsaunde.org> * varasm.c (register_asmspec_ok_p): New function. (make_decl_rtl): Adjust. * varasm.h (register_asmspec_ok_p): New prototype. gcc/cp/ChangeLog: 2016-01-25 Trevor Saunders <tbsaunde+...@tbsaunde.org> * decl.c (make_rtl_for_nonlocal_decl): Check if register asm is valid. --- gcc/c/c-decl.c | 8 +- gcc/cp/decl.c | 4 +- gcc/testsuite/g++.dg/torture/register-asm-1.C | 14 +++ gcc/testsuite/gcc.dg/reg-vol-struct-1.c | 2 +- gcc/testsuite/gcc.dg/torture/register-asm-1.c | 12 +++ gcc/varasm.c | 150 +++++++++++++++----------- gcc/varasm.h | 3 + 7 files changed, 129 insertions(+), 64 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/register-asm-1.C create mode 100644 gcc/testsuite/gcc.dg/torture/register-asm-1.c diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 1ec6042..9257f35 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -4867,7 +4867,9 @@ finish_decl (tree decl, location_t init_loc, tree init, when a tentative file-scope definition is seen. But at end of compilation, do output code for them. */ DECL_DEFER_OUTPUT (decl) = 1; - if (asmspec && C_DECL_REGISTER (decl)) + if (asmspec + && C_DECL_REGISTER (decl) + && register_asmspec_ok_p (decl, asmspec, DECL_MODE (decl))) DECL_HARD_REGISTER (decl) = 1; rest_of_decl_compilation (decl, true, 0); } @@ -4878,7 +4880,9 @@ finish_decl (tree decl, location_t init_loc, tree init, in a particular register. */ if (asmspec && C_DECL_REGISTER (decl)) { - DECL_HARD_REGISTER (decl) = 1; + if (register_asmspec_ok_p (decl, asmspec, DECL_MODE (decl))) + DECL_HARD_REGISTER (decl) = 1; + /* This cannot be done for a structure with volatile fields, on which DECL_REGISTER will have been reset. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f4604b6..6d130bd 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6201,7 +6201,9 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec) /* The `register' keyword, when used together with an asm-specification, indicates that the variable should be placed in a particular register. */ - if (VAR_P (decl) && DECL_REGISTER (decl)) + if (VAR_P (decl) + && DECL_REGISTER (decl) + && register_asmspec_ok_p (decl, asmspec, DECL_MODE (decl))) { set_user_assembler_name (decl, asmspec); DECL_HARD_REGISTER (decl) = 1; diff --git a/gcc/testsuite/g++.dg/torture/register-asm-1.C b/gcc/testsuite/g++.dg/torture/register-asm-1.C new file mode 100644 index 0000000..b5cfc84 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/register-asm-1.C @@ -0,0 +1,14 @@ +/* { dg-do compile } */ + +class A { + int m_fn1() const; +}; +int a[1]; +int b; +int A::m_fn1() const { + register int c asm(""); // { dg-error "invalid register name for 'c'" } + while (b) + if (a[5]) + c = b; + return c; +} diff --git a/gcc/testsuite/gcc.dg/reg-vol-struct-1.c b/gcc/testsuite/gcc.dg/reg-vol-struct-1.c index b885f91..e67c7a2 100644 --- a/gcc/testsuite/gcc.dg/reg-vol-struct-1.c +++ b/gcc/testsuite/gcc.dg/reg-vol-struct-1.c @@ -12,7 +12,7 @@ f (void) { register struct S a; register struct S b[2]; - register struct S c __asm__("nosuchreg"); /* { dg-error "object with volatile field" "explicit reg name" } */ + register struct S c __asm__("nosuchreg"); /* { dg-error "invalid register name for 'c'|cannot put object with volatile field into register" } */ &a; /* { dg-error "address of register" "explicit address" } */ b; /* { dg-error "address of register" "implicit address" } */ } diff --git a/gcc/testsuite/gcc.dg/torture/register-asm-1.c b/gcc/testsuite/gcc.dg/torture/register-asm-1.c new file mode 100644 index 0000000..1949f62 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/register-asm-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + + int a[1], b; +int +foo () +{ + register int c asm (""); /* { dg-error "invalid register name for 'c'" } */ + while (b) + if (a[5]) + c = b; + return c; +} diff --git a/gcc/varasm.c b/gcc/varasm.c index 3a3573e..7e3aebc9 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -1270,6 +1270,55 @@ ultimate_transparent_alias_target (tree *alias) return target; } +/* Check that a register asm spec is correct, and compatibility with + machine_mode mode. If reg_number is nonnull and the spec is valid then set + it to the register number designated by the spec. */ + +bool +register_asmspec_ok_p (tree decl, const char *asmspec, machine_mode mode, + int *reg_number) +{ + int reg = decode_reg_name (asmspec); + if (reg == -1) + { + error ("register name not specified for %q+D", decl); + return false; + } + else if (reg < 0) + { + error ("invalid register name for %q+D", decl); + return false; + } + else if (mode == BLKmode) + { + error ("data type of %q+D isn%'t suitable for a register", decl); + return false; + } + else if (!in_hard_reg_set_p (accessible_reg_set, mode, reg)) + { + error ("the register specified for %q+D cannot be accessed" + " by the current target", decl); + return false; + } + else if (!in_hard_reg_set_p (operand_reg_set, mode, reg)) + { + error ("the register specified for %q+D is not general enough" + " to be used as a register variable", decl); + return false; + } + else if (!HARD_REGNO_MODE_OK (reg, mode)) + { + error ("register specified for %q+D isn%'t suitable for data type", + decl); + return false; + } + + if (reg_number) + *reg_number = reg; + + return true; +} + /* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL. DECL should have static storage duration. In other words, it should not be an automatic variable, including PARM_DECLs. @@ -1283,7 +1332,6 @@ void make_decl_rtl (tree decl) { const char *name = 0; - int reg_number; tree id; rtx x; @@ -1358,73 +1406,55 @@ make_decl_rtl (tree decl) { const char *asmspec = name+1; machine_mode mode = DECL_MODE (decl); - reg_number = decode_reg_name (asmspec); - /* First detect errors in declaring global registers. */ - if (reg_number == -1) - error ("register name not specified for %q+D", decl); - else if (reg_number < 0) - error ("invalid register name for %q+D", decl); - else if (mode == BLKmode) - error ("data type of %q+D isn%'t suitable for a register", - decl); - else if (!in_hard_reg_set_p (accessible_reg_set, mode, reg_number)) - error ("the register specified for %q+D cannot be accessed" - " by the current target", decl); - else if (!in_hard_reg_set_p (operand_reg_set, mode, reg_number)) - error ("the register specified for %q+D is not general enough" - " to be used as a register variable", decl); - else if (!HARD_REGNO_MODE_OK (reg_number, mode)) - error ("register specified for %q+D isn%'t suitable for data type", - decl); - /* Now handle properly declared static register variables. */ - else + int reg_number; + if (!register_asmspec_ok_p (decl, asmspec, mode, ®_number)) { - int nregs; + /* Avoid internal errors from invalid register + specifications. */ + SET_DECL_ASSEMBLER_NAME (decl, NULL_TREE); + DECL_HARD_REGISTER (decl) = 0; + /* Also avoid SSA inconsistencies by pretending this is an external + decl now. */ + DECL_EXTERNAL (decl) = 1; + return; + } - if (DECL_INITIAL (decl) != 0 && TREE_STATIC (decl)) - { - DECL_INITIAL (decl) = 0; - error ("global register variable has initial value"); - } - if (TREE_THIS_VOLATILE (decl)) - warning (OPT_Wvolatile_register_var, - "optimization may eliminate reads and/or " - "writes to register variables"); - /* If the user specified one of the eliminables registers here, - e.g., FRAME_POINTER_REGNUM, we don't want to get this variable - confused with that register and be eliminated. This usage is - somewhat suspect... */ + if (DECL_INITIAL (decl) != 0 && TREE_STATIC (decl)) + { + DECL_INITIAL (decl) = 0; + error ("global register variable has initial value"); + } + if (TREE_THIS_VOLATILE (decl)) + warning (OPT_Wvolatile_register_var, + "optimization may eliminate reads and/or " + "writes to register variables"); - SET_DECL_RTL (decl, gen_raw_REG (mode, reg_number)); - ORIGINAL_REGNO (DECL_RTL (decl)) = reg_number; - REG_USERVAR_P (DECL_RTL (decl)) = 1; + /* If the user specified one of the eliminables registers here, + e.g., FRAME_POINTER_REGNUM, we don't want to get this variable + confused with that register and be eliminated. This usage is + somewhat suspect... */ - if (TREE_STATIC (decl)) - { - /* Make this register global, so not usable for anything - else. */ + SET_DECL_RTL (decl, gen_raw_REG (mode, reg_number)); + ORIGINAL_REGNO (DECL_RTL (decl)) = reg_number; + REG_USERVAR_P (DECL_RTL (decl)) = 1; + + if (TREE_STATIC (decl)) + { + /* Make this register global, so not usable for anything + else. */ #ifdef ASM_DECLARE_REGISTER_GLOBAL - name = IDENTIFIER_POINTER (DECL_NAME (decl)); - ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name); + name = IDENTIFIER_POINTER (DECL_NAME (decl)); + ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name); #endif - nregs = hard_regno_nregs[reg_number][mode]; - while (nregs > 0) - globalize_reg (decl, reg_number + --nregs); - } - - /* As a register variable, it has no section. */ - return; + int nregs = hard_regno_nregs[reg_number][mode]; + while (nregs > 0) + globalize_reg (decl, reg_number + --nregs); } - /* Avoid internal errors from invalid register - specifications. */ - SET_DECL_ASSEMBLER_NAME (decl, NULL_TREE); - DECL_HARD_REGISTER (decl) = 0; - /* Also avoid SSA inconsistencies by pretending this is an external - decl now. */ - DECL_EXTERNAL (decl) = 1; + + /* As a register variable, it has no section. */ return; - } + } /* Now handle ordinary static variables and functions (in memory). Also handle vars declared register invalidly. */ else if (name[0] == '*') @@ -1432,7 +1462,7 @@ make_decl_rtl (tree decl) #ifdef REGISTER_PREFIX if (strlen (REGISTER_PREFIX) != 0) { - reg_number = decode_reg_name (name); + int reg_number = decode_reg_name (name); if (reg_number >= 0 || reg_number == -3) error ("register name given for non-register variable %q+D", decl); } diff --git a/gcc/varasm.h b/gcc/varasm.h index 51a5492..042ce1a 100644 --- a/gcc/varasm.h +++ b/gcc/varasm.h @@ -79,4 +79,7 @@ extern rtx assemble_static_space (unsigned HOST_WIDE_INT); extern rtx assemble_trampoline_template (void); +extern bool register_asmspec_ok_p (tree decl, const char *spec, + machine_mode mode, int *regnum = NULL); + #endif // GCC_VARASM_H -- 2.7.0