blob: 9f0851d9f771acb24510a9f03febbc2aa88b8769 [file] [log] [blame]
/* 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;
}
/* ------------------------------------------------------------------------ */