bool scev_is_linear_expression (tree scev) { if (scev == NULL || !operator_is_linear (scev)) return false; if (TREE_CODE (scev) == MULT_EXPR) return !(tree_contains_chrecs (TREE_OPERAND (scev, 0), NULL) && tree_contains_chrecs (TREE_OPERAND (scev, 1), NULL)); switch (TREE_CODE_LENGTH (TREE_CODE (scev))) { case 3: return scev_is_linear_expression (TREE_OPERAND (scev, 0)) && scev_is_linear_expression (TREE_OPERAND (scev, 1)) && scev_is_linear_expression (TREE_OPERAND (scev, 2)); case 2: return scev_is_linear_expression (TREE_OPERAND (scev, 0)) && scev_is_linear_expression (TREE_OPERAND (scev, 1)); case 1: return scev_is_linear_expression (TREE_OPERAND (scev, 0)); case 0: return true; default: return false; } }
bool tree_contains_chrecs (tree expr, int *size) { if (expr == NULL_TREE) return false; if (size) (*size)++; if (tree_is_chrec (expr)) return true; switch (TREE_CODE_LENGTH (TREE_CODE (expr))) { case 3: if (tree_contains_chrecs (TREE_OPERAND (expr, 2), size)) return true; case 2: if (tree_contains_chrecs (TREE_OPERAND (expr, 1), size)) return true; case 1: if (tree_contains_chrecs (TREE_OPERAND (expr, 0), size)) return true; default: return false; } }
static bool graphite_can_represent_scev (tree scev) { if (chrec_contains_undetermined (scev)) return false; /* We disable the handling of pointer types, because it’s currently not supported by Graphite with the ISL AST generator. SSA_NAME nodes are the only nodes, which are disabled in case they are pointers to object types, but this can be changed. */ if (POINTER_TYPE_P (TREE_TYPE (scev)) && TREE_CODE (scev) == SSA_NAME) return false; switch (TREE_CODE (scev)) { case NEGATE_EXPR: case BIT_NOT_EXPR: CASE_CONVERT: case NON_LVALUE_EXPR: return graphite_can_represent_scev (TREE_OPERAND (scev, 0)); case PLUS_EXPR: case POINTER_PLUS_EXPR: case MINUS_EXPR: return graphite_can_represent_scev (TREE_OPERAND (scev, 0)) && graphite_can_represent_scev (TREE_OPERAND (scev, 1)); case MULT_EXPR: return !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (scev, 0))) && !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (scev, 1))) && !(chrec_contains_symbols (TREE_OPERAND (scev, 0)) && chrec_contains_symbols (TREE_OPERAND (scev, 1))) && graphite_can_represent_init (scev) && graphite_can_represent_scev (TREE_OPERAND (scev, 0)) && graphite_can_represent_scev (TREE_OPERAND (scev, 1)); case POLYNOMIAL_CHREC: /* Check for constant strides. With a non constant stride of 'n' we would have a value of 'iv * n'. Also check that the initial value can represented: for example 'n * m' cannot be represented. */ if (!evolution_function_right_is_integer_cst (scev) || !graphite_can_represent_init (scev)) return false; return graphite_can_represent_scev (CHREC_LEFT (scev)); default: break; } /* Only affine functions can be represented. */ if (tree_contains_chrecs (scev, NULL) || !scev_is_linear_expression (scev)) return false; return true; }
bool evolution_function_is_univariate_p (const_tree chrec) { if (chrec == NULL_TREE) return true; switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: switch (TREE_CODE (CHREC_LEFT (chrec))) { case POLYNOMIAL_CHREC: if (CHREC_VARIABLE (chrec) != CHREC_VARIABLE (CHREC_LEFT (chrec))) return false; if (!evolution_function_is_univariate_p (CHREC_LEFT (chrec))) return false; break; default: if (tree_contains_chrecs (CHREC_LEFT (chrec), NULL)) return false; break; } switch (TREE_CODE (CHREC_RIGHT (chrec))) { case POLYNOMIAL_CHREC: if (CHREC_VARIABLE (chrec) != CHREC_VARIABLE (CHREC_RIGHT (chrec))) return false; if (!evolution_function_is_univariate_p (CHREC_RIGHT (chrec))) return false; break; default: if (tree_contains_chrecs (CHREC_RIGHT (chrec), NULL)) return false; break; } default: return true; } }
static bool graphite_can_represent_scev (tree scev) { if (chrec_contains_undetermined (scev)) return false; switch (TREE_CODE (scev)) { case NEGATE_EXPR: case BIT_NOT_EXPR: CASE_CONVERT: case NON_LVALUE_EXPR: return graphite_can_represent_scev (TREE_OPERAND (scev, 0)); case PLUS_EXPR: case POINTER_PLUS_EXPR: case MINUS_EXPR: return graphite_can_represent_scev (TREE_OPERAND (scev, 0)) && graphite_can_represent_scev (TREE_OPERAND (scev, 1)); case MULT_EXPR: return !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (scev, 0))) && !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (scev, 1))) && !(chrec_contains_symbols (TREE_OPERAND (scev, 0)) && chrec_contains_symbols (TREE_OPERAND (scev, 1))) && graphite_can_represent_init (scev) && graphite_can_represent_scev (TREE_OPERAND (scev, 0)) && graphite_can_represent_scev (TREE_OPERAND (scev, 1)); case POLYNOMIAL_CHREC: /* Check for constant strides. With a non constant stride of 'n' we would have a value of 'iv * n'. Also check that the initial value can represented: for example 'n * m' cannot be represented. */ if (!evolution_function_right_is_integer_cst (scev) || !graphite_can_represent_init (scev)) return false; return graphite_can_represent_scev (CHREC_LEFT (scev)); default: break; } /* Only affine functions can be represented. */ if (tree_contains_chrecs (scev, NULL) || !scev_is_linear_expression (scev)) return false; return true; }
bool scev_is_linear_expression (tree scev) { if (scev == NULL || !operator_is_linear (scev)) return false; if (TREE_CODE (scev) == MULT_EXPR) return !(tree_contains_chrecs (TREE_OPERAND (scev, 0), NULL) && tree_contains_chrecs (TREE_OPERAND (scev, 1), NULL)); if (TREE_CODE (scev) == POLYNOMIAL_CHREC && !evolution_function_is_affine_multivariate_p (scev, CHREC_VARIABLE (scev))) return false; switch (TREE_CODE_LENGTH (TREE_CODE (scev))) { case 3: return scev_is_linear_expression (TREE_OPERAND (scev, 0)) && scev_is_linear_expression (TREE_OPERAND (scev, 1)) && scev_is_linear_expression (TREE_OPERAND (scev, 2)); case 2: return scev_is_linear_expression (TREE_OPERAND (scev, 0)) && scev_is_linear_expression (TREE_OPERAND (scev, 1)); case 1: return scev_is_linear_expression (TREE_OPERAND (scev, 0)); case 0: return true; default: return false; } }
bool tree_contains_chrecs (const_tree expr, int *size) { int i, n; if (expr == NULL_TREE) return false; if (size) (*size)++; if (tree_is_chrec (expr)) return true; n = TREE_OPERAND_LENGTH (expr); for (i = 0; i < n; i++) if (tree_contains_chrecs (TREE_OPERAND (expr, i), size)) return true; return false; }
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: 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_multiply_poly_poly (type, op0, op1); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; default: if (integer_onep (op1)) return op0; if (integer_zerop (op1)) return build_int_cst (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)); } CASE_CONVERT: if (tree_contains_chrecs (op0, NULL)) return chrec_dont_know; default: if (integer_onep (op0)) return op1; if (integer_zerop (op0)) return build_int_cst (type, 0); switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op1, CHREC_VARIABLE (op1))); return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_multiply (type, CHREC_LEFT (op1), op0), chrec_fold_multiply (type, CHREC_RIGHT (op1), op0)); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; default: if (integer_onep (op1)) return op0; if (integer_zerop (op1)) return build_int_cst (type, 0); return fold_build2 (MULT_EXPR, type, op0, op1); } } }
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; } } } }
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; } } } }