/* Internal functions. Copyright (C) 2011-2013 Free Software Foundation, Inc. This file is part of GCC. GCC 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, or (at your option) any later version. GCC 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 GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "internal-fn.h" #include "tree.h" #include "expr.h" #include "optabs.h" #include "gimple.h" /* The names of each internal function, indexed by function number. */ const char *const internal_fn_name_array[] = { #define DEF_INTERNAL_FN(CODE, FLAGS) #CODE, #include "internal-fn.def" #undef DEF_INTERNAL_FN "" }; /* The ECF_* flags of each internal function, indexed by function number. */ const int internal_fn_flags_array[] = { #define DEF_INTERNAL_FN(CODE, FLAGS) FLAGS, #include "internal-fn.def" #undef DEF_INTERNAL_FN 0 }; /* ARRAY_TYPE is an array of vector modes. Return the associated insn for load-lanes-style optab OPTAB. The insn must exist. */ static enum insn_code get_multi_vector_move (tree array_type, convert_optab optab) { enum insn_code icode; enum machine_mode imode; enum machine_mode vmode; gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE); imode = TYPE_MODE (array_type); vmode = TYPE_MODE (TREE_TYPE (array_type)); icode = convert_optab_handler (optab, imode, vmode); gcc_assert (icode != CODE_FOR_nothing); return icode; } /* Expand LOAD_LANES call STMT. */ static void expand_LOAD_LANES (gimple stmt) { struct expand_operand ops[2]; tree type, lhs, rhs; rtx target, mem; lhs = gimple_call_lhs (stmt); rhs = gimple_call_arg (stmt, 0); type = TREE_TYPE (lhs); target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); mem = expand_normal (rhs); gcc_assert (MEM_P (mem)); PUT_MODE (mem, TYPE_MODE (type)); create_output_operand (&ops[0], target, TYPE_MODE (type)); create_fixed_operand (&ops[1], mem); expand_insn (get_multi_vector_move (type, vec_load_lanes_optab), 2, ops); } /* Expand STORE_LANES call STMT. */ static void expand_STORE_LANES (gimple stmt) { struct expand_operand ops[2]; tree type, lhs, rhs; rtx target, reg; lhs = gimple_call_lhs (stmt); rhs = gimple_call_arg (stmt, 0); type = TREE_TYPE (rhs); target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); reg = expand_normal (rhs); gcc_assert (MEM_P (target)); PUT_MODE (target, TYPE_MODE (type)); create_fixed_operand (&ops[0], target); create_input_operand (&ops[1], reg, TYPE_MODE (type)); expand_insn (get_multi_vector_move (type, vec_store_lanes_optab), 2, ops); } /* Routines to expand each internal function, indexed by function number. Each routine has the prototype: expand_ (gimple stmt) where STMT is the statement that performs the call. */ static void (*const internal_fn_expanders[]) (gimple) = { #define DEF_INTERNAL_FN(CODE, FLAGS) expand_##CODE, #include "internal-fn.def" #undef DEF_INTERNAL_FN 0 }; /* Expand STMT, which is a call to internal function FN. */ void expand_internal_call (gimple stmt) { internal_fn_expanders[(int) gimple_call_internal_fn (stmt)] (stmt); }