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 <ubiz...@gmail.com> * 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]); } }