| /* Intrinsic functions of Andes NDS32 cpu for GNU compiler |
| Copyright (C) 2012-2015 Free Software Foundation, Inc. |
| Contributed by Andes Technology Corporation. |
| |
| 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 |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* ------------------------------------------------------------------------ */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "hash-set.h" |
| #include "machmode.h" |
| #include "vec.h" |
| #include "double-int.h" |
| #include "input.h" |
| #include "alias.h" |
| #include "symtab.h" |
| #include "wide-int.h" |
| #include "inchash.h" |
| #include "tree.h" |
| #include "stor-layout.h" |
| #include "varasm.h" |
| #include "calls.h" |
| #include "rtl.h" |
| #include "regs.h" |
| #include "hard-reg-set.h" |
| #include "insn-config.h" /* Required by recog.h. */ |
| #include "conditions.h" |
| #include "output.h" |
| #include "insn-attr.h" /* For DFA state_t. */ |
| #include "insn-codes.h" /* For CODE_FOR_xxx. */ |
| #include "reload.h" /* For push_reload(). */ |
| #include "flags.h" |
| #include "function.h" |
| #include "hashtab.h" |
| #include "statistics.h" |
| #include "real.h" |
| #include "fixed-value.h" |
| #include "insn-config.h" |
| #include "expmed.h" |
| #include "dojump.h" |
| #include "explow.h" |
| #include "emit-rtl.h" |
| #include "stmt.h" |
| #include "expr.h" |
| #include "recog.h" |
| #include "diagnostic-core.h" |
| #include "dominance.h" |
| #include "cfg.h" |
| #include "cfgrtl.h" |
| #include "cfganal.h" |
| #include "lcm.h" |
| #include "cfgbuild.h" |
| #include "cfgcleanup.h" |
| #include "predict.h" |
| #include "basic-block.h" |
| #include "df.h" |
| #include "tm_p.h" |
| #include "tm-constrs.h" |
| #include "optabs.h" /* For GEN_FCN. */ |
| #include "target.h" |
| #include "target-def.h" |
| #include "langhooks.h" /* For add_builtin_function(). */ |
| #include "ggc.h" |
| #include "builtins.h" |
| |
| /* ------------------------------------------------------------------------ */ |
| |
| /* Function to expand builtin function for |
| '[(unspec_volatile [(reg)])]'. */ |
| static rtx |
| nds32_expand_builtin_null_ftype_reg (enum insn_code icode, |
| tree exp, rtx target) |
| { |
| /* Mapping: |
| ops[0] <--> value0 <--> arg0 */ |
| struct expand_operand ops[1]; |
| tree arg0; |
| rtx value0; |
| |
| /* Grab the incoming arguments and extract its rtx. */ |
| arg0 = CALL_EXPR_ARG (exp, 0); |
| value0 = expand_normal (arg0); |
| |
| /* Create operands. */ |
| create_input_operand (&ops[0], value0, TYPE_MODE (TREE_TYPE (arg0))); |
| |
| /* Emit new instruction. */ |
| if (!maybe_expand_insn (icode, 1, ops)) |
| error ("invalid argument to built-in function"); |
| |
| return target; |
| } |
| |
| /* Function to expand builtin function for |
| '[(set (reg) (unspec_volatile [(imm)]))]'. */ |
| static rtx |
| nds32_expand_builtin_reg_ftype_imm (enum insn_code icode, |
| tree exp, rtx target) |
| { |
| /* Mapping: |
| ops[0] <--> target <--> exp |
| ops[1] <--> value0 <--> arg0 */ |
| struct expand_operand ops[2]; |
| tree arg0; |
| rtx value0; |
| |
| /* Grab the incoming arguments and extract its rtx. */ |
| arg0 = CALL_EXPR_ARG (exp, 0); |
| value0 = expand_normal (arg0); |
| |
| /* Create operands. */ |
| create_output_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (exp))); |
| create_input_operand (&ops[1], value0, TYPE_MODE (TREE_TYPE (arg0))); |
| |
| /* Emit new instruction. */ |
| if (!maybe_expand_insn (icode, 2, ops)) |
| error ("invalid argument to built-in function"); |
| |
| return target; |
| } |
| |
| /* Function to expand builtin function for |
| '[(unspec_volatile [(reg) (imm)])]' pattern. */ |
| static rtx |
| nds32_expand_builtin_null_ftype_reg_imm (enum insn_code icode, |
| tree exp, rtx target) |
| { |
| /* Mapping: |
| ops[0] <--> value0 <--> arg0 |
| ops[1] <--> value1 <--> arg1 */ |
| struct expand_operand ops[2]; |
| tree arg0, arg1; |
| rtx value0, value1; |
| |
| /* Grab the incoming arguments and extract its rtx. */ |
| arg0 = CALL_EXPR_ARG (exp, 0); |
| arg1 = CALL_EXPR_ARG (exp, 1); |
| value0 = expand_normal (arg0); |
| value1 = expand_normal (arg1); |
| |
| /* Create operands. */ |
| create_input_operand (&ops[0], value0, TYPE_MODE (TREE_TYPE (arg0))); |
| create_input_operand (&ops[1], value1, TYPE_MODE (TREE_TYPE (arg1))); |
| |
| /* Emit new instruction. */ |
| if (!maybe_expand_insn (icode, 2, ops)) |
| error ("invalid argument to built-in function"); |
| |
| return target; |
| } |
| |
| /* ------------------------------------------------------------------------ */ |
| |
| void |
| nds32_init_builtins_impl (void) |
| { |
| tree pointer_type_node = build_pointer_type (integer_type_node); |
| |
| tree void_ftype_void = build_function_type (void_type_node, |
| void_list_node); |
| |
| tree void_ftype_pint = build_function_type_list (void_type_node, |
| pointer_type_node, |
| NULL_TREE); |
| |
| tree int_ftype_int = build_function_type_list (integer_type_node, |
| integer_type_node, |
| NULL_TREE); |
| |
| tree void_ftype_int_int = build_function_type_list (void_type_node, |
| integer_type_node, |
| integer_type_node, |
| NULL_TREE); |
| |
| /* Cache. */ |
| add_builtin_function ("__builtin_nds32_isync", void_ftype_pint, |
| NDS32_BUILTIN_ISYNC, |
| BUILT_IN_MD, NULL, NULL_TREE); |
| add_builtin_function ("__builtin_nds32_isb", void_ftype_void, |
| NDS32_BUILTIN_ISB, |
| BUILT_IN_MD, NULL, NULL_TREE); |
| |
| /* Register Transfer. */ |
| add_builtin_function ("__builtin_nds32_mfsr", int_ftype_int, |
| NDS32_BUILTIN_MFSR, |
| BUILT_IN_MD, NULL, NULL_TREE); |
| add_builtin_function ("__builtin_nds32_mfusr", int_ftype_int, |
| NDS32_BUILTIN_MFUSR, |
| BUILT_IN_MD, NULL, NULL_TREE); |
| add_builtin_function ("__builtin_nds32_mtsr", void_ftype_int_int, |
| NDS32_BUILTIN_MTSR, |
| BUILT_IN_MD, NULL, NULL_TREE); |
| add_builtin_function ("__builtin_nds32_mtusr", void_ftype_int_int, |
| NDS32_BUILTIN_MTUSR, |
| BUILT_IN_MD, NULL, NULL_TREE); |
| |
| /* Interrupt. */ |
| add_builtin_function ("__builtin_nds32_setgie_en", void_ftype_void, |
| NDS32_BUILTIN_SETGIE_EN, |
| BUILT_IN_MD, NULL, NULL_TREE); |
| add_builtin_function ("__builtin_nds32_setgie_dis", void_ftype_void, |
| NDS32_BUILTIN_SETGIE_DIS, |
| BUILT_IN_MD, NULL, NULL_TREE); |
| } |
| |
| |
| rtx |
| nds32_expand_builtin_impl (tree exp, |
| rtx target, |
| rtx subtarget ATTRIBUTE_UNUSED, |
| machine_mode mode ATTRIBUTE_UNUSED, |
| int ignore ATTRIBUTE_UNUSED) |
| { |
| tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); |
| |
| int fcode = DECL_FUNCTION_CODE (fndecl); |
| |
| switch (fcode) |
| { |
| /* Cache. */ |
| case NDS32_BUILTIN_ISYNC: |
| return nds32_expand_builtin_null_ftype_reg |
| (CODE_FOR_unspec_volatile_isync, exp, target); |
| case NDS32_BUILTIN_ISB: |
| /* Since there are no result and operands for isb instruciton, |
| we can simply emit this rtx. */ |
| emit_insn (gen_unspec_volatile_isb ()); |
| return target; |
| |
| /* Register Transfer. */ |
| case NDS32_BUILTIN_MFSR: |
| return nds32_expand_builtin_reg_ftype_imm |
| (CODE_FOR_unspec_volatile_mfsr, exp, target); |
| case NDS32_BUILTIN_MFUSR: |
| return nds32_expand_builtin_reg_ftype_imm |
| (CODE_FOR_unspec_volatile_mfusr, exp, target); |
| case NDS32_BUILTIN_MTSR: |
| return nds32_expand_builtin_null_ftype_reg_imm |
| (CODE_FOR_unspec_volatile_mtsr, exp, target); |
| case NDS32_BUILTIN_MTUSR: |
| return nds32_expand_builtin_null_ftype_reg_imm |
| (CODE_FOR_unspec_volatile_mtusr, exp, target); |
| |
| /* Interrupt. */ |
| case NDS32_BUILTIN_SETGIE_EN: |
| /* Since there are no result and operands for setgie.e instruciton, |
| we can simply emit this rtx. */ |
| emit_insn (gen_unspec_volatile_setgie_en ()); |
| return target; |
| case NDS32_BUILTIN_SETGIE_DIS: |
| /* Since there are no result and operands for setgie.d instruciton, |
| we can simply emit this rtx. */ |
| emit_insn (gen_unspec_volatile_setgie_dis ()); |
| return target; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| return NULL_RTX; |
| } |
| |
| /* ------------------------------------------------------------------------ */ |