blob: 07b51e51d089d8f691b2389db8c48f4a63e983df [file] [log] [blame]
/* 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
<http://www.gnu.org/licenses/>. */
#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);
val = save_expr (val);
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);
}