varasm: Reject soft frame or arg pointer registers for register vars [PR92469]

The following patch rejects frame, argp and retarg registers (unless they are equal
to hard frame pointer registers or if they aren't eliminable) from local or global
register vars.
These are just internal implementation details eliminated later into hard
frame pointer or stack pointer and using them as register variable leads
to numerous ICEs.

2020-12-13  Jakub Jelinek  <jakub@redhat.com>

	PR target/92469
	* varasm.c (eliminable_regno_p): New function.
	(make_decl_rtl): Reject asm vars for frame and argp
	if they are different from hard frame pointer.

	* gcc.target/i386/pr92469.c: New test.
	* gcc.target/i386/pr79804.c: Adjust expected diagnostics.
	* gcc.target/i386/pr88178.c: Expect an error.
This commit is contained in:
Jakub Jelinek 2020-12-13 17:08:08 +01:00
parent 3b8a82f97d
commit d88e2cb549
4 changed files with 54 additions and 4 deletions

View File

@ -4,7 +4,7 @@
void foo (void)
{
register int r19 asm ("19");
register int r19 asm ("19"); /* { dg-error "register specified for 'r19' is an internal GCC implementation detail" } */
asm volatile ("# %0" : "=r"(r19)); /* { dg-error "invalid use of register" } */
} /* { dg-error "cannot be used in 'asm' here" } */
asm volatile ("# %0" : "=r"(r19));
}

View File

@ -4,5 +4,5 @@
void foo (void)
{
register int r19 asm ("19");
register int r19 asm ("19"); /* { dg-error "register specified for 'r19' is an internal GCC implementation detail" } */
}

View File

@ -0,0 +1,24 @@
/* PR target/92469 */
/* { dg-do compile } */
/* { dg-options "-O0" } */
void
foo (void)
{
register int x asm ("frame"); /* { dg-error "register specified for 'x' is an internal GCC implementation detail" } */
int y = x;
}
void
bar (void)
{
register int x asm ("19"); /* { dg-error "register specified for 'x' is an internal GCC implementation detail" } */
int y = x;
}
void
baz (void)
{
register int x asm ("argp"); /* { dg-error "register specified for 'x' is an internal GCC implementation detail" } */
int y = x;
}

View File

@ -1371,6 +1371,23 @@ ultimate_transparent_alias_target (tree *alias)
return target;
}
/* Return true if REGNUM is mentioned in ELIMINABLE_REGS as a from
register number. */
static bool
eliminable_regno_p (int regnum)
{
static const struct
{
const int from;
const int to;
} eliminables[] = ELIMINABLE_REGS;
for (size_t i = 0; i < ARRAY_SIZE (eliminables); i++)
if (regnum == eliminables[i].from)
return true;
return false;
}
/* 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.
@ -1473,6 +1490,15 @@ make_decl_rtl (tree decl)
else if (!targetm.hard_regno_mode_ok (reg_number, mode))
error ("register specified for %q+D isn%'t suitable for data type",
decl);
else if (reg_number != HARD_FRAME_POINTER_REGNUM
&& (reg_number == FRAME_POINTER_REGNUM
#ifdef RETURN_ADDRESS_POINTER_REGNUM
|| reg_number == RETURN_ADDRESS_POINTER_REGNUM
#endif
|| reg_number == ARG_POINTER_REGNUM)
&& eliminable_regno_p (reg_number))
error ("register specified for %q+D is an internal GCC "
"implementation detail", decl);
/* Now handle properly declared static register variables. */
else
{