| /* Sign extension elimination optimization for GNU compiler. | 
 |    Copyright (C) 2005 Free Software Foundation, Inc. | 
 |    Contributed by Leehod Baruch <leehod@il.ibm.com> | 
 |  | 
 | This file is part of GCC. | 
 |  | 
 | GCC is free software; you can redistribute it and/or modify it under | 
 | the terms of the GNU General Public License as published by the Free | 
 | -Software Foundation; either version 2, 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 COPYING.  If not, write to the Free | 
 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | 
 | 02111-1307, USA. | 
 |  | 
 | Problem description: | 
 | -------------------- | 
 | In order to support 32bit computations on a 64bit machine, sign | 
 | extension instructions are generated to ensure the correctness of | 
 | the computation. | 
 | A possible policy (as currently implemented) is to generate a sign | 
 | extension right after each 32bit computation. | 
 | Depending on the instruction set of the architecture, some of these | 
 | sign extension instructions may be redundant. | 
 | There are two cases in which the extension may be redundant: | 
 |  | 
 | Case1: | 
 | The instruction that uses the 64bit operands that are sign | 
 | extended has a dual mode that works with 32bit operands. | 
 | For example: | 
 |  | 
 |   int32 a, b; | 
 |  | 
 |   a = ....	       -->	a = .... | 
 |   a = sign extend a    --> | 
 |   b = ....	       -->	b = .... | 
 |   b = sign extend a    --> | 
 | 		       --> | 
 |   cmpd a, b	       -->	cmpw a, b  //half word compare | 
 |  | 
 | Case2: | 
 | The instruction that defines the 64bit operand (which is later sign | 
 | extended) has a dual mode that defines and sign-extends simultaneously | 
 | a 32bit operand.  For example: | 
 |  | 
 |   int32 a; | 
 |  | 
 |   ld a		     -->   lwa a   // load half word and sign extend | 
 |   a = sign extend a  --> | 
 | 		     --> | 
 |   return a	     -->   return a | 
 |  | 
 |  | 
 | General idea for solution: | 
 | -------------------------- | 
 | First, try to merge the sign extension with the instruction that | 
 | defines the source of the extension and (separately) with the | 
 | instructions that uses the extended result.  By doing this, both cases | 
 | of redundancies (as described above) will be eliminated. | 
 |  | 
 | Then, use partial redundancy elimination to place the non redundant | 
 | ones at optimal placements. | 
 |  | 
 |  | 
 | Implementation by example: | 
 | -------------------------- | 
 | Note: The instruction stream is not changed till the last phase. | 
 |  | 
 | Phase 0: Initial code, as currently generated by gcc. | 
 |  | 
 | 			 def1		def3 | 
 | 			 se1	 def2	 se3 | 
 | 			  | \	  |	/ | | 
 | 			  |  \	  |    /  | | 
 | 			  |   \	  |   /	  | | 
 | 			  |    \  |  /	  | | 
 | 			  |	\ | /	  | | 
 | 			  |	 \|/	  | | 
 | 			use1	use2	 use3 | 
 | 					 use4 | 
 | def1 + se1: | 
 | set ((reg:SI 10) (..def1rhs..)) | 
 | set ((reg:DI 100) (sign_extend:DI (reg:SI 10))) | 
 |  | 
 | def2: | 
 | set ((reg:DI 100) (const_int 7)) | 
 |  | 
 | def3 + se3: | 
 | set ((reg:SI 20) (..def3rhs..)) | 
 | set ((reg:DI 100) (sign_extend:DI (reg:SI 20))) | 
 |  | 
 | use1: | 
 | set ((reg:CC...) (compare:CC (reg:DI 100) (...))) | 
 |  | 
 | use2, use3, use4: | 
 | set ((...) (reg:DI 100)) | 
 |  | 
 | Phase 1: Propagate extensions to uses. | 
 |  | 
 | 			 def1		def3 | 
 | 			 se1	 def2	 se3 | 
 | 			  | \	  |	/ | | 
 | 			  |  \	  |    /  | | 
 | 			  |   \	  |   /	  | | 
 | 			  |    \  |  /	  | | 
 | 			  |	\ | /	  | | 
 | 			  |	 \|/	  | | 
 | 			 se	 se	 se | 
 | 			use1	use2	 use3 | 
 | 					 se | 
 | 					 use4 | 
 |  | 
 | From here, all of the subregs are lowpart ! | 
 |  | 
 | def1, def2, def3: No change. | 
 |  | 
 | use1: | 
 | set ((reg:DI 100) (sign_extend:DI ((subreg:SI (reg:DI 100))))) | 
 | set ((reg:CC...) (compare:CC (reg:DI 100) (...))) | 
 |  | 
 | use2, use3, use4: | 
 | set ((reg:DI 100) (sign_extend:DI ((subreg:SI (reg:DI 100))))) | 
 | set ((...) (reg:DI 100)) | 
 |  | 
 |  | 
 | Phase 2: Merge and eliminate locally redundant extensions. | 
 |  | 
 |  | 
 | 			*def1	 def2	*def3 | 
 | 		  [se removed]	  se	 se3 | 
 | 			  | \	  |	/ | | 
 | 			  |  \	  |    /  | | 
 | 			  |   \	  |   /	  | | 
 | 			  |    \  |  /	  | | 
 | 			  |	\ | /	  | | 
 | 			  |	 \|/	  | | 
 | 		  [se removed]	 se	  se | 
 | 			*use1	use2	 use3 | 
 | 				      [se removed] | 
 | 					 use4 | 
 |  | 
 | The instructions that were changed at this phase are marked with | 
 | asterisk. | 
 |  | 
 | *def1: Merge failed. | 
 |        Remove the sign extension instruction, modify def1 and | 
 |        insert a move instruction to assure to correctness of the code. | 
 | set ((subreg:SI (reg:DI 100)) (..def1rhs..)) | 
 | set ((reg:SI 10) (subreg:SI (reg:DI 100))) | 
 |  | 
 | def2 + se: There is no need for merge. | 
 | 	   Def2 is not changed but a sign extension instruction is  | 
 | 	   created. | 
 | set ((reg:DI 100) (const_int 7)) | 
 | set ((reg:DI 100) (sign_extend:DI ((subreg:SI (reg:DI 100))))) | 
 |  | 
 | *def3 + se3: Merge succeeded. | 
 | set ((reg:DI 100) (sign_extend:DI (..def3rhs..))) | 
 | set ((reg:SI 20) (reg:DI 100)) | 
 | set ((reg:DI 100) (sign_extend:DI (reg:SI 20))) | 
 | (The extension instruction is the original one). | 
 |  | 
 | *use1: Merge succeeded.  Remove the sign extension instruction. | 
 | set ((reg:CC...) | 
 |      (compare:CC (subreg:SI (reg:DI 100)) (...))) | 
 |  | 
 | use2, use3: Merge failed.  No change. | 
 |  | 
 | use4: The extension is locally redundant, therefore it is eliminated  | 
 |       at this point. | 
 |  | 
 |  | 
 | Phase 3: Eliminate globally redundant extensions. | 
 |  | 
 | Following the LCM output: | 
 |  | 
 | 			 def1	 def2	 def3 | 
 | 				  se	 se3 | 
 | 			  | \	  |	/ | | 
 | 			  |  \	  |    /  | | 
 | 			  |   se  |   /	  | | 
 | 			  |    \  |  /	  | | 
 | 			  |	\ | /	  | | 
 | 			  |	 \|/	  | | 
 | 				[ses removed] | 
 | 			 use1	use2	 use3 | 
 | 					 use4 | 
 |  | 
 | se: | 
 | set ((reg:DI 100) (sign_extend:DI ((subreg:SI (reg:DI 100))))) | 
 |  | 
 | se3: | 
 | set ((reg:DI 100) (sign_extend:DI (reg:SI 20))) | 
 |  | 
 |  | 
 | Phase 4: Commit changes to the insn stream. | 
 |  | 
 |  | 
 |    def1		   def3			*def1	 def2	*def3 | 
 |     se1	   def2	   se3		    [se removed]       [se removed] | 
 |     | \	    |	  / |			  | \	  |	/ | | 
 |     |  \    |	 /  |	   ------>	  |  \	  |    /  | | 
 |     |	\   |	/   |	   ------>	  |   se  |   /	  | | 
 |     |	 \  |  /    |			  |    \  |  /	  | | 
 |     |	  \ | /	    |			  |	\ | /	  | | 
 |     |	   \|/	    |			  |	 \|/	  | | 
 |    use1	   use2	   use3			 *use1	 use2	 use3 | 
 | 		   use4					 use4 | 
 |  | 
 | The instructions that were changed during the whole optimization are | 
 | marked with asterisk. | 
 |  | 
 | The result: | 
 |  | 
 | def1 + se1: | 
 | [  set ((reg:SI 10) (..def1rhs..))		     ]	 - Deleted | 
 | [  set ((reg:DI 100) (sign_extend:DI (reg:SI 10)))   ]	 - Deleted | 
 | set ((subreg:SI (reg:DI 100)) (..def3rhs..))		 - Inserted | 
 | set ((reg:SI 10) (subreg:SI (reg:DI 100)))		 - Inserted | 
 |  | 
 | def2: | 
 | set ((reg:DI 100) (const_int 7))			 - No change | 
 |  | 
 | def3 + se3: | 
 | [  set ((reg:SI 20) (..def3rhs..))		     ]	 - Deleted | 
 | [  set ((reg:DI 100) (sign_extend:DI (reg:SI 20)))   ]	 - Deleted | 
 | set ((reg:DI 100) (sign_extend:DI (..def3rhs..)))	 - Inserted | 
 | set ((reg:SI 20) (reg:DI 100))				 - Inserted | 
 |  | 
 | use1: | 
 | [  set ((reg:CC...) (compare:CC (reg:DI 100) (...))) ]	 - Deleted | 
 | set ((reg:CC...)					 - Inserted | 
 |      (compare:CC (subreg:SI (reg:DI 100)) (...))) | 
 |  | 
 | use2, use3, use4: | 
 | set ((...) (reg:DI 100))				 - No change | 
 |  | 
 | se:							 - Inserted | 
 | set ((reg:DI 100) (sign_extend:DI ((subreg:SI (reg:DI 100))))) | 
 |  | 
 | Note: Most of the simple move instructions that were inserted will be | 
 |       trivially dead and therefore eliminated. | 
 |  | 
 | The implementation outline: | 
 | --------------------------- | 
 | Some definitions: | 
 |    A web is RELEVANT if at the end of phase 1, his leader's | 
 |      relevancy is {ZERO, SIGN}_EXTENDED_DEF.  The source_mode of | 
 |      the web is the source_mode of his leader. | 
 |    A definition is a candidate for the optimization if it is part | 
 |      of a RELEVANT web and his local source_mode is not narrower | 
 |      then the source_mode of its web. | 
 |    A use is a candidate for the optimization if it is part of a | 
 |      RELEVANT web. | 
 |    A simple explicit extension is a single set instruction that | 
 |      extends a register (or a subregister) to a register (or | 
 |      subregister). | 
 |    A complex explicit extension is an explicit extension instruction | 
 |      that is not simple. | 
 |    A def extension is a simple explicit extension that is | 
 |      also a candidate for the optimization.  This extension is part | 
 |      of the instruction stream, it is not generated by this | 
 |      optimization. | 
 |    A use extension is a simple explicit extension that is generated | 
 |      and stored for candidate use during this optimization.  It is | 
 |      not emitted to the instruction stream till the last phase of | 
 |      the optimization. | 
 |    A reference is an instruction that satisfy at least on of these | 
 |      criteria: | 
 |      - It contains a definition with EXTENDED_DEF relevancy in a RELEVANT web. | 
 |      - It is followed by a def extension. | 
 |      - It contains a candidate use. | 
 |  | 
 | Phase 1: Propagate extensions to uses. | 
 |   In this phase, we find candidate extensions for the optimization | 
 |   and we generate (but not emit) proper extensions "right before the | 
 |   uses". | 
 |  | 
 |   a. Build a DF object. | 
 |   b. Traverse over all the instructions that contains a definition | 
 |      and set their local relevancy and local source_mode like this: | 
 |      - If the instruction is a simple explicit extension instruction, | 
 |        mark it as {ZERO, SIGN}_EXTENDED_DEF according to the extension | 
 |        type and mark its source_mode to be the mode of the quantity | 
 |        that is been extended. | 
 |      - Otherwise, If the instruction has an implicit extension, | 
 |        which means that its high part is an extension of its low part, | 
 |        or if it is a complicated explicit extension, mark it as | 
 |        EXTENDED_DEF and set its source_mode to be the narrowest | 
 |        mode that is been extended in the instruction. | 
 |   c. Traverse over all the instructions that contains a use and set | 
 |      their local relevancy to RELEVANT_USE (except for few corner | 
 |      cases). | 
 |   d. Produce the web.  During union of two entries, update the | 
 |      relevancy and source_mode of the leader.  There are two major | 
 |      guide lines for this update: | 
 |      - If one of the entries is NOT_RELEVANT, mark the leader | 
 |        NOT_RELEVANT. | 
 |      - If one is ZERO_EXTENDED_DEF and the other is SIGN_EXTENDED_DEF | 
 |        (or vice versa) mark the leader as NOT_RELEVANT.  We don't | 
 |        handle this kind of mixed webs. | 
 |      (For more details about this update process, | 
 |       see see_update_leader_extra_info ()). | 
 |   e. Generate uses extensions according to the relevancy and | 
 |      source_mode of the webs. | 
 |  | 
 | Phase 2: Merge and eliminate locally redundant extensions. | 
 |   In this phase, we try to merge def extensions and use | 
 |   extensions with their references, and eliminate redundant extensions | 
 |   in the same basic block. | 
 |  | 
 |   Traverse over all the references.  Do this in basic block number and | 
 |   luid number forward order. | 
 |   For each reference do: | 
 |     a. Peephole optimization - try to merge it with all its | 
 |        def extensions and use extensions in the following | 
 |        order: | 
 |        - Try to merge only the def extensions, one by one. | 
 |        - Try to merge only the use extensions, one by one. | 
 |        - Try to merge any couple of use extensions simultaneously. | 
 |        - Try to merge any def extension with one or two uses | 
 | 	 extensions simultaneously. | 
 |     b. Handle each EXTENDED_DEF in it as if it was already merged with | 
 |        an extension. | 
 |  | 
 |   During the merge process we save the following data for each | 
 |   register in each basic block: | 
 |     a. The first instruction that defines the register in the basic | 
 |        block. | 
 |     b. The last instruction that defines the register in the basic | 
 |        block. | 
 |     c. The first extension of this register before the first | 
 |        instruction that defines it in the basic block. | 
 |     c. The first extension of this register after the last | 
 |        instruction that defines it in the basic block. | 
 |   This data will help us eliminate (or more precisely, not generate) | 
 |   locally redundant extensions, and will be useful in the next stage. | 
 |  | 
 |   While merging extensions with their reference there are 4 possible | 
 |   situations: | 
 |     a. A use extension was merged with the reference: | 
 |        Delete the extension instruction and save the merged reference | 
 |        for phase 4.  (For details, see see_use_extension_merged ()) | 
 |     b. A use extension failed to be merged with the reference: | 
 |        If there is already such an extension in the same basic block | 
 |        and it is not dead at this point, delete the unmerged extension | 
 |        (it is locally redundant), otherwise properly update the above | 
 |        basic block data. | 
 |        (For details, see see_merge_one_use_extension ()) | 
 |     c. A def extension was merged with the reference: | 
 |        Mark this extension as a merged_def extension and properly | 
 |        update the above basic block data. | 
 |        (For details, see see_merge_one_def_extension ()) | 
 |     d. A def extension failed to be merged with the reference: | 
 |        Replace the definition of the NARROWmode register in the | 
 |        reference with the proper subreg of WIDEmode register and save | 
 |        the result as a merged reference.  Also, properly update the | 
 |        the above basic block data. | 
 |        (For details, see see_def_extension_not_merged ()) | 
 |  | 
 | Phase 3: Eliminate globally redundant extensions. | 
 | In this phase, we set the bit vectors input of the edge based LCM | 
 | using the recorded data on the registers in each basic block. | 
 | We also save pointers for all the anticipatable and available | 
 | occurrences of the relevant extensions.  Then we run the LCM. | 
 |  | 
 |   a. Initialize the comp, antloc, kill bit vectors to zero and the | 
 |      transp bit vector to ones. | 
 |  | 
 |   b. Traverse over all the references.  Do this in basic block number | 
 |      and luid number forward order.  For each reference: | 
 |      - Go over all its use extensions.  For each such extension - | 
 | 	 If it is not dead from the beginning of the basic block SET | 
 | 	   the antloc bit of the current extension in the current | 
 | 	   basic block bits. | 
 | 	 If it is not dead till the end of the basic block SET the | 
 | 	   comp bit of the current extension in the current basic | 
 | 	   block bits. | 
 |      - Go over all its def extensions that were merged with | 
 |        it.  For each such extension - | 
 | 	 If it is not dead till the end of the basic block SET the | 
 |   	   comp bit of the current extension in the current basic | 
 | 	   block bits. | 
 | 	 RESET the proper transp and kill bits. | 
 |      - Go over all its def extensions that were not merged | 
 |        with it.  For each such extension - | 
 | 	 RESET the transp bit and SET the kill bit of the current | 
 | 	 extension in the current basic block bits. | 
 |  | 
 |   c. Run the edge based LCM. | 
 |  | 
 | Phase 4: Commit changes to the insn stream. | 
 | This is the only phase that actually changes the instruction stream. | 
 | Up to this point the optimization could be aborted at any time. | 
 | Here we insert extensions at their best placements and delete the | 
 | redundant ones according to the output of the LCM.  We also replace | 
 | some of the instructions according to the second phase merges results. | 
 |  | 
 |   a. Use the pre_delete_map (from the output of the LCM) in order to | 
 |      delete redundant extensions.  This will prevent them from been | 
 |      emitted in the first place. | 
 |  | 
 |   b. Insert extensions on edges where needed according to | 
 |      pre_insert_map and edge_list (from the output of the LCM). | 
 |  | 
 |   c. For each reference do- | 
 |      - Emit all the uses extensions that were not deleted until now, | 
 |        right before the reference. | 
 |      - Delete all the merged and unmerged def extensions from | 
 |        the instruction stream. | 
 |      - Replace the reference with the merged one, if exist. | 
 |  | 
 | The implementation consists of four data structures: | 
 | - Data structure I | 
 |   Purpose: To handle the relevancy of the uses, definitions and webs. | 
 |   Relevant structures: web_entry (from df.h), see_entry_extra_info. | 
 |   Details: This is a disjoint-set data structure.  Most of its functions are | 
 | 	   implemented in web.c.  Each definition and use in the code are | 
 | 	   elements.  A web_entry structure is allocated for each element to | 
 | 	   hold the element's relevancy and source_mode.  The union rules are | 
 | 	   defined in see_update_leader_extra_info (). | 
 | - Data structure II | 
 |   Purpose: To store references and their extensions (uses and defs) | 
 | 	   and to enable traverse over these references according to basic | 
 | 	   block order. | 
 |   Relevant structure: see_ref_s. | 
 |   Details: This data structure consists of an array of splay trees.  One splay | 
 | 	   tree for each basic block.  The splay tree nodes are references and | 
 | 	   the keys are the luids of the references. | 
 | 	   A see_ref_s structure is allocated for each reference.  It holds the | 
 | 	   reference itself, its def and uses extensions and later the merged | 
 | 	   version of the reference. | 
 | 	   Using this data structure we can traverse over all the references of | 
 | 	   a basic block and their extensions in forward order. | 
 | - Data structure III. | 
 |   Purpose: To store local properties of registers for each basic block. | 
 | 	   This data will later help us build the LCM sbitmap_vectors | 
 | 	   input. | 
 |   Relevant structure: see_register_properties. | 
 |   Details: This data structure consists of an array of hash tables.  One hash | 
 | 	   for each basic block.  The hash node are a register properties | 
 | 	   and the keys are the numbers of the registers. | 
 | 	   A see_register_properties structure is allocated for each register | 
 | 	   that we might be interested in its properties. | 
 | 	   Using this data structure we can easily find the properties of a | 
 | 	   register in a specific basic block.  This is necessary for locally | 
 | 	   redundancy elimination and for setting up the LCM input. | 
 | - Data structure IV. | 
 |   Purpose: To store the extensions that are candidate for PRE and their | 
 | 	   anticipatable and available occurrences. | 
 |   Relevant structure: see_occr, see_pre_extension_expr. | 
 |   Details: This data structure is a hash tables.  Its nodes are the extensions | 
 | 	   that are candidate for PRE. | 
 | 	   A see_pre_extension_expr structure is allocated for each candidate | 
 | 	   extension.  It holds a copy of the extension and a linked list of all | 
 | 	   the anticipatable and available occurrences of it. | 
 | 	   We use this data structure when we read the output of the LCM.  */ | 
 |  | 
 | #include "config.h" | 
 | #include "system.h" | 
 | #include "coretypes.h" | 
 | #include "tm.h" | 
 |  | 
 | #include "obstack.h" | 
 | #include "rtl.h" | 
 | #include "output.h" | 
 | #include "df.h" | 
 | #include "insn-config.h" | 
 | #include "recog.h" | 
 | #include "expr.h" | 
 | #include "splay-tree.h" | 
 | #include "hashtab.h" | 
 | #include "regs.h" | 
 | #include "timevar.h" | 
 | #include "tree-pass.h" | 
 |  | 
 | /* Used to classify defs and uses according to relevancy.  */ | 
 | enum entry_type { | 
 |   NOT_RELEVANT, | 
 |   SIGN_EXTENDED_DEF, | 
 |   ZERO_EXTENDED_DEF, | 
 |   EXTENDED_DEF, | 
 |   RELEVANT_USE | 
 | }; | 
 |  | 
 | /* Used to classify extensions in relevant webs.  */ | 
 | enum extension_type { | 
 |   DEF_EXTENSION, | 
 |   EXPLICIT_DEF_EXTENSION, | 
 |   IMPLICIT_DEF_EXTENSION, | 
 |   USE_EXTENSION | 
 | }; | 
 |  | 
 | /* Global data structures and flags.  */ | 
 |  | 
 | /* This structure will be assigned for each web_entry structure (defined | 
 |    in df.h).  It is placed in the extra_info field of a web_entry and holds the | 
 |    relevancy and source mode of the web_entry.  */ | 
 |  | 
 | struct see_entry_extra_info | 
 | { | 
 |   /* The relevancy of the ref.  */ | 
 |   enum entry_type relevancy; | 
 |   /* The relevancy of the ref. | 
 |      This field is updated only once - when this structure is created.  */ | 
 |   enum entry_type local_relevancy; | 
 |   /* The source register mode.  */ | 
 |   enum machine_mode source_mode; | 
 |   /* This field is used only if the relevancy is ZERO/SIGN_EXTENDED_DEF. | 
 |      It is updated only once when this structure is created.  */ | 
 |   enum machine_mode local_source_mode; | 
 |   /* This field is used only if the relevancy is EXTENDED_DEF. | 
 |      It holds the narrowest mode that is sign extended.  */ | 
 |   enum machine_mode source_mode_signed; | 
 |   /* This field is used only if the relevancy is EXTENDED_DEF. | 
 |      It holds the narrowest mode that is zero extended.  */ | 
 |   enum machine_mode source_mode_unsigned; | 
 | }; | 
 |  | 
 | /* There is one such structure for every reference.  It stores the reference | 
 |    itself as well as its extensions (uses and definitions). | 
 |    Used as the value in splay_tree see_bb_splay_ar[].  */ | 
 | struct see_ref_s | 
 | { | 
 |   /* The luid of the insn.  */ | 
 |   unsigned int luid; | 
 |   /* The insn of the ref.  */ | 
 |   rtx insn; | 
 |   /* The merged insn that was formed from the reference's insn and extensions. | 
 |      If all merges failed, it remains NULL.  */ | 
 |   rtx merged_insn; | 
 |   /* The def extensions of the reference that were not merged with | 
 |      it.  */ | 
 |   htab_t unmerged_def_se_hash; | 
 |   /* The def extensions of the reference that were merged with | 
 |      it.  Implicit extensions of the reference will be stored here too.  */ | 
 |   htab_t merged_def_se_hash; | 
 |   /* The uses extensions of reference.  */ | 
 |   htab_t use_se_hash; | 
 | }; | 
 |  | 
 | /* There is one such structure for every relevant extended register in a | 
 |    specific basic block.  This data will help us build the LCM sbitmap_vectors | 
 |    input.  */ | 
 | struct see_register_properties | 
 | { | 
 |   /* The register number.  */ | 
 |   unsigned int regno; | 
 |   /* The last luid of the reference that defines this register in this basic | 
 |      block.  */ | 
 |   int last_def; | 
 |   /* The luid of the reference that has the first extension of this register | 
 |      that appears before any definition in this basic block.  */ | 
 |   int first_se_before_any_def; | 
 |   /* The luid of the reference that has the first extension of this register | 
 |      that appears after the last definition in this basic block.  */ | 
 |   int first_se_after_last_def; | 
 | }; | 
 |  | 
 | /* Occurrence of an expression. | 
 |    There must be at most one available occurrence and at most one anticipatable | 
 |    occurrence per basic block.  */ | 
 | struct see_occr | 
 | { | 
 |   /* Next occurrence of this expression.  */ | 
 |   struct see_occr *next; | 
 |   /* The insn that computes the expression.  */ | 
 |   rtx insn; | 
 |   int block_num; | 
 | }; | 
 |  | 
 | /* There is one such structure for every relevant extension expression. | 
 |    It holds a copy of this extension instruction as well as a linked lists of | 
 |    pointers to all the antic and avail occurrences of it.  */ | 
 | struct see_pre_extension_expr | 
 | { | 
 |   /* A copy of the extension instruction.  */ | 
 |   rtx se_insn; | 
 |   /* Index in the available expression bitmaps.  */ | 
 |   int bitmap_index; | 
 |   /* List of anticipatable occurrences in basic blocks in the function. | 
 |      An "anticipatable occurrence" is the first occurrence in the basic block, | 
 |      the operands are not modified in the basic block prior to the occurrence | 
 |      and the output is not used between the start of the block and the | 
 |      occurrence.  */ | 
 |   struct see_occr *antic_occr; | 
 |   /* List of available occurrence in basic blocks in the function. | 
 |      An "available occurrence" is the last occurrence in the basic block and | 
 |      the operands are not modified by following statements in the basic block | 
 |      [including this insn].  */ | 
 |   struct see_occr *avail_occr; | 
 | }; | 
 |  | 
 | /* Helper structure for the note_uses and see_replace_src functions.  */ | 
 | struct see_replace_data | 
 | { | 
 |   rtx from; | 
 |   rtx to; | 
 | }; | 
 |  | 
 | /* Helper structure for the note_uses and see_mentioned_reg functions.  */ | 
 | struct see_mentioned_reg_data | 
 | { | 
 |   rtx reg; | 
 |   bool mentioned; | 
 | }; | 
 |  | 
 | /* A data flow object that will be created once and used throughout the | 
 |    optimization.  */ | 
 | static struct df *df = NULL; | 
 | /* An array of web_entries.  The i'th definition in the df object is associated | 
 |    with def_entry[i]  */ | 
 | static struct web_entry *def_entry = NULL; | 
 | /* An array of web_entries.  The i'th use in the df object is associated with | 
 |    use_entry[i]  */ | 
 | static struct web_entry *use_entry = NULL; | 
 | /* Array of splay_trees. | 
 |    see_bb_splay_ar[i] refers to the splay tree of the i'th basic block. | 
 |    The splay tree will hold see_ref_s structures.  The key is the luid | 
 |    of the insn.  This way we can traverse over the references of each basic | 
 |    block in forward or backward order.  */ | 
 | static splay_tree *see_bb_splay_ar = NULL; | 
 | /* Array of hashes. | 
 |    see_bb_hash_ar[i] refers to the hash of the i'th basic block. | 
 |    The hash will hold see_register_properties structure.  The key is regno.  */ | 
 | static htab_t *see_bb_hash_ar = NULL; | 
 | /* Hash table that holds a copy of all the extensions.  The key is the right | 
 |    hand side of the se_insn field.  */ | 
 | static htab_t see_pre_extension_hash = NULL; | 
 |  | 
 | /* Local LCM properties of expressions.  */ | 
 | /* Nonzero for expressions that are transparent in the block.  */ | 
 | static sbitmap *transp = NULL; | 
 | /* Nonzero for expressions that are computed (available) in the block.  */ | 
 | static sbitmap *comp = NULL; | 
 | /* Nonzero for expressions that are locally anticipatable in the block.  */ | 
 | static sbitmap *antloc = NULL; | 
 | /* Nonzero for expressions that are locally killed in the block.  */ | 
 | static sbitmap *ae_kill = NULL; | 
 | /* Nonzero for expressions which should be inserted on a specific edge.  */ | 
 | static sbitmap *pre_insert_map = NULL; | 
 | /* Nonzero for expressions which should be deleted in a specific block.  */ | 
 | static sbitmap *pre_delete_map = NULL; | 
 | /* Contains the edge_list returned by pre_edge_lcm.  */ | 
 | static struct edge_list *edge_list = NULL; | 
 | /* Records the last basic block at the beginning of the optimization.  */ | 
 | static int last_bb; | 
 | /* Records the number of uses at the beginning of the optimization.  */ | 
 | static unsigned int uses_num; | 
 | /* Records the number of definitions at the beginning of the optimization.  */ | 
 | static unsigned int defs_num; | 
 |  | 
 | #define ENTRY_EI(ENTRY) ((struct see_entry_extra_info *) (ENTRY)->extra_info) | 
 |  | 
 | /* Functions implementation.  */ | 
 |  | 
 | /*  Verifies that EXTENSION's pattern is this: | 
 |  | 
 |     set (reg/subreg reg1) (sign/zero_extend:WIDEmode (reg/subreg reg2)) | 
 |  | 
 |     If it doesn't have the expected pattern return NULL. | 
 |     Otherwise, if RETURN_DEST_REG is set, return reg1 else return reg2.  */ | 
 |  | 
 | static rtx | 
 | see_get_extension_reg (rtx extension, bool return_dest_reg) | 
 | { | 
 |   rtx set, rhs, lhs; | 
 |   rtx reg1 = NULL; | 
 |   rtx reg2 = NULL; | 
 |  | 
 |   /* Parallel pattern for extension not supported for the moment.  */ | 
 |   if (GET_CODE (PATTERN (extension)) == PARALLEL) | 
 |     return NULL; | 
 |  | 
 |   set = single_set (extension); | 
 |   if (!set) | 
 |     return NULL; | 
 |   lhs = SET_DEST (set); | 
 |   rhs = SET_SRC (set); | 
 |  | 
 |   if (REG_P (lhs)) | 
 |     reg1 = lhs; | 
 |   else if (REG_P (SUBREG_REG (lhs))) | 
 |     reg1 = SUBREG_REG (lhs); | 
 |   else | 
 |     return NULL; | 
 |  | 
 |   if (GET_CODE (rhs) != SIGN_EXTEND && GET_CODE (rhs) != ZERO_EXTEND) | 
 |     return NULL; | 
 |  | 
 |   rhs = XEXP (rhs, 0); | 
 |   if (REG_P (rhs)) | 
 |     reg2 = rhs; | 
 |   else if (REG_P (SUBREG_REG (rhs))) | 
 |     reg2 = SUBREG_REG (rhs); | 
 |   else | 
 |     return NULL; | 
 |  | 
 |   if (return_dest_reg) | 
 |     return reg1; | 
 |   return reg2; | 
 | } | 
 |  | 
 | /*  Verifies that EXTENSION's pattern is this: | 
 |  | 
 |     set (reg/subreg reg1) (sign/zero_extend: (...expr...) | 
 |  | 
 |     If it doesn't have the expected pattern return UNKNOWN. | 
 |     Otherwise, set SOURCE_MODE to be the mode of the extended expr and return | 
 |     the rtx code of the extension.  */ | 
 |  | 
 | static enum rtx_code | 
 | see_get_extension_data (rtx extension, enum machine_mode *source_mode) | 
 | { | 
 |   rtx rhs, lhs, set; | 
 |  | 
 |   if (!extension || !INSN_P (extension)) | 
 |     return UNKNOWN; | 
 |  | 
 |   /* Parallel pattern for extension not supported for the moment.  */ | 
 |   if (GET_CODE (PATTERN (extension)) == PARALLEL) | 
 |     return NOT_RELEVANT; | 
 |  | 
 |   set = single_set (extension); | 
 |   if (!set) | 
 |     return NOT_RELEVANT; | 
 |   rhs = SET_SRC (set); | 
 |   lhs = SET_DEST (set); | 
 |  | 
 |   /* Don't handle extensions to something other then register or | 
 |      subregister.  */ | 
 |   if (!REG_P (lhs) && !SUBREG_REG (lhs)) | 
 |     return UNKNOWN; | 
 |  | 
 |   if (GET_CODE (rhs) != SIGN_EXTEND && GET_CODE (rhs) != ZERO_EXTEND) | 
 |     return UNKNOWN; | 
 |  | 
 |   if (!REG_P (XEXP (rhs, 0)) | 
 |       && !(GET_CODE (XEXP (rhs, 0)) == SUBREG | 
 | 	   && REG_P (SUBREG_REG (XEXP (rhs, 0))))) | 
 |     return UNKNOWN; | 
 |  | 
 |   *source_mode = GET_MODE (XEXP (rhs, 0)); | 
 |  | 
 |   if (GET_CODE (rhs) == SIGN_EXTEND) | 
 |     return SIGN_EXTEND; | 
 |   return ZERO_EXTEND; | 
 | } | 
 |  | 
 |  | 
 | /* Generate instruction with the pattern: | 
 |    set ((reg r) (sign/zero_extend (subreg:mode (reg r)))) | 
 |    (the register r on both sides of the set is the same register). | 
 |    And recognize it. | 
 |    If the recognition failed, this is very bad, return NULL (This will abort | 
 |    the entire optimization). | 
 |    Otherwise, return the generated instruction.  */ | 
 |  | 
 | static rtx | 
 | see_gen_normalized_extension (rtx reg, enum rtx_code extension_code, | 
 |    			      enum machine_mode mode) | 
 | { | 
 |   rtx subreg, insn; | 
 |   rtx extension = NULL; | 
 |  | 
 |   if (!reg | 
 |       || !REG_P (reg) | 
 |       || (extension_code != SIGN_EXTEND && extension_code != ZERO_EXTEND)) | 
 |     return NULL; | 
 |  | 
 |   subreg = gen_lowpart_SUBREG (mode, reg); | 
 |   if (extension_code == SIGN_EXTEND) | 
 |     extension = gen_rtx_SIGN_EXTEND (GET_MODE (reg), subreg); | 
 |   else | 
 |     extension = gen_rtx_ZERO_EXTEND (GET_MODE (reg), subreg); | 
 |  | 
 |   start_sequence (); | 
 |   emit_insn (gen_rtx_SET (VOIDmode, reg, extension)); | 
 |   insn = get_insns (); | 
 |   end_sequence (); | 
 |  | 
 |   if (insn_invalid_p (insn)) | 
 |     /* Recognition failed, this is very bad for this optimization. | 
 |        Abort the optimization.  */ | 
 |     return NULL; | 
 |   return insn; | 
 | } | 
 |  | 
 | /* Hashes and splay_trees related functions implementation.  */ | 
 |  | 
 | /* Helper functions for the pre_extension hash. | 
 |    This kind of hash will hold see_pre_extension_expr structures. | 
 |  | 
 |    The key is the right hand side of the se_insn field. | 
 |    Note that the se_insn is an expression that looks like: | 
 |  | 
 |    set ((reg:WIDEmode r1) (sign_extend:WIDEmode | 
 | 			   (subreg:NARROWmode (reg:WIDEmode r2))))  */ | 
 |  | 
 | /* Return TRUE if P1 has the same value in its rhs as P2. | 
 |    Otherwise, return FALSE. | 
 |    P1 and P2 are see_pre_extension_expr structures.  */ | 
 |  | 
 | static int | 
 | eq_descriptor_pre_extension (const void *p1, const void *p2) | 
 | { | 
 |   const struct see_pre_extension_expr *extension1 = p1; | 
 |   const struct see_pre_extension_expr *extension2 = p2; | 
 |   rtx set1 = single_set (extension1->se_insn); | 
 |   rtx set2 = single_set (extension2->se_insn); | 
 |   rtx rhs1, rhs2; | 
 |  | 
 |   gcc_assert (set1 && set2); | 
 |   rhs1 = SET_SRC (set1); | 
 |   rhs2 = SET_SRC (set2); | 
 |  | 
 |   return rtx_equal_p (rhs1, rhs2); | 
 | } | 
 |  | 
 |  | 
 | /* P is a see_pre_extension_expr struct, use the RHS of the se_insn field. | 
 |    Note that the RHS is an expression that looks like this: | 
 |    (sign_extend:WIDEmode (subreg:NARROWmode (reg:WIDEmode r)))  */ | 
 |  | 
 | static hashval_t | 
 | hash_descriptor_pre_extension (const void *p) | 
 | { | 
 |   const struct see_pre_extension_expr *extension = p; | 
 |   rtx set = single_set (extension->se_insn); | 
 |   rtx rhs; | 
 |  | 
 |   gcc_assert (set); | 
 |   rhs = SET_SRC (set); | 
 |  | 
 |   return hash_rtx (rhs, GET_MODE (rhs), 0, NULL, 0); | 
 | } | 
 |  | 
 |  | 
 | /* Free the allocated memory of the current see_pre_extension_expr struct. | 
 |     | 
 |    It frees the two linked list of the occurrences structures.  */ | 
 |  | 
 | static void | 
 | hash_del_pre_extension (void *p) | 
 | { | 
 |   struct see_pre_extension_expr *extension = p; | 
 |   struct see_occr *curr_occr = extension->antic_occr; | 
 |   struct see_occr *next_occr = NULL; | 
 |  | 
 |   /*  Free the linked list of the anticipatable occurrences.  */ | 
 |   while (curr_occr) | 
 |     { | 
 |       next_occr = curr_occr->next; | 
 |       free (curr_occr); | 
 |       curr_occr = next_occr; | 
 |     } | 
 |  | 
 |   /*  Free the linked list of the available occurrences.  */ | 
 |   curr_occr = extension->avail_occr; | 
 |   while (curr_occr) | 
 |     { | 
 |       next_occr = curr_occr->next; | 
 |       free (curr_occr); | 
 |       curr_occr = next_occr; | 
 |     } | 
 |  | 
 |   /* Free the see_pre_extension_expr structure itself.  */ | 
 |   free (extension); | 
 | } | 
 |  | 
 |  | 
 | /* Helper functions for the register_properties hash. | 
 |    This kind of hash will hold see_register_properties structures. | 
 |  | 
 |    The value of the key is the regno field of the structure.  */ | 
 |  | 
 | /* Return TRUE if P1 has the same value in the regno field as P2. | 
 |    Otherwise, return FALSE. | 
 |    Where P1 and P2 are see_register_properties structures.  */ | 
 |  | 
 | static int | 
 | eq_descriptor_properties (const void *p1, const void *p2) | 
 | { | 
 |   const struct see_register_properties *curr_prop1 = p1; | 
 |   const struct see_register_properties *curr_prop2 = p2; | 
 |  | 
 |   return curr_prop1->regno == curr_prop2->regno; | 
 | } | 
 |  | 
 |  | 
 | /* P is a see_register_properties struct, use the register number in the | 
 |    regno field.  */ | 
 |  | 
 | static hashval_t | 
 | hash_descriptor_properties (const void *p) | 
 | { | 
 |   const struct see_register_properties *curr_prop = p; | 
 |   return curr_prop->regno; | 
 | } | 
 |  | 
 |  | 
 | /* Free the allocated memory of the current see_register_properties struct.  */ | 
 | static void | 
 | hash_del_properties (void *p) | 
 | { | 
 |   struct see_register_properties *curr_prop = p; | 
 |   free (curr_prop); | 
 | } | 
 |  | 
 |  | 
 | /* Helper functions for an extension hash. | 
 |    This kind of hash will hold insns that look like: | 
 |  | 
 |    set ((reg:WIDEmode r1) (sign_extend:WIDEmode | 
 | 			   (subreg:NARROWmode (reg:WIDEmode r2)))) | 
 |    or | 
 |    set ((reg:WIDEmode r1) (sign_extend:WIDEmode (reg:NARROWmode r2))) | 
 |  | 
 |    The value of the key is (REGNO (reg:WIDEmode r1)) | 
 |    It is possible to search this hash in two ways: | 
 |    1.  By a register rtx. The Value that is been compared to the keys is the | 
 |        REGNO of it. | 
 |    2.  By an insn with the above pattern. The Value that is been compared to | 
 |        the keys is the REGNO of the reg on the lhs.  */ | 
 |  | 
 | /* Return TRUE if P1 has the same value as P2.  Otherwise, return FALSE. | 
 |    Where P1 is an insn and P2 is an insn or a register.  */ | 
 |  | 
 | static int | 
 | eq_descriptor_extension (const void *p1, const void *p2) | 
 | { | 
 |   const rtx insn = (rtx) p1; | 
 |   const rtx element = (rtx) p2; | 
 |   rtx set1 = single_set (insn); | 
 |   rtx dest_reg1; | 
 |   rtx set2 = NULL; | 
 |   rtx dest_reg2 = NULL; | 
 |  | 
 |   gcc_assert (set1 && element && (REG_P (element) || INSN_P (element))); | 
 |  | 
 |   dest_reg1 = SET_DEST (set1); | 
 |  | 
 |   if (INSN_P (element)) | 
 |     { | 
 |       set2 = single_set (element); | 
 |       dest_reg2 = SET_DEST (set2); | 
 |     } | 
 |   else | 
 |     dest_reg2 = element; | 
 |  | 
 |   return REGNO (dest_reg1) == REGNO (dest_reg2); | 
 | } | 
 |  | 
 |  | 
 | /* If P is an insn, use the register number of its lhs | 
 |    otherwise, P is a register, use its number.  */ | 
 |  | 
 | static hashval_t | 
 | hash_descriptor_extension (const void *p) | 
 | { | 
 |   const rtx r = (rtx) p; | 
 |   rtx set, lhs; | 
 |  | 
 |   if (r && REG_P (r)) | 
 |     return REGNO (r); | 
 |  | 
 |   gcc_assert (r && INSN_P (r)); | 
 |   set = single_set (r); | 
 |   gcc_assert (set); | 
 |   lhs = SET_DEST (set); | 
 |   return REGNO (lhs); | 
 | } | 
 |  | 
 |  | 
 | /* Helper function for a see_bb_splay_ar[i] splay tree. | 
 |    It frees all the allocated memory of a struct see_ref_s pointer. | 
 |  | 
 |    VALUE is the value of a splay tree node.  */ | 
 |  | 
 | static void | 
 | see_free_ref_s (splay_tree_value value) | 
 | { | 
 |   struct see_ref_s *ref_s = (struct see_ref_s *)value; | 
 |  | 
 |   if (ref_s->unmerged_def_se_hash) | 
 |     htab_delete (ref_s->unmerged_def_se_hash); | 
 |   if (ref_s->merged_def_se_hash) | 
 |     htab_delete (ref_s->merged_def_se_hash); | 
 |   if (ref_s->use_se_hash) | 
 |     htab_delete (ref_s->use_se_hash); | 
 |   free (ref_s); | 
 | } | 
 |  | 
 |  | 
 | /* Rest of the implementation.  */ | 
 |  | 
 | /* Search the extension hash for a suitable entry for EXTENSION. | 
 |    TYPE is the type of EXTENSION (USE_EXTENSION or DEF_EXTENSION). | 
 |  | 
 |    If TYPE is DEF_EXTENSION we need to normalize EXTENSION before searching the | 
 |    extension hash. | 
 |  | 
 |    If a suitable entry was found, return the slot.  Otherwise, store EXTENSION | 
 |    in the hash and return NULL.  */ | 
 |  | 
 | static struct see_pre_extension_expr * | 
 | see_seek_pre_extension_expr (rtx extension, enum extension_type type) | 
 | { | 
 |   struct see_pre_extension_expr **slot_pre_exp, temp_pre_exp; | 
 |   rtx dest_extension_reg = see_get_extension_reg (extension, 1); | 
 |   enum rtx_code extension_code; | 
 |   enum machine_mode source_extension_mode; | 
 |  | 
 |   if (type == DEF_EXTENSION) | 
 |     { | 
 |       extension_code = see_get_extension_data (extension, | 
 | 					       &source_extension_mode); | 
 |       gcc_assert (extension_code != UNKNOWN); | 
 |       extension = | 
 | 	see_gen_normalized_extension (dest_extension_reg, extension_code, | 
 | 				      source_extension_mode); | 
 |     } | 
 |   temp_pre_exp.se_insn = extension; | 
 |   slot_pre_exp = | 
 |     (struct see_pre_extension_expr **) htab_find_slot (see_pre_extension_hash, | 
 | 							&temp_pre_exp, INSERT); | 
 |   if (*slot_pre_exp == NULL) | 
 |     /* This is the first time this extension instruction is encountered.  Store | 
 |        it in the hash.  */ | 
 |     { | 
 |       (*slot_pre_exp) = xmalloc (sizeof (struct see_pre_extension_expr)); | 
 |       (*slot_pre_exp)->se_insn = extension; | 
 |       (*slot_pre_exp)->bitmap_index = | 
 | 	(htab_elements (see_pre_extension_hash) - 1); | 
 |       (*slot_pre_exp)->antic_occr = NULL; | 
 |       (*slot_pre_exp)->avail_occr = NULL; | 
 |       return NULL; | 
 |     } | 
 |   return *slot_pre_exp; | 
 | } | 
 |  | 
 |  | 
 | /* This function defines how to update the extra_info of the web_entry. | 
 |  | 
 |    FIRST is the pointer of the extra_info of the first web_entry. | 
 |    SECOND is the pointer of the extra_info of the second web_entry. | 
 |    The first web_entry will be the predecessor (leader) of the second web_entry | 
 |    after the union. | 
 |     | 
 |    Return true if FIRST and SECOND points to the same web entry structure and  | 
 |    nothing is done.  Otherwise, return false.  */ | 
 |  | 
 | static bool | 
 | see_update_leader_extra_info (struct web_entry *first, struct web_entry *second) | 
 | { | 
 |   struct see_entry_extra_info *first_ei, *second_ei; | 
 |  | 
 |   first = unionfind_root (first); | 
 |   second = unionfind_root (second); | 
 |  | 
 |   if (unionfind_union (first, second)) | 
 |     return true; | 
 |  | 
 |   first_ei = (struct see_entry_extra_info *) first->extra_info; | 
 |   second_ei = (struct see_entry_extra_info *) second->extra_info; | 
 |  | 
 |   gcc_assert (first_ei && second_ei); | 
 |  | 
 |   if (second_ei->relevancy == NOT_RELEVANT) | 
 |     { | 
 |       first_ei->relevancy = NOT_RELEVANT; | 
 |       return false; | 
 |     } | 
 |   switch (first_ei->relevancy) | 
 |     { | 
 |     case NOT_RELEVANT: | 
 |       break; | 
 |     case RELEVANT_USE: | 
 |       switch (second_ei->relevancy) | 
 | 	{ | 
 | 	case RELEVANT_USE: | 
 | 	  break; | 
 | 	case EXTENDED_DEF: | 
 | 	  first_ei->relevancy = second_ei->relevancy; | 
 | 	  first_ei->source_mode_signed = second_ei->source_mode_signed; | 
 | 	  first_ei->source_mode_unsigned = second_ei->source_mode_unsigned; | 
 | 	  break; | 
 | 	case SIGN_EXTENDED_DEF: | 
 | 	case ZERO_EXTENDED_DEF: | 
 | 	  first_ei->relevancy = second_ei->relevancy; | 
 | 	  first_ei->source_mode = second_ei->source_mode; | 
 | 	  break; | 
 | 	default: | 
 | 	  gcc_unreachable (); | 
 | 	} | 
 |       break; | 
 |     case SIGN_EXTENDED_DEF: | 
 |       switch (second_ei->relevancy) | 
 | 	{ | 
 | 	case SIGN_EXTENDED_DEF: | 
 | 	  /* The mode of the root should be the wider one in this case.  */ | 
 | 	  first_ei->source_mode = | 
 | 	    (first_ei->source_mode > second_ei->source_mode) ? | 
 | 	    first_ei->source_mode : second_ei->source_mode; | 
 | 	  break; | 
 | 	case RELEVANT_USE: | 
 | 	  break; | 
 | 	case ZERO_EXTENDED_DEF: | 
 | 	  /* Don't mix webs with zero extend and sign extend.  */ | 
 | 	  first_ei->relevancy = NOT_RELEVANT; | 
 | 	  break; | 
 | 	case EXTENDED_DEF: | 
 | 	  if (second_ei->source_mode_signed == MAX_MACHINE_MODE) | 
 | 	    first_ei->relevancy = NOT_RELEVANT; | 
 | 	  else | 
 | 	    /* The mode of the root should be the wider one in this case.  */ | 
 | 	    first_ei->source_mode = | 
 | 	      (first_ei->source_mode > second_ei->source_mode_signed) ? | 
 | 	      first_ei->source_mode : second_ei->source_mode_signed; | 
 | 	  break; | 
 | 	default: | 
 | 	  gcc_unreachable (); | 
 | 	} | 
 |       break; | 
 |     /* This case is similar to the previous one, with little changes.  */ | 
 |     case ZERO_EXTENDED_DEF: | 
 |       switch (second_ei->relevancy) | 
 | 	{ | 
 | 	case SIGN_EXTENDED_DEF: | 
 | 	  /* Don't mix webs with zero extend and sign extend.  */ | 
 | 	  first_ei->relevancy = NOT_RELEVANT; | 
 | 	  break; | 
 | 	case RELEVANT_USE: | 
 | 	  break; | 
 | 	case ZERO_EXTENDED_DEF: | 
 | 	  /* The mode of the root should be the wider one in this case.  */ | 
 | 	  first_ei->source_mode = | 
 | 	    (first_ei->source_mode > second_ei->source_mode) ? | 
 | 	    first_ei->source_mode : second_ei->source_mode; | 
 | 	  break; | 
 | 	case EXTENDED_DEF: | 
 | 	  if (second_ei->source_mode_unsigned == MAX_MACHINE_MODE) | 
 | 	    first_ei->relevancy = NOT_RELEVANT; | 
 | 	  else | 
 | 	    /* The mode of the root should be the wider one in this case.  */ | 
 | 	    first_ei->source_mode = | 
 | 	      (first_ei->source_mode > second_ei->source_mode_unsigned) ? | 
 | 	      first_ei->source_mode : second_ei->source_mode_unsigned; | 
 | 	  break; | 
 | 	default: | 
 | 	  gcc_unreachable (); | 
 | 	} | 
 |       break; | 
 |     case EXTENDED_DEF: | 
 |       if (first_ei->source_mode_signed != MAX_MACHINE_MODE | 
 | 	  && first_ei->source_mode_unsigned != MAX_MACHINE_MODE) | 
 | 	{ | 
 | 	  switch (second_ei->relevancy) | 
 | 	    { | 
 | 	    case SIGN_EXTENDED_DEF: | 
 | 	      first_ei->relevancy = SIGN_EXTENDED_DEF; | 
 | 	      first_ei->source_mode = | 
 | 		(first_ei->source_mode_signed > second_ei->source_mode) ? | 
 | 		first_ei->source_mode_signed : second_ei->source_mode; | 
 | 	      break; | 
 | 	    case RELEVANT_USE: | 
 | 	      break; | 
 | 	    case ZERO_EXTENDED_DEF: | 
 | 	      first_ei->relevancy = ZERO_EXTENDED_DEF; | 
 | 	      first_ei->source_mode = | 
 | 		(first_ei->source_mode_unsigned > second_ei->source_mode) ? | 
 | 		first_ei->source_mode_unsigned : second_ei->source_mode; | 
 | 	      break; | 
 | 	    case EXTENDED_DEF: | 
 | 	      if (second_ei->source_mode_unsigned != MAX_MACHINE_MODE) | 
 | 		first_ei->source_mode_unsigned = | 
 | 		  (first_ei->source_mode_unsigned > | 
 | 		  second_ei->source_mode_unsigned) ? | 
 | 		  first_ei->source_mode_unsigned : | 
 | 		  second_ei->source_mode_unsigned; | 
 | 	      if (second_ei->source_mode_signed != MAX_MACHINE_MODE) | 
 | 		first_ei->source_mode_signed = | 
 | 		  (first_ei->source_mode_signed > | 
 | 		  second_ei->source_mode_signed) ? | 
 | 		  first_ei->source_mode_signed : second_ei->source_mode_signed; | 
 | 	      break; | 
 | 	    default: | 
 | 	      gcc_unreachable (); | 
 | 	    } | 
 | 	} | 
 |       else if (first_ei->source_mode_signed == MAX_MACHINE_MODE) | 
 | 	{ | 
 | 	  gcc_assert (first_ei->source_mode_unsigned != MAX_MACHINE_MODE); | 
 | 	  switch (second_ei->relevancy) | 
 | 	    { | 
 | 	    case SIGN_EXTENDED_DEF: | 
 | 	      first_ei->relevancy = NOT_RELEVANT; | 
 | 	      break; | 
 | 	    case RELEVANT_USE: | 
 | 	      break; | 
 | 	    case ZERO_EXTENDED_DEF: | 
 | 	      first_ei->relevancy = ZERO_EXTENDED_DEF; | 
 | 	      first_ei->source_mode = | 
 | 		(first_ei->source_mode_unsigned > second_ei->source_mode) ? | 
 | 		first_ei->source_mode_unsigned : second_ei->source_mode; | 
 | 	      break; | 
 | 	    case EXTENDED_DEF: | 
 | 	      if (second_ei->source_mode_unsigned == MAX_MACHINE_MODE) | 
 | 		first_ei->relevancy = NOT_RELEVANT; | 
 | 	      else | 
 | 		first_ei->source_mode_unsigned = | 
 | 		  (first_ei->source_mode_unsigned > | 
 | 		  second_ei->source_mode_unsigned) ? | 
 | 		  first_ei->source_mode_unsigned : | 
 | 		  second_ei->source_mode_unsigned; | 
 | 	      break; | 
 | 	    default: | 
 | 	      gcc_unreachable (); | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  gcc_assert (first_ei->source_mode_unsigned == MAX_MACHINE_MODE); | 
 | 	  gcc_assert (first_ei->source_mode_signed != MAX_MACHINE_MODE); | 
 | 	  switch (second_ei->relevancy) | 
 | 	    { | 
 | 	    case SIGN_EXTENDED_DEF: | 
 | 	      first_ei->relevancy = SIGN_EXTENDED_DEF; | 
 | 	      first_ei->source_mode = | 
 | 		(first_ei->source_mode_signed > second_ei->source_mode) ? | 
 | 		first_ei->source_mode_signed : second_ei->source_mode; | 
 | 	      break; | 
 | 	    case RELEVANT_USE: | 
 | 	      break; | 
 | 	    case ZERO_EXTENDED_DEF: | 
 | 	      first_ei->relevancy = NOT_RELEVANT; | 
 | 	      break; | 
 | 	    case EXTENDED_DEF: | 
 | 	      if (second_ei->source_mode_signed == MAX_MACHINE_MODE) | 
 | 		first_ei->relevancy = NOT_RELEVANT; | 
 | 	      else | 
 | 		first_ei->source_mode_signed = | 
 | 		  (first_ei->source_mode_signed > | 
 | 		  second_ei->source_mode_signed) ? | 
 | 		  first_ei->source_mode_signed : second_ei->source_mode_signed; | 
 | 	      break; | 
 | 	    default: | 
 | 	      gcc_unreachable (); | 
 | 	    } | 
 | 	} | 
 |       break; | 
 |     default: | 
 |       /* Unknown patern type.  */ | 
 |       gcc_unreachable (); | 
 |     } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 |  | 
 | /* Free global data structures.  */ | 
 |  | 
 | static void | 
 | see_free_data_structures (void) | 
 | { | 
 |   int i; | 
 |   unsigned int j; | 
 |  | 
 |   /* Free the bitmap vectors.  */ | 
 |   if (transp) | 
 |     { | 
 |       sbitmap_vector_free (transp); | 
 |       transp = NULL; | 
 |       sbitmap_vector_free (comp); | 
 |       comp = NULL; | 
 |       sbitmap_vector_free (antloc); | 
 |       antloc = NULL; | 
 |       sbitmap_vector_free (ae_kill); | 
 |       ae_kill = NULL; | 
 |     } | 
 |   if (pre_insert_map) | 
 |     { | 
 |       sbitmap_vector_free (pre_insert_map); | 
 |       pre_insert_map = NULL; | 
 |     } | 
 |   if (pre_delete_map) | 
 |     { | 
 |       sbitmap_vector_free (pre_delete_map); | 
 |       pre_delete_map = NULL; | 
 |     } | 
 |   if (edge_list) | 
 |     { | 
 |       free_edge_list (edge_list); | 
 |       edge_list = NULL; | 
 |     } | 
 |  | 
 |   /*  Free the extension hash.  */ | 
 |   htab_delete (see_pre_extension_hash); | 
 |  | 
 |   /*  Free the array of hashes.  */ | 
 |   for (i = 0; i < last_bb; i++) | 
 |     if (see_bb_hash_ar[i]) | 
 |       htab_delete (see_bb_hash_ar[i]); | 
 |   free (see_bb_hash_ar); | 
 |  | 
 |   /*  Free the array of splay trees.  */ | 
 |   for (i = 0; i < last_bb; i++) | 
 |     if (see_bb_splay_ar[i]) | 
 |       splay_tree_delete (see_bb_splay_ar[i]); | 
 |   free (see_bb_splay_ar); | 
 |  | 
 |   /*  Free the array of web entries and their extra info field.  */ | 
 |   for (j = 0; j < defs_num; j++) | 
 |     free (def_entry[j].extra_info); | 
 |   free (def_entry); | 
 |   for (j = 0; j < uses_num; j++) | 
 |     free (use_entry[j].extra_info); | 
 |   free (use_entry); | 
 | } | 
 |  | 
 |  | 
 | /* Initialize global data structures and variables.  */ | 
 |  | 
 | static void | 
 | see_initialize_data_structures (void) | 
 | { | 
 |   /* Build the df object. */ | 
 |   df = df_init (DF_HARD_REGS | DF_EQUIV_NOTES | DF_SUBREGS); | 
 |   df_rd_add_problem (df, 0); | 
 |   df_chain_add_problem (df, DF_DU_CHAIN | DF_UD_CHAIN); | 
 |   df_analyze (df); | 
 |  | 
 |   if (dump_file) | 
 |     df_dump (df, dump_file); | 
 |  | 
 |   /* Record the last basic block at the beginning of the optimization.  */ | 
 |   last_bb = last_basic_block; | 
 |   /* Record the number of uses at the beginning of the optimization.  */ | 
 |   uses_num = DF_USES_SIZE (df); | 
 |   /* Record the number of definitions at the beginning of the optimization.  */ | 
 |   defs_num = DF_DEFS_SIZE (df); | 
 |  | 
 |   /*  Allocate web entries array for the union-find data structure.  */ | 
 |   def_entry = xcalloc (defs_num, sizeof (struct web_entry)); | 
 |   use_entry = xcalloc (uses_num, sizeof (struct web_entry)); | 
 |  | 
 |   /*  Allocate an array of splay trees. | 
 |       One splay tree for each basic block.  */ | 
 |   see_bb_splay_ar = xcalloc (last_bb, sizeof (splay_tree)); | 
 |  | 
 |   /*  Allocate an array of hashes. | 
 |       One hash for each basic block.  */ | 
 |   see_bb_hash_ar = xcalloc (last_bb, sizeof (htab_t)); | 
 |  | 
 |   /*  Allocate the extension hash.  It will hold the extensions that we want | 
 |       to PRE.  */ | 
 |   see_pre_extension_hash = htab_create (10,  | 
 | 					hash_descriptor_pre_extension,  | 
 | 					eq_descriptor_pre_extension, | 
 | 					hash_del_pre_extension); | 
 | } | 
 |  | 
 |  | 
 | /* Function called by note_uses to check if a register is used in a | 
 |    subexpressions. | 
 |  | 
 |    X is a pointer to the subexpression and DATA is a pointer to a | 
 |    see_mentioned_reg_data structure that contains the register to look for and | 
 |    a place for the result.  */ | 
 |  | 
 | static void | 
 | see_mentioned_reg (rtx *x, void *data) | 
 | { | 
 |   struct see_mentioned_reg_data *d | 
 |     = (struct see_mentioned_reg_data *) data; | 
 |  | 
 |   if (reg_mentioned_p (d->reg, *x)) | 
 |     d->mentioned = true; | 
 | } | 
 |  | 
 |  | 
 | /* We don't want to merge a use extension with a reference if the extended | 
 |    register is used only in a simple move instruction.  We also don't want to | 
 |    merge a def extension with a reference if the source register of the | 
 |    extension is defined only in a simple move in the reference. | 
 |  | 
 |    REF is the reference instruction. | 
 |    EXTENSION is the use extension or def extension instruction. | 
 |    TYPE is the type of the extension (use or def). | 
 |  | 
 |    Return true if the reference is complicated enough, so we would like to merge | 
 |    it with the extension.  Otherwise, return false.  */ | 
 |  | 
 | static bool | 
 | see_want_to_be_merged_with_extension (rtx ref, rtx extension, | 
 |    				      enum extension_type type) | 
 | { | 
 |   rtx pat; | 
 |   rtx dest_extension_reg = see_get_extension_reg (extension, 1); | 
 |   rtx source_extension_reg = see_get_extension_reg (extension, 0); | 
 |   enum rtx_code code; | 
 |   struct see_mentioned_reg_data d; | 
 |   int i; | 
 |  | 
 |   pat = PATTERN (ref); | 
 |   code = GET_CODE (pat); | 
 |  | 
 |   if (code == PARALLEL) | 
 |     { | 
 |       for (i = 0; i < XVECLEN (pat, 0); i++) | 
 | 	{ | 
 | 	  rtx sub = XVECEXP (pat, 0, i); | 
 |  | 
 | 	  if (GET_CODE (sub) == SET | 
 | 	      && (REG_P (SET_DEST (sub)) | 
 | 		  || (GET_CODE (SET_DEST (sub)) == SUBREG | 
 | 		      && REG_P (SUBREG_REG (SET_DEST (sub))))) | 
 | 	      && (REG_P (SET_SRC (sub)) | 
 | 		  || (GET_CODE (SET_SRC (sub)) == SUBREG | 
 | 		      && REG_P (SUBREG_REG (SET_SRC (sub)))))) | 
 | 	    { | 
 | 	      /* This is a simple move SET.  */ | 
 | 	      if (type == DEF_EXTENSION | 
 | 		  && reg_mentioned_p (source_extension_reg, SET_DEST (sub))) | 
 | 		return false; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      /* This is not a simple move SET. | 
 | 		 Check if it uses the source of the extension.  */ | 
 | 	      if (type == USE_EXTENSION) | 
 | 		{ | 
 |   		  d.reg = dest_extension_reg; | 
 | 		  d.mentioned = false; | 
 | 		  note_uses (&sub, see_mentioned_reg, &d); | 
 | 		  if (d.mentioned) | 
 | 		    return true; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |       if (type == USE_EXTENSION) | 
 | 	return false; | 
 |     } | 
 |   else | 
 |     { | 
 |       if (code == SET | 
 | 	  && (REG_P (SET_DEST (pat)) | 
 | 	      || (GET_CODE (SET_DEST (pat)) == SUBREG | 
 | 		  && REG_P (SUBREG_REG (SET_DEST (pat))))) | 
 | 	  && (REG_P (SET_SRC (pat)) | 
 | 	      || (GET_CODE (SET_SRC (pat)) == SUBREG | 
 | 		  && REG_P (SUBREG_REG (SET_SRC (pat)))))) | 
 | 	/* This is a simple move SET.  */ | 
 | 	return false; | 
 |      } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 |  | 
 | /* Print the register number of the current see_register_properties | 
 |    structure. | 
 |  | 
 |    This is a subroutine of see_main called via htab_traverse. | 
 |    SLOT contains the current see_register_properties structure pointer.  */ | 
 |  | 
 | static int | 
 | see_print_register_properties (void **slot, void *b ATTRIBUTE_UNUSED) | 
 | { | 
 |   struct see_register_properties *prop = *slot; | 
 |  | 
 |   gcc_assert (prop); | 
 |   fprintf (dump_file, "Property found for register %d\n", prop->regno); | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Print the extension instruction of the current see_register_properties | 
 |    structure. | 
 |  | 
 |    This is a subroutine of see_main called via htab_traverse. | 
 |    SLOT contains the current see_pre_extension_expr structure pointer.  */ | 
 |  | 
 | static int | 
 | see_print_pre_extension_expr (void **slot, void *b ATTRIBUTE_UNUSED) | 
 | { | 
 |   struct see_pre_extension_expr *pre_extension = *slot; | 
 |  | 
 |   gcc_assert (pre_extension | 
 |   	      && pre_extension->se_insn | 
 | 	      && INSN_P (pre_extension->se_insn)); | 
 |  | 
 |   fprintf (dump_file, "Index %d for:\n", pre_extension->bitmap_index); | 
 |   print_rtl_single (dump_file, pre_extension->se_insn); | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Phase 4 implementation: Commit changes to the insn stream.  */ | 
 |  | 
 | /* Delete the merged def extension. | 
 |  | 
 |    This is a subroutine of see_commit_ref_changes called via htab_traverse. | 
 |  | 
 |    SLOT contains the current def extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_delete_merged_def_extension (void **slot, void *b ATTRIBUTE_UNUSED) | 
 | { | 
 |   rtx def_se = *slot; | 
 |  | 
 |   if (dump_file) | 
 |     { | 
 |       fprintf (dump_file, "Deleting merged def extension:\n"); | 
 |       print_rtl_single (dump_file, def_se); | 
 |     } | 
 |  | 
 |   if (INSN_DELETED_P (def_se)) | 
 |     /* This def extension is an implicit one.  No need to delete it since | 
 |        it is not in the insn stream.  */ | 
 |     return 1; | 
 |  | 
 |   delete_insn (def_se); | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Delete the unmerged def extension. | 
 |  | 
 |    This is a subroutine of see_commit_ref_changes called via htab_traverse. | 
 |  | 
 |    SLOT contains the current def extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_delete_unmerged_def_extension (void **slot, void *b ATTRIBUTE_UNUSED) | 
 | { | 
 |   rtx def_se = *slot; | 
 |  | 
 |   if (dump_file) | 
 |     { | 
 |       fprintf (dump_file, "Deleting unmerged def extension:\n"); | 
 |       print_rtl_single (dump_file, def_se); | 
 |     } | 
 |  | 
 |   delete_insn (def_se); | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Emit the non-redundant use extension to the instruction stream. | 
 |  | 
 |    This is a subroutine of see_commit_ref_changes called via htab_traverse. | 
 |  | 
 |    SLOT contains the current use extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_emit_use_extension (void **slot, void *b) | 
 | { | 
 |   rtx use_se = *slot; | 
 |   struct see_ref_s *curr_ref_s = (struct see_ref_s *) b; | 
 |  | 
 |   if (INSN_DELETED_P (use_se)) | 
 |     /* This use extension was previously removed according to the lcm | 
 |        output.  */ | 
 |     return 1; | 
 |  | 
 |   if (dump_file) | 
 |     { | 
 |       fprintf (dump_file, "Inserting use extension:\n"); | 
 |       print_rtl_single (dump_file, use_se); | 
 |     } | 
 |  | 
 |   add_insn_before (use_se, curr_ref_s->insn); | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* For each relevant reference: | 
 |    a. Emit the non-redundant use extensions. | 
 |    b. Delete the def extensions. | 
 |    c. Replace the original reference with the merged one (if exists) and add the | 
 |       move instructions that were generated. | 
 |  | 
 |    This is a subroutine of see_commit_changes called via splay_tree_foreach. | 
 |  | 
 |    STN is the current node in the see_bb_splay_ar[i] splay tree.  It holds a | 
 |    see_ref_s structure.  */ | 
 |  | 
 | static int | 
 | see_commit_ref_changes (splay_tree_node stn, | 
 | 		   	void *data ATTRIBUTE_UNUSED) | 
 | { | 
 |   htab_t use_se_hash = ((struct see_ref_s *) (stn->value))->use_se_hash; | 
 |   htab_t unmerged_def_se_hash = | 
 |     ((struct see_ref_s *) (stn->value))->unmerged_def_se_hash; | 
 |   htab_t merged_def_se_hash = | 
 |     ((struct see_ref_s *) (stn->value))->merged_def_se_hash; | 
 |   rtx ref = ((struct see_ref_s *) (stn->value))->insn; | 
 |   rtx merged_ref = ((struct see_ref_s *) (stn->value))->merged_insn; | 
 |  | 
 |   /* Emit the non-redundant use extensions.  */ | 
 |   if (use_se_hash) | 
 |     htab_traverse_noresize (use_se_hash, see_emit_use_extension, | 
 | 			    (PTR) (stn->value)); | 
 |  | 
 |   /* Delete the def extensions.  */ | 
 |   if (unmerged_def_se_hash) | 
 |     htab_traverse (unmerged_def_se_hash, see_delete_unmerged_def_extension, | 
 | 		   (PTR) (stn->value)); | 
 |  | 
 |   if (merged_def_se_hash) | 
 |     htab_traverse (merged_def_se_hash, see_delete_merged_def_extension, | 
 | 		   (PTR) (stn->value)); | 
 |  | 
 |   /* Replace the original reference with the merged one (if exists) and add the | 
 |      move instructions that were generated.  */ | 
 |   if (merged_ref && !INSN_DELETED_P (ref)) | 
 |     { | 
 |       if (dump_file) | 
 | 	{ | 
 | 	  fprintf (dump_file, "Replacing orig reference:\n"); | 
 | 	  print_rtl_single (dump_file, ref); | 
 | 	  fprintf (dump_file, "With merged reference:\n"); | 
 | 	  print_rtl_single (dump_file, merged_ref); | 
 | 	} | 
 |       emit_insn_after (merged_ref, ref); | 
 |       delete_insn (ref); | 
 |     } | 
 |  | 
 |   /* Continue to the next reference.  */ | 
 |   return 0; | 
 | } | 
 |  | 
 |  | 
 | /* Insert partially redundant expressions on edges to make the expressions fully | 
 |    redundant. | 
 |  | 
 |    INDEX_MAP is a mapping of an index to an expression. | 
 |    Return true if an instruction was inserted on an edge. | 
 |    Otherwise, return false.  */ | 
 |  | 
 | static bool | 
 | see_pre_insert_extensions (struct see_pre_extension_expr **index_map) | 
 | { | 
 |   int num_edges = NUM_EDGES (edge_list); | 
 |   int set_size = pre_insert_map[0]->size; | 
 |   size_t pre_extension_num = htab_elements (see_pre_extension_hash); | 
 |  | 
 |   int did_insert = 0; | 
 |   int e; | 
 |   int i; | 
 |   int j; | 
 |  | 
 |   for (e = 0; e < num_edges; e++) | 
 |     { | 
 |       int indx; | 
 |       basic_block bb = INDEX_EDGE_PRED_BB (edge_list, e); | 
 |  | 
 |       for (i = indx = 0; i < set_size; i++, indx += SBITMAP_ELT_BITS) | 
 | 	{ | 
 | 	  SBITMAP_ELT_TYPE insert = pre_insert_map[e]->elms[i]; | 
 |  | 
 | 	  for (j = indx; insert && j < (int) pre_extension_num; | 
 | 	       j++, insert >>= 1) | 
 | 	    if (insert & 1) | 
 | 	      { | 
 | 		struct see_pre_extension_expr *expr = index_map[j]; | 
 | 		int idx = expr->bitmap_index; | 
 | 		rtx se_insn = NULL; | 
 | 		edge eg = INDEX_EDGE (edge_list, e); | 
 |  | 
 | 		start_sequence (); | 
 | 		emit_insn (PATTERN (expr->se_insn)); | 
 | 		se_insn = get_insns (); | 
 | 		end_sequence (); | 
 |  | 
 | 		if (eg->flags & EDGE_ABNORMAL) | 
 | 		  { | 
 | 		    rtx new_insn = NULL; | 
 |  | 
 | 		    new_insn = insert_insn_end_bb_new (se_insn, bb); | 
 | 		    gcc_assert (new_insn && INSN_P (new_insn)); | 
 |  | 
 | 		    if (dump_file) | 
 | 		      { | 
 | 			fprintf (dump_file, | 
 | 				 "PRE: end of bb %d, insn %d, ", | 
 | 				 bb->index, INSN_UID (new_insn)); | 
 | 			fprintf (dump_file, | 
 | 				 "inserting expression %d\n", idx); | 
 | 		      } | 
 | 		  } | 
 | 		else | 
 | 		  { | 
 | 		    insert_insn_on_edge (se_insn, eg); | 
 |  | 
 | 		    if (dump_file) | 
 | 		      { | 
 | 			fprintf (dump_file, "PRE: edge (%d,%d), ", | 
 | 				 bb->index, | 
 | 				 INDEX_EDGE_SUCC_BB (edge_list, e)->index); | 
 | 			fprintf (dump_file, "inserting expression %d\n", idx); | 
 | 		      } | 
 | 		  } | 
 | 		did_insert = true; | 
 | 	      } | 
 | 	} | 
 |     } | 
 |   return did_insert; | 
 | } | 
 |  | 
 |  | 
 | /* Since all the redundant extensions must be anticipatable, they must be a use | 
 |    extensions.  Mark them as deleted.  This will prevent them from been emitted | 
 |    in the first place. | 
 |  | 
 |    This is a subroutine of see_commit_changes called via htab_traverse. | 
 |  | 
 |    SLOT contains the current see_pre_extension_expr structure pointer.  */ | 
 |  | 
 | static int | 
 | see_pre_delete_extension (void **slot, void *b ATTRIBUTE_UNUSED) | 
 | { | 
 |   struct see_pre_extension_expr *expr = *slot; | 
 |   struct see_occr *occr; | 
 |   int indx = expr->bitmap_index; | 
 |  | 
 |   for (occr = expr->antic_occr; occr != NULL; occr = occr->next) | 
 |     { | 
 |       if (TEST_BIT (pre_delete_map[occr->block_num], indx)) | 
 | 	{ | 
 | 	  /* Mark as deleted.  */ | 
 | 	  INSN_DELETED_P (occr->insn) = 1; | 
 | 	  if (dump_file) | 
 | 	    { | 
 | 	      fprintf (dump_file,"Redundant extension deleted:\n"); | 
 | 	      print_rtl_single (dump_file, occr->insn); | 
 | 	    } | 
 | 	} | 
 |     } | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Create the index_map mapping of an index to an expression. | 
 |  | 
 |    This is a subroutine of see_commit_changes called via htab_traverse. | 
 |  | 
 |    SLOT contains the current see_pre_extension_expr structure pointer. | 
 |    B a pointer to see_pre_extension_expr structure pointer.  */ | 
 |  | 
 | static int | 
 | see_map_extension (void **slot, void *b) | 
 | { | 
 |   struct see_pre_extension_expr *expr = *slot; | 
 |   struct see_pre_extension_expr **index_map = | 
 |     (struct see_pre_extension_expr **) b; | 
 |  | 
 |   index_map[expr->bitmap_index] = expr; | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Phase 4 top level function. | 
 |    In this phase we finally change the instruction stream. | 
 |    Here we insert extensions at their best placements and delete the | 
 |    redundant ones according to the output of the LCM.  We also replace | 
 |    some of the instructions according to phase 2 merges results.  */ | 
 |  | 
 | static void | 
 | see_commit_changes (void) | 
 | { | 
 |   struct see_pre_extension_expr **index_map; | 
 |   size_t pre_extension_num = htab_elements (see_pre_extension_hash); | 
 |   bool did_insert = false; | 
 |   int i; | 
 |  | 
 |   index_map = xcalloc (pre_extension_num, | 
 |   		       sizeof (struct see_pre_extension_expr *)); | 
 |  | 
 |   if (dump_file) | 
 |     fprintf (dump_file, | 
 |       "* Phase 4: Commit changes to the insn stream.  *\n"); | 
 |  | 
 |   /* Produce a mapping of all the pre_extensions.  */ | 
 |   htab_traverse (see_pre_extension_hash, see_map_extension, (PTR) index_map); | 
 |  | 
 |   /* Delete redundant extension.  This will prevent them from been emitted in | 
 |      the first place.  */ | 
 |   htab_traverse (see_pre_extension_hash, see_pre_delete_extension, NULL); | 
 |  | 
 |   /* At this point, we must free the DF object, since the number of basic blocks | 
 |      may change.  */ | 
 |   df_finish (df); | 
 |   df = NULL; | 
 |  | 
 |   /* Insert extensions on edges, according to the LCM result.  */ | 
 |   did_insert = see_pre_insert_extensions (index_map); | 
 |  | 
 |   if (did_insert) | 
 |     commit_edge_insertions (); | 
 |  | 
 |   /* Commit the rest of the changes.  */ | 
 |   for (i = 0; i < last_bb; i++) | 
 |     { | 
 |       if (see_bb_splay_ar[i]) | 
 | 	{ | 
 | 	  /* Traverse over all the references in the basic block in forward | 
 | 	     order.  */ | 
 | 	  splay_tree_foreach (see_bb_splay_ar[i], | 
 | 			      see_commit_ref_changes, NULL); | 
 | 	} | 
 |     } | 
 |  | 
 |   free (index_map); | 
 | } | 
 |  | 
 |  | 
 | /* Phase 3 implementation: Eliminate globally redundant extensions.  */ | 
 |  | 
 | /* Analyze the properties of a merged def extension for the LCM and record avail | 
 |    occurrences. | 
 |  | 
 |    This is a subroutine of see_analyze_ref_local_prop called | 
 |    via htab_traverse. | 
 |  | 
 |    SLOT contains the current def extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_analyze_merged_def_local_prop (void **slot, void *b) | 
 | { | 
 |   rtx def_se = *slot; | 
 |   struct see_ref_s *curr_ref_s = (struct see_ref_s *) b; | 
 |   rtx ref = curr_ref_s->insn; | 
 |   struct see_pre_extension_expr *extension_expr; | 
 |   int indx; | 
 |   int bb_num = BLOCK_NUM (ref); | 
 |   htab_t curr_bb_hash; | 
 |   struct see_register_properties *curr_prop, **slot_prop; | 
 |   struct see_register_properties temp_prop; | 
 |   rtx dest_extension_reg = see_get_extension_reg (def_se, 1); | 
 |   struct see_occr *curr_occr = NULL; | 
 |   struct see_occr *tmp_occr = NULL; | 
 |  | 
 |   extension_expr = see_seek_pre_extension_expr (def_se, DEF_EXTENSION); | 
 |   /* The extension_expr must be found.  */ | 
 |   gcc_assert (extension_expr); | 
 |  | 
 |   curr_bb_hash = see_bb_hash_ar[bb_num]; | 
 |   gcc_assert (curr_bb_hash); | 
 |   temp_prop.regno = REGNO (dest_extension_reg); | 
 |   slot_prop = | 
 |     (struct see_register_properties **) htab_find_slot (curr_bb_hash, | 
 | 							&temp_prop, INSERT); | 
 |   curr_prop = *slot_prop; | 
 |   gcc_assert (curr_prop); | 
 |  | 
 |   indx = extension_expr->bitmap_index; | 
 |  | 
 |   /* Reset the transparency bit.  */ | 
 |   RESET_BIT (transp[bb_num], indx); | 
 |   /* Reset the killed bit.  */ | 
 |   RESET_BIT (ae_kill[bb_num], indx); | 
 |  | 
 |   if (curr_prop->first_se_after_last_def == DF_INSN_LUID (df, ref)) | 
 |     { | 
 |       /* Set the available bit.  */ | 
 |       SET_BIT (comp[bb_num], indx); | 
 |       /* Record the available occurrence.  */ | 
 |       curr_occr = xmalloc (sizeof (struct see_occr)); | 
 |       curr_occr->next = NULL; | 
 |       curr_occr->insn = def_se; | 
 |       curr_occr->block_num = bb_num; | 
 |       tmp_occr = extension_expr->avail_occr; | 
 |       if (!tmp_occr) | 
 | 	extension_expr->avail_occr = curr_occr; | 
 |       else | 
 | 	{ | 
 | 	  while (tmp_occr->next) | 
 | 	    tmp_occr = tmp_occr->next; | 
 | 	  tmp_occr->next = curr_occr; | 
 | 	} | 
 |     } | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Analyze the properties of a unmerged def extension for the LCM. | 
 |  | 
 |    This is a subroutine of see_analyze_ref_local_prop called | 
 |    via htab_traverse. | 
 |  | 
 |    SLOT contains the current def extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_analyze_unmerged_def_local_prop (void **slot, void *b) | 
 | { | 
 |   rtx def_se = *slot; | 
 |   struct see_ref_s *curr_ref_s = (struct see_ref_s *) b; | 
 |   rtx ref = curr_ref_s->insn; | 
 |   struct see_pre_extension_expr *extension_expr; | 
 |   int indx; | 
 |   int bb_num = BLOCK_NUM (ref); | 
 |   htab_t curr_bb_hash; | 
 |   struct see_register_properties *curr_prop, **slot_prop; | 
 |   struct see_register_properties temp_prop; | 
 |   rtx dest_extension_reg = see_get_extension_reg (def_se, 1); | 
 |  | 
 |   extension_expr = see_seek_pre_extension_expr (def_se, DEF_EXTENSION); | 
 |   /* The extension_expr must be found.  */ | 
 |   gcc_assert (extension_expr); | 
 |  | 
 |   curr_bb_hash = see_bb_hash_ar[bb_num]; | 
 |   gcc_assert (curr_bb_hash); | 
 |   temp_prop.regno = REGNO (dest_extension_reg); | 
 |   slot_prop = | 
 |     (struct see_register_properties **) htab_find_slot (curr_bb_hash, | 
 | 							&temp_prop, INSERT); | 
 |   curr_prop = *slot_prop; | 
 |   gcc_assert (curr_prop); | 
 |  | 
 |   indx = extension_expr->bitmap_index; | 
 |  | 
 |   /* Reset the transparency bit.  */ | 
 |   RESET_BIT (transp[bb_num], indx); | 
 |   /* Set the killed bit.  */ | 
 |   SET_BIT (ae_kill[bb_num], indx); | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Analyze the properties of a use extension for the LCM and record anic and | 
 |    avail occurrences. | 
 |  | 
 |    This is a subroutine of see_analyze_ref_local_prop called | 
 |    via htab_traverse. | 
 |  | 
 |    SLOT contains the current use extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_analyze_use_local_prop (void **slot, void *b) | 
 | { | 
 |   struct see_ref_s *curr_ref_s = (struct see_ref_s *) b; | 
 |   rtx use_se = *slot; | 
 |   rtx ref = curr_ref_s->insn; | 
 |   rtx dest_extension_reg = see_get_extension_reg (use_se, 1); | 
 |   struct see_pre_extension_expr *extension_expr; | 
 |   struct see_register_properties *curr_prop, **slot_prop; | 
 |   struct see_register_properties temp_prop; | 
 |   struct see_occr *curr_occr = NULL; | 
 |   struct see_occr *tmp_occr = NULL; | 
 |   htab_t curr_bb_hash; | 
 |   int indx; | 
 |   int bb_num = BLOCK_NUM (ref); | 
 |  | 
 |   extension_expr = see_seek_pre_extension_expr (use_se, USE_EXTENSION); | 
 |   /* The extension_expr must be found.  */ | 
 |   gcc_assert (extension_expr); | 
 |  | 
 |   curr_bb_hash = see_bb_hash_ar[bb_num]; | 
 |   gcc_assert (curr_bb_hash); | 
 |   temp_prop.regno = REGNO (dest_extension_reg); | 
 |   slot_prop = | 
 |     (struct see_register_properties **) htab_find_slot (curr_bb_hash, | 
 | 							&temp_prop, INSERT); | 
 |   curr_prop = *slot_prop; | 
 |   gcc_assert (curr_prop); | 
 |  | 
 |   indx = extension_expr->bitmap_index; | 
 |  | 
 |   if (curr_prop->first_se_before_any_def == DF_INSN_LUID (df, ref)) | 
 |     { | 
 |       /* Set the anticipatable bit.  */ | 
 |       SET_BIT (antloc[bb_num], indx); | 
 |       /* Record the anticipatable occurrence.  */ | 
 |       curr_occr = xmalloc (sizeof (struct see_occr)); | 
 |       curr_occr->next = NULL; | 
 |       curr_occr->insn = use_se; | 
 |       curr_occr->block_num = bb_num; | 
 |       tmp_occr = extension_expr->antic_occr; | 
 |       if (!tmp_occr) | 
 | 	extension_expr->antic_occr = curr_occr; | 
 |       else | 
 | 	{ | 
 | 	  while (tmp_occr->next) | 
 | 	    tmp_occr = tmp_occr->next; | 
 | 	  tmp_occr->next = curr_occr; | 
 | 	} | 
 |       if (curr_prop->last_def < 0) | 
 | 	{ | 
 | 	  /* Set the available bit.  */ | 
 | 	  SET_BIT (comp[bb_num], indx); | 
 | 	  /* Record the available occurrence.  */ | 
 | 	  curr_occr = xmalloc (sizeof (struct see_occr)); | 
 | 	  curr_occr->next = NULL; | 
 | 	  curr_occr->insn = use_se; | 
 | 	  curr_occr->block_num = bb_num; | 
 | 	  tmp_occr = extension_expr->avail_occr; | 
 | 	  if (!tmp_occr) | 
 | 	    extension_expr->avail_occr = curr_occr; | 
 | 	  else | 
 | 	    { | 
 |   	      while (tmp_occr->next) | 
 |   		tmp_occr = tmp_occr->next; | 
 | 	      tmp_occr->next = curr_occr; | 
 | 	    } | 
 | 	} | 
 |       /* Note: there is no need to reset the killed bit since it must be zero at | 
 | 	 this point.  */ | 
 |     } | 
 |   else if (curr_prop->first_se_after_last_def == DF_INSN_LUID (df, ref)) | 
 |     { | 
 |       /* Set the available bit.  */ | 
 |       SET_BIT (comp[bb_num], indx); | 
 |       /* Reset the killed bit.  */ | 
 |       RESET_BIT (ae_kill[bb_num], indx); | 
 |       /* Record the available occurrence.  */ | 
 |       curr_occr = xmalloc (sizeof (struct see_occr)); | 
 |       curr_occr->next = NULL; | 
 |       curr_occr->insn = use_se; | 
 |       curr_occr->block_num = bb_num; | 
 |       tmp_occr = extension_expr->avail_occr; | 
 |       if (!tmp_occr) | 
 | 	extension_expr->avail_occr = curr_occr; | 
 |       else | 
 | 	{ | 
 | 	  while (tmp_occr->next) | 
 | 	    tmp_occr = tmp_occr->next; | 
 | 	  tmp_occr->next = curr_occr; | 
 | 	} | 
 |     } | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Here we traverse over all the merged and unmerged extensions of the reference | 
 |    and analyze their properties for the LCM. | 
 |  | 
 |    This is a subroutine of see_execute_LCM called via splay_tree_foreach. | 
 |  | 
 |    STN is the current node in the see_bb_splay_ar[i] splay tree.  It holds a | 
 |    see_ref_s structure.  */ | 
 |  | 
 | static int | 
 | see_analyze_ref_local_prop (splay_tree_node stn, | 
 | 			    void *data ATTRIBUTE_UNUSED) | 
 | { | 
 |   htab_t use_se_hash = ((struct see_ref_s *) (stn->value))->use_se_hash; | 
 |   htab_t unmerged_def_se_hash = | 
 |     ((struct see_ref_s *) (stn->value))->unmerged_def_se_hash; | 
 |   htab_t merged_def_se_hash = | 
 |     ((struct see_ref_s *) (stn->value))->merged_def_se_hash; | 
 |  | 
 |   /* Analyze use extensions that were not merged with the reference.  */ | 
 |   if (use_se_hash) | 
 |     htab_traverse_noresize (use_se_hash, see_analyze_use_local_prop, | 
 | 			    (PTR) (stn->value)); | 
 |  | 
 |   /* Analyze def extensions that were not merged with the reference.  */ | 
 |   if (unmerged_def_se_hash) | 
 |     htab_traverse (unmerged_def_se_hash, see_analyze_unmerged_def_local_prop, | 
 | 		   (PTR) (stn->value)); | 
 |  | 
 |   /* Analyze def extensions that were merged with the reference.  */ | 
 |   if (merged_def_se_hash) | 
 |     htab_traverse (merged_def_se_hash, see_analyze_merged_def_local_prop, | 
 | 		   (PTR) (stn->value)); | 
 |  | 
 |   /* Continue to the next definition.  */ | 
 |   return 0; | 
 | } | 
 |  | 
 |  | 
 | /* Phase 3 top level function. | 
 |    In this phase, we set the input bit vectors of the LCM according to data | 
 |    gathered in phase 2. | 
 |    Then we run the edge based LCM.  */ | 
 |  | 
 | static void | 
 | see_execute_LCM (void) | 
 | { | 
 |   size_t pre_extension_num = htab_elements (see_pre_extension_hash); | 
 |   int i = 0; | 
 |  | 
 |   if (dump_file) | 
 |     fprintf (dump_file, | 
 |       "* Phase 3: Eliminate globally redundant extensions.  *\n"); | 
 |  | 
 |   /* Initialize the global sbitmap vectors.  */ | 
 |   transp = sbitmap_vector_alloc (last_bb, pre_extension_num); | 
 |   comp = sbitmap_vector_alloc (last_bb, pre_extension_num); | 
 |   antloc = sbitmap_vector_alloc (last_bb, pre_extension_num); | 
 |   ae_kill = sbitmap_vector_alloc (last_bb, pre_extension_num); | 
 |   sbitmap_vector_ones (transp, last_bb); | 
 |   sbitmap_vector_zero (comp, last_bb); | 
 |   sbitmap_vector_zero (antloc, last_bb); | 
 |   sbitmap_vector_zero (ae_kill, last_bb); | 
 |  | 
 |   /* Traverse over all the splay trees of the basic blocks.  */ | 
 |   for (i = 0; i < last_bb; i++) | 
 |     { | 
 |       if (see_bb_splay_ar[i]) | 
 | 	{ | 
 | 	  /* Traverse over all the references in the basic block in forward | 
 | 	     order.  */ | 
 | 	  splay_tree_foreach (see_bb_splay_ar[i], | 
 | 			      see_analyze_ref_local_prop, NULL); | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Add fake exit edges before running the lcm.  */ | 
 |   add_noreturn_fake_exit_edges (); | 
 |  | 
 |   /* Run the LCM.  */ | 
 |   edge_list = pre_edge_lcm (pre_extension_num, transp, comp, antloc, | 
 |   			    ae_kill, &pre_insert_map, &pre_delete_map); | 
 |  | 
 |   /* Remove the fake edges.  */ | 
 |   remove_fake_exit_edges (); | 
 | } | 
 |  | 
 |  | 
 | /* Phase 2 implementation: Merge and eliminate locally redundant extensions.  */ | 
 |  | 
 | /* In this function we set the register properties for the register that is | 
 |    defined and extended in the reference. | 
 |    The properties are defined in see_register_properties structure which is | 
 |    allocated per basic block and per register. | 
 |    Later the extension is inserted into the see_pre_extension_hash for the next | 
 |    phase of the optimization. | 
 |  | 
 |    This is a subroutine of see_handle_extensions_for_one_ref called | 
 |    via htab_traverse. | 
 |  | 
 |    SLOT contains the current def extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_set_prop_merged_def (void **slot, void *b) | 
 | { | 
 |   rtx def_se = *slot; | 
 |   struct see_ref_s *curr_ref_s = (struct see_ref_s *) b; | 
 |   rtx insn = curr_ref_s->insn; | 
 |   rtx dest_extension_reg = see_get_extension_reg (def_se, 1); | 
 |   htab_t curr_bb_hash; | 
 |   struct see_register_properties *curr_prop = NULL; | 
 |   struct see_register_properties **slot_prop; | 
 |   struct see_register_properties temp_prop; | 
 |   int ref_luid = DF_INSN_LUID (df, insn); | 
 |  | 
 |   curr_bb_hash = see_bb_hash_ar[BLOCK_NUM (curr_ref_s->insn)]; | 
 |   if (!curr_bb_hash) | 
 |     { | 
 |       /* The hash doesn't exist yet.  Create it.  */ | 
 |       curr_bb_hash = htab_create (10,  | 
 | 				  hash_descriptor_properties,  | 
 | 				  eq_descriptor_properties, | 
 | 				  hash_del_properties); | 
 |       see_bb_hash_ar[BLOCK_NUM (curr_ref_s->insn)] = curr_bb_hash; | 
 |     } | 
 |  | 
 |   /* Find the right register properties in the right basic block.  */ | 
 |   temp_prop.regno = REGNO (dest_extension_reg); | 
 |   slot_prop = | 
 |     (struct see_register_properties **) htab_find_slot (curr_bb_hash, | 
 | 							&temp_prop, INSERT); | 
 |  | 
 |   if (slot_prop && *slot_prop != NULL) | 
 |     { | 
 |       /* Property already exists.  */ | 
 |       curr_prop = *slot_prop; | 
 |       gcc_assert (curr_prop->regno == REGNO (dest_extension_reg)); | 
 |  | 
 |       curr_prop->last_def = ref_luid; | 
 |       curr_prop->first_se_after_last_def = ref_luid; | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Property doesn't exist yet.  */ | 
 |       curr_prop = xmalloc (sizeof (struct see_register_properties)); | 
 |       curr_prop->regno = REGNO (dest_extension_reg); | 
 |       curr_prop->last_def = ref_luid; | 
 |       curr_prop->first_se_before_any_def = -1; | 
 |       curr_prop->first_se_after_last_def = ref_luid; | 
 |       *slot_prop = curr_prop; | 
 |     } | 
 |  | 
 |   /* Insert the def_se into see_pre_extension_hash if it isn't already | 
 |      there.  */ | 
 |   see_seek_pre_extension_expr (def_se, DEF_EXTENSION); | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* In this function we set the register properties for the register that is | 
 |    defined but not extended in the reference. | 
 |    The properties are defined in see_register_properties structure which is | 
 |    allocated per basic block and per register. | 
 |    Later the extension is inserted into the see_pre_extension_hash for the next | 
 |    phase of the optimization. | 
 |  | 
 |    This is a subroutine of see_handle_extensions_for_one_ref called | 
 |    via htab_traverse. | 
 |  | 
 |    SLOT contains the current def extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_set_prop_unmerged_def (void **slot, void *b) | 
 | { | 
 |   rtx def_se = *slot; | 
 |   struct see_ref_s *curr_ref_s = (struct see_ref_s *) b; | 
 |   rtx insn = curr_ref_s->insn; | 
 |   rtx dest_extension_reg = see_get_extension_reg (def_se, 1); | 
 |   htab_t curr_bb_hash; | 
 |   struct see_register_properties *curr_prop = NULL; | 
 |   struct see_register_properties **slot_prop; | 
 |   struct see_register_properties temp_prop; | 
 |   int ref_luid = DF_INSN_LUID (df, insn); | 
 |  | 
 |   curr_bb_hash = see_bb_hash_ar[BLOCK_NUM (curr_ref_s->insn)]; | 
 |   if (!curr_bb_hash) | 
 |     { | 
 |       /* The hash doesn't exist yet.  Create it.  */ | 
 |       curr_bb_hash = htab_create (10,  | 
 | 				  hash_descriptor_properties,  | 
 | 				  eq_descriptor_properties, | 
 | 				  hash_del_properties); | 
 |       see_bb_hash_ar[BLOCK_NUM (curr_ref_s->insn)] = curr_bb_hash; | 
 |     } | 
 |  | 
 |   /* Find the right register properties in the right basic block.  */ | 
 |   temp_prop.regno = REGNO (dest_extension_reg); | 
 |   slot_prop = | 
 |     (struct see_register_properties **) htab_find_slot (curr_bb_hash, | 
 | 							&temp_prop, INSERT); | 
 |  | 
 |   if (slot_prop && *slot_prop != NULL) | 
 |     { | 
 |       /* Property already exists.  */ | 
 |       curr_prop = *slot_prop; | 
 |       gcc_assert (curr_prop->regno == REGNO (dest_extension_reg)); | 
 |  | 
 |       curr_prop->last_def = ref_luid; | 
 |       curr_prop->first_se_after_last_def = -1; | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Property doesn't exist yet.  */ | 
 |       curr_prop = xmalloc (sizeof (struct see_register_properties)); | 
 |       curr_prop->regno = REGNO (dest_extension_reg); | 
 |       curr_prop->last_def = ref_luid; | 
 |       curr_prop->first_se_before_any_def = -1; | 
 |       curr_prop->first_se_after_last_def = -1; | 
 |       *slot_prop = curr_prop; | 
 |     } | 
 |  | 
 |   /* Insert the def_se into see_pre_extension_hash if it isn't already | 
 |      there.  */ | 
 |   see_seek_pre_extension_expr (def_se, DEF_EXTENSION); | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* In this function we set the register properties for the register that is used | 
 |    in the reference. | 
 |    The properties are defined in see_register_properties structure which is | 
 |    allocated per basic block and per register. | 
 |    When a redundant use extension is found it is removed from the hash of the | 
 |    reference. | 
 |    If the extension is non redundant it is inserted into the | 
 |    see_pre_extension_hash for the next phase of the optimization. | 
 |  | 
 |    This is a subroutine of see_handle_extensions_for_one_ref called | 
 |    via htab_traverse. | 
 |  | 
 |    SLOT contains the current use extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_set_prop_unmerged_use (void **slot, void *b) | 
 | { | 
 |   rtx use_se = *slot; | 
 |   struct see_ref_s *curr_ref_s = (struct see_ref_s *) b; | 
 |   rtx insn = curr_ref_s->insn; | 
 |   rtx dest_extension_reg = see_get_extension_reg (use_se, 1); | 
 |   htab_t curr_bb_hash; | 
 |   struct see_register_properties *curr_prop = NULL; | 
 |   struct see_register_properties **slot_prop; | 
 |   struct see_register_properties temp_prop; | 
 |   bool locally_redundant = false; | 
 |   int ref_luid = DF_INSN_LUID (df, insn); | 
 |  | 
 |   curr_bb_hash = see_bb_hash_ar[BLOCK_NUM (curr_ref_s->insn)]; | 
 |   if (!curr_bb_hash) | 
 |     { | 
 |       /* The hash doesn't exist yet.  Create it.  */ | 
 |       curr_bb_hash = htab_create (10,  | 
 | 				  hash_descriptor_properties,  | 
 | 				  eq_descriptor_properties, | 
 | 				  hash_del_properties); | 
 |       see_bb_hash_ar[BLOCK_NUM (curr_ref_s->insn)] = curr_bb_hash; | 
 |     } | 
 |  | 
 |   /* Find the right register properties in the right basic block.  */ | 
 |   temp_prop.regno = REGNO (dest_extension_reg); | 
 |   slot_prop = | 
 |     (struct see_register_properties **) htab_find_slot (curr_bb_hash, | 
 | 							&temp_prop, INSERT); | 
 |  | 
 |   if (slot_prop && *slot_prop != NULL) | 
 |     { | 
 |       /* Property already exists.  */ | 
 |       curr_prop = *slot_prop; | 
 |       gcc_assert (curr_prop->regno == REGNO (dest_extension_reg)); | 
 |  | 
 |  | 
 |       if (curr_prop->last_def < 0 && curr_prop->first_se_before_any_def < 0) | 
 | 	curr_prop->first_se_before_any_def = ref_luid; | 
 |       else if (curr_prop->last_def < 0 | 
 | 	       && curr_prop->first_se_before_any_def >= 0) | 
 | 	{ | 
 | 	  /* In this case the extension is locally redundant.  */ | 
 | 	  htab_clear_slot (curr_ref_s->use_se_hash, (PTR *)slot); | 
 | 	  locally_redundant = true; | 
 | 	} | 
 |       else if (curr_prop->last_def >= 0 | 
 | 	       && curr_prop->first_se_after_last_def < 0) | 
 | 	curr_prop->first_se_after_last_def = ref_luid; | 
 |       else if (curr_prop->last_def >= 0 | 
 | 	       && curr_prop->first_se_after_last_def >= 0) | 
 | 	{ | 
 | 	  /* In this case the extension is locally redundant.  */ | 
 | 	  htab_clear_slot (curr_ref_s->use_se_hash, (PTR *)slot); | 
 | 	  locally_redundant = true; | 
 | 	} | 
 |       else | 
 | 	gcc_unreachable (); | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Property doesn't exist yet.  Create a new one.  */ | 
 |       curr_prop = xmalloc (sizeof (struct see_register_properties)); | 
 |       curr_prop->regno = REGNO (dest_extension_reg); | 
 |       curr_prop->last_def = -1; | 
 |       curr_prop->first_se_before_any_def = ref_luid; | 
 |       curr_prop->first_se_after_last_def = -1; | 
 |       *slot_prop = curr_prop; | 
 |     } | 
 |  | 
 |   /* Insert the use_se into see_pre_extension_hash if it isn't already | 
 |      there.  */ | 
 |   if (!locally_redundant) | 
 |     see_seek_pre_extension_expr (use_se, USE_EXTENSION); | 
 |   if (locally_redundant && dump_file) | 
 |     { | 
 |       fprintf (dump_file, "Locally redundant extension:\n"); | 
 |       print_rtl_single (dump_file, use_se); | 
 |     } | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Print an extension instruction. | 
 |  | 
 |    This is a subroutine of see_handle_extensions_for_one_ref called | 
 |    via htab_traverse. | 
 |    SLOT contains the extension instruction.  */ | 
 |  | 
 | static int | 
 | see_print_one_extension (void **slot, void *b ATTRIBUTE_UNUSED) | 
 | { | 
 |   rtx def_se = *slot; | 
 |  | 
 |   gcc_assert (def_se && INSN_P (def_se)); | 
 |   print_rtl_single (dump_file, def_se); | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Function called by note_uses to replace used subexpressions. | 
 |  | 
 |    X is a pointer to the subexpression and DATA is a pointer to a | 
 |    see_replace_data structure that contains the data for the replacement.  */ | 
 |  | 
 | static void | 
 | see_replace_src (rtx *x, void *data) | 
 | { | 
 |   struct see_replace_data *d | 
 |     = (struct see_replace_data *) data; | 
 |  | 
 |   *x = replace_rtx (*x, d->from, d->to); | 
 | } | 
 |  | 
 |  | 
 | /* At this point the pattern is expected to be: | 
 |  | 
 |    ref:	    set (dest_reg) (rhs) | 
 |    def_se:  set (dest_extension_reg) (sign/zero_extend (source_extension_reg)) | 
 |  | 
 |    The merge of these two instructions didn't succeed. | 
 |  | 
 |    We try to generate the pattern: | 
 |    set (subreg (dest_extension_reg)) (rhs) | 
 |  | 
 |    We do this in 4 steps: | 
 |    a. Replace every use of dest_reg with a new pseudo register. | 
 |    b. Replace every instance of dest_reg with the subreg. | 
 |    c. Replace every use of the new pseudo register back to dest_reg. | 
 |    d. Try to recognize and simplify. | 
 |  | 
 |    If the manipulation failed, leave the original ref but try to generate and | 
 |    recognize a simple move instruction: | 
 |    set (subreg (dest_extension_reg)) (dest_reg) | 
 |    This move instruction will be emitted right after the ref to the instruction | 
 |    stream and assure the correctness of the code after def_se will be removed. | 
 |  | 
 |    CURR_REF_S is the current reference. | 
 |    DEF_SE is the extension that couldn't be merged.  */ | 
 |  | 
 | static void | 
 | see_def_extension_not_merged (struct see_ref_s *curr_ref_s, rtx def_se) | 
 | { | 
 |   struct see_replace_data d; | 
 |   /* If the original insn was already merged with an extension before, | 
 |      take the merged one.  */ | 
 |   rtx ref = (curr_ref_s->merged_insn) ? curr_ref_s->merged_insn : | 
 | 					curr_ref_s->insn; | 
 |   rtx merged_ref_next = (curr_ref_s->merged_insn) ? | 
 |   			NEXT_INSN (curr_ref_s->merged_insn): NULL_RTX; | 
 |   rtx ref_copy = copy_rtx (ref); | 
 |   rtx source_extension_reg = see_get_extension_reg (def_se, 0); | 
 |   rtx dest_extension_reg = see_get_extension_reg (def_se, 1); | 
 |   rtx move_insn = NULL; | 
 |   rtx set, rhs; | 
 |   rtx dest_reg, dest_real_reg; | 
 |   rtx new_pseudo_reg, subreg; | 
 |   enum machine_mode source_extension_mode = GET_MODE (source_extension_reg); | 
 |   enum machine_mode dest_mode; | 
 |  | 
 |   set = single_set (def_se); | 
 |   gcc_assert (set); | 
 |   rhs = SET_SRC (set); | 
 |   gcc_assert (GET_CODE (rhs) == SIGN_EXTEND | 
 | 	      || GET_CODE (rhs) == ZERO_EXTEND); | 
 |   dest_reg = XEXP (rhs, 0); | 
 |   gcc_assert (REG_P (dest_reg) | 
 | 	      || (GET_CODE (dest_reg) == SUBREG | 
 | 		  && REG_P (SUBREG_REG (dest_reg)))); | 
 |   dest_real_reg = REG_P (dest_reg) ? dest_reg : SUBREG_REG (dest_reg); | 
 |   dest_mode = GET_MODE (dest_reg); | 
 |  | 
 |   subreg = gen_lowpart_SUBREG (dest_mode, dest_extension_reg); | 
 |   new_pseudo_reg = gen_reg_rtx (source_extension_mode); | 
 |  | 
 |   /* Step a: Replace every use of dest_real_reg with a new pseudo register.  */ | 
 |   d.from = dest_real_reg; | 
 |   d.to = new_pseudo_reg; | 
 |   note_uses (&PATTERN (ref_copy), see_replace_src, &d); | 
 |   /* Step b: Replace every instance of dest_reg with the subreg.  */ | 
 |   ref_copy = replace_rtx (ref_copy, dest_reg, subreg); | 
 |  | 
 |   /* Step c: Replace every use of the new pseudo register back to | 
 |      dest_real_reg.  */ | 
 |   d.from = new_pseudo_reg; | 
 |   d.to = dest_real_reg; | 
 |   note_uses (&PATTERN (ref_copy), see_replace_src, &d); | 
 |  | 
 |   if (rtx_equal_p (PATTERN (ref), PATTERN (ref_copy)) | 
 |       || insn_invalid_p (ref_copy)) | 
 |     { | 
 |       /* The manipulation failed.  */ | 
 |  | 
 |       /* Create a new copy.  */ | 
 |       ref_copy = copy_rtx (ref); | 
 |  | 
 |       /* Create a simple move instruction that will replace the def_se.  */ | 
 |       start_sequence (); | 
 |       emit_move_insn (subreg, dest_reg); | 
 |       move_insn = get_insns (); | 
 |       end_sequence (); | 
 |  | 
 |       /* Link the manipulated instruction to the newly created move instruction | 
 | 	 and to the former created move instructions.  */ | 
 |       PREV_INSN (ref_copy) = NULL_RTX; | 
 |       NEXT_INSN (ref_copy) = move_insn; | 
 |       PREV_INSN (move_insn) = ref_copy; | 
 |       NEXT_INSN (move_insn) = merged_ref_next; | 
 |       if (merged_ref_next != NULL_RTX) | 
 | 	PREV_INSN (merged_ref_next) = move_insn; | 
 |       curr_ref_s->merged_insn = ref_copy; | 
 |  | 
 |       if (dump_file) | 
 | 	{ | 
 | 	  fprintf (dump_file, "Following def merge failure a move "); | 
 | 	  fprintf (dump_file, "insn was added after the ref.\n"); | 
 | 	  fprintf (dump_file, "Original ref:\n"); | 
 | 	  print_rtl_single (dump_file, ref); | 
 | 	  fprintf (dump_file, "Move insn that was added:\n"); | 
 | 	  print_rtl_single (dump_file, move_insn); | 
 | 	} | 
 |       return; | 
 |     } | 
 |  | 
 |   /* The manipulation succeeded.  Store the new manipulated reference.  */ | 
 |  | 
 |   /* Try to simplify the new manipulated insn.  */ | 
 |   validate_simplify_insn (ref_copy); | 
 |  | 
 |   /* Create a simple move instruction to assure the correctness of the code.  */ | 
 |   start_sequence (); | 
 |   emit_move_insn (dest_reg, subreg); | 
 |   move_insn = get_insns (); | 
 |   end_sequence (); | 
 |  | 
 |   /* Link the manipulated instruction to the newly created move instruction and | 
 |      to the former created move instructions.  */ | 
 |   PREV_INSN (ref_copy) = NULL_RTX; | 
 |   NEXT_INSN (ref_copy) = move_insn; | 
 |   PREV_INSN (move_insn) = ref_copy; | 
 |   NEXT_INSN (move_insn) = merged_ref_next; | 
 |   if (merged_ref_next != NULL_RTX) | 
 |     PREV_INSN (merged_ref_next) = move_insn; | 
 |   curr_ref_s->merged_insn = ref_copy; | 
 |  | 
 |   if (dump_file) | 
 |     { | 
 |       fprintf (dump_file, "Following merge failure the ref was transformed!\n"); | 
 |       fprintf (dump_file, "Original ref:\n"); | 
 |       print_rtl_single (dump_file, ref); | 
 |       fprintf (dump_file, "Transformed ref:\n"); | 
 |       print_rtl_single (dump_file, ref_copy); | 
 |       fprintf (dump_file, "Move insn that was added:\n"); | 
 |       print_rtl_single (dump_file, move_insn); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* Merge the reference instruction (ref) with the current use extension. | 
 |  | 
 |    use_se extends a NARROWmode register to a WIDEmode register. | 
 |    ref uses the WIDEmode register. | 
 |  | 
 |    The pattern we try to merge is this: | 
 |    use_se: set (dest_extension_reg) (sign/zero_extend (source_extension_reg)) | 
 |    ref:	   use (dest_extension_reg) | 
 |  | 
 |    where dest_extension_reg and source_extension_reg can be subregs. | 
 |  | 
 |    The merge is done by generating, simplifying and recognizing the pattern: | 
 |    use (sign/zero_extend (source_extension_reg)) | 
 |  | 
 |    If ref is too simple (according to see_want_to_be_merged_with_extension ()) | 
 |    we don't try to merge it with use_se and we continue as if the merge failed. | 
 |  | 
 |    This is a subroutine of see_handle_extensions_for_one_ref called | 
 |    via htab_traverse. | 
 |    SLOT contains the current use extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_merge_one_use_extension (void **slot, void *b) | 
 | { | 
 |   struct see_ref_s *curr_ref_s = (struct see_ref_s *) b; | 
 |   rtx use_se = *slot; | 
 |   rtx ref = (curr_ref_s->merged_insn) ? curr_ref_s->merged_insn : | 
 | 					curr_ref_s->insn; | 
 |   rtx merged_ref_next = (curr_ref_s->merged_insn) ? | 
 |   			NEXT_INSN (curr_ref_s->merged_insn): NULL_RTX; | 
 |   rtx ref_copy = copy_rtx (ref); | 
 |   rtx extension_set = single_set (use_se); | 
 |   rtx extension_rhs = NULL; | 
 |   rtx dest_extension_reg = see_get_extension_reg (use_se, 1); | 
 |   rtx note = NULL; | 
 |   rtx simplified_note = NULL; | 
 |  | 
 |   gcc_assert (use_se && curr_ref_s && extension_set); | 
 |  | 
 |   extension_rhs = SET_SRC (extension_set); | 
 |  | 
 |   /* In REG_EQUIV and REG_EQUAL notes that mention the register we need to | 
 |      replace the uses of the dest_extension_reg with the rhs of the extension | 
 |      instruction.  This is necessary since there might not be an extension in | 
 |      the path between the definition and the note when this optimization is | 
 |      over.  */ | 
 |   note = find_reg_equal_equiv_note (ref_copy); | 
 |   if (note) | 
 |     { | 
 |       simplified_note = simplify_replace_rtx (XEXP (note, 0), | 
 |       					      dest_extension_reg, | 
 | 					      extension_rhs); | 
 |       if (rtx_equal_p (XEXP (note, 0), simplified_note)) | 
 | 	/* Replacement failed.  Remove the note.  */ | 
 | 	remove_note (ref_copy, note); | 
 |       else | 
 | 	XEXP (note, 0) = simplified_note; | 
 |     } | 
 |  | 
 |   if (!see_want_to_be_merged_with_extension (ref, use_se, USE_EXTENSION)) | 
 |     { | 
 |       /* The use in the reference is too simple.  Don't try to merge.  */ | 
 |       if (dump_file) | 
 | 	{ | 
 | 	  fprintf (dump_file, "Use merge skipped!\n"); | 
 | 	  fprintf (dump_file, "Original instructions:\n"); | 
 | 	  print_rtl_single (dump_file, use_se); | 
 | 	  print_rtl_single (dump_file, ref); | 
 | 	} | 
 |       /* Don't remove the current use_se from the use_se_hash and continue to | 
 | 	 the next extension.  */ | 
 |       return 1; | 
 |     } | 
 |  | 
 |   validate_replace_src_group (dest_extension_reg, extension_rhs, ref_copy); | 
 |  | 
 |   if (!num_changes_pending ()) | 
 |     /* In this case this is not a real use (the only use is/was in the notes | 
 |        list).  Remove the use extension from the hash.  This will prevent it | 
 |        from been emitted in the first place.  */ | 
 |     { | 
 |       if (dump_file) | 
 | 	{ | 
 | 	  fprintf (dump_file, "Use extension not necessary before:\n"); | 
 | 	  print_rtl_single (dump_file, ref); | 
 | 	} | 
 |       htab_clear_slot (curr_ref_s->use_se_hash, (PTR *)slot); | 
 |       PREV_INSN (ref_copy) = NULL_RTX; | 
 |       NEXT_INSN (ref_copy) = merged_ref_next; | 
 |       if (merged_ref_next != NULL_RTX) | 
 | 	PREV_INSN (merged_ref_next) = ref_copy; | 
 |       curr_ref_s->merged_insn = ref_copy; | 
 |       return 1; | 
 |     } | 
 |  | 
 |   if (!apply_change_group ()) | 
 |     { | 
 |       /* The merge failed.  */ | 
 |       if (dump_file) | 
 | 	{ | 
 | 	  fprintf (dump_file, "Use merge failed!\n"); | 
 | 	  fprintf (dump_file, "Original instructions:\n"); | 
 | 	  print_rtl_single (dump_file, use_se); | 
 | 	  print_rtl_single (dump_file, ref); | 
 | 	} | 
 |       /* Don't remove the current use_se from the use_se_hash and continue to | 
 | 	 the next extension.  */ | 
 |       return 1; | 
 |     } | 
 |  | 
 |   /* The merge succeeded!  */ | 
 |  | 
 |   /* Try to simplify the new merged insn.  */ | 
 |   validate_simplify_insn (ref_copy); | 
 |  | 
 |   PREV_INSN (ref_copy) = NULL_RTX; | 
 |   NEXT_INSN (ref_copy) = merged_ref_next; | 
 |   if (merged_ref_next != NULL_RTX) | 
 |     PREV_INSN (merged_ref_next) = ref_copy; | 
 |   curr_ref_s->merged_insn = ref_copy; | 
 |  | 
 |   if (dump_file) | 
 |     { | 
 |       fprintf (dump_file, "Use merge succeeded!\n"); | 
 |       fprintf (dump_file, "Original instructions:\n"); | 
 |       print_rtl_single (dump_file, use_se); | 
 |       print_rtl_single (dump_file, ref); | 
 |       fprintf (dump_file, "Merged instruction:\n"); | 
 |       print_rtl_single (dump_file, ref_copy); | 
 |     } | 
 |  | 
 |   /* Remove the current use_se from the use_se_hash.  This will prevent it from | 
 |      been emitted in the first place.  */ | 
 |   htab_clear_slot (curr_ref_s->use_se_hash, (PTR *)slot); | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Merge the reference instruction (ref) with the extension that follows it | 
 |    in the same basic block (def_se). | 
 |    ref sets a NARROWmode register and def_se extends it to WIDEmode register. | 
 |  | 
 |    The pattern we try to merge is this: | 
 |    ref:	   set (dest_reg) (rhs) | 
 |    def_se: set (dest_extension_reg) (sign/zero_extend (source_extension_reg)) | 
 |  | 
 |    where dest_reg and source_extension_reg can both be subregs (together) | 
 |    and (REGNO (dest_reg) == REGNO (source_extension_reg)) | 
 |  | 
 |    The merge is done by generating, simplifying and recognizing the pattern: | 
 |    set (dest_extension_reg) (sign/zero_extend (rhs)) | 
 |    If ref is a parallel instruction we just replace the relevant set in it. | 
 |  | 
 |    If ref is too simple (according to see_want_to_be_merged_with_extension ()) | 
 |    we don't try to merge it with def_se and we continue as if the merge failed. | 
 |  | 
 |    This is a subroutine of see_handle_extensions_for_one_ref called | 
 |    via htab_traverse. | 
 |  | 
 |    SLOT contains the current def extension instruction. | 
 |    B is the see_ref_s structure pointer.  */ | 
 |  | 
 | static int | 
 | see_merge_one_def_extension (void **slot, void *b) | 
 | { | 
 |   struct see_ref_s *curr_ref_s = (struct see_ref_s *) b; | 
 |   rtx def_se = *slot; | 
 |   /* If the original insn was already merged with an extension before, | 
 |      take the merged one.  */ | 
 |   rtx ref = (curr_ref_s->merged_insn) ? curr_ref_s->merged_insn : | 
 | 					curr_ref_s->insn; | 
 |   rtx merged_ref_next = (curr_ref_s->merged_insn) ? | 
 |   			NEXT_INSN (curr_ref_s->merged_insn): NULL_RTX; | 
 |   rtx ref_copy = copy_rtx (ref); | 
 |   rtx new_set = NULL; | 
 |   rtx source_extension_reg = see_get_extension_reg (def_se, 0); | 
 |   rtx dest_extension_reg = see_get_extension_reg (def_se, 1); | 
 |   rtx move_insn, *rtx_slot, subreg; | 
 |   rtx temp_extension = NULL; | 
 |   rtx simplified_temp_extension = NULL; | 
 |   rtx *pat; | 
 |   enum rtx_code code; | 
 |   enum rtx_code extension_code; | 
 |   enum machine_mode source_extension_mode; | 
 |   enum machine_mode source_mode; | 
 |   enum machine_mode dest_extension_mode; | 
 |   bool merge_success = false; | 
 |   int i; | 
 |  | 
 |   gcc_assert (def_se | 
 |   	      && INSN_P (def_se) | 
 | 	      && curr_ref_s | 
 | 	      && ref | 
 | 	      && INSN_P (ref)); | 
 |  | 
 |   if (!see_want_to_be_merged_with_extension (ref, def_se, DEF_EXTENSION)) | 
 |     { | 
 |       /* The definition in the reference is too simple.  Don't try to merge.  */ | 
 |       if (dump_file) | 
 | 	{ | 
 | 	  fprintf (dump_file, "Def merge skipped!\n"); | 
 | 	  fprintf (dump_file, "Original instructions:\n"); | 
 | 	  print_rtl_single (dump_file, ref); | 
 | 	  print_rtl_single (dump_file, def_se); | 
 | 	} | 
 |  | 
 |       see_def_extension_not_merged (curr_ref_s, def_se); | 
 |       /* Continue to the next extension.  */ | 
 |       return 1; | 
 |     } | 
 |  | 
 |   extension_code = see_get_extension_data (def_se, &source_mode); | 
 |  | 
 |   /* Try to merge and simplify the extension.  */ | 
 |   source_extension_mode = GET_MODE (source_extension_reg); | 
 |   dest_extension_mode = GET_MODE (dest_extension_reg); | 
 |  | 
 |   pat = &PATTERN (ref_copy); | 
 |   code = GET_CODE (*pat); | 
 |  | 
 |   if (code == PARALLEL) | 
 |     { | 
 |       bool need_to_apply_change = false; | 
 |  | 
 |       for (i = 0; i < XVECLEN (*pat, 0); i++) | 
 | 	{ | 
 | 	  rtx *sub = &XVECEXP (*pat, 0, i); | 
 |  | 
 | 	  if (GET_CODE (*sub) == SET | 
 | 	      && GET_MODE (SET_SRC (*sub)) != VOIDmode | 
 | 	      && GET_MODE (SET_DEST (*sub)) == source_mode | 
 | 	      && ((REG_P (SET_DEST (*sub)) | 
 | 		   && REGNO (SET_DEST (*sub)) == REGNO (source_extension_reg)) | 
 | 		  || (GET_CODE (SET_DEST (*sub)) == SUBREG | 
 | 		      && REG_P (SUBREG_REG (SET_DEST (*sub))) | 
 | 		      && (REGNO (SUBREG_REG (SET_DEST (*sub))) == | 
 | 			  REGNO (source_extension_reg))))) | 
 | 	    { | 
 | 	      rtx orig_src = SET_SRC (*sub); | 
 |  | 
 | 	      if (extension_code == SIGN_EXTEND) | 
 | 		temp_extension = gen_rtx_SIGN_EXTEND (dest_extension_mode, | 
 | 						      orig_src); | 
 | 	      else | 
 | 		temp_extension = gen_rtx_ZERO_EXTEND (dest_extension_mode, | 
 | 						      orig_src); | 
 | 	      simplified_temp_extension = simplify_rtx (temp_extension); | 
 | 	      temp_extension = | 
 | 		(simplified_temp_extension) ? simplified_temp_extension : | 
 | 					      temp_extension; | 
 | 	      new_set = gen_rtx_SET (VOIDmode, dest_extension_reg, | 
 | 				     temp_extension); | 
 | 	      validate_change (ref_copy, sub, new_set, 1); | 
 | 	      need_to_apply_change = true; | 
 | 	    } | 
 | 	} | 
 |       if (need_to_apply_change) | 
 | 	if (apply_change_group ()) | 
 | 	  merge_success = true; | 
 |     } | 
 |   else if (code == SET | 
 | 	   && GET_MODE (SET_SRC (*pat)) != VOIDmode | 
 | 	   && GET_MODE (SET_DEST (*pat)) == source_mode | 
 | 	   && ((REG_P (SET_DEST (*pat)) | 
 | 		&& REGNO (SET_DEST (*pat)) == REGNO (source_extension_reg)) | 
 | 	       || (GET_CODE (SET_DEST (*pat)) == SUBREG | 
 | 		   && REG_P (SUBREG_REG (SET_DEST (*pat))) | 
 | 		   && (REGNO (SUBREG_REG (SET_DEST (*pat))) == | 
 | 		       REGNO (source_extension_reg))))) | 
 |     { | 
 |       rtx orig_src = SET_SRC (*pat); | 
 |  | 
 |       if (extension_code == SIGN_EXTEND) | 
 | 	temp_extension = gen_rtx_SIGN_EXTEND (dest_extension_mode, orig_src); | 
 |       else | 
 | 	temp_extension = gen_rtx_ZERO_EXTEND (dest_extension_mode, orig_src); | 
 |       simplified_temp_extension = simplify_rtx (temp_extension); | 
 |       temp_extension = (simplified_temp_extension) ? simplified_temp_extension : | 
 | 						     temp_extension; | 
 |       new_set = gen_rtx_SET (VOIDmode, dest_extension_reg, temp_extension); | 
 |       if (validate_change (ref_copy, pat, new_set, 0)) | 
 | 	merge_success = true; | 
 |     } | 
 |   if (!merge_success) | 
 |     { | 
 |       /* The merge failed.  */ | 
 |       if (dump_file) | 
 | 	{ | 
 | 	  fprintf (dump_file, "Def merge failed!\n"); | 
 | 	  fprintf (dump_file, "Original instructions:\n"); | 
 | 	  print_rtl_single (dump_file, ref); | 
 | 	  print_rtl_single (dump_file, def_se); | 
 | 	} | 
 |  | 
 |       see_def_extension_not_merged (curr_ref_s, def_se); | 
 |       /* Continue to the next extension.  */ | 
 |       return 1; | 
 |     } | 
 |  | 
 |   /* The merge succeeded!  */ | 
 |  | 
 |   /* Create a simple move instruction to assure the correctness of the code.  */ | 
 |   subreg = gen_lowpart_SUBREG (source_extension_mode, dest_extension_reg); | 
 |   start_sequence (); | 
 |   emit_move_insn (source_extension_reg, subreg); | 
 |   move_insn = get_insns (); | 
 |   end_sequence (); | 
 |  | 
 |   /* Link the merged instruction to the newly created move instruction and | 
 |      to the former created move instructions.  */ | 
 |   PREV_INSN (ref_copy) = NULL_RTX; | 
 |   NEXT_INSN (ref_copy) = move_insn; | 
 |   PREV_INSN (move_insn) = ref_copy; | 
 |   NEXT_INSN (move_insn) = merged_ref_next; | 
 |   if (merged_ref_next != NULL_RTX) | 
 |     PREV_INSN (merged_ref_next) = move_insn; | 
 |   curr_ref_s->merged_insn = ref_copy; | 
 |  | 
 |   if (dump_file) | 
 |     { | 
 |       fprintf (dump_file, "Def merge succeeded!\n"); | 
 |       fprintf (dump_file, "Original instructions:\n"); | 
 |       print_rtl_single (dump_file, ref); | 
 |       print_rtl_single (dump_file, def_se); | 
 |       fprintf (dump_file, "Merged instruction:\n"); | 
 |       print_rtl_single (dump_file, ref_copy); | 
 |       fprintf (dump_file, "Move instruction that was added:\n"); | 
 |       print_rtl_single (dump_file, move_insn); | 
 |     } | 
 |  | 
 |   /* Remove the current def_se from the unmerged_def_se_hash and insert it to | 
 |      the merged_def_se_hash.  */ | 
 |   htab_clear_slot (curr_ref_s->unmerged_def_se_hash, (PTR *)slot); | 
 |   if (!curr_ref_s->merged_def_se_hash) | 
 |     curr_ref_s->merged_def_se_hash = htab_create (10,  | 
 | 						  hash_descriptor_extension,  | 
 | 						  eq_descriptor_extension, | 
 | 						  NULL); | 
 |   rtx_slot = (rtx *) htab_find_slot (curr_ref_s->merged_def_se_hash, | 
 |   				     dest_extension_reg, INSERT); | 
 |   gcc_assert (*rtx_slot == NULL); | 
 |   *rtx_slot = def_se; | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | /* Try to eliminate extensions in this order: | 
 |    a. Try to merge only the def extensions, one by one. | 
 |    b. Try to merge only the use extensions, one by one. | 
 |  | 
 |    TODO: | 
 |    Try to merge any couple of use extensions simultaneously. | 
 |    Try to merge any def extension with one or two uses extensions | 
 |    simultaneously. | 
 |  | 
 |    After all the merges are done, update the register properties for the basic | 
 |    block and eliminate locally redundant use extensions. | 
 |  | 
 |    This is a subroutine of see_merge_and_eliminate_extensions called | 
 |    via splay_tree_foreach. | 
 |    STN is the current node in the see_bb_splay_ar[i] splay tree.  It holds a | 
 |    see_ref_s structure.  */ | 
 |  | 
 | static int | 
 | see_handle_extensions_for_one_ref (splay_tree_node stn, | 
 | 				   void *data ATTRIBUTE_UNUSED) | 
 | { | 
 |   htab_t use_se_hash = ((struct see_ref_s *) (stn->value))->use_se_hash; | 
 |   htab_t unmerged_def_se_hash = | 
 |     ((struct see_ref_s *) (stn->value))->unmerged_def_se_hash; | 
 |   htab_t merged_def_se_hash; | 
 |   rtx ref = ((struct see_ref_s *) (stn->value))->insn; | 
 |  | 
 |   if (dump_file) | 
 |     { | 
 |       fprintf (dump_file, "Handling ref:\n"); | 
 |       print_rtl_single (dump_file, ref); | 
 |     } | 
 |  | 
 |   /* a. Try to eliminate only def extensions, one by one.  */ | 
 |   if (unmerged_def_se_hash) | 
 |     htab_traverse_noresize (unmerged_def_se_hash, see_merge_one_def_extension, | 
 |     			    (PTR) (stn->value)); | 
 |  | 
 |   if (use_se_hash) | 
 |     /* b. Try to eliminate only use extensions, one by one.  */ | 
 |     htab_traverse_noresize (use_se_hash, see_merge_one_use_extension, | 
 | 			    (PTR) (stn->value)); | 
 |  | 
 |   merged_def_se_hash = ((struct see_ref_s *) (stn->value))->merged_def_se_hash; | 
 |  | 
 |   if (dump_file) | 
 |     { | 
 |       fprintf (dump_file, "The hashes of the current reference:\n"); | 
 |       if (unmerged_def_se_hash) | 
 | 	{ | 
 | 	  fprintf (dump_file, "unmerged_def_se_hash:\n"); | 
 | 	  htab_traverse (unmerged_def_se_hash, see_print_one_extension, NULL); | 
 | 	} | 
 |       if (merged_def_se_hash) | 
 | 	{ | 
 | 	  fprintf (dump_file, "merged_def_se_hash:\n"); | 
 | 	  htab_traverse (merged_def_se_hash, see_print_one_extension, NULL); | 
 | 	} | 
 |       if (use_se_hash) | 
 | 	{ | 
 | 	  fprintf (dump_file, "use_se_hash:\n"); | 
 | 	  htab_traverse (use_se_hash, see_print_one_extension, NULL); | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Now that all the merges are done, update the register properties of the | 
 |      basic block and eliminate locally redundant extensions. | 
 |      It is important that we first traverse the use extensions hash and | 
 |      afterwards the def extensions hashes.  */ | 
 |  | 
 |   if (use_se_hash) | 
 |     htab_traverse_noresize (use_se_hash, see_set_prop_unmerged_use, | 
 | 			    (PTR) (stn->value)); | 
 |  | 
 |   if (unmerged_def_se_hash) | 
 |     htab_traverse (unmerged_def_se_hash, see_set_prop_unmerged_def, | 
 | 		   (PTR) (stn->value)); | 
 |  | 
 |   if (merged_def_se_hash) | 
 |     htab_traverse (merged_def_se_hash, see_set_prop_merged_def, | 
 | 		   (PTR) (stn->value)); | 
 |  | 
 |   /* Continue to the next definition.  */ | 
 |   return 0; | 
 | } | 
 |  | 
 |  | 
 | /* Phase 2 top level function. | 
 |    In this phase, we try to merge def extensions and use extensions with their | 
 |    references, and eliminate redundant extensions in the same basic block.   | 
 |    We also gather information for the next phases.  */ | 
 |  | 
 | static void | 
 | see_merge_and_eliminate_extensions (void) | 
 | { | 
 |   int i = 0; | 
 |  | 
 |   if (dump_file) | 
 |     fprintf (dump_file, | 
 |       "* Phase 2: Merge and eliminate locally redundant extensions.  *\n"); | 
 |  | 
 |   /* Traverse over all the splay trees of the basic blocks.  */ | 
 |   for (i = 0; i < last_bb; i++) | 
 |     { | 
 |       if (see_bb_splay_ar[i]) | 
 | 	{ | 
 | 	  if (dump_file) | 
 | 	    fprintf (dump_file, "Handling references for bb %d\n", i); | 
 | 	  /* Traverse over all the references in the basic block in forward | 
 | 	     order.  */ | 
 | 	  splay_tree_foreach (see_bb_splay_ar[i], | 
 | 			      see_handle_extensions_for_one_ref, NULL); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* Phase 1 implementation: Propagate extensions to uses.  */ | 
 |  | 
 | /* Insert REF_INSN into the splay tree of its basic block. | 
 |    SE_INSN is the extension to store in the proper hash according to TYPE. | 
 |  | 
 |    Return true if everything went well. | 
 |    Otherwise, return false (this will cause the optimization to be aborted).  */ | 
 |  | 
 | static bool | 
 | see_store_reference_and_extension (rtx ref_insn, rtx se_insn, | 
 | 				   enum extension_type type) | 
 | { | 
 |   rtx *rtx_slot; | 
 |   int curr_bb_num; | 
 |   splay_tree_node stn = NULL; | 
 |   htab_t se_hash = NULL; | 
 |   struct see_ref_s *ref_s = NULL; | 
 |  | 
 |   /* Check the arguments.  */ | 
 |   gcc_assert (ref_insn && se_insn); | 
 |   if (!see_bb_splay_ar) | 
 |     return false; | 
 |  | 
 |   curr_bb_num = BLOCK_NUM (ref_insn); | 
 |   gcc_assert (curr_bb_num < last_bb && curr_bb_num >= 0); | 
 |  | 
 |   /* Insert the reference to the splay tree of its basic block.  */ | 
 |   if (!see_bb_splay_ar[curr_bb_num]) | 
 |     /* The splay tree for this block doesn't exist yet, create it.  */ | 
 |     see_bb_splay_ar[curr_bb_num] = splay_tree_new (splay_tree_compare_ints, | 
 | 						    NULL, see_free_ref_s); | 
 |   else | 
 |     /* Splay tree already exists, check if the current reference is already | 
 |        in it.  */ | 
 |     { | 
 |       stn = splay_tree_lookup (see_bb_splay_ar[curr_bb_num], | 
 | 			       DF_INSN_LUID (df, ref_insn)); | 
 |       if (stn) | 
 | 	switch (type) | 
 | 	  { | 
 | 	  case EXPLICIT_DEF_EXTENSION: | 
 | 	    se_hash = | 
 | 	      ((struct see_ref_s *) (stn->value))->unmerged_def_se_hash; | 
 | 	    if (!se_hash) | 
 | 	      { | 
 | 		se_hash = htab_create (10,  | 
 | 				       hash_descriptor_extension, | 
 | 				       eq_descriptor_extension,  | 
 | 				       NULL); | 
 | 		((struct see_ref_s *) (stn->value))->unmerged_def_se_hash = | 
 | 		  se_hash; | 
 | 	      } | 
 | 	    break; | 
 | 	  case IMPLICIT_DEF_EXTENSION: | 
 | 	    se_hash = ((struct see_ref_s *) (stn->value))->merged_def_se_hash; | 
 | 	    if (!se_hash) | 
 | 	      { | 
 | 		se_hash = htab_create (10,  | 
 | 				       hash_descriptor_extension, | 
 | 				       eq_descriptor_extension,  | 
 | 				       NULL); | 
 | 		((struct see_ref_s *) (stn->value))->merged_def_se_hash = | 
 | 		  se_hash; | 
 | 	      } | 
 | 	    break; | 
 | 	  case USE_EXTENSION: | 
 | 	    se_hash = ((struct see_ref_s *) (stn->value))->use_se_hash; | 
 | 	    if (!se_hash) | 
 | 	      { | 
 | 		se_hash = htab_create (10,  | 
 | 				       hash_descriptor_extension, | 
 | 				       eq_descriptor_extension,  | 
 | 				       NULL); | 
 | 		((struct see_ref_s *) (stn->value))->use_se_hash = se_hash; | 
 | 	      } | 
 | 	    break; | 
 | 	  default: | 
 | 	    gcc_unreachable (); | 
 | 	  } | 
 |     } | 
 |  | 
 |   /* Initialize a new see_ref_s structure and insert it to the splay | 
 |      tree.  */ | 
 |   if (!stn) | 
 |     { | 
 |       ref_s = xmalloc (sizeof (struct see_ref_s)); | 
 |       ref_s->luid = DF_INSN_LUID (df, ref_insn); | 
 |       ref_s->insn = ref_insn; | 
 |       ref_s->merged_insn = NULL; | 
 |  | 
 |       /* Initialize the hashes.  */ | 
 |       switch (type) | 
 | 	{ | 
 | 	case EXPLICIT_DEF_EXTENSION: | 
 | 	  ref_s->unmerged_def_se_hash = htab_create (10,  | 
 | 						     hash_descriptor_extension,  | 
 | 						     eq_descriptor_extension, | 
 | 						     NULL); | 
 | 	  se_hash = ref_s->unmerged_def_se_hash; | 
 | 	  ref_s->merged_def_se_hash = NULL; | 
 | 	  ref_s->use_se_hash = NULL; | 
 | 	  break; | 
 | 	case IMPLICIT_DEF_EXTENSION: | 
 | 	  ref_s->merged_def_se_hash = htab_create (10,  | 
 | 						   hash_descriptor_extension,  | 
 | 						   eq_descriptor_extension, | 
 | 						   NULL); | 
 | 	  se_hash = ref_s->merged_def_se_hash; | 
 | 	  ref_s->unmerged_def_se_hash = NULL; | 
 | 	  ref_s->use_se_hash = NULL; | 
 | 	  break; | 
 | 	case USE_EXTENSION: | 
 | 	  ref_s->use_se_hash = htab_create (10,  | 
 | 					    hash_descriptor_extension,  | 
 | 					    eq_descriptor_extension, | 
 | 					    NULL); | 
 | 	  se_hash = ref_s->use_se_hash; | 
 | 	  ref_s->unmerged_def_se_hash = NULL; | 
 | 	  ref_s->merged_def_se_hash = NULL; | 
 | 	  break; | 
 | 	default: | 
 | 	  gcc_unreachable (); | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Insert the new extension instruction into the correct se_hash of the | 
 |      current reference.  */ | 
 |   rtx_slot = (rtx *) htab_find_slot (se_hash, se_insn, INSERT); | 
 |   if (*rtx_slot != NULL) | 
 |     { | 
 |       gcc_assert (type == USE_EXTENSION); | 
 |       gcc_assert (rtx_equal_p (PATTERN (*rtx_slot), PATTERN (se_insn))); | 
 |     } | 
 |   else | 
 |     *rtx_slot = se_insn; | 
 |  | 
 |   /* If this is a new reference, insert it into the splay_tree.  */ | 
 |   if (!stn) | 
 |     splay_tree_insert (see_bb_splay_ar[curr_bb_num], | 
 | 		       DF_INSN_LUID (df, ref_insn), (splay_tree_value) ref_s); | 
 |   return true; | 
 | } | 
 |  | 
 |  | 
 | /* Go over all the defs, for each relevant definition (defined below) store its | 
 |    instruction as a reference. | 
 |  | 
 |    A definition is relevant if its root has | 
 |    ((entry_type == SIGN_EXTENDED_DEF) || (entry_type == ZERO_EXTENDED_DEF)) and | 
 |    his source_mode is not narrower then the the roots source_mode. | 
 |  | 
 |    Return the number of relevant defs or negative number if something bad had | 
 |    happened and the optimization should be aborted.  */ | 
 |  | 
 | static int | 
 | see_handle_relevant_defs (void) | 
 | { | 
 |   rtx insn = NULL; | 
 |   rtx se_insn = NULL; | 
 |   rtx reg = NULL; | 
 |   rtx ref_insn = NULL; | 
 |   struct web_entry *root_entry = NULL; | 
 |   unsigned int i; | 
 |   int num_relevant_defs = 0; | 
 |   enum rtx_code extension_code; | 
 |  | 
 |   for (i = 0; i < defs_num; i++) | 
 |     { | 
 |       insn = DF_REF_INSN (DF_DEFS_GET (df, i)); | 
 |       reg = DF_REF_REAL_REG (DF_DEFS_GET (df, i)); | 
 |  | 
 |       if (!insn) | 
 | 	continue; | 
 |  | 
 |       if (!INSN_P (insn)) | 
 | 	continue; | 
 |  | 
 |       root_entry = unionfind_root (&def_entry[i]); | 
 |  | 
 |       if (ENTRY_EI (root_entry)->relevancy != SIGN_EXTENDED_DEF | 
 | 	  && ENTRY_EI (root_entry)->relevancy != ZERO_EXTENDED_DEF) | 
 | 	/* The current web is not relevant.  Continue to the next def.  */ | 
 | 	continue; | 
 |  | 
 |       if (root_entry->reg) | 
 | 	/* It isn't possible to have two different register for the same | 
 | 	   web.  */ | 
 | 	gcc_assert (rtx_equal_p (root_entry->reg, reg)); | 
 |       else | 
 | 	root_entry->reg = reg; | 
 |  | 
 |       /* The current definition is an EXTENDED_DEF or a definition that its | 
 | 	 source_mode is narrower then its web's source_mode. | 
 | 	 This means that we need to generate the implicit extension explicitly | 
 | 	 and store it in the current reference's merged_def_se_hash.  */ | 
 |       if (ENTRY_EI (&def_entry[i])->local_relevancy == EXTENDED_DEF | 
 | 	  || (ENTRY_EI (&def_entry[i])->local_source_mode < | 
 | 	      ENTRY_EI (root_entry)->source_mode)) | 
 | 	{ | 
 | 	  num_relevant_defs++; | 
 |  | 
 | 	  if (ENTRY_EI (root_entry)->relevancy == SIGN_EXTENDED_DEF) | 
 | 	    extension_code = SIGN_EXTEND; | 
 | 	  else | 
 | 	    extension_code = ZERO_EXTEND; | 
 |  | 
 | 	  se_insn = | 
 | 	    see_gen_normalized_extension (reg, extension_code, | 
 | 	    				  ENTRY_EI (root_entry)->source_mode); | 
 |  | 
 | 	  /* This is a dummy extension, mark it as deleted.  */ | 
 | 	  INSN_DELETED_P (se_insn) = 1; | 
 |  | 
 | 	  if (!see_store_reference_and_extension (insn, se_insn, | 
 | 	  					  IMPLICIT_DEF_EXTENSION)) | 
 | 	    /* Something bad happened.  Abort the optimization.  */ | 
 | 	    return -1; | 
 | 	  continue; | 
 | 	} | 
 |  | 
 |       ref_insn = PREV_INSN (insn); | 
 |       gcc_assert (BLOCK_NUM (ref_insn) == BLOCK_NUM (insn)); | 
 |  | 
 |       num_relevant_defs++; | 
 |  | 
 |       if (!see_store_reference_and_extension (ref_insn, insn, | 
 |       					      EXPLICIT_DEF_EXTENSION)) | 
 | 	/* Something bad happened.  Abort the optimization.  */ | 
 | 	return -1; | 
 |     } | 
 |    return num_relevant_defs; | 
 | } | 
 |  | 
 |  | 
 | /* Go over all the uses, for each use in relevant web store its instruction as | 
 |    a reference and generate an extension before it. | 
 |  | 
 |    Return the number of relevant uses or negative number if something bad had | 
 |    happened and the optimization should be aborted.  */ | 
 |  | 
 | static int | 
 | see_handle_relevant_uses (void) | 
 | { | 
 |   rtx insn = NULL; | 
 |   rtx reg = NULL; | 
 |   struct web_entry *root_entry = NULL; | 
 |   rtx se_insn = NULL; | 
 |   unsigned int i; | 
 |   int num_relevant_uses = 0; | 
 |   enum rtx_code extension_code; | 
 |  | 
 |   for (i = 0; i < uses_num; i++) | 
 |     { | 
 |       insn = DF_REF_INSN (DF_USES_GET (df, i)); | 
 |       reg = DF_REF_REAL_REG (DF_USES_GET (df, i)); | 
 |  | 
 |       if (!insn) | 
 | 	continue; | 
 |  | 
 |       if (!INSN_P (insn)) | 
 | 	continue; | 
 |  | 
 |       root_entry = unionfind_root (&use_entry[i]); | 
 |  | 
 |       if (ENTRY_EI (root_entry)->relevancy != SIGN_EXTENDED_DEF | 
 | 	  && ENTRY_EI (root_entry)->relevancy != ZERO_EXTENDED_DEF) | 
 | 	/* The current web is not relevant.  Continue to the next use.  */ | 
 | 	continue; | 
 |  | 
 |       if (root_entry->reg) | 
 | 	/* It isn't possible to have two different register for the same | 
 | 	   web.  */ | 
 | 	gcc_assert (rtx_equal_p (root_entry->reg, reg)); | 
 |       else | 
 | 	root_entry->reg = reg; | 
 |  | 
 |       /* Generate the use extension.  */ | 
 |       if (ENTRY_EI (root_entry)->relevancy == SIGN_EXTENDED_DEF) | 
 | 	extension_code = SIGN_EXTEND; | 
 |       else | 
 | 	extension_code = ZERO_EXTEND; | 
 |  | 
 |       se_insn = | 
 | 	see_gen_normalized_extension (reg, extension_code, | 
 | 				      ENTRY_EI (root_entry)->source_mode); | 
 |       if (!se_insn) | 
 | 	/* This is very bad, abort the transformation.  */ | 
 | 	return -1; | 
 |  | 
 |       num_relevant_uses++; | 
 |  | 
 |       if (!see_store_reference_and_extension (insn, se_insn, | 
 |       					      USE_EXTENSION)) | 
 | 	/* Something bad happened.  Abort the optimization.  */ | 
 | 	return -1; | 
 |     } | 
 |  | 
 |   return num_relevant_uses; | 
 | } | 
 |  | 
 |  | 
 | /* Updates the relevancy of all the uses. | 
 |    The information of the i'th use is stored in use_entry[i]. | 
 |    Currently all the uses are relevant for the optimization except for uses that | 
 |    are in LIBCALL or RETVAL instructions.  */ | 
 |  | 
 | static void | 
 | see_update_uses_relevancy (void) | 
 | { | 
 |   rtx insn = NULL; | 
 |   rtx reg = NULL; | 
 |   struct see_entry_extra_info *curr_entry_extra_info; | 
 |   enum entry_type et; | 
 |   unsigned int i; | 
 |  | 
 |   if (!df || !use_entry) | 
 |     return; | 
 |  | 
 |   for (i = 0; i < uses_num; i++) | 
 |     { | 
 |  | 
 |       insn = DF_REF_INSN (DF_USES_GET (df, i)); | 
 |       reg = DF_REF_REAL_REG (DF_USES_GET (df, i)); | 
 |  | 
 |       et = RELEVANT_USE; | 
 |  | 
 |       if (insn)  | 
 | 	{ | 
 | 	  if (!INSN_P (insn)) | 
 | 	    et = NOT_RELEVANT; | 
 | 	  if (insn && find_reg_note (insn, REG_LIBCALL, NULL_RTX)) | 
 | 	    et = NOT_RELEVANT; | 
 | 	  if (find_reg_note (insn, REG_RETVAL, NULL_RTX)) | 
 | 	    et = NOT_RELEVANT; | 
 | 	} | 
 |       else | 
 | 	et = NOT_RELEVANT; | 
 |  | 
 |       if (dump_file) | 
 | 	{ | 
 | 	  fprintf (dump_file, "u%i insn %i reg %i ",  | 
 |           i, (insn ? INSN_UID (insn) : -1), REGNO (reg)); | 
 | 	  if (et == NOT_RELEVANT) | 
 | 	    fprintf (dump_file, "NOT RELEVANT \n"); | 
 | 	  else | 
 | 	    fprintf (dump_file, "RELEVANT USE \n"); | 
 | 	} | 
 |  | 
 |       curr_entry_extra_info = xmalloc (sizeof (struct see_entry_extra_info)); | 
 |       curr_entry_extra_info->relevancy = et; | 
 |       curr_entry_extra_info->local_relevancy = et; | 
 |       use_entry[i].extra_info = curr_entry_extra_info; | 
 |       use_entry[i].reg = NULL; | 
 |       use_entry[i].pred = NULL; | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* A definition in a candidate for this optimization only if its pattern is | 
 |    recognized as relevant in this function. | 
 |    INSN is the instruction to be recognized. | 
 |  | 
 | -  If this is the pattern of a common sign extension after definition: | 
 |    PREV_INSN (INSN):	def (reg:NARROWmode r) | 
 |    INSN:		set ((reg:WIDEmode r') | 
 |    			     (sign_extend:WIDEmode (reg:NARROWmode r))) | 
 |    return SIGN_EXTENDED_DEF and set SOURCE_MODE to NARROWmode. | 
 |  | 
 | -  If this is the pattern of a common zero extension after definition: | 
 |    PREV_INSN (INSN):	def (reg:NARROWmode r) | 
 |    INSN:		set ((reg:WIDEmode r') | 
 |    			     (zero_extend:WIDEmode (reg:NARROWmode r))) | 
 |    return ZERO_EXTENDED_DEF and set SOURCE_MODE to NARROWmode. | 
 |  | 
 | -  Otherwise, | 
 |  | 
 |    For the pattern: | 
 |    INSN:  set ((reg:WIDEmode r) (sign_extend:WIDEmode (...expr...))) | 
 |    return EXTENDED_DEF and set SOURCE_MODE to the mode of expr. | 
 |  | 
 |    For the pattern: | 
 |    INSN:  set ((reg:WIDEmode r) (zero_extend:WIDEmode (...expr...))) | 
 |    return EXTENDED_DEF and set SOURCE_MODE_UNSIGNED to the mode of expr. | 
 |  | 
 |    For the pattern: | 
 |    INSN:  set ((reg:WIDEmode r) (CONST_INT (...))) | 
 |    return EXTENDED_DEF and set SOURCE_MODE(_UNSIGNED) to the narrowest mode that | 
 |    is implicitly sign(zero) extended to WIDEmode in the INSN. | 
 |  | 
 | -  FIXME: Extensions that are not adjacent to their definition and EXTENDED_DEF | 
 |    that is part of a PARALLEL instruction are not handled. | 
 |    These restriction can be relaxed.  */ | 
 |  | 
 | static enum entry_type | 
 | see_analyze_one_def (rtx insn, enum machine_mode *source_mode, | 
 | 		     enum machine_mode *source_mode_unsigned) | 
 | { | 
 |   enum rtx_code extension_code; | 
 |   rtx rhs = NULL; | 
 |   rtx lhs = NULL; | 
 |   rtx set = NULL; | 
 |   rtx source_register = NULL; | 
 |   rtx prev_insn = NULL; | 
 |   rtx next_insn = NULL; | 
 |   enum machine_mode mode; | 
 |   enum machine_mode next_source_mode; | 
 |   HOST_WIDE_INT val = 0; | 
 |   HOST_WIDE_INT val2 = 0; | 
 |   int i = 0; | 
 |  | 
 |   *source_mode = MAX_MACHINE_MODE; | 
 |   *source_mode_unsigned = MAX_MACHINE_MODE; | 
 |  | 
 |   if (!insn) | 
 |     return NOT_RELEVANT; | 
 |  | 
 |   if (!INSN_P (insn)) | 
 |     return NOT_RELEVANT; | 
 |  | 
 |   extension_code = see_get_extension_data (insn, source_mode); | 
 |   switch (extension_code) | 
 |     { | 
 |     case SIGN_EXTEND: | 
 |     case ZERO_EXTEND: | 
 |       source_register = see_get_extension_reg (insn, 0); | 
 |       /* FIXME: This restriction can be relaxed.  The only thing that is | 
 | 	 important is that the reference would be inside the same basic block | 
 | 	 as the extension.  */ | 
 |       prev_insn = PREV_INSN (insn); | 
 |       if (!prev_insn || !INSN_P (prev_insn)) | 
 | 	return NOT_RELEVANT; | 
 |  | 
 |       if (!reg_set_between_p (source_register, PREV_INSN (prev_insn), insn)) | 
 | 	return NOT_RELEVANT; | 
 |  | 
 |       if (find_reg_note (prev_insn, REG_LIBCALL, NULL_RTX)) | 
 | 	return NOT_RELEVANT; | 
 |  | 
 |       if (find_reg_note (prev_insn, REG_RETVAL, NULL_RTX)) | 
 | 	return NOT_RELEVANT; | 
 |  | 
 |       /* If we can't use copy_rtx on the reference it can't be a reference.  */ | 
 |       if (GET_CODE (PATTERN (prev_insn)) == PARALLEL | 
 | 	   && asm_noperands (PATTERN (prev_insn)) >= 0) | 
 | 	return NOT_RELEVANT; | 
 |  | 
 |       /* Now, check if this extension is a reference itself.  If so, it is not | 
 | 	 relevant.  Handling this extension as relevant would make things much | 
 | 	 more complicated.  */ | 
 |       next_insn = NEXT_INSN (insn); | 
 |       if (next_insn | 
 | 	  && INSN_P (next_insn) | 
 | 	  && (see_get_extension_data (next_insn, &next_source_mode) != | 
 | 	      NOT_RELEVANT)) | 
 | 	{ | 
 | 	  rtx curr_dest_register = see_get_extension_reg (insn, 1); | 
 | 	  rtx next_source_register = see_get_extension_reg (next_insn, 0); | 
 |  | 
 | 	  if (REGNO (curr_dest_register) == REGNO (next_source_register)) | 
 | 	    return NOT_RELEVANT; | 
 | 	} | 
 |  | 
 |       if (extension_code == SIGN_EXTEND) | 
 | 	return SIGN_EXTENDED_DEF; | 
 |       else | 
 | 	return ZERO_EXTENDED_DEF; | 
 |  | 
 |     case UNKNOWN: | 
 |       /* This may still be an EXTENDED_DEF.  */ | 
 |  | 
 |       /* FIXME: This restriction can be relaxed.  It is possible to handle | 
 | 	 PARALLEL insns too.  */ | 
 |       set = single_set (insn); | 
 |       if (!set) | 
 | 	return NOT_RELEVANT; | 
 |       rhs = SET_SRC (set); | 
 |       lhs = SET_DEST (set); | 
 |  | 
 |       /* Don't handle extensions to something other then register or | 
 | 	 subregister.  */ | 
 |       if (!REG_P (lhs) && !SUBREG_REG (lhs)) | 
 | 	return NOT_RELEVANT; | 
 |  | 
 |       switch (GET_CODE (rhs)) | 
 | 	{ | 
 | 	case SIGN_EXTEND: | 
 | 	  *source_mode = GET_MODE (XEXP (rhs, 0)); | 
 | 	  *source_mode_unsigned = MAX_MACHINE_MODE; | 
 | 	  return EXTENDED_DEF; | 
 | 	case ZERO_EXTEND: | 
 | 	  *source_mode = MAX_MACHINE_MODE; | 
 | 	  *source_mode_unsigned = GET_MODE (XEXP (rhs, 0)); | 
 | 	  return EXTENDED_DEF; | 
 | 	case CONST_INT: | 
 |  | 
 | 	  val = INTVAL (rhs); | 
 |  | 
 | 	  /* Find the narrowest mode, val could fit into.  */ | 
 | 	  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT), i = 0; | 
 | 	       GET_MODE_BITSIZE (mode) < BITS_PER_WORD; | 
 | 	       mode = GET_MODE_WIDER_MODE (mode), i++) | 
 | 	    { | 
 | 	      val2 = trunc_int_for_mode (val, mode); | 
 |   	      if (val2 == val && *source_mode == MAX_MACHINE_MODE) | 
 | 		*source_mode = mode; | 
 | 	      if (val == (val & (HOST_WIDE_INT)GET_MODE_MASK (mode)) | 
 | 		  && *source_mode_unsigned == MAX_MACHINE_MODE) | 
 | 		*source_mode_unsigned = mode; | 
 | 	      if (*source_mode != MAX_MACHINE_MODE | 
 | 		  && *source_mode_unsigned !=MAX_MACHINE_MODE) | 
 | 		return EXTENDED_DEF; | 
 | 	    } | 
 | 	  if (*source_mode != MAX_MACHINE_MODE | 
 | 	      || *source_mode_unsigned !=MAX_MACHINE_MODE) | 
 | 	    return EXTENDED_DEF; | 
 | 	  return NOT_RELEVANT; | 
 | 	default: | 
 | 	  return NOT_RELEVANT; | 
 | 	} | 
 |     default: | 
 |       gcc_unreachable (); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* Updates the relevancy and source_mode of all the definitions. | 
 |    The information of the i'th definition is stored in def_entry[i].  */ | 
 |  | 
 | static void | 
 | see_update_defs_relevancy (void) | 
 | { | 
 |   struct see_entry_extra_info *curr_entry_extra_info; | 
 |   unsigned int i; | 
 |   rtx insn = NULL; | 
 |   rtx reg = NULL; | 
 |   enum entry_type et; | 
 |   enum machine_mode source_mode; | 
 |   enum machine_mode source_mode_unsigned; | 
 |  | 
 |   if (!df || !def_entry) | 
 |     return; | 
 |  | 
 |   for (i = 0; i < defs_num; i++) | 
 |     { | 
 |       insn = DF_REF_INSN (DF_DEFS_GET (df, i)); | 
 |       reg = DF_REF_REAL_REG (DF_DEFS_GET (df, i)); | 
 |  | 
 |       et = see_analyze_one_def (insn, &source_mode, &source_mode_unsigned); | 
 |  | 
 |       curr_entry_extra_info = xmalloc (sizeof (struct see_entry_extra_info)); | 
 |       curr_entry_extra_info->relevancy = et; | 
 |       curr_entry_extra_info->local_relevancy = et; | 
 |       if (et != EXTENDED_DEF) | 
 | 	{ | 
 | 	  curr_entry_extra_info->source_mode = source_mode; | 
 | 	  curr_entry_extra_info->local_source_mode = source_mode; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  curr_entry_extra_info->source_mode_signed = source_mode; | 
 | 	  curr_entry_extra_info->source_mode_unsigned = source_mode_unsigned; | 
 | 	} | 
 |       def_entry[i].extra_info = curr_entry_extra_info; | 
 |       def_entry[i].reg = NULL; | 
 |       def_entry[i].pred = NULL; | 
 |  | 
 |       if (dump_file) | 
 | 	{ | 
 | 	  if (et == NOT_RELEVANT) | 
 | 	    { | 
 | 	      fprintf (dump_file, "d%i insn %i reg %i ", | 
 |               i, (insn ? INSN_UID (insn) : -1), REGNO (reg)); | 
 | 	      fprintf (dump_file, "NOT RELEVANT \n"); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      fprintf (dump_file, "d%i insn %i reg %i ", | 
 | 		       i ,INSN_UID (insn), REGNO (reg)); | 
 | 	      fprintf (dump_file, "RELEVANT - "); | 
 | 	      switch (et) | 
 | 		{ | 
 | 		case SIGN_EXTENDED_DEF : | 
 | 		  fprintf (dump_file, "SIGN_EXTENDED_DEF, source_mode = %s\n", | 
 | 			   GET_MODE_NAME (source_mode)); | 
 | 		  break; | 
 | 		case ZERO_EXTENDED_DEF : | 
 | 		  fprintf (dump_file, "ZERO_EXTENDED_DEF, source_mode = %s\n", | 
 | 			   GET_MODE_NAME (source_mode)); | 
 | 		  break; | 
 | 		case EXTENDED_DEF : | 
 | 		  fprintf (dump_file, "EXTENDED_DEF, "); | 
 | 		  if (source_mode != MAX_MACHINE_MODE | 
 | 		      && source_mode_unsigned != MAX_MACHINE_MODE) | 
 | 		    { | 
 | 		      fprintf (dump_file, "positive const, "); | 
 | 		      fprintf (dump_file, "source_mode_signed = %s, ", | 
 | 			       GET_MODE_NAME (source_mode)); | 
 | 		      fprintf (dump_file, "source_mode_unsigned = %s\n", | 
 | 			       GET_MODE_NAME (source_mode_unsigned)); | 
 | 		    } | 
 | 		  else if (source_mode != MAX_MACHINE_MODE) | 
 | 		    fprintf (dump_file, "source_mode_signed = %s\n", | 
 | 			     GET_MODE_NAME (source_mode)); | 
 | 		  else | 
 | 		    fprintf (dump_file, "source_mode_unsigned = %s\n", | 
 | 			     GET_MODE_NAME (source_mode_unsigned)); | 
 | 		  break; | 
 | 		default : | 
 | 		  gcc_unreachable (); | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* Phase 1 top level function. | 
 |    In this phase the relevancy of all the definitions and uses are checked, | 
 |    later the webs are produces and the extensions are generated. | 
 |    These extensions are not emitted yet into the insns stream. | 
 |  | 
 |    returns true if at list one relevant web was found and there were no | 
 |    problems, otherwise return false.  */ | 
 |  | 
 | static bool | 
 | see_propagate_extensions_to_uses (void) | 
 | { | 
 |   unsigned int i = 0; | 
 |   int num_relevant_uses; | 
 |   int num_relevant_defs; | 
 |  | 
 |   if (dump_file) | 
 |     fprintf (dump_file, | 
 |       "* Phase 1: Propagate extensions to uses.  *\n"); | 
 |  | 
 |   /* Update the relevancy of references using the DF object.  */ | 
 |   see_update_defs_relevancy (); | 
 |   see_update_uses_relevancy (); | 
 |  | 
 |   /* Produce the webs and update the extra_info of the root. | 
 |      In general, a web is relevant if all its definitions and uses are relevant | 
 |      and there is at least one definition that was marked as SIGN_EXTENDED_DEF | 
 |      or ZERO_EXTENDED_DEF.  */ | 
 |   for (i = 0; i < uses_num; i++) | 
 |     union_defs (df, DF_USES_GET (df, i), def_entry, use_entry, | 
 | 		see_update_leader_extra_info); | 
 |  | 
 |   /* Generate use extensions for references and insert these | 
 |      references to see_bb_splay_ar data structure.    */ | 
 |   num_relevant_uses = see_handle_relevant_uses (); | 
 |  | 
 |   if (num_relevant_uses < 0) | 
 |     return false; | 
 |  | 
 |   /* Store the def extensions in their references structures and insert these | 
 |      references to see_bb_splay_ar data structure.    */ | 
 |   num_relevant_defs = see_handle_relevant_defs (); | 
 |  | 
 |   if (num_relevant_defs < 0) | 
 |     return false; | 
 |  | 
 |  return num_relevant_uses > 0 || num_relevant_defs > 0; | 
 | } | 
 |  | 
 |  | 
 | /* Main entry point for the sign extension elimination optimization.  */ | 
 |  | 
 | static void | 
 | see_main (void) | 
 | { | 
 |   bool cont = false; | 
 |   int i = 0; | 
 |  | 
 |   /* Initialize global data structures.  */ | 
 |   see_initialize_data_structures (); | 
 |  | 
 |   /* Phase 1: Propagate extensions to uses.  */ | 
 |   cont = see_propagate_extensions_to_uses (); | 
 |  | 
 |   if (cont) | 
 |     { | 
 |       init_recog (); | 
 |  | 
 |       /* Phase 2: Merge and eliminate locally redundant extensions.  */ | 
 |       see_merge_and_eliminate_extensions (); | 
 |  | 
 |       /* Phase 3: Eliminate globally redundant extensions.  */ | 
 |       see_execute_LCM (); | 
 |  | 
 |       /* Phase 4: Commit changes to the insn stream.  */ | 
 |       see_commit_changes (); | 
 |  | 
 |       if (dump_file) | 
 | 	{ | 
 | 	  /* For debug purpose only.  */ | 
 | 	  fprintf (dump_file, "see_pre_extension_hash:\n"); | 
 | 	  htab_traverse (see_pre_extension_hash, see_print_pre_extension_expr, | 
 |       			 NULL); | 
 |  | 
 | 	  for (i = 0; i < last_bb; i++) | 
 | 	    { | 
 |  	      if (see_bb_hash_ar[i]) | 
 | 		/* Traverse over all the references in the basic block in | 
 | 		   forward order.  */ | 
 | 		{ | 
 | 		  fprintf (dump_file, | 
 | 			   "Searching register properties in bb %d\n", i); | 
 | 		  htab_traverse (see_bb_hash_ar[i], | 
 | 		  		 see_print_register_properties, NULL); | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Free global data structures.  */ | 
 |   see_free_data_structures (); | 
 | } | 
 |  | 
 |  | 
 | static bool | 
 | gate_handle_see (void) | 
 | { | 
 |   return optimize > 1 && flag_see; | 
 | } | 
 |  | 
 | static unsigned int | 
 | rest_of_handle_see (void) | 
 | { | 
 |   int no_new_pseudos_bcp = no_new_pseudos; | 
 |  | 
 |   no_new_pseudos = 0; | 
 |   see_main (); | 
 |   no_new_pseudos = no_new_pseudos_bcp; | 
 |    | 
 |   delete_trivially_dead_insns (get_insns (), max_reg_num ()); | 
 |   update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,  | 
 |   				    (PROP_DEATH_NOTES)); | 
 |   cleanup_cfg (CLEANUP_EXPENSIVE); | 
 |   reg_scan (get_insns (), max_reg_num ()); | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | struct tree_opt_pass pass_see = | 
 | { | 
 |   "see",				/* name */ | 
 |   gate_handle_see,			/* gate */ | 
 |   rest_of_handle_see,			/* execute */ | 
 |   NULL,					/* sub */ | 
 |   NULL,					/* next */ | 
 |   0,					/* static_pass_number */ | 
 |   TV_SEE,				/* tv_id */ | 
 |   0,					/* properties_required */ | 
 |   0,					/* properties_provided */ | 
 |   0,					/* properties_destroyed */ | 
 |   0,					/* todo_flags_start */ | 
 |   TODO_dump_func,			/* todo_flags_finish */ | 
 |   'u'					/* letter */ | 
 | }; | 
 |  |