1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
/* Header file for the GIMPLE fold_using_range interface.
Copyright (C) 2019-2024 Free Software Foundation, Inc.
Contributed by Andrew MacLeod <amacleod@redhat.com>
and Aldy Hernandez <aldyh@redhat.com>.
This file is part of GCC.
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/>. */
#ifndef GCC_GIMPLE_RANGE_FOLD_H
#define GCC_GIMPLE_RANGE_FOLD_H
// This file is the main include point for gimple range folding.
// These routines will fold stmt S into the result range R.
// Any ssa_names on the stmt will be calculated using the range_query
// parameter via a call to range_of_expr.
// If no range_query is provided, current global range info will be used.
// The second variation specifies an edge, and stmt S is recalculated as if
// it appeared on that edge.
// Fold stmt S into range R using range query Q.
bool fold_range (vrange &r, gimple *s, range_query *q = NULL);
// Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
bool fold_range (vrange &v, gimple *s, edge on_edge, range_query *q = NULL);
// These routines the operands to be specified when manually folding.
// Any excess queries will be drawn from the current range_query.
bool fold_range (vrange &r, gimple *s, vrange &r1, range_query *q = NULL);
bool fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2,
range_query *q = NULL);
bool fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector,
range_query *q = NULL);
// This routine will return a relation trio for stmt S.
relation_trio fold_relations (gimple *s, range_query *q = NULL);
// Return the type of range which statement S calculates. If the type is
// unsupported or no type can be determined, return NULL_TREE.
inline tree
gimple_range_type (const gimple *s)
{
tree lhs = gimple_get_lhs (s);
tree type = NULL_TREE;
if (lhs)
type = TREE_TYPE (lhs);
else
{
enum gimple_code code = gimple_code (s);
if (code == GIMPLE_COND)
type = boolean_type_node;
else if (code == GIMPLE_PHI)
type = TREE_TYPE (gimple_phi_result (s));
else if (code == GIMPLE_CALL)
{
type = gimple_call_fntype (s);
// If it has a type, get the return type.
if (type)
type = TREE_TYPE (type);
}
}
if (type && Value_Range::supports_type_p (type))
return type;
return NULL_TREE;
}
// Return EXP if it is an SSA_NAME with a type supported by gimple ranges.
inline tree
gimple_range_ssa_p (tree exp)
{
if (exp && TREE_CODE (exp) == SSA_NAME &&
!SSA_NAME_IS_VIRTUAL_OPERAND (exp) &&
!SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp) &&
Value_Range::supports_type_p (TREE_TYPE (exp)))
return exp;
return NULL_TREE;
}
// Source of all operands for fold_using_range and gori_compute.
// It abstracts out the source of an operand so it can come from a stmt or
// and edge or anywhere a derived class of fur_source wants.
// The default simply picks up ranges from the current range_query.
class fur_source
{
public:
fur_source (range_query *q = NULL);
inline range_query *query () { return m_query; }
inline class gori_compute *gori () { return m_gori; };
virtual bool get_operand (vrange &r, tree expr);
virtual bool get_phi_operand (vrange &r, tree expr, edge e);
virtual relation_kind query_relation (tree op1, tree op2);
virtual void register_relation (gimple *stmt, relation_kind k, tree op1,
tree op2);
virtual void register_relation (edge e, relation_kind k, tree op1,
tree op2);
void register_outgoing_edges (gcond *, irange &lhs_range, edge e0, edge e1);
protected:
range_query *m_query;
gori_compute *m_gori;
};
// fur_stmt is the specification for drawing an operand from range_query Q
// via a range_of_Expr call on stmt S.
class fur_stmt : public fur_source
{
public:
fur_stmt (gimple *s, range_query *q = NULL);
virtual bool get_operand (vrange &r, tree expr) override;
virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
virtual relation_kind query_relation (tree op1, tree op2) override;
private:
gimple *m_stmt;
};
// This version of fur_source will pick a range from a stmt, and also register
// dependencies via a gori_compute object. This is mostly an internal API.
class fur_depend : public fur_stmt
{
public:
fur_depend (gimple *s, gori_compute *gori, range_query *q = NULL);
virtual void register_relation (gimple *stmt, relation_kind k, tree op1,
tree op2) override;
virtual void register_relation (edge e, relation_kind k, tree op1,
tree op2) override;
protected:
relation_oracle *m_oracle;
};
// This version of fur_source will pick a range up off an edge.
class fur_edge : public fur_source
{
public:
fur_edge (edge e, range_query *q = NULL) : fur_source (q)
{ m_edge = e; }
virtual bool get_operand (vrange &r, tree expr) override;
virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
private:
edge m_edge;
};
// This class uses ranges to fold a gimple statement producing a range for
// the LHS. The source of all operands is supplied via the fur_source class
// which provides a range_query as well as a source location and any other
// required information.
class fold_using_range
{
public:
bool fold_stmt (vrange &r, gimple *s, class fur_source &src,
tree name = NULL_TREE);
protected:
bool range_of_range_op (vrange &r, gimple_range_op_handler &handler,
fur_source &src);
bool range_of_call (vrange &r, gcall *call, fur_source &src);
bool range_of_cond_expr (vrange &r, gassign* cond, fur_source &src);
bool range_of_address (irange &r, gimple *s, fur_source &src);
bool range_of_phi (vrange &r, gphi *phi, fur_source &src);
void range_of_ssa_name_with_loop_info (vrange &, tree, class loop *, gphi *,
fur_source &src);
void relation_fold_and_or (irange& lhs_range, gimple *s, fur_source &src,
vrange &op1, vrange &op2);
};
#endif // GCC_GIMPLE_RANGE_FOLD_H
|