From 640df4ef815aa35fedf1d724ab31d8eed8817f82 Mon Sep 17 00:00:00 2001 From: Jonathan Wright Date: Wed, 18 Aug 2021 09:10:22 +0100 Subject: aarch64: Fix float <-> int errors in vld4[q]_lane intrinsics A previous commit "aarch64: Remove macros for vld4[q]_lane Neon intrinsics" introduced some float <-> int type conversion errors. This patch fixes those errors. gcc/ChangeLog: 2021-08-18 Jonathan Wright * config/aarch64/arm_neon.h (vld3_lane_f64): Use float RTL pattern and type cast. (vld4_lane_f32): Use float RTL pattern. (vld4q_lane_f64): Use float type cast. --- gcc/config/aarch64/arm_neon.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h index d8b2970..635a223 100644 --- a/gcc/config/aarch64/arm_neon.h +++ b/gcc/config/aarch64/arm_neon.h @@ -20546,8 +20546,8 @@ vld3_lane_f64 (const float64_t * __ptr, float64x1x3_t __b, const int __c) __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[1], 1); __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[2], 2); - __o = __builtin_aarch64_ld3_lanedi ( - (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __o = __builtin_aarch64_ld3_lanedf ( + (__builtin_aarch64_simd_df *) __ptr, __o, __c); __b.val[0] = (float64x1_t) __builtin_aarch64_get_dregcidi (__o, 0); __b.val[1] = (float64x1_t) __builtin_aarch64_get_dregcidi (__o, 1); __b.val[2] = (float64x1_t) __builtin_aarch64_get_dregcidi (__o, 2); @@ -21077,7 +21077,7 @@ vld4_lane_f32 (const float32_t * __ptr, float32x2x4_t __b, const int __c) __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[1], 1); __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[2], 2); __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[3], 3); - __o = __builtin_aarch64_ld4_lanev2si ( + __o = __builtin_aarch64_ld4_lanev2sf ( (__builtin_aarch64_simd_sf *) __ptr, __o, __c); __b.val[0] = (float32x2_t) __builtin_aarch64_get_dregxidi (__o, 0); __b.val[1] = (float32x2_t) __builtin_aarch64_get_dregxidi (__o, 1); @@ -21381,7 +21381,7 @@ vld4q_lane_f64 (const float64_t * __ptr, float64x2x4_t __b, const int __c) __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); __o = __builtin_aarch64_ld4_lanev2df ( - (__builtin_aarch64_simd_di *) __ptr, __o, __c); + (__builtin_aarch64_simd_df *) __ptr, __o, __c); ret.val[0] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 0); ret.val[1] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 1); ret.val[2] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 2); -- cgit v1.1 From bb04a03c6f9bacc890118b9e12b657503093c2f8 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Wed, 18 Aug 2021 17:20:40 +0200 Subject: Make 'gcc/hash-map-tests.c:test_map_of_type_with_ctor_and_dtor_expand' work on 32-bit architectures [PR101959] Bug fix for recent commit e4f16e9f357a38ec702fb69a0ffab9d292a6af9b "Add more self-tests for 'hash_map' with Value type with non-trivial constructor/destructor". gcc/ PR bootstrap/101959 * hash-map-tests.c (test_map_of_type_with_ctor_and_dtor_expand): Use an 'int_hash'. --- gcc/hash-map-tests.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/hash-map-tests.c b/gcc/hash-map-tests.c index 257f2be..6acc0d4 100644 --- a/gcc/hash-map-tests.c +++ b/gcc/hash-map-tests.c @@ -328,11 +328,22 @@ test_map_of_type_with_ctor_and_dtor_expand (bool remove_some_inline) size_t expand_c_expected = 4; size_t expand_c = 0; - void *a[N_elem]; + /* For stability of this testing, we need all Key values 'k' to produce + unique hash values 'Traits::hash (k)', as otherwise the dynamic + insert/remove behavior may diverge across different architectures. This + is, for example, a problem when using the standard 'pointer_hash::hash', + which is simply doing a 'k >> 3' operation, which is fine on 64-bit + architectures, but on 32-bit architectures produces the same hash value + for subsequent 'a[i] = &a[i]' array elements. Therefore, use an + 'int_hash'. */ + + int a[N_elem]; for (size_t i = 0; i < N_elem; ++i) - a[i] = &a[i]; + a[i] = i; - typedef hash_map Map; + const int EMPTY = -1; + const int DELETED = -2; + typedef hash_map, val_t> Map; /* Note that we are starting with a fresh 'Map'. Even if an existing one has been cleared out completely, there remain 'deleted' elements, and these -- cgit v1.1 From aef703cf982072427e74034f4c460a11c5e04b8e Mon Sep 17 00:00:00 2001 From: Ankur Saini Date: Thu, 29 Jul 2021 15:48:07 +0530 Subject: analyzer: detect and analyze calls via function pointer 2021-07-29 Ankur Saini gcc/analyzer/ChangeLog: PR analyzer/100546 * analysis-plan.cc (analysis_plan::use_summary_p): Don't use call summaries if there is no callgraph edge * checker-path.cc (call_event::call_event): Handle calls events that are not represented by a supergraph call edge (return_event::return_event): Likewise. (call_event::get_desc): Work with new call_event structure. (return_event::get_desc): Likeise. * checker-path.h (call_event::m_src_snode): New field. (call_event::m_dest_snode): New field. (return_event::m_src_snode): New field. (return_event::m_dest_snode): New field. * diagnostic-manager.cc (diagnostic_manager::prune_for_sm_diagnostic): Refactor to work with edges without callgraph edge. (diagnostic_manager::prune_for_sm_diagnostic): Likewise. * engine.cc (dynamic_call_info_t::update_model): New function. (dynamic_call_info_t::add_events_to_path): New function. (exploded_graph::create_dynamic_call): New function. (exploded_graph::process_node): Work with dynamically discovered calls. * exploded-graph.h (class dynamic_call_info_t): New class. (exploded_graph::create_dynamic_call): New decl. * program-point.cc (program_point::push_to_call_stack): New function. (program_point::pop_from_call_stack): New function. * program-point.h (program_point::push_to_call_stack): New decl. (program_point::pop_from_call_stack): New decl. * program-state.cc (program_state::push_call): New function. (program_state::returning_call): New function. * program-state.h (program_state::push_call): New decl. (program_state::returning_call): New decl. * region-model.cc (region_model::update_for_gcall) New function. (region_model::update_for_return_gcall): New function. (egion_model::update_for_call_superedge): Get the underlying gcall and update for gcall. (region_model::update_for_return_superedge): Likewise. * region-model.h (region_model::update_for_gcall): New decl. (region_model::update_for_return_gcall): New decl. * state-purge.cc (state_purge_per_ssa_name::process_point): Update to work with calls without underlying cgraph edge. * supergraph.cc (supergraph::supergraph) Split snodes at every callsite. * supergraph.h (supernode::get_returning_call) New accessor. gcc/testsuite/ChangeLog: PR analyzer/100546 * gcc.dg/analyzer/function-ptr-4.c: New test. * gcc.dg/analyzer/pr100546.c: New test. --- gcc/analyzer/analysis-plan.cc | 4 + gcc/analyzer/checker-path.cc | 28 ++-- gcc/analyzer/checker-path.h | 6 + gcc/analyzer/diagnostic-manager.cc | 23 +--- gcc/analyzer/engine.cc | 183 +++++++++++++++++++++++++ gcc/analyzer/exploded-graph.h | 39 ++++++ gcc/analyzer/program-point.cc | 18 +++ gcc/analyzer/program-point.h | 3 +- gcc/analyzer/program-state.cc | 44 ++++++ gcc/analyzer/program-state.h | 11 ++ gcc/analyzer/region-model.cc | 44 ++++-- gcc/analyzer/region-model.h | 6 + gcc/analyzer/state-purge.cc | 35 +++-- gcc/analyzer/supergraph.cc | 43 +++++- gcc/analyzer/supergraph.h | 7 +- gcc/testsuite/gcc.dg/analyzer/function-ptr-4.c | 24 ++++ gcc/testsuite/gcc.dg/analyzer/pr100546.c | 17 +++ 17 files changed, 481 insertions(+), 54 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/function-ptr-4.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr100546.c (limited to 'gcc') diff --git a/gcc/analyzer/analysis-plan.cc b/gcc/analyzer/analysis-plan.cc index 7dfc48e..57a6dcb 100644 --- a/gcc/analyzer/analysis-plan.cc +++ b/gcc/analyzer/analysis-plan.cc @@ -109,6 +109,10 @@ analysis_plan::use_summary_p (const cgraph_edge *edge) const if (!flag_analyzer_call_summaries) return false; + /* Don't use call summaries if there is no callgraph edge */ + if (!edge || !edge->callee) + return false; + /* TODO: don't count callsites each time. */ int num_call_sites = 0; const cgraph_node *callee = edge->callee; diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc index e10c8e2..e132f00 100644 --- a/gcc/analyzer/checker-path.cc +++ b/gcc/analyzer/checker-path.cc @@ -614,7 +614,11 @@ call_event::call_event (const exploded_edge &eedge, location_t loc, tree fndecl, int depth) : superedge_event (EK_CALL_EDGE, eedge, loc, fndecl, depth) { - gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL); + if (eedge.m_sedge) + gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL); + + m_src_snode = eedge.m_src->get_supernode (); + m_dest_snode = eedge.m_dest->get_supernode (); } /* Implementation of diagnostic_event::get_desc vfunc for @@ -638,8 +642,8 @@ call_event::get_desc (bool can_colorize) const label_text custom_desc = m_pending_diagnostic->describe_call_with_state (evdesc::call_with_state (can_colorize, - m_sedge->m_src->m_fun->decl, - m_sedge->m_dest->m_fun->decl, + m_src_snode->m_fun->decl, + m_dest_snode->m_fun->decl, var, m_critical_state)); if (custom_desc.m_buffer) @@ -648,8 +652,8 @@ call_event::get_desc (bool can_colorize) const return make_label_text (can_colorize, "calling %qE from %qE", - m_sedge->m_dest->m_fun->decl, - m_sedge->m_src->m_fun->decl); + m_dest_snode->m_fun->decl, + m_src_snode->m_fun->decl); } /* Override of checker_event::is_call_p for calls. */ @@ -668,7 +672,11 @@ return_event::return_event (const exploded_edge &eedge, location_t loc, tree fndecl, int depth) : superedge_event (EK_RETURN_EDGE, eedge, loc, fndecl, depth) { - gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN); + if (eedge.m_sedge) + gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN); + + m_src_snode = eedge.m_src->get_supernode (); + m_dest_snode = eedge.m_dest->get_supernode (); } /* Implementation of diagnostic_event::get_desc vfunc for @@ -694,16 +702,16 @@ return_event::get_desc (bool can_colorize) const label_text custom_desc = m_pending_diagnostic->describe_return_of_state (evdesc::return_of_state (can_colorize, - m_sedge->m_dest->m_fun->decl, - m_sedge->m_src->m_fun->decl, + m_dest_snode->m_fun->decl, + m_src_snode->m_fun->decl, m_critical_state)); if (custom_desc.m_buffer) return custom_desc; } return make_label_text (can_colorize, "returning to %qE from %qE", - m_sedge->m_dest->m_fun->decl, - m_sedge->m_src->m_fun->decl); + m_dest_snode->m_fun->decl, + m_src_snode->m_fun->decl); } /* Override of checker_event::is_return_p for returns. */ diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h index 1843c4b..27634c2 100644 --- a/gcc/analyzer/checker-path.h +++ b/gcc/analyzer/checker-path.h @@ -338,6 +338,9 @@ public: label_text get_desc (bool can_colorize) const FINAL OVERRIDE; bool is_call_p () const FINAL OVERRIDE; + + const supernode *m_src_snode; + const supernode *m_dest_snode; }; /* A concrete event subclass for an interprocedural return. */ @@ -351,6 +354,9 @@ public: label_text get_desc (bool can_colorize) const FINAL OVERRIDE; bool is_return_p () const FINAL OVERRIDE; + + const supernode *m_src_snode; + const supernode *m_dest_snode; }; /* A concrete event subclass for the start of a consolidated run of CFG diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index ef3df32..06e7510 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -2093,18 +2093,13 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, case EK_CALL_EDGE: { call_event *event = (call_event *)base_event; - const callgraph_superedge& cg_superedge - = event->get_callgraph_superedge (); const region_model *callee_model = event->m_eedge.m_dest->get_state ().m_region_model; + const region_model *caller_model + = event->m_eedge.m_src->get_state ().m_region_model; tree callee_var = callee_model->get_representative_tree (sval); - /* We could just use caller_model->get_representative_tree (sval); - to get the caller_var, but for now use - map_expr_from_callee_to_caller so as to only record critical - state for parms and the like. */ callsite_expr expr; - tree caller_var - = cg_superedge.map_expr_from_callee_to_caller (callee_var, &expr); + tree caller_var = caller_model->get_representative_tree (sval); if (caller_var) { if (get_logger ()) @@ -2126,15 +2121,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, if (sval) { return_event *event = (return_event *)base_event; - const callgraph_superedge& cg_superedge - = event->get_callgraph_superedge (); - const region_model *caller_model - = event->m_eedge.m_dest->get_state ().m_region_model; - tree caller_var = caller_model->get_representative_tree (sval); callsite_expr expr; - tree callee_var - = cg_superedge.map_expr_from_caller_to_callee (caller_var, - &expr); + + const region_model *callee_model + = event->m_eedge.m_src->get_state ().m_region_model; + tree callee_var = callee_model->get_representative_tree (sval); if (callee_var) { if (get_logger ()) diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index ecd4265..461de9c 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -1627,6 +1627,50 @@ exploded_node::dump_succs_and_preds (FILE *outf) const } } +/* class dynamic_call_info_t : public exploded_edge::custom_info_t. */ + +/* Implementation of exploded_edge::custom_info_t::update_model vfunc + for dynamic_call_info_t. + + Update state for the dynamically discorverd calls */ + +void +dynamic_call_info_t::update_model (region_model *model, + const exploded_edge &eedge) +{ + const program_state &dest_state = eedge.m_dest->get_state (); + *model = *dest_state.m_region_model; +} + +/* Implementation of exploded_edge::custom_info_t::add_events_to_path vfunc + for dynamic_call_info_t. */ + +void +dynamic_call_info_t::add_events_to_path (checker_path *emission_path, + const exploded_edge &eedge) +{ + const exploded_node *src_node = eedge.m_src; + const program_point &src_point = src_node->get_point (); + const int src_stack_depth = src_point.get_stack_depth (); + const exploded_node *dest_node = eedge.m_dest; + const program_point &dest_point = dest_node->get_point (); + const int dest_stack_depth = dest_point.get_stack_depth (); + + if (m_is_returning_call) + emission_path->add_event (new return_event (eedge, (m_dynamic_call + ? m_dynamic_call->location + : UNKNOWN_LOCATION), + dest_point.get_fndecl (), + dest_stack_depth)); + else + emission_path->add_event (new call_event (eedge, (m_dynamic_call + ? m_dynamic_call->location + : UNKNOWN_LOCATION), + src_point.get_fndecl (), + src_stack_depth)); + +} + /* class rewind_info_t : public exploded_edge::custom_info_t. */ /* Implementation of exploded_edge::custom_info_t::update_model vfunc @@ -2980,6 +3024,61 @@ state_change_requires_new_enode_p (const program_state &old_state, return false; } +/* Create enodes and eedges for the function calls that doesn't have an + underlying call superedge. + + Such case occurs when GCC's middle end didn't know which function to + call but the analyzer does (with the help of current state). + + Some example such calls are dynamically dispatched calls to virtual + functions or calls that happen via function pointer. */ + +void +exploded_graph::create_dynamic_call (const gcall *call, + tree fn_decl, + exploded_node *node, + program_state next_state, + program_point &next_point, + uncertainty_t *uncertainty, + logger *logger) +{ + LOG_FUNC (logger); + + const program_point *this_point = &node->get_point (); + function *fun = DECL_STRUCT_FUNCTION (fn_decl); + if (fun) + { + const supergraph &sg = this->get_supergraph (); + supernode * sn_entry = sg.get_node_for_function_entry (fun); + supernode * sn_exit = sg.get_node_for_function_exit (fun); + + program_point new_point + = program_point::before_supernode (sn_entry, + NULL, + this_point->get_call_string ()); + + new_point.push_to_call_stack (sn_exit, + next_point.get_supernode()); + next_state.push_call (*this, node, call, uncertainty); + + if (next_state.m_valid) + { + if (logger) + logger->log ("Discovered call to %s [SN: %i -> SN: %i]", + function_name(fun), + this_point->get_supernode ()->m_index, + sn_entry->m_index); + + exploded_node *enode = get_or_create_node (new_point, + next_state, + node); + if (enode) + add_edge (node,enode, NULL, + new dynamic_call_info_t (call)); + } + } +} + /* The core of exploded_graph::process_worklist (the main analysis loop), handling one node in the worklist. @@ -3174,10 +3273,13 @@ exploded_graph::process_node (exploded_node *node) break; case PK_AFTER_SUPERNODE: { + bool found_a_superedge = false; + bool is_an_exit_block = false; /* If this is an EXIT BB, detect leaks, and potentially create a function summary. */ if (point.get_supernode ()->return_p ()) { + is_an_exit_block = true; node->detect_leaks (*this); if (flag_analyzer_call_summaries && point.get_call_string ().empty_p ()) @@ -3205,6 +3307,7 @@ exploded_graph::process_node (exploded_node *node) superedge *succ; FOR_EACH_VEC_ELT (point.get_supernode ()->m_succs, i, succ) { + found_a_superedge = true; if (logger) logger->log ("considering SN: %i -> SN: %i", succ->m_src->m_index, succ->m_dest->m_index); @@ -3214,6 +3317,54 @@ exploded_graph::process_node (exploded_node *node) point.get_call_string ()); program_state next_state (state); uncertainty_t uncertainty; + + /* Make use the current state and try to discover and analyse + indirect function calls (a call that doesn't have an underlying + cgraph edge representing call). + + Some examples of such calls are virtual function calls + and calls that happen via a function pointer. */ + if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL + && !(succ->get_any_callgraph_edge ())) + { + const gcall *call + = point.get_supernode ()->get_final_call (); + + impl_region_model_context ctxt (*this, + node, + &state, + &next_state, + &uncertainty, + point.get_stmt()); + + region_model *model = state.m_region_model; + + if (tree fn_decl = model->get_fndecl_for_call(call,&ctxt)) + create_dynamic_call (call, + fn_decl, + node, + next_state, + next_point, + &uncertainty, + logger); + else + { + /* An unknown function was called at this point, in such + case, don't terminate the analysis of the current + function. + + The analyzer handles calls to unknown functions while + analysing the stmt itself, so the the function call + must have been handled by the anlyzer till now. */ + exploded_node *next + = get_or_create_node (next_point, + next_state, + node); + if (next) + add_edge (node, next, succ); + } + } + if (!node->on_edge (*this, succ, &next_point, &next_state, &uncertainty)) { @@ -3227,6 +3378,38 @@ exploded_graph::process_node (exploded_node *node) if (next) add_edge (node, next, succ); } + + /* Return from the calls which doesn't have a return superedge. + Such case occurs when GCC's middle end didn't knew which function to + call but analyzer did. */ + if((is_an_exit_block && !found_a_superedge) + && (!point.get_call_string ().empty_p ())) + { + const call_string cs = point.get_call_string (); + program_point next_point + = program_point::before_supernode (cs.get_caller_node (), + NULL, + cs); + program_state next_state (state); + uncertainty_t uncertainty; + + const gcall *call + = next_point.get_supernode ()->get_returning_call (); + + if(call) + next_state.returning_call (*this, node, call, &uncertainty); + + if (next_state.m_valid) + { + next_point.pop_from_call_stack (); + exploded_node *enode = get_or_create_node (next_point, + next_state, + node); + if (enode) + add_edge (node, enode, NULL, + new dynamic_call_info_t (call, true)); + } + } } break; } diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index 8f48d8a..192a4b3 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -362,6 +362,37 @@ private: DISABLE_COPY_AND_ASSIGN (exploded_edge); }; +/* Extra data for an exploded_edge that represents dynamic call info ( calls + that doesn't have an underlying superedge representing the call ). */ + +class dynamic_call_info_t : public exploded_edge::custom_info_t +{ +public: + dynamic_call_info_t (const gcall *dynamic_call, + const bool is_returning_call = false) + : m_dynamic_call (dynamic_call), + m_is_returning_call (is_returning_call) + {} + + void print (pretty_printer *pp) FINAL OVERRIDE + { + if (m_is_returning_call) + pp_string (pp, "dynamic_return"); + else + pp_string (pp, "dynamic_call"); + } + + void update_model (region_model *model, + const exploded_edge &eedge) FINAL OVERRIDE; + + void add_events_to_path (checker_path *emission_path, + const exploded_edge &eedge) FINAL OVERRIDE; +private: + const gcall *m_dynamic_call; + const bool m_is_returning_call; +}; + + /* Extra data for an exploded_edge that represents a rewind from a longjmp to a setjmp (or from a siglongjmp to a sigsetjmp). */ @@ -785,6 +816,14 @@ public: bool maybe_process_run_of_before_supernode_enodes (exploded_node *node); void process_node (exploded_node *node); + void create_dynamic_call (const gcall *call, + tree fn_decl, + exploded_node *node, + program_state next_state, + program_point &next_point, + uncertainty_t *uncertainty, + logger *logger); + exploded_node *get_or_create_node (const program_point &point, const program_state &state, exploded_node *enode_for_diag); diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc index d9f50da..25d56af 100644 --- a/gcc/analyzer/program-point.cc +++ b/gcc/analyzer/program-point.cc @@ -330,6 +330,24 @@ program_point::to_json () const return point_obj; } +/* Update the callstack to represent a call from caller to callee. + + Generally used to push a custom call to a perticular program point + where we don't have a superedge representing the call. */ +void +program_point::push_to_call_stack (const supernode *caller, + const supernode *callee) +{ + m_call_string.push_call (callee, caller); +} + +/* Pop the topmost call from the current callstack. */ +void +program_point::pop_from_call_stack () +{ + m_call_string.pop (); +} + /* Generate a hash value for this program_point. */ hashval_t diff --git a/gcc/analyzer/program-point.h b/gcc/analyzer/program-point.h index 5f86745..6bae29b 100644 --- a/gcc/analyzer/program-point.h +++ b/gcc/analyzer/program-point.h @@ -293,7 +293,8 @@ public: } bool on_edge (exploded_graph &eg, const superedge *succ); - + void push_to_call_stack (const supernode *caller, const supernode *callee); + void pop_from_call_stack (); void validate () const; /* For before_stmt, go to next stmt. */ diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index 5bb8676..ea53c61 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -1034,6 +1034,50 @@ program_state::on_edge (exploded_graph &eg, return true; } +/* Update this program_state to reflect a call to function + represented by CALL_STMT. + currently used only when the call doesn't have a superedge representing + the call ( like call via a function pointer ) */ +void +program_state::push_call (exploded_graph &eg, + exploded_node *enode, + const gcall *call_stmt, + uncertainty_t *uncertainty) +{ + /* Update state. */ + const program_point &point = enode->get_point (); + const gimple *last_stmt = point.get_supernode ()->get_last_stmt (); + + impl_region_model_context ctxt (eg, enode, + &enode->get_state (), + this, + uncertainty, + last_stmt); + m_region_model->update_for_gcall (call_stmt, &ctxt); +} + +/* Update this program_state to reflect a return from function + call to which is represented by CALL_STMT. + currently used only when the call doesn't have a superedge representing + the return */ +void +program_state::returning_call (exploded_graph &eg, + exploded_node *enode, + const gcall *call_stmt, + uncertainty_t *uncertainty) +{ + /* Update state. */ + const program_point &point = enode->get_point (); + const gimple *last_stmt = point.get_supernode ()->get_last_stmt (); + + impl_region_model_context ctxt (eg, enode, + &enode->get_state (), + this, + uncertainty, + last_stmt); + m_region_model->update_for_return_gcall (call_stmt, &ctxt); +} + /* Generate a simpler version of THIS, discarding state that's no longer relevant at POINT. The idea is that we're more likely to be able to consolidate diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index 8dee930..eb49006 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -218,6 +218,17 @@ public: void push_frame (const extrinsic_state &ext_state, function *fun); function * get_current_function () const; + void push_call (exploded_graph &eg, + exploded_node *enode, + const gcall *call_stmt, + uncertainty_t *uncertainty); + + void returning_call (exploded_graph &eg, + exploded_node *enode, + const gcall *call_stmt, + uncertainty_t *uncertainty); + + bool on_edge (exploded_graph &eg, exploded_node *enode, const superedge *succ, diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 58da7e3..2316fbe 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -3172,12 +3172,11 @@ region_model::maybe_update_for_edge (const superedge &edge, caller's frame. */ void -region_model::update_for_call_superedge (const call_superedge &call_edge, - region_model_context *ctxt) +region_model::update_for_gcall (const gcall *call_stmt, + region_model_context *ctxt) { /* Build a vec of argument svalues, using the current top frame for resolving tree expressions. */ - const gcall *call_stmt = call_edge.get_call_stmt (); auto_vec arg_svals (gimple_call_num_args (call_stmt)); for (unsigned i = 0; i < gimple_call_num_args (call_stmt); i++) @@ -3186,33 +3185,58 @@ region_model::update_for_call_superedge (const call_superedge &call_edge, arg_svals.quick_push (get_rvalue (arg, ctxt)); } - push_frame (call_edge.get_callee_function (), &arg_svals, ctxt); + /* Get the function * from the call. */ + tree fn_decl = get_fndecl_for_call (call_stmt,ctxt); + function *fun = DECL_STRUCT_FUNCTION (fn_decl); + push_frame (fun, &arg_svals, ctxt); } /* Pop the top-most frame_region from the stack, and copy the return region's values (if any) into the region for the lvalue of the LHS of the call (if any). */ + void -region_model::update_for_return_superedge (const return_superedge &return_edge, - region_model_context *ctxt) +region_model::update_for_return_gcall (const gcall *call_stmt, + region_model_context *ctxt) { /* Get the region for the result of the call, within the caller frame. */ const region *result_dst_reg = NULL; - const gcall *call_stmt = return_edge.get_call_stmt (); tree lhs = gimple_call_lhs (call_stmt); if (lhs) { /* Normally we access the top-level frame, which is: - path_var (expr, get_stack_depth () - 1) - whereas here we need the caller frame, hence "- 2" here. */ + path_var (expr, get_stack_depth () - 1) + whereas here we need the caller frame, hence "- 2" here. */ gcc_assert (get_stack_depth () >= 2); result_dst_reg = get_lvalue (path_var (lhs, get_stack_depth () - 2), - ctxt); + ctxt); } pop_frame (result_dst_reg, NULL, ctxt); } +/* Extract calling information from the superedge and update the model for the + call */ + +void +region_model::update_for_call_superedge (const call_superedge &call_edge, + region_model_context *ctxt) +{ + const gcall *call_stmt = call_edge.get_call_stmt (); + update_for_gcall (call_stmt,ctxt); +} + +/* Extract calling information from the return superedge and update the model + for the returning call */ + +void +region_model::update_for_return_superedge (const return_superedge &return_edge, + region_model_context *ctxt) +{ + const gcall *call_stmt = return_edge.get_call_stmt (); + update_for_return_gcall (call_stmt, ctxt); +} + /* Update this region_model with a summary of the effect of calling and returning from CG_SEDGE. diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 30f02a0..e40264e 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -608,6 +608,12 @@ class region_model region_model_context *ctxt, rejected_constraint **out); + void update_for_gcall (const gcall *call_stmt, + region_model_context *ctxt); + + void update_for_return_gcall (const gcall *call_stmt, + region_model_context *ctxt); + const region *push_frame (function *fun, const vec *arg_sids, region_model_context *ctxt); const frame_region *get_current_frame () const { return m_current_frame; } diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc index bfa48a9..8800570 100644 --- a/gcc/analyzer/state-purge.cc +++ b/gcc/analyzer/state-purge.cc @@ -383,18 +383,31 @@ state_purge_per_ssa_name::process_point (const function_point &point, { /* Add any intraprocedually edge for a call. */ if (snode->m_returning_call) - { - cgraph_edge *cedge + { + gcall *returning_call = snode->m_returning_call; + cgraph_edge *cedge = supergraph_call_edge (snode->m_fun, - snode->m_returning_call); - gcc_assert (cedge); - superedge *sedge - = map.get_sg ().get_intraprocedural_edge_for_call (cedge); - gcc_assert (sedge); - add_to_worklist - (function_point::after_supernode (sedge->m_src), - worklist, logger); - } + returning_call); + if(cedge) + { + superedge *sedge + = map.get_sg ().get_intraprocedural_edge_for_call (cedge); + gcc_assert (sedge); + add_to_worklist + (function_point::after_supernode (sedge->m_src), + worklist, logger); + } + else + { + supernode *callernode + = map.get_sg ().get_supernode_for_stmt (returning_call); + + gcc_assert (callernode); + add_to_worklist + (function_point::after_supernode (callernode), + worklist, logger); + } + } } } break; diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index 1eb2543..66ef765 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -183,11 +183,33 @@ supergraph::supergraph (logger *logger) m_stmt_to_node_t.put (stmt, node_for_stmts); m_stmt_uids.make_uid_unique (stmt); if (cgraph_edge *edge = supergraph_call_edge (fun, stmt)) - { - m_cgraph_edge_to_caller_prev_node.put(edge, node_for_stmts); - node_for_stmts = add_node (fun, bb, as_a (stmt), NULL); - m_cgraph_edge_to_caller_next_node.put (edge, node_for_stmts); - } + { + m_cgraph_edge_to_caller_prev_node.put(edge, node_for_stmts); + node_for_stmts = add_node (fun, bb, as_a (stmt), + NULL); + m_cgraph_edge_to_caller_next_node.put (edge, node_for_stmts); + } + else + { + // maybe call is via a function pointer + if (gcall *call = dyn_cast (stmt)) + { + cgraph_edge *edge + = cgraph_node::get (fun->decl)->get_edge (stmt); + if (!edge || !edge->callee) + { + supernode *old_node_for_stmts = node_for_stmts; + node_for_stmts = add_node (fun, bb, call, NULL); + + superedge *sedge + = new callgraph_superedge (old_node_for_stmts, + node_for_stmts, + SUPEREDGE_INTRAPROCEDURAL_CALL, + NULL); + add_edge (sedge); + } + } + } } m_bb_to_final_node.put (bb, node_for_stmts); @@ -1139,6 +1161,17 @@ callgraph_superedge::get_callee_decl () const return get_callee_function ()->decl; } +/* Get the gcall * of this interprocedural call/return edge. */ + +gcall * +callgraph_superedge::get_call_stmt () const +{ + if (m_cedge) + return m_cedge->call_stmt; + + return m_src->get_final_call (); +} + /* Get the calling fndecl at this interprocedural call/return edge. */ tree diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h index 877958f..335f513 100644 --- a/gcc/analyzer/supergraph.h +++ b/gcc/analyzer/supergraph.h @@ -268,6 +268,11 @@ class supernode : public dnode return i; } + gcall *get_returning_call () const + { + return m_returning_call; + } + gimple *get_last_stmt () const { if (m_stmts.length () == 0) @@ -400,7 +405,7 @@ class callgraph_superedge : public superedge function *get_caller_function () const; tree get_callee_decl () const; tree get_caller_decl () const; - gcall *get_call_stmt () const { return m_cedge->call_stmt; } + gcall *get_call_stmt () const; tree get_arg_for_parm (tree parm, callsite_expr *out) const; tree get_parm_for_arg (tree arg, callsite_expr *out) const; tree map_expr_from_caller_to_callee (tree caller_expr, diff --git a/gcc/testsuite/gcc.dg/analyzer/function-ptr-4.c b/gcc/testsuite/gcc.dg/analyzer/function-ptr-4.c new file mode 100644 index 0000000..016351a --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/function-ptr-4.c @@ -0,0 +1,24 @@ +/* Test to see if the analyzer detect and analyze calls via + function pointers or not. */ + +#include + +void fun(int *int_ptr) +{ + free(int_ptr); /* { dg-warning "double-'free' of 'int_ptr'" } */ +} + +void single_call() +{ + int *int_ptr = (int*)malloc(sizeof(int)); + void (*fun_ptr)(int *) = &fun; + (*fun_ptr)(int_ptr); +} + +void double_call() +{ + int *int_ptr = (int*)malloc(sizeof(int)); + void (*fun_ptr)(int *) = &fun; + (*fun_ptr)(int_ptr); /* { dg-message "calling 'fun' from 'double_call'" } */ + (*fun_ptr)(int_ptr); +} diff --git a/gcc/testsuite/gcc.dg/analyzer/pr100546.c b/gcc/testsuite/gcc.dg/analyzer/pr100546.c new file mode 100644 index 0000000..3349d40 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/pr100546.c @@ -0,0 +1,17 @@ +#include +#include + +static void noReturn(const char *str) __attribute__((noreturn)); +static void noReturn(const char *str) { + printf("%s\n", str); + exit(1); +} + +void (*noReturnPtr)(const char *str) = &noReturn; + +int main(int argc, char **argv) { + char *str = 0; + if (!str) + noReturnPtr(__FILE__); + return printf("%c\n", *str); +} -- cgit v1.1 From 1b34248527472496ca3fe2a07183beac8cf69041 Mon Sep 17 00:00:00 2001 From: Ankur Saini Date: Sun, 15 Aug 2021 19:19:07 +0530 Subject: analyzer: detect and analyze virtual function calls 2021-08-15 Ankur Saini gcc/analyzer/ChangeLog: PR analyzer/97114 * region-model.cc (region_model::get_rvalue_1): Add case for OBJ_TYPE_REF. gcc/testsuite/ChangeLog: PR analyzer/97114 * g++.dg/analyzer/vfunc-2.C: New test. * g++.dg/analyzer/vfunc-3.C: New test. * g++.dg/analyzer/vfunc-4.C: New test. * g++.dg/analyzer/vfunc-5.C: New test. --- gcc/analyzer/region-model.cc | 5 ++ gcc/testsuite/g++.dg/analyzer/vfunc-2.C | 44 ++++++++++++++ gcc/testsuite/g++.dg/analyzer/vfunc-3.C | 32 ++++++++++ gcc/testsuite/g++.dg/analyzer/vfunc-4.C | 28 +++++++++ gcc/testsuite/g++.dg/analyzer/vfunc-5.C | 103 ++++++++++++++++++++++++++++++++ 5 files changed, 212 insertions(+) create mode 100644 gcc/testsuite/g++.dg/analyzer/vfunc-2.C create mode 100644 gcc/testsuite/g++.dg/analyzer/vfunc-3.C create mode 100644 gcc/testsuite/g++.dg/analyzer/vfunc-4.C create mode 100644 gcc/testsuite/g++.dg/analyzer/vfunc-5.C (limited to 'gcc') diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 2316fbe..822e893 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -1841,6 +1841,11 @@ region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt) const const region *ref_reg = get_lvalue (pv, ctxt); return get_store_value (ref_reg, ctxt); } + case OBJ_TYPE_REF: + { + tree expr = OBJ_TYPE_REF_EXPR (pv.m_tree); + return get_rvalue (expr, ctxt); + } } } diff --git a/gcc/testsuite/g++.dg/analyzer/vfunc-2.C b/gcc/testsuite/g++.dg/analyzer/vfunc-2.C new file mode 100644 index 0000000..46b68e5 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/vfunc-2.C @@ -0,0 +1,44 @@ +#include +#include + +struct A +{ + int m_data; + A() {m_data = 0;} + virtual int deallocate (void) + { + return 42; + } +}; + +struct B: public A +{ + int *ptr; + int m_data_b; + B() {m_data_b = 0;} + void allocate () + { + ptr = (int*)malloc(sizeof(int)); + } + int deallocate (void) + { + free(ptr); + return 0; + } +}; + +void foo(A *a_ptr) +{ + printf("%d\n",a_ptr->deallocate()); +} + +void test() +{ + B b; + A a, *aptr; + aptr = &b; + b.allocate(); + foo(aptr); + aptr = &a; + foo(aptr); +} diff --git a/gcc/testsuite/g++.dg/analyzer/vfunc-3.C b/gcc/testsuite/g++.dg/analyzer/vfunc-3.C new file mode 100644 index 0000000..03d3cdc --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/vfunc-3.C @@ -0,0 +1,32 @@ +#include + +struct A +{ + virtual int foo (void) + { + return 42; + } +}; + +struct B: public A +{ + int *ptr; + void alloc () + { + ptr = (int*)malloc(sizeof(int)); + } + int foo (void) + { + free(ptr); /* { dg-warning "double-'free' of 'b.B::ptr'" } */ + return 0; + } +}; + +int test () +{ + struct B b, *bptr=&b; + b.alloc (); + bptr->foo (); /* { dg-message "\\(6\\) calling 'B::foo' from 'test'" "event 6" } */ + /* { dg-message "\\(9\\) returning to 'test' from 'B::foo'" "event 9" { target *-*-* } .-1 } */ + return bptr->foo (); +} diff --git a/gcc/testsuite/g++.dg/analyzer/vfunc-4.C b/gcc/testsuite/g++.dg/analyzer/vfunc-4.C new file mode 100644 index 0000000..9751084 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/vfunc-4.C @@ -0,0 +1,28 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct A +{ + int m_data; + virtual char foo () + { + return 'A'; + } +}; + +struct B: public A +{ + int m_data_b; + char foo () + { + return 'B'; + } +}; + +void test() +{ + A a, *a_ptr = &a; + B b; + __analyzer_eval (a_ptr->foo () == 'A'); /* { dg-warning "TRUE" } */ + a_ptr = &b; + __analyzer_eval (a_ptr->foo () == 'B'); /* { dg-warning "TRUE" } */ +} diff --git a/gcc/testsuite/g++.dg/analyzer/vfunc-5.C b/gcc/testsuite/g++.dg/analyzer/vfunc-5.C new file mode 100644 index 0000000..2af8465 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/vfunc-5.C @@ -0,0 +1,103 @@ +/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fanalyzer-checker=malloc -fdiagnostics-show-caret" } */ +/* { dg-enable-nn-line-numbers "" } */ + +#include + +struct Base +{ + virtual void allocate (); + virtual void deallocate (); +}; + +struct Derived: public Base +{ + int *ptr; + void allocate () + { + ptr = (int*)malloc(sizeof(int)); + } + void deallocate () + { + free(ptr); + } +}; + +void test() +{ + Derived D; + Base B, *base_ptr; + base_ptr = &D; + + D.allocate(); + base_ptr->deallocate(); + int n = *D.ptr; /* { dg-warning "use after 'free' of 'D.Derived::ptr'" } */ +} + +/* use after 'free' */ +/* { dg-begin-multiline-output "" } + NN | int n = *D.ptr; + | ^ + 'void test()': events 1-2 + | + | NN | void test() + | | ^~~~ + | | | + | | (1) entry to 'test' + |...... + | NN | D.allocate(); + | | ~~~~~~~~~~~~ + | | | + | | (2) calling 'Derived::allocate' from 'test' + | + +--> 'virtual void Derived::allocate()': events 3-4 + | + | NN | void allocate () + | | ^~~~~~~~ + | | | + | | (3) entry to 'Derived::allocate' + | NN | { + | NN | ptr = (int*)malloc(sizeof(int)); + | | ~~~~~~~~~~~~~~~~~~~ + | | | + | | (4) allocated here + | + <------+ + | + 'void test()': events 5-6 + | + | NN | D.allocate(); + | | ~~~~~~~~~~^~ + | | | + | | (5) returning to 'test' from 'Derived::allocate' + | NN | base_ptr->deallocate(); + | | ~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (6) calling 'Derived::deallocate' from 'test' + | + +--> 'virtual void Derived::deallocate()': events 7-8 + | + | NN | void deallocate () + | | ^~~~~~~~~~ + | | | + | | (7) entry to 'Derived::deallocate' + | NN | { + | NN | free(ptr); + | | ~~~~~~~~~ + | | | + | | (8) freed here + | + <------+ + | + 'void test()': events 9-10 + | + | NN | base_ptr->deallocate(); + | | ~~~~~~~~~~~~~~~~~~~~^~ + | | | + | | (9) returning to 'test' from 'Derived::deallocate' + | NN | int n = *D.ptr; + | | ~ + | | | + | | (10) use after 'free' of 'D.Derived::ptr'; freed at (8) + | + { dg-end-multiline-output "" } */ + -- cgit v1.1 From 15bdae016654f63a36e49a37c9d26282bebb1da9 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sun, 28 Mar 2021 14:48:17 +0100 Subject: Darwin: Handle the -rpath command line option. This handles the command line '-rpath' option by passing it through to the static linker. Signed-off-by: Iain Sandoe gcc/ChangeLog: * config.gcc: Include rpath.opt for Darwin. * config/darwin.h (DRIVER_SELF_SPECS): Handle -rpath. --- gcc/config.gcc | 2 +- gcc/config/darwin.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config.gcc b/gcc/config.gcc index d9bfbfd..eb232df 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -700,7 +700,7 @@ case ${target} in tm_file="${tm_file} ${cpu_type}/darwin.h" tm_p_file="${tm_p_file} darwin-protos.h" target_gtfiles="$target_gtfiles \$(srcdir)/config/darwin.c" - extra_options="${extra_options} darwin.opt" + extra_options="${extra_options} rpath.opt darwin.opt" c_target_objs="${c_target_objs} darwin-c.o" cxx_target_objs="${cxx_target_objs} darwin-c.o" d_target_objs="${d_target_objs} darwin-d.o" diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index 20d6b1e..b1be561 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -132,6 +132,7 @@ extern GTY(()) int darwin_ms_struct; "%{gsplit-dwarf:%ngsplit-dwarf is not supported on this platform} \ % Date: Sat, 14 Aug 2021 12:27:55 +0100 Subject: Objective-C: fix crash with -fobjc-nilcheck When -fobjc-nilcheck is enabled, messages that result in a struct type should yield a zero-initialized struct when sent to nil. Currently, the frontend crashes when it encounters this situation. This patch fixes the crash by generating the tree for the `{}` initializer. Signed-off-by: Iain Sandoe Co-authored-by: Matt Jacobson PR objc/101666 gcc/objc/ChangeLog: * objc-act.c (objc_build_constructor): Handle empty constructor lists. * objc-next-runtime-abi-02.c (build_v2_objc_method_fixup_call): Handle nil receivers. (build_v2_build_objc_method_call): Likewise. gcc/testsuite/ChangeLog: * obj-c++.dg/pr101666-0.mm: New test. * obj-c++.dg/pr101666-1.mm: New test. * obj-c++.dg/pr101666.inc: New. * objc.dg/pr101666-0.m: New test. * objc.dg/pr101666-1.m: New test. * objc.dg/pr101666.inc: New. --- gcc/objc/objc-act.c | 16 +++++++++------- gcc/objc/objc-next-runtime-abi-02.c | 22 +++++++--------------- gcc/testsuite/obj-c++.dg/pr101666-0.mm | 7 +++++++ gcc/testsuite/obj-c++.dg/pr101666-1.mm | 10 ++++++++++ gcc/testsuite/obj-c++.dg/pr101666.inc | 29 +++++++++++++++++++++++++++++ gcc/testsuite/objc.dg/pr101666-0.m | 7 +++++++ gcc/testsuite/objc.dg/pr101666-1.m | 10 ++++++++++ gcc/testsuite/objc.dg/pr101666.inc | 29 +++++++++++++++++++++++++++++ 8 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/obj-c++.dg/pr101666-0.mm create mode 100644 gcc/testsuite/obj-c++.dg/pr101666-1.mm create mode 100644 gcc/testsuite/obj-c++.dg/pr101666.inc create mode 100644 gcc/testsuite/objc.dg/pr101666-0.m create mode 100644 gcc/testsuite/objc.dg/pr101666-1.m create mode 100644 gcc/testsuite/objc.dg/pr101666.inc (limited to 'gcc') diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index ec20891..6e4fb62 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -3377,8 +3377,10 @@ objc_build_string_object (tree string) return addr; } -/* Build a static constant CONSTRUCTOR - with type TYPE and elements ELTS. */ +/* Build a static constant CONSTRUCTOR with type TYPE and elements ELTS. + We might be presented with a NULL for ELTS, which means 'empty ctor' + which will subsequently be converted into a zero initializer in the + middle end. */ tree objc_build_constructor (tree type, vec *elts) @@ -3390,12 +3392,10 @@ objc_build_constructor (tree type, vec *elts) TREE_READONLY (constructor) = 1; #ifdef OBJCPLUS - /* Adjust for impedance mismatch. We should figure out how to build - CONSTRUCTORs that consistently please both the C and C++ gods. */ - if (!(*elts)[0].index) + /* If we know the initializer, then set the type to what C++ expects. */ + if (elts && !(*elts)[0].index) TREE_TYPE (constructor) = init_list_type_node; #endif - return constructor; } @@ -9664,7 +9664,9 @@ objc_gimplify_property_ref (tree *expr_p) call_exp = TREE_OPERAND (getter, 1); } #endif - gcc_assert (TREE_CODE (call_exp) == CALL_EXPR); + gcc_checking_assert ((flag_objc_nilcheck + && TREE_CODE (call_exp) == COND_EXPR) + || TREE_CODE (call_exp) == CALL_EXPR); *expr_p = call_exp; } diff --git a/gcc/objc/objc-next-runtime-abi-02.c b/gcc/objc/objc-next-runtime-abi-02.c index c552013..0d963e3 100644 --- a/gcc/objc/objc-next-runtime-abi-02.c +++ b/gcc/objc/objc-next-runtime-abi-02.c @@ -1675,13 +1675,8 @@ build_v2_objc_method_fixup_call (int super_flag, tree method_prototype, if (TREE_CODE (ret_type) == RECORD_TYPE || TREE_CODE (ret_type) == UNION_TYPE) - { - vec *rtt = NULL; - /* ??? CHECKME. hmmm..... think we need something more - here. */ - CONSTRUCTOR_APPEND_ELT (rtt, NULL_TREE, NULL_TREE); - ftree = objc_build_constructor (ret_type, rtt); - } + /* An empty constructor is zero-filled by the middle end. */ + ftree = objc_build_constructor (ret_type, NULL); else ftree = fold_convert (ret_type, integer_zero_node); @@ -1694,11 +1689,11 @@ build_v2_objc_method_fixup_call (int super_flag, tree method_prototype, ifexp, ret_val, ftree, tf_warning_or_error); #else - /* ??? CHECKME. */ ret_val = build_conditional_expr (input_location, - ifexp, 1, + ifexp, 0, ret_val, NULL_TREE, input_location, ftree, NULL_TREE, input_location); + ret_val = fold_convert (ret_type, ret_val); #endif } return ret_val; @@ -1790,11 +1785,8 @@ build_v2_build_objc_method_call (int super, tree method_prototype, if (TREE_CODE (ret_type) == RECORD_TYPE || TREE_CODE (ret_type) == UNION_TYPE) { - vec *rtt = NULL; - /* ??? CHECKME. hmmm..... think we need something more - here. */ - CONSTRUCTOR_APPEND_ELT (rtt, NULL_TREE, NULL_TREE); - ftree = objc_build_constructor (ret_type, rtt); + /* An empty constructor is zero-filled by the middle end. */ + ftree = objc_build_constructor (ret_type, NULL); } else ftree = fold_convert (ret_type, integer_zero_node); @@ -1807,10 +1799,10 @@ build_v2_build_objc_method_call (int super, tree method_prototype, ret_val = build_conditional_expr (loc, ifexp, ret_val, ftree, tf_warning_or_error); #else - /* ??? CHECKME. */ ret_val = build_conditional_expr (loc, ifexp, 1, ret_val, NULL_TREE, loc, ftree, NULL_TREE, loc); + ret_val = fold_convert (ret_type, ret_val); #endif } return ret_val; diff --git a/gcc/testsuite/obj-c++.dg/pr101666-0.mm b/gcc/testsuite/obj-c++.dg/pr101666-0.mm new file mode 100644 index 0000000..5f87f60 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/pr101666-0.mm @@ -0,0 +1,7 @@ +/* { dg-do run } */ +/* { dg-skip-if "NeXT only" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-skip-if "ABI 2 only" { *-*-* && { ! objc2 } } { "*" } { "" } } */ +/* { dg-additional-options "-fobjc-nilcheck -Wno-objc-root-class" } */ + +#include "pr101666.inc" + diff --git a/gcc/testsuite/obj-c++.dg/pr101666-1.mm b/gcc/testsuite/obj-c++.dg/pr101666-1.mm new file mode 100644 index 0000000..41ef370 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/pr101666-1.mm @@ -0,0 +1,10 @@ +/* Later versions of Darwin can compile for 10.5, but cannot link it so we + can only run this test up to 10.13. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-do run { target *-*-darwin[89]* *-*-darwin1[0-7]* } } */ +/* { dg-skip-if "NeXT only" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-skip-if "ABI 2 only" { *-*-* && { ! objc2 } } { "*" } { "" } } */ +/* { dg-additional-options "-fobjc-nilcheck -mmacosx-version-min=10.5 " } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ + +#include "pr101666.inc" diff --git a/gcc/testsuite/obj-c++.dg/pr101666.inc b/gcc/testsuite/obj-c++.dg/pr101666.inc new file mode 100644 index 0000000..e81e1be --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/pr101666.inc @@ -0,0 +1,29 @@ +#include +struct point { double x, y, z; }; + +@interface Foo +- (struct point)bar; +- (struct point)baz; +@end + +@implementation Foo +- (struct point)bar { struct point q = { 1.0, 2.0, 3.0 }; return q; }; +- (struct point)baz { struct point q = { 4.0, 5.0, 6.0 }; return q; }; +@end + +/* Cases where a check for nil should be inserted by the compiler, when + -fobjc-nilcheck is in force. We should not attempt the calls, and the + result should be 0-filled. */ + +Foo *f; + +int main(void) { + struct point p = [f bar]; + if (p.x != 0.0 || p.y != 0.0 || p.z != 0.0) + abort (); + id nilobj = (id)0; + p = [nilobj baz]; + if (p.x != 0.0 || p.y != 0.0 || p.z != 0.0) + abort (); + return 0; +} diff --git a/gcc/testsuite/objc.dg/pr101666-0.m b/gcc/testsuite/objc.dg/pr101666-0.m new file mode 100644 index 0000000..5f87f60 --- /dev/null +++ b/gcc/testsuite/objc.dg/pr101666-0.m @@ -0,0 +1,7 @@ +/* { dg-do run } */ +/* { dg-skip-if "NeXT only" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-skip-if "ABI 2 only" { *-*-* && { ! objc2 } } { "*" } { "" } } */ +/* { dg-additional-options "-fobjc-nilcheck -Wno-objc-root-class" } */ + +#include "pr101666.inc" + diff --git a/gcc/testsuite/objc.dg/pr101666-1.m b/gcc/testsuite/objc.dg/pr101666-1.m new file mode 100644 index 0000000..41ef370 --- /dev/null +++ b/gcc/testsuite/objc.dg/pr101666-1.m @@ -0,0 +1,10 @@ +/* Later versions of Darwin can compile for 10.5, but cannot link it so we + can only run this test up to 10.13. */ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-do run { target *-*-darwin[89]* *-*-darwin1[0-7]* } } */ +/* { dg-skip-if "NeXT only" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-skip-if "ABI 2 only" { *-*-* && { ! objc2 } } { "*" } { "" } } */ +/* { dg-additional-options "-fobjc-nilcheck -mmacosx-version-min=10.5 " } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ + +#include "pr101666.inc" diff --git a/gcc/testsuite/objc.dg/pr101666.inc b/gcc/testsuite/objc.dg/pr101666.inc new file mode 100644 index 0000000..f1dddca --- /dev/null +++ b/gcc/testsuite/objc.dg/pr101666.inc @@ -0,0 +1,29 @@ +#include +struct point { double x, y, z; }; + +@interface Foo +- (struct point)bar; +- (struct point)baz; +@end + +@implementation Foo +- (struct point)bar { struct point q = { 1.0, 2.0, 3.0 }; return q; }; +- (struct point)baz { struct point q = { 4.0, 5.0, 6.0 }; return q; }; +@end + +/* Cases where a check for nil should be inserted by the compiler, when + -fobjc-nilcheck is in force. We should not attempt the calls, and the + result should be 0-filled. */ + +Foo *f; + +int main(void) { + struct point p = [f bar]; + if (p.x != 0.0 || p.y != 0.0 || p.z != 0.0) + abort (); + id nilobj = (id)0; + p = [nilobj baz]; + if (p.x != 0.0 || p.y != 0.0 || p.z != 0.0) + abort (); + return 0; +} -- cgit v1.1 From 08defd9c4e4f8dc428f2f490705ab816af81a03d Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Thu, 5 Aug 2021 09:55:19 +0100 Subject: Darwin, jit: Fix build [PR100613]. The generic unix build is not completely suitable for Darwin platforms: * It is a convention to encode the library versioning in the binary and to have only one level of symlink for the installed files. This needs to be applied to the installation too. * The library needs to be built with its correct install name so that two-level library naming works. * The extension for shared libraries should be .dylib Signed-off-by: Iain Sandoe PR jit/100613 - libgccjit should produce dylib on macOS PR jit/100613 gcc/jit/ChangeLog: * Make-lang.in: Provide clauses for Darwin hosts. --- gcc/jit/Make-lang.in | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in index 663772a..2a774d7 100644 --- a/gcc/jit/Make-lang.in +++ b/gcc/jit/Make-lang.in @@ -53,8 +53,40 @@ jit: $(LIBGCCJIT_FILENAME) \ else -LIBGCCJIT_LINKER_NAME = libgccjit.so +ifneq (,$(findstring darwin,$(host))) + +LIBGCCJIT_AGE = 1 +LIBGCCJIT_BASENAME = libgccjit + +LIBGCCJIT_SONAME = \ + ${libdir}/$(LIBGCCJIT_BASENAME).$(LIBGCCJIT_VERSION_NUM).dylib +LIBGCCJIT_FILENAME = $(LIBGCCJIT_BASENAME).$(LIBGCCJIT_VERSION_NUM).dylib +LIBGCCJIT_LINKER_NAME = $(LIBGCCJIT_BASENAME).dylib + +# Conditionalize the use of the LD_VERSION_SCRIPT_OPTION and +# LD_SONAME_OPTION depending if configure found them, using $(if) +# We have to define a COMMA here, otherwise the commas in the "true" +# result are treated as separators by the $(if). +COMMA := , +LIBGCCJIT_VERSION_SCRIPT_OPTION = \ + $(if $(LD_VERSION_SCRIPT_OPTION),\ + -Wl$(COMMA)$(LD_VERSION_SCRIPT_OPTION)$(COMMA)$(srcdir)/jit/libgccjit.map) + +LIBGCCJIT_SONAME_OPTION = \ + $(if $(LD_SONAME_OPTION), \ + -Wl$(COMMA)$(LD_SONAME_OPTION)$(COMMA)$(LIBGCCJIT_SONAME)) + +LIBGCCJIT_SONAME_SYMLINK = $(LIBGCCJIT_FILENAME) +LIBGCCJIT_LINKER_NAME_SYMLINK = $(LIBGCCJIT_LINKER_NAME) + +jit: $(LIBGCCJIT_FILENAME) \ + $(LIBGCCJIT_SYMLINK) \ + $(LIBGCCJIT_LINKER_NAME_SYMLINK) \ + $(FULL_DRIVER_NAME) +else + +LIBGCCJIT_LINKER_NAME = libgccjit.so LIBGCCJIT_SONAME = $(LIBGCCJIT_LINKER_NAME).$(LIBGCCJIT_VERSION_NUM) LIBGCCJIT_FILENAME = \ $(LIBGCCJIT_SONAME).$(LIBGCCJIT_MINOR_NUM).$(LIBGCCJIT_RELEASE_NUM) @@ -79,6 +111,8 @@ jit: $(LIBGCCJIT_FILENAME) \ $(LIBGCCJIT_SYMLINK) \ $(LIBGCCJIT_LINKER_NAME_SYMLINK) \ $(FULL_DRIVER_NAME) + +endif endif jit.serial = $(LIBGCCJIT_FILENAME) @@ -109,9 +143,19 @@ ifneq (,$(findstring mingw,$(target))) # Create import library LIBGCCJIT_EXTRA_OPTS = -Wl,--out-implib,$(LIBGCCJIT_IMPORT_LIB) else + +ifneq (,$(findstring darwin,$(host))) +# TODO : Construct a Darwin-style symbol export file. +LIBGCCJIT_EXTRA_OPTS = -Wl,-compatibility_version,$(LIBGCCJIT_VERSION_NUM) \ + -Wl,-current_version,$(LIBGCCJIT_VERSION_NUM).$(LIBGCCJIT_MINOR_NUM).$(LIBGCCJIT_AGE) \ + $(LIBGCCJIT_VERSION_SCRIPT_OPTION) \ + $(LIBGCCJIT_SONAME_OPTION) +else + LIBGCCJIT_EXTRA_OPTS = $(LIBGCCJIT_VERSION_SCRIPT_OPTION) \ $(LIBGCCJIT_SONAME_OPTION) endif +endif # We avoid using $(BACKEND) from Makefile.in in order to avoid pulling # in main.o @@ -130,8 +174,12 @@ $(LIBGCCJIT_FILENAME): $(jit_OBJS) \ # Create symlinks when not building for Windows ifeq (,$(findstring mingw,$(target))) + +ifeq (,$(findstring darwin,$(host))) +# but only one level for Darwin, version info is embedded. $(LIBGCCJIT_SONAME_SYMLINK): $(LIBGCCJIT_FILENAME) ln -sf $(LIBGCCJIT_FILENAME) $(LIBGCCJIT_SONAME_SYMLINK) +endif $(LIBGCCJIT_LINKER_NAME_SYMLINK): $(LIBGCCJIT_SONAME_SYMLINK) ln -sf $(LIBGCCJIT_SONAME_SYMLINK) $(LIBGCCJIT_LINKER_NAME_SYMLINK) @@ -319,6 +367,18 @@ jit.install-common: installdirs jit.install-headers # Install DLL file $(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \ $(DESTDIR)$(bindir)/$(LIBGCCJIT_FILENAME) + +else +ifneq (,$(findstring darwin,$(host))) +# but only one level for Darwin + +jit.install-common: installdirs jit.install-headers + $(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \ + $(DESTDIR)$(libdir)/$(LIBGCCJIT_FILENAME) + ln -sf \ + $(LIBGCCJIT_SONAME_SYMLINK)\ + $(DESTDIR)$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK) + else jit.install-common: installdirs jit.install-headers $(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \ @@ -330,6 +390,7 @@ jit.install-common: installdirs jit.install-headers $(LIBGCCJIT_SONAME_SYMLINK)\ $(DESTDIR)$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK) endif +endif jit.install-man: -- cgit v1.1 From f0fca213bc52644ba896da622b35842a6157bd98 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Wed, 18 Aug 2021 21:47:04 +0200 Subject: Fortran: Add OpenMP's nothing directive support (con't) Fix directory to enable -fopenmp processing. gcc/testsuite/ PR testsuite/101963 * gfortran.dg/nothing-1.f90: Moved to ... * gfortran.dg/gomp/nothing-1.f90: ... here. * gfortran.dg/nothing-2.f90: Moved to ... * gfortran.dg/gomp/nothing-2.f90: ... here; avoid $ issue in $OMP in dg-error. --- gcc/testsuite/gfortran.dg/gomp/nothing-1.f90 | 28 ++++++++++++++++++++++++++++ gcc/testsuite/gfortran.dg/gomp/nothing-2.f90 | 7 +++++++ gcc/testsuite/gfortran.dg/nothing-1.f90 | 28 ---------------------------- gcc/testsuite/gfortran.dg/nothing-2.f90 | 7 ------- 4 files changed, 35 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/gomp/nothing-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/nothing-2.f90 delete mode 100644 gcc/testsuite/gfortran.dg/nothing-1.f90 delete mode 100644 gcc/testsuite/gfortran.dg/nothing-2.f90 (limited to 'gcc') diff --git a/gcc/testsuite/gfortran.dg/gomp/nothing-1.f90 b/gcc/testsuite/gfortran.dg/gomp/nothing-1.f90 new file mode 100644 index 0000000..9fc24d4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/nothing-1.f90 @@ -0,0 +1,28 @@ +module m + implicit none (type, external) + !$omp nothing + + type t + !$omp nothing + integer s + end type + +contains + +integer function foo (i) + integer :: i + + !$omp nothing + if (.false.) & +& & !$omp nothing + i = i + 1 + +! In the following, '& & !$' is not a valid OpenMP sentinel and, +! hence, the line is regarded as comment + if (.false.) & +& & !$omp nothing + then + end if + foo = i +end +end module diff --git a/gcc/testsuite/gfortran.dg/gomp/nothing-2.f90 b/gcc/testsuite/gfortran.dg/gomp/nothing-2.f90 new file mode 100644 index 0000000..554d4ef --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/nothing-2.f90 @@ -0,0 +1,7 @@ +pure subroutine foo + !$omp nothing ! { dg-error "OpenMP directives other than SIMD or DECLARE TARGET at .1. may not appear in PURE procedures" } +end subroutine + +subroutine bar + !$omp nothing foo ! { dg-error "Unexpected junk after .OMP NOTHING statement" } +end diff --git a/gcc/testsuite/gfortran.dg/nothing-1.f90 b/gcc/testsuite/gfortran.dg/nothing-1.f90 deleted file mode 100644 index 9fc24d4..0000000 --- a/gcc/testsuite/gfortran.dg/nothing-1.f90 +++ /dev/null @@ -1,28 +0,0 @@ -module m - implicit none (type, external) - !$omp nothing - - type t - !$omp nothing - integer s - end type - -contains - -integer function foo (i) - integer :: i - - !$omp nothing - if (.false.) & -& & !$omp nothing - i = i + 1 - -! In the following, '& & !$' is not a valid OpenMP sentinel and, -! hence, the line is regarded as comment - if (.false.) & -& & !$omp nothing - then - end if - foo = i -end -end module diff --git a/gcc/testsuite/gfortran.dg/nothing-2.f90 b/gcc/testsuite/gfortran.dg/nothing-2.f90 deleted file mode 100644 index 74a4a5a..0000000 --- a/gcc/testsuite/gfortran.dg/nothing-2.f90 +++ /dev/null @@ -1,7 +0,0 @@ -pure subroutine foo - !$omp nothing ! { dg-error "OpenMP directives other than SIMD or DECLARE TARGET at .1. may not appear in PURE procedures" } -end subroutine - -subroutine bar - !$omp nothing foo ! { dg-error "Unexpected junk after $OMP NOTHING statement" } -end -- cgit v1.1 From 6e529985d8956f74492e3176026fc02dc8f01b6c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 19 Aug 2021 00:16:42 +0000 Subject: Daily bump. --- gcc/ChangeLog | 51 ++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/ada/ChangeLog | 5 ++++ gcc/analyzer/ChangeLog | 51 ++++++++++++++++++++++++++++++++++ gcc/c-family/ChangeLog | 6 ++++ gcc/c/ChangeLog | 29 +++++++++++++++++++ gcc/cp/ChangeLog | 39 ++++++++++++++++++++++++++ gcc/fortran/ChangeLog | 6 ++++ gcc/jit/ChangeLog | 5 ++++ gcc/objc/ChangeLog | 10 +++++++ gcc/testsuite/ChangeLog | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 277 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b26f256..4fd8ff7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,54 @@ +2021-08-18 Iain Sandoe + + * config.gcc: Include rpath.opt for Darwin. + * config/darwin.h (DRIVER_SELF_SPECS): Handle -rpath. + +2021-08-18 Thomas Schwinge + + PR bootstrap/101959 + * hash-map-tests.c (test_map_of_type_with_ctor_and_dtor_expand): + Use an 'int_hash'. + +2021-08-18 Jonathan Wright + + * config/aarch64/arm_neon.h (vld3_lane_f64): Use float RTL + pattern and type cast. + (vld4_lane_f32): Use float RTL pattern. + (vld4q_lane_f64): Use float type cast. + +2021-08-18 Jan Hubicka + + * tree-ssa-uninit.c (maybe_warn_pass_by_reference): Check also + EAF_NOREAD. + +2021-08-18 Thomas Schwinge + + * hash-map-tests.c (test_map_of_type_with_ctor_and_dtor): Extend. + (test_map_of_type_with_ctor_and_dtor_expand): Add function. + (hash_map_tests_c_tests): Call it. + +2021-08-18 Thomas Schwinge + + * ggc.h (enum ggc_collect): New. + (ggc_collect): Use it. + * ggc-page.c: Adjust. + * ggc-common.c: Likewise. + * ggc-tests.c: Likewise. + * read-rtl-function.c: Likewise. + * selftest-run-tests.c: Likewise. + * doc/gty.texi (Invoking the garbage collector): Likewise. + +2021-08-18 liuhongt + + PR target/97147 + * config/i386/i386.h (TARGET_V2DF_REDUCTION_PREFER_HADDPD): + New macro. + * config/i386/sse.md (*sse3_haddv2df3_low): Add + TARGET_V2DF_REDUCTION_PREFER_HADDPD. + (*sse3_hsubv2df3_low): Ditto. + * config/i386/x86-tune.def + (X86_TUNE_V2DF_REDUCTION_PREFER_HADDPD): New tune. + 2021-08-17 Andrew MacLeod * gimple-range-gori.cc (gori_compute::gori_compute): Enable tracing. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 70b09db..30a51b9 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210818 +20210819 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 8e19ca4..63a04b1 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2021-08-18 Eric Botcazou + + * gcc-interface/decl.c (gnat_to_gnu_entity) : Fix + thinko in latest change. + 2021-08-11 Bernd Edlinger PR debug/101598 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 43e3c63..0b483cc 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,54 @@ +2021-08-18 Ankur Saini + + PR analyzer/97114 + * region-model.cc (region_model::get_rvalue_1): Add case for + OBJ_TYPE_REF. + +2021-08-18 Ankur Saini + + PR analyzer/100546 + * analysis-plan.cc (analysis_plan::use_summary_p): Don't use call + summaries if there is no callgraph edge + * checker-path.cc (call_event::call_event): Handle calls events that + are not represented by a supergraph call edge + (return_event::return_event): Likewise. + (call_event::get_desc): Work with new call_event structure. + (return_event::get_desc): Likeise. + * checker-path.h (call_event::m_src_snode): New field. + (call_event::m_dest_snode): New field. + (return_event::m_src_snode): New field. + (return_event::m_dest_snode): New field. + * diagnostic-manager.cc + (diagnostic_manager::prune_for_sm_diagnostic): + Refactor to work with edges without callgraph edge. + (diagnostic_manager::prune_for_sm_diagnostic): + Likewise. + * engine.cc (dynamic_call_info_t::update_model): New function. + (dynamic_call_info_t::add_events_to_path): New function. + (exploded_graph::create_dynamic_call): New function. + (exploded_graph::process_node): Work with dynamically discovered calls. + * exploded-graph.h (class dynamic_call_info_t): New class. + (exploded_graph::create_dynamic_call): New decl. + * program-point.cc (program_point::push_to_call_stack): New function. + (program_point::pop_from_call_stack): New function. + * program-point.h (program_point::push_to_call_stack): New decl. + (program_point::pop_from_call_stack): New decl. + * program-state.cc (program_state::push_call): New function. + (program_state::returning_call): New function. + * program-state.h (program_state::push_call): New decl. + (program_state::returning_call): New decl. + * region-model.cc (region_model::update_for_gcall) New function. + (region_model::update_for_return_gcall): New function. + (egion_model::update_for_call_superedge): Get the underlying gcall and + update for gcall. + (region_model::update_for_return_superedge): Likewise. + * region-model.h (region_model::update_for_gcall): New decl. + (region_model::update_for_return_gcall): New decl. + * state-purge.cc (state_purge_per_ssa_name::process_point): Update to + work with calls without underlying cgraph edge. + * supergraph.cc (supergraph::supergraph) Split snodes at every callsite. + * supergraph.h (supernode::get_returning_call) New accessor. + 2021-08-04 David Malcolm PR analyzer/101570 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 5595994..ab566ba 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2021-08-18 Jakub Jelinek + + * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_NOTHING. + * c-pragma.c (omp_pragmas): Add nothing directive. + * c-omp.c (omp_directives): Uncomment nothing directive entry. + 2021-08-17 Jakub Jelinek PR c++/101539 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index caeac5b..53abd1a 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,32 @@ +2021-08-18 Jakub Jelinek + + * c-parser.c (c_parser_omp_nothing): New function. + (c_parser_pragma): Handle PRAGMA_OMP_NOTHING. + +2021-08-18 Jakub Jelinek + + * c-parser.c (c_parser_statement_after_labels): Add restart label + near the start of the function. If c_parser_pragma returns false, + goto restart. + (c_parser_pragma): For PRAGMA_OMP_CANCELLATION_POINT return what + c_parser_omp_cancellation_point returned. For PRAGMA_OMP_DECLARE + return what c_parser_omp_declare returned. Return true instead of + false after emitting errors that the directive is not allowed in + pragma_stmt context. + (c_parser_omp_ordered): Return true instead of + false after emitting errors that the directive is not allowed in + pragma_stmt context. + (c_parser_omp_target_update): Likewise. + (c_parser_omp_target_enter_data, c_parser_omp_target_exit_data): + Change return type from tree to bool, return false if the + directive should be ignored in pragma_stmt contexts. + (c_parser_omp_target): Adjust callers of c_parser_omp_target_*_data, + return their result directly. + (c_parser_omp_cancellation_point): Change return type from void to + bool, return false if the directive should be ignored in pragma_stmt + contexts. + (c_parser_omp_declare): Likewise. + 2021-08-17 Jakub Jelinek * c-parser.c (OMP_SCOPE_CLAUSE_MASK): Define. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a2d47b3..a06a496 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,42 @@ +2021-08-18 Patrick Palka + + PR c++/101344 + PR c++/101820 + * cp-tree.h (CONSTRUCTOR_BRACES_ELIDED_P): Define. + * decl.c (reshape_init_r): Set it. + * pt.c (collect_ctor_idx_types): Recurse into a sub-CONSTRUCTOR + iff CONSTRUCTOR_BRACES_ELIDED_P. + +2021-08-18 Patrick Palka + + PR c++/101883 + * pt.c (convert_template_argument): Pass LOOKUP_IMPLICIT to + do_auto_deduction. + +2021-08-18 Jakub Jelinek + + * parser.c (cp_parser_omp_nothing): New function. + (cp_parser_pragma): Handle PRAGMA_OMP_NOTHING. + +2021-08-18 Jakub Jelinek + + * parser.c (cp_parser_omp_ordered): Return true instead of + false after emitting errors that the directive is not allowed in + pragma_stmt context. + (cp_parser_omp_target_update): Likewise. + (cp_parser_omp_cancellation_point): Change return type from void to + bool, return false if the directive should be ignored in pragma_stmt + contexts. + (cp_parser_omp_target_enter_data, cp_parser_omp_target_exit_data): + Change return type from tree to bool, return false if the + directive should be ignored in pragma_stmt contexts. + (cp_parser_omp_target): Adjust callers of cp_parser_omp_target_*_data, + return their result directly. + (cp_parser_pragma): For PRAGMA_OMP_CANCELLATION_POINT return what + cp_parser_omp_cancellation_point returned. Return true instead of + false after emitting errors that the directive is not allowed in + pragma_stmt context. + 2021-08-17 Jakub Jelinek PR c++/101539 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 86a2bda..90a3e53 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2021-08-18 Tobias Burnus + + * match.h (gfc_match_omp_nothing): New. + * openmp.c (gfc_match_omp_nothing): New. + * parse.c (decode_omp_directive): Match 'nothing' directive. + 2021-08-17 Tobias Burnus * dump-parse-tree.c (show_omp_node, show_code_node): Handle diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index 2a2675a..7557e17 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,8 @@ +2021-08-18 Iain Sandoe + + PR jit/100613 + * Make-lang.in: Provide clauses for Darwin hosts. + 2021-07-18 Antoni Boucher PR target/95498 diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 8adde0d..ea8c88b 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,13 @@ +2021-08-18 Iain Sandoe + Matt Jacobson + + PR objc/101666 + * objc-act.c (objc_build_constructor): Handle empty constructor + lists. + * objc-next-runtime-abi-02.c (build_v2_objc_method_fixup_call): + Handle nil receivers. + (build_v2_build_objc_method_call): Likewise. + 2021-08-17 Matt Jacobson * objc-next-runtime-abi-02.c diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e5dcd4a..57b714a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,77 @@ +2021-08-18 Tobias Burnus + + PR testsuite/101963 + * gfortran.dg/nothing-1.f90: Moved to ... + * gfortran.dg/gomp/nothing-1.f90: ... here. + * gfortran.dg/nothing-2.f90: Moved to ... + * gfortran.dg/gomp/nothing-2.f90: ... here; + avoid $ issue in $OMP in dg-error. + +2021-08-18 Iain Sandoe + Matt Jacobson + + PR objc/101666 + * obj-c++.dg/pr101666-0.mm: New test. + * obj-c++.dg/pr101666-1.mm: New test. + * obj-c++.dg/pr101666.inc: New. + * objc.dg/pr101666-0.m: New test. + * objc.dg/pr101666-1.m: New test. + * objc.dg/pr101666.inc: New. + +2021-08-18 Ankur Saini + + PR analyzer/97114 + * g++.dg/analyzer/vfunc-2.C: New test. + * g++.dg/analyzer/vfunc-3.C: New test. + * g++.dg/analyzer/vfunc-4.C: New test. + * g++.dg/analyzer/vfunc-5.C: New test. + +2021-08-18 Ankur Saini + + PR analyzer/100546 + * gcc.dg/analyzer/function-ptr-4.c: New test. + * gcc.dg/analyzer/pr100546.c: New test. + +2021-08-18 Tobias Burnus + + * gfortran.dg/nothing-1.f90: New test. + * gfortran.dg/nothing-2.f90: New test. + +2021-08-18 Patrick Palka + + PR c++/101344 + PR c++/101820 + * g++.dg/cpp2a/class-deduction-aggr11.C: New test. + * g++.dg/cpp2a/class-deduction-aggr12.C: New test. + +2021-08-18 Patrick Palka + + PR c++/101883 + * g++.dg/cpp2a/nontype-class49.C: New test. + +2021-08-18 Jakub Jelinek + + * c-c++-common/gomp/nothing-1.c: New test. + * g++.dg/gomp/attrs-1.C (bar): Add nothing directive test. + * g++.dg/gomp/attrs-2.C (bar): Likewise. + * g++.dg/gomp/attrs-9.C: Likewise. + +2021-08-18 Jakub Jelinek + + * c-c++-common/gomp/pr63326.c: Don't expect extra "before" errors + in C++. + * g++.dg/gomp/attrs-7.C: Don't expect one extra error. + * g++.dg/gomp/barrier-2.C: Likewise. + * gcc.dg/gomp/declare-simd-5.c: Likewise. + * gcc.dg/gomp/barrier-2.c: Likewise. + * gcc.dg/gomp/declare-variant-2.c: Likewise. + +2021-08-18 liuhongt + + PR target/97147 + * gcc.target/i386/pr54400.c: Adjust testcase. + * gcc.target/i386/pr94147.c: New test. + 2021-08-17 Martin Sebor PR middle-end/101854 -- cgit v1.1 From 1db70e61a92978377a648bbd90e383859fc0126b Mon Sep 17 00:00:00 2001 From: liuhongt Date: Tue, 17 Aug 2021 17:29:06 +0800 Subject: Revert "Add the member integer_to_sse to processor_cost as a cost simulation for movd/pinsrd. It will be used to calculate the cost of vec_construct." This reverts commit 872da9a6f664a06d73c987aa0cb2e5b830158a10. PR target/101936 PR target/101929 --- gcc/config/i386/i386.c | 6 +----- gcc/config/i386/i386.h | 1 - gcc/config/i386/x86-tune-costs.h | 26 -------------------------- gcc/testsuite/gcc.target/i386/pr99881.c | 2 +- 4 files changed, 2 insertions(+), 33 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 4d4ab6a..46844fa 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -22203,11 +22203,7 @@ ix86_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost, case vec_construct: { /* N element inserts into SSE vectors. */ - int cost - = TYPE_VECTOR_SUBPARTS (vectype) * (fp ? - ix86_cost->sse_op - : ix86_cost->integer_to_sse); - + int cost = TYPE_VECTOR_SUBPARTS (vectype) * ix86_cost->sse_op; /* One vinserti128 for combining two SSE vectors for AVX256. */ if (GET_MODE_BITSIZE (mode) == 256) cost += ix86_vec_cost (mode, ix86_cost->addss); diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index b3e57a8..8aba86d 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -165,7 +165,6 @@ struct processor_costs { const int xmm_move, ymm_move, /* cost of moving XMM and YMM register. */ zmm_move; const int sse_to_integer; /* cost of moving SSE register to integer. */ - const int integer_to_sse; /* cost of moving integer to SSE register. */ const int gather_static, gather_per_elt; /* Cost of gather load is computed as static + per_item * nelts. */ const int scatter_static, scatter_per_elt; /* Cost of gather store is diff --git a/gcc/config/i386/x86-tune-costs.h b/gcc/config/i386/x86-tune-costs.h index 67cfa00..ffe810f 100644 --- a/gcc/config/i386/x86-tune-costs.h +++ b/gcc/config/i386/x86-tune-costs.h @@ -102,7 +102,6 @@ struct processor_costs ix86_size_cost = {/* costs for tuning for size */ in 128bit, 256bit and 512bit */ 3, 3, 3, /* cost of moving XMM,YMM,ZMM register */ 3, /* cost of moving SSE register to integer. */ - COSTS_N_BYTES (2), /* cost of moving integer to sse register. */ 5, 0, /* Gather load static, per_elt. */ 5, 0, /* Gather store static, per_elt. */ 0, /* size of l1 cache */ @@ -212,7 +211,6 @@ struct processor_costs i386_cost = { /* 386 specific costs */ {4, 8, 16, 32, 64}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 3, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 4, 4, /* Gather load static, per_elt. */ 4, 4, /* Gather store static, per_elt. */ 0, /* size of l1 cache */ @@ -321,7 +319,6 @@ struct processor_costs i486_cost = { /* 486 specific costs */ {4, 8, 16, 32, 64}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 3, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 4, 4, /* Gather load static, per_elt. */ 4, 4, /* Gather store static, per_elt. */ 4, /* size of l1 cache. 486 has 8kB cache @@ -432,7 +429,6 @@ struct processor_costs pentium_cost = { {4, 8, 16, 32, 64}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 3, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 4, 4, /* Gather load static, per_elt. */ 4, 4, /* Gather store static, per_elt. */ 8, /* size of l1 cache. */ @@ -534,7 +530,6 @@ struct processor_costs lakemont_cost = { {4, 8, 16, 32, 64}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 3, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 4, 4, /* Gather load static, per_elt. */ 4, 4, /* Gather store static, per_elt. */ 8, /* size of l1 cache. */ @@ -651,7 +646,6 @@ struct processor_costs pentiumpro_cost = { {4, 8, 16, 32, 64}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 3, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 4, 4, /* Gather load static, per_elt. */ 4, 4, /* Gather store static, per_elt. */ 8, /* size of l1 cache. */ @@ -759,7 +753,6 @@ struct processor_costs geode_cost = { {2, 2, 8, 16, 32}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 6, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 2, 2, /* Gather load static, per_elt. */ 2, 2, /* Gather store static, per_elt. */ 64, /* size of l1 cache. */ @@ -867,7 +860,6 @@ struct processor_costs k6_cost = { {2, 2, 8, 16, 32}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 6, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 2, 2, /* Gather load static, per_elt. */ 2, 2, /* Gather store static, per_elt. */ 32, /* size of l1 cache. */ @@ -981,7 +973,6 @@ struct processor_costs athlon_cost = { {4, 4, 10, 10, 20}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 5, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (2), /* cost of moving integer to sse register. */ 4, 4, /* Gather load static, per_elt. */ 4, 4, /* Gather store static, per_elt. */ 64, /* size of l1 cache. */ @@ -1097,7 +1088,6 @@ struct processor_costs k8_cost = { {4, 4, 10, 10, 20}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 5, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (2), /* cost of moving integer to sse register. */ 4, 4, /* Gather load static, per_elt. */ 4, 4, /* Gather store static, per_elt. */ 64, /* size of l1 cache. */ @@ -1226,7 +1216,6 @@ struct processor_costs amdfam10_cost = { {4, 4, 5, 10, 20}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 3, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (2), /* cost of moving integer to sse register. */ 4, 4, /* Gather load static, per_elt. */ 4, 4, /* Gather store static, per_elt. */ 64, /* size of l1 cache. */ @@ -1347,7 +1336,6 @@ const struct processor_costs bdver_cost = { {10, 10, 10, 40, 60}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 16, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (2), /* cost of moving integer to sse register. */ 12, 12, /* Gather load static, per_elt. */ 10, 10, /* Gather store static, per_elt. */ 16, /* size of l1 cache. */ @@ -1489,7 +1477,6 @@ struct processor_costs znver1_cost = { {8, 8, 8, 16, 32}, /* cost of unaligned stores. */ 2, 3, 6, /* cost of moving XMM,YMM,ZMM register. */ 6, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ /* VGATHERDPD is 23 uops and throughput is 9, VGATHERDPD is 35 uops, throughput 12. Approx 9 uops do not depend on vector size and every load is 7 uops. */ @@ -1646,7 +1633,6 @@ struct processor_costs znver2_cost = { 2, 2, 3, /* cost of moving XMM,YMM,ZMM register. */ 6, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ /* VGATHERDPD is 23 uops and throughput is 9, VGATHERDPD is 35 uops, throughput 12. Approx 9 uops do not depend on vector size and every load is 7 uops. */ @@ -1779,7 +1765,6 @@ struct processor_costs znver3_cost = { 2, 2, 3, /* cost of moving XMM,YMM,ZMM register. */ 6, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ /* VGATHERDPD is 15 uops and throughput is 4, VGATHERDPS is 23 uops, throughput 9. Approx 7 uops do not depend on vector size and every load is 4 uops. */ @@ -1924,7 +1909,6 @@ struct processor_costs skylake_cost = { {8, 8, 8, 8, 16}, /* cost of unaligned stores. */ 2, 2, 4, /* cost of moving XMM,YMM,ZMM register */ 6, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (2)+1, /* cost of moving integer to sse register. */ 20, 8, /* Gather load static, per_elt. */ 22, 10, /* Gather store static, per_elt. */ 64, /* size of l1 cache. */ @@ -2051,7 +2035,6 @@ struct processor_costs icelake_cost = { {8, 8, 8, 8, 16}, /* cost of unaligned stores. */ 2, 2, 4, /* cost of moving XMM,YMM,ZMM register */ 6, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 20, 8, /* Gather load static, per_elt. */ 22, 10, /* Gather store static, per_elt. */ 64, /* size of l1 cache. */ @@ -2165,7 +2148,6 @@ const struct processor_costs btver1_cost = { {10, 10, 12, 48, 96}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 14, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 10, 10, /* Gather load static, per_elt. */ 10, 10, /* Gather store static, per_elt. */ 32, /* size of l1 cache. */ @@ -2276,7 +2258,6 @@ const struct processor_costs btver2_cost = { {10, 10, 12, 48, 96}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 14, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 10, 10, /* Gather load static, per_elt. */ 10, 10, /* Gather store static, per_elt. */ 32, /* size of l1 cache. */ @@ -2386,7 +2367,6 @@ struct processor_costs pentium4_cost = { {32, 32, 32, 64, 128}, /* cost of unaligned stores. */ 12, 24, 48, /* cost of moving XMM,YMM,ZMM register */ 20, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (2), /* cost of moving integer to sse register. */ 16, 16, /* Gather load static, per_elt. */ 16, 16, /* Gather store static, per_elt. */ 8, /* size of l1 cache. */ @@ -2499,7 +2479,6 @@ struct processor_costs nocona_cost = { {24, 24, 24, 48, 96}, /* cost of unaligned stores. */ 6, 12, 24, /* cost of moving XMM,YMM,ZMM register */ 20, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (2), /* cost of moving integer to sse register. */ 12, 12, /* Gather load static, per_elt. */ 12, 12, /* Gather store static, per_elt. */ 8, /* size of l1 cache. */ @@ -2610,7 +2589,6 @@ struct processor_costs atom_cost = { {16, 16, 16, 32, 64}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 8, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 8, 8, /* Gather load static, per_elt. */ 8, 8, /* Gather store static, per_elt. */ 32, /* size of l1 cache. */ @@ -2721,7 +2699,6 @@ struct processor_costs slm_cost = { {16, 16, 16, 32, 64}, /* cost of unaligned stores. */ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */ 8, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 8, 8, /* Gather load static, per_elt. */ 8, 8, /* Gather store static, per_elt. */ 32, /* size of l1 cache. */ @@ -2832,7 +2809,6 @@ struct processor_costs intel_cost = { {10, 10, 10, 10, 10}, /* cost of unaligned loads. */ 2, 2, 2, /* cost of moving XMM,YMM,ZMM register */ 4, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 6, 6, /* Gather load static, per_elt. */ 6, 6, /* Gather store static, per_elt. */ 32, /* size of l1 cache. */ @@ -2950,7 +2926,6 @@ struct processor_costs generic_cost = { {6, 6, 6, 10, 15}, /* cost of unaligned storess. */ 2, 3, 4, /* cost of moving XMM,YMM,ZMM register */ 6, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ 18, 6, /* Gather load static, per_elt. */ 18, 6, /* Gather store static, per_elt. */ 32, /* size of l1 cache. */ @@ -3074,7 +3049,6 @@ struct processor_costs core_cost = { {6, 6, 6, 6, 12}, /* cost of unaligned stores. */ 2, 2, 4, /* cost of moving XMM,YMM,ZMM register */ 2, /* cost of moving SSE register to integer. */ - COSTS_N_INSNS (1), /* cost of moving integer to sse register. */ /* VGATHERDPD is 7 uops, rec throughput 5, while VGATHERDPD is 9 uops, rec. throughput 6. So 5 uops statically and one uops per load. */ diff --git a/gcc/testsuite/gcc.target/i386/pr99881.c b/gcc/testsuite/gcc.target/i386/pr99881.c index a1ec1d1b..3e087eb 100644 --- a/gcc/testsuite/gcc.target/i386/pr99881.c +++ b/gcc/testsuite/gcc.target/i386/pr99881.c @@ -1,7 +1,7 @@ /* PR target/99881. */ /* { dg-do compile { target { ! ia32 } } } */ /* { dg-options "-Ofast -march=skylake" } */ -/* { dg-final { scan-assembler-not "xmm\[0-9\]" } } */ +/* { dg-final { scan-assembler-not "xmm\[0-9\]" { xfail *-*-* } } } */ void foo (int* __restrict a, int n, int c) -- cgit v1.1 From b7fc42073c04813f6b63e0641d3f6765424857c9 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Thu, 19 Aug 2021 08:25:47 +0200 Subject: Fix up 'gcc.dg/pr78213.c' for '--enable-checking=release' etc. Fix up for r242748 (commit 3615816da830d41f67a5d8955ae588eba7f0b6fb) "[PR target/78213] Do not ICE on non-empty -fself-test", as made apparent by recent commit a42467bdb70650cd2f421e67b6c3418f74feaec2 "Restore 'gcc.dg/pr78213.c' testing", after the test case had gotten disabled in r243681 (commit ecfc21ff34ddc6f8aa517251fb51494c68ff741f) "Introduce selftest::locate_file" shortly after its original introduction. gcc/testsuite/ PR testsuite/101969 * gcc.dg/pr78213.c: Fix up for '--enable-checking=release' etc. --- gcc/testsuite/gcc.dg/pr78213.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/pr78213.c b/gcc/testsuite/gcc.dg/pr78213.c index 40dd3c8..04bf038 100644 --- a/gcc/testsuite/gcc.dg/pr78213.c +++ b/gcc/testsuite/gcc.dg/pr78213.c @@ -8,4 +8,5 @@ int i; while (i--) bar(); } -/* { dg-message "fself\-test: " "-fself-test" { target *-*-* } 0 } */ + +/* { dg-regexp {^-fself-test: [0-9]+ pass\(es\) in [.0-9]+ seconds$|.*: note: self-tests are not enabled in this build$} } */ -- cgit v1.1 From eea1677fd03a1cb820cbb72044d4a0770f8a7a93 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Thu, 5 Aug 2021 10:07:03 +0100 Subject: JIT, testsuite, Darwin: Initial testsuite fixes. The testsuite setup for jit is not compatible with Darwin since it assumes that all targets support --export-dynamic. - this is fixed by adding '-rdynamic' conditionally upon target support for that (-rdynamic will be converted to the appropriate linker option). There is also an assumption that a suitable version of dejagnu.h is present in some default include search path that is usable from the testsuite. This is not the case for Darwin (dejagnu.h is not installed, and would not, in general, be found in any default include search path if installed via one of the main 'distros'). Also the upstream dejagnu.h has a definition of 'wait()' that clashes with a libc routines and therefore causes fails in the testsuite. - This patch imports the header from dejagnu-1.6.2 and * renames it to 'jit-dejagnu.h' * patches it to avoid unused variable warnings and the clash with the libc definition of wait () * In accordance with the advice in the expect man page, ensures that the final output of the 'totals' print is stable. Signed-off-by: Iain Sandoe gcc/jit/ChangeLog: * docs/examples/tut04-toyvm/toyvm.c: Include jit-dejagnu.h. * docs/examples/tut04-toyvm/toyvm.cc: Likewise. * jit-dejagnu.h: New file, imported from dejagnu-1.6.2 and patched for this application. gcc/testsuite/ChangeLog: * jit.dg/harness.h: Include jit-dejagnu.h. * jit.dg/jit.exp: Use -rdynamic conditionally on target support, instead of unconditional -Wl,--export-dynamic. --- gcc/jit/docs/examples/tut04-toyvm/toyvm.c | 2 +- gcc/jit/docs/examples/tut04-toyvm/toyvm.cc | 2 +- gcc/jit/jit-dejagnu.h | 338 +++++++++++++++++++++++++++++ gcc/testsuite/jit.dg/harness.h | 2 +- gcc/testsuite/jit.dg/jit.exp | 7 +- 5 files changed, 347 insertions(+), 4 deletions(-) create mode 100644 gcc/jit/jit-dejagnu.h (limited to 'gcc') diff --git a/gcc/jit/docs/examples/tut04-toyvm/toyvm.c b/gcc/jit/docs/examples/tut04-toyvm/toyvm.c index e742f34..8ea716e 100644 --- a/gcc/jit/docs/examples/tut04-toyvm/toyvm.c +++ b/gcc/jit/docs/examples/tut04-toyvm/toyvm.c @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see #include #include -#include +#include "jit-dejagnu.h" #include diff --git a/gcc/jit/docs/examples/tut04-toyvm/toyvm.cc b/gcc/jit/docs/examples/tut04-toyvm/toyvm.cc index 4b9c765..7e95501 100644 --- a/gcc/jit/docs/examples/tut04-toyvm/toyvm.cc +++ b/gcc/jit/docs/examples/tut04-toyvm/toyvm.cc @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see #include #include -#include +#include "jit-dejagnu.h" #include diff --git a/gcc/jit/jit-dejagnu.h b/gcc/jit/jit-dejagnu.h new file mode 100644 index 0000000..eb53cc9 --- /dev/null +++ b/gcc/jit/jit-dejagnu.h @@ -0,0 +1,338 @@ +/* DejaGnu unit testing header. + Copyright (C) 2000-2016 Free Software Foundation, Inc. + +This file is part of DejaGnu. + +DejaGnu is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +DejaGnu is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with DejaGnu; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Imported from 1.6.2 with modifications + * to avoid and unused symbol in C compilations + * avoid wait () clashing with system-provided routines + * provide a deterministic last line of output after the totals. */ + +#ifndef __DEJAGNU_H__ +#define __DEJAGNU_H__ + +#include +#include +#include + +/* If you have problems with DejaGnu dropping failed, untested, or + * unresolved messages generated by a unit testcase, then: */ + +/* #define _DEJAGNU_WAIT_ */ + +#ifdef _DEJAGNU_WAIT_ +#include +#include +#include +#endif + +static int passed; +static int failed; +static int untest; +static int unresolve; +static int xfailed; +#ifdef __cplusplus +static int xpassed; +#endif + +static char buffer[512]; + +#ifdef _DEJAGNU_WAIT_ +void +dg_wait (void) +{ + fd_set rfds; + struct timeval tv; + + FD_ZERO (&rfds); + tv.tv_sec = 0; + tv.tv_usec = 1; + + select (0, &rfds, NULL, NULL, &tv); +} +#endif + +static inline void +pass (const char* fmt, ...) +{ + va_list ap; + + passed++; + va_start (ap, fmt); + vsnprintf (buffer, sizeof (buffer), fmt, ap); + va_end (ap); + printf ("\tPASSED: %s\n", buffer); +#ifdef _DEJAGNU_WAIT_ + dg_wait (); +#endif +} + +static inline void +xpass (const char* fmt, ...) +{ + va_list ap; + + passed++; + va_start (ap, fmt); + vsnprintf (buffer, sizeof (buffer), fmt, ap); + va_end (ap); + printf ("\tXPASSED: %s\n", buffer); +#ifdef _DEJAGNU_WAIT_ + dg_wait (); +#endif +} + +static inline void +fail (const char* fmt, ...) +{ + va_list ap; + + failed++; + va_start (ap, fmt); + vsnprintf (buffer, sizeof (buffer), fmt, ap); + va_end (ap); + printf ("\tFAILED: %s\n", buffer); +#ifdef _DEJAGNU_WAIT_ + dg_wait (); +#endif +} + +static inline void +xfail (const char* fmt, ...) +{ + va_list ap; + + failed++; + va_start (ap, fmt); + vsnprintf (buffer, sizeof (buffer), fmt, ap); + va_end (ap); + printf ("\tXFAILED: %s\n", buffer); +#ifdef _DEJAGNU_WAIT_ + dg_wait (); +#endif +} + +static inline void +untested (const char* fmt, ...) +{ + va_list ap; + + untest++; + va_start (ap, fmt); + vsnprintf (buffer, sizeof (buffer), fmt, ap); + va_end (ap); + printf ("\tUNTESTED: %s\n", buffer); +#ifdef _DEJAGNU_WAIT_ + dg_wait (); +#endif +} + +static inline void +unresolved (const char* fmt, ...) +{ + va_list ap; + + unresolve++; + va_start (ap, fmt); + vsnprintf (buffer, sizeof (buffer), fmt, ap); + va_end (ap); + printf ("\tUNRESOLVED: %s\n", buffer); +#ifdef _DEJAGNU_WAIT_ + dg_wait (); +#endif +} + +static inline void +note (const char* fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + vsnprintf (buffer, sizeof (buffer), fmt, ap); + va_end (ap); + printf ("\tNOTE: %s\n", buffer); +#ifdef _DEJAGNU_WAIT_ + dg_wait (); +#endif +} + +static inline void +totals (void) +{ + printf ("\nTotals:\n"); + printf ("\t#passed:\t\t%d\n", passed); + printf ("\t#real failed:\t\t%d\n", failed); + if (xfailed) + printf ("\t#expected failures:\t\t%d\n", xfailed); + if (untest) + printf ("\t#untested:\t\t%d\n", untest); + if (unresolve) + printf ("\t#unresolved:\t\t%d\n", unresolve); + printf ("\njit-dg-harness-complete\n"); +} + +#ifdef __cplusplus + +#include +#include +#include +#include + +const char *outstate_list[] = { + "FAILED: ", "PASSED: ", "UNTESTED: ", "UNRESOLVED: ", "XFAILED: ", "XPASSED: " +}; + +const char ** outstate = outstate_list; + +enum teststate { FAILED, PASSED, UNTESTED, UNRESOLVED, XFAILED, XPASSED} laststate; + +class TestState { + private: + teststate laststate; + std::string lastmsg; + public: + TestState (void) + { + passed = 0; + failed = 0; + untest = 0; + xpassed = 0; + xfailed = 0; + unresolve = 0; + } + + ~TestState (void) { totals(); } + + void testrun (bool b, std::string s) + { + if (b) + pass (s); + else + fail (s); + } + + void pass (std::string s) + { + passed++; + laststate = PASSED; + lastmsg = s; + std::cout << "\t" << outstate[PASSED] << s << std::endl; + } + + void pass (const char *c) + { + std::string s = c; + pass (s); + } + + void xpass (std::string s) + { + xpassed++; + laststate = PASSED; + lastmsg = s; + std::cout << "\t" << outstate[XPASSED] << s << std::endl; + } + + void xpass (const char *c) + { + std::string s = c; + xpass (s); + } + + void fail (std::string s) + { + failed++; + laststate = FAILED; + lastmsg = s; + std::cout << "\t" << outstate[FAILED] << s << std::endl; + } + + void fail (const char *c) + { + std::string s = c; + fail (s); + } + + void xfail (std::string s) + { + xfailed++; + laststate = XFAILED; + lastmsg = s; + std::cout << "\t" << outstate[XFAILED] << s << std::endl; + } + + void xfail (const char *c) + { + std::string s = c; + xfail (s); + } + + void untested (std::string s) + { + untest++; + laststate = UNTESTED; + lastmsg = s; + std::cout << "\t" << outstate[UNTESTED] << s << std::endl; + } + + void untested (const char *c) + { + std::string s = c; + untested (s); + } + + void unresolved (std::string s) + { + unresolve++; + laststate = UNRESOLVED; + lastmsg = s; + std::cout << "\t" << outstate[UNRESOLVED] << s << std::endl; + } + + void unresolved (const char *c) + { + std::string s = c; + unresolved (s); + } + + void totals (void) + { + std::cout << "\t#passed:\t\t" << passed << std::endl; + std::cout << "\t#real failed:\t\t" << failed << std::endl; + if (xfailed) + std::cout << "\t#expected failures:\t\t" << xfailed << std::endl; + if (xpassed) + std::cout << "\t#unexpected passes:\t\t" << xpassed << std::endl; + if (untest) + std::cout << "\t#untested:\t\t" << untest << std::endl; + if (unresolve) + std::cout << "\t#unresolved:\t\t" << unresolve << std::endl; + std::cout << "\njit-dg-harness-complete" << std::endl; + } + + // This is so this class can be printed in an ostream. + friend std::ostream & operator << (std::ostream &os, TestState& t) + { + return os << "\t" << outstate[t.laststate] << t.lastmsg ; + } + + int GetState (void) { return laststate; } + std::string GetMsg (void) { return lastmsg; } +}; + +#endif /* __cplusplus */ +#endif /* _DEJAGNU_H_ */ diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h index 6b59fb5..0dc5ed1 100644 --- a/gcc/testsuite/jit.dg/harness.h +++ b/gcc/testsuite/jit.dg/harness.h @@ -27,7 +27,7 @@ #define note dejagnu_note #endif -#include +#include "jit-dejagnu.h" #ifdef MAKE_DEJAGNU_H_THREADSAFE #undef pass diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp index 9af87f9..005ba01 100644 --- a/gcc/testsuite/jit.dg/jit.exp +++ b/gcc/testsuite/jit.dg/jit.exp @@ -914,9 +914,14 @@ proc jit-verify-executable { args } { jit-run-executable $output_filename ${dg-output-text} } +set DEFAULT_CFLAGS "-I$srcdir/../jit -lgccjit -g -Wall -Werror" + # We need to link with --export-dynamic for test-calling-external-function.c # so that the JIT-built code can call into functions from the main program. -set DEFAULT_CFLAGS "-I$srcdir/../jit -lgccjit -g -Wall -Werror -Wl,--export-dynamic" + +if { [check_effective_target_rdynamic] } { + set DEFAULT_CFLAGS "$DEFAULT_CFLAGS -rdynamic" +} # Main loop. This will invoke jig-dg-test on each test-*.c file. dg-runtest $tests "" $DEFAULT_CFLAGS -- cgit v1.1 From 4e6a5fa403782590088b2796261b023963f912af Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 19 Aug 2021 10:35:39 +0200 Subject: openmp: For C++ ensure nothing directive has no operands When working on error directive, I've noticed that while C FE diagnosed clauses on nothing directive which doesn't allow any, the C++ FE silently accepted it. 2021-08-19 Jakub Jelinek * parser.c (cp_parser_omp_nothing): Use cp_parser_require_pragma_eol instead of cp_parser_skip_to_pragma_eol. * c-c++-common/gomp/nothing-2.c: New test. --- gcc/cp/parser.c | 2 +- gcc/testsuite/c-c++-common/gomp/nothing-2.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/nothing-2.c (limited to 'gcc') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 04116fb..1d48b83 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -45570,7 +45570,7 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) static void cp_parser_omp_nothing (cp_parser *parser, cp_token *pragma_tok) { - cp_parser_skip_to_pragma_eol (parser, pragma_tok); + cp_parser_require_pragma_eol (parser, pragma_tok); } diff --git a/gcc/testsuite/c-c++-common/gomp/nothing-2.c b/gcc/testsuite/c-c++-common/gomp/nothing-2.c new file mode 100644 index 0000000..a152035 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/nothing-2.c @@ -0,0 +1,2 @@ +#pragma omp nothing , /* { dg-error "expected end of line before" } */ +#pragma omp nothing asdf /* { dg-error "expected end of line before" } */ -- cgit v1.1 From cb23be4fa59be26a7ba08918d6973e1d94629f8a Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Fri, 13 Aug 2021 20:25:59 +0100 Subject: testsuite, JIT, Darwin: Adjust asm tests for Mach-O. This provides adjusted assembler fragments that are suitable for x86_64 Mach-O. Signed-off-by: Iain Sandoe gcc/testsuite/ChangeLog: * jit.dg/test-asm.c: Provide Mach-O fragment. * jit.dg/test-asm.cc: Likewise. --- gcc/testsuite/jit.dg/test-asm.c | 13 +++++++++++++ gcc/testsuite/jit.dg/test-asm.cc | 12 ++++++++++++ 2 files changed, 25 insertions(+) (limited to 'gcc') diff --git a/gcc/testsuite/jit.dg/test-asm.c b/gcc/testsuite/jit.dg/test-asm.c index 35a9f9d..43255dc 100644 --- a/gcc/testsuite/jit.dg/test-asm.c +++ b/gcc/testsuite/jit.dg/test-asm.c @@ -438,6 +438,18 @@ verify_code_4 (gcc_jit_context *ctxt, gcc_jit_result *result) static void create_test_i386_basic_asm_5 (gcc_jit_context *ctxt) { +#if __APPLE__ + /* Darwin's assemblers do not support push/pop section, do not use .type + and external symbols should use __USER_LABEL_PREFIX__. */ + gcc_jit_context_add_top_level_asm (ctxt, NULL, + "\t.text\n" + "\t.globl _add_asm\n" + "_add_asm:\n" + "\tmovq %rdi, %rax\n" + "\tadd %rsi, %rax\n" + "\tret\n" + "\t# some asm here\n"); +#else /* Quote from here in docs/topics/asm.rst: example 5: jit. */ gcc_jit_context_add_top_level_asm (ctxt, NULL, "\t.pushsection .text\n" @@ -450,6 +462,7 @@ create_test_i386_basic_asm_5 (gcc_jit_context *ctxt) "\t# some asm here\n" "\t.popsection\n"); /* Quote up to here in docs/topics/asm.rst: example 5: jit. */ +#endif } static void diff --git a/gcc/testsuite/jit.dg/test-asm.cc b/gcc/testsuite/jit.dg/test-asm.cc index be487e3..a3b45da 100644 --- a/gcc/testsuite/jit.dg/test-asm.cc +++ b/gcc/testsuite/jit.dg/test-asm.cc @@ -400,6 +400,17 @@ static void create_test_i386_basic_asm_5 (gcc_jit_context *c_ctxt) { gccjit::context ctxt (c_ctxt); +#if __APPLE__ + /* Darwin's assemblers do not support push/pop section, do not use .type + and external symbols should use __USER_LABEL_PREFIX__. */ + ctxt.add_top_level_asm ("\t.text\n" + "\t.globl _add_asm\n" + "_add_asm:\n" + "\tmovq %rdi, %rax\n" + "\tadd %rsi, %rax\n" + "\tret\n" + "\t# some asm here\n"); +#else /* Quote from here in docs/cp/topics/asm.rst: example 5: jit. */ ctxt.add_top_level_asm ("\t.pushsection .text\n" "\t.globl add_asm\n" @@ -411,6 +422,7 @@ create_test_i386_basic_asm_5 (gcc_jit_context *c_ctxt) "\t# some asm here\n" "\t.popsection\n"); /* Quote up to here in docs/cp/topics/asm.rst: example 5: jit. */ +#endif } static void -- cgit v1.1 From c04d766942274da89b236c4cb7e954b26da397c7 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 19 Aug 2021 10:38:19 +0200 Subject: openmp: Fix ICE on requires clause with atomic_default_mem_order ( When working on error directive, I've noticed the C FE ICEs on #pragma omp requires atomic_default_mem_order ( where it tries to peek 2nd token after the CPP_PRAGMA_EOL (or CPP_EOF) in there in order to improve error-recovery on say atomic_default_mem_order (acquire) or atomic_default_mem_order (seqcst) etc. The C++ FE didn't ICE, but it is better to follow the same thing there. 2021-08-19 Jakub Jelinek gcc/c/ * c-parser.c (c_parser_omp_requires): Don't call c_parser_peek_2nd_token and optionally consume token if current token is CPP_EOF, CPP_PRAGMA_EOL or CPP_CLOSE_PAREN. gcc/cp/ * parser.c (cp_parser_omp_requires): Don't call cp_lexer_nth_token_is and optionally consume token if current token is CPP_EOF, CPP_PRAGMA_EOL or CPP_CLOSE_PAREN. gcc/testsuite/ * c-c++-common/gomp/requires-3.c: Add testcase for atomic_default_mem_order ( at the end of line without corresponding ). --- gcc/c/c-parser.c | 15 ++++++++++++--- gcc/cp/parser.c | 15 ++++++++++++--- gcc/testsuite/c-c++-common/gomp/requires-3.c | 2 ++ 3 files changed, 26 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index d5f51b1..407f279 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -21710,9 +21710,18 @@ c_parser_omp_requires (c_parser *parser) error_at (c_parser_peek_token (parser)->location, "expected %, % or " "%"); - if (c_parser_peek_2nd_token (parser)->type - == CPP_CLOSE_PAREN) - c_parser_consume_token (parser); + switch (c_parser_peek_token (parser)->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + case CPP_CLOSE_PAREN: + break; + default: + if (c_parser_peek_2nd_token (parser)->type + == CPP_CLOSE_PAREN) + c_parser_consume_token (parser); + break; + } } else c_parser_consume_token (parser); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1d48b83..0af1a2c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -45479,9 +45479,18 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) error_at (cp_lexer_peek_token (parser->lexer)->location, "expected %, % or " "%"); - if (cp_lexer_nth_token_is (parser->lexer, 2, - CPP_CLOSE_PAREN)) - cp_lexer_consume_token (parser->lexer); + switch (cp_lexer_peek_token (parser->lexer)->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + case CPP_CLOSE_PAREN: + break; + default: + if (cp_lexer_nth_token_is (parser->lexer, 2, + CPP_CLOSE_PAREN)) + cp_lexer_consume_token (parser->lexer); + break; + } } else cp_lexer_consume_token (parser->lexer); diff --git a/gcc/testsuite/c-c++-common/gomp/requires-3.c b/gcc/testsuite/c-c++-common/gomp/requires-3.c index e5a6cbb..0e55b66 100644 --- a/gcc/testsuite/c-c++-common/gomp/requires-3.c +++ b/gcc/testsuite/c-c++-common/gomp/requires-3.c @@ -1,3 +1,5 @@ #pragma omp requires atomic_default_mem_order(acquire) /* { dg-error "expected 'seq_cst', 'relaxed' or 'acq_rel'" } */ #pragma omp requires atomic_default_mem_order(release) /* { dg-error "expected 'seq_cst', 'relaxed' or 'acq_rel'" } */ #pragma omp requires atomic_default_mem_order(foobar) /* { dg-error "expected 'seq_cst', 'relaxed' or 'acq_rel'" } */ +#pragma omp requires atomic_default_mem_order ( /* { dg-error "expected 'seq_cst', 'relaxed' or 'acq_rel'" } */ +/* { dg-error "expected '\\\)' before end of line" "" { target *-*-* } .-1 } */ -- cgit v1.1 From 301dc6011cbceb7ea9debd86aaec7cadb37213c8 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 19 Aug 2021 11:00:27 +0200 Subject: expand: Add new clrsb fallback expansion [PR101950] As suggested in the PR, the following patch adds two new clrsb expansion possibilities if target doesn't have clrsb_optab for the requested nor wider modes, but does have clz_optab for the requested mode. One expansion is clrsb (op0) expands as clz (op0 ^ (((stype)op0) >> (prec-1))) - 1 which is usable if CLZ_DEFINED_VALUE_AT_ZERO is 2 with value of prec, because the clz argument can be 0 and clrsb should give prec-1 in that case. The other expansion is clz (((op0 << 1) ^ (((stype)op0) >> (prec-1))) | 1) where the clz argument is never 0, but it is one operation longer. E.g. on x86_64-linux with -O2 -mno-lzcnt, this results for int foo (int x) { return __builtin_clrsb (x); } in - subq $8, %rsp - movslq %edi, %rdi - call __clrsbdi2 - addq $8, %rsp - subl $32, %eax + leal (%rdi,%rdi), %eax + sarl $31, %edi + xorl %edi, %eax + orl $1, %eax + bsrl %eax, %eax + xorl $31, %eax and with -O2 -mlzcnt: + movl %edi, %eax + sarl $31, %eax + xorl %edi, %eax + lzcntl %eax, %eax + subl $1, %eax On armv7hl-linux-gnueabi with -O2: - push {r4, lr} - bl __clrsbsi2 - pop {r4, pc} + @ link register save eliminated. + eor r0, r0, r0, asr #31 + clz r0, r0 + sub r0, r0, #1 + bx lr As it (at least usually) will make code larger, it is disabled for -Os or cold instructions. 2021-08-19 Jakub Jelinek PR middle-end/101950 * optabs.c (expand_clrsb_using_clz): New function. (expand_unop): Use it as another clrsb expansion fallback. * gcc.target/i386/pr101950-1.c: New test. * gcc.target/i386/pr101950-2.c: New test. --- gcc/optabs.c | 79 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr101950-1.c | 20 ++++++++ gcc/testsuite/gcc.target/i386/pr101950-2.c | 19 +++++++ 3 files changed, 118 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr101950-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr101950-2.c (limited to 'gcc') diff --git a/gcc/optabs.c b/gcc/optabs.c index 14d8ad2..ebed78f 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -2600,6 +2600,82 @@ widen_leading (scalar_int_mode mode, rtx op0, rtx target, optab unoptab) return 0; } +/* Attempt to emit (clrsb:mode op0) as + (plus:mode (clz:mode (xor:mode op0 (ashr:mode op0 (const_int prec-1)))) + (const_int -1)) + if CLZ_DEFINED_VALUE_AT_ZERO (mode, val) is 2 and val is prec, + or as + (clz:mode (ior:mode (xor:mode (ashl:mode op0 (const_int 1)) + (ashr:mode op0 (const_int prec-1))) + (const_int 1))) + otherwise. */ + +static rtx +expand_clrsb_using_clz (scalar_int_mode mode, rtx op0, rtx target) +{ + if (optimize_insn_for_size_p () + || optab_handler (clz_optab, mode) == CODE_FOR_nothing) + return NULL_RTX; + + start_sequence (); + HOST_WIDE_INT val = 0; + if (CLZ_DEFINED_VALUE_AT_ZERO (mode, val) != 2 + || val != GET_MODE_PRECISION (mode)) + val = 0; + else + val = 1; + + rtx temp2 = op0; + if (!val) + { + temp2 = expand_binop (mode, ashl_optab, op0, const1_rtx, + NULL_RTX, 0, OPTAB_DIRECT); + if (!temp2) + { + fail: + end_sequence (); + return NULL_RTX; + } + } + + rtx temp = expand_binop (mode, ashr_optab, op0, + GEN_INT (GET_MODE_PRECISION (mode) - 1), + NULL_RTX, 0, OPTAB_DIRECT); + if (!temp) + goto fail; + + temp = expand_binop (mode, xor_optab, temp2, temp, NULL_RTX, 0, + OPTAB_DIRECT); + if (!temp) + goto fail; + + if (!val) + { + temp = expand_binop (mode, ior_optab, temp, const1_rtx, + NULL_RTX, 0, OPTAB_DIRECT); + if (!temp) + goto fail; + } + temp = expand_unop_direct (mode, clz_optab, temp, val ? NULL_RTX : target, + true); + if (!temp) + goto fail; + if (val) + { + temp = expand_binop (mode, add_optab, temp, constm1_rtx, + target, 0, OPTAB_DIRECT); + if (!temp) + goto fail; + } + + rtx_insn *seq = get_insns (); + end_sequence (); + + add_equal_note (seq, temp, CLRSB, op0, NULL_RTX, mode); + emit_insn (seq); + return temp; +} + /* Try calculating clz of a double-word quantity as two clz's of word-sized quantities, choosing which based on whether the high word is nonzero. */ static rtx @@ -3171,6 +3247,9 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, rtx target, temp = widen_leading (int_mode, op0, target, unoptab); if (temp) return temp; + temp = expand_clrsb_using_clz (int_mode, op0, target); + if (temp) + return temp; } goto try_libcall; } diff --git a/gcc/testsuite/gcc.target/i386/pr101950-1.c b/gcc/testsuite/gcc.target/i386/pr101950-1.c new file mode 100644 index 0000000..cc98064 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101950-1.c @@ -0,0 +1,20 @@ +/* PR middle-end/101950 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-lzcnt" } */ +/* { dg-final { scan-assembler-not "call\[^\n\r]*__clrsb.i2" } } */ +/* { dg-final { scan-assembler-times "\tbsr\[ql]\t" 2 } } */ +/* { dg-final { scan-assembler-times "\txor\[ql]\t" 4 } } */ +/* { dg-final { scan-assembler-times "\tor\[ql]\t" 2 } } */ +/* { dg-final { scan-assembler-times "\tsar\[ql]\t|\tcltd" 2 } } */ + +int +foo (long x) +{ + return __builtin_clrsbl (x); +} + +int +bar (int x) +{ + return __builtin_clrsb (x); +} diff --git a/gcc/testsuite/gcc.target/i386/pr101950-2.c b/gcc/testsuite/gcc.target/i386/pr101950-2.c new file mode 100644 index 0000000..896f1b4 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101950-2.c @@ -0,0 +1,19 @@ +/* PR middle-end/101950 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mlzcnt" } */ +/* { dg-final { scan-assembler-not "call\[^\n\r]*__clrsb.i2" } } */ +/* { dg-final { scan-assembler-times "\tlzcnt\[ql]\t" 2 } } */ +/* { dg-final { scan-assembler-times "\txor\[ql]\t" 2 } } */ +/* { dg-final { scan-assembler-times "\tsar\[ql]\t|\tcltd" 2 } } */ + +int +foo (long x) +{ + return __builtin_clrsbl (x); +} + +int +bar (int x) +{ + return __builtin_clrsb (x); +} -- cgit v1.1