xref: /dflybsd-src/contrib/gcc-8.0/gcc/lower-subreg.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj /* Decompose multiword subregs.
238fd1498Szrj    Copyright (C) 2007-2018 Free Software Foundation, Inc.
338fd1498Szrj    Contributed by Richard Henderson <rth@redhat.com>
438fd1498Szrj 		  Ian Lance Taylor <iant@google.com>
538fd1498Szrj 
638fd1498Szrj This file is part of GCC.
738fd1498Szrj 
838fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
938fd1498Szrj the terms of the GNU General Public License as published by the Free
1038fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1138fd1498Szrj version.
1238fd1498Szrj 
1338fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1438fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1538fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1638fd1498Szrj for more details.
1738fd1498Szrj 
1838fd1498Szrj You should have received a copy of the GNU General Public License
1938fd1498Szrj along with GCC; see the file COPYING3.  If not see
2038fd1498Szrj <http://www.gnu.org/licenses/>.  */
2138fd1498Szrj 
2238fd1498Szrj #include "config.h"
2338fd1498Szrj #include "system.h"
2438fd1498Szrj #include "coretypes.h"
2538fd1498Szrj #include "backend.h"
2638fd1498Szrj #include "rtl.h"
2738fd1498Szrj #include "tree.h"
2838fd1498Szrj #include "cfghooks.h"
2938fd1498Szrj #include "df.h"
3038fd1498Szrj #include "memmodel.h"
3138fd1498Szrj #include "tm_p.h"
3238fd1498Szrj #include "expmed.h"
3338fd1498Szrj #include "insn-config.h"
3438fd1498Szrj #include "emit-rtl.h"
3538fd1498Szrj #include "recog.h"
3638fd1498Szrj #include "cfgrtl.h"
3738fd1498Szrj #include "cfgbuild.h"
3838fd1498Szrj #include "dce.h"
3938fd1498Szrj #include "expr.h"
4038fd1498Szrj #include "tree-pass.h"
4138fd1498Szrj #include "lower-subreg.h"
4238fd1498Szrj #include "rtl-iter.h"
4338fd1498Szrj #include "target.h"
4438fd1498Szrj 
4538fd1498Szrj 
4638fd1498Szrj /* Decompose multi-word pseudo-registers into individual
4738fd1498Szrj    pseudo-registers when possible and profitable.  This is possible
4838fd1498Szrj    when all the uses of a multi-word register are via SUBREG, or are
4938fd1498Szrj    copies of the register to another location.  Breaking apart the
5038fd1498Szrj    register permits more CSE and permits better register allocation.
5138fd1498Szrj    This is profitable if the machine does not have move instructions
5238fd1498Szrj    to do this.
5338fd1498Szrj 
5438fd1498Szrj    This pass only splits moves with modes that are wider than
5538fd1498Szrj    word_mode and ASHIFTs, LSHIFTRTs, ASHIFTRTs and ZERO_EXTENDs with
5638fd1498Szrj    integer modes that are twice the width of word_mode.  The latter
5738fd1498Szrj    could be generalized if there was a need to do this, but the trend in
5838fd1498Szrj    architectures is to not need this.
5938fd1498Szrj 
6038fd1498Szrj    There are two useful preprocessor defines for use by maintainers:
6138fd1498Szrj 
6238fd1498Szrj    #define LOG_COSTS 1
6338fd1498Szrj 
6438fd1498Szrj    if you wish to see the actual cost estimates that are being used
6538fd1498Szrj    for each mode wider than word mode and the cost estimates for zero
6638fd1498Szrj    extension and the shifts.   This can be useful when port maintainers
6738fd1498Szrj    are tuning insn rtx costs.
6838fd1498Szrj 
6938fd1498Szrj    #define FORCE_LOWERING 1
7038fd1498Szrj 
7138fd1498Szrj    if you wish to test the pass with all the transformation forced on.
7238fd1498Szrj    This can be useful for finding bugs in the transformations.  */
7338fd1498Szrj 
7438fd1498Szrj #define LOG_COSTS 0
7538fd1498Szrj #define FORCE_LOWERING 0
7638fd1498Szrj 
7738fd1498Szrj /* Bit N in this bitmap is set if regno N is used in a context in
7838fd1498Szrj    which we can decompose it.  */
7938fd1498Szrj static bitmap decomposable_context;
8038fd1498Szrj 
8138fd1498Szrj /* Bit N in this bitmap is set if regno N is used in a context in
8238fd1498Szrj    which it can not be decomposed.  */
8338fd1498Szrj static bitmap non_decomposable_context;
8438fd1498Szrj 
8538fd1498Szrj /* Bit N in this bitmap is set if regno N is used in a subreg
8638fd1498Szrj    which changes the mode but not the size.  This typically happens
8738fd1498Szrj    when the register accessed as a floating-point value; we want to
8838fd1498Szrj    avoid generating accesses to its subwords in integer modes.  */
8938fd1498Szrj static bitmap subreg_context;
9038fd1498Szrj 
9138fd1498Szrj /* Bit N in the bitmap in element M of this array is set if there is a
9238fd1498Szrj    copy from reg M to reg N.  */
9338fd1498Szrj static vec<bitmap> reg_copy_graph;
9438fd1498Szrj 
9538fd1498Szrj struct target_lower_subreg default_target_lower_subreg;
9638fd1498Szrj #if SWITCHABLE_TARGET
9738fd1498Szrj struct target_lower_subreg *this_target_lower_subreg
9838fd1498Szrj   = &default_target_lower_subreg;
9938fd1498Szrj #endif
10038fd1498Szrj 
10138fd1498Szrj #define twice_word_mode \
10238fd1498Szrj   this_target_lower_subreg->x_twice_word_mode
10338fd1498Szrj #define choices \
10438fd1498Szrj   this_target_lower_subreg->x_choices
10538fd1498Szrj 
10638fd1498Szrj /* Return true if MODE is a mode we know how to lower.  When returning true,
10738fd1498Szrj    store its byte size in *BYTES and its word size in *WORDS.  */
10838fd1498Szrj 
10938fd1498Szrj static inline bool
interesting_mode_p(machine_mode mode,unsigned int * bytes,unsigned int * words)11038fd1498Szrj interesting_mode_p (machine_mode mode, unsigned int *bytes,
11138fd1498Szrj 		    unsigned int *words)
11238fd1498Szrj {
11338fd1498Szrj   if (!GET_MODE_SIZE (mode).is_constant (bytes))
11438fd1498Szrj     return false;
11538fd1498Szrj   *words = CEIL (*bytes, UNITS_PER_WORD);
11638fd1498Szrj   return true;
11738fd1498Szrj }
11838fd1498Szrj 
11938fd1498Szrj /* RTXes used while computing costs.  */
12038fd1498Szrj struct cost_rtxes {
12138fd1498Szrj   /* Source and target registers.  */
12238fd1498Szrj   rtx source;
12338fd1498Szrj   rtx target;
12438fd1498Szrj 
12538fd1498Szrj   /* A twice_word_mode ZERO_EXTEND of SOURCE.  */
12638fd1498Szrj   rtx zext;
12738fd1498Szrj 
12838fd1498Szrj   /* A shift of SOURCE.  */
12938fd1498Szrj   rtx shift;
13038fd1498Szrj 
13138fd1498Szrj   /* A SET of TARGET.  */
13238fd1498Szrj   rtx set;
13338fd1498Szrj };
13438fd1498Szrj 
13538fd1498Szrj /* Return the cost of a CODE shift in mode MODE by OP1 bits, using the
13638fd1498Szrj    rtxes in RTXES.  SPEED_P selects between the speed and size cost.  */
13738fd1498Szrj 
13838fd1498Szrj static int
shift_cost(bool speed_p,struct cost_rtxes * rtxes,enum rtx_code code,machine_mode mode,int op1)13938fd1498Szrj shift_cost (bool speed_p, struct cost_rtxes *rtxes, enum rtx_code code,
14038fd1498Szrj 	    machine_mode mode, int op1)
14138fd1498Szrj {
14238fd1498Szrj   PUT_CODE (rtxes->shift, code);
14338fd1498Szrj   PUT_MODE (rtxes->shift, mode);
14438fd1498Szrj   PUT_MODE (rtxes->source, mode);
14538fd1498Szrj   XEXP (rtxes->shift, 1) = gen_int_shift_amount (mode, op1);
14638fd1498Szrj   return set_src_cost (rtxes->shift, mode, speed_p);
14738fd1498Szrj }
14838fd1498Szrj 
14938fd1498Szrj /* For each X in the range [0, BITS_PER_WORD), set SPLITTING[X]
15038fd1498Szrj    to true if it is profitable to split a double-word CODE shift
15138fd1498Szrj    of X + BITS_PER_WORD bits.  SPEED_P says whether we are testing
15238fd1498Szrj    for speed or size profitability.
15338fd1498Szrj 
15438fd1498Szrj    Use the rtxes in RTXES to calculate costs.  WORD_MOVE_ZERO_COST is
15538fd1498Szrj    the cost of moving zero into a word-mode register.  WORD_MOVE_COST
15638fd1498Szrj    is the cost of moving between word registers.  */
15738fd1498Szrj 
15838fd1498Szrj static void
compute_splitting_shift(bool speed_p,struct cost_rtxes * rtxes,bool * splitting,enum rtx_code code,int word_move_zero_cost,int word_move_cost)15938fd1498Szrj compute_splitting_shift (bool speed_p, struct cost_rtxes *rtxes,
16038fd1498Szrj 			 bool *splitting, enum rtx_code code,
16138fd1498Szrj 			 int word_move_zero_cost, int word_move_cost)
16238fd1498Szrj {
16338fd1498Szrj   int wide_cost, narrow_cost, upper_cost, i;
16438fd1498Szrj 
16538fd1498Szrj   for (i = 0; i < BITS_PER_WORD; i++)
16638fd1498Szrj     {
16738fd1498Szrj       wide_cost = shift_cost (speed_p, rtxes, code, twice_word_mode,
16838fd1498Szrj 			      i + BITS_PER_WORD);
16938fd1498Szrj       if (i == 0)
17038fd1498Szrj 	narrow_cost = word_move_cost;
17138fd1498Szrj       else
17238fd1498Szrj 	narrow_cost = shift_cost (speed_p, rtxes, code, word_mode, i);
17338fd1498Szrj 
17438fd1498Szrj       if (code != ASHIFTRT)
17538fd1498Szrj 	upper_cost = word_move_zero_cost;
17638fd1498Szrj       else if (i == BITS_PER_WORD - 1)
17738fd1498Szrj 	upper_cost = word_move_cost;
17838fd1498Szrj       else
17938fd1498Szrj 	upper_cost = shift_cost (speed_p, rtxes, code, word_mode,
18038fd1498Szrj 				 BITS_PER_WORD - 1);
18138fd1498Szrj 
18238fd1498Szrj       if (LOG_COSTS)
18338fd1498Szrj 	fprintf (stderr, "%s %s by %d: original cost %d, split cost %d + %d\n",
18438fd1498Szrj 		 GET_MODE_NAME (twice_word_mode), GET_RTX_NAME (code),
18538fd1498Szrj 		 i + BITS_PER_WORD, wide_cost, narrow_cost, upper_cost);
18638fd1498Szrj 
18738fd1498Szrj       if (FORCE_LOWERING || wide_cost >= narrow_cost + upper_cost)
18838fd1498Szrj 	splitting[i] = true;
18938fd1498Szrj     }
19038fd1498Szrj }
19138fd1498Szrj 
19238fd1498Szrj /* Compute what we should do when optimizing for speed or size; SPEED_P
19338fd1498Szrj    selects which.  Use RTXES for computing costs.  */
19438fd1498Szrj 
19538fd1498Szrj static void
compute_costs(bool speed_p,struct cost_rtxes * rtxes)19638fd1498Szrj compute_costs (bool speed_p, struct cost_rtxes *rtxes)
19738fd1498Szrj {
19838fd1498Szrj   unsigned int i;
19938fd1498Szrj   int word_move_zero_cost, word_move_cost;
20038fd1498Szrj 
20138fd1498Szrj   PUT_MODE (rtxes->target, word_mode);
20238fd1498Szrj   SET_SRC (rtxes->set) = CONST0_RTX (word_mode);
20338fd1498Szrj   word_move_zero_cost = set_rtx_cost (rtxes->set, speed_p);
20438fd1498Szrj 
20538fd1498Szrj   SET_SRC (rtxes->set) = rtxes->source;
20638fd1498Szrj   word_move_cost = set_rtx_cost (rtxes->set, speed_p);
20738fd1498Szrj 
20838fd1498Szrj   if (LOG_COSTS)
20938fd1498Szrj     fprintf (stderr, "%s move: from zero cost %d, from reg cost %d\n",
21038fd1498Szrj 	     GET_MODE_NAME (word_mode), word_move_zero_cost, word_move_cost);
21138fd1498Szrj 
21238fd1498Szrj   for (i = 0; i < MAX_MACHINE_MODE; i++)
21338fd1498Szrj     {
21438fd1498Szrj       machine_mode mode = (machine_mode) i;
21538fd1498Szrj       unsigned int size, factor;
21638fd1498Szrj       if (interesting_mode_p (mode, &size, &factor) && factor > 1)
21738fd1498Szrj 	{
21838fd1498Szrj 	  unsigned int mode_move_cost;
21938fd1498Szrj 
22038fd1498Szrj 	  PUT_MODE (rtxes->target, mode);
22138fd1498Szrj 	  PUT_MODE (rtxes->source, mode);
22238fd1498Szrj 	  mode_move_cost = set_rtx_cost (rtxes->set, speed_p);
22338fd1498Szrj 
22438fd1498Szrj 	  if (LOG_COSTS)
22538fd1498Szrj 	    fprintf (stderr, "%s move: original cost %d, split cost %d * %d\n",
22638fd1498Szrj 		     GET_MODE_NAME (mode), mode_move_cost,
22738fd1498Szrj 		     word_move_cost, factor);
22838fd1498Szrj 
22938fd1498Szrj 	  if (FORCE_LOWERING || mode_move_cost >= word_move_cost * factor)
23038fd1498Szrj 	    {
23138fd1498Szrj 	      choices[speed_p].move_modes_to_split[i] = true;
23238fd1498Szrj 	      choices[speed_p].something_to_do = true;
23338fd1498Szrj 	    }
23438fd1498Szrj 	}
23538fd1498Szrj     }
23638fd1498Szrj 
23738fd1498Szrj   /* For the moves and shifts, the only case that is checked is one
23838fd1498Szrj      where the mode of the target is an integer mode twice the width
23938fd1498Szrj      of the word_mode.
24038fd1498Szrj 
24138fd1498Szrj      If it is not profitable to split a double word move then do not
24238fd1498Szrj      even consider the shifts or the zero extension.  */
24338fd1498Szrj   if (choices[speed_p].move_modes_to_split[(int) twice_word_mode])
24438fd1498Szrj     {
24538fd1498Szrj       int zext_cost;
24638fd1498Szrj 
24738fd1498Szrj       /* The only case here to check to see if moving the upper part with a
24838fd1498Szrj 	 zero is cheaper than doing the zext itself.  */
24938fd1498Szrj       PUT_MODE (rtxes->source, word_mode);
25038fd1498Szrj       zext_cost = set_src_cost (rtxes->zext, twice_word_mode, speed_p);
25138fd1498Szrj 
25238fd1498Szrj       if (LOG_COSTS)
25338fd1498Szrj 	fprintf (stderr, "%s %s: original cost %d, split cost %d + %d\n",
25438fd1498Szrj 		 GET_MODE_NAME (twice_word_mode), GET_RTX_NAME (ZERO_EXTEND),
25538fd1498Szrj 		 zext_cost, word_move_cost, word_move_zero_cost);
25638fd1498Szrj 
25738fd1498Szrj       if (FORCE_LOWERING || zext_cost >= word_move_cost + word_move_zero_cost)
25838fd1498Szrj 	choices[speed_p].splitting_zext = true;
25938fd1498Szrj 
26038fd1498Szrj       compute_splitting_shift (speed_p, rtxes,
26138fd1498Szrj 			       choices[speed_p].splitting_ashift, ASHIFT,
26238fd1498Szrj 			       word_move_zero_cost, word_move_cost);
26338fd1498Szrj       compute_splitting_shift (speed_p, rtxes,
26438fd1498Szrj 			       choices[speed_p].splitting_lshiftrt, LSHIFTRT,
26538fd1498Szrj 			       word_move_zero_cost, word_move_cost);
26638fd1498Szrj       compute_splitting_shift (speed_p, rtxes,
26738fd1498Szrj 			       choices[speed_p].splitting_ashiftrt, ASHIFTRT,
26838fd1498Szrj 			       word_move_zero_cost, word_move_cost);
26938fd1498Szrj     }
27038fd1498Szrj }
27138fd1498Szrj 
27238fd1498Szrj /* Do one-per-target initialisation.  This involves determining
27338fd1498Szrj    which operations on the machine are profitable.  If none are found,
27438fd1498Szrj    then the pass just returns when called.  */
27538fd1498Szrj 
27638fd1498Szrj void
init_lower_subreg(void)27738fd1498Szrj init_lower_subreg (void)
27838fd1498Szrj {
27938fd1498Szrj   struct cost_rtxes rtxes;
28038fd1498Szrj 
28138fd1498Szrj   memset (this_target_lower_subreg, 0, sizeof (*this_target_lower_subreg));
28238fd1498Szrj 
28338fd1498Szrj   twice_word_mode = GET_MODE_2XWIDER_MODE (word_mode).require ();
28438fd1498Szrj 
28538fd1498Szrj   rtxes.target = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
28638fd1498Szrj   rtxes.source = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 2);
28738fd1498Szrj   rtxes.set = gen_rtx_SET (rtxes.target, rtxes.source);
28838fd1498Szrj   rtxes.zext = gen_rtx_ZERO_EXTEND (twice_word_mode, rtxes.source);
28938fd1498Szrj   rtxes.shift = gen_rtx_ASHIFT (twice_word_mode, rtxes.source, const0_rtx);
29038fd1498Szrj 
29138fd1498Szrj   if (LOG_COSTS)
29238fd1498Szrj     fprintf (stderr, "\nSize costs\n==========\n\n");
29338fd1498Szrj   compute_costs (false, &rtxes);
29438fd1498Szrj 
29538fd1498Szrj   if (LOG_COSTS)
29638fd1498Szrj     fprintf (stderr, "\nSpeed costs\n===========\n\n");
29738fd1498Szrj   compute_costs (true, &rtxes);
29838fd1498Szrj }
29938fd1498Szrj 
30038fd1498Szrj static bool
simple_move_operand(rtx x)30138fd1498Szrj simple_move_operand (rtx x)
30238fd1498Szrj {
30338fd1498Szrj   if (GET_CODE (x) == SUBREG)
30438fd1498Szrj     x = SUBREG_REG (x);
30538fd1498Szrj 
30638fd1498Szrj   if (!OBJECT_P (x))
30738fd1498Szrj     return false;
30838fd1498Szrj 
30938fd1498Szrj   if (GET_CODE (x) == LABEL_REF
31038fd1498Szrj       || GET_CODE (x) == SYMBOL_REF
31138fd1498Szrj       || GET_CODE (x) == HIGH
31238fd1498Szrj       || GET_CODE (x) == CONST)
31338fd1498Szrj     return false;
31438fd1498Szrj 
31538fd1498Szrj   if (MEM_P (x)
31638fd1498Szrj       && (MEM_VOLATILE_P (x)
31738fd1498Szrj 	  || mode_dependent_address_p (XEXP (x, 0), MEM_ADDR_SPACE (x))))
31838fd1498Szrj     return false;
31938fd1498Szrj 
32038fd1498Szrj   return true;
32138fd1498Szrj }
32238fd1498Szrj 
32338fd1498Szrj /* If INSN is a single set between two objects that we want to split,
32438fd1498Szrj    return the single set.  SPEED_P says whether we are optimizing
32538fd1498Szrj    INSN for speed or size.
32638fd1498Szrj 
32738fd1498Szrj    INSN should have been passed to recog and extract_insn before this
32838fd1498Szrj    is called.  */
32938fd1498Szrj 
33038fd1498Szrj static rtx
simple_move(rtx_insn * insn,bool speed_p)33138fd1498Szrj simple_move (rtx_insn *insn, bool speed_p)
33238fd1498Szrj {
33338fd1498Szrj   rtx x;
33438fd1498Szrj   rtx set;
33538fd1498Szrj   machine_mode mode;
33638fd1498Szrj 
33738fd1498Szrj   if (recog_data.n_operands != 2)
33838fd1498Szrj     return NULL_RTX;
33938fd1498Szrj 
34038fd1498Szrj   set = single_set (insn);
34138fd1498Szrj   if (!set)
34238fd1498Szrj     return NULL_RTX;
34338fd1498Szrj 
34438fd1498Szrj   x = SET_DEST (set);
34538fd1498Szrj   if (x != recog_data.operand[0] && x != recog_data.operand[1])
34638fd1498Szrj     return NULL_RTX;
34738fd1498Szrj   if (!simple_move_operand (x))
34838fd1498Szrj     return NULL_RTX;
34938fd1498Szrj 
35038fd1498Szrj   x = SET_SRC (set);
35138fd1498Szrj   if (x != recog_data.operand[0] && x != recog_data.operand[1])
35238fd1498Szrj     return NULL_RTX;
35338fd1498Szrj   /* For the src we can handle ASM_OPERANDS, and it is beneficial for
35438fd1498Szrj      things like x86 rdtsc which returns a DImode value.  */
35538fd1498Szrj   if (GET_CODE (x) != ASM_OPERANDS
35638fd1498Szrj       && !simple_move_operand (x))
35738fd1498Szrj     return NULL_RTX;
35838fd1498Szrj 
35938fd1498Szrj   /* We try to decompose in integer modes, to avoid generating
36038fd1498Szrj      inefficient code copying between integer and floating point
36138fd1498Szrj      registers.  That means that we can't decompose if this is a
36238fd1498Szrj      non-integer mode for which there is no integer mode of the same
36338fd1498Szrj      size.  */
36438fd1498Szrj   mode = GET_MODE (SET_DEST (set));
36538fd1498Szrj   if (!SCALAR_INT_MODE_P (mode)
36638fd1498Szrj       && !int_mode_for_size (GET_MODE_BITSIZE (mode), 0).exists ())
36738fd1498Szrj     return NULL_RTX;
36838fd1498Szrj 
36938fd1498Szrj   /* Reject PARTIAL_INT modes.  They are used for processor specific
37038fd1498Szrj      purposes and it's probably best not to tamper with them.  */
37138fd1498Szrj   if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
37238fd1498Szrj     return NULL_RTX;
37338fd1498Szrj 
37438fd1498Szrj   if (!choices[speed_p].move_modes_to_split[(int) mode])
37538fd1498Szrj     return NULL_RTX;
37638fd1498Szrj 
37738fd1498Szrj   return set;
37838fd1498Szrj }
37938fd1498Szrj 
38038fd1498Szrj /* If SET is a copy from one multi-word pseudo-register to another,
38138fd1498Szrj    record that in reg_copy_graph.  Return whether it is such a
38238fd1498Szrj    copy.  */
38338fd1498Szrj 
38438fd1498Szrj static bool
find_pseudo_copy(rtx set)38538fd1498Szrj find_pseudo_copy (rtx set)
38638fd1498Szrj {
38738fd1498Szrj   rtx dest = SET_DEST (set);
38838fd1498Szrj   rtx src = SET_SRC (set);
38938fd1498Szrj   unsigned int rd, rs;
39038fd1498Szrj   bitmap b;
39138fd1498Szrj 
39238fd1498Szrj   if (!REG_P (dest) || !REG_P (src))
39338fd1498Szrj     return false;
39438fd1498Szrj 
39538fd1498Szrj   rd = REGNO (dest);
39638fd1498Szrj   rs = REGNO (src);
39738fd1498Szrj   if (HARD_REGISTER_NUM_P (rd) || HARD_REGISTER_NUM_P (rs))
39838fd1498Szrj     return false;
39938fd1498Szrj 
40038fd1498Szrj   b = reg_copy_graph[rs];
40138fd1498Szrj   if (b == NULL)
40238fd1498Szrj     {
40338fd1498Szrj       b = BITMAP_ALLOC (NULL);
40438fd1498Szrj       reg_copy_graph[rs] = b;
40538fd1498Szrj     }
40638fd1498Szrj 
40738fd1498Szrj   bitmap_set_bit (b, rd);
40838fd1498Szrj 
40938fd1498Szrj   return true;
41038fd1498Szrj }
41138fd1498Szrj 
41238fd1498Szrj /* Look through the registers in DECOMPOSABLE_CONTEXT.  For each case
41338fd1498Szrj    where they are copied to another register, add the register to
41438fd1498Szrj    which they are copied to DECOMPOSABLE_CONTEXT.  Use
41538fd1498Szrj    NON_DECOMPOSABLE_CONTEXT to limit this--we don't bother to track
41638fd1498Szrj    copies of registers which are in NON_DECOMPOSABLE_CONTEXT.  */
41738fd1498Szrj 
41838fd1498Szrj static void
propagate_pseudo_copies(void)41938fd1498Szrj propagate_pseudo_copies (void)
42038fd1498Szrj {
42138fd1498Szrj   auto_bitmap queue, propagate;
42238fd1498Szrj 
42338fd1498Szrj   bitmap_copy (queue, decomposable_context);
42438fd1498Szrj   do
42538fd1498Szrj     {
42638fd1498Szrj       bitmap_iterator iter;
42738fd1498Szrj       unsigned int i;
42838fd1498Szrj 
42938fd1498Szrj       bitmap_clear (propagate);
43038fd1498Szrj 
43138fd1498Szrj       EXECUTE_IF_SET_IN_BITMAP (queue, 0, i, iter)
43238fd1498Szrj 	{
43338fd1498Szrj 	  bitmap b = reg_copy_graph[i];
43438fd1498Szrj 	  if (b)
43538fd1498Szrj 	    bitmap_ior_and_compl_into (propagate, b, non_decomposable_context);
43638fd1498Szrj 	}
43738fd1498Szrj 
43838fd1498Szrj       bitmap_and_compl (queue, propagate, decomposable_context);
43938fd1498Szrj       bitmap_ior_into (decomposable_context, propagate);
44038fd1498Szrj     }
44138fd1498Szrj   while (!bitmap_empty_p (queue));
44238fd1498Szrj }
44338fd1498Szrj 
44438fd1498Szrj /* A pointer to one of these values is passed to
44538fd1498Szrj    find_decomposable_subregs.  */
44638fd1498Szrj 
44738fd1498Szrj enum classify_move_insn
44838fd1498Szrj {
44938fd1498Szrj   /* Not a simple move from one location to another.  */
45038fd1498Szrj   NOT_SIMPLE_MOVE,
45138fd1498Szrj   /* A simple move we want to decompose.  */
45238fd1498Szrj   DECOMPOSABLE_SIMPLE_MOVE,
45338fd1498Szrj   /* Any other simple move.  */
45438fd1498Szrj   SIMPLE_MOVE
45538fd1498Szrj };
45638fd1498Szrj 
45738fd1498Szrj /* If we find a SUBREG in *LOC which we could use to decompose a
45838fd1498Szrj    pseudo-register, set a bit in DECOMPOSABLE_CONTEXT.  If we find an
45938fd1498Szrj    unadorned register which is not a simple pseudo-register copy,
46038fd1498Szrj    DATA will point at the type of move, and we set a bit in
46138fd1498Szrj    DECOMPOSABLE_CONTEXT or NON_DECOMPOSABLE_CONTEXT as appropriate.  */
46238fd1498Szrj 
46338fd1498Szrj static void
find_decomposable_subregs(rtx * loc,enum classify_move_insn * pcmi)46438fd1498Szrj find_decomposable_subregs (rtx *loc, enum classify_move_insn *pcmi)
46538fd1498Szrj {
46638fd1498Szrj   subrtx_var_iterator::array_type array;
46738fd1498Szrj   FOR_EACH_SUBRTX_VAR (iter, array, *loc, NONCONST)
46838fd1498Szrj     {
46938fd1498Szrj       rtx x = *iter;
47038fd1498Szrj       if (GET_CODE (x) == SUBREG)
47138fd1498Szrj 	{
47238fd1498Szrj 	  rtx inner = SUBREG_REG (x);
47338fd1498Szrj 	  unsigned int regno, outer_size, inner_size, outer_words, inner_words;
47438fd1498Szrj 
47538fd1498Szrj 	  if (!REG_P (inner))
47638fd1498Szrj 	    continue;
47738fd1498Szrj 
47838fd1498Szrj 	  regno = REGNO (inner);
47938fd1498Szrj 	  if (HARD_REGISTER_NUM_P (regno))
48038fd1498Szrj 	    {
48138fd1498Szrj 	      iter.skip_subrtxes ();
48238fd1498Szrj 	      continue;
48338fd1498Szrj 	    }
48438fd1498Szrj 
48538fd1498Szrj 	  if (!interesting_mode_p (GET_MODE (x), &outer_size, &outer_words)
48638fd1498Szrj 	      || !interesting_mode_p (GET_MODE (inner), &inner_size,
48738fd1498Szrj 				      &inner_words))
48838fd1498Szrj 	    continue;
48938fd1498Szrj 
49038fd1498Szrj 	  /* We only try to decompose single word subregs of multi-word
49138fd1498Szrj 	     registers.  When we find one, we return -1 to avoid iterating
49238fd1498Szrj 	     over the inner register.
49338fd1498Szrj 
49438fd1498Szrj 	     ??? This doesn't allow, e.g., DImode subregs of TImode values
49538fd1498Szrj 	     on 32-bit targets.  We would need to record the way the
49638fd1498Szrj 	     pseudo-register was used, and only decompose if all the uses
49738fd1498Szrj 	     were the same number and size of pieces.  Hopefully this
49838fd1498Szrj 	     doesn't happen much.  */
49938fd1498Szrj 
500*58e805e6Szrj 	  if (outer_words == 1
501*58e805e6Szrj 	      && inner_words > 1
502*58e805e6Szrj 	      /* Don't allow to decompose floating point subregs of
503*58e805e6Szrj 		 multi-word pseudos if the floating point mode does
504*58e805e6Szrj 		 not have word size, because otherwise we'd generate
505*58e805e6Szrj 		 a subreg with that floating mode from a different
506*58e805e6Szrj 		 sized integral pseudo which is not allowed by
507*58e805e6Szrj 		 validate_subreg.  */
508*58e805e6Szrj 	      && (!FLOAT_MODE_P (GET_MODE (x))
509*58e805e6Szrj 		  || outer_size == UNITS_PER_WORD))
51038fd1498Szrj 	    {
51138fd1498Szrj 	      bitmap_set_bit (decomposable_context, regno);
51238fd1498Szrj 	      iter.skip_subrtxes ();
51338fd1498Szrj 	      continue;
51438fd1498Szrj 	    }
51538fd1498Szrj 
51638fd1498Szrj 	  /* If this is a cast from one mode to another, where the modes
51738fd1498Szrj 	     have the same size, and they are not tieable, then mark this
51838fd1498Szrj 	     register as non-decomposable.  If we decompose it we are
51938fd1498Szrj 	     likely to mess up whatever the backend is trying to do.  */
52038fd1498Szrj 	  if (outer_words > 1
52138fd1498Szrj 	      && outer_size == inner_size
52238fd1498Szrj 	      && !targetm.modes_tieable_p (GET_MODE (x), GET_MODE (inner)))
52338fd1498Szrj 	    {
52438fd1498Szrj 	      bitmap_set_bit (non_decomposable_context, regno);
52538fd1498Szrj 	      bitmap_set_bit (subreg_context, regno);
52638fd1498Szrj 	      iter.skip_subrtxes ();
52738fd1498Szrj 	      continue;
52838fd1498Szrj 	    }
52938fd1498Szrj 	}
53038fd1498Szrj       else if (REG_P (x))
53138fd1498Szrj 	{
53238fd1498Szrj 	  unsigned int regno, size, words;
53338fd1498Szrj 
53438fd1498Szrj 	  /* We will see an outer SUBREG before we see the inner REG, so
53538fd1498Szrj 	     when we see a plain REG here it means a direct reference to
53638fd1498Szrj 	     the register.
53738fd1498Szrj 
53838fd1498Szrj 	     If this is not a simple copy from one location to another,
53938fd1498Szrj 	     then we can not decompose this register.  If this is a simple
54038fd1498Szrj 	     copy we want to decompose, and the mode is right,
54138fd1498Szrj 	     then we mark the register as decomposable.
54238fd1498Szrj 	     Otherwise we don't say anything about this register --
54338fd1498Szrj 	     it could be decomposed, but whether that would be
54438fd1498Szrj 	     profitable depends upon how it is used elsewhere.
54538fd1498Szrj 
54638fd1498Szrj 	     We only set bits in the bitmap for multi-word
54738fd1498Szrj 	     pseudo-registers, since those are the only ones we care about
54838fd1498Szrj 	     and it keeps the size of the bitmaps down.  */
54938fd1498Szrj 
55038fd1498Szrj 	  regno = REGNO (x);
55138fd1498Szrj 	  if (!HARD_REGISTER_NUM_P (regno)
55238fd1498Szrj 	      && interesting_mode_p (GET_MODE (x), &size, &words)
55338fd1498Szrj 	      && words > 1)
55438fd1498Szrj 	    {
55538fd1498Szrj 	      switch (*pcmi)
55638fd1498Szrj 		{
55738fd1498Szrj 		case NOT_SIMPLE_MOVE:
55838fd1498Szrj 		  bitmap_set_bit (non_decomposable_context, regno);
55938fd1498Szrj 		  break;
56038fd1498Szrj 		case DECOMPOSABLE_SIMPLE_MOVE:
56138fd1498Szrj 		  if (targetm.modes_tieable_p (GET_MODE (x), word_mode))
56238fd1498Szrj 		    bitmap_set_bit (decomposable_context, regno);
56338fd1498Szrj 		  break;
56438fd1498Szrj 		case SIMPLE_MOVE:
56538fd1498Szrj 		  break;
56638fd1498Szrj 		default:
56738fd1498Szrj 		  gcc_unreachable ();
56838fd1498Szrj 		}
56938fd1498Szrj 	    }
57038fd1498Szrj 	}
57138fd1498Szrj       else if (MEM_P (x))
57238fd1498Szrj 	{
57338fd1498Szrj 	  enum classify_move_insn cmi_mem = NOT_SIMPLE_MOVE;
57438fd1498Szrj 
57538fd1498Szrj 	  /* Any registers used in a MEM do not participate in a
57638fd1498Szrj 	     SIMPLE_MOVE or DECOMPOSABLE_SIMPLE_MOVE.  Do our own recursion
57738fd1498Szrj 	     here, and return -1 to block the parent's recursion.  */
57838fd1498Szrj 	  find_decomposable_subregs (&XEXP (x, 0), &cmi_mem);
57938fd1498Szrj 	  iter.skip_subrtxes ();
58038fd1498Szrj 	}
58138fd1498Szrj     }
58238fd1498Szrj }
58338fd1498Szrj 
58438fd1498Szrj /* Decompose REGNO into word-sized components.  We smash the REG node
58538fd1498Szrj    in place.  This ensures that (1) something goes wrong quickly if we
58638fd1498Szrj    fail to make some replacement, and (2) the debug information inside
58738fd1498Szrj    the symbol table is automatically kept up to date.  */
58838fd1498Szrj 
58938fd1498Szrj static void
decompose_register(unsigned int regno)59038fd1498Szrj decompose_register (unsigned int regno)
59138fd1498Szrj {
59238fd1498Szrj   rtx reg;
59338fd1498Szrj   unsigned int size, words, i;
59438fd1498Szrj   rtvec v;
59538fd1498Szrj 
59638fd1498Szrj   reg = regno_reg_rtx[regno];
59738fd1498Szrj 
59838fd1498Szrj   regno_reg_rtx[regno] = NULL_RTX;
59938fd1498Szrj 
60038fd1498Szrj   if (!interesting_mode_p (GET_MODE (reg), &size, &words))
60138fd1498Szrj     gcc_unreachable ();
60238fd1498Szrj 
60338fd1498Szrj   v = rtvec_alloc (words);
60438fd1498Szrj   for (i = 0; i < words; ++i)
60538fd1498Szrj     RTVEC_ELT (v, i) = gen_reg_rtx_offset (reg, word_mode, i * UNITS_PER_WORD);
60638fd1498Szrj 
60738fd1498Szrj   PUT_CODE (reg, CONCATN);
60838fd1498Szrj   XVEC (reg, 0) = v;
60938fd1498Szrj 
61038fd1498Szrj   if (dump_file)
61138fd1498Szrj     {
61238fd1498Szrj       fprintf (dump_file, "; Splitting reg %u ->", regno);
61338fd1498Szrj       for (i = 0; i < words; ++i)
61438fd1498Szrj 	fprintf (dump_file, " %u", REGNO (XVECEXP (reg, 0, i)));
61538fd1498Szrj       fputc ('\n', dump_file);
61638fd1498Szrj     }
61738fd1498Szrj }
61838fd1498Szrj 
61938fd1498Szrj /* Get a SUBREG of a CONCATN.  */
62038fd1498Szrj 
62138fd1498Szrj static rtx
simplify_subreg_concatn(machine_mode outermode,rtx op,poly_uint64 orig_byte)62238fd1498Szrj simplify_subreg_concatn (machine_mode outermode, rtx op, poly_uint64 orig_byte)
62338fd1498Szrj {
62438fd1498Szrj   unsigned int outer_size, outer_words, inner_size, inner_words;
62538fd1498Szrj   machine_mode innermode, partmode;
62638fd1498Szrj   rtx part;
62738fd1498Szrj   unsigned int final_offset;
62838fd1498Szrj   unsigned int byte;
62938fd1498Szrj 
63038fd1498Szrj   innermode = GET_MODE (op);
63138fd1498Szrj   if (!interesting_mode_p (outermode, &outer_size, &outer_words)
63238fd1498Szrj       || !interesting_mode_p (innermode, &inner_size, &inner_words))
63338fd1498Szrj     gcc_unreachable ();
63438fd1498Szrj 
63538fd1498Szrj   /* Must be constant if interesting_mode_p passes.  */
63638fd1498Szrj   byte = orig_byte.to_constant ();
63738fd1498Szrj   gcc_assert (GET_CODE (op) == CONCATN);
63838fd1498Szrj   gcc_assert (byte % outer_size == 0);
63938fd1498Szrj 
64038fd1498Szrj   gcc_assert (byte < inner_size);
64138fd1498Szrj   if (outer_size > inner_size)
64238fd1498Szrj     return NULL_RTX;
64338fd1498Szrj 
64438fd1498Szrj   inner_size /= XVECLEN (op, 0);
64538fd1498Szrj   part = XVECEXP (op, 0, byte / inner_size);
64638fd1498Szrj   partmode = GET_MODE (part);
64738fd1498Szrj 
64838fd1498Szrj   final_offset = byte % inner_size;
64938fd1498Szrj   if (final_offset + outer_size > inner_size)
65038fd1498Szrj     return NULL_RTX;
65138fd1498Szrj 
65238fd1498Szrj   /* VECTOR_CSTs in debug expressions are expanded into CONCATN instead of
65338fd1498Szrj      regular CONST_VECTORs.  They have vector or integer modes, depending
65438fd1498Szrj      on the capabilities of the target.  Cope with them.  */
65538fd1498Szrj   if (partmode == VOIDmode && VECTOR_MODE_P (innermode))
65638fd1498Szrj     partmode = GET_MODE_INNER (innermode);
65738fd1498Szrj   else if (partmode == VOIDmode)
65838fd1498Szrj     partmode = mode_for_size (inner_size * BITS_PER_UNIT,
65938fd1498Szrj 			      GET_MODE_CLASS (innermode), 0).require ();
66038fd1498Szrj 
66138fd1498Szrj   return simplify_gen_subreg (outermode, part, partmode, final_offset);
66238fd1498Szrj }
66338fd1498Szrj 
66438fd1498Szrj /* Wrapper around simplify_gen_subreg which handles CONCATN.  */
66538fd1498Szrj 
66638fd1498Szrj static rtx
simplify_gen_subreg_concatn(machine_mode outermode,rtx op,machine_mode innermode,unsigned int byte)66738fd1498Szrj simplify_gen_subreg_concatn (machine_mode outermode, rtx op,
66838fd1498Szrj 			     machine_mode innermode, unsigned int byte)
66938fd1498Szrj {
67038fd1498Szrj   rtx ret;
67138fd1498Szrj 
67238fd1498Szrj   /* We have to handle generating a SUBREG of a SUBREG of a CONCATN.
67338fd1498Szrj      If OP is a SUBREG of a CONCATN, then it must be a simple mode
67438fd1498Szrj      change with the same size and offset 0, or it must extract a
67538fd1498Szrj      part.  We shouldn't see anything else here.  */
67638fd1498Szrj   if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == CONCATN)
67738fd1498Szrj     {
67838fd1498Szrj       rtx op2;
67938fd1498Szrj 
68038fd1498Szrj       if (known_eq (GET_MODE_SIZE (GET_MODE (op)),
68138fd1498Szrj 		    GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
68238fd1498Szrj 	  && known_eq (SUBREG_BYTE (op), 0))
68338fd1498Szrj 	return simplify_gen_subreg_concatn (outermode, SUBREG_REG (op),
68438fd1498Szrj 					    GET_MODE (SUBREG_REG (op)), byte);
68538fd1498Szrj 
68638fd1498Szrj       op2 = simplify_subreg_concatn (GET_MODE (op), SUBREG_REG (op),
68738fd1498Szrj 				     SUBREG_BYTE (op));
68838fd1498Szrj       if (op2 == NULL_RTX)
68938fd1498Szrj 	{
69038fd1498Szrj 	  /* We don't handle paradoxical subregs here.  */
69138fd1498Szrj 	  gcc_assert (!paradoxical_subreg_p (outermode, GET_MODE (op)));
69238fd1498Szrj 	  gcc_assert (!paradoxical_subreg_p (op));
69338fd1498Szrj 	  op2 = simplify_subreg_concatn (outermode, SUBREG_REG (op),
69438fd1498Szrj 					 byte + SUBREG_BYTE (op));
69538fd1498Szrj 	  gcc_assert (op2 != NULL_RTX);
69638fd1498Szrj 	  return op2;
69738fd1498Szrj 	}
69838fd1498Szrj 
69938fd1498Szrj       op = op2;
70038fd1498Szrj       gcc_assert (op != NULL_RTX);
70138fd1498Szrj       gcc_assert (innermode == GET_MODE (op));
70238fd1498Szrj     }
70338fd1498Szrj 
70438fd1498Szrj   if (GET_CODE (op) == CONCATN)
70538fd1498Szrj     return simplify_subreg_concatn (outermode, op, byte);
70638fd1498Szrj 
70738fd1498Szrj   ret = simplify_gen_subreg (outermode, op, innermode, byte);
70838fd1498Szrj 
70938fd1498Szrj   /* If we see an insn like (set (reg:DI) (subreg:DI (reg:SI) 0)) then
71038fd1498Szrj      resolve_simple_move will ask for the high part of the paradoxical
71138fd1498Szrj      subreg, which does not have a value.  Just return a zero.  */
71238fd1498Szrj   if (ret == NULL_RTX
71338fd1498Szrj       && paradoxical_subreg_p (op))
71438fd1498Szrj     return CONST0_RTX (outermode);
71538fd1498Szrj 
71638fd1498Szrj   gcc_assert (ret != NULL_RTX);
71738fd1498Szrj   return ret;
71838fd1498Szrj }
71938fd1498Szrj 
72038fd1498Szrj /* Return whether we should resolve X into the registers into which it
72138fd1498Szrj    was decomposed.  */
72238fd1498Szrj 
72338fd1498Szrj static bool
resolve_reg_p(rtx x)72438fd1498Szrj resolve_reg_p (rtx x)
72538fd1498Szrj {
72638fd1498Szrj   return GET_CODE (x) == CONCATN;
72738fd1498Szrj }
72838fd1498Szrj 
72938fd1498Szrj /* Return whether X is a SUBREG of a register which we need to
73038fd1498Szrj    resolve.  */
73138fd1498Szrj 
73238fd1498Szrj static bool
resolve_subreg_p(rtx x)73338fd1498Szrj resolve_subreg_p (rtx x)
73438fd1498Szrj {
73538fd1498Szrj   if (GET_CODE (x) != SUBREG)
73638fd1498Szrj     return false;
73738fd1498Szrj   return resolve_reg_p (SUBREG_REG (x));
73838fd1498Szrj }
73938fd1498Szrj 
74038fd1498Szrj /* Look for SUBREGs in *LOC which need to be decomposed.  */
74138fd1498Szrj 
74238fd1498Szrj static bool
resolve_subreg_use(rtx * loc,rtx insn)74338fd1498Szrj resolve_subreg_use (rtx *loc, rtx insn)
74438fd1498Szrj {
74538fd1498Szrj   subrtx_ptr_iterator::array_type array;
74638fd1498Szrj   FOR_EACH_SUBRTX_PTR (iter, array, loc, NONCONST)
74738fd1498Szrj     {
74838fd1498Szrj       rtx *loc = *iter;
74938fd1498Szrj       rtx x = *loc;
75038fd1498Szrj       if (resolve_subreg_p (x))
75138fd1498Szrj 	{
75238fd1498Szrj 	  x = simplify_subreg_concatn (GET_MODE (x), SUBREG_REG (x),
75338fd1498Szrj 				       SUBREG_BYTE (x));
75438fd1498Szrj 
75538fd1498Szrj 	  /* It is possible for a note to contain a reference which we can
75638fd1498Szrj 	     decompose.  In this case, return 1 to the caller to indicate
75738fd1498Szrj 	     that the note must be removed.  */
75838fd1498Szrj 	  if (!x)
75938fd1498Szrj 	    {
76038fd1498Szrj 	      gcc_assert (!insn);
76138fd1498Szrj 	      return true;
76238fd1498Szrj 	    }
76338fd1498Szrj 
76438fd1498Szrj 	  validate_change (insn, loc, x, 1);
76538fd1498Szrj 	  iter.skip_subrtxes ();
76638fd1498Szrj 	}
76738fd1498Szrj       else if (resolve_reg_p (x))
76838fd1498Szrj 	/* Return 1 to the caller to indicate that we found a direct
76938fd1498Szrj 	   reference to a register which is being decomposed.  This can
77038fd1498Szrj 	   happen inside notes, multiword shift or zero-extend
77138fd1498Szrj 	   instructions.  */
77238fd1498Szrj 	return true;
77338fd1498Szrj     }
77438fd1498Szrj 
77538fd1498Szrj   return false;
77638fd1498Szrj }
77738fd1498Szrj 
77838fd1498Szrj /* Resolve any decomposed registers which appear in register notes on
77938fd1498Szrj    INSN.  */
78038fd1498Szrj 
78138fd1498Szrj static void
resolve_reg_notes(rtx_insn * insn)78238fd1498Szrj resolve_reg_notes (rtx_insn *insn)
78338fd1498Szrj {
78438fd1498Szrj   rtx *pnote, note;
78538fd1498Szrj 
78638fd1498Szrj   note = find_reg_equal_equiv_note (insn);
78738fd1498Szrj   if (note)
78838fd1498Szrj     {
78938fd1498Szrj       int old_count = num_validated_changes ();
79038fd1498Szrj       if (resolve_subreg_use (&XEXP (note, 0), NULL_RTX))
79138fd1498Szrj 	remove_note (insn, note);
79238fd1498Szrj       else
79338fd1498Szrj 	if (old_count != num_validated_changes ())
79438fd1498Szrj 	  df_notes_rescan (insn);
79538fd1498Szrj     }
79638fd1498Szrj 
79738fd1498Szrj   pnote = &REG_NOTES (insn);
79838fd1498Szrj   while (*pnote != NULL_RTX)
79938fd1498Szrj     {
80038fd1498Szrj       bool del = false;
80138fd1498Szrj 
80238fd1498Szrj       note = *pnote;
80338fd1498Szrj       switch (REG_NOTE_KIND (note))
80438fd1498Szrj 	{
80538fd1498Szrj 	case REG_DEAD:
80638fd1498Szrj 	case REG_UNUSED:
80738fd1498Szrj 	  if (resolve_reg_p (XEXP (note, 0)))
80838fd1498Szrj 	    del = true;
80938fd1498Szrj 	  break;
81038fd1498Szrj 
81138fd1498Szrj 	default:
81238fd1498Szrj 	  break;
81338fd1498Szrj 	}
81438fd1498Szrj 
81538fd1498Szrj       if (del)
81638fd1498Szrj 	*pnote = XEXP (note, 1);
81738fd1498Szrj       else
81838fd1498Szrj 	pnote = &XEXP (note, 1);
81938fd1498Szrj     }
82038fd1498Szrj }
82138fd1498Szrj 
82238fd1498Szrj /* Return whether X can be decomposed into subwords.  */
82338fd1498Szrj 
82438fd1498Szrj static bool
can_decompose_p(rtx x)82538fd1498Szrj can_decompose_p (rtx x)
82638fd1498Szrj {
82738fd1498Szrj   if (REG_P (x))
82838fd1498Szrj     {
82938fd1498Szrj       unsigned int regno = REGNO (x);
83038fd1498Szrj 
83138fd1498Szrj       if (HARD_REGISTER_NUM_P (regno))
83238fd1498Szrj 	{
83338fd1498Szrj 	  unsigned int byte, num_bytes, num_words;
83438fd1498Szrj 
83538fd1498Szrj 	  if (!interesting_mode_p (GET_MODE (x), &num_bytes, &num_words))
83638fd1498Szrj 	    return false;
83738fd1498Szrj 	  for (byte = 0; byte < num_bytes; byte += UNITS_PER_WORD)
83838fd1498Szrj 	    if (simplify_subreg_regno (regno, GET_MODE (x), byte, word_mode) < 0)
83938fd1498Szrj 	      return false;
84038fd1498Szrj 	  return true;
84138fd1498Szrj 	}
84238fd1498Szrj       else
84338fd1498Szrj 	return !bitmap_bit_p (subreg_context, regno);
84438fd1498Szrj     }
84538fd1498Szrj 
84638fd1498Szrj   return true;
84738fd1498Szrj }
84838fd1498Szrj 
84938fd1498Szrj /* Decompose the registers used in a simple move SET within INSN.  If
85038fd1498Szrj    we don't change anything, return INSN, otherwise return the start
85138fd1498Szrj    of the sequence of moves.  */
85238fd1498Szrj 
85338fd1498Szrj static rtx_insn *
resolve_simple_move(rtx set,rtx_insn * insn)85438fd1498Szrj resolve_simple_move (rtx set, rtx_insn *insn)
85538fd1498Szrj {
85638fd1498Szrj   rtx src, dest, real_dest;
85738fd1498Szrj   rtx_insn *insns;
85838fd1498Szrj   machine_mode orig_mode, dest_mode;
85938fd1498Szrj   unsigned int orig_size, words;
86038fd1498Szrj   bool pushing;
86138fd1498Szrj 
86238fd1498Szrj   src = SET_SRC (set);
86338fd1498Szrj   dest = SET_DEST (set);
86438fd1498Szrj   orig_mode = GET_MODE (dest);
86538fd1498Szrj 
86638fd1498Szrj   if (!interesting_mode_p (orig_mode, &orig_size, &words))
86738fd1498Szrj     gcc_unreachable ();
86838fd1498Szrj   gcc_assert (words > 1);
86938fd1498Szrj 
87038fd1498Szrj   start_sequence ();
87138fd1498Szrj 
87238fd1498Szrj   /* We have to handle copying from a SUBREG of a decomposed reg where
87338fd1498Szrj      the SUBREG is larger than word size.  Rather than assume that we
87438fd1498Szrj      can take a word_mode SUBREG of the destination, we copy to a new
87538fd1498Szrj      register and then copy that to the destination.  */
87638fd1498Szrj 
87738fd1498Szrj   real_dest = NULL_RTX;
87838fd1498Szrj 
87938fd1498Szrj   if (GET_CODE (src) == SUBREG
88038fd1498Szrj       && resolve_reg_p (SUBREG_REG (src))
88138fd1498Szrj       && (maybe_ne (SUBREG_BYTE (src), 0)
88238fd1498Szrj 	  || maybe_ne (orig_size, GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))))
88338fd1498Szrj     {
88438fd1498Szrj       real_dest = dest;
88538fd1498Szrj       dest = gen_reg_rtx (orig_mode);
88638fd1498Szrj       if (REG_P (real_dest))
88738fd1498Szrj 	REG_ATTRS (dest) = REG_ATTRS (real_dest);
88838fd1498Szrj     }
88938fd1498Szrj 
89038fd1498Szrj   /* Similarly if we are copying to a SUBREG of a decomposed reg where
89138fd1498Szrj      the SUBREG is larger than word size.  */
89238fd1498Szrj 
89338fd1498Szrj   if (GET_CODE (dest) == SUBREG
89438fd1498Szrj       && resolve_reg_p (SUBREG_REG (dest))
89538fd1498Szrj       && (maybe_ne (SUBREG_BYTE (dest), 0)
89638fd1498Szrj 	  || maybe_ne (orig_size,
89738fd1498Szrj 		       GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))))
89838fd1498Szrj     {
89938fd1498Szrj       rtx reg, smove;
90038fd1498Szrj       rtx_insn *minsn;
90138fd1498Szrj 
90238fd1498Szrj       reg = gen_reg_rtx (orig_mode);
90338fd1498Szrj       minsn = emit_move_insn (reg, src);
90438fd1498Szrj       smove = single_set (minsn);
90538fd1498Szrj       gcc_assert (smove != NULL_RTX);
90638fd1498Szrj       resolve_simple_move (smove, minsn);
90738fd1498Szrj       src = reg;
90838fd1498Szrj     }
90938fd1498Szrj 
91038fd1498Szrj   /* If we didn't have any big SUBREGS of decomposed registers, and
91138fd1498Szrj      neither side of the move is a register we are decomposing, then
91238fd1498Szrj      we don't have to do anything here.  */
91338fd1498Szrj 
91438fd1498Szrj   if (src == SET_SRC (set)
91538fd1498Szrj       && dest == SET_DEST (set)
91638fd1498Szrj       && !resolve_reg_p (src)
91738fd1498Szrj       && !resolve_subreg_p (src)
91838fd1498Szrj       && !resolve_reg_p (dest)
91938fd1498Szrj       && !resolve_subreg_p (dest))
92038fd1498Szrj     {
92138fd1498Szrj       end_sequence ();
92238fd1498Szrj       return insn;
92338fd1498Szrj     }
92438fd1498Szrj 
92538fd1498Szrj   /* It's possible for the code to use a subreg of a decomposed
92638fd1498Szrj      register while forming an address.  We need to handle that before
92738fd1498Szrj      passing the address to emit_move_insn.  We pass NULL_RTX as the
92838fd1498Szrj      insn parameter to resolve_subreg_use because we can not validate
92938fd1498Szrj      the insn yet.  */
93038fd1498Szrj   if (MEM_P (src) || MEM_P (dest))
93138fd1498Szrj     {
93238fd1498Szrj       int acg;
93338fd1498Szrj 
93438fd1498Szrj       if (MEM_P (src))
93538fd1498Szrj 	resolve_subreg_use (&XEXP (src, 0), NULL_RTX);
93638fd1498Szrj       if (MEM_P (dest))
93738fd1498Szrj 	resolve_subreg_use (&XEXP (dest, 0), NULL_RTX);
93838fd1498Szrj       acg = apply_change_group ();
93938fd1498Szrj       gcc_assert (acg);
94038fd1498Szrj     }
94138fd1498Szrj 
94238fd1498Szrj   /* If SRC is a register which we can't decompose, or has side
94338fd1498Szrj      effects, we need to move via a temporary register.  */
94438fd1498Szrj 
94538fd1498Szrj   if (!can_decompose_p (src)
94638fd1498Szrj       || side_effects_p (src)
94738fd1498Szrj       || GET_CODE (src) == ASM_OPERANDS)
94838fd1498Szrj     {
94938fd1498Szrj       rtx reg;
95038fd1498Szrj 
95138fd1498Szrj       reg = gen_reg_rtx (orig_mode);
95238fd1498Szrj 
95338fd1498Szrj       if (AUTO_INC_DEC)
95438fd1498Szrj 	{
95538fd1498Szrj 	  rtx_insn *move = emit_move_insn (reg, src);
95638fd1498Szrj 	  if (MEM_P (src))
95738fd1498Szrj 	    {
95838fd1498Szrj 	      rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
95938fd1498Szrj 	      if (note)
96038fd1498Szrj 		add_reg_note (move, REG_INC, XEXP (note, 0));
96138fd1498Szrj 	    }
96238fd1498Szrj 	}
96338fd1498Szrj       else
96438fd1498Szrj 	emit_move_insn (reg, src);
96538fd1498Szrj 
96638fd1498Szrj       src = reg;
96738fd1498Szrj     }
96838fd1498Szrj 
96938fd1498Szrj   /* If DEST is a register which we can't decompose, or has side
97038fd1498Szrj      effects, we need to first move to a temporary register.  We
97138fd1498Szrj      handle the common case of pushing an operand directly.  We also
97238fd1498Szrj      go through a temporary register if it holds a floating point
97338fd1498Szrj      value.  This gives us better code on systems which can't move
97438fd1498Szrj      data easily between integer and floating point registers.  */
97538fd1498Szrj 
97638fd1498Szrj   dest_mode = orig_mode;
97738fd1498Szrj   pushing = push_operand (dest, dest_mode);
97838fd1498Szrj   if (!can_decompose_p (dest)
97938fd1498Szrj       || (side_effects_p (dest) && !pushing)
98038fd1498Szrj       || (!SCALAR_INT_MODE_P (dest_mode)
98138fd1498Szrj 	  && !resolve_reg_p (dest)
98238fd1498Szrj 	  && !resolve_subreg_p (dest)))
98338fd1498Szrj     {
98438fd1498Szrj       if (real_dest == NULL_RTX)
98538fd1498Szrj 	real_dest = dest;
98638fd1498Szrj       if (!SCALAR_INT_MODE_P (dest_mode))
98738fd1498Szrj 	dest_mode = int_mode_for_mode (dest_mode).require ();
98838fd1498Szrj       dest = gen_reg_rtx (dest_mode);
98938fd1498Szrj       if (REG_P (real_dest))
99038fd1498Szrj 	REG_ATTRS (dest) = REG_ATTRS (real_dest);
99138fd1498Szrj     }
99238fd1498Szrj 
99338fd1498Szrj   if (pushing)
99438fd1498Szrj     {
99538fd1498Szrj       unsigned int i, j, jinc;
99638fd1498Szrj 
99738fd1498Szrj       gcc_assert (orig_size % UNITS_PER_WORD == 0);
99838fd1498Szrj       gcc_assert (GET_CODE (XEXP (dest, 0)) != PRE_MODIFY);
99938fd1498Szrj       gcc_assert (GET_CODE (XEXP (dest, 0)) != POST_MODIFY);
100038fd1498Szrj 
100138fd1498Szrj       if (WORDS_BIG_ENDIAN == STACK_GROWS_DOWNWARD)
100238fd1498Szrj 	{
100338fd1498Szrj 	  j = 0;
100438fd1498Szrj 	  jinc = 1;
100538fd1498Szrj 	}
100638fd1498Szrj       else
100738fd1498Szrj 	{
100838fd1498Szrj 	  j = words - 1;
100938fd1498Szrj 	  jinc = -1;
101038fd1498Szrj 	}
101138fd1498Szrj 
101238fd1498Szrj       for (i = 0; i < words; ++i, j += jinc)
101338fd1498Szrj 	{
101438fd1498Szrj 	  rtx temp;
101538fd1498Szrj 
101638fd1498Szrj 	  temp = copy_rtx (XEXP (dest, 0));
101738fd1498Szrj 	  temp = adjust_automodify_address_nv (dest, word_mode, temp,
101838fd1498Szrj 					       j * UNITS_PER_WORD);
101938fd1498Szrj 	  emit_move_insn (temp,
102038fd1498Szrj 			  simplify_gen_subreg_concatn (word_mode, src,
102138fd1498Szrj 						       orig_mode,
102238fd1498Szrj 						       j * UNITS_PER_WORD));
102338fd1498Szrj 	}
102438fd1498Szrj     }
102538fd1498Szrj   else
102638fd1498Szrj     {
102738fd1498Szrj       unsigned int i;
102838fd1498Szrj 
102938fd1498Szrj       if (REG_P (dest) && !HARD_REGISTER_NUM_P (REGNO (dest)))
103038fd1498Szrj 	emit_clobber (dest);
103138fd1498Szrj 
103238fd1498Szrj       for (i = 0; i < words; ++i)
103338fd1498Szrj 	emit_move_insn (simplify_gen_subreg_concatn (word_mode, dest,
103438fd1498Szrj 						     dest_mode,
103538fd1498Szrj 						     i * UNITS_PER_WORD),
103638fd1498Szrj 			simplify_gen_subreg_concatn (word_mode, src,
103738fd1498Szrj 						     orig_mode,
103838fd1498Szrj 						     i * UNITS_PER_WORD));
103938fd1498Szrj     }
104038fd1498Szrj 
104138fd1498Szrj   if (real_dest != NULL_RTX)
104238fd1498Szrj     {
104338fd1498Szrj       rtx mdest, smove;
104438fd1498Szrj       rtx_insn *minsn;
104538fd1498Szrj 
104638fd1498Szrj       if (dest_mode == orig_mode)
104738fd1498Szrj 	mdest = dest;
104838fd1498Szrj       else
104938fd1498Szrj 	mdest = simplify_gen_subreg (orig_mode, dest, GET_MODE (dest), 0);
105038fd1498Szrj       minsn = emit_move_insn (real_dest, mdest);
105138fd1498Szrj 
105238fd1498Szrj   if (AUTO_INC_DEC && MEM_P (real_dest)
105338fd1498Szrj       && !(resolve_reg_p (real_dest) || resolve_subreg_p (real_dest)))
105438fd1498Szrj     {
105538fd1498Szrj       rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
105638fd1498Szrj       if (note)
105738fd1498Szrj 	add_reg_note (minsn, REG_INC, XEXP (note, 0));
105838fd1498Szrj     }
105938fd1498Szrj 
106038fd1498Szrj       smove = single_set (minsn);
106138fd1498Szrj       gcc_assert (smove != NULL_RTX);
106238fd1498Szrj 
106338fd1498Szrj       resolve_simple_move (smove, minsn);
106438fd1498Szrj     }
106538fd1498Szrj 
106638fd1498Szrj   insns = get_insns ();
106738fd1498Szrj   end_sequence ();
106838fd1498Szrj 
106938fd1498Szrj   copy_reg_eh_region_note_forward (insn, insns, NULL_RTX);
107038fd1498Szrj 
107138fd1498Szrj   emit_insn_before (insns, insn);
107238fd1498Szrj 
107338fd1498Szrj   /* If we get here via self-recursion, then INSN is not yet in the insns
107438fd1498Szrj      chain and delete_insn will fail.  We only want to remove INSN from the
107538fd1498Szrj      current sequence.  See PR56738.  */
107638fd1498Szrj   if (in_sequence_p ())
107738fd1498Szrj     remove_insn (insn);
107838fd1498Szrj   else
107938fd1498Szrj     delete_insn (insn);
108038fd1498Szrj 
108138fd1498Szrj   return insns;
108238fd1498Szrj }
108338fd1498Szrj 
108438fd1498Szrj /* Change a CLOBBER of a decomposed register into a CLOBBER of the
108538fd1498Szrj    component registers.  Return whether we changed something.  */
108638fd1498Szrj 
108738fd1498Szrj static bool
resolve_clobber(rtx pat,rtx_insn * insn)108838fd1498Szrj resolve_clobber (rtx pat, rtx_insn *insn)
108938fd1498Szrj {
109038fd1498Szrj   rtx reg;
109138fd1498Szrj   machine_mode orig_mode;
109238fd1498Szrj   unsigned int orig_size, words, i;
109338fd1498Szrj   int ret;
109438fd1498Szrj 
109538fd1498Szrj   reg = XEXP (pat, 0);
109638fd1498Szrj   if (!resolve_reg_p (reg) && !resolve_subreg_p (reg))
109738fd1498Szrj     return false;
109838fd1498Szrj 
109938fd1498Szrj   orig_mode = GET_MODE (reg);
110038fd1498Szrj   if (!interesting_mode_p (orig_mode, &orig_size, &words))
110138fd1498Szrj     gcc_unreachable ();
110238fd1498Szrj 
110338fd1498Szrj   ret = validate_change (NULL_RTX, &XEXP (pat, 0),
110438fd1498Szrj 			 simplify_gen_subreg_concatn (word_mode, reg,
110538fd1498Szrj 						      orig_mode, 0),
110638fd1498Szrj 			 0);
110738fd1498Szrj   df_insn_rescan (insn);
110838fd1498Szrj   gcc_assert (ret != 0);
110938fd1498Szrj 
111038fd1498Szrj   for (i = words - 1; i > 0; --i)
111138fd1498Szrj     {
111238fd1498Szrj       rtx x;
111338fd1498Szrj 
111438fd1498Szrj       x = simplify_gen_subreg_concatn (word_mode, reg, orig_mode,
111538fd1498Szrj 				       i * UNITS_PER_WORD);
111638fd1498Szrj       x = gen_rtx_CLOBBER (VOIDmode, x);
111738fd1498Szrj       emit_insn_after (x, insn);
111838fd1498Szrj     }
111938fd1498Szrj 
112038fd1498Szrj   resolve_reg_notes (insn);
112138fd1498Szrj 
112238fd1498Szrj   return true;
112338fd1498Szrj }
112438fd1498Szrj 
112538fd1498Szrj /* A USE of a decomposed register is no longer meaningful.  Return
112638fd1498Szrj    whether we changed something.  */
112738fd1498Szrj 
112838fd1498Szrj static bool
resolve_use(rtx pat,rtx_insn * insn)112938fd1498Szrj resolve_use (rtx pat, rtx_insn *insn)
113038fd1498Szrj {
113138fd1498Szrj   if (resolve_reg_p (XEXP (pat, 0)) || resolve_subreg_p (XEXP (pat, 0)))
113238fd1498Szrj     {
113338fd1498Szrj       delete_insn (insn);
113438fd1498Szrj       return true;
113538fd1498Szrj     }
113638fd1498Szrj 
113738fd1498Szrj   resolve_reg_notes (insn);
113838fd1498Szrj 
113938fd1498Szrj   return false;
114038fd1498Szrj }
114138fd1498Szrj 
114238fd1498Szrj /* A VAR_LOCATION can be simplified.  */
114338fd1498Szrj 
114438fd1498Szrj static void
resolve_debug(rtx_insn * insn)114538fd1498Szrj resolve_debug (rtx_insn *insn)
114638fd1498Szrj {
114738fd1498Szrj   subrtx_ptr_iterator::array_type array;
114838fd1498Szrj   FOR_EACH_SUBRTX_PTR (iter, array, &PATTERN (insn), NONCONST)
114938fd1498Szrj     {
115038fd1498Szrj       rtx *loc = *iter;
115138fd1498Szrj       rtx x = *loc;
115238fd1498Szrj       if (resolve_subreg_p (x))
115338fd1498Szrj 	{
115438fd1498Szrj 	  x = simplify_subreg_concatn (GET_MODE (x), SUBREG_REG (x),
115538fd1498Szrj 				       SUBREG_BYTE (x));
115638fd1498Szrj 
115738fd1498Szrj 	  if (x)
115838fd1498Szrj 	    *loc = x;
115938fd1498Szrj 	  else
116038fd1498Szrj 	    x = copy_rtx (*loc);
116138fd1498Szrj 	}
116238fd1498Szrj       if (resolve_reg_p (x))
116338fd1498Szrj 	*loc = copy_rtx (x);
116438fd1498Szrj     }
116538fd1498Szrj 
116638fd1498Szrj   df_insn_rescan (insn);
116738fd1498Szrj 
116838fd1498Szrj   resolve_reg_notes (insn);
116938fd1498Szrj }
117038fd1498Szrj 
117138fd1498Szrj /* Check if INSN is a decomposable multiword-shift or zero-extend and
117238fd1498Szrj    set the decomposable_context bitmap accordingly.  SPEED_P is true
117338fd1498Szrj    if we are optimizing INSN for speed rather than size.  Return true
117438fd1498Szrj    if INSN is decomposable.  */
117538fd1498Szrj 
117638fd1498Szrj static bool
find_decomposable_shift_zext(rtx_insn * insn,bool speed_p)117738fd1498Szrj find_decomposable_shift_zext (rtx_insn *insn, bool speed_p)
117838fd1498Szrj {
117938fd1498Szrj   rtx set;
118038fd1498Szrj   rtx op;
118138fd1498Szrj   rtx op_operand;
118238fd1498Szrj 
118338fd1498Szrj   set = single_set (insn);
118438fd1498Szrj   if (!set)
118538fd1498Szrj     return false;
118638fd1498Szrj 
118738fd1498Szrj   op = SET_SRC (set);
118838fd1498Szrj   if (GET_CODE (op) != ASHIFT
118938fd1498Szrj       && GET_CODE (op) != LSHIFTRT
119038fd1498Szrj       && GET_CODE (op) != ASHIFTRT
119138fd1498Szrj       && GET_CODE (op) != ZERO_EXTEND)
119238fd1498Szrj     return false;
119338fd1498Szrj 
119438fd1498Szrj   op_operand = XEXP (op, 0);
119538fd1498Szrj   if (!REG_P (SET_DEST (set)) || !REG_P (op_operand)
119638fd1498Szrj       || HARD_REGISTER_NUM_P (REGNO (SET_DEST (set)))
119738fd1498Szrj       || HARD_REGISTER_NUM_P (REGNO (op_operand))
119838fd1498Szrj       || GET_MODE (op) != twice_word_mode)
119938fd1498Szrj     return false;
120038fd1498Szrj 
120138fd1498Szrj   if (GET_CODE (op) == ZERO_EXTEND)
120238fd1498Szrj     {
120338fd1498Szrj       if (GET_MODE (op_operand) != word_mode
120438fd1498Szrj 	  || !choices[speed_p].splitting_zext)
120538fd1498Szrj 	return false;
120638fd1498Szrj     }
120738fd1498Szrj   else /* left or right shift */
120838fd1498Szrj     {
120938fd1498Szrj       bool *splitting = (GET_CODE (op) == ASHIFT
121038fd1498Szrj 			 ? choices[speed_p].splitting_ashift
121138fd1498Szrj 			 : GET_CODE (op) == ASHIFTRT
121238fd1498Szrj 			 ? choices[speed_p].splitting_ashiftrt
121338fd1498Szrj 			 : choices[speed_p].splitting_lshiftrt);
121438fd1498Szrj       if (!CONST_INT_P (XEXP (op, 1))
121538fd1498Szrj 	  || !IN_RANGE (INTVAL (XEXP (op, 1)), BITS_PER_WORD,
121638fd1498Szrj 			2 * BITS_PER_WORD - 1)
121738fd1498Szrj 	  || !splitting[INTVAL (XEXP (op, 1)) - BITS_PER_WORD])
121838fd1498Szrj 	return false;
121938fd1498Szrj 
122038fd1498Szrj       bitmap_set_bit (decomposable_context, REGNO (op_operand));
122138fd1498Szrj     }
122238fd1498Szrj 
122338fd1498Szrj   bitmap_set_bit (decomposable_context, REGNO (SET_DEST (set)));
122438fd1498Szrj 
122538fd1498Szrj   return true;
122638fd1498Szrj }
122738fd1498Szrj 
122838fd1498Szrj /* Decompose a more than word wide shift (in INSN) of a multiword
122938fd1498Szrj    pseudo or a multiword zero-extend of a wordmode pseudo into a move
123038fd1498Szrj    and 'set to zero' insn.  Return a pointer to the new insn when a
123138fd1498Szrj    replacement was done.  */
123238fd1498Szrj 
123338fd1498Szrj static rtx_insn *
resolve_shift_zext(rtx_insn * insn)123438fd1498Szrj resolve_shift_zext (rtx_insn *insn)
123538fd1498Szrj {
123638fd1498Szrj   rtx set;
123738fd1498Szrj   rtx op;
123838fd1498Szrj   rtx op_operand;
123938fd1498Szrj   rtx_insn *insns;
124038fd1498Szrj   rtx src_reg, dest_reg, dest_upper, upper_src = NULL_RTX;
124138fd1498Szrj   int src_reg_num, dest_reg_num, offset1, offset2, src_offset;
124238fd1498Szrj   scalar_int_mode inner_mode;
124338fd1498Szrj 
124438fd1498Szrj   set = single_set (insn);
124538fd1498Szrj   if (!set)
124638fd1498Szrj     return NULL;
124738fd1498Szrj 
124838fd1498Szrj   op = SET_SRC (set);
124938fd1498Szrj   if (GET_CODE (op) != ASHIFT
125038fd1498Szrj       && GET_CODE (op) != LSHIFTRT
125138fd1498Szrj       && GET_CODE (op) != ASHIFTRT
125238fd1498Szrj       && GET_CODE (op) != ZERO_EXTEND)
125338fd1498Szrj     return NULL;
125438fd1498Szrj 
125538fd1498Szrj   op_operand = XEXP (op, 0);
125638fd1498Szrj   if (!is_a <scalar_int_mode> (GET_MODE (op_operand), &inner_mode))
125738fd1498Szrj     return NULL;
125838fd1498Szrj 
125938fd1498Szrj   /* We can tear this operation apart only if the regs were already
126038fd1498Szrj      torn apart.  */
126138fd1498Szrj   if (!resolve_reg_p (SET_DEST (set)) && !resolve_reg_p (op_operand))
126238fd1498Szrj     return NULL;
126338fd1498Szrj 
126438fd1498Szrj   /* src_reg_num is the number of the word mode register which we
126538fd1498Szrj      are operating on.  For a left shift and a zero_extend on little
126638fd1498Szrj      endian machines this is register 0.  */
126738fd1498Szrj   src_reg_num = (GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFTRT)
126838fd1498Szrj 		? 1 : 0;
126938fd1498Szrj 
127038fd1498Szrj   if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
127138fd1498Szrj     src_reg_num = 1 - src_reg_num;
127238fd1498Szrj 
127338fd1498Szrj   if (GET_CODE (op) == ZERO_EXTEND)
127438fd1498Szrj     dest_reg_num = WORDS_BIG_ENDIAN ? 1 : 0;
127538fd1498Szrj   else
127638fd1498Szrj     dest_reg_num = 1 - src_reg_num;
127738fd1498Szrj 
127838fd1498Szrj   offset1 = UNITS_PER_WORD * dest_reg_num;
127938fd1498Szrj   offset2 = UNITS_PER_WORD * (1 - dest_reg_num);
128038fd1498Szrj   src_offset = UNITS_PER_WORD * src_reg_num;
128138fd1498Szrj 
128238fd1498Szrj   start_sequence ();
128338fd1498Szrj 
128438fd1498Szrj   dest_reg = simplify_gen_subreg_concatn (word_mode, SET_DEST (set),
128538fd1498Szrj                                           GET_MODE (SET_DEST (set)),
128638fd1498Szrj                                           offset1);
128738fd1498Szrj   dest_upper = simplify_gen_subreg_concatn (word_mode, SET_DEST (set),
128838fd1498Szrj 					    GET_MODE (SET_DEST (set)),
128938fd1498Szrj 					    offset2);
129038fd1498Szrj   src_reg = simplify_gen_subreg_concatn (word_mode, op_operand,
129138fd1498Szrj                                          GET_MODE (op_operand),
129238fd1498Szrj                                          src_offset);
129338fd1498Szrj   if (GET_CODE (op) == ASHIFTRT
129438fd1498Szrj       && INTVAL (XEXP (op, 1)) != 2 * BITS_PER_WORD - 1)
129538fd1498Szrj     upper_src = expand_shift (RSHIFT_EXPR, word_mode, copy_rtx (src_reg),
129638fd1498Szrj 			      BITS_PER_WORD - 1, NULL_RTX, 0);
129738fd1498Szrj 
129838fd1498Szrj   if (GET_CODE (op) != ZERO_EXTEND)
129938fd1498Szrj     {
130038fd1498Szrj       int shift_count = INTVAL (XEXP (op, 1));
130138fd1498Szrj       if (shift_count > BITS_PER_WORD)
130238fd1498Szrj 	src_reg = expand_shift (GET_CODE (op) == ASHIFT ?
130338fd1498Szrj 				LSHIFT_EXPR : RSHIFT_EXPR,
130438fd1498Szrj 				word_mode, src_reg,
130538fd1498Szrj 				shift_count - BITS_PER_WORD,
130638fd1498Szrj 				dest_reg, GET_CODE (op) != ASHIFTRT);
130738fd1498Szrj     }
130838fd1498Szrj 
130938fd1498Szrj   if (dest_reg != src_reg)
131038fd1498Szrj     emit_move_insn (dest_reg, src_reg);
131138fd1498Szrj   if (GET_CODE (op) != ASHIFTRT)
131238fd1498Szrj     emit_move_insn (dest_upper, CONST0_RTX (word_mode));
131338fd1498Szrj   else if (INTVAL (XEXP (op, 1)) == 2 * BITS_PER_WORD - 1)
131438fd1498Szrj     emit_move_insn (dest_upper, copy_rtx (src_reg));
131538fd1498Szrj   else
131638fd1498Szrj     emit_move_insn (dest_upper, upper_src);
131738fd1498Szrj   insns = get_insns ();
131838fd1498Szrj 
131938fd1498Szrj   end_sequence ();
132038fd1498Szrj 
132138fd1498Szrj   emit_insn_before (insns, insn);
132238fd1498Szrj 
132338fd1498Szrj   if (dump_file)
132438fd1498Szrj     {
132538fd1498Szrj       rtx_insn *in;
132638fd1498Szrj       fprintf (dump_file, "; Replacing insn: %d with insns: ", INSN_UID (insn));
132738fd1498Szrj       for (in = insns; in != insn; in = NEXT_INSN (in))
132838fd1498Szrj 	fprintf (dump_file, "%d ", INSN_UID (in));
132938fd1498Szrj       fprintf (dump_file, "\n");
133038fd1498Szrj     }
133138fd1498Szrj 
133238fd1498Szrj   delete_insn (insn);
133338fd1498Szrj   return insns;
133438fd1498Szrj }
133538fd1498Szrj 
133638fd1498Szrj /* Print to dump_file a description of what we're doing with shift code CODE.
133738fd1498Szrj    SPLITTING[X] is true if we are splitting shifts by X + BITS_PER_WORD.  */
133838fd1498Szrj 
133938fd1498Szrj static void
dump_shift_choices(enum rtx_code code,bool * splitting)134038fd1498Szrj dump_shift_choices (enum rtx_code code, bool *splitting)
134138fd1498Szrj {
134238fd1498Szrj   int i;
134338fd1498Szrj   const char *sep;
134438fd1498Szrj 
134538fd1498Szrj   fprintf (dump_file,
134638fd1498Szrj 	   "  Splitting mode %s for %s lowering with shift amounts = ",
134738fd1498Szrj 	   GET_MODE_NAME (twice_word_mode), GET_RTX_NAME (code));
134838fd1498Szrj   sep = "";
134938fd1498Szrj   for (i = 0; i < BITS_PER_WORD; i++)
135038fd1498Szrj     if (splitting[i])
135138fd1498Szrj       {
135238fd1498Szrj 	fprintf (dump_file, "%s%d", sep, i + BITS_PER_WORD);
135338fd1498Szrj 	sep = ",";
135438fd1498Szrj       }
135538fd1498Szrj   fprintf (dump_file, "\n");
135638fd1498Szrj }
135738fd1498Szrj 
135838fd1498Szrj /* Print to dump_file a description of what we're doing when optimizing
135938fd1498Szrj    for speed or size; SPEED_P says which.  DESCRIPTION is a description
136038fd1498Szrj    of the SPEED_P choice.  */
136138fd1498Szrj 
136238fd1498Szrj static void
dump_choices(bool speed_p,const char * description)136338fd1498Szrj dump_choices (bool speed_p, const char *description)
136438fd1498Szrj {
136538fd1498Szrj   unsigned int size, factor, i;
136638fd1498Szrj 
136738fd1498Szrj   fprintf (dump_file, "Choices when optimizing for %s:\n", description);
136838fd1498Szrj 
136938fd1498Szrj   for (i = 0; i < MAX_MACHINE_MODE; i++)
137038fd1498Szrj     if (interesting_mode_p ((machine_mode) i, &size, &factor)
137138fd1498Szrj 	&& factor > 1)
137238fd1498Szrj       fprintf (dump_file, "  %s mode %s for copy lowering.\n",
137338fd1498Szrj 	       choices[speed_p].move_modes_to_split[i]
137438fd1498Szrj 	       ? "Splitting"
137538fd1498Szrj 	       : "Skipping",
137638fd1498Szrj 	       GET_MODE_NAME ((machine_mode) i));
137738fd1498Szrj 
137838fd1498Szrj   fprintf (dump_file, "  %s mode %s for zero_extend lowering.\n",
137938fd1498Szrj 	   choices[speed_p].splitting_zext ? "Splitting" : "Skipping",
138038fd1498Szrj 	   GET_MODE_NAME (twice_word_mode));
138138fd1498Szrj 
138238fd1498Szrj   dump_shift_choices (ASHIFT, choices[speed_p].splitting_ashift);
138338fd1498Szrj   dump_shift_choices (LSHIFTRT, choices[speed_p].splitting_lshiftrt);
138438fd1498Szrj   dump_shift_choices (ASHIFTRT, choices[speed_p].splitting_ashiftrt);
138538fd1498Szrj   fprintf (dump_file, "\n");
138638fd1498Szrj }
138738fd1498Szrj 
138838fd1498Szrj /* Look for registers which are always accessed via word-sized SUBREGs
138938fd1498Szrj    or -if DECOMPOSE_COPIES is true- via copies.  Decompose these
139038fd1498Szrj    registers into several word-sized pseudo-registers.  */
139138fd1498Szrj 
139238fd1498Szrj static void
decompose_multiword_subregs(bool decompose_copies)139338fd1498Szrj decompose_multiword_subregs (bool decompose_copies)
139438fd1498Szrj {
139538fd1498Szrj   unsigned int max;
139638fd1498Szrj   basic_block bb;
139738fd1498Szrj   bool speed_p;
139838fd1498Szrj 
139938fd1498Szrj   if (dump_file)
140038fd1498Szrj     {
140138fd1498Szrj       dump_choices (false, "size");
140238fd1498Szrj       dump_choices (true, "speed");
140338fd1498Szrj     }
140438fd1498Szrj 
140538fd1498Szrj   /* Check if this target even has any modes to consider lowering.   */
140638fd1498Szrj   if (!choices[false].something_to_do && !choices[true].something_to_do)
140738fd1498Szrj     {
140838fd1498Szrj       if (dump_file)
140938fd1498Szrj 	fprintf (dump_file, "Nothing to do!\n");
141038fd1498Szrj       return;
141138fd1498Szrj     }
141238fd1498Szrj 
141338fd1498Szrj   max = max_reg_num ();
141438fd1498Szrj 
141538fd1498Szrj   /* First see if there are any multi-word pseudo-registers.  If there
141638fd1498Szrj      aren't, there is nothing we can do.  This should speed up this
141738fd1498Szrj      pass in the normal case, since it should be faster than scanning
141838fd1498Szrj      all the insns.  */
141938fd1498Szrj   {
142038fd1498Szrj     unsigned int i;
142138fd1498Szrj     bool useful_modes_seen = false;
142238fd1498Szrj 
142338fd1498Szrj     for (i = FIRST_PSEUDO_REGISTER; i < max; ++i)
142438fd1498Szrj       if (regno_reg_rtx[i] != NULL)
142538fd1498Szrj 	{
142638fd1498Szrj 	  machine_mode mode = GET_MODE (regno_reg_rtx[i]);
142738fd1498Szrj 	  if (choices[false].move_modes_to_split[(int) mode]
142838fd1498Szrj 	      || choices[true].move_modes_to_split[(int) mode])
142938fd1498Szrj 	    {
143038fd1498Szrj 	      useful_modes_seen = true;
143138fd1498Szrj 	      break;
143238fd1498Szrj 	    }
143338fd1498Szrj 	}
143438fd1498Szrj 
143538fd1498Szrj     if (!useful_modes_seen)
143638fd1498Szrj       {
143738fd1498Szrj 	if (dump_file)
143838fd1498Szrj 	  fprintf (dump_file, "Nothing to lower in this function.\n");
143938fd1498Szrj 	return;
144038fd1498Szrj       }
144138fd1498Szrj   }
144238fd1498Szrj 
144338fd1498Szrj   if (df)
144438fd1498Szrj     {
144538fd1498Szrj       df_set_flags (DF_DEFER_INSN_RESCAN);
144638fd1498Szrj       run_word_dce ();
144738fd1498Szrj     }
144838fd1498Szrj 
144938fd1498Szrj   /* FIXME: It may be possible to change this code to look for each
145038fd1498Szrj      multi-word pseudo-register and to find each insn which sets or
145138fd1498Szrj      uses that register.  That should be faster than scanning all the
145238fd1498Szrj      insns.  */
145338fd1498Szrj 
145438fd1498Szrj   decomposable_context = BITMAP_ALLOC (NULL);
145538fd1498Szrj   non_decomposable_context = BITMAP_ALLOC (NULL);
145638fd1498Szrj   subreg_context = BITMAP_ALLOC (NULL);
145738fd1498Szrj 
145838fd1498Szrj   reg_copy_graph.create (max);
145938fd1498Szrj   reg_copy_graph.safe_grow_cleared (max);
146038fd1498Szrj   memset (reg_copy_graph.address (), 0, sizeof (bitmap) * max);
146138fd1498Szrj 
146238fd1498Szrj   speed_p = optimize_function_for_speed_p (cfun);
146338fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
146438fd1498Szrj     {
146538fd1498Szrj       rtx_insn *insn;
146638fd1498Szrj 
146738fd1498Szrj       FOR_BB_INSNS (bb, insn)
146838fd1498Szrj 	{
146938fd1498Szrj 	  rtx set;
147038fd1498Szrj 	  enum classify_move_insn cmi;
147138fd1498Szrj 	  int i, n;
147238fd1498Szrj 
147338fd1498Szrj 	  if (!INSN_P (insn)
147438fd1498Szrj 	      || GET_CODE (PATTERN (insn)) == CLOBBER
147538fd1498Szrj 	      || GET_CODE (PATTERN (insn)) == USE)
147638fd1498Szrj 	    continue;
147738fd1498Szrj 
147838fd1498Szrj 	  recog_memoized (insn);
147938fd1498Szrj 
148038fd1498Szrj 	  if (find_decomposable_shift_zext (insn, speed_p))
148138fd1498Szrj 	    continue;
148238fd1498Szrj 
148338fd1498Szrj 	  extract_insn (insn);
148438fd1498Szrj 
148538fd1498Szrj 	  set = simple_move (insn, speed_p);
148638fd1498Szrj 
148738fd1498Szrj 	  if (!set)
148838fd1498Szrj 	    cmi = NOT_SIMPLE_MOVE;
148938fd1498Szrj 	  else
149038fd1498Szrj 	    {
149138fd1498Szrj 	      /* We mark pseudo-to-pseudo copies as decomposable during the
149238fd1498Szrj 		 second pass only.  The first pass is so early that there is
149338fd1498Szrj 		 good chance such moves will be optimized away completely by
149438fd1498Szrj 		 subsequent optimizations anyway.
149538fd1498Szrj 
149638fd1498Szrj 		 However, we call find_pseudo_copy even during the first pass
149738fd1498Szrj 		 so as to properly set up the reg_copy_graph.  */
149838fd1498Szrj 	      if (find_pseudo_copy (set))
149938fd1498Szrj 		cmi = decompose_copies? DECOMPOSABLE_SIMPLE_MOVE : SIMPLE_MOVE;
150038fd1498Szrj 	      else
150138fd1498Szrj 		cmi = SIMPLE_MOVE;
150238fd1498Szrj 	    }
150338fd1498Szrj 
150438fd1498Szrj 	  n = recog_data.n_operands;
150538fd1498Szrj 	  for (i = 0; i < n; ++i)
150638fd1498Szrj 	    {
150738fd1498Szrj 	      find_decomposable_subregs (&recog_data.operand[i], &cmi);
150838fd1498Szrj 
150938fd1498Szrj 	      /* We handle ASM_OPERANDS as a special case to support
151038fd1498Szrj 		 things like x86 rdtsc which returns a DImode value.
151138fd1498Szrj 		 We can decompose the output, which will certainly be
151238fd1498Szrj 		 operand 0, but not the inputs.  */
151338fd1498Szrj 
151438fd1498Szrj 	      if (cmi == SIMPLE_MOVE
151538fd1498Szrj 		  && GET_CODE (SET_SRC (set)) == ASM_OPERANDS)
151638fd1498Szrj 		{
151738fd1498Szrj 		  gcc_assert (i == 0);
151838fd1498Szrj 		  cmi = NOT_SIMPLE_MOVE;
151938fd1498Szrj 		}
152038fd1498Szrj 	    }
152138fd1498Szrj 	}
152238fd1498Szrj     }
152338fd1498Szrj 
152438fd1498Szrj   bitmap_and_compl_into (decomposable_context, non_decomposable_context);
152538fd1498Szrj   if (!bitmap_empty_p (decomposable_context))
152638fd1498Szrj     {
152738fd1498Szrj       unsigned int i;
152838fd1498Szrj       sbitmap_iterator sbi;
152938fd1498Szrj       bitmap_iterator iter;
153038fd1498Szrj       unsigned int regno;
153138fd1498Szrj 
153238fd1498Szrj       propagate_pseudo_copies ();
153338fd1498Szrj 
153438fd1498Szrj       auto_sbitmap sub_blocks (last_basic_block_for_fn (cfun));
153538fd1498Szrj       bitmap_clear (sub_blocks);
153638fd1498Szrj 
153738fd1498Szrj       EXECUTE_IF_SET_IN_BITMAP (decomposable_context, 0, regno, iter)
153838fd1498Szrj 	decompose_register (regno);
153938fd1498Szrj 
154038fd1498Szrj       FOR_EACH_BB_FN (bb, cfun)
154138fd1498Szrj 	{
154238fd1498Szrj 	  rtx_insn *insn;
154338fd1498Szrj 
154438fd1498Szrj 	  FOR_BB_INSNS (bb, insn)
154538fd1498Szrj 	    {
154638fd1498Szrj 	      rtx pat;
154738fd1498Szrj 
154838fd1498Szrj 	      if (!INSN_P (insn))
154938fd1498Szrj 		continue;
155038fd1498Szrj 
155138fd1498Szrj 	      pat = PATTERN (insn);
155238fd1498Szrj 	      if (GET_CODE (pat) == CLOBBER)
155338fd1498Szrj 		resolve_clobber (pat, insn);
155438fd1498Szrj 	      else if (GET_CODE (pat) == USE)
155538fd1498Szrj 		resolve_use (pat, insn);
155638fd1498Szrj 	      else if (DEBUG_INSN_P (insn))
155738fd1498Szrj 		resolve_debug (insn);
155838fd1498Szrj 	      else
155938fd1498Szrj 		{
156038fd1498Szrj 		  rtx set;
156138fd1498Szrj 		  int i;
156238fd1498Szrj 
156338fd1498Szrj 		  recog_memoized (insn);
156438fd1498Szrj 		  extract_insn (insn);
156538fd1498Szrj 
156638fd1498Szrj 		  set = simple_move (insn, speed_p);
156738fd1498Szrj 		  if (set)
156838fd1498Szrj 		    {
156938fd1498Szrj 		      rtx_insn *orig_insn = insn;
157038fd1498Szrj 		      bool cfi = control_flow_insn_p (insn);
157138fd1498Szrj 
157238fd1498Szrj 		      /* We can end up splitting loads to multi-word pseudos
157338fd1498Szrj 			 into separate loads to machine word size pseudos.
157438fd1498Szrj 			 When this happens, we first had one load that can
157538fd1498Szrj 			 throw, and after resolve_simple_move we'll have a
157638fd1498Szrj 			 bunch of loads (at least two).  All those loads may
157738fd1498Szrj 			 trap if we can have non-call exceptions, so they
157838fd1498Szrj 			 all will end the current basic block.  We split the
157938fd1498Szrj 			 block after the outer loop over all insns, but we
158038fd1498Szrj 			 make sure here that we will be able to split the
158138fd1498Szrj 			 basic block and still produce the correct control
158238fd1498Szrj 			 flow graph for it.  */
158338fd1498Szrj 		      gcc_assert (!cfi
158438fd1498Szrj 				  || (cfun->can_throw_non_call_exceptions
158538fd1498Szrj 				      && can_throw_internal (insn)));
158638fd1498Szrj 
158738fd1498Szrj 		      insn = resolve_simple_move (set, insn);
158838fd1498Szrj 		      if (insn != orig_insn)
158938fd1498Szrj 			{
159038fd1498Szrj 			  recog_memoized (insn);
159138fd1498Szrj 			  extract_insn (insn);
159238fd1498Szrj 
159338fd1498Szrj 			  if (cfi)
159438fd1498Szrj 			    bitmap_set_bit (sub_blocks, bb->index);
159538fd1498Szrj 			}
159638fd1498Szrj 		    }
159738fd1498Szrj 		  else
159838fd1498Szrj 		    {
159938fd1498Szrj 		      rtx_insn *decomposed_shift;
160038fd1498Szrj 
160138fd1498Szrj 		      decomposed_shift = resolve_shift_zext (insn);
160238fd1498Szrj 		      if (decomposed_shift != NULL_RTX)
160338fd1498Szrj 			{
160438fd1498Szrj 			  insn = decomposed_shift;
160538fd1498Szrj 			  recog_memoized (insn);
160638fd1498Szrj 			  extract_insn (insn);
160738fd1498Szrj 			}
160838fd1498Szrj 		    }
160938fd1498Szrj 
161038fd1498Szrj 		  for (i = recog_data.n_operands - 1; i >= 0; --i)
161138fd1498Szrj 		    resolve_subreg_use (recog_data.operand_loc[i], insn);
161238fd1498Szrj 
161338fd1498Szrj 		  resolve_reg_notes (insn);
161438fd1498Szrj 
161538fd1498Szrj 		  if (num_validated_changes () > 0)
161638fd1498Szrj 		    {
161738fd1498Szrj 		      for (i = recog_data.n_dups - 1; i >= 0; --i)
161838fd1498Szrj 			{
161938fd1498Szrj 			  rtx *pl = recog_data.dup_loc[i];
162038fd1498Szrj 			  int dup_num = recog_data.dup_num[i];
162138fd1498Szrj 			  rtx *px = recog_data.operand_loc[dup_num];
162238fd1498Szrj 
162338fd1498Szrj 			  validate_unshare_change (insn, pl, *px, 1);
162438fd1498Szrj 			}
162538fd1498Szrj 
162638fd1498Szrj 		      i = apply_change_group ();
162738fd1498Szrj 		      gcc_assert (i);
162838fd1498Szrj 		    }
162938fd1498Szrj 		}
163038fd1498Szrj 	    }
163138fd1498Szrj 	}
163238fd1498Szrj 
163338fd1498Szrj       /* If we had insns to split that caused control flow insns in the middle
163438fd1498Szrj 	 of a basic block, split those blocks now.  Note that we only handle
163538fd1498Szrj 	 the case where splitting a load has caused multiple possibly trapping
163638fd1498Szrj 	 loads to appear.  */
163738fd1498Szrj       EXECUTE_IF_SET_IN_BITMAP (sub_blocks, 0, i, sbi)
163838fd1498Szrj 	{
163938fd1498Szrj 	  rtx_insn *insn, *end;
164038fd1498Szrj 	  edge fallthru;
164138fd1498Szrj 
164238fd1498Szrj 	  bb = BASIC_BLOCK_FOR_FN (cfun, i);
164338fd1498Szrj 	  insn = BB_HEAD (bb);
164438fd1498Szrj 	  end = BB_END (bb);
164538fd1498Szrj 
164638fd1498Szrj 	  while (insn != end)
164738fd1498Szrj 	    {
164838fd1498Szrj 	      if (control_flow_insn_p (insn))
164938fd1498Szrj 		{
165038fd1498Szrj 		  /* Split the block after insn.  There will be a fallthru
165138fd1498Szrj 		     edge, which is OK so we keep it.  We have to create the
165238fd1498Szrj 		     exception edges ourselves.  */
165338fd1498Szrj 		  fallthru = split_block (bb, insn);
165438fd1498Szrj 		  rtl_make_eh_edge (NULL, bb, BB_END (bb));
165538fd1498Szrj 		  bb = fallthru->dest;
165638fd1498Szrj 		  insn = BB_HEAD (bb);
165738fd1498Szrj 		}
165838fd1498Szrj 	      else
165938fd1498Szrj 	        insn = NEXT_INSN (insn);
166038fd1498Szrj 	    }
166138fd1498Szrj 	}
166238fd1498Szrj     }
166338fd1498Szrj 
166438fd1498Szrj   {
166538fd1498Szrj     unsigned int i;
166638fd1498Szrj     bitmap b;
166738fd1498Szrj 
166838fd1498Szrj     FOR_EACH_VEC_ELT (reg_copy_graph, i, b)
166938fd1498Szrj       if (b)
167038fd1498Szrj 	BITMAP_FREE (b);
167138fd1498Szrj   }
167238fd1498Szrj 
167338fd1498Szrj   reg_copy_graph.release ();
167438fd1498Szrj 
167538fd1498Szrj   BITMAP_FREE (decomposable_context);
167638fd1498Szrj   BITMAP_FREE (non_decomposable_context);
167738fd1498Szrj   BITMAP_FREE (subreg_context);
167838fd1498Szrj }
167938fd1498Szrj 
168038fd1498Szrj /* Implement first lower subreg pass.  */
168138fd1498Szrj 
168238fd1498Szrj namespace {
168338fd1498Szrj 
168438fd1498Szrj const pass_data pass_data_lower_subreg =
168538fd1498Szrj {
168638fd1498Szrj   RTL_PASS, /* type */
168738fd1498Szrj   "subreg1", /* name */
168838fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
168938fd1498Szrj   TV_LOWER_SUBREG, /* tv_id */
169038fd1498Szrj   0, /* properties_required */
169138fd1498Szrj   0, /* properties_provided */
169238fd1498Szrj   0, /* properties_destroyed */
169338fd1498Szrj   0, /* todo_flags_start */
169438fd1498Szrj   0, /* todo_flags_finish */
169538fd1498Szrj };
169638fd1498Szrj 
169738fd1498Szrj class pass_lower_subreg : public rtl_opt_pass
169838fd1498Szrj {
169938fd1498Szrj public:
pass_lower_subreg(gcc::context * ctxt)170038fd1498Szrj   pass_lower_subreg (gcc::context *ctxt)
170138fd1498Szrj     : rtl_opt_pass (pass_data_lower_subreg, ctxt)
170238fd1498Szrj   {}
170338fd1498Szrj 
170438fd1498Szrj   /* opt_pass methods: */
gate(function *)170538fd1498Szrj   virtual bool gate (function *) { return flag_split_wide_types != 0; }
execute(function *)170638fd1498Szrj   virtual unsigned int execute (function *)
170738fd1498Szrj     {
170838fd1498Szrj       decompose_multiword_subregs (false);
170938fd1498Szrj       return 0;
171038fd1498Szrj     }
171138fd1498Szrj 
171238fd1498Szrj }; // class pass_lower_subreg
171338fd1498Szrj 
171438fd1498Szrj } // anon namespace
171538fd1498Szrj 
171638fd1498Szrj rtl_opt_pass *
make_pass_lower_subreg(gcc::context * ctxt)171738fd1498Szrj make_pass_lower_subreg (gcc::context *ctxt)
171838fd1498Szrj {
171938fd1498Szrj   return new pass_lower_subreg (ctxt);
172038fd1498Szrj }
172138fd1498Szrj 
172238fd1498Szrj /* Implement second lower subreg pass.  */
172338fd1498Szrj 
172438fd1498Szrj namespace {
172538fd1498Szrj 
172638fd1498Szrj const pass_data pass_data_lower_subreg2 =
172738fd1498Szrj {
172838fd1498Szrj   RTL_PASS, /* type */
172938fd1498Szrj   "subreg2", /* name */
173038fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
173138fd1498Szrj   TV_LOWER_SUBREG, /* tv_id */
173238fd1498Szrj   0, /* properties_required */
173338fd1498Szrj   0, /* properties_provided */
173438fd1498Szrj   0, /* properties_destroyed */
173538fd1498Szrj   0, /* todo_flags_start */
173638fd1498Szrj   TODO_df_finish, /* todo_flags_finish */
173738fd1498Szrj };
173838fd1498Szrj 
173938fd1498Szrj class pass_lower_subreg2 : public rtl_opt_pass
174038fd1498Szrj {
174138fd1498Szrj public:
pass_lower_subreg2(gcc::context * ctxt)174238fd1498Szrj   pass_lower_subreg2 (gcc::context *ctxt)
174338fd1498Szrj     : rtl_opt_pass (pass_data_lower_subreg2, ctxt)
174438fd1498Szrj   {}
174538fd1498Szrj 
174638fd1498Szrj   /* opt_pass methods: */
gate(function *)174738fd1498Szrj   virtual bool gate (function *) { return flag_split_wide_types != 0; }
execute(function *)174838fd1498Szrj   virtual unsigned int execute (function *)
174938fd1498Szrj     {
175038fd1498Szrj       decompose_multiword_subregs (true);
175138fd1498Szrj       return 0;
175238fd1498Szrj     }
175338fd1498Szrj 
175438fd1498Szrj }; // class pass_lower_subreg2
175538fd1498Szrj 
175638fd1498Szrj } // anon namespace
175738fd1498Szrj 
175838fd1498Szrj rtl_opt_pass *
make_pass_lower_subreg2(gcc::context * ctxt)175938fd1498Szrj make_pass_lower_subreg2 (gcc::context *ctxt)
176038fd1498Szrj {
176138fd1498Szrj   return new pass_lower_subreg2 (ctxt);
176238fd1498Szrj }
1763