I have tested this fix on x86_64 host, and found no regression in the C and C++ testsuites. I'm marking this patch as RFC simply because I don't have experience with other architectures, and I don't have a setup to test all architectures supported by GCC.
gcc/ChangeLog: 2018-12-07 Dimitar Dimitrov <dimi...@dinux.eu> * cfgexpand.c (asm_clobber_reg_is_valid): Also produce error when stack pointer is clobbered. (expand_asm_stmt): Refactor clobber check in separate function. gcc/testsuite/ChangeLog: 2018-12-07 Dimitar Dimitrov <dimi...@dinux.eu> * gcc.target/i386/pr52813.c: New test. Signed-off-by: Dimitar Dimitrov <dimi...@dinux.eu> --- gcc/cfgexpand.c | 42 ++++++++++++++++++++++++++------- gcc/testsuite/gcc.target/i386/pr52813.c | 9 +++++++ 2 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr52813.c diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 5e23bc242b9..8474372a216 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -2845,6 +2845,38 @@ tree_conflicts_with_clobbers_p (tree t, HARD_REG_SET *clobbered_regs) return false; } +/* Check that the given REGNO spanning NREGS is a valid + asm clobber operand. Some HW registers cannot be + saved/restored, hence they should not be clobbered by + asm statements. */ +static bool +asm_clobber_reg_is_valid (int regno, int nregs, const char *regname) +{ + bool is_valid = true; + HARD_REG_SET regset; + + CLEAR_HARD_REG_SET (regset); + + add_range_to_hard_reg_set (®set, regno, nregs); + + /* Clobbering the PIC register is an error. */ + if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM + && overlaps_hard_reg_set_p (regset, Pmode, PIC_OFFSET_TABLE_REGNUM)) + { + /* ??? Diagnose during gimplification? */ + error ("PIC register clobbered by %qs in %<asm%>", regname); + is_valid = false; + } + /* Clobbering the STACK POINTER register is an error. */ + if (overlaps_hard_reg_set_p (regset, Pmode, STACK_POINTER_REGNUM)) + { + error ("Stack Pointer register clobbered by %qs in %<asm%>", regname); + is_valid = false; + } + + return is_valid; +} + /* Generate RTL for an asm statement with arguments. STRING is the instruction template. OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs. @@ -2977,14 +3009,8 @@ expand_asm_stmt (gasm *stmt) else for (int reg = j; reg < j + nregs; reg++) { - /* Clobbering the PIC register is an error. */ - if (reg == (int) PIC_OFFSET_TABLE_REGNUM) - { - /* ??? Diagnose during gimplification? */ - error ("PIC register clobbered by %qs in %<asm%>", - regname); - return; - } + if (!asm_clobber_reg_is_valid (reg, nregs, regname)) + return; SET_HARD_REG_BIT (clobbered_regs, reg); rtx x = gen_rtx_REG (reg_raw_mode[reg], reg); diff --git a/gcc/testsuite/gcc.target/i386/pr52813.c b/gcc/testsuite/gcc.target/i386/pr52813.c new file mode 100644 index 00000000000..154ebbfc423 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr52813.c @@ -0,0 +1,9 @@ +/* Ensure that stack pointer cannot be an asm clobber. */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ + +void +test1 (void) +{ + asm volatile ("" : : : "%esp"); /* { dg-error "Stack Pointer register clobbered" } */ +} -- 2.11.0