This patch merges the tree functions that handled builtins with one, two, three arguments to one function.
Code is clearer and smaller if the arguments are handled in a loop instead of hand-unrolled loops as with the old functions. Ok for trunk? Johann * config/avr/avr.c (avr_default_expand_builtin): New function. (avr_expand_builtin): Use it. (avr_expand_unop_builtin): Remove. (avr_expand_binop_builtin): Remove. (avr_expand_triop_builtin): Remove.
Index: config/avr/avr.c =================================================================== --- config/avr/avr.c (revision 188267) +++ config/avr/avr.c (working copy) @@ -10389,170 +10389,64 @@ avr_init_builtins (void) } -/* Subroutine of avr_expand_builtin to take care of unop insns. */ +/* Subroutine of avr_expand_builtin to expand vanilla builtins + with non-void result and 1 ... 3 arguments. */ static rtx -avr_expand_unop_builtin (enum insn_code icode, tree exp, - rtx target) +avr_default_expand_builtin (enum insn_code icode, tree exp, rtx target) { - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - enum machine_mode op0mode = GET_MODE (op0); + rtx pat, xop[3]; + int n, n_args = call_expr_nargs (exp); enum machine_mode tmode = insn_data[icode].operand[0].mode; - enum machine_mode mode0 = insn_data[icode].operand[1].mode; - if (! target + gcc_assert (n_args >= 1 && n_args <= 3); + + if (target == NULL_RTX || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + || !insn_data[icode].operand[0].predicate (target, tmode)) { target = gen_reg_rtx (tmode); } - if (op0mode == SImode && mode0 == HImode) + for (n = 0; n < n_args; n++) { - op0mode = HImode; - op0 = gen_lowpart (HImode, op0); - } - - gcc_assert (op0mode == mode0 || op0mode == VOIDmode); + tree arg = CALL_EXPR_ARG (exp, n); + rtx op = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL); + enum machine_mode opmode = GET_MODE (op); + enum machine_mode mode = insn_data[icode].operand[n+1].mode; - if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); + if ((opmode == SImode || opmode == VOIDmode) && mode == HImode) + { + opmode = HImode; + op = gen_lowpart (HImode, op); + } - pat = GEN_FCN (icode) (target, op0); - if (! pat) - return 0; - - emit_insn (pat); + /* In case the insn wants input operands in modes different from + the result, abort. */ - return target; -} - - -/* Subroutine of avr_expand_builtin to take care of binop insns. */ + gcc_assert (opmode == mode || opmode == VOIDmode); -static rtx -avr_expand_binop_builtin (enum insn_code icode, tree exp, rtx target) -{ - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - tree arg1 = CALL_EXPR_ARG (exp, 1); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL); - enum machine_mode op0mode = GET_MODE (op0); - enum machine_mode op1mode = GET_MODE (op1); - enum machine_mode tmode = insn_data[icode].operand[0].mode; - enum machine_mode mode0 = insn_data[icode].operand[1].mode; - enum machine_mode mode1 = insn_data[icode].operand[2].mode; + if (!insn_data[icode].operand[n+1].predicate (op, mode)) + op = copy_to_mode_reg (mode, op); - if (! target - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - { - target = gen_reg_rtx (tmode); + xop[n] = op; } - if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode) + switch (n_args) { - op0mode = HImode; - op0 = gen_lowpart (HImode, op0); - } - - if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode) - { - op1mode = HImode; - op1 = gen_lowpart (HImode, op1); - } - - /* In case the insn wants input operands in modes different from - the result, abort. */ - - gcc_assert ((op0mode == mode0 || op0mode == VOIDmode) - && (op1mode == mode1 || op1mode == VOIDmode)); - - if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - - if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - - pat = GEN_FCN (icode) (target, op0, op1); - - if (! pat) - return 0; + case 1: pat = GEN_FCN (icode) (target, xop[0]); break; + case 2: pat = GEN_FCN (icode) (target, xop[0], xop[1]); break; + case 3: pat = GEN_FCN (icode) (target, xop[0], xop[1], xop[2]); break; - emit_insn (pat); - return target; -} - -/* Subroutine of avr_expand_builtin to take care of 3-operand insns. */ - -static rtx -avr_expand_triop_builtin (enum insn_code icode, tree exp, rtx target) -{ - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - tree arg1 = CALL_EXPR_ARG (exp, 1); - tree arg2 = CALL_EXPR_ARG (exp, 2); - rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL); - rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, EXPAND_NORMAL); - enum machine_mode op0mode = GET_MODE (op0); - enum machine_mode op1mode = GET_MODE (op1); - enum machine_mode op2mode = GET_MODE (op2); - enum machine_mode tmode = insn_data[icode].operand[0].mode; - enum machine_mode mode0 = insn_data[icode].operand[1].mode; - enum machine_mode mode1 = insn_data[icode].operand[2].mode; - enum machine_mode mode2 = insn_data[icode].operand[3].mode; - - if (! target - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - { - target = gen_reg_rtx (tmode); - } - - if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode) - { - op0mode = HImode; - op0 = gen_lowpart (HImode, op0); + default: + gcc_unreachable(); } - if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode) - { - op1mode = HImode; - op1 = gen_lowpart (HImode, op1); - } - - if ((op2mode == SImode || op2mode == VOIDmode) && mode2 == HImode) - { - op2mode = HImode; - op2 = gen_lowpart (HImode, op2); - } - - /* In case the insn wants input operands in modes different from - the result, abort. */ - - gcc_assert ((op0mode == mode0 || op0mode == VOIDmode) - && (op1mode == mode1 || op1mode == VOIDmode) - && (op2mode == mode2 || op2mode == VOIDmode)); - - if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - - if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - - if (! (*insn_data[icode].operand[3].predicate) (op2, mode2)) - op2 = copy_to_mode_reg (mode2, op2); - - pat = GEN_FCN (icode) (target, op0, op1, op2); - - if (! pat) - return 0; + if (pat == NULL_RTX) + return NULL_RTX; emit_insn (pat); + return target; } @@ -10571,7 +10465,7 @@ avr_expand_builtin (tree exp, rtx target int ignore ATTRIBUTE_UNUSED) { tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - const char* bname = IDENTIFIER_POINTER (DECL_NAME (fndecl)); + const char *bname = IDENTIFIER_POINTER (DECL_NAME (fndecl)); unsigned int id = DECL_FUNCTION_CODE (fndecl); const struct avr_builtin_description *d = &avr_bdesc[id]; tree arg0; @@ -10595,7 +10489,7 @@ avr_expand_builtin (tree exp, rtx target else avr_expand_delay_cycles (op0); - return 0; + return NULL_RTX; } case AVR_BUILTIN_INSERT_BITS: @@ -10613,24 +10507,16 @@ avr_expand_builtin (tree exp, rtx target } /* No special treatment needed: vanilla expand. */ - - switch (d->n_args) + + gcc_assert (d->n_args == call_expr_nargs (exp)); + + if (d->n_args == 0) { - case 0: emit_insn ((GEN_FCN (d->icode)) (target)); - return 0; - - case 1: - return avr_expand_unop_builtin (d->icode, exp, target); - - case 2: - return avr_expand_binop_builtin (d->icode, exp, target); - - case 3: - return avr_expand_triop_builtin (d->icode, exp, target); + return NULL_RTX; } - - gcc_unreachable (); + + return avr_default_expand_builtin (d->icode, exp, target); }