1 | /* Target-dependent costs for expmed.cc. |
2 | Copyright (C) 1987-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #ifndef EXPMED_H |
21 | #define EXPMED_H 1 |
22 | |
23 | #include "insn-codes.h" |
24 | |
25 | enum alg_code { |
26 | alg_unknown, |
27 | alg_zero, |
28 | alg_m, alg_shift, |
29 | alg_add_t_m2, |
30 | alg_sub_t_m2, |
31 | alg_add_factor, |
32 | alg_sub_factor, |
33 | alg_add_t2_m, |
34 | alg_sub_t2_m, |
35 | alg_impossible |
36 | }; |
37 | |
38 | /* Indicates the type of fixup needed after a constant multiplication. |
39 | BASIC_VARIANT means no fixup is needed, NEGATE_VARIANT means that |
40 | the result should be negated, and ADD_VARIANT means that the |
41 | multiplicand should be added to the result. */ |
42 | enum mult_variant {basic_variant, negate_variant, add_variant}; |
43 | |
44 | bool choose_mult_variant (machine_mode, HOST_WIDE_INT, |
45 | struct algorithm *, enum mult_variant *, int); |
46 | |
47 | /* This structure holds the "cost" of a multiply sequence. The |
48 | "cost" field holds the total rtx_cost of every operator in the |
49 | synthetic multiplication sequence, hence cost(a op b) is defined |
50 | as rtx_cost(op) + cost(a) + cost(b), where cost(leaf) is zero. |
51 | The "latency" field holds the minimum possible latency of the |
52 | synthetic multiply, on a hypothetical infinitely parallel CPU. |
53 | This is the critical path, or the maximum height, of the expression |
54 | tree which is the sum of rtx_costs on the most expensive path from |
55 | any leaf to the root. Hence latency(a op b) is defined as zero for |
56 | leaves and rtx_cost(op) + max(latency(a), latency(b)) otherwise. */ |
57 | |
58 | struct mult_cost { |
59 | short cost; /* Total rtx_cost of the multiplication sequence. */ |
60 | short latency; /* The latency of the multiplication sequence. */ |
61 | }; |
62 | |
63 | /* This macro is used to compare a pointer to a mult_cost against an |
64 | single integer "rtx_cost" value. This is equivalent to the macro |
65 | CHEAPER_MULT_COST(X,Z) where Z = {Y,Y}. */ |
66 | #define MULT_COST_LESS(X,Y) ((X)->cost < (Y) \ |
67 | || ((X)->cost == (Y) && (X)->latency < (Y))) |
68 | |
69 | /* This macro is used to compare two pointers to mult_costs against |
70 | each other. The macro returns true if X is cheaper than Y. |
71 | Currently, the cheaper of two mult_costs is the one with the |
72 | lower "cost". If "cost"s are tied, the lower latency is cheaper. */ |
73 | #define CHEAPER_MULT_COST(X,Y) ((X)->cost < (Y)->cost \ |
74 | || ((X)->cost == (Y)->cost \ |
75 | && (X)->latency < (Y)->latency)) |
76 | |
77 | /* This structure records a sequence of operations. |
78 | `ops' is the number of operations recorded. |
79 | `cost' is their total cost. |
80 | The operations are stored in `op' and the corresponding |
81 | logarithms of the integer coefficients in `log'. |
82 | |
83 | These are the operations: |
84 | alg_zero total := 0; |
85 | alg_m total := multiplicand; |
86 | alg_shift total := total * coeff |
87 | alg_add_t_m2 total := total + multiplicand * coeff; |
88 | alg_sub_t_m2 total := total - multiplicand * coeff; |
89 | alg_add_factor total := total * coeff + total; |
90 | alg_sub_factor total := total * coeff - total; |
91 | alg_add_t2_m total := total * coeff + multiplicand; |
92 | alg_sub_t2_m total := total * coeff - multiplicand; |
93 | |
94 | The first operand must be either alg_zero or alg_m. */ |
95 | |
96 | struct algorithm |
97 | { |
98 | struct mult_cost cost; |
99 | short ops; |
100 | /* The size of the OP and LOG fields are not directly related to the |
101 | word size, but the worst-case algorithms will be if we have few |
102 | consecutive ones or zeros, i.e., a multiplicand like 10101010101... |
103 | In that case we will generate shift-by-2, add, shift-by-2, add,..., |
104 | in total wordsize operations. */ |
105 | enum alg_code op[MAX_BITS_PER_WORD]; |
106 | char log[MAX_BITS_PER_WORD]; |
107 | }; |
108 | |
109 | /* The entry for our multiplication cache/hash table. */ |
110 | struct alg_hash_entry { |
111 | /* The number we are multiplying by. */ |
112 | unsigned HOST_WIDE_INT t; |
113 | |
114 | /* The mode in which we are multiplying something by T. */ |
115 | machine_mode mode; |
116 | |
117 | /* The best multiplication algorithm for t. */ |
118 | enum alg_code alg; |
119 | |
120 | /* The cost of multiplication if ALG_CODE is not alg_impossible. |
121 | Otherwise, the cost within which multiplication by T is |
122 | impossible. */ |
123 | struct mult_cost cost; |
124 | |
125 | /* Optimized for speed? */ |
126 | bool speed; |
127 | }; |
128 | |
129 | /* The number of cache/hash entries. */ |
130 | #if HOST_BITS_PER_WIDE_INT == 64 |
131 | #define NUM_ALG_HASH_ENTRIES 1031 |
132 | #else |
133 | #define NUM_ALG_HASH_ENTRIES 307 |
134 | #endif |
135 | |
136 | #define NUM_MODE_IP_INT (NUM_MODE_INT + NUM_MODE_PARTIAL_INT) |
137 | #define NUM_MODE_IPV_INT (NUM_MODE_IP_INT + NUM_MODE_VECTOR_INT) |
138 | |
139 | struct expmed_op_cheap { |
140 | bool cheap[2][NUM_MODE_IPV_INT]; |
141 | }; |
142 | |
143 | struct expmed_op_costs { |
144 | int cost[2][NUM_MODE_IPV_INT]; |
145 | }; |
146 | |
147 | /* Target-dependent globals. */ |
148 | struct target_expmed { |
149 | /* Each entry of ALG_HASH caches alg_code for some integer. This is |
150 | actually a hash table. If we have a collision, that the older |
151 | entry is kicked out. */ |
152 | struct alg_hash_entry x_alg_hash[NUM_ALG_HASH_ENTRIES]; |
153 | |
154 | /* True if x_alg_hash might already have been used. */ |
155 | bool x_alg_hash_used_p; |
156 | |
157 | /* Nonzero means divides or modulus operations are relatively cheap for |
158 | powers of two, so don't use branches; emit the operation instead. |
159 | Usually, this will mean that the MD file will emit non-branch |
160 | sequences. */ |
161 | struct expmed_op_cheap x_sdiv_pow2_cheap; |
162 | struct expmed_op_cheap x_smod_pow2_cheap; |
163 | |
164 | /* Cost of various pieces of RTL. */ |
165 | int x_zero_cost[2]; |
166 | struct expmed_op_costs x_add_cost; |
167 | struct expmed_op_costs x_neg_cost; |
168 | int x_shift_cost[2][NUM_MODE_IPV_INT][MAX_BITS_PER_WORD]; |
169 | int x_shiftadd_cost[2][NUM_MODE_IPV_INT][MAX_BITS_PER_WORD]; |
170 | int x_shiftsub0_cost[2][NUM_MODE_IPV_INT][MAX_BITS_PER_WORD]; |
171 | int x_shiftsub1_cost[2][NUM_MODE_IPV_INT][MAX_BITS_PER_WORD]; |
172 | struct expmed_op_costs x_mul_cost; |
173 | struct expmed_op_costs x_sdiv_cost; |
174 | struct expmed_op_costs x_udiv_cost; |
175 | int x_mul_widen_cost[2][NUM_MODE_INT]; |
176 | int x_mul_highpart_cost[2][NUM_MODE_INT]; |
177 | |
178 | /* Conversion costs are only defined between two scalar integer modes |
179 | of different sizes. The first machine mode is the destination mode, |
180 | and the second is the source mode. */ |
181 | int x_convert_cost[2][NUM_MODE_IP_INT][NUM_MODE_IP_INT]; |
182 | }; |
183 | |
184 | extern struct target_expmed default_target_expmed; |
185 | #if SWITCHABLE_TARGET |
186 | extern struct target_expmed *this_target_expmed; |
187 | #else |
188 | #define this_target_expmed (&default_target_expmed) |
189 | #endif |
190 | |
191 | /* Return a pointer to the alg_hash_entry at IDX. */ |
192 | |
193 | inline struct alg_hash_entry * |
194 | alg_hash_entry_ptr (int idx) |
195 | { |
196 | return &this_target_expmed->x_alg_hash[idx]; |
197 | } |
198 | |
199 | /* Return true if the x_alg_hash field might have been used. */ |
200 | |
201 | inline bool |
202 | alg_hash_used_p (void) |
203 | { |
204 | return this_target_expmed->x_alg_hash_used_p; |
205 | } |
206 | |
207 | /* Set whether the x_alg_hash field might have been used. */ |
208 | |
209 | inline void |
210 | set_alg_hash_used_p (bool usedp) |
211 | { |
212 | this_target_expmed->x_alg_hash_used_p = usedp; |
213 | } |
214 | |
215 | /* Compute an index into the cost arrays by mode class. */ |
216 | |
217 | inline int |
218 | expmed_mode_index (machine_mode mode) |
219 | { |
220 | switch (GET_MODE_CLASS (mode)) |
221 | { |
222 | case MODE_INT: |
223 | return mode - MIN_MODE_INT; |
224 | case MODE_PARTIAL_INT: |
225 | /* If there are no partial integer modes, help the compiler |
226 | to figure out this will never happen. See PR59934. */ |
227 | if (MIN_MODE_PARTIAL_INT != VOIDmode) |
228 | return mode - MIN_MODE_PARTIAL_INT + NUM_MODE_INT; |
229 | break; |
230 | case MODE_VECTOR_INT: |
231 | /* If there are no vector integer modes, help the compiler |
232 | to figure out this will never happen. See PR59934. */ |
233 | if (MIN_MODE_VECTOR_INT != VOIDmode) |
234 | return mode - MIN_MODE_VECTOR_INT + NUM_MODE_IP_INT; |
235 | break; |
236 | default: |
237 | break; |
238 | } |
239 | gcc_unreachable (); |
240 | } |
241 | |
242 | /* Return a pointer to a boolean contained in EOC indicating whether |
243 | a particular operation performed in MODE is cheap when optimizing |
244 | for SPEED. */ |
245 | |
246 | inline bool * |
247 | expmed_op_cheap_ptr (struct expmed_op_cheap *eoc, bool speed, |
248 | machine_mode mode) |
249 | { |
250 | int idx = expmed_mode_index (mode); |
251 | return &eoc->cheap[speed][idx]; |
252 | } |
253 | |
254 | /* Return a pointer to a cost contained in COSTS when a particular |
255 | operation is performed in MODE when optimizing for SPEED. */ |
256 | |
257 | inline int * |
258 | expmed_op_cost_ptr (struct expmed_op_costs *costs, bool speed, |
259 | machine_mode mode) |
260 | { |
261 | int idx = expmed_mode_index (mode); |
262 | return &costs->cost[speed][idx]; |
263 | } |
264 | |
265 | /* Subroutine of {set_,}sdiv_pow2_cheap. Not to be used otherwise. */ |
266 | |
267 | inline bool * |
268 | sdiv_pow2_cheap_ptr (bool speed, machine_mode mode) |
269 | { |
270 | return expmed_op_cheap_ptr (eoc: &this_target_expmed->x_sdiv_pow2_cheap, |
271 | speed, mode); |
272 | } |
273 | |
274 | /* Set whether a signed division by a power of 2 is cheap in MODE |
275 | when optimizing for SPEED. */ |
276 | |
277 | inline void |
278 | set_sdiv_pow2_cheap (bool speed, machine_mode mode, bool cheap_p) |
279 | { |
280 | *sdiv_pow2_cheap_ptr (speed, mode) = cheap_p; |
281 | } |
282 | |
283 | /* Return whether a signed division by a power of 2 is cheap in MODE |
284 | when optimizing for SPEED. */ |
285 | |
286 | inline bool |
287 | sdiv_pow2_cheap (bool speed, machine_mode mode) |
288 | { |
289 | return *sdiv_pow2_cheap_ptr (speed, mode); |
290 | } |
291 | |
292 | /* Subroutine of {set_,}smod_pow2_cheap. Not to be used otherwise. */ |
293 | |
294 | inline bool * |
295 | smod_pow2_cheap_ptr (bool speed, machine_mode mode) |
296 | { |
297 | return expmed_op_cheap_ptr (eoc: &this_target_expmed->x_smod_pow2_cheap, |
298 | speed, mode); |
299 | } |
300 | |
301 | /* Set whether a signed modulo by a power of 2 is CHEAP in MODE when |
302 | optimizing for SPEED. */ |
303 | |
304 | inline void |
305 | set_smod_pow2_cheap (bool speed, machine_mode mode, bool cheap) |
306 | { |
307 | *smod_pow2_cheap_ptr (speed, mode) = cheap; |
308 | } |
309 | |
310 | /* Return whether a signed modulo by a power of 2 is cheap in MODE |
311 | when optimizing for SPEED. */ |
312 | |
313 | inline bool |
314 | smod_pow2_cheap (bool speed, machine_mode mode) |
315 | { |
316 | return *smod_pow2_cheap_ptr (speed, mode); |
317 | } |
318 | |
319 | /* Subroutine of {set_,}zero_cost. Not to be used otherwise. */ |
320 | |
321 | inline int * |
322 | zero_cost_ptr (bool speed) |
323 | { |
324 | return &this_target_expmed->x_zero_cost[speed]; |
325 | } |
326 | |
327 | /* Set the COST of loading zero when optimizing for SPEED. */ |
328 | |
329 | inline void |
330 | set_zero_cost (bool speed, int cost) |
331 | { |
332 | *zero_cost_ptr (speed) = cost; |
333 | } |
334 | |
335 | /* Return the COST of loading zero when optimizing for SPEED. */ |
336 | |
337 | inline int |
338 | zero_cost (bool speed) |
339 | { |
340 | return *zero_cost_ptr (speed); |
341 | } |
342 | |
343 | /* Subroutine of {set_,}add_cost. Not to be used otherwise. */ |
344 | |
345 | inline int * |
346 | add_cost_ptr (bool speed, machine_mode mode) |
347 | { |
348 | return expmed_op_cost_ptr (costs: &this_target_expmed->x_add_cost, speed, mode); |
349 | } |
350 | |
351 | /* Set the COST of computing an add in MODE when optimizing for SPEED. */ |
352 | |
353 | inline void |
354 | set_add_cost (bool speed, machine_mode mode, int cost) |
355 | { |
356 | *add_cost_ptr (speed, mode) = cost; |
357 | } |
358 | |
359 | /* Return the cost of computing an add in MODE when optimizing for SPEED. */ |
360 | |
361 | inline int |
362 | add_cost (bool speed, machine_mode mode) |
363 | { |
364 | return *add_cost_ptr (speed, mode); |
365 | } |
366 | |
367 | /* Subroutine of {set_,}neg_cost. Not to be used otherwise. */ |
368 | |
369 | inline int * |
370 | neg_cost_ptr (bool speed, machine_mode mode) |
371 | { |
372 | return expmed_op_cost_ptr (costs: &this_target_expmed->x_neg_cost, speed, mode); |
373 | } |
374 | |
375 | /* Set the COST of computing a negation in MODE when optimizing for SPEED. */ |
376 | |
377 | inline void |
378 | set_neg_cost (bool speed, machine_mode mode, int cost) |
379 | { |
380 | *neg_cost_ptr (speed, mode) = cost; |
381 | } |
382 | |
383 | /* Return the cost of computing a negation in MODE when optimizing for |
384 | SPEED. */ |
385 | |
386 | inline int |
387 | neg_cost (bool speed, machine_mode mode) |
388 | { |
389 | return *neg_cost_ptr (speed, mode); |
390 | } |
391 | |
392 | /* Subroutine of {set_,}shift_cost. Not to be used otherwise. */ |
393 | |
394 | inline int * |
395 | shift_cost_ptr (bool speed, machine_mode mode, int bits) |
396 | { |
397 | int midx = expmed_mode_index (mode); |
398 | return &this_target_expmed->x_shift_cost[speed][midx][bits]; |
399 | } |
400 | |
401 | /* Set the COST of doing a shift in MODE by BITS when optimizing for SPEED. */ |
402 | |
403 | inline void |
404 | set_shift_cost (bool speed, machine_mode mode, int bits, int cost) |
405 | { |
406 | *shift_cost_ptr (speed, mode, bits) = cost; |
407 | } |
408 | |
409 | /* Return the cost of doing a shift in MODE by BITS when optimizing for |
410 | SPEED. */ |
411 | |
412 | inline int |
413 | shift_cost (bool speed, machine_mode mode, int bits) |
414 | { |
415 | return *shift_cost_ptr (speed, mode, bits); |
416 | } |
417 | |
418 | /* Subroutine of {set_,}shiftadd_cost. Not to be used otherwise. */ |
419 | |
420 | inline int * |
421 | shiftadd_cost_ptr (bool speed, machine_mode mode, int bits) |
422 | { |
423 | int midx = expmed_mode_index (mode); |
424 | return &this_target_expmed->x_shiftadd_cost[speed][midx][bits]; |
425 | } |
426 | |
427 | /* Set the COST of doing a shift in MODE by BITS followed by an add when |
428 | optimizing for SPEED. */ |
429 | |
430 | inline void |
431 | set_shiftadd_cost (bool speed, machine_mode mode, int bits, int cost) |
432 | { |
433 | *shiftadd_cost_ptr (speed, mode, bits) = cost; |
434 | } |
435 | |
436 | /* Return the cost of doing a shift in MODE by BITS followed by an add |
437 | when optimizing for SPEED. */ |
438 | |
439 | inline int |
440 | shiftadd_cost (bool speed, machine_mode mode, int bits) |
441 | { |
442 | return *shiftadd_cost_ptr (speed, mode, bits); |
443 | } |
444 | |
445 | /* Subroutine of {set_,}shiftsub0_cost. Not to be used otherwise. */ |
446 | |
447 | inline int * |
448 | shiftsub0_cost_ptr (bool speed, machine_mode mode, int bits) |
449 | { |
450 | int midx = expmed_mode_index (mode); |
451 | return &this_target_expmed->x_shiftsub0_cost[speed][midx][bits]; |
452 | } |
453 | |
454 | /* Set the COST of doing a shift in MODE by BITS and then subtracting a |
455 | value when optimizing for SPEED. */ |
456 | |
457 | inline void |
458 | set_shiftsub0_cost (bool speed, machine_mode mode, int bits, int cost) |
459 | { |
460 | *shiftsub0_cost_ptr (speed, mode, bits) = cost; |
461 | } |
462 | |
463 | /* Return the cost of doing a shift in MODE by BITS and then subtracting |
464 | a value when optimizing for SPEED. */ |
465 | |
466 | inline int |
467 | shiftsub0_cost (bool speed, machine_mode mode, int bits) |
468 | { |
469 | return *shiftsub0_cost_ptr (speed, mode, bits); |
470 | } |
471 | |
472 | /* Subroutine of {set_,}shiftsub1_cost. Not to be used otherwise. */ |
473 | |
474 | inline int * |
475 | shiftsub1_cost_ptr (bool speed, machine_mode mode, int bits) |
476 | { |
477 | int midx = expmed_mode_index (mode); |
478 | return &this_target_expmed->x_shiftsub1_cost[speed][midx][bits]; |
479 | } |
480 | |
481 | /* Set the COST of subtracting a shift in MODE by BITS from a value when |
482 | optimizing for SPEED. */ |
483 | |
484 | inline void |
485 | set_shiftsub1_cost (bool speed, machine_mode mode, int bits, int cost) |
486 | { |
487 | *shiftsub1_cost_ptr (speed, mode, bits) = cost; |
488 | } |
489 | |
490 | /* Return the cost of subtracting a shift in MODE by BITS from a value |
491 | when optimizing for SPEED. */ |
492 | |
493 | inline int |
494 | shiftsub1_cost (bool speed, machine_mode mode, int bits) |
495 | { |
496 | return *shiftsub1_cost_ptr (speed, mode, bits); |
497 | } |
498 | |
499 | /* Subroutine of {set_,}mul_cost. Not to be used otherwise. */ |
500 | |
501 | inline int * |
502 | mul_cost_ptr (bool speed, machine_mode mode) |
503 | { |
504 | return expmed_op_cost_ptr (costs: &this_target_expmed->x_mul_cost, speed, mode); |
505 | } |
506 | |
507 | /* Set the COST of doing a multiplication in MODE when optimizing for |
508 | SPEED. */ |
509 | |
510 | inline void |
511 | set_mul_cost (bool speed, machine_mode mode, int cost) |
512 | { |
513 | *mul_cost_ptr (speed, mode) = cost; |
514 | } |
515 | |
516 | /* Return the cost of doing a multiplication in MODE when optimizing |
517 | for SPEED. */ |
518 | |
519 | inline int |
520 | mul_cost (bool speed, machine_mode mode) |
521 | { |
522 | return *mul_cost_ptr (speed, mode); |
523 | } |
524 | |
525 | /* Subroutine of {set_,}sdiv_cost. Not to be used otherwise. */ |
526 | |
527 | inline int * |
528 | sdiv_cost_ptr (bool speed, machine_mode mode) |
529 | { |
530 | return expmed_op_cost_ptr (costs: &this_target_expmed->x_sdiv_cost, speed, mode); |
531 | } |
532 | |
533 | /* Set the COST of doing a signed division in MODE when optimizing |
534 | for SPEED. */ |
535 | |
536 | inline void |
537 | set_sdiv_cost (bool speed, machine_mode mode, int cost) |
538 | { |
539 | *sdiv_cost_ptr (speed, mode) = cost; |
540 | } |
541 | |
542 | /* Return the cost of doing a signed division in MODE when optimizing |
543 | for SPEED. */ |
544 | |
545 | inline int |
546 | sdiv_cost (bool speed, machine_mode mode) |
547 | { |
548 | return *sdiv_cost_ptr (speed, mode); |
549 | } |
550 | |
551 | /* Subroutine of {set_,}udiv_cost. Not to be used otherwise. */ |
552 | |
553 | inline int * |
554 | udiv_cost_ptr (bool speed, machine_mode mode) |
555 | { |
556 | return expmed_op_cost_ptr (costs: &this_target_expmed->x_udiv_cost, speed, mode); |
557 | } |
558 | |
559 | /* Set the COST of doing an unsigned division in MODE when optimizing |
560 | for SPEED. */ |
561 | |
562 | inline void |
563 | set_udiv_cost (bool speed, machine_mode mode, int cost) |
564 | { |
565 | *udiv_cost_ptr (speed, mode) = cost; |
566 | } |
567 | |
568 | /* Return the cost of doing an unsigned division in MODE when |
569 | optimizing for SPEED. */ |
570 | |
571 | inline int |
572 | udiv_cost (bool speed, machine_mode mode) |
573 | { |
574 | return *udiv_cost_ptr (speed, mode); |
575 | } |
576 | |
577 | /* Subroutine of {set_,}mul_widen_cost. Not to be used otherwise. */ |
578 | |
579 | inline int * |
580 | mul_widen_cost_ptr (bool speed, machine_mode mode) |
581 | { |
582 | gcc_assert (GET_MODE_CLASS (mode) == MODE_INT); |
583 | |
584 | return &this_target_expmed->x_mul_widen_cost[speed][mode - MIN_MODE_INT]; |
585 | } |
586 | |
587 | /* Set the COST for computing a widening multiplication in MODE when |
588 | optimizing for SPEED. */ |
589 | |
590 | inline void |
591 | set_mul_widen_cost (bool speed, machine_mode mode, int cost) |
592 | { |
593 | *mul_widen_cost_ptr (speed, mode) = cost; |
594 | } |
595 | |
596 | /* Return the cost for computing a widening multiplication in MODE when |
597 | optimizing for SPEED. */ |
598 | |
599 | inline int |
600 | mul_widen_cost (bool speed, machine_mode mode) |
601 | { |
602 | return *mul_widen_cost_ptr (speed, mode); |
603 | } |
604 | |
605 | /* Subroutine of {set_,}mul_highpart_cost. Not to be used otherwise. */ |
606 | |
607 | inline int * |
608 | mul_highpart_cost_ptr (bool speed, machine_mode mode) |
609 | { |
610 | gcc_assert (GET_MODE_CLASS (mode) == MODE_INT); |
611 | int m = mode - MIN_MODE_INT; |
612 | gcc_assert (m < NUM_MODE_INT); |
613 | |
614 | return &this_target_expmed->x_mul_highpart_cost[speed][m]; |
615 | } |
616 | |
617 | /* Set the COST for computing the high part of a multiplication in MODE |
618 | when optimizing for SPEED. */ |
619 | |
620 | inline void |
621 | set_mul_highpart_cost (bool speed, machine_mode mode, int cost) |
622 | { |
623 | *mul_highpart_cost_ptr (speed, mode) = cost; |
624 | } |
625 | |
626 | /* Return the cost for computing the high part of a multiplication in MODE |
627 | when optimizing for SPEED. */ |
628 | |
629 | inline int |
630 | mul_highpart_cost (bool speed, machine_mode mode) |
631 | { |
632 | return *mul_highpart_cost_ptr (speed, mode); |
633 | } |
634 | |
635 | /* Subroutine of {set_,}convert_cost. Not to be used otherwise. */ |
636 | |
637 | inline int * |
638 | convert_cost_ptr (machine_mode to_mode, machine_mode from_mode, |
639 | bool speed) |
640 | { |
641 | int to_idx = expmed_mode_index (mode: to_mode); |
642 | int from_idx = expmed_mode_index (mode: from_mode); |
643 | |
644 | gcc_assert (IN_RANGE (to_idx, 0, NUM_MODE_IP_INT - 1)); |
645 | gcc_assert (IN_RANGE (from_idx, 0, NUM_MODE_IP_INT - 1)); |
646 | |
647 | return &this_target_expmed->x_convert_cost[speed][to_idx][from_idx]; |
648 | } |
649 | |
650 | /* Set the COST for converting from FROM_MODE to TO_MODE when optimizing |
651 | for SPEED. */ |
652 | |
653 | inline void |
654 | set_convert_cost (machine_mode to_mode, machine_mode from_mode, |
655 | bool speed, int cost) |
656 | { |
657 | *convert_cost_ptr (to_mode, from_mode, speed) = cost; |
658 | } |
659 | |
660 | /* Return the cost for converting from FROM_MODE to TO_MODE when optimizing |
661 | for SPEED. */ |
662 | |
663 | inline int |
664 | convert_cost (machine_mode to_mode, machine_mode from_mode, |
665 | bool speed) |
666 | { |
667 | return *convert_cost_ptr (to_mode, from_mode, speed); |
668 | } |
669 | |
670 | extern int mult_by_coeff_cost (HOST_WIDE_INT, machine_mode, bool); |
671 | extern rtx emit_cstore (rtx target, enum insn_code icode, enum rtx_code code, |
672 | machine_mode mode, machine_mode compare_mode, |
673 | int unsignedp, rtx x, rtx y, int normalizep, |
674 | machine_mode target_mode); |
675 | |
676 | /* Arguments MODE, RTX: return an rtx for the negation of that value. |
677 | May emit insns. */ |
678 | extern rtx negate_rtx (machine_mode, rtx); |
679 | |
680 | /* Arguments MODE, RTX: return an rtx for the flipping of that value. |
681 | May emit insns. */ |
682 | extern rtx flip_storage_order (machine_mode, rtx); |
683 | |
684 | /* Expand a logical AND operation. */ |
685 | extern rtx expand_and (machine_mode, rtx, rtx, rtx); |
686 | |
687 | /* Emit a store-flag operation. */ |
688 | extern rtx emit_store_flag (rtx, enum rtx_code, rtx, rtx, machine_mode, |
689 | int, int); |
690 | |
691 | /* Like emit_store_flag, but always succeeds. */ |
692 | extern rtx emit_store_flag_force (rtx, enum rtx_code, rtx, rtx, |
693 | machine_mode, int, int); |
694 | |
695 | extern void canonicalize_comparison (machine_mode, enum rtx_code *, rtx *); |
696 | |
697 | /* Choose a minimal N + 1 bit approximation to 1/D that can be used to |
698 | replace division by D, and put the least significant N bits of the result |
699 | in *MULTIPLIER_PTR and return the most significant bit. */ |
700 | extern unsigned HOST_WIDE_INT choose_multiplier (unsigned HOST_WIDE_INT, int, |
701 | int, unsigned HOST_WIDE_INT *, |
702 | int *, int *); |
703 | |
704 | #ifdef TREE_CODE |
705 | extern rtx expand_variable_shift (enum tree_code, machine_mode, |
706 | rtx, tree, rtx, int); |
707 | extern rtx expand_shift (enum tree_code, machine_mode, rtx, poly_int64, rtx, |
708 | int); |
709 | extern rtx maybe_expand_shift (enum tree_code, machine_mode, rtx, int, rtx, |
710 | int); |
711 | #ifdef GCC_OPTABS_H |
712 | extern rtx expand_divmod (int, enum tree_code, machine_mode, rtx, rtx, |
713 | rtx, int, enum optab_methods = OPTAB_LIB_WIDEN); |
714 | #endif |
715 | #endif |
716 | |
717 | extern void store_bit_field (rtx, poly_uint64, poly_uint64, |
718 | poly_uint64, poly_uint64, |
719 | machine_mode, rtx, bool, bool); |
720 | extern rtx (rtx, poly_uint64, poly_uint64, int, rtx, |
721 | machine_mode, machine_mode, bool, rtx *); |
722 | extern rtx (machine_mode, machine_mode, rtx); |
723 | extern rtx expand_mult (machine_mode, rtx, rtx, rtx, int, bool = false); |
724 | extern rtx expand_mult_highpart_adjust (scalar_int_mode, rtx, rtx, rtx, |
725 | rtx, int); |
726 | |
727 | #endif // EXPMED_H |
728 | |