Hello!
This patch is based on the discussion in PR88178. Apparently, MIPS
uses accessible_reg_set array to disable register sets, unsupported by
currently active ISAs. The patch implements the same approach for x86,
which also results in IMO better error messages. The middle-end misses
to error out in asm having inaccessible clobber registers, so the
patch implements the missing handling (the error message could
probably be improved...)
A couple of test cases now emit better diagnostics, e.g.:
* gcc.target/i386/asm-1.c:5:23: error: the register specified for
'EAX' cannot be accessed by the current target
* gcc.target/i386/pr62120.c:6:16: error: the register specified for
'zmm_var' cannot be accessed by the current target
* gcc.target/i386/pr62120.c:7:16: error: the register specified for
'zmm_var2' cannot be accessed by the current target
instead of "invalid register name" messages.
2018-11-27 Uros Bizjak <[email protected]>
* cfgexpand.c (expand_asm_stmt): Reject clobbers outside of
accessible_reg_set.
* config/i386/i386.c (ix86_conditional_register_usage):
Disable register sets by clearing corresponding bits in
accessible_reg_set. Do not set corresponding bits in fixed_regs,
call_used_regs and don't clear corresponding reg_names array members.
Patch was bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.
This is gcc-10 material, so the patch is not committed to the repository.
Uros.
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 21bdcdaeaa35..691e0c7c1b0b 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2981,6 +2981,14 @@ expand_asm_stmt (gasm *stmt)
regname);
return;
}
+ else if (!in_hard_reg_set_p
+ (accessible_reg_set, reg_raw_mode[reg], reg))
+ {
+ /* ??? Diagnose during gimplification? */
+ error ("the register %qs cannot be clobbered in %<asm%>"
+ " for the current target", regname);
+ return;
+ }
SET_HARD_REG_BIT (clobbered_regs, reg);
rtx x = gen_rtx_REG (reg_raw_mode[reg], reg);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 95abde95f89d..9abd441930f4 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -4743,15 +4743,15 @@ ix86_conditional_register_usage (void)
if (!fixed_regs[i] && !ix86_function_value_regno_p (i))
call_used_regs[i] = 0;
- /* For 32-bit targets, squash the REX registers. */
+ /* For 32-bit targets, disable the REX registers. */
if (! TARGET_64BIT)
{
for (i = FIRST_REX_INT_REG; i <= LAST_REX_INT_REG; i++)
- fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+ CLEAR_HARD_REG_BIT (accessible_reg_set, i);
for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++)
- fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+ CLEAR_HARD_REG_BIT (accessible_reg_set, i);
for (i = FIRST_EXT_REX_SSE_REG; i <= LAST_EXT_REX_SSE_REG; i++)
- fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+ CLEAR_HARD_REG_BIT (accessible_reg_set, i);
}
/* See the definition of CALL_USED_REGISTERS in i386.h. */
@@ -4773,32 +4773,29 @@ ix86_conditional_register_usage (void)
SET_HARD_REG_BIT (reg_class_contents[(int)CLOBBERED_REGS], i);
}
- /* If MMX is disabled, squash the registers. */
+ /* If MMX is disabled, disable the registers. */
if (! TARGET_MMX)
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (TEST_HARD_REG_BIT (reg_class_contents[(int)MMX_REGS], i))
- fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+ AND_COMPL_HARD_REG_SET (accessible_reg_set,
+ reg_class_contents[(int) MMX_REGS]);
- /* If SSE is disabled, squash the registers. */
+ /* If SSE is disabled, disable the registers. */
if (! TARGET_SSE)
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (TEST_HARD_REG_BIT (reg_class_contents[(int)SSE_REGS], i))
- fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+ AND_COMPL_HARD_REG_SET (accessible_reg_set,
+ reg_class_contents[(int) ALL_SSE_REGS]);
- /* If the FPU is disabled, squash the registers. */
+ /* If the FPU is disabled, disable the registers. */
if (! (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387))
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (TEST_HARD_REG_BIT (reg_class_contents[(int)FLOAT_REGS], i))
- fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+ AND_COMPL_HARD_REG_SET (accessible_reg_set,
+ reg_class_contents[(int) FLOAT_REGS]);
- /* If AVX512F is disabled, squash the registers. */
+ /* If AVX512F is disabled, disable the registers. */
if (! TARGET_AVX512F)
{
for (i = FIRST_EXT_REX_SSE_REG; i <= LAST_EXT_REX_SSE_REG; i++)
- fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+ CLEAR_HARD_REG_BIT (accessible_reg_set, i);
- for (i = FIRST_MASK_REG; i <= LAST_MASK_REG; i++)
- fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+ AND_COMPL_HARD_REG_SET (accessible_reg_set,
+ reg_class_contents[(int) ALL_MASK_REGS]);
}
}