From: Jakub Jelinek Date: Mon, 21 Jun 2021 11:30:42 +0000 (+0200) Subject: inline-asm: Fix ICE with bitfields in "m" operands [PR100785] X-Git-Tag: releases/gcc-11.2.0~160 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b6e4453172e6502318d31517b7d3771b157ae71a;p=thirdparty%2Fgcc.git inline-asm: Fix ICE with bitfields in "m" operands [PR100785] Bitfields, while they live in memory, aren't something inline-asm can easily operate on. For C and "=m" or "+m", we were diagnosing bitfields in the past in the FE, where c_mark_addressable had: case COMPONENT_REF: if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1))) { error ("cannot take address of bit-field %qD", TREE_OPERAND (x, 1)); return false; } but that check got moved in GCC 6 to build_unary_op instead and now we emit an error during expansion and ICE afterwards (i.e. error-recovery). For "m" it used to be diagnosed in c_mark_addressable too, but since GCC 6 it is ice-on-invalid. For C++, this was never diagnosed in the FE, but used to be diagnosed in the gimplifier and/or during expansion before 4.8. The following patch does multiple things: 1) diagnoses it in the FEs 2) simplifies during expansion the inline asm if any errors have been reported (similarly how e.g. vregs pass if it detects errors on inline-asm either deletes them or simplifies to bare minimum - just labels), so that we don't have error-recovery ICEs there 2021-06-11 Jakub Jelinek PR inline-asm/100785 gcc/ * cfgexpand.c (expand_asm_stmt): If errors are emitted, remove all inputs, outputs and clobbers from the asm and set template to "". gcc/c/ * c-typeck.c (c_mark_addressable): Diagnose trying to make bit-fields addressable. gcc/cp/ * typeck.c (cxx_mark_addressable): Diagnose trying to make bit-fields addressable. gcc/testsuite/ * c-c++-common/pr100785.c: New test. (cherry picked from commit 644c2cc5f2c09506a7bfef293a7f90efa8d7e5fa) --- diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 917e670ddd71..7b84f3e64566 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -5033,8 +5033,17 @@ c_mark_addressable (tree exp, bool array_ref_p) && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0)))) return true; - /* FALLTHRU */ + x = TREE_OPERAND (x, 0); + break; + case COMPONENT_REF: + if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1))) + { + error ("cannot take address of bit-field %qD", + TREE_OPERAND (x, 1)); + return false; + } + /* FALLTHRU */ case ADDR_EXPR: case ARRAY_REF: case REALPART_EXPR: diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index c221b4165caf..0c26337bfa34 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -3076,6 +3076,7 @@ expand_asm_stmt (gasm *stmt) unsigned ninputs = gimple_asm_ninputs (stmt); unsigned nlabels = gimple_asm_nlabels (stmt); unsigned i; + bool error_seen = false; /* ??? Diagnose during gimplification? */ if (ninputs + noutputs + nlabels > MAX_RECOG_OPERANDS) @@ -3134,6 +3135,7 @@ expand_asm_stmt (gasm *stmt) { /* ??? Diagnose during gimplification? */ error ("unknown register name %qs in %", regname); + error_seen = true; } else if (j == -4) { @@ -3196,7 +3198,10 @@ expand_asm_stmt (gasm *stmt) && REG_P (DECL_RTL (output_tvec[j])) && HARD_REGISTER_P (DECL_RTL (output_tvec[j])) && output_hregno == REGNO (DECL_RTL (output_tvec[j]))) - error ("invalid hard register usage between output operands"); + { + error ("invalid hard register usage between output operands"); + error_seen = true; + } /* Verify matching constraint operands use the same hard register and that the non-matching constraint operands do not use the same @@ -3219,13 +3224,19 @@ expand_asm_stmt (gasm *stmt) } if (i == match && output_hregno != input_hregno) - error ("invalid hard register usage between output operand " - "and matching constraint operand"); + { + error ("invalid hard register usage between output " + "operand and matching constraint operand"); + error_seen = true; + } else if (early_clobber_p && i != match && output_hregno == input_hregno) - error ("invalid hard register usage between earlyclobber " - "operand and input operand"); + { + error ("invalid hard register usage between " + "earlyclobber operand and input operand"); + error_seen = true; + } } } @@ -3301,7 +3312,10 @@ expand_asm_stmt (gasm *stmt) op = validize_mem (op); if (! allows_reg && !MEM_P (op)) - error ("output number %d not directly addressable", i); + { + error ("output number %d not directly addressable", i); + error_seen = true; + } if ((! allows_mem && MEM_P (op) && GET_MODE (op) != BLKmode) || GET_CODE (op) == CONCAT) { @@ -3341,6 +3355,19 @@ expand_asm_stmt (gasm *stmt) inout_opnum.safe_push (i); } + const char *str = gimple_asm_string (stmt); + if (error_seen) + { + ninputs = 0; + noutputs = 0; + inout_opnum.truncate (0); + output_rvec.truncate (0); + clobber_rvec.truncate (0); + constraints.truncate (0); + CLEAR_HARD_REG_SET (clobbered_regs); + str = ""; + } + auto_vec input_rvec; auto_vec input_mode; @@ -3399,7 +3426,7 @@ expand_asm_stmt (gasm *stmt) } /* For in-out operands, copy output rtx to input rtx. */ - unsigned ninout = inout_opnum.length(); + unsigned ninout = inout_opnum.length (); for (i = 0; i < ninout; i++) { int j = inout_opnum[i]; @@ -3453,7 +3480,7 @@ expand_asm_stmt (gasm *stmt) rtx body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode : GET_MODE (output_rvec[0])), - ggc_strdup (gimple_asm_string (stmt)), + ggc_strdup (str), "", 0, argvec, constraintvec, labelvec, locus); MEM_VOLATILE_P (body) = gimple_asm_volatile_p (stmt); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index cce26b89cdec..1b68c53b831a 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -7081,9 +7081,14 @@ cxx_mark_addressable (tree exp, bool array_ref_p) && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0)))) return true; + x = TREE_OPERAND (x, 0); + break; + + case COMPONENT_REF: + if (bitfield_p (x)) + error ("attempt to take address of bit-field"); /* FALLTHRU */ case ADDR_EXPR: - case COMPONENT_REF: case ARRAY_REF: case REALPART_EXPR: case IMAGPART_EXPR: diff --git a/gcc/testsuite/c-c++-common/pr100785.c b/gcc/testsuite/c-c++-common/pr100785.c new file mode 100644 index 000000000000..a3cd4cfa5c03 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr100785.c @@ -0,0 +1,21 @@ +/* PR inline-asm/100785 */ + +struct S { int a : 1; }; + +void +foo (struct S *x) +{ + __asm__ ("" : "+m" (x->a)); /* { dg-error "address of bit-field" } */ +} /* { dg-error "invalid lvalue in 'asm' output 0" "" { target c } .-1 } */ + /* { dg-error "memory input 1 is not directly addressable" "" { target c } .-2 } */ +void +bar (struct S *x) +{ + __asm__ ("" : "=m" (x->a)); /* { dg-error "address of bit-field" } */ +} /* { dg-error "invalid lvalue in 'asm' output 0" "" { target c } .-1 } */ + +void +baz (struct S *x) +{ + __asm__ ("" : : "m" (x->a)); /* { dg-error "address of bit-field" } */ +} /* { dg-error "memory input 0 is not directly addressable" "" { target c } .-1 } */