From 7a12ea32b2cf7ee53d0c43e26e12eb41e9853db1 Mon Sep 17 00:00:00 2001 From: Monk Chiang Date: Sat, 3 Mar 2018 16:05:25 +0000 Subject: [PATCH] [NDS32] Rewrite infrastructure for intrinsic. gcc/ * config/nds32/nds32-intrinsic.c (nds32_expand_builtin_null_ftype_reg): Delete. (nds32_expand_builtin_reg_ftype_imm): Ditto. (nds32_expand_builtin_null_ftype_reg_imm): Ditto. (nds32_read_argument): New. (nds32_legitimize_target): Ditto. (nds32_legitimize_argument): Ditto. (nds32_check_constant_argument): Ditto. (nds32_expand_unop_builtin): Ditto. (nds32_expand_unopimm_builtin): Ditto. (nds32_expand_binop_builtin): Ditto. (nds32_builtin_decl_impl): Ditto. (builtin_description): Ditto. (nds32_expand_builtin_impl): Rewrite with new infrastructure. (nds32_init_builtins_impl): Ditto. * config/nds32/nds32.c (TARGET_BUILTIN_DECL): Define. (nds32_builtin_decl): New. * config/nds32/nds32.h (nds32_builtins): Add NDS32_BUILTIN_COUNT. * config/nds32/nds32-protos.h (nds32_builtin_decl_impl): Declare. Co-Authored-By: Chung-Ju Wu Co-Authored-By: Kito Cheng From-SVN: r258211 --- gcc/ChangeLog | 24 ++ gcc/config/nds32/nds32-intrinsic.c | 413 +++++++++++++++++++---------- gcc/config/nds32/nds32-protos.h | 1 + gcc/config/nds32/nds32.c | 10 + gcc/config/nds32/nds32.h | 3 +- 5 files changed, 312 insertions(+), 139 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ef804524f45..e5aa19d0022 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2018-03-03 Monk Chiang + Kito Cheng + Chung-Ju Wu + + * config/nds32/nds32-intrinsic.c + (nds32_expand_builtin_null_ftype_reg): Delete. + (nds32_expand_builtin_reg_ftype_imm): Ditto. + (nds32_expand_builtin_null_ftype_reg_imm): Ditto. + (nds32_read_argument): New. + (nds32_legitimize_target): Ditto. + (nds32_legitimize_argument): Ditto. + (nds32_check_constant_argument): Ditto. + (nds32_expand_unop_builtin): Ditto. + (nds32_expand_unopimm_builtin): Ditto. + (nds32_expand_binop_builtin): Ditto. + (nds32_builtin_decl_impl): Ditto. + (builtin_description): Ditto. + (nds32_expand_builtin_impl): Rewrite with new infrastructure. + (nds32_init_builtins_impl): Ditto. + * config/nds32/nds32.c (TARGET_BUILTIN_DECL): Define. + (nds32_builtin_decl): New. + * config/nds32/nds32.h (nds32_builtins): Add NDS32_BUILTIN_COUNT. + * config/nds32/nds32-protos.h (nds32_builtin_decl_impl): Declare. + 2018-03-02 Jeff Law * reorg.c (stop_search_p): Handle DEBUG_INSN. diff --git a/gcc/config/nds32/nds32-intrinsic.c b/gcc/config/nds32/nds32-intrinsic.c index 5a1b92d604c..ad744c846e0 100644 --- a/gcc/config/nds32/nds32-intrinsic.c +++ b/gcc/config/nds32/nds32-intrinsic.c @@ -28,6 +28,8 @@ #include "backend.h" #include "target.h" #include "rtl.h" +#include "memmodel.h" +#include "emit-rtl.h" #include "tree.h" #include "memmodel.h" #include "optabs.h" /* For GEN_FCN. */ @@ -35,202 +37,337 @@ #include "stor-layout.h" #include "expr.h" #include "langhooks.h" /* For add_builtin_function(). */ +#include "recog.h" +#include "explow.h" /* ------------------------------------------------------------------------ */ -/* Function to expand builtin function for - '[(unspec_volatile [(reg)])]'. */ +/* Read the requested argument from the EXP given by INDEX. + Return the value as an rtx. */ static rtx -nds32_expand_builtin_null_ftype_reg (enum insn_code icode, - tree exp, rtx target) +nds32_read_argument (tree exp, unsigned int index) { - /* Mapping: - ops[0] <--> value0 <--> arg0 */ - struct expand_operand ops[1]; - tree arg0; - rtx value0; + return expand_normal (CALL_EXPR_ARG (exp, index)); +} - /* Grab the incoming arguments and extract its rtx. */ - arg0 = CALL_EXPR_ARG (exp, 0); - value0 = expand_normal (arg0); +/* Return a legitimate rtx for instruction ICODE's return value. Use TARGET + if it's not null, has the right mode, and satisfies operand 0's + predicate. */ +static rtx +nds32_legitimize_target (enum insn_code icode, rtx target) +{ + enum machine_mode mode = insn_data[icode].operand[0].mode; + + if (! target + || GET_MODE (target) != mode + || ! (*insn_data[icode].operand[0].predicate) (target, mode)) + return gen_reg_rtx (mode); + else + return target; +} - /* Create operands. */ - create_input_operand (&ops[0], value0, TYPE_MODE (TREE_TYPE (arg0))); +/* Given that ARG is being passed as operand OPNUM to instruction ICODE, + check whether ARG satisfies the operand's constraints. If it doesn't, + copy ARG to a temporary register and return that. Otherwise return ARG + itself. */ +static rtx +nds32_legitimize_argument (enum insn_code icode, int opnum, rtx arg) +{ + enum machine_mode mode = insn_data[icode].operand[opnum].mode; - /* Emit new instruction. */ - if (!maybe_expand_insn (icode, 1, ops)) - error ("invalid argument to built-in function"); + if ((*insn_data[icode].operand[opnum].predicate) (arg, mode)) + return arg; + else if (VECTOR_MODE_P (mode) && CONST_INT_P (arg)) + { + /* Handle CONST_INT covert to CONST_VECTOR. */ + int nunits = GET_MODE_NUNITS (mode); + int i, shift = 0; + rtvec v = rtvec_alloc (nunits); + int val = INTVAL (arg); + enum machine_mode val_mode = (mode == V4QImode) ? QImode : HImode; + int shift_acc = (val_mode == QImode) ? 8 : 16; + int mask = (val_mode == QImode) ? 0xff : 0xffff; + int tmp_val = val; + + if (TARGET_BIG_ENDIAN) + for (i = 0; i < nunits; i++) + { + tmp_val = (val >> shift) & mask; + RTVEC_ELT (v, nunits - i - 1) = gen_int_mode (tmp_val, val_mode); + shift += shift_acc; + } + else + for (i = 0; i < nunits; i++) + { + tmp_val = (val >> shift) & mask; + RTVEC_ELT (v, i) = gen_int_mode (tmp_val, val_mode); + shift += shift_acc; + } + + return copy_to_mode_reg (mode, gen_rtx_CONST_VECTOR (mode, v)); + } + else + { + rtx tmp_rtx = gen_reg_rtx (mode); + convert_move (tmp_rtx, arg, false); + return tmp_rtx; + } +} - return target; +/* Return true if OPVAL can be used for operand OPNUM of instruction ICODE. + The instruction should require a constant operand of some sort. The + function prints an error if OPVAL is not valid. */ +static int +nds32_check_constant_argument (enum insn_code icode, int opnum, rtx opval, + const char *name) +{ + if (GET_CODE (opval) != CONST_INT) + { + error ("invalid argument to built-in function %s", name); + return false; + } + if (! (*insn_data[icode].operand[opnum].predicate) (opval, VOIDmode)) + { + error ("constant argument out of range for %s", name); + + return false; + } + return true; } -/* Function to expand builtin function for - '[(set (reg) (unspec_volatile [(imm)]))]'. */ +/* Expand builtins that take one operand. */ static rtx -nds32_expand_builtin_reg_ftype_imm (enum insn_code icode, - tree exp, rtx target) +nds32_expand_unop_builtin (enum insn_code icode, tree exp, rtx target, + bool return_p) { - /* Mapping: - ops[0] <--> target <--> exp - ops[1] <--> value0 <--> arg0 */ - struct expand_operand ops[2]; - tree arg0; - rtx value0; + rtx pat; + rtx op0 = nds32_read_argument (exp, 0); + int op0_num = return_p ? 1 : 0; + + if (return_p) + target = nds32_legitimize_target (icode, target); - /* Grab the incoming arguments and extract its rtx. */ - arg0 = CALL_EXPR_ARG (exp, 0); - value0 = expand_normal (arg0); + op0 = nds32_legitimize_argument (icode, op0_num, op0); - /* 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 and return the new instruction. */ + if (return_p) + pat = GEN_FCN (icode) (target, op0); + else + pat = GEN_FCN (icode) (op0); - /* Emit new instruction. */ - if (!maybe_expand_insn (icode, 2, ops)) - error ("invalid argument to built-in function"); + if (! pat) + return NULL_RTX; + emit_insn (pat); return target; } -/* Function to expand builtin function for - '[(unspec_volatile [(reg) (imm)])]' pattern. */ +/* Expand builtins that take one operands and the first is immediate. */ static rtx -nds32_expand_builtin_null_ftype_reg_imm (enum insn_code icode, - tree exp, rtx target) +nds32_expand_unopimm_builtin (enum insn_code icode, tree exp, rtx target, + bool return_p, const char *name) { - /* 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"); + rtx pat; + rtx op0 = nds32_read_argument (exp, 0); + int op0_num = return_p ? 1 : 0; + + if (return_p) + target = nds32_legitimize_target (icode, target); + + if (!nds32_check_constant_argument (icode, op0_num, op0, name)) + return NULL_RTX; + + op0 = nds32_legitimize_argument (icode, op0_num, op0); + + /* Emit and return the new instruction. */ + if (return_p) + pat = GEN_FCN (icode) (target, op0); + else + pat = GEN_FCN (icode) (op0); + if (! pat) + return NULL_RTX; + + emit_insn (pat); return target; } -/* ------------------------------------------------------------------------ */ - -void -nds32_init_builtins_impl (void) +/* Expand builtins that take two operands. */ +static rtx +nds32_expand_binop_builtin (enum insn_code icode, tree exp, rtx target, + bool return_p) { - tree pointer_type_node = build_pointer_type (integer_type_node); + rtx pat; + rtx op0 = nds32_read_argument (exp, 0); + rtx op1 = nds32_read_argument (exp, 1); + int op0_num = return_p ? 1 : 0; + int op1_num = return_p ? 2 : 1; - tree void_ftype_void = build_function_type (void_type_node, - void_list_node); + if (return_p) + target = nds32_legitimize_target (icode, target); - tree void_ftype_pint = build_function_type_list (void_type_node, - pointer_type_node, - NULL_TREE); + op0 = nds32_legitimize_argument (icode, op0_num, op0); + op1 = nds32_legitimize_argument (icode, op1_num, op1); - tree int_ftype_int = build_function_type_list (integer_type_node, - integer_type_node, - NULL_TREE); + /* Emit and return the new instruction. */ + if (return_p) + pat = GEN_FCN (icode) (target, op0, op1); + else + pat = GEN_FCN (icode) (op0, op1); - tree void_ftype_int_int = build_function_type_list (void_type_node, - integer_type_node, - integer_type_node, - NULL_TREE); + if (! pat) + return NULL_RTX; - /* 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); + emit_insn (pat); + return target; +} - /* 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); +struct builtin_description +{ + const enum insn_code icode; + const char *name; + enum nds32_builtins code; + bool return_p; +}; + +#define NDS32_BUILTIN(code, string, builtin) \ + { CODE_FOR_##code, "__nds32__" string, \ + NDS32_BUILTIN_##builtin, true }, + +#define NDS32_NO_TARGET_BUILTIN(code, string, builtin) \ + { CODE_FOR_##code, "__nds32__" string, \ + NDS32_BUILTIN_##builtin, false }, + +/* Intrinsics that take just one argument. */ +static struct builtin_description bdesc_1arg[] = +{ + NDS32_NO_TARGET_BUILTIN(unspec_volatile_isync, "isync", ISYNC) +}; - /* 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); -} +/* Intrinsics that take just one argument. and the argument is immediate. */ +static struct builtin_description bdesc_1argimm[] = +{ + NDS32_BUILTIN(unspec_volatile_mfsr, "mfsr", MFSR) + NDS32_BUILTIN(unspec_volatile_mfusr, "mfsr", MFUSR) +}; +/* Intrinsics that take two arguments. */ +static struct builtin_description bdesc_2arg[] = +{ + NDS32_NO_TARGET_BUILTIN(unspec_volatile_mtsr, "mtsr", MTSR) + NDS32_NO_TARGET_BUILTIN(unspec_volatile_mtusr, "mtusr", MTUSR) +}; rtx nds32_expand_builtin_impl (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, - machine_mode mode ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) { tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + unsigned int fcode = DECL_FUNCTION_CODE (fndecl); + unsigned i; + struct builtin_description *d; - int fcode = DECL_FUNCTION_CODE (fndecl); - + /* Since there are no result and operands, we can simply emit this rtx. */ 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 (); + break; } + /* Expand groups of builtins. */ + for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++) + if (d->code == fcode) + return nds32_expand_unop_builtin (d->icode, exp, target, d->return_p); + + for (i = 0, d = bdesc_1argimm; i < ARRAY_SIZE (bdesc_1argimm); i++, d++) + if (d->code == fcode) + return nds32_expand_unopimm_builtin (d->icode, exp, target, + d->return_p, d->name); + + for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++) + if (d->code == fcode) + return nds32_expand_binop_builtin (d->icode, exp, target, d->return_p); + + return NULL_RTX; } -/* ------------------------------------------------------------------------ */ +static GTY(()) tree nds32_builtin_decls[NDS32_BUILTIN_COUNT]; + +/* Return the NDS32 builtin for CODE. */ +tree +nds32_builtin_decl_impl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) +{ + if (code >= NDS32_BUILTIN_COUNT) + return error_mark_node; + + return nds32_builtin_decls[code]; +} + +void +nds32_init_builtins_impl (void) +{ +#define ADD_NDS32_BUILTIN0(NAME, RET_TYPE, CODE) \ + nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \ + add_builtin_function ("__builtin_nds32_" NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + NULL_TREE), \ + NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE) + +#define ADD_NDS32_BUILTIN1(NAME, RET_TYPE, ARG_TYPE, CODE) \ + nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \ + add_builtin_function ("__builtin_nds32_" NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE##_type_node, \ + NULL_TREE), \ + NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE) + +#define ADD_NDS32_BUILTIN2(NAME, RET_TYPE, ARG_TYPE1, ARG_TYPE2, CODE) \ + nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \ + add_builtin_function ("__builtin_nds32_" NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE1##_type_node,\ + ARG_TYPE2##_type_node,\ + NULL_TREE), \ + NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE) + +#define ADD_NDS32_BUILTIN3(NAME, RET_TYPE, \ + ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, CODE) \ + nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \ + add_builtin_function ("__builtin_nds32_" NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE1##_type_node,\ + ARG_TYPE2##_type_node,\ + ARG_TYPE3##_type_node,\ + NULL_TREE), \ + NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE) + + /* Looking for return type and argument can be found in tree.h file. */ + tree ptr_uint_type_node = build_pointer_type (unsigned_type_node); + + /* Cache. */ + ADD_NDS32_BUILTIN1 ("isync", void, ptr_uint, ISYNC); + ADD_NDS32_BUILTIN0 ("isb", void, ISB); + + /* Register Transfer. */ + ADD_NDS32_BUILTIN1 ("mfsr", unsigned, integer, MFSR); + ADD_NDS32_BUILTIN1 ("mfusr", unsigned, integer, MFUSR); + ADD_NDS32_BUILTIN2 ("mtsr", void, unsigned, integer, MTSR); + ADD_NDS32_BUILTIN2 ("mtusr", void, unsigned, integer, MTUSR); + + /* Interrupt. */ + ADD_NDS32_BUILTIN0 ("setgie_en", void, SETGIE_EN); + ADD_NDS32_BUILTIN0 ("setgie_dis", void, SETGIE_DIS); +} diff --git a/gcc/config/nds32/nds32-protos.h b/gcc/config/nds32/nds32-protos.h index 75496135880..a989c3f0d23 100644 --- a/gcc/config/nds32/nds32-protos.h +++ b/gcc/config/nds32/nds32-protos.h @@ -125,6 +125,7 @@ extern int nds32_target_alignment (rtx_insn *); extern void nds32_init_builtins_impl (void); extern rtx nds32_expand_builtin_impl (tree, rtx, rtx, machine_mode, int); +extern tree nds32_builtin_decl_impl (unsigned, bool); /* Auxiliary functions for ISR implementation. */ diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c index 08331f324a4..085a7b86ade 100644 --- a/gcc/config/nds32/nds32.c +++ b/gcc/config/nds32/nds32.c @@ -2728,6 +2728,13 @@ nds32_init_builtins (void) nds32_init_builtins_impl (); } +static tree +nds32_builtin_decl (unsigned code, bool initialize_p) +{ + /* Implement in nds32-intrinsic.c. */ + return nds32_builtin_decl_impl (code, initialize_p); +} + static rtx nds32_expand_builtin (tree exp, rtx target, @@ -3825,6 +3832,9 @@ nds32_target_alignment (rtx_insn *label) #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS nds32_init_builtins +#undef TARGET_BUILTIN_DECL +#define TARGET_BUILTIN_DECL nds32_builtin_decl + #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN nds32_expand_builtin diff --git a/gcc/config/nds32/nds32.h b/gcc/config/nds32/nds32.h index 66f692a70fb..5b33e3cc450 100644 --- a/gcc/config/nds32/nds32.h +++ b/gcc/config/nds32/nds32.h @@ -345,7 +345,8 @@ enum nds32_builtins NDS32_BUILTIN_MTSR, NDS32_BUILTIN_MTUSR, NDS32_BUILTIN_SETGIE_EN, - NDS32_BUILTIN_SETGIE_DIS + NDS32_BUILTIN_SETGIE_DIS, + NDS32_BUILTIN_COUNT }; /* ------------------------------------------------------------------------ */ -- 2.30.2