/* Lowering routines for all things related to INT values. Copyright (C) 2025 Jose E. Marchesi. Written by Jose E. Marchesi. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #define INCLUDE_MEMORY #include "config.h" #include "system.h" #include "coretypes.h" #include "tree.h" #include "fold-const.h" #include "diagnostic.h" #include "langhooks.h" #include "tm.h" #include "function.h" #include "cgraph.h" #include "toplev.h" #include "varasm.h" #include "predict.h" #include "stor-layout.h" #include "tree-iterator.h" #include "stringpool.h" #include "print-tree.h" #include "gimplify.h" #include "dumpfile.h" #include "convert.h" #include "a68.h" /* Return a tree with the yielind of SKIP for the given integral mode. */ tree a68_get_int_skip_tree (MOID_T *m) { tree type; if (m == M_INT) type = a68_int_type; else if (m == M_LONG_INT) type = a68_long_int_type; else if (m == M_LONG_LONG_INT) type = a68_long_long_int_type; else if (m == M_SHORT_INT) type = a68_short_int_type; else if (m == M_SHORT_SHORT_INT) type = a68_short_short_int_type; else gcc_unreachable (); return build_int_cst (type, 0); } /* Given an integral type, build the maximum value expressable in that type. */ tree a68_int_maxval (tree type) { return fold_convert (type, TYPE_MAX_VALUE (type)); } /* Given an integral type, build the minimum value expressable in that type. */ tree a68_int_minval (tree type) { return fold_convert (type, TYPE_MIN_VALUE (type)); } /* Given an integral type, build an INT with the number of decimal digits required to represent a value of that typ, not including sign. */ tree a68_int_width (tree type) { /* Note that log10 (2) is ~ 0.3. Thanks to Andrew Pinski for suggesting using this expression. */ return fold_build2 (PLUS_EXPR, a68_int_type, build_int_cst (a68_int_type, 1), fold_build2 (TRUNC_DIV_EXPR, a68_int_type, fold_build2 (MULT_EXPR, a68_int_type, build_int_cst (a68_int_type, TYPE_PRECISION (type)), build_int_cst (a68_int_type, 3)), build_int_cst (a68_int_type, 10))); } /* Given an integer value VAL, return -1 if it is less than zero, 0 if it is zero and +1 if it is bigger than zero. The built value is always of mode M_INT. */ tree a68_int_sign (tree val) { tree zero = build_int_cst (TREE_TYPE (val), 0); return fold_build3 (COND_EXPR, a68_int_type, fold_build2 (EQ_EXPR, integer_type_node, val, zero), build_int_cst (a68_int_type, 0), fold_build3 (COND_EXPR, a68_int_type, fold_build2 (GT_EXPR, integer_type_node, val, zero), build_int_cst (a68_int_type, 1), build_int_cst (a68_int_type, -1))); } /* Absolute value of an integer. */ tree a68_int_abs (tree val) { return fold_build1 (ABS_EXPR, TREE_TYPE (val), val); } /* Build the integral value lengthened from the value of VAL, from mode FROM_MODE to mode TO_MODE. */ tree a68_int_leng (MOID_T *to_mode, MOID_T *from_mode ATTRIBUTE_UNUSED, tree val) { /* Lengthening can be done by just a cast. */ return fold_convert (CTYPE (to_mode), val); } /* Build the integral value that can be lengthened to the value of VAL, from mode FROM_MODE to mode TO_MODE. If VAL cannot be represented in TO_MODE because it is bigger than the most positive value representable in TO_MODE, then it is truncated to that value. Likewise, if VAL cannot be represented in TO_MODE because it is less than the most negative value representable in TO_MODE, then it is truncated to that value. */ tree a68_int_shorten (MOID_T *to_mode, MOID_T *from_mode ATTRIBUTE_UNUSED, tree val) { tree most_positive_value = fold_convert (CTYPE (from_mode), a68_int_maxval (CTYPE (to_mode))); tree most_negative_value = fold_convert (CTYPE (from_mode), a68_int_minval (CTYPE (to_mode))); val = save_expr (val); most_positive_value = save_expr (most_positive_value); most_negative_value = save_expr (most_negative_value); return fold_build3 (COND_EXPR, CTYPE (to_mode), fold_build2 (GT_EXPR, a68_bool_type, val, most_positive_value), fold_convert (CTYPE (to_mode), most_positive_value), fold_build3 (COND_EXPR, CTYPE (to_mode), fold_build2 (LT_EXPR, a68_bool_type, val, most_negative_value), fold_convert (CTYPE (to_mode), most_negative_value), fold_convert (CTYPE (to_mode), val))); } /* Given two integral values of mode M, build an expression that calculates the addition of A and B. */ tree a68_int_plus (MOID_T *m, tree a, tree b, location_t loc) { return fold_build2_loc (loc, PLUS_EXPR, CTYPE (m), a, b); } /* Given two integral values of mode M, build an expression that calculates the subtraction of A by B. */ tree a68_int_minus (MOID_T *m, tree a, tree b, location_t loc) { return fold_build2_loc (loc, MINUS_EXPR, CTYPE (m), a, b); } /* Given two integral values of mode M, build an expression that calculates the multiplication of A by B. */ tree a68_int_mult (MOID_T *m, tree a, tree b, location_t loc) { return fold_build2_loc (loc, MULT_EXPR, CTYPE (m), a, b); } /* Given two integral values of mode M, build an expression that calculates the division of A by B. */ tree a68_int_div (MOID_T *m, tree a, tree b, location_t loc) { return fold_build2_loc (loc, TRUNC_DIV_EXPR, CTYPE (m), a, b); } /* Given two integral values of mode M, build an expression that calculates whether A = B. */ tree a68_int_eq (tree a, tree b, location_t loc) { return fold_build2_loc (loc, EQ_EXPR, boolean_type_node, a, b); } /* Given two integral values of mode M, build an expression that calculates whether A /= B. */ tree a68_int_ne (tree a, tree b, location_t loc) { return fold_build2_loc (loc, NE_EXPR, boolean_type_node, a, b); } /* Given two integral values of mode M, build an expression that calculates whether A < B. */ tree a68_int_lt (tree a, tree b, location_t loc) { return fold_build2_loc (loc, LT_EXPR, boolean_type_node, a, b); } /* Given two integral values of mode M, build an expression that calculates whether A <= B. */ tree a68_int_le (tree a, tree b, location_t loc) { return fold_build2_loc (loc, LE_EXPR, boolean_type_node, a, b); } /* Given two integral values of mode M, build an expression that calculates whether A > B. */ tree a68_int_gt (tree a, tree b, location_t loc) { return fold_build2_loc (loc, GT_EXPR, boolean_type_node, a, b); } /* Given two integral values of mode M, build an expression that calculates whether A >= B. */ tree a68_int_ge (tree a, tree b, location_t loc) { return fold_build2_loc (loc, GE_EXPR, boolean_type_node, a, b); } /* Given two integral values of mode M, build and expression that calculates the modulus as specified by the Revised Report: OP MOD = (L INT a, b) L INT: (INT r = a - a % b * b; r < 0 | r + ABS b | r) */ tree a68_int_mod (MOID_T *m, tree a, tree b, location_t loc) { a = save_expr (a); b = save_expr (b); tree r = a68_int_minus (m, a, a68_int_mult (m, a68_int_div (m, a, b), b)); r = save_expr (r); return fold_build3_loc (loc, COND_EXPR, CTYPE (m), a68_int_lt (r, build_int_cst (CTYPE (m), 0)), a68_int_plus (m, r, a68_int_abs (b)), r); } /* Given two integral values values, the first of mode M an the second of mode INT, build an expression that calculates the exponentiation of A by B, as specified by the Revised Report: OP ** = (L INT a, INT b) L INT: (b >= 0 | L INT p := L 1; TO b DO p := p * a OD; p) */ tree a68_int_pow (MOID_T *m, tree a, tree b, location_t loc) { tree zero = build_int_cst (CTYPE (m), 0); tree one = build_int_cst (CTYPE (m), 1); a = save_expr (a); b = save_expr (fold_convert (CTYPE (m), b)); a68_push_range (m); tree index = a68_lower_tmpvar ("index%", CTYPE (m), zero); tree p = a68_lower_tmpvar ("p%", CTYPE (m), one); /* Begin of loop body. */ a68_push_range (NULL); { /* if (index == b) break; */ a68_add_stmt (fold_build1 (EXIT_EXPR, void_type_node, fold_build2 (EQ_EXPR, CTYPE (m), index, b))); a68_add_stmt (fold_build2 (MODIFY_EXPR, CTYPE (m), p, a68_int_mult (m, p, a))); /* index++ */ a68_add_stmt (fold_build2 (POSTINCREMENT_EXPR, CTYPE (m), index, one)); } tree loop_body = a68_pop_range (); a68_add_stmt (fold_build1 (LOOP_EXPR, void_type_node, loop_body)); a68_add_stmt (p); tree calculate_p = a68_pop_range (); return fold_build3_loc (loc, COND_EXPR, CTYPE (m), a68_int_ge (b, zero), calculate_p, zero); }