summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2022-06-16 10:58:58 +0200
committerJakub Jelinek <jakub@redhat.com>2022-06-19 12:08:35 +0200
commit86e10e471fddfcacb0c02d02f30ab5bb2038e504 (patch)
tree77ce147df088a4b70ef6f9daefcbe524d1aa72ac
parentFix ipa-cp wrt volatile loads (diff)
downloadgcc-86e10e471fddfcacb0c02d02f30ab5bb2038e504.tar.gz
gcc-86e10e471fddfcacb0c02d02f30ab5bb2038e504.tar.bz2
gcc-86e10e471fddfcacb0c02d02f30ab5bb2038e504.tar.xz
expand: Fix up IFN_ATOMIC_{BIT*,*CMP_0} expansion [PR105951]
Both IFN_ATOMIC_BIT_TEST_AND_* and IFN_ATOMIC_*_FETCH_CMP_0 ifns are matched if their corresponding optab is implemented for the particular mode. The fact that those optabs are implemented doesn't guarantee they will succeed though, they can just FAIL in their expansion. The expansion in that case uses expand_atomic_fetch_op as fallback, but as has been reported and and can be reproduced on the testcases, even those can fail and we didn't have any fallback after that. For IFN_ATOMIC_BIT_TEST_AND_* we actually have such calls. One is done whenever we lost lhs of the ifn at some point in between matching it in tree-ssa-ccp.cc and expansion. The following patch for that case just falls through and expands as if there was a lhs, creates a temporary for it. For the other expand_atomic_fetch_op call in the same expander and for the only expand_atomic_fetch_op call in the other, this falls back the hard way, by constructing a CALL_EXPR to the call from which the ifn has been matched and expanding that. Either it is lucky and manages to expand inline, or it emits a libatomic API call. So that we don't have to rediscover which builtin function to call in the fallback, we record at tree-ssa-ccp.cc time gimple_call_fn (call) in an extra argument to the ifn. 2022-06-16 Jakub Jelinek <jakub@redhat.com> PR middle-end/105951 * tree-ssa-ccp.cc (optimize_atomic_bit_test_and, optimize_atomic_op_fetch_cmp_0): Remember gimple_call_fn (call) as last argument to the internal functions. * builtins.cc (expand_ifn_atomic_bit_test_and): Adjust for the extra call argument to ifns. If expand_atomic_fetch_op fails for the lhs == NULL_TREE case, fall through into the optab code with gen_reg_rtx (mode) as target. If second expand_atomic_fetch_op fails, construct a CALL_EXPR and expand that. (expand_ifn_atomic_op_fetch_cmp_0): Adjust for the extra call argument to ifns. If expand_atomic_fetch_op fails, construct a CALL_EXPR and expand that. * gcc.target/i386/pr105951-1.c: New test. * gcc.target/i386/pr105951-2.c: New test. (cherry picked from commit 6a27c430468cb85454b19cef881a1422580657ff)
-rw-r--r--gcc/builtins.cc51
-rw-r--r--gcc/testsuite/gcc.target/i386/pr105951-1.c5
-rw-r--r--gcc/testsuite/gcc.target/i386/pr105951-2.c5
-rw-r--r--gcc/tree-ssa-ccp.cc19
4 files changed, 64 insertions, 16 deletions
diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 5b085e3a14f..85459200a09 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -6224,7 +6224,7 @@ expand_ifn_atomic_bit_test_and (gcall *call)
6224 6224
6225 gcc_assert (flag_inline_atomics); 6225 gcc_assert (flag_inline_atomics);
6226 6226
6227 if (gimple_call_num_args (call) == 4) 6227 if (gimple_call_num_args (call) == 5)
6228 model = get_memmodel (gimple_call_arg (call, 3)); 6228 model = get_memmodel (gimple_call_arg (call, 3));
6229 6229
6230 rtx mem = get_builtin_sync_mem (ptr, mode); 6230 rtx mem = get_builtin_sync_mem (ptr, mode);
@@ -6250,15 +6250,19 @@ expand_ifn_atomic_bit_test_and (gcall *call)
6250 6250
6251 if (lhs == NULL_TREE) 6251 if (lhs == NULL_TREE)
6252 { 6252 {
6253 val = expand_simple_binop (mode, ASHIFT, const1_rtx, 6253 rtx val2 = expand_simple_binop (mode, ASHIFT, const1_rtx,
6254 val, NULL_RTX, true, OPTAB_DIRECT); 6254 val, NULL_RTX, true, OPTAB_DIRECT);
6255 if (code == AND) 6255 if (code == AND)
6256 val = expand_simple_unop (mode, NOT, val, NULL_RTX, true); 6256 val2 = expand_simple_unop (mode, NOT, val2, NULL_RTX, true);
6257 expand_atomic_fetch_op (const0_rtx, mem, val, code, model, false); 6257 if (expand_atomic_fetch_op (const0_rtx, mem, val2, code, model, false))
6258 return; 6258 return;
6259 } 6259 }
6260 6260
6261 rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); 6261 rtx target;
6262 if (lhs)
6263 target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
6264 else
6265 target = gen_reg_rtx (mode);
6262 enum insn_code icode = direct_optab_handler (optab, mode); 6266 enum insn_code icode = direct_optab_handler (optab, mode);
6263 gcc_assert (icode != CODE_FOR_nothing); 6267 gcc_assert (icode != CODE_FOR_nothing);
6264 create_output_operand (&ops[0], target, mode); 6268 create_output_operand (&ops[0], target, mode);
@@ -6277,6 +6281,22 @@ expand_ifn_atomic_bit_test_and (gcall *call)
6277 val = expand_simple_unop (mode, NOT, val, NULL_RTX, true); 6281 val = expand_simple_unop (mode, NOT, val, NULL_RTX, true);
6278 rtx result = expand_atomic_fetch_op (gen_reg_rtx (mode), mem, val, 6282 rtx result = expand_atomic_fetch_op (gen_reg_rtx (mode), mem, val,
6279 code, model, false); 6283 code, model, false);
6284 if (!result)
6285 {
6286 bool is_atomic = gimple_call_num_args (call) == 5;
6287 tree tcall = gimple_call_arg (call, 3 + is_atomic);
6288 tree fndecl = gimple_call_addr_fndecl (tcall);
6289 tree type = TREE_TYPE (TREE_TYPE (fndecl));
6290 tree exp = build_call_nary (type, tcall, 2 + is_atomic, ptr,
6291 make_tree (type, val),
6292 is_atomic
6293 ? gimple_call_arg (call, 3)
6294 : integer_zero_node);
6295 result = expand_builtin (exp, gen_reg_rtx (mode), NULL_RTX,
6296 mode, !lhs);
6297 }
6298 if (!lhs)
6299 return;
6280 if (integer_onep (flag)) 6300 if (integer_onep (flag))
6281 { 6301 {
6282 result = expand_simple_binop (mode, ASHIFTRT, result, bitval, 6302 result = expand_simple_binop (mode, ASHIFTRT, result, bitval,
@@ -6308,7 +6328,7 @@ expand_ifn_atomic_op_fetch_cmp_0 (gcall *call)
6308 6328
6309 gcc_assert (flag_inline_atomics); 6329 gcc_assert (flag_inline_atomics);
6310 6330
6311 if (gimple_call_num_args (call) == 4) 6331 if (gimple_call_num_args (call) == 5)
6312 model = get_memmodel (gimple_call_arg (call, 3)); 6332 model = get_memmodel (gimple_call_arg (call, 3));
6313 6333
6314 rtx mem = get_builtin_sync_mem (ptr, mode); 6334 rtx mem = get_builtin_sync_mem (ptr, mode);
@@ -6369,6 +6389,21 @@ expand_ifn_atomic_op_fetch_cmp_0 (gcall *call)
6369 6389
6370 rtx result = expand_atomic_fetch_op (gen_reg_rtx (mode), mem, op, 6390 rtx result = expand_atomic_fetch_op (gen_reg_rtx (mode), mem, op,
6371 code, model, true); 6391 code, model, true);
6392 if (!result)
6393 {
6394 bool is_atomic = gimple_call_num_args (call) == 5;
6395 tree tcall = gimple_call_arg (call, 3 + is_atomic);
6396 tree fndecl = gimple_call_addr_fndecl (tcall);
6397 tree type = TREE_TYPE (TREE_TYPE (fndecl));
6398 tree exp = build_call_nary (type, tcall,
6399 2 + is_atomic, ptr, arg,
6400 is_atomic
6401 ? gimple_call_arg (call, 3)
6402 : integer_zero_node);
6403 result = expand_builtin (exp, gen_reg_rtx (mode), NULL_RTX,
6404 mode, !lhs);
6405 }
6406
6372 if (lhs) 6407 if (lhs)
6373 { 6408 {
6374 result = emit_store_flag_force (target, comp, result, const0_rtx, mode, 6409 result = emit_store_flag_force (target, comp, result, const0_rtx, mode,
diff --git a/gcc/testsuite/gcc.target/i386/pr105951-1.c b/gcc/testsuite/gcc.target/i386/pr105951-1.c
new file mode 100644
index 00000000000..ff1c1db133a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr105951-1.c
@@ -0,0 +1,5 @@
1/* PR middle-end/105951 */
2/* { dg-do compile { target ia32 } } */
3/* { dg-options "-O2 -march=i386" } */
4
5#include "pr98737-2.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr105951-2.c b/gcc/testsuite/gcc.target/i386/pr105951-2.c
new file mode 100644
index 00000000000..fed77f795e0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr105951-2.c
@@ -0,0 +1,5 @@
1/* PR middle-end/105951 */
2/* { dg-do compile { target ia32 } } */
3/* { dg-options "-O2 -march=i386" } */
4
5#include "pr98737-4.c"
diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc
index 9164efe3037..29661884b92 100644
--- a/gcc/tree-ssa-ccp.cc
+++ b/gcc/tree-ssa-ccp.cc
@@ -3789,11 +3789,12 @@ optimize_atomic_bit_test_and (gimple_stmt_iterator *gsip,
3789 tree new_lhs = make_ssa_name (TREE_TYPE (lhs)); 3789 tree new_lhs = make_ssa_name (TREE_TYPE (lhs));
3790 tree flag = build_int_cst (TREE_TYPE (lhs), use_bool); 3790 tree flag = build_int_cst (TREE_TYPE (lhs), use_bool);
3791 if (has_model_arg) 3791 if (has_model_arg)
3792 g = gimple_build_call_internal (fn, 4, gimple_call_arg (call, 0), 3792 g = gimple_build_call_internal (fn, 5, gimple_call_arg (call, 0),
3793 bit, flag, gimple_call_arg (call, 2)); 3793 bit, flag, gimple_call_arg (call, 2),
3794 gimple_call_fn (call));
3794 else 3795 else
3795 g = gimple_build_call_internal (fn, 3, gimple_call_arg (call, 0), 3796 g = gimple_build_call_internal (fn, 4, gimple_call_arg (call, 0),
3796 bit, flag); 3797 bit, flag, gimple_call_fn (call));
3797 gimple_call_set_lhs (g, new_lhs); 3798 gimple_call_set_lhs (g, new_lhs);
3798 gimple_set_location (g, gimple_location (call)); 3799 gimple_set_location (g, gimple_location (call));
3799 gimple_move_vops (g, call); 3800 gimple_move_vops (g, call);
@@ -4003,14 +4004,16 @@ optimize_atomic_op_fetch_cmp_0 (gimple_stmt_iterator *gsip,
4003 gimple *g; 4004 gimple *g;
4004 tree flag = build_int_cst (TREE_TYPE (lhs), encoded); 4005 tree flag = build_int_cst (TREE_TYPE (lhs), encoded);
4005 if (has_model_arg) 4006 if (has_model_arg)
4006 g = gimple_build_call_internal (fn, 4, flag, 4007 g = gimple_build_call_internal (fn, 5, flag,
4007 gimple_call_arg (call, 0), 4008 gimple_call_arg (call, 0),
4008 gimple_call_arg (call, 1), 4009 gimple_call_arg (call, 1),
4009 gimple_call_arg (call, 2)); 4010 gimple_call_arg (call, 2),
4011 gimple_call_fn (call));
4010 else 4012 else
4011 g = gimple_build_call_internal (fn, 3, flag, 4013 g = gimple_build_call_internal (fn, 4, flag,
4012 gimple_call_arg (call, 0), 4014 gimple_call_arg (call, 0),
4013 gimple_call_arg (call, 1)); 4015 gimple_call_arg (call, 1),
4016 gimple_call_fn (call));
4014 gimple_call_set_lhs (g, new_lhs); 4017 gimple_call_set_lhs (g, new_lhs);
4015 gimple_set_location (g, gimple_location (call)); 4018 gimple_set_location (g, gimple_location (call));
4016 gimple_move_vops (g, call); 4019 gimple_move_vops (g, call);