bool aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi) { bool changed = false; gimple stmt = gsi_stmt (*gsi); tree call = gimple_call_fn (stmt); tree fndecl; gimple new_stmt = NULL; if (call) { fndecl = gimple_call_fndecl (stmt); if (fndecl) { int fcode = DECL_FUNCTION_CODE (fndecl); int nargs = gimple_call_num_args (stmt); tree *args = (nargs > 0 ? gimple_call_arg_ptr (stmt, 0) : &error_mark_node); /* We use gimple's REDUC_(PLUS|MIN|MAX)_EXPRs for float, signed int and unsigned int; it will distinguish according to the types of the arguments to the __builtin. */ switch (fcode) { BUILTIN_VALL (UNOP, reduc_plus_scal_, 10) new_stmt = gimple_build_assign (gimple_call_lhs (stmt), REDUC_PLUS_EXPR, args[0]); break; BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10) BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10) new_stmt = gimple_build_assign (gimple_call_lhs (stmt), REDUC_MAX_EXPR, args[0]); break; BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10) BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10) new_stmt = gimple_build_assign (gimple_call_lhs (stmt), REDUC_MIN_EXPR, args[0]); break; default: break; } } } if (new_stmt) { gsi_replace (gsi, new_stmt, true); changed = true; } return changed; }
tree walk_gimple_op (gimple *stmt, walk_tree_fn callback_op, struct walk_stmt_info *wi) { hash_set<tree> *pset = (wi) ? wi->pset : NULL; unsigned i; tree ret = NULL_TREE; switch (gimple_code (stmt)) { case GIMPLE_ASSIGN: /* Walk the RHS operands. If the LHS is of a non-renamable type or is a register variable, we may use a COMPONENT_REF on the RHS. */ if (wi) { tree lhs = gimple_assign_lhs (stmt); wi->val_only = (is_gimple_reg_type (TREE_TYPE (lhs)) && !is_gimple_reg (lhs)) || gimple_assign_rhs_class (stmt) != GIMPLE_SINGLE_RHS; } for (i = 1; i < gimple_num_ops (stmt); i++) { ret = walk_tree (gimple_op_ptr (stmt, i), callback_op, wi, pset); if (ret) return ret; } /* Walk the LHS. If the RHS is appropriate for a memory, we may use a COMPONENT_REF on the LHS. */ if (wi) { /* If the RHS is of a non-renamable type or is a register variable, we may use a COMPONENT_REF on the LHS. */ tree rhs1 = gimple_assign_rhs1 (stmt); wi->val_only = (is_gimple_reg_type (TREE_TYPE (rhs1)) && !is_gimple_reg (rhs1)) || gimple_assign_rhs_class (stmt) != GIMPLE_SINGLE_RHS; wi->is_lhs = true; } ret = walk_tree (gimple_op_ptr (stmt, 0), callback_op, wi, pset); if (ret) return ret; if (wi) { wi->val_only = true; wi->is_lhs = false; } break; case GIMPLE_CALL: if (wi) { wi->is_lhs = false; wi->val_only = true; } ret = walk_tree (gimple_call_chain_ptr (as_a <gcall *> (stmt)), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_call_fn_ptr (stmt), callback_op, wi, pset); if (ret) return ret; for (i = 0; i < gimple_call_num_args (stmt); i++) { if (wi) wi->val_only = is_gimple_reg_type (TREE_TYPE (gimple_call_arg (stmt, i))); ret = walk_tree (gimple_call_arg_ptr (stmt, i), callback_op, wi, pset); if (ret) return ret; } if (gimple_call_lhs (stmt)) { if (wi) { wi->is_lhs = true; wi->val_only = is_gimple_reg_type (TREE_TYPE (gimple_call_lhs (stmt))); } ret = walk_tree (gimple_call_lhs_ptr (stmt), callback_op, wi, pset); if (ret) return ret; } if (wi) { wi->is_lhs = false; wi->val_only = true; } break; case GIMPLE_CATCH: ret = walk_tree (gimple_catch_types_ptr (as_a <gcatch *> (stmt)), callback_op, wi, pset); if (ret) return ret; break; case GIMPLE_EH_FILTER: ret = walk_tree (gimple_eh_filter_types_ptr (stmt), callback_op, wi, pset); if (ret) return ret; break; case GIMPLE_ASM: ret = walk_gimple_asm (as_a <gasm *> (stmt), callback_op, wi); if (ret) return ret; break; case GIMPLE_OMP_CONTINUE: { gomp_continue *cont_stmt = as_a <gomp_continue *> (stmt); ret = walk_tree (gimple_omp_continue_control_def_ptr (cont_stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_continue_control_use_ptr (cont_stmt), callback_op, wi, pset); if (ret) return ret; } break; case GIMPLE_OMP_CRITICAL: { gomp_critical *omp_stmt = as_a <gomp_critical *> (stmt); ret = walk_tree (gimple_omp_critical_name_ptr (omp_stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_critical_clauses_ptr (omp_stmt), callback_op, wi, pset); if (ret) return ret; } break; case GIMPLE_OMP_ORDERED: { gomp_ordered *omp_stmt = as_a <gomp_ordered *> (stmt); ret = walk_tree (gimple_omp_ordered_clauses_ptr (omp_stmt), callback_op, wi, pset); if (ret) return ret; } break; case GIMPLE_OMP_FOR: ret = walk_tree (gimple_omp_for_clauses_ptr (stmt), callback_op, wi, pset); if (ret) return ret; for (i = 0; i < gimple_omp_for_collapse (stmt); i++) { ret = walk_tree (gimple_omp_for_index_ptr (stmt, i), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_for_initial_ptr (stmt, i), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_for_final_ptr (stmt, i), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_for_incr_ptr (stmt, i), callback_op, wi, pset); if (ret) return ret; } break; case GIMPLE_OMP_PARALLEL: { gomp_parallel *omp_par_stmt = as_a <gomp_parallel *> (stmt); ret = walk_tree (gimple_omp_parallel_clauses_ptr (omp_par_stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_parallel_child_fn_ptr (omp_par_stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_parallel_data_arg_ptr (omp_par_stmt), callback_op, wi, pset); if (ret) return ret; } break; case GIMPLE_OMP_TASK: ret = walk_tree (gimple_omp_task_clauses_ptr (stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_task_child_fn_ptr (stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_task_data_arg_ptr (stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_task_copy_fn_ptr (stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_task_arg_size_ptr (stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_task_arg_align_ptr (stmt), callback_op, wi, pset); if (ret) return ret; break; case GIMPLE_OMP_SECTIONS: ret = walk_tree (gimple_omp_sections_clauses_ptr (stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_sections_control_ptr (stmt), callback_op, wi, pset); if (ret) return ret; break; case GIMPLE_OMP_SINGLE: ret = walk_tree (gimple_omp_single_clauses_ptr (stmt), callback_op, wi, pset); if (ret) return ret; break; case GIMPLE_OMP_TARGET: { gomp_target *omp_stmt = as_a <gomp_target *> (stmt); ret = walk_tree (gimple_omp_target_clauses_ptr (omp_stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_target_child_fn_ptr (omp_stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_target_data_arg_ptr (omp_stmt), callback_op, wi, pset); if (ret) return ret; } break; case GIMPLE_OMP_TEAMS: ret = walk_tree (gimple_omp_teams_clauses_ptr (stmt), callback_op, wi, pset); if (ret) return ret; break; case GIMPLE_OMP_ATOMIC_LOAD: { gomp_atomic_load *omp_stmt = as_a <gomp_atomic_load *> (stmt); ret = walk_tree (gimple_omp_atomic_load_lhs_ptr (omp_stmt), callback_op, wi, pset); if (ret) return ret; ret = walk_tree (gimple_omp_atomic_load_rhs_ptr (omp_stmt), callback_op, wi, pset); if (ret) return ret; } break; case GIMPLE_OMP_ATOMIC_STORE: { gomp_atomic_store *omp_stmt = as_a <gomp_atomic_store *> (stmt); ret = walk_tree (gimple_omp_atomic_store_val_ptr (omp_stmt), callback_op, wi, pset); if (ret) return ret; } break; case GIMPLE_TRANSACTION: ret = walk_tree (gimple_transaction_label_ptr ( as_a <gtransaction *> (stmt)), callback_op, wi, pset); if (ret) return ret; break; case GIMPLE_OMP_RETURN: ret = walk_tree (gimple_omp_return_lhs_ptr (stmt), callback_op, wi, pset); if (ret) return ret; break; /* Tuples that do not have operands. */ case GIMPLE_NOP: case GIMPLE_RESX: case GIMPLE_PREDICT: break; default: { enum gimple_statement_structure_enum gss; gss = gimple_statement_structure (stmt); if (gss == GSS_WITH_OPS || gss == GSS_WITH_MEM_OPS) for (i = 0; i < gimple_num_ops (stmt); i++) { ret = walk_tree (gimple_op_ptr (stmt, i), callback_op, wi, pset); if (ret) return ret; } } break; } return NULL_TREE; }
/* Transform 1) Memory references. 2) BUILTIN_ALLOCA calls. */ static void mf_xform_statements (void) { basic_block bb, next; gimple_stmt_iterator i; int saved_last_basic_block = last_basic_block; enum gimple_rhs_class grhs_class; unsigned argc, j; bb = ENTRY_BLOCK_PTR ->next_bb; do { next = bb->next_bb; for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) { gimple s = gsi_stmt (i); /* Only a few GIMPLE statements can reference memory. */ switch (gimple_code (s)) { case GIMPLE_ASSIGN: DEBUGLOG("\n\n******** Gimlpe Assign LHS ***********\n"); mf_xform_derefs_1 (&i, gimple_assign_lhs_ptr (s), gimple_location (s), integer_one_node); DEBUGLOG("******** Gimlpe Assign RHS ***********\n"); mf_xform_derefs_1 (&i, gimple_assign_rhs1_ptr (s), gimple_location (s), integer_zero_node); grhs_class = get_gimple_rhs_class (gimple_assign_rhs_code (s)); if (grhs_class == GIMPLE_BINARY_RHS) mf_xform_derefs_1 (&i, gimple_assign_rhs2_ptr (s), gimple_location (s), integer_zero_node); break; case GIMPLE_RETURN: if (gimple_return_retval (s) != NULL_TREE) { mf_xform_derefs_1 (&i, gimple_return_retval_ptr (s), gimple_location (s), integer_zero_node); } break; case GIMPLE_CALL: { tree fndecl = gimple_call_fndecl (s); //if (fndecl && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA)) // gimple_call_set_cannot_inline (s, true); argc = gimple_call_num_args(s); for (j = 0; j < argc; j++){ mf_xform_derefs_1 (&i, gimple_call_arg_ptr (s, j), gimple_location (s), integer_zero_node); } } break; default: ; } } bb = next; } while (bb && bb->index <= saved_last_basic_block); }