aboutsummaryrefslogtreecommitdiff
path: root/gcc/ifcvt.h
blob: 204bcf6d18a23f60aaf787c614b08b3b45bb84e3 (plain)
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
/* If-conversion header file.
   Copyright (C) 2014-2024 Free Software Foundation, Inc.

   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_IFCVT_H
#define GCC_IFCVT_H

/* Structure to group all of the information to process IF-THEN and
   IF-THEN-ELSE blocks for the conditional execution support.  */

struct ce_if_block
{
  basic_block test_bb;			/* First test block.  */
  basic_block then_bb;			/* THEN block.  */
  basic_block else_bb;			/* ELSE block or NULL.  */
  basic_block join_bb;			/* Join THEN/ELSE blocks.  */
  basic_block last_test_bb;		/* Last bb to hold && or || tests.  */
  int num_multiple_test_blocks;		/* # of && and || basic blocks.  */
  int num_and_and_blocks;		/* # of && blocks.  */
  int num_or_or_blocks;			/* # of || blocks.  */
  int num_multiple_test_insns;		/* # of insns in && and || blocks.  */
  int and_and_p;			/* Complex test is &&.  */
  int num_then_insns;			/* # of insns in THEN block.  */
  int num_else_insns;			/* # of insns in ELSE block.  */
  int pass;				/* Pass number.  */
};

struct noce_multiple_sets_info
{
  /* A list of indices to instructions that we need to rewire into this
     instruction when we replace them with temporary conditional moves.  */
  auto_vec<int> rewired_src;
  /* The true targets for a conditional move.  */
  rtx target;
  /* The temporaries introduced to allow us to not consider register
     overlap.  */
  rtx temporary;
  /* The insns we've emitted.  */
  rtx_insn *unmodified_insn;
  /* True if a simple move can be used instead of a conditional move.  */
  bool need_cmov;
};

/* Used by noce_process_if_block to communicate with its subroutines.

   The subroutines know that A and B may be evaluated freely.  They
   know that X is a register.  They should insert new instructions
   before cond_earliest.  */

struct noce_if_info
{
  /* The basic blocks that make up the IF-THEN-{ELSE-,}JOIN block.  */
  basic_block test_bb, then_bb, else_bb, join_bb;

  /* The jump that ends TEST_BB.  */
  rtx_insn *jump;

  /* The jump condition.  */
  rtx cond;

  /* Reversed jump condition.  */
  rtx rev_cond;

  /* New insns should be inserted before this one.  */
  rtx_insn *cond_earliest;

  /* Insns in the THEN and ELSE block.  There is always just this
     one insns in those blocks.  The insns are single_set insns.
     If there was no ELSE block, INSN_B is the last insn before
     COND_EARLIEST, or NULL_RTX.  In the former case, the insn
     operands are still valid, as if INSN_B was moved down below
     the jump.  */
  rtx_insn *insn_a, *insn_b;

  /* The SET_SRC of INSN_A and INSN_B.  */
  rtx a, b;

  /* The SET_DEST of INSN_A.  */
  rtx x;

  /* The original set destination that the THEN and ELSE basic blocks finally
     write their result to.  */
  rtx orig_x;
  /* True if this if block is not canonical.  In the canonical form of
     if blocks, the THEN_BB is the block reached via the fallthru edge
     from TEST_BB.  For the noce transformations, we allow the symmetric
     form as well.  */
  bool then_else_reversed;

  /* True if THEN_BB is conditional on !COND rather than COND.
     This is used if:

     - JUMP branches to THEN_BB on COND
     - JUMP falls through to JOIN_BB on !COND
     - COND cannot be reversed.  */
  bool cond_inverted;

  /* True if the contents of then_bb and else_bb are a
     simple single set instruction.  */
  bool then_simple;
  bool else_simple;

  /* True if we're optimisizing the control block for speed, false if
     we're optimizing for size.  */
  bool speed_p;

  /* An estimate of the original costs.  When optimizing for size, this is the
     combined cost of COND, JUMP and the costs for THEN_BB and ELSE_BB.
     When optimizing for speed, we use the costs of COND plus weighted average
     of the costs for THEN_BB and ELSE_BB, as computed in the next field.  */
  unsigned int original_cost;

  /* Maximum permissible cost for the unconditional sequence we should
     generate to replace this branch.  */
  unsigned int max_seq_cost;

  /* The name of the noce transform that succeeded in if-converting
     this structure.  Used for debugging.  */
  const char *transform_name;
};

#endif /* GCC_IFCVT_H */