cd.maybe_set_lhs (ptr_sval);
}
-/* Handler for:
- void __atomic_exchange (type *ptr, type *val, type *ret, int memorder). */
+/* Handler for __atomic_exchange.
+ Although the user-facing documentation specifies it as having this
+ signature:
+ void __atomic_exchange (type *ptr, type *val, type *ret, int memorder)
+
+ by the time the C/C++ frontends have acted on it, any calls that
+ can't be mapped to a _N variation end up with this signature:
+
+ void
+ __atomic_exchange (size_t sz, void *ptr, void *val, void *ret,
+ int memorder)
+
+ as seen in the gimple seen by the analyzer, and as specified
+ in sync-builtins.def. */
class kf_atomic_exchange : public internal_known_function
{
public:
/* This is effectively:
- *RET = *PTR;
- *PTR = *VAL;
+ tmpA = *PTR;
+ tmpB = *VAL;
+ *PTR = tmpB;
+ *RET = tmpA;
*/
void impl_call_pre (const call_details &cd) const final override
{
- const svalue *ptr_ptr_sval = cd.get_arg_svalue (0);
- tree ptr_ptr_tree = cd.get_arg_tree (0);
- const svalue *val_ptr_sval = cd.get_arg_svalue (1);
- tree val_ptr_tree = cd.get_arg_tree (1);
- const svalue *ret_ptr_sval = cd.get_arg_svalue (2);
- tree ret_ptr_tree = cd.get_arg_tree (2);
+ const svalue *num_bytes_sval = cd.get_arg_svalue (0);
+ const svalue *ptr_sval = cd.get_arg_svalue (1);
+ tree ptr_tree = cd.get_arg_tree (1);
+ const svalue *val_sval = cd.get_arg_svalue (2);
+ tree val_tree = cd.get_arg_tree (2);
+ const svalue *ret_sval = cd.get_arg_svalue (3);
+ tree ret_tree = cd.get_arg_tree (3);
/* Ignore the memorder param. */
region_model *model = cd.get_model ();
region_model_context *ctxt = cd.get_ctxt ();
- const region *val_region
- = model->deref_rvalue (val_ptr_sval, val_ptr_tree, ctxt);
- const svalue *star_val_sval = model->get_store_value (val_region, ctxt);
- const region *ptr_region
- = model->deref_rvalue (ptr_ptr_sval, ptr_ptr_tree, ctxt);
- const svalue *star_ptr_sval = model->get_store_value (ptr_region, ctxt);
- const region *ret_region
- = model->deref_rvalue (ret_ptr_sval, ret_ptr_tree, ctxt);
- model->set_value (ptr_region, star_val_sval, ctxt);
- model->set_value (ret_region, star_ptr_sval, ctxt);
+ const region *ptr_reg = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
+ const region *val_reg = model->deref_rvalue (val_sval, val_tree, ctxt);
+ const region *ret_reg = model->deref_rvalue (ret_sval, ret_tree, ctxt);
+
+ const svalue *tmp_a_sval
+ = model->read_bytes (ptr_reg, ptr_tree, num_bytes_sval, ctxt);
+ const svalue *tmp_b_sval
+ = model->read_bytes (val_reg, val_tree, num_bytes_sval, ctxt);
+ model->write_bytes (ptr_reg, num_bytes_sval, tmp_b_sval, ctxt);
+ model->write_bytes (ret_reg, num_bytes_sval, tmp_a_sval, ctxt);
}
};
enum tree_code m_op;
};
-/* Handler for:
- void __atomic_load (type *ptr, type *ret, int memorder). */
+/* Handler for __atomic_load.
+ Although the user-facing documentation specifies it as having this
+ signature:
+
+ void __atomic_load (type *ptr, type *ret, int memorder)
+
+ by the time the C/C++ frontends have acted on it, any calls that
+ can't be mapped to a _N variation end up with this signature:
+
+ void __atomic_load (size_t sz, const void *src, void *dst, int memorder);
+
+ as seen in the gimple seen by the analyzer, and as specified
+ in sync-builtins.def. */
class kf_atomic_load : public internal_known_function
{
public:
/* This is effectively:
- *RET = *PTR;
+ memmove (dst, src, sz);
*/
void impl_call_pre (const call_details &cd) const final override
{
- const svalue *ptr_ptr_sval = cd.get_arg_svalue (0);
- tree ptr_ptr_tree = cd.get_arg_tree (0);
- const svalue *ret_ptr_sval = cd.get_arg_svalue (1);
- tree ret_ptr_tree = cd.get_arg_tree (1);
+ const svalue *num_bytes_sval = cd.get_arg_svalue (0);
+ const svalue *src_sval = cd.get_arg_svalue (1);
+ tree src_tree = cd.get_arg_tree (1);
+ const svalue *dst_sval = cd.get_arg_svalue (2);
+ tree dst_tree = cd.get_arg_tree (2);
/* Ignore the memorder param. */
region_model *model = cd.get_model ();
region_model_context *ctxt = cd.get_ctxt ();
- const region *ptr_region
- = model->deref_rvalue (ptr_ptr_sval, ptr_ptr_tree, ctxt);
- const svalue *star_ptr_sval = model->get_store_value (ptr_region, ctxt);
- const region *ret_region
- = model->deref_rvalue (ret_ptr_sval, ret_ptr_tree, ctxt);
- model->set_value (ret_region, star_ptr_sval, ctxt);
+ const region *dst_reg = model->deref_rvalue (dst_sval, dst_tree, ctxt);
+ const region *src_reg = model->deref_rvalue (src_sval, src_tree, ctxt);
+
+ const svalue *data_sval
+ = model->read_bytes (src_reg, src_tree, num_bytes_sval, ctxt);
+ model->write_bytes (dst_reg, num_bytes_sval, data_sval, ctxt);
+ }
+};
+
+/* Handler for __atomic_store.
+ Although the user-facing documentation specifies it as having this
+ signature:
+
+ void __atomic_store (type *ptr, type *val, int memorder)
+
+ by the time the C/C++ frontends have acted on it, any calls that
+ can't be mapped to a _N variation end up with this signature:
+
+ void __atomic_store (size_t sz, type *dst, type *src, int memorder)
+
+ as seen in the gimple seen by the analyzer, and as specified
+ in sync-builtins.def. */
+
+class kf_atomic_store : public internal_known_function
+{
+public:
+ /* This is effectively:
+ memmove (dst, src, sz);
+ */
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ const svalue *num_bytes_sval = cd.get_arg_svalue (0);
+ const svalue *dst_sval = cd.get_arg_svalue (1);
+ tree dst_tree = cd.get_arg_tree (1);
+ const svalue *src_sval = cd.get_arg_svalue (2);
+ tree src_tree = cd.get_arg_tree (2);
+ /* Ignore the memorder param. */
+
+ region_model *model = cd.get_model ();
+ region_model_context *ctxt = cd.get_ctxt ();
+
+ const region *dst_reg = model->deref_rvalue (dst_sval, dst_tree, ctxt);
+ const region *src_reg = model->deref_rvalue (src_sval, src_tree, ctxt);
+
+ const svalue *data_sval
+ = model->read_bytes (src_reg, src_tree, num_bytes_sval, ctxt);
+ model->write_bytes (dst_reg, num_bytes_sval, data_sval, ctxt);
}
};
kfm.add (BUILT_IN_ATOMIC_LOAD_4, make_unique<kf_atomic_load_n> ());
kfm.add (BUILT_IN_ATOMIC_LOAD_8, make_unique<kf_atomic_load_n> ());
kfm.add (BUILT_IN_ATOMIC_LOAD_16, make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE, make_unique<kf_atomic_store> ());
kfm.add (BUILT_IN_ATOMIC_STORE_N, make_unique<kf_atomic_store_n> ());
kfm.add (BUILT_IN_ATOMIC_STORE_1, make_unique<kf_atomic_store_n> ());
kfm.add (BUILT_IN_ATOMIC_STORE_2, make_unique<kf_atomic_store_n> ());