diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b3c3a529003..f392069de66 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2004-09-27 Devang Patel + + * expr.c (expand_expr_real_1): Handle VEC_COND_EXPR. + * genopinit.c (optabs): New entry for vcond_gen_code and + vcondu_gen_code. + * optabs.c (vcond_gen_code, vcondu_gen_code): New optabs. + (get_rtx_code): New function. + (vector_compare_rtx): New function. + (init_optabs): Initialize vcond_gen_code and vcondu_gen_code. + (expand_vec_cond_expr_p): New function. + (expand_vec_cond_expr): New function. + (get_vcond_icode): New function. + * optabs.h (expand_vec_cond_expr, expand_vec_cond_expr_p): New externs. + (vcond_gen_code, vcondu_gen_code): Same. + 2004-09-27 Kelley Cook * Makefile.in (STAGESTUFF): Split into ... @@ -45,7 +60,6 @@ * tree-pretty-print.c (dump_generic_node): Print VEC_COND_EXPR. (print_call_name): Do not print VEC_COND_EXPR. - 2004-09-27 Devang Patel diff --git a/gcc/expr.c b/gcc/expr.c index 96cab626f7b..ff8355bc738 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8053,6 +8053,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, OK_DEFER_POP; return temp; + case VEC_COND_EXPR: + target = expand_vec_cond_expr (exp, target); + return target; + case MODIFY_EXPR: { /* If lhs is complex, expand calls in rhs before computing it. diff --git a/gcc/genopinit.c b/gcc/genopinit.c index 0d39f67ef75..8c6c8feb292 100644 --- a/gcc/genopinit.c +++ b/gcc/genopinit.c @@ -171,7 +171,9 @@ static const char * const optabs[] = "vec_extract_optab->handlers[$A].insn_code = CODE_FOR_$(vec_extract$a$)", "vec_init_optab->handlers[$A].insn_code = CODE_FOR_$(vec_init$a$)", "vec_realign_store_optab->handlers[$A].insn_code = CODE_FOR_$(vec_realign_store_$a$)", - "vec_realign_load_optab->handlers[$A].insn_code = CODE_FOR_$(vec_realign_load_$a$)" }; + "vec_realign_load_optab->handlers[$A].insn_code = CODE_FOR_$(vec_realign_load_$a$)", + "vcond_gen_code[$A] = CODE_FOR_$(vcond$a$)", + "vcondu_gen_code[$A] = CODE_FOR_$(vcondu$a$)" }; static void gen_insn (rtx); diff --git a/gcc/optabs.c b/gcc/optabs.c index abb69700a04..8354f7878fc 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -84,6 +84,12 @@ enum insn_code setcc_gen_code[NUM_RTX_CODE]; enum insn_code movcc_gen_code[NUM_MACHINE_MODES]; #endif +/* Indexed by the machine mode, gives the insn code for vector conditional + operation. */ + +enum insn_code vcond_gen_code[NUM_MACHINE_MODES]; +enum insn_code vcondu_gen_code[NUM_MACHINE_MODES]; + /* The insn generating function can not take an rtx_code argument. TRAP_RTX is used as an rtx argument. Its code is replaced with the code to be used in the trap insn and all other fields are ignored. */ @@ -116,6 +122,8 @@ static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *, enum machine_mode *, int *); static rtx widen_clz (enum machine_mode, rtx, rtx); static rtx expand_parity (enum machine_mode, rtx, rtx); +static enum rtx_code get_rtx_code (enum tree_code, bool); +static rtx vector_compare_rtx (tree, bool, enum insn_code); #ifndef HAVE_conditional_trap #define HAVE_conditional_trap 0 @@ -2982,7 +2990,6 @@ can_compare_p (enum rtx_code code, enum machine_mode mode, if (purpose == ccp_store_flag && cstore_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) return 1; - mode = GET_MODE_WIDER_MODE (mode); } while (mode != VOIDmode); @@ -4649,6 +4656,12 @@ init_optabs (void) movcc_gen_code[i] = CODE_FOR_nothing; #endif + for (i = 0; i < NUM_MACHINE_MODES; i++) + { + vcond_gen_code[i] = CODE_FOR_nothing; + vcondu_gen_code[i] = CODE_FOR_nothing; + } + add_optab = init_optab (PLUS); addv_optab = init_optabv (PLUS); sub_optab = init_optab (MINUS); @@ -4992,4 +5005,168 @@ gen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1, return insn; } +/* Return rtx code for TCODE. Use UNSIGNEDP to select signed + or unsigned operation code. */ + +static enum rtx_code +get_rtx_code (enum tree_code tcode, bool unsignedp) +{ + enum rtx_code code; + switch (tcode) + { + case EQ_EXPR: + code = EQ; + break; + case NE_EXPR: + code = NE; + break; + case LT_EXPR: + code = unsignedp ? LTU : LT; + break; + case LE_EXPR: + code = unsignedp ? LEU : LE; + break; + case GT_EXPR: + code = unsignedp ? GTU : GT; + break; + case GE_EXPR: + code = unsignedp ? GEU : GE; + break; + + case UNORDERED_EXPR: + code = UNORDERED; + break; + case ORDERED_EXPR: + code = ORDERED; + break; + case UNLT_EXPR: + code = UNLT; + break; + case UNLE_EXPR: + code = UNLE; + break; + case UNGT_EXPR: + code = UNGT; + break; + case UNGE_EXPR: + code = UNGE; + break; + case UNEQ_EXPR: + code = UNEQ; + break; + case LTGT_EXPR: + code = LTGT; + break; + + default: + abort (); + } + return code; +} + +/* Return comparison rtx for COND. Use UNSIGNEDP to select signed or + unsigned operators. Do not generate compare instruction. */ + +static rtx +vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode) +{ + enum rtx_code rcode; + tree t_op0, t_op1; + rtx rtx_op0, rtx_op1; + + if (TREE_CODE_CLASS (TREE_CODE (cond)) != '<') + { + /* This is unlikely. While generating VEC_COND_EXPR, + auto vectorizer ensures that condition is a relational + operation. */ + abort (); + } + else + { + rcode = get_rtx_code (TREE_CODE (cond), unsignedp); + t_op0 = TREE_OPERAND (cond, 0); + t_op1 = TREE_OPERAND (cond, 1); + } + + /* Expand operands. */ + rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)), 1); + rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)), 1); + + if (!(*insn_data[icode].operand[4].predicate) (rtx_op0, GET_MODE (rtx_op0)) + && GET_MODE (rtx_op0) != VOIDmode) + rtx_op0 = force_reg (GET_MODE (rtx_op0), rtx_op0); + + if (!(*insn_data[icode].operand[5].predicate) (rtx_op1, GET_MODE (rtx_op1)) + && GET_MODE (rtx_op1) != VOIDmode) + rtx_op1 = force_reg (GET_MODE (rtx_op1), rtx_op1); + + return gen_rtx_fmt_ee (rcode, VOIDmode, rtx_op0, rtx_op1); +} + +/* Return insn code for VEC_COND_EXPR EXPR. */ + +static inline enum insn_code +get_vcond_icode (tree expr, enum machine_mode mode) +{ + enum insn_code icode = CODE_FOR_nothing; + + if (TYPE_UNSIGNED (TREE_TYPE (expr))) + icode = vcondu_gen_code[mode]; + else + icode = vcond_gen_code[mode]; + return icode; +} + +/* Return TRUE iff, appropriate vector insns are available + for vector cond expr expr in VMODE mode. */ + +bool +expand_vec_cond_expr_p (tree expr, enum machine_mode vmode) +{ + if (get_vcond_icode (expr, vmode) == CODE_FOR_nothing) + return false; + return true; +} + +/* Generate insns for VEC_COND_EXPR. */ + +rtx +expand_vec_cond_expr (tree vec_cond_expr, rtx target) +{ + enum insn_code icode; + rtx comparison, rtx_op1, rtx_op2, cc_op0, cc_op1; + enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_cond_expr)); + bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (vec_cond_expr)); + + icode = get_vcond_icode (vec_cond_expr, mode); + if (icode == CODE_FOR_nothing) + return 0; + + if (!target) + target = gen_reg_rtx (mode); + + /* Get comparision rtx. First expand both cond expr operands. */ + comparison = vector_compare_rtx (TREE_OPERAND (vec_cond_expr, 0), + unsignedp, icode); + cc_op0 = XEXP (comparison, 0); + cc_op1 = XEXP (comparison, 1); + /* Expand both operands and force them in reg, if required. */ + rtx_op1 = expand_expr (TREE_OPERAND (vec_cond_expr, 1), + NULL_RTX, VOIDmode, 1); + if (!(*insn_data[icode].operand[1].predicate) (rtx_op1, mode) + && mode != VOIDmode) + rtx_op1 = force_reg (mode, rtx_op1); + + rtx_op2 = expand_expr (TREE_OPERAND (vec_cond_expr, 2), + NULL_RTX, VOIDmode, 1); + if (!(*insn_data[icode].operand[2].predicate) (rtx_op2, mode) + && mode != VOIDmode) + rtx_op2 = force_reg (mode, rtx_op2); + + /* Emit instruction! */ + emit_insn (GEN_FCN (icode) (target, rtx_op1, rtx_op2, + comparison, cc_op0, cc_op1)); + + return target; +} #include "gt-optabs.h" diff --git a/gcc/optabs.h b/gcc/optabs.h index 8e895f203c5..68be8d35e7f 100644 --- a/gcc/optabs.h +++ b/gcc/optabs.h @@ -398,6 +398,12 @@ extern enum insn_code setcc_gen_code[NUM_RTX_CODE]; extern enum insn_code movcc_gen_code[NUM_MACHINE_MODES]; #endif +/* Indexed by the machine mode, gives the insn code for vector conditional + operation. */ + +extern enum insn_code vcond_gen_code[NUM_MACHINE_MODES]; +extern enum insn_code vcondu_gen_code[NUM_MACHINE_MODES]; + /* This array records the insn_code of insns to perform block moves. */ extern enum insn_code movmem_optab[NUM_MACHINE_MODES]; @@ -498,4 +504,10 @@ extern void expand_float (rtx, rtx, int); /* Generate code for a FIX_EXPR. */ extern void expand_fix (rtx, rtx, int); +/* Return tree if target supports vector operatiosn for COND_EXPR. */ +bool expand_vec_cond_expr_p (tree, enum machine_mode); + +/* Generate code for VEC_COND_EXPR. */ +extern rtx expand_vec_cond_expr (tree, rtx); + #endif /* GCC_OPTABS_H */