tree chrec_fold_multiply (tree type, tree op0, tree op1) { if (automatically_generated_chrec_p (op0) || automatically_generated_chrec_p (op1)) return chrec_fold_automatically_generated_operands (op0, op1); switch (TREE_CODE (op0)) { case POLYNOMIAL_CHREC: switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: return chrec_fold_multiply_poly_poly (type, op0, op1); default: if (integer_onep (op1)) return op0; if (integer_zerop (op1)) return build_int_cst_type (type, 0); return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_multiply (type, CHREC_LEFT (op0), op1), chrec_fold_multiply (type, CHREC_RIGHT (op0), op1)); } default: if (integer_onep (op0)) return op1; if (integer_zerop (op0)) return build_int_cst_type (type, 0); switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_multiply (type, CHREC_LEFT (op1), op0), chrec_fold_multiply (type, CHREC_RIGHT (op1), op0)); default: if (integer_onep (op1)) return op0; if (integer_zerop (op1)) return build_int_cst_type (type, 0); return fold (build2 (MULT_EXPR, type, op0, op1)); } } }
static tree build_cst_from_int (tree type, HOST_WIDE_INT low) { if (SCALAR_FLOAT_TYPE_P (type)) return convert (type, build_int_cst (gnat_type_for_size (32, 0), low)); else return build_int_cst_type (type, low); }
/* Return constant CST extended to size type. */ static tree chkp_extend_const (tree cst) { if (TYPE_PRECISION (TREE_TYPE (cst)) < TYPE_PRECISION (size_type_node)) return build_int_cst_type (size_type_node, tree_to_shwi (cst)); return cst; }
static tree build_cst_from_int (tree type, HOST_WIDE_INT low) { if (TREE_CODE (type) == REAL_TYPE) return convert (type, build_int_cst (NULL_TREE, low)); else return build_int_cst_type (type, low); }
static inline tree chrec_fold_multiply_poly_poly (tree type, tree poly0, tree poly1) { /* APPLE LOCAL begin 4233898 */ tree t0, t1, t2; int var; /* APPLE LOCAL end 4233898 */ gcc_assert (poly0); gcc_assert (poly1); gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC); gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC); /* {a, +, b}_1 * {c, +, d}_2 -> {c*{a, +, b}_1, +, d}_2, {a, +, b}_2 * {c, +, d}_1 -> {a*{c, +, d}_1, +, b}_2, {a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */ if (CHREC_VARIABLE (poly0) < CHREC_VARIABLE (poly1)) /* poly0 is a constant wrt. poly1. */ return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_multiply (type, CHREC_LEFT (poly1), poly0), CHREC_RIGHT (poly1)); if (CHREC_VARIABLE (poly1) < CHREC_VARIABLE (poly0)) /* poly1 is a constant wrt. poly0. */ return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_multiply (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); /* poly0 and poly1 are two polynomials in the same variable, {a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */ /* APPLE LOCAL begin 4233898 */ /* "a*c". */ t0 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); /* "a*d + b*c + b*d". */ t1 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_RIGHT (poly1)); t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_LEFT (poly1))); t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1))); /* "2*b*d". */ t2 = chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); t2 = chrec_fold_multiply (type, build_int_cst_type (type, 2), t2); var = CHREC_VARIABLE (poly0); return build_polynomial_chrec (var, t0, build_polynomial_chrec (var, t1, t2)); /* APPLE LOCAL end 4233898 */ }
void gimple_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) { gimple stmt = value->hvalue.stmt; gimple_stmt_iterator gsi = gsi_for_stmt (stmt); tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; gcall *call; tree val; tree start = build_int_cst_type (integer_type_node, value->hdata.intvl.int_start); tree steps = build_int_cst_type (unsigned_type_node, value->hdata.intvl.steps); ref_ptr = force_gimple_operand_gsi (&gsi, build_addr (ref, current_function_decl), true, NULL_TREE, true, GSI_SAME_STMT); val = prepare_instrumented_value (&gsi, value); call = gimple_build_call (tree_interval_profiler_fn, 4, ref_ptr, val, start, steps); gsi_insert_before (&gsi, call, GSI_NEW_STMT); }
static void tree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) { tree stmt = value->hvalue.stmt; block_stmt_iterator bsi = bsi_for_stmt (stmt); tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; tree args, call, val; tree start = build_int_cst_type (integer_type_node, value->hdata.intvl.int_start); tree steps = build_int_cst_type (unsigned_type_node, value->hdata.intvl.steps); ref_ptr = force_gimple_operand_bsi (&bsi, build_addr (ref, current_function_decl), true, NULL_TREE); val = prepare_instrumented_value (&bsi, value); args = tree_cons (NULL_TREE, ref_ptr, tree_cons (NULL_TREE, val, tree_cons (NULL_TREE, start, tree_cons (NULL_TREE, steps, NULL_TREE)))); call = build_function_call_expr (tree_interval_profiler_fn, args); bsi_insert_before (&bsi, call, BSI_SAME_STMT); }
static inline tree chrec_fold_plus_poly_poly (enum tree_code code, tree type, tree poly0, tree poly1) { tree left, right; struct loop *loop0 = get_chrec_loop (poly0); struct loop *loop1 = get_chrec_loop (poly1); tree rtype = code == POINTER_PLUS_EXPR ? chrec_type (poly1) : type; gcc_assert (poly0); gcc_assert (poly1); gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC); gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC); if (POINTER_TYPE_P (chrec_type (poly0))) gcc_checking_assert (ptrofftype_p (chrec_type (poly1)) && useless_type_conversion_p (type, chrec_type (poly0))); else gcc_checking_assert (useless_type_conversion_p (type, chrec_type (poly0)) && useless_type_conversion_p (type, chrec_type (poly1))); /* {a, +, b}_1 + {c, +, d}_2 -> {{a, +, b}_1 + c, +, d}_2, {a, +, b}_2 + {c, +, d}_1 -> {{c, +, d}_1 + a, +, b}_2, {a, +, b}_x + {c, +, d}_x -> {a+c, +, b+d}_x. */ if (flow_loop_nested_p (loop0, loop1)) { if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_plus (type, poly0, CHREC_LEFT (poly1)), CHREC_RIGHT (poly1)); else return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_minus (type, poly0, CHREC_LEFT (poly1)), chrec_fold_multiply (type, CHREC_RIGHT (poly1), SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconstm1) : build_int_cst_type (type, -1))); } if (flow_loop_nested_p (loop1, loop0)) { if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_plus (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); else return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_minus (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); } /* This function should never be called for chrecs of loops that do not belong to the same loop nest. */ gcc_assert (loop0 == loop1); if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) { left = chrec_fold_plus (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); right = chrec_fold_plus (rtype, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); } else { left = chrec_fold_minus (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); right = chrec_fold_minus (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); } if (chrec_zerop (right)) return left; else return build_polynomial_chrec (CHREC_VARIABLE (poly0), left, right); }
static tree chrec_fold_plus_1 (enum tree_code code, tree type, tree op0, tree op1) { if (automatically_generated_chrec_p (op0) || automatically_generated_chrec_p (op1)) return chrec_fold_automatically_generated_operands (op0, op1); switch (TREE_CODE (op0)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op0, CHREC_VARIABLE (op0))); switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op1, CHREC_VARIABLE (op1))); return chrec_fold_plus_poly_poly (code, type, op0, op1); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; default: if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_plus (type, CHREC_LEFT (op0), op1), CHREC_RIGHT (op0)); else return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_minus (type, CHREC_LEFT (op0), op1), CHREC_RIGHT (op0)); } CASE_CONVERT: if (tree_contains_chrecs (op0, NULL)) return chrec_dont_know; default: switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op1, CHREC_VARIABLE (op1))); if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_plus (type, op0, CHREC_LEFT (op1)), CHREC_RIGHT (op1)); else return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_minus (type, op0, CHREC_LEFT (op1)), chrec_fold_multiply (type, CHREC_RIGHT (op1), SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconstm1) : build_int_cst_type (type, -1))); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; default: { int size = 0; if ((tree_contains_chrecs (op0, &size) || tree_contains_chrecs (op1, &size)) && size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE)) return build2 (code, type, op0, op1); else if (size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE)) { if (code == POINTER_PLUS_EXPR) return fold_build_pointer_plus (fold_convert (type, op0), op1); else return fold_build2 (code, type, fold_convert (type, op0), fold_convert (type, op1)); } else return chrec_dont_know; } } } }
void do_jump (tree exp, rtx if_false_label, rtx if_true_label) { enum tree_code code = TREE_CODE (exp); rtx temp; int i; tree type; enum machine_mode mode; rtx drop_through_label = 0; switch (code) { case ERROR_MARK: break; case INTEGER_CST: temp = integer_zerop (exp) ? if_false_label : if_true_label; if (temp) emit_jump (temp); break; #if 0 /* This is not true with #pragma weak */ case ADDR_EXPR: /* The address of something can never be zero. */ if (if_true_label) emit_jump (if_true_label); break; #endif case NOP_EXPR: if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_RANGE_REF) goto normal; case CONVERT_EXPR: /* If we are narrowing the operand, we have to do the compare in the narrower mode. */ if ((TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))) goto normal; case NON_LVALUE_EXPR: case ABS_EXPR: case NEGATE_EXPR: case LROTATE_EXPR: case RROTATE_EXPR: /* These cannot change zero->nonzero or vice versa. */ do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); break; case BIT_AND_EXPR: /* fold_single_bit_test() converts (X & (1 << C)) into (X >> C) & 1. See if the former is preferred for jump tests and restore it if so. */ if (integer_onep (TREE_OPERAND (exp, 1))) { tree exp0 = TREE_OPERAND (exp, 0); rtx set_label, clr_label; /* Strip narrowing integral type conversions. */ while ((TREE_CODE (exp0) == NOP_EXPR || TREE_CODE (exp0) == CONVERT_EXPR || TREE_CODE (exp0) == NON_LVALUE_EXPR) && TREE_OPERAND (exp0, 0) != error_mark_node && TYPE_PRECISION (TREE_TYPE (exp0)) <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp0, 0)))) exp0 = TREE_OPERAND (exp0, 0); /* "exp0 ^ 1" inverts the sense of the single bit test. */ if (TREE_CODE (exp0) == BIT_XOR_EXPR && integer_onep (TREE_OPERAND (exp0, 1))) { exp0 = TREE_OPERAND (exp0, 0); clr_label = if_true_label; set_label = if_false_label; } else { clr_label = if_false_label; set_label = if_true_label; } if (TREE_CODE (exp0) == RSHIFT_EXPR) { tree arg = TREE_OPERAND (exp0, 0); tree shift = TREE_OPERAND (exp0, 1); tree argtype = TREE_TYPE (arg); if (TREE_CODE (shift) == INTEGER_CST && compare_tree_int (shift, 0) >= 0 && compare_tree_int (shift, HOST_BITS_PER_WIDE_INT) < 0 && prefer_and_bit_test (TYPE_MODE (argtype), TREE_INT_CST_LOW (shift))) { HOST_WIDE_INT mask = (HOST_WIDE_INT) 1 << TREE_INT_CST_LOW (shift); do_jump (build2 (BIT_AND_EXPR, argtype, arg, build_int_cst_type (argtype, mask)), clr_label, set_label); break; } } } /* If we are AND'ing with a small constant, do this comparison in the smallest type that fits. If the machine doesn't have comparisons that small, it will be converted back to the wider comparison. This helps if we are testing the sign bit of a narrower object. combine can't do this for us because it can't know whether a ZERO_EXTRACT or a compare in a smaller mode exists, but we do. */ if (! SLOW_BYTE_ACCESS && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT && (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0 && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode && (type = lang_hooks.types.type_for_mode (mode, 1)) != 0 && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp)) && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code != CODE_FOR_nothing)) { do_jump (fold_convert (type, exp), if_false_label, if_true_label); break; } goto normal; case TRUTH_NOT_EXPR: do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); break; case COND_EXPR: { rtx label1 = gen_label_rtx (); if (!if_true_label || !if_false_label) { drop_through_label = gen_label_rtx (); if (!if_true_label) if_true_label = drop_through_label; if (!if_false_label) if_false_label = drop_through_label; } do_pending_stack_adjust (); do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX); do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); emit_label (label1); do_jump (TREE_OPERAND (exp, 2), if_false_label, if_true_label); break; } case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case COMPOUND_EXPR: /* Lowered by gimplify.c. */ gcc_unreachable (); case COMPONENT_REF: case BIT_FIELD_REF: case ARRAY_REF: case ARRAY_RANGE_REF: { HOST_WIDE_INT bitsize, bitpos; int unsignedp; enum machine_mode mode; tree type; tree offset; int volatilep = 0; /* Get description of this reference. We don't actually care about the underlying object here. */ get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode, &unsignedp, &volatilep, false); type = lang_hooks.types.type_for_size (bitsize, unsignedp); if (! SLOW_BYTE_ACCESS && type != 0 && bitsize >= 0 && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp)) && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code != CODE_FOR_nothing)) { do_jump (fold_convert (type, exp), if_false_label, if_true_label); break; } goto normal; } case EQ_EXPR: { tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0)); gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type)) != MODE_COMPLEX_FLOAT); gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type)) != MODE_COMPLEX_INT); if (integer_zerop (TREE_OPERAND (exp, 1))) do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT && !can_compare_p (EQ, TYPE_MODE (inner_type), ccp_jump)) do_jump_by_parts_equality (exp, if_false_label, if_true_label); else do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label); break; } case MINUS_EXPR: /* Nonzero iff operands of minus differ. */ exp = build2 (NE_EXPR, TREE_TYPE (exp), TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1)); /* FALLTHRU */ case NE_EXPR: { tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0)); gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type)) != MODE_COMPLEX_FLOAT); gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type)) != MODE_COMPLEX_INT); if (integer_zerop (TREE_OPERAND (exp, 1))) do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT && !can_compare_p (NE, TYPE_MODE (inner_type), ccp_jump)) do_jump_by_parts_equality (exp, if_true_label, if_false_label); else do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label); break; } case LT_EXPR: mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (LT, mode, ccp_jump)) do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label); else do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label); break; case LE_EXPR: mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (LE, mode, ccp_jump)) do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label); else do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label); break; case GT_EXPR: mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (GT, mode, ccp_jump)) do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label); else do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label); break; case GE_EXPR: mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (GE, mode, ccp_jump)) do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label); else do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label); break; case UNORDERED_EXPR: case ORDERED_EXPR: { enum rtx_code cmp, rcmp; int do_rev; if (code == UNORDERED_EXPR) cmp = UNORDERED, rcmp = ORDERED; else cmp = ORDERED, rcmp = UNORDERED; mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); do_rev = 0; if (! can_compare_p (cmp, mode, ccp_jump) && (can_compare_p (rcmp, mode, ccp_jump) /* If the target doesn't provide either UNORDERED or ORDERED comparisons, canonicalize on UNORDERED for the library. */ || rcmp == UNORDERED)) do_rev = 1; if (! do_rev) do_compare_and_jump (exp, cmp, cmp, if_false_label, if_true_label); else do_compare_and_jump (exp, rcmp, rcmp, if_true_label, if_false_label); } break; { enum rtx_code rcode1; enum tree_code tcode1, tcode2; case UNLT_EXPR: rcode1 = UNLT; tcode1 = UNORDERED_EXPR; tcode2 = LT_EXPR; goto unordered_bcc; case UNLE_EXPR: rcode1 = UNLE; tcode1 = UNORDERED_EXPR; tcode2 = LE_EXPR; goto unordered_bcc; case UNGT_EXPR: rcode1 = UNGT; tcode1 = UNORDERED_EXPR; tcode2 = GT_EXPR; goto unordered_bcc; case UNGE_EXPR: rcode1 = UNGE; tcode1 = UNORDERED_EXPR; tcode2 = GE_EXPR; goto unordered_bcc; case UNEQ_EXPR: rcode1 = UNEQ; tcode1 = UNORDERED_EXPR; tcode2 = EQ_EXPR; goto unordered_bcc; case LTGT_EXPR: /* It is ok for LTGT_EXPR to trap when the result is unordered, so expand to (a < b) || (a > b). */ rcode1 = LTGT; tcode1 = LT_EXPR; tcode2 = GT_EXPR; goto unordered_bcc; unordered_bcc: mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); if (can_compare_p (rcode1, mode, ccp_jump)) do_compare_and_jump (exp, rcode1, rcode1, if_false_label, if_true_label); else { tree op0 = save_expr (TREE_OPERAND (exp, 0)); tree op1 = save_expr (TREE_OPERAND (exp, 1)); tree cmp0, cmp1; /* If the target doesn't support combined unordered compares, decompose into two comparisons. */ if (if_true_label == 0) drop_through_label = if_true_label = gen_label_rtx (); cmp0 = fold_build2 (tcode1, TREE_TYPE (exp), op0, op1); cmp1 = fold_build2 (tcode2, TREE_TYPE (exp), op0, op1); do_jump (cmp0, 0, if_true_label); do_jump (cmp1, if_false_label, if_true_label); } } break; case TRUTH_AND_EXPR: /* High branch cost, expand as the bitwise AND of the conditions. Do the same if the RHS has side effects, because we're effectively turning a TRUTH_AND_EXPR into a TRUTH_ANDIF_EXPR. */ if (BRANCH_COST >= 4 || TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1))) goto normal; if (if_false_label == NULL_RTX) { drop_through_label = gen_label_rtx (); do_jump (TREE_OPERAND (exp, 0), drop_through_label, NULL_RTX); do_jump (TREE_OPERAND (exp, 1), NULL_RTX, if_true_label); } else { do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX); do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); } break; case TRUTH_OR_EXPR: /* High branch cost, expand as the bitwise OR of the conditions. Do the same if the RHS has side effects, because we're effectively turning a TRUTH_OR_EXPR into a TRUTH_ORIF_EXPR. */ if (BRANCH_COST >= 4 || TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1))) goto normal; if (if_true_label == NULL_RTX) { drop_through_label = gen_label_rtx (); do_jump (TREE_OPERAND (exp, 0), NULL_RTX, drop_through_label); do_jump (TREE_OPERAND (exp, 1), if_false_label, NULL_RTX); } else { do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label); do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); } break; /* Special case: __builtin_expect (<test>, 0) and __builtin_expect (<test>, 1) We need to do this here, so that <test> is not converted to a SCC operation on machines that use condition code registers and COMPARE like the PowerPC, and then the jump is done based on whether the SCC operation produced a 1 or 0. */ case CALL_EXPR: /* Check for a built-in function. */ { tree fndecl = get_callee_fndecl (exp); tree arglist = TREE_OPERAND (exp, 1); if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT && arglist != NULL_TREE && TREE_CHAIN (arglist) != NULL_TREE) { rtx seq = expand_builtin_expect_jump (exp, if_false_label, if_true_label); if (seq != NULL_RTX) { emit_insn (seq); return; } } } /* Fall through and generate the normal code. */ default: normal: temp = expand_normal (exp); do_pending_stack_adjust (); /* The RTL optimizers prefer comparisons against pseudos. */ if (GET_CODE (temp) == SUBREG) { /* Compare promoted variables in their promoted mode. */ if (SUBREG_PROMOTED_VAR_P (temp) && REG_P (XEXP (temp, 0))) temp = XEXP (temp, 0); else temp = copy_to_reg (temp); } do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)), NE, TYPE_UNSIGNED (TREE_TYPE (exp)), GET_MODE (temp), NULL_RTX, if_false_label, if_true_label); } if (drop_through_label) { do_pending_stack_adjust (); emit_label (drop_through_label); } }
static tree cp_convert_to_pointer (tree type, tree expr) { tree intype = TREE_TYPE (expr); enum tree_code form; tree rval; if (intype == error_mark_node) return error_mark_node; if (MAYBE_CLASS_TYPE_P (intype)) { intype = complete_type (intype); if (!COMPLETE_TYPE_P (intype)) { error ("can't convert from incomplete type %qT to %qT", intype, type); return error_mark_node; } rval = build_type_conversion (type, expr); if (rval) { if (rval == error_mark_node) error ("conversion of %qE from %qT to %qT is ambiguous", expr, intype, type); return rval; } } /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */ if (TREE_CODE (type) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE || VOID_TYPE_P (TREE_TYPE (type)))) { if (TYPE_PTRMEMFUNC_P (intype) || TREE_CODE (intype) == METHOD_TYPE) return convert_member_func_to_ptr (type, expr); if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) return build_nop (type, expr); intype = TREE_TYPE (expr); } if (expr == error_mark_node) return error_mark_node; form = TREE_CODE (intype); if (POINTER_TYPE_P (intype)) { intype = TYPE_MAIN_VARIANT (intype); if (TYPE_MAIN_VARIANT (type) != intype && TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && MAYBE_CLASS_TYPE_P (TREE_TYPE (type)) && MAYBE_CLASS_TYPE_P (TREE_TYPE (intype)) && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE) { enum tree_code code = PLUS_EXPR; tree binfo; tree intype_class; tree type_class; bool same_p; intype_class = TREE_TYPE (intype); type_class = TREE_TYPE (type); same_p = same_type_p (TYPE_MAIN_VARIANT (intype_class), TYPE_MAIN_VARIANT (type_class)); binfo = NULL_TREE; /* Try derived to base conversion. */ if (!same_p) binfo = lookup_base (intype_class, type_class, ba_check, NULL); if (!same_p && !binfo) { /* Try base to derived conversion. */ binfo = lookup_base (type_class, intype_class, ba_check, NULL); code = MINUS_EXPR; } if (binfo == error_mark_node) return error_mark_node; if (binfo || same_p) { if (binfo) expr = build_base_path (code, expr, binfo, 0); /* Add any qualifier conversions. */ return build_nop (type, expr); } } if (TYPE_PTRMEMFUNC_P (type)) { error ("cannot convert %qE from type %qT to type %qT", expr, intype, type); return error_mark_node; } return build_nop (type, expr); } else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)) || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))) return convert_ptrmem (type, expr, /*allow_inverse_p=*/false, /*c_cast_p=*/false); else if (TYPE_PTRMEMFUNC_P (intype)) { if (!warn_pmf2ptr) { if (TREE_CODE (expr) == PTRMEM_CST) return cp_convert_to_pointer (type, PTRMEM_CST_MEMBER (expr)); else if (TREE_CODE (expr) == OFFSET_REF) { tree object = TREE_OPERAND (expr, 0); return get_member_function_from_ptrfunc (&object, TREE_OPERAND (expr, 1)); } } error ("cannot convert %qE from type %qT to type %qT", expr, intype, type); return error_mark_node; } if (integer_zerop (expr)) { if (TYPE_PTRMEMFUNC_P (type)) return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0, /*c_cast_p=*/false); if (TYPE_PTRMEM_P (type)) { /* A NULL pointer-to-member is represented by -1, not by zero. */ expr = build_int_cst_type (type, -1); } else expr = build_int_cst (type, 0); return expr; } else if (TYPE_PTR_TO_MEMBER_P (type) && INTEGRAL_CODE_P (form)) { error ("invalid conversion from %qT to %qT", intype, type); return error_mark_node; } if (INTEGRAL_CODE_P (form)) { if (TYPE_PRECISION (intype) == POINTER_SIZE) return build1 (CONVERT_EXPR, type, expr); expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr); /* Modes may be different but sizes should be the same. There is supposed to be some integral type that is the same width as a pointer. */ gcc_assert (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) == GET_MODE_SIZE (TYPE_MODE (type))); return convert_to_pointer (type, expr); } if (type_unknown_p (expr)) return instantiate_type (type, expr, tf_warning_or_error); error ("cannot convert %qE from type %qT to type %qT", expr, intype, type); return error_mark_node; }
static tree rewrite_bittest (block_stmt_iterator *bsi) { tree stmt, lhs, rhs, var, name, use_stmt, stmt1, stmt2, t; use_operand_p use; stmt = bsi_stmt (*bsi); lhs = GENERIC_TREE_OPERAND (stmt, 0); rhs = GENERIC_TREE_OPERAND (stmt, 1); /* Verify that the single use of lhs is a comparison against zero. */ if (TREE_CODE (lhs) != SSA_NAME || !single_imm_use (lhs, &use, &use_stmt) || TREE_CODE (use_stmt) != COND_EXPR) return stmt; t = COND_EXPR_COND (use_stmt); if (TREE_OPERAND (t, 0) != lhs || (TREE_CODE (t) != NE_EXPR && TREE_CODE (t) != EQ_EXPR) || !integer_zerop (TREE_OPERAND (t, 1))) return stmt; /* Get at the operands of the shift. The rhs is TMP1 & 1. */ stmt1 = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0)); if (TREE_CODE (stmt1) != GIMPLE_MODIFY_STMT) return stmt; /* There is a conversion in between possibly inserted by fold. */ t = GIMPLE_STMT_OPERAND (stmt1, 1); if (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR) { t = TREE_OPERAND (t, 0); if (TREE_CODE (t) != SSA_NAME || !has_single_use (t)) return stmt; stmt1 = SSA_NAME_DEF_STMT (t); if (TREE_CODE (stmt1) != GIMPLE_MODIFY_STMT) return stmt; t = GIMPLE_STMT_OPERAND (stmt1, 1); } /* Verify that B is loop invariant but A is not. Verify that with all the stmt walking we are still in the same loop. */ if (TREE_CODE (t) == RSHIFT_EXPR && loop_containing_stmt (stmt1) == loop_containing_stmt (stmt) && outermost_invariant_loop_expr (TREE_OPERAND (t, 1), loop_containing_stmt (stmt1)) != NULL && outermost_invariant_loop_expr (TREE_OPERAND (t, 0), loop_containing_stmt (stmt1)) == NULL) { tree a = TREE_OPERAND (t, 0); tree b = TREE_OPERAND (t, 1); /* 1 << B */ var = create_tmp_var (TREE_TYPE (a), "shifttmp"); add_referenced_var (var); t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (a), build_int_cst (TREE_TYPE (a), 1), b); stmt1 = build_gimple_modify_stmt (var, t); name = make_ssa_name (var, stmt1); GIMPLE_STMT_OPERAND (stmt1, 0) = name; /* A & (1 << B) */ t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (a), a, name); stmt2 = build_gimple_modify_stmt (var, t); name = make_ssa_name (var, stmt2); GIMPLE_STMT_OPERAND (stmt2, 0) = name; /* Replace the SSA_NAME we compare against zero. Adjust the type of zero accordingly. */ SET_USE (use, name); TREE_OPERAND (COND_EXPR_COND (use_stmt), 1) = build_int_cst_type (TREE_TYPE (name), 0); bsi_insert_before (bsi, stmt1, BSI_SAME_STMT); bsi_replace (bsi, stmt2, true); return stmt1; } return stmt; }
static inline tree chrec_fold_plus_poly_poly (enum tree_code code, tree type, tree poly0, tree poly1) { tree left, right; gcc_assert (poly0); gcc_assert (poly1); gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC); gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC); gcc_assert (chrec_type (poly0) == chrec_type (poly1)); gcc_assert (type == chrec_type (poly0)); /* {a, +, b}_1 + {c, +, d}_2 -> {{a, +, b}_1 + c, +, d}_2, {a, +, b}_2 + {c, +, d}_1 -> {{c, +, d}_1 + a, +, b}_2, {a, +, b}_x + {c, +, d}_x -> {a+c, +, b+d}_x. */ if (CHREC_VARIABLE (poly0) < CHREC_VARIABLE (poly1)) { if (code == PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_plus (type, poly0, CHREC_LEFT (poly1)), CHREC_RIGHT (poly1)); else return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_minus (type, poly0, CHREC_LEFT (poly1)), chrec_fold_multiply (type, CHREC_RIGHT (poly1), SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconstm1) : build_int_cst_type (type, -1))); } if (CHREC_VARIABLE (poly0) > CHREC_VARIABLE (poly1)) { if (code == PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_plus (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); else return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_minus (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); } if (code == PLUS_EXPR) { left = chrec_fold_plus (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); right = chrec_fold_plus (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); } else { left = chrec_fold_minus (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); right = chrec_fold_minus (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); } if (chrec_zerop (right)) return left; else return build_polynomial_chrec (CHREC_VARIABLE (poly0), left, right); }
static tree chrec_fold_plus_1 (enum tree_code code, tree type, tree op0, tree op1) { if (automatically_generated_chrec_p (op0) || automatically_generated_chrec_p (op1)) return chrec_fold_automatically_generated_operands (op0, op1); switch (TREE_CODE (op0)) { case POLYNOMIAL_CHREC: switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: return chrec_fold_plus_poly_poly (code, type, op0, op1); default: if (code == PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_plus (type, CHREC_LEFT (op0), op1), CHREC_RIGHT (op0)); else return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_minus (type, CHREC_LEFT (op0), op1), CHREC_RIGHT (op0)); } default: switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: if (code == PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_plus (type, op0, CHREC_LEFT (op1)), CHREC_RIGHT (op1)); else return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_minus (type, op0, CHREC_LEFT (op1)), chrec_fold_multiply (type, CHREC_RIGHT (op1), build_int_cst_type (type, -1))); default: { int size = 0; if ((tree_contains_chrecs (op0, &size) || tree_contains_chrecs (op1, &size)) && size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE)) return build2 (code, type, op0, op1); else if (size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE)) return fold (build2 (code, type, op0, op1)); else return chrec_dont_know; } } } }
static void mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp, location_t *locus, tree dirflag) { tree type, base, limit, addr, size, t; /* Don't instrument read operations. */ if (dirflag == integer_zero_node && flag_mudflap_ignore_reads) return; /* Don't instrument marked nodes. */ if (mf_marked_p (*tp)) return; t = *tp; type = TREE_TYPE (t); size = TYPE_SIZE_UNIT (type); switch (TREE_CODE (t)) { case ARRAY_REF: case COMPONENT_REF: { /* This is trickier than it may first appear. The reason is that we are looking at expressions from the "inside out" at this point. We may have a complex nested aggregate/array expression (e.g. "a.b[i].c"), maybe with an indirection as the leftmost operator ("p->a.b.d"), where instrumentation is necessary. Or we may have an innocent "a.b.c" expression that must not be instrumented. We need to recurse all the way down the nesting structure to figure it out: looking just at the outer node is not enough. */ tree var; int component_ref_only = (TREE_CODE (t) == COMPONENT_REF); /* If we have a bitfield component reference, we must note the innermost addressable object in ELT, from which we will construct the byte-addressable bounds of the bitfield. */ tree elt = NULL_TREE; int bitfield_ref_p = (TREE_CODE (t) == COMPONENT_REF && DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1))); /* Iterate to the top of the ARRAY_REF/COMPONENT_REF containment hierarchy to find the outermost VAR_DECL. */ var = TREE_OPERAND (t, 0); while (1) { if (bitfield_ref_p && elt == NULL_TREE && (TREE_CODE (var) == ARRAY_REF || TREE_CODE (var) == COMPONENT_REF)) elt = var; if (TREE_CODE (var) == ARRAY_REF) { component_ref_only = 0; var = TREE_OPERAND (var, 0); } else if (TREE_CODE (var) == COMPONENT_REF) var = TREE_OPERAND (var, 0); else if (INDIRECT_REF_P (var)) { base = TREE_OPERAND (var, 0); break; } else { gcc_assert (TREE_CODE (var) == VAR_DECL || TREE_CODE (var) == PARM_DECL || TREE_CODE (var) == RESULT_DECL || TREE_CODE (var) == STRING_CST); /* Don't instrument this access if the underlying variable is not "eligible". This test matches those arrays that have only known-valid indexes, and thus are not labeled TREE_ADDRESSABLE. */ if (! mf_decl_eligible_p (var) || component_ref_only) return; else { base = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (var)), var); break; } } } /* Handle the case of ordinary non-indirection structure accesses. These have only nested COMPONENT_REF nodes (no INDIRECT_REF), but pass through the above filter loop. Note that it's possible for such a struct variable to match the eligible_p test because someone else might take its address sometime. */ /* We need special processing for bitfield components, because their addresses cannot be taken. */ if (bitfield_ref_p) { tree field = TREE_OPERAND (t, 1); if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST) size = DECL_SIZE_UNIT (field); if (elt) elt = build1 (ADDR_EXPR, build_pointer_type TREE_TYPE (elt), elt); addr = fold_convert (ptr_type_node, elt ? elt : base); addr = fold_build2 (PLUS_EXPR, ptr_type_node, addr, fold_convert (ptr_type_node, byte_position (field))); } else addr = build1 (ADDR_EXPR, build_pointer_type (type), t); limit = fold_build2 (MINUS_EXPR, mf_uintptr_type, fold_build2 (PLUS_EXPR, mf_uintptr_type, convert (mf_uintptr_type, addr), size), integer_one_node); } break; case INDIRECT_REF: addr = TREE_OPERAND (t, 0); base = addr; limit = fold_build2 (MINUS_EXPR, ptr_type_node, fold_build2 (PLUS_EXPR, ptr_type_node, base, size), integer_one_node); break; case TARGET_MEM_REF: addr = tree_mem_ref_addr (ptr_type_node, t); base = addr; limit = fold_build2 (MINUS_EXPR, ptr_type_node, fold_build2 (PLUS_EXPR, ptr_type_node, base, size), build_int_cst_type (ptr_type_node, 1)); break; case ARRAY_RANGE_REF: warning (0, "mudflap checking not yet implemented for ARRAY_RANGE_REF"); return; case BIT_FIELD_REF: /* ??? merge with COMPONENT_REF code above? */ { tree ofs, rem, bpu; /* If we're not dereferencing something, then the access must be ok. */ if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF) return; bpu = bitsize_int (BITS_PER_UNIT); ofs = convert (bitsizetype, TREE_OPERAND (t, 2)); rem = size_binop (TRUNC_MOD_EXPR, ofs, bpu); ofs = size_binop (TRUNC_DIV_EXPR, ofs, bpu); size = convert (bitsizetype, TREE_OPERAND (t, 1)); size = size_binop (PLUS_EXPR, size, rem); size = size_binop (CEIL_DIV_EXPR, size, bpu); size = convert (sizetype, size); addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0); addr = convert (ptr_type_node, addr); addr = fold_build2 (PLUS_EXPR, ptr_type_node, addr, ofs); base = addr; limit = fold_build2 (MINUS_EXPR, ptr_type_node, fold_build2 (PLUS_EXPR, ptr_type_node, base, size), integer_one_node); } break; default: return; } mf_build_check_statement_for (base, limit, iter, locus, dirflag); }