+ /* BIT_AND_EXPR is for bitwise anding. TRUTH_AND_EXPR is for anding two
+ boolean values when we want in all cases to compute both of them. In
+ general it is fastest to do TRUTH_AND_EXPR by computing both operands
+ as actual zero-or-1 values and then bitwise anding. In cases where
+ there cannot be any side effects, better code would be made by
+ treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR; but the question is
+ how to recognize those cases. */
+
+ case TRUTH_AND_EXPR:
+ code = BIT_AND_EXPR;
+ case BIT_AND_EXPR:
+ goto binop;
+
+ case TRUTH_OR_EXPR:
+ code = BIT_IOR_EXPR;
+ case BIT_IOR_EXPR:
+ goto binop;
+
+ case TRUTH_XOR_EXPR:
+ code = BIT_XOR_EXPR;
+ case BIT_XOR_EXPR:
+ goto binop;
+
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ gcc_assert (VECTOR_MODE_P (TYPE_MODE (type))
+ || (GET_MODE_PRECISION (TYPE_MODE (type))
+ == TYPE_PRECISION (type)));
+ /* fall through */
+
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ /* If this is a fixed-point operation, then we cannot use the code
+ below because "expand_shift" doesn't support sat/no-sat fixed-point
+ shifts. */
+ if (ALL_FIXED_POINT_MODE_P (mode))
+ goto binop;
+
+ if (! safe_from_p (subtarget, treeop1, 1))
+ subtarget = 0;
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
+ op0 = expand_expr (treeop0, subtarget,
+ VOIDmode, EXPAND_NORMAL);
+ temp = expand_shift (code, mode, op0, treeop1, target,
+ unsignedp);
+ if (code == LSHIFT_EXPR)
+ temp = REDUCE_BIT_FIELD (temp);
+ return temp;
+
+ /* Could determine the answer when only additive constants differ. Also,
+ the addition of one can be handled by changing the condition. */
+ case LT_EXPR:
+ case LE_EXPR:
+ case GT_EXPR:
+ case GE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ case UNEQ_EXPR:
+ case LTGT_EXPR:
+ temp = do_store_flag (ops,
+ modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
+ tmode != VOIDmode ? tmode : mode);
+ if (temp)
+ return temp;
+
+ /* Use a compare and a jump for BLKmode comparisons, or for function
+ type comparisons is HAVE_canonicalize_funcptr_for_compare. */
+
+ if ((target == 0
+ || modifier == EXPAND_STACK_PARM
+ || ! safe_from_p (target, treeop0, 1)
+ || ! safe_from_p (target, treeop1, 1)
+ /* Make sure we don't have a hard reg (such as function's return
+ value) live across basic blocks, if not optimizing. */
+ || (!optimize && REG_P (target)
+ && REGNO (target) < FIRST_PSEUDO_REGISTER)))
+ target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
+
+ emit_move_insn (target, const0_rtx);
+
+ op1 = gen_label_rtx ();
+ jumpifnot_1 (code, treeop0, treeop1, op1, -1);
+
+ emit_move_insn (target, const1_rtx);
+
+ emit_label (op1);
+ return target;
+
+ case TRUTH_NOT_EXPR:
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
+ op0 = expand_expr (treeop0, target,
+ VOIDmode, EXPAND_NORMAL);
+ /* The parser is careful to generate TRUTH_NOT_EXPR
+ only with operands that are always zero or one. */
+ temp = expand_binop (mode, xor_optab, op0, const1_rtx,
+ target, 1, OPTAB_LIB_WIDEN);
+ gcc_assert (temp);
+ return temp;
+
+ case COMPLEX_EXPR:
+ /* Get the rtx code of the operands. */
+ op0 = expand_normal (treeop0);
+ op1 = expand_normal (treeop1);
+
+ if (!target)
+ target = gen_reg_rtx (TYPE_MODE (type));
+
+ /* Move the real (op0) and imaginary (op1) parts to their location. */
+ write_complex_part (target, op0, false);
+ write_complex_part (target, op1, true);
+
+ return target;
+
+ case WIDEN_SUM_EXPR:
+ {
+ tree oprnd0 = treeop0;
+ tree oprnd1 = treeop1;
+
+ expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ target = expand_widen_pattern_expr (ops, op0, NULL_RTX, op1,
+ target, unsignedp);
+ return target;
+ }
+
+ case REDUC_MAX_EXPR:
+ case REDUC_MIN_EXPR:
+ case REDUC_PLUS_EXPR:
+ {
+ op0 = expand_normal (treeop0);
+ this_optab = optab_for_tree_code (code, type, optab_default);
+ temp = expand_unop (mode, this_optab, op0, target, unsignedp);
+ gcc_assert (temp);
+ return temp;
+ }
+
+ case VEC_EXTRACT_EVEN_EXPR:
+ case VEC_EXTRACT_ODD_EXPR:
+ {
+ expand_operands (treeop0, treeop1,
+ NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ this_optab = optab_for_tree_code (code, type, optab_default);
+ temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
+ OPTAB_WIDEN);
+ gcc_assert (temp);
+ return temp;
+ }
+
+ case VEC_INTERLEAVE_HIGH_EXPR:
+ case VEC_INTERLEAVE_LOW_EXPR:
+ {
+ expand_operands (treeop0, treeop1,
+ NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ this_optab = optab_for_tree_code (code, type, optab_default);
+ temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
+ OPTAB_WIDEN);
+ gcc_assert (temp);
+ return temp;
+ }
+
+ case VEC_LSHIFT_EXPR:
+ case VEC_RSHIFT_EXPR:
+ {
+ target = expand_vec_shift_expr (ops, target);
+ return target;
+ }
+
+ case VEC_UNPACK_HI_EXPR:
+ case VEC_UNPACK_LO_EXPR:
+ {
+ op0 = expand_normal (treeop0);
+ this_optab = optab_for_tree_code (code, type, optab_default);
+ temp = expand_widen_pattern_expr (ops, op0, NULL_RTX, NULL_RTX,
+ target, unsignedp);
+ gcc_assert (temp);
+ return temp;
+ }
+
+ case VEC_UNPACK_FLOAT_HI_EXPR:
+ case VEC_UNPACK_FLOAT_LO_EXPR:
+ {
+ op0 = expand_normal (treeop0);
+ /* The signedness is determined from input operand. */
+ this_optab = optab_for_tree_code (code,
+ TREE_TYPE (treeop0),
+ optab_default);
+ temp = expand_widen_pattern_expr
+ (ops, op0, NULL_RTX, NULL_RTX,
+ target, TYPE_UNSIGNED (TREE_TYPE (treeop0)));
+
+ gcc_assert (temp);
+ return temp;
+ }
+
+ case VEC_WIDEN_MULT_HI_EXPR:
+ case VEC_WIDEN_MULT_LO_EXPR:
+ {
+ tree oprnd0 = treeop0;
+ tree oprnd1 = treeop1;
+
+ expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ target = expand_widen_pattern_expr (ops, op0, op1, NULL_RTX,
+ target, unsignedp);
+ gcc_assert (target);
+ return target;
+ }
+
+ case VEC_PACK_TRUNC_EXPR:
+ case VEC_PACK_SAT_EXPR:
+ case VEC_PACK_FIX_TRUNC_EXPR:
+ mode = TYPE_MODE (TREE_TYPE (treeop0));
+ goto binop;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Here to do an ordinary binary operator. */
+ binop:
+ expand_operands (treeop0, treeop1,
+ subtarget, &op0, &op1, EXPAND_NORMAL);
+ binop2:
+ this_optab = optab_for_tree_code (code, type, optab_default);
+ binop3:
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
+ temp = expand_binop (mode, this_optab, op0, op1, target,
+ unsignedp, OPTAB_LIB_WIDEN);
+ gcc_assert (temp);
+ return REDUCE_BIT_FIELD (temp);
+}
+#undef REDUCE_BIT_FIELD
+
+rtx
+expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
+ enum expand_modifier modifier, rtx *alt_rtl)
+{
+ rtx op0, op1, temp, decl_rtl;
+ tree type;
+ int unsignedp;
+ enum machine_mode mode;
+ enum tree_code code = TREE_CODE (exp);
+ optab this_optab;
+ rtx subtarget, original_target;
+ int ignore;
+ tree context;
+ bool reduce_bit_field;
+ location_t loc = EXPR_LOCATION (exp);
+ struct separate_ops ops;
+ tree treeop0, treeop1, treeop2;
+
+ type = TREE_TYPE (exp);
+ mode = TYPE_MODE (type);
+ unsignedp = TYPE_UNSIGNED (type);
+
+ treeop0 = treeop1 = treeop2 = NULL_TREE;
+ if (!VL_EXP_CLASS_P (exp))
+ switch (TREE_CODE_LENGTH (code))
+ {
+ default:
+ case 3: treeop2 = TREE_OPERAND (exp, 2);
+ case 2: treeop1 = TREE_OPERAND (exp, 1);
+ case 1: treeop0 = TREE_OPERAND (exp, 0);
+ case 0: break;
+ }
+ ops.code = code;
+ ops.type = type;
+ ops.op0 = treeop0;
+ ops.op1 = treeop1;
+ ops.op2 = treeop2;
+ ops.location = loc;