diff options
Diffstat (limited to 'gcc/ada/gcc-interface/utils.cc')
-rw-r--r-- | gcc/ada/gcc-interface/utils.cc | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc index f720f3a..4e2ed17 100644 --- a/gcc/ada/gcc-interface/utils.cc +++ b/gcc/ada/gcc-interface/utils.cc @@ -3830,6 +3830,100 @@ fntype_same_flags_p (const_tree t, tree cico_list, bool return_by_direct_ref_p, && TREE_ADDRESSABLE (t) == return_by_invisi_ref_p; } +/* Try to compute the maximum (if MAX_P) or minimum (if !MAX_P) value for the + expression EXP, for very simple expressions. Substitute variable references + with their respective type's min/max values. Return the computed value if + any, or EXP if no value can be computed. */ + +tree +max_value (tree exp, bool max_p) +{ + enum tree_code code = TREE_CODE (exp); + tree type = TREE_TYPE (exp); + tree op0, op1, op2; + + switch (TREE_CODE_CLASS (code)) + { + case tcc_declaration: + if (VAR_P (exp)) + return fold_convert (type, + max_p + ? TYPE_MAX_VALUE (type) : TYPE_MIN_VALUE (type)); + break; + + case tcc_vl_exp: + if (code == CALL_EXPR) + { + tree t; + + t = maybe_inline_call_in_expr (exp); + if (t) + return max_value (t, max_p); + } + break; + + case tcc_comparison: + return build_int_cst (type, max_p ? 1 : 0); + + case tcc_unary: + op0 = TREE_OPERAND (exp, 0); + + if (code == NON_LVALUE_EXPR) + return max_value (op0, max_p); + + if (code == NEGATE_EXPR) + return max_value (op0, !max_p); + + if (code == NOP_EXPR) + return fold_convert (type, max_value (op0, max_p)); + + break; + + case tcc_binary: + op0 = TREE_OPERAND (exp, 0); + op1 = TREE_OPERAND (exp, 1); + + switch (code) { + case PLUS_EXPR: + case MULT_EXPR: + return fold_build2 (code, type, max_value(op0, max_p), + max_value (op1, max_p)); + case MINUS_EXPR: + case TRUNC_DIV_EXPR: + return fold_build2 (code, type, max_value(op0, max_p), + max_value (op1, !max_p)); + default: + break; + } + break; + + case tcc_expression: + if (code == COND_EXPR) + { + op0 = TREE_OPERAND (exp, 0); + op1 = TREE_OPERAND (exp, 1); + op2 = TREE_OPERAND (exp, 2); + + if (!op1 || !op2) + break; + + op1 = max_value (op1, max_p); + op2 = max_value (op2, max_p); + + if (op1 == TREE_OPERAND (exp, 1) && op2 == TREE_OPERAND (exp, 2)) + break; + + return fold_build2 (max_p ? MAX_EXPR : MIN_EXPR, type, op1, op2); + } + break; + + default: + break; + } + return exp; +} + + /* EXP is an expression for the size of an object. If this size contains discriminant references, replace them with the maximum (if MAX_P) or minimum (if !MAX_P) possible value of the discriminant. @@ -3867,6 +3961,7 @@ max_size (tree exp, bool max_p) n = call_expr_nargs (exp); gcc_assert (n > 0); argarray = XALLOCAVEC (tree, n); + /* This is used to remove possible placeholder in call args. */ for (i = 0; i < n; i++) argarray[i] = max_size (CALL_EXPR_ARG (exp, i), max_p); return build_call_array (type, CALL_EXPR_FN (exp), n, argarray); |