Hi! BIT_INSERT_EXPR is only defined for integral and vector types, so if we have an array type which is bitfield representative if there is no integral type, this fails to gimplify. This still uses BIT_INSERT_EXPR with those types to hold the expressions between c-omp.c and gimplification, but fixes it there.
Bootstrapped/regtested on {x86_64,i686,powerpc64{,le}}-linux, committed to trunk, queued for backports. 2019-01-22 Jakub Jelinek <ja...@redhat.com> PR middle-end/88968 * gimplify.c (gimplify_omp_atomic): Handle bitfield atomics with non-integral DECL_BIT_FIELD_REPRESENTATIVEs. * c-omp.c (c_finish_omp_atomic): For bitfield atomics, update type variable after using BIT_FIELD_REF. * c-c++-common/gomp/atomic-23.c: New test. --- gcc/gimplify.c.jj 2019-01-01 12:37:19.881930257 +0100 +++ gcc/gimplify.c 2019-01-22 15:42:28.112511624 +0100 @@ -11969,9 +11969,36 @@ gimplify_omp_atomic (tree *expr_p, gimpl loadstmt = gimple_build_omp_atomic_load (tmp_load, addr, OMP_ATOMIC_MEMORY_ORDER (*expr_p)); gimplify_seq_add_stmt (pre_p, loadstmt); - if (rhs && gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue) - != GS_ALL_DONE) - return GS_ERROR; + if (rhs) + { + /* BIT_INSERT_EXPR is not valid for non-integral bitfield + representatives. Use BIT_FIELD_REF on the lhs instead. */ + if (TREE_CODE (rhs) == BIT_INSERT_EXPR + && !INTEGRAL_TYPE_P (TREE_TYPE (tmp_load))) + { + tree bitpos = TREE_OPERAND (rhs, 2); + tree op1 = TREE_OPERAND (rhs, 1); + tree bitsize; + tree tmp_store = tmp_load; + if (TREE_CODE (*expr_p) == OMP_ATOMIC_CAPTURE_OLD) + tmp_store = get_initialized_tmp_var (tmp_load, pre_p, NULL); + if (INTEGRAL_TYPE_P (TREE_TYPE (op1))) + bitsize = bitsize_int (TYPE_PRECISION (TREE_TYPE (op1))); + else + bitsize = TYPE_SIZE (TREE_TYPE (op1)); + gcc_assert (TREE_OPERAND (rhs, 0) == tmp_load); + tree t = build2_loc (EXPR_LOCATION (rhs), + MODIFY_EXPR, void_type_node, + build3_loc (EXPR_LOCATION (rhs), BIT_FIELD_REF, + TREE_TYPE (op1), tmp_store, bitsize, + bitpos), op1); + gimplify_and_add (t, pre_p); + rhs = tmp_store; + } + if (gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue) + != GS_ALL_DONE) + return GS_ERROR; + } if (TREE_CODE (*expr_p) == OMP_ATOMIC_READ) rhs = tmp_load; --- gcc/c-family/c-omp.c.jj 2019-01-01 12:37:51.324414364 +0100 +++ gcc/c-family/c-omp.c 2019-01-22 15:28:39.110981144 +0100 @@ -378,8 +378,11 @@ c_finish_omp_atomic (location_t loc, enu } } if (blhs) - x = build3_loc (loc, BIT_FIELD_REF, TREE_TYPE (blhs), x, - bitsize_int (bitsize), bitsize_int (bitpos)); + { + x = build3_loc (loc, BIT_FIELD_REF, TREE_TYPE (blhs), x, + bitsize_int (bitsize), bitsize_int (bitpos)); + type = TREE_TYPE (blhs); + } x = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR, loc, x, NULL_TREE); if (rhs1 && rhs1 != orig_lhs) --- gcc/testsuite/c-c++-common/gomp/atomic-23.c.jj 2019-01-22 15:56:23.289958860 +0100 +++ gcc/testsuite/c-c++-common/gomp/atomic-23.c 2019-01-22 15:56:01.331314322 +0100 @@ -0,0 +1,47 @@ +/* PR middle-end/88968 */ +/* { dg-do compile } */ + +struct __attribute__((packed)) S { + unsigned int a : 16; + unsigned int b : 1; +} s; + +void +f1 (void) +{ +#pragma omp atomic + ++s.a; +} + +int +f2 (void) +{ + int r; +#pragma omp atomic capture + { + r = s.a; + s.a = 0; + } + return r; +} + +int +f3 (void) +{ + int r; +#pragma omp atomic capture + { + r = s.a; + s.a = s.a + 32; + } + return r; +} + +int +f4 (void) +{ + int r; +#pragma omp atomic capture + r = s.a = s.a + 32; + return r; +} Jakub