1 /* Operations with affine combinations of trees.
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 GCC is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
23 #include "coretypes.h"
28 #include "hard-reg-set.h"
30 #include "diagnostic.h"
31 #include "tree-dump.h"
32 #include "tree-affine.h"
34 /* Extends CST as appropriate for the affine combinations COMB. */
37 double_int_ext_for_comb (double_int cst
, aff_tree
*comb
)
39 return double_int_sext (cst
, TYPE_PRECISION (comb
->type
));
42 /* Initializes affine combination COMB so that its value is zero in TYPE. */
45 aff_combination_zero (aff_tree
*comb
, tree type
)
48 comb
->offset
= double_int_zero
;
50 comb
->rest
= NULL_TREE
;
53 /* Sets COMB to CST. */
56 aff_combination_const (aff_tree
*comb
, tree type
, double_int cst
)
58 aff_combination_zero (comb
, type
);
59 comb
->offset
= double_int_ext_for_comb (cst
, comb
);
62 /* Sets COMB to single element ELT. */
65 aff_combination_elt (aff_tree
*comb
, tree type
, tree elt
)
67 aff_combination_zero (comb
, type
);
70 comb
->elts
[0].val
= elt
;
71 comb
->elts
[0].coef
= double_int_one
;
74 /* Scales COMB by SCALE. */
77 aff_combination_scale (aff_tree
*comb
, double_int scale
)
81 scale
= double_int_ext_for_comb (scale
, comb
);
82 if (double_int_one_p (scale
))
85 if (double_int_zero_p (scale
))
87 aff_combination_zero (comb
, comb
->type
);
92 = double_int_ext_for_comb (double_int_mul (scale
, comb
->offset
), comb
);
93 for (i
= 0, j
= 0; i
< comb
->n
; i
++)
98 = double_int_ext_for_comb (double_int_mul (scale
, comb
->elts
[i
].coef
),
100 /* A coefficient may become zero due to overflow. Remove the zero
102 if (double_int_zero_p (new_coef
))
104 comb
->elts
[j
].coef
= new_coef
;
105 comb
->elts
[j
].val
= comb
->elts
[i
].val
;
112 if (comb
->n
< MAX_AFF_ELTS
)
114 comb
->elts
[comb
->n
].coef
= scale
;
115 comb
->elts
[comb
->n
].val
= comb
->rest
;
116 comb
->rest
= NULL_TREE
;
120 comb
->rest
= fold_build2 (MULT_EXPR
, comb
->type
, comb
->rest
,
121 double_int_to_tree (comb
->type
, scale
));
125 /* Adds ELT * SCALE to COMB. */
128 aff_combination_add_elt (aff_tree
*comb
, tree elt
, double_int scale
)
132 scale
= double_int_ext_for_comb (scale
, comb
);
133 if (double_int_zero_p (scale
))
136 for (i
= 0; i
< comb
->n
; i
++)
137 if (operand_equal_p (comb
->elts
[i
].val
, elt
, 0))
141 new_coef
= double_int_add (comb
->elts
[i
].coef
, scale
);
142 new_coef
= double_int_ext_for_comb (new_coef
, comb
);
143 if (!double_int_zero_p (new_coef
))
145 comb
->elts
[i
].coef
= new_coef
;
150 comb
->elts
[i
] = comb
->elts
[comb
->n
];
154 gcc_assert (comb
->n
== MAX_AFF_ELTS
- 1);
155 comb
->elts
[comb
->n
].coef
= double_int_one
;
156 comb
->elts
[comb
->n
].val
= comb
->rest
;
157 comb
->rest
= NULL_TREE
;
162 if (comb
->n
< MAX_AFF_ELTS
)
164 comb
->elts
[comb
->n
].coef
= scale
;
165 comb
->elts
[comb
->n
].val
= elt
;
170 if (double_int_one_p (scale
))
171 elt
= fold_convert (comb
->type
, elt
);
173 elt
= fold_build2 (MULT_EXPR
, comb
->type
,
174 fold_convert (comb
->type
, elt
),
175 double_int_to_tree (comb
->type
, scale
));
178 comb
->rest
= fold_build2 (PLUS_EXPR
, comb
->type
, comb
->rest
, elt
);
186 aff_combination_add_cst (aff_tree
*c
, double_int cst
)
188 c
->offset
= double_int_ext_for_comb (double_int_add (c
->offset
, cst
), c
);
191 /* Adds COMB2 to COMB1. */
194 aff_combination_add (aff_tree
*comb1
, aff_tree
*comb2
)
198 aff_combination_add_cst (comb1
, comb2
->offset
);
199 for (i
= 0; i
< comb2
->n
; i
++)
200 aff_combination_add_elt (comb1
, comb2
->elts
[i
].val
, comb2
->elts
[i
].coef
);
202 aff_combination_add_elt (comb1
, comb2
->rest
, double_int_one
);
205 /* Converts affine combination COMB to TYPE. */
208 aff_combination_convert (aff_tree
*comb
, tree type
)
211 tree comb_type
= comb
->type
;
213 if (TYPE_PRECISION (type
) > TYPE_PRECISION (comb_type
))
215 tree val
= fold_convert (type
, aff_combination_to_tree (comb
));
216 tree_to_aff_combination (val
, type
, comb
);
222 comb
->rest
= fold_convert (type
, comb
->rest
);
224 if (TYPE_PRECISION (type
) == TYPE_PRECISION (comb_type
))
227 comb
->offset
= double_int_ext_for_comb (comb
->offset
, comb
);
228 for (i
= j
= 0; i
< comb
->n
; i
++)
230 double_int new_coef
= double_int_ext_for_comb (comb
->elts
[i
].coef
, comb
);
231 if (double_int_zero_p (new_coef
))
233 comb
->elts
[j
].coef
= new_coef
;
234 comb
->elts
[j
].val
= fold_convert (type
, comb
->elts
[i
].val
);
239 if (comb
->n
< MAX_AFF_ELTS
&& comb
->rest
)
241 comb
->elts
[comb
->n
].coef
= double_int_one
;
242 comb
->elts
[comb
->n
].val
= comb
->rest
;
243 comb
->rest
= NULL_TREE
;
248 /* Splits EXPR into an affine combination of parts. */
251 tree_to_aff_combination (tree expr
, tree type
, aff_tree
*comb
)
255 tree cst
, core
, toffset
;
256 HOST_WIDE_INT bitpos
, bitsize
;
257 enum machine_mode mode
;
258 int unsignedp
, volatilep
;
262 code
= TREE_CODE (expr
);
266 aff_combination_const (comb
, type
, tree_to_double_int (expr
));
271 tree_to_aff_combination (TREE_OPERAND (expr
, 0), type
, comb
);
272 tree_to_aff_combination (TREE_OPERAND (expr
, 1), type
, &tmp
);
273 if (code
== MINUS_EXPR
)
274 aff_combination_scale (&tmp
, double_int_minus_one
);
275 aff_combination_add (comb
, &tmp
);
279 cst
= TREE_OPERAND (expr
, 1);
280 if (TREE_CODE (cst
) != INTEGER_CST
)
282 tree_to_aff_combination (TREE_OPERAND (expr
, 0), type
, comb
);
283 aff_combination_scale (comb
, tree_to_double_int (cst
));
287 tree_to_aff_combination (TREE_OPERAND (expr
, 0), type
, comb
);
288 aff_combination_scale (comb
, double_int_minus_one
);
293 tree_to_aff_combination (TREE_OPERAND (expr
, 0), type
, comb
);
294 aff_combination_scale (comb
, double_int_minus_one
);
295 aff_combination_add_cst (comb
, double_int_minus_one
);
299 core
= get_inner_reference (TREE_OPERAND (expr
, 0), &bitsize
, &bitpos
,
300 &toffset
, &mode
, &unsignedp
, &volatilep
,
302 if (bitpos
% BITS_PER_UNIT
!= 0)
304 aff_combination_const (comb
, type
,
305 uhwi_to_double_int (bitpos
/ BITS_PER_UNIT
));
306 core
= build_fold_addr_expr (core
);
307 if (TREE_CODE (core
) == ADDR_EXPR
)
308 aff_combination_add_elt (comb
, core
, double_int_one
);
311 tree_to_aff_combination (core
, type
, &tmp
);
312 aff_combination_add (comb
, &tmp
);
316 tree_to_aff_combination (toffset
, type
, &tmp
);
317 aff_combination_add (comb
, &tmp
);
325 aff_combination_elt (comb
, type
, expr
);
328 /* Creates EXPR + ELT * SCALE in TYPE. EXPR is taken from affine
332 add_elt_to_tree (tree expr
, tree type
, tree elt
, double_int scale
,
337 scale
= double_int_ext_for_comb (scale
, comb
);
338 elt
= fold_convert (type
, elt
);
340 if (double_int_one_p (scale
))
345 return fold_build2 (PLUS_EXPR
, type
, expr
, elt
);
348 if (double_int_minus_one_p (scale
))
351 return fold_build1 (NEGATE_EXPR
, type
, elt
);
353 return fold_build2 (MINUS_EXPR
, type
, expr
, elt
);
357 return fold_build2 (MULT_EXPR
, type
, elt
,
358 double_int_to_tree (type
, scale
));
360 if (double_int_negative_p (scale
))
363 scale
= double_int_neg (scale
);
368 elt
= fold_build2 (MULT_EXPR
, type
, elt
,
369 double_int_to_tree (type
, scale
));
370 return fold_build2 (code
, type
, expr
, elt
);
373 /* Makes tree from the affine combination COMB. */
376 aff_combination_to_tree (aff_tree
*comb
)
378 tree type
= comb
->type
;
379 tree expr
= comb
->rest
;
383 gcc_assert (comb
->n
== MAX_AFF_ELTS
|| comb
->rest
== NULL_TREE
);
385 for (i
= 0; i
< comb
->n
; i
++)
386 expr
= add_elt_to_tree (expr
, type
, comb
->elts
[i
].val
, comb
->elts
[i
].coef
,
389 /* Ensure that we get x - 1, not x + (-1) or x + 0xff..f if x is
391 if (double_int_negative_p (comb
->offset
))
393 off
= double_int_neg (comb
->offset
);
394 sgn
= double_int_minus_one
;
399 sgn
= double_int_one
;
401 return add_elt_to_tree (expr
, type
, double_int_to_tree (type
, off
), sgn
,
405 /* Copies the tree elements of COMB to ensure that they are not shared. */
408 unshare_aff_combination (aff_tree
*comb
)
412 for (i
= 0; i
< comb
->n
; i
++)
413 comb
->elts
[i
].val
= unshare_expr (comb
->elts
[i
].val
);
415 comb
->rest
= unshare_expr (comb
->rest
);
418 /* Remove M-th element from COMB. */
421 aff_combination_remove_elt (aff_tree
*comb
, unsigned m
)
425 comb
->elts
[m
] = comb
->elts
[comb
->n
];
428 comb
->elts
[comb
->n
].coef
= double_int_one
;
429 comb
->elts
[comb
->n
].val
= comb
->rest
;
430 comb
->rest
= NULL_TREE
;
435 /* Adds C * COEF * VAL to R. VAL may be NULL, in that case only
436 C * COEF is added to R. */
440 aff_combination_add_product (aff_tree
*c
, double_int coef
, tree val
,
446 for (i
= 0; i
< c
->n
; i
++)
448 aval
= c
->elts
[i
].val
;
451 type
= TREE_TYPE (aval
);
452 aval
= fold_build2 (MULT_EXPR
, type
, aval
,
453 fold_convert (type
, val
));
456 aff_combination_add_elt (r
, aval
,
457 double_int_mul (coef
, c
->elts
[i
].coef
));
465 type
= TREE_TYPE (aval
);
466 aval
= fold_build2 (MULT_EXPR
, type
, aval
,
467 fold_convert (type
, val
));
470 aff_combination_add_elt (r
, aval
, coef
);
474 aff_combination_add_elt (r
, val
,
475 double_int_mul (coef
, c
->offset
));
477 aff_combination_add_cst (r
, double_int_mul (coef
, c
->offset
));
480 /* Multiplies C1 by C2, storing the result to R */
483 aff_combination_mult (aff_tree
*c1
, aff_tree
*c2
, aff_tree
*r
)
486 gcc_assert (TYPE_PRECISION (c1
->type
) == TYPE_PRECISION (c2
->type
));
488 aff_combination_zero (r
, c1
->type
);
490 for (i
= 0; i
< c2
->n
; i
++)
491 aff_combination_add_product (c1
, c2
->elts
[i
].coef
, c2
->elts
[i
].val
, r
);
493 aff_combination_add_product (c1
, double_int_one
, c2
->rest
, r
);
494 aff_combination_add_product (c1
, c2
->offset
, NULL
, r
);