aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorHans-Peter Nilsson <hp@axis.com>2023-09-23 05:06:52 +0200
committerHans-Peter Nilsson <hp@bitrange.com>2023-09-26 23:39:46 +0200
commit8e6757b30d0f3f13d47d0f842801a751ba6293c2 (patch)
treea56aa786ab9b2835e64c7ba278331aad0f4d424a /gcc
parentdd0c42cd37dab62f9f61ac834333ec899305dee4 (diff)
downloadgcc-8e6757b30d0f3f13d47d0f842801a751ba6293c2.zip
gcc-8e6757b30d0f3f13d47d0f842801a751ba6293c2.tar.gz
gcc-8e6757b30d0f3f13d47d0f842801a751ba6293c2.tar.bz2
__atomic_test_and_set: Fall back to library, not non-atomic code
Make __atomic_test_and_set consistent with other __atomic_ and __sync_ builtins: call a matching library function instead of emitting non-atomic code when the target has no direct insn support. There's special-case code handling targetm.atomic_test_and_set_trueval != 1 trying a modified maybe_emit_sync_lock_test_and_set. Previously, if that worked but its matching emit_store_flag_force returned NULL, we'd segfault later on. Now that the caller handles NULL, gcc_assert here instead. While the referenced PR:s are ARM-specific, the issue is general. PR target/107567 PR target/109166 * builtins.cc (expand_builtin) <case BUILT_IN_ATOMIC_TEST_AND_SET>: Handle failure from expand_builtin_atomic_test_and_set. * optabs.cc (expand_atomic_test_and_set): When all attempts fail to generate atomic code through target support, return NULL instead of emitting non-atomic code. Also, for code handling targetm.atomic_test_and_set_trueval != 1, gcc_assert result from calling emit_store_flag_force instead of returning NULL.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/builtins.cc5
-rw-r--r--gcc/optabs.cc22
2 files changed, 11 insertions, 16 deletions
diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 6e4274b..40dfd36 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -8387,7 +8387,10 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
break;
case BUILT_IN_ATOMIC_TEST_AND_SET:
- return expand_builtin_atomic_test_and_set (exp, target);
+ target = expand_builtin_atomic_test_and_set (exp, target);
+ if (target)
+ return target;
+ break;
case BUILT_IN_ATOMIC_CLEAR:
return expand_builtin_atomic_clear (exp);
diff --git a/gcc/optabs.cc b/gcc/optabs.cc
index 8b96f23..e1898da 100644
--- a/gcc/optabs.cc
+++ b/gcc/optabs.cc
@@ -7080,25 +7080,17 @@ expand_atomic_test_and_set (rtx target, rtx mem, enum memmodel model)
/* Recall that the legacy lock_test_and_set optab was allowed to do magic
things with the value 1. Thus we try again without trueval. */
if (!ret && targetm.atomic_test_and_set_trueval != 1)
- ret = maybe_emit_sync_lock_test_and_set (subtarget, mem, const1_rtx, model);
-
- /* Failing all else, assume a single threaded environment and simply
- perform the operation. */
- if (!ret)
{
- /* If the result is ignored skip the move to target. */
- if (subtarget != const0_rtx)
- emit_move_insn (subtarget, mem);
+ ret = maybe_emit_sync_lock_test_and_set (subtarget, mem, const1_rtx, model);
- emit_move_insn (mem, trueval);
- ret = subtarget;
+ if (ret)
+ {
+ /* Rectify the not-one trueval. */
+ ret = emit_store_flag_force (target, NE, ret, const0_rtx, mode, 0, 1);
+ gcc_assert (ret);
+ }
}
- /* Recall that have to return a boolean value; rectify if trueval
- is not exactly one. */
- if (targetm.atomic_test_and_set_trueval != 1)
- ret = emit_store_flag_force (target, NE, ret, const0_rtx, mode, 0, 1);
-
return ret;
}