public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PR68432 00/26] Handle size/speed choices for internal functions
@ 2015-11-25 12:22 Richard Sandiford
  2015-11-25 12:23 ` [PR68432 01/22][ARM] Remove operand dependency from "type" attribute Richard Sandiford
                   ` (23 more replies)
  0 siblings, 24 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:22 UTC (permalink / raw)
  To: gcc-patches

This series fixes PR 68432, a regression caused by my internal-functions-
for-optabs series.  Some of the libm optabs in i386.md have a true HAVE_*
condition but conditionally FAIL if we're optimising for size:

  if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
      && !flag_trapping_math)
    {
      if (TARGET_ROUND)
	emit_insn (gen_sse4_1_round<mode>2
		   (operands[0], operands[1], GEN_INT (ROUND_MXCSR)));
      else if (optimize_insn_for_size_p ())
        FAIL;
      else
	ix86_expand_rint (operands[0], operands[1]);
    }

This is going to cause problems if we want to make more decisions
related to optabs at the gimple level.

We've already had the same problem in rtl, where some patterns used
to check optimize_insn_for_size_p in their C condition, and would then
fail to match if an instruction were moved from a hot block to a cold
block.  Now rtl has two attributes, preferred_for_size and
preferred_for_speed, that say whether a particular alternative of a
particular instruction should be used when optimising for size or speed
respectively.  We try to honour a "false" value as much as possible,
but it's not an absolute guarantee.

The point of this series is to extend preferred_for_size and
preferred_for_speed to define_expands, so that the attributes
can be tested for optabs too.

enabled, preferred_for_size and preferred_for_speed are supposed
to be an inavariant property of a given (code, alternative) pair.
They're not supposed to depend on a particular insn or its operands.
However, the attribute functions still take an rtx_insn * as argument,
so mistakes are only caught at runtime if we see a specific instruction
for which the attributes conflict with the cached ones
(recog.c:check_bool_attrs).

Extending the attributes to define_expands means that we finally
need to "fix" that and make the attributes take a (code, alternative)
pair instead.  Most ports were already structured to allow that.
The two exceptions are ARM and NDS32.

The problem for NDS32 is that "enabled" depends on "length", which
needs access to an instruction in order to calculate branch lengths.
This isn't a problem in practice because all instructions with
operand-dependent lengths force "enabled" to 1.  However,
it's easier to enforce the restriction at compile time if we
have an "is_16bit" attribute, to go along with the TARGET_16_BIT
condition that controls whether 16-bit instructions can be used.

The problem for ARM is that "enabled" depends on "type" and
"use_literal_pool", both of which use match_operand tests in some cases.
I think the "type" match_operands were actually OK for "enabled" in
practice, but I think the "use_literal_pool" ones are a genuine bug.
They are used when we have one alternative that accepts both memory and
immediate operands.  The alternative is supposed to be disabled for
immediate operands when arm_disable_literal_pool is true, but not
disabled for memory operands.  However, the "enabled" cache only cares
about the alternative number, so we can end up disabling memory operands
if we cached based on an immediate operand, or allow immediate operands
if we cached based on a memory operand.  The series fixes that by
splitting alternatives where necessary.

Due to the define_subst patches, it's already syntactically possible to
attach attributes to define_expands, but genattrtab.c currently ignores
them.  The series restricts these attributes to the new "code,alternative"
style and then handles them in the same way as define_insn attributes.

I realise this is rather invasive for stage 3, but I think it's
worth fixing the bug "properly" rather than papering over it.
The ARM "use_literal_pool" bug described above shows how easy
it is for the enabled attribute to go wrong in subtle ways.

The series is split into five parts:

  (1) Make the ARM and NDS32 changes described above
  (2) Add support for "code,alternative" attributes
  (3) Make all ports use them for enabled, preferred_for_size and
      preferred_for_speed
  (4) Use preferred_for_size and preferred_for_speed to decide whether
      to use internal functions
  (5) Convert the internal-function-related i386 patterns to use
      preferred_for_size instead of FAILing.

(3) is a purely mechanical change.  I think it counts as obvious if the
other parts are OK.

Tested by building GCC before and after the series on:

    aarch64-linux-gnueabi alpha-linux-gnu arc-elf arm-linux-gnueabi
    arm-linux-gnueabihf avr-rtems bfin-elf c6x-elf cr16-elf cris-elf
    epiphany-elf fr30-elf frv-linux-gnu ft32-elf h8300-elf
    ia64-linux-gnu iq2000-elf lm32-elf m32c-elf m32r-elf
    m68k-linux-gnu mcore-elf mep-elf microblaze-elf mips-linux-gnu
    mmix mn10300-elf moxie-elf msp430-elf nds32le-elf
    hppa64-hp-hpux11.23 nios2-linux-gnu nvptx-none pdp11
    powerpc-linux-gnu powerpc-eabispe rl78-elf rx-elf s390-linux-gnu
    sh-linux-gnu sparc-linux-gnu spu-elf tilegx-elf tilepro-elf
    xstormy16-elf v850-elf vax-netbsdelf visium-elf xtensa-elf
    x86_64-darwin

and comparing the assembly output for gcc.dg, g++.dg and gcc.c-torture
at -O2.  There were no differences besides the usual timestamps.

Also tested on x86_64-linux-gnu and arm-linux-gnueabihf.  I will test
on powerpc64-linux-gnu as well before committing.  OK to install?

Thanks,
Richard

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 01/22][ARM] Remove operand dependency from "type" attribute
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
@ 2015-11-25 12:23 ` Richard Sandiford
  2015-11-25 13:55   ` Bernd Schmidt
  2015-11-25 12:24 ` [PR68432 02/22][ARM] Remove operand dependency from use_literal_pool Richard Sandiford
                   ` (22 subsequent siblings)
  23 siblings, 1 reply; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:23 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, richard.earnshaw, ramana.radhakrishnan, kyrylo.tkachov

The "enabled" attribute is supposed to be an invariant property of an
alternative and shouldn't depend on having access to a particular insn.
Although I think ARM honours that, it's not really enforceable at
compile time because "enabled" depends on "type", which in turn depends
on match_operand.  This patch removes the type->match_operand dependency
by splitting alternatives where necessary.  This is needed for the fix to
PR 68432.

Tested as described in the covering note.

gcc/
	* config/arm/arm.md (*arm_addsi3): Split register+immediate
	alternatives and make "type" a constant property of the
	alternative number.
	(*addsi3_carryin_shift_<optab>): Likewise.
	(*subsi3_carryin_shift): Likewise.
	(*rsbsi3_carryin_shift): Likewise.
	(andsi_not_shiftsi_si): Likewise.
	(andsi_not_shiftsi_si_scc_no_reuse): Likewise.
	(andsi_not_shiftsi_si_scc): Likewise.
	(*movhi_insn_arch4): Likewise.
	(*arm_cmpsi_negshiftsi_si): Likewise.
	(*movsicc_insn): Likewise.
	(*cond_move): Likewise.
	(*if_plus_move): Likewise.
	(*if_move_plus): Likewise.
	(*if_arith_move): Likewise.
	(*if_move_arith): Likewise.
	(*if_shift_move): Likewise.
	(*if_move_shift): Likewise.
	(*if_shift_shift): Likewise.
	* config/arm/thumb2.md (*thumb2_movsicc_insn): Likewise.
	(*thumb2_addsi_short): Likewise.
	(thumb2_addsi3_compare0): Likewise.
	(*thumb2_addsi3_compare0_scratch): Likewise.
	(*thumb2_shiftsi3_short): Make "type" a constant property of the
	alternative number.
	* config/arm/neon.md (neon_vc<cmp_op><mode>_insn): Likewise.

diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 5782b35..40666b4 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -574,9 +574,9 @@
 ;;  (plus (reg rN) (reg sp)) into (reg rN).  In this case reload will
 ;; put the duplicated register first, and not try the commutative version.
 (define_insn_and_split "*arm_addsi3"
-  [(set (match_operand:SI          0 "s_register_operand" "=rk,l,l ,l ,r ,k ,r,r ,k ,r ,k,k,r ,k ,r")
-        (plus:SI (match_operand:SI 1 "s_register_operand" "%0 ,l,0 ,l ,rk,k ,r,rk,k ,rk,k,r,rk,k ,rk")
-                 (match_operand:SI 2 "reg_or_int_operand" "rk ,l,Py,Pd,rI,rI,k,Pj,Pj,L ,L,L,PJ,PJ,?n")))]
+  [(set (match_operand:SI          0 "s_register_operand" "=rk,l,l ,l ,r ,r ,k,k,r,r ,k ,r ,k,k,r ,k ,r")
+        (plus:SI (match_operand:SI 1 "s_register_operand" "%0 ,l,0 ,l ,rk,rk,k,k,r,rk,k ,rk,k,r,rk,k ,rk")
+                 (match_operand:SI 2 "reg_or_int_operand" "rk ,l,Py,Pd,r, I, r,I,k,Pj,Pj,L ,L,L,PJ,PJ,?n")))]
   "TARGET_32BIT"
   "@
    add%?\\t%0, %0, %2
@@ -585,6 +585,8 @@
    add%?\\t%0, %1, %2
    add%?\\t%0, %1, %2
    add%?\\t%0, %1, %2
+   add%?\\t%0, %1, %2
+   add%?\\t%0, %1, %2
    add%?\\t%0, %2, %1
    addw%?\\t%0, %1, %2
    addw%?\\t%0, %1, %2
@@ -605,13 +607,11 @@
 		      operands[1], 0);
   DONE;
   "
-  [(set_attr "length" "2,4,4,4,4,4,4,4,4,4,4,4,4,4,16")
+  [(set_attr "length" "2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,16")
    (set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "yes,yes,yes,yes,no,no,no,no,no,no,no,no,no,no,no")
-   (set_attr "arch" "t2,t2,t2,t2,*,*,*,t2,t2,*,*,a,t2,t2,*")
-   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
-		      (const_string "alu_imm")
-		      (const_string "alu_sreg")))
+   (set_attr "predicable_short_it" "yes,yes,yes,yes,no,no,no,no,no,no,no,no,no,no,no,no,no")
+   (set_attr "arch" "t2,t2,t2,t2,*,*,*,*,*,t2,t2,*,*,a,t2,t2,*")
+   (set_attr "type" "alu_sreg,alu_sreg,alu_imm,alu_imm,alu_sreg,alu_imm,alu_sreg,alu_imm,alu_sreg,alu_imm,alu_imm,alu_imm,alu_imm,alu_imm,alu_imm,alu_imm,alu_imm")
  ]
 )
 
@@ -835,21 +835,19 @@
 )
 
 (define_insn "*addsi3_carryin_shift_<optab>"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
 	(plus:SI (plus:SI
 		  (match_operator:SI 2 "shift_operator"
-		    [(match_operand:SI 3 "s_register_operand" "r")
-		     (match_operand:SI 4 "reg_or_int_operand" "rM")])
-		  (match_operand:SI 1 "s_register_operand" "r"))
+		    [(match_operand:SI 3 "s_register_operand" "r,r")
+		     (match_operand:SI 4 "reg_or_int_operand" "r,M")])
+		  (match_operand:SI 1 "s_register_operand" "r,r"))
 		 (LTUGEU:SI (reg:<cnb> CC_REGNUM) (const_int 0))))]
   "TARGET_32BIT"
   "adc%?\\t%0, %1, %3%S2"
   [(set_attr "conds" "use")
    (set_attr "predicable" "yes")
    (set_attr "predicable_short_it" "no")
-   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
-		      (const_string "alu_shift_imm")
-		      (const_string "alu_shift_reg")))]
+   (set_attr "type" "alu_shift_reg,alu_shift_imm")]
 )
 
 (define_insn "*addsi3_carryin_clobercc_<optab>"
@@ -920,37 +918,33 @@
 )
 
 (define_insn "*subsi3_carryin_shift"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
 	(minus:SI (minus:SI
-		  (match_operand:SI 1 "s_register_operand" "r")
+		  (match_operand:SI 1 "s_register_operand" "r,r")
                   (match_operator:SI 2 "shift_operator"
-                   [(match_operand:SI 3 "s_register_operand" "r")
-                    (match_operand:SI 4 "reg_or_int_operand" "rM")]))
+                   [(match_operand:SI 3 "s_register_operand" "r,r")
+                    (match_operand:SI 4 "reg_or_int_operand" "r,M")]))
                  (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
   "TARGET_32BIT"
   "sbc%?\\t%0, %1, %3%S2"
   [(set_attr "conds" "use")
    (set_attr "predicable" "yes")
-   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
-		      (const_string "alu_shift_imm")
-                     (const_string "alu_shift_reg")))]
+   (set_attr "type" "alu_shift_reg,alu_shift_imm")]
 )
 
 (define_insn "*rsbsi3_carryin_shift"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
 	(minus:SI (minus:SI
                   (match_operator:SI 2 "shift_operator"
-                   [(match_operand:SI 3 "s_register_operand" "r")
-                    (match_operand:SI 4 "reg_or_int_operand" "rM")])
-		   (match_operand:SI 1 "s_register_operand" "r"))
+                   [(match_operand:SI 3 "s_register_operand" "r,r")
+                    (match_operand:SI 4 "reg_or_int_operand" "r,M")])
+		   (match_operand:SI 1 "s_register_operand" "r,r"))
                  (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
   "TARGET_ARM"
   "rsc%?\\t%0, %1, %3%S2"
   [(set_attr "conds" "use")
    (set_attr "predicable" "yes")
-   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
-		      (const_string "alu_shift_imm")
-		      (const_string "alu_shift_reg")))]
+   (set_attr "type" "alu_shift_reg,alu_shift_imm")]
 )
 
 ; transform ((x << y) - 1) to ~(~(x-1) << y)  Where X is a constant.
@@ -2772,18 +2766,16 @@
 )
 
 (define_insn "andsi_not_shiftsi_si"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
 	(and:SI (not:SI (match_operator:SI 4 "shift_operator"
-			 [(match_operand:SI 2 "s_register_operand" "r")
-			  (match_operand:SI 3 "arm_rhs_operand" "rM")]))
-		(match_operand:SI 1 "s_register_operand" "r")))]
+			 [(match_operand:SI 2 "s_register_operand" "r,r")
+			  (match_operand:SI 3 "arm_rhs_operand" "r,M")]))
+		(match_operand:SI 1 "s_register_operand" "r,r")))]
   "TARGET_ARM"
   "bic%?\\t%0, %1, %2%S4"
   [(set_attr "predicable" "yes")
    (set_attr "shift" "2")
-   (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
-		      (const_string "logic_shift_imm")
-		      (const_string "logic_shift_reg")))]
+   (set_attr "type" "logic_shift_reg,logic_shift_imm")]
 )
 
 ;; Shifted bics pattern used to set up CC status register and not reusing
@@ -2793,20 +2785,18 @@
   [(set (reg:CC_NOOV CC_REGNUM)
 	(compare:CC_NOOV
 		(and:SI (not:SI (match_operator:SI 0 "shift_operator"
-			[(match_operand:SI 1 "s_register_operand" "r")
-			 (match_operand:SI 2 "arm_rhs_operand" "rM")]))
-			(match_operand:SI 3 "s_register_operand" "r"))
+			[(match_operand:SI 1 "s_register_operand" "r,r")
+			 (match_operand:SI 2 "arm_rhs_operand" "r,M")]))
+			(match_operand:SI 3 "s_register_operand" "r,r"))
 		(const_int 0)))
-   (clobber (match_scratch:SI 4 "=r"))]
+   (clobber (match_scratch:SI 4 "=r,r"))]
   "TARGET_ARM || (TARGET_THUMB2 && CONST_INT_P (operands[2]))"
   "bics%?\\t%4, %3, %1%S0"
   [(set_attr "predicable" "yes")
    (set_attr "predicable_short_it" "no")
    (set_attr "conds" "set")
    (set_attr "shift" "1")
-   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
-		      (const_string "logic_shift_imm")
-		      (const_string "logic_shift_reg")))]
+   (set_attr "type" "logic_shift_reg,logic_shift_imm")]
 )
 
 ;; Same as andsi_not_shiftsi_si_scc_no_reuse, but the bics result is also
@@ -2815,11 +2805,11 @@
   [(parallel [(set (reg:CC_NOOV CC_REGNUM)
 	(compare:CC_NOOV
 		(and:SI (not:SI (match_operator:SI 0 "shift_operator"
-			[(match_operand:SI 1 "s_register_operand" "r")
-			 (match_operand:SI 2 "arm_rhs_operand" "rM")]))
-			(match_operand:SI 3 "s_register_operand" "r"))
+			[(match_operand:SI 1 "s_register_operand" "r,r")
+			 (match_operand:SI 2 "arm_rhs_operand" "r,M")]))
+			(match_operand:SI 3 "s_register_operand" "r,r"))
 		(const_int 0)))
-	(set (match_operand:SI 4 "s_register_operand" "=r")
+	(set (match_operand:SI 4 "s_register_operand" "=r,r")
 	     (and:SI (not:SI (match_op_dup 0
 		     [(match_dup 1)
 		      (match_dup 2)]))
@@ -2830,9 +2820,7 @@
    (set_attr "predicable_short_it" "no")
    (set_attr "conds" "set")
    (set_attr "shift" "1")
-   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
-		      (const_string "logic_shift_imm")
-		      (const_string "logic_shift_reg")))]
+   (set_attr "type" "logic_shift_reg,logic_shift_imm")]
 )
 
 (define_insn "*andsi_notsi_si_compare0"
@@ -6343,30 +6331,24 @@
 
 ;; Pattern to recognize insn generated default case above
 (define_insn "*movhi_insn_arch4"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m,r")
-	(match_operand:HI 1 "general_operand"      "rIk,K,n,r,mi"))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,m,r")
+	(match_operand:HI 1 "general_operand"      "rk,I,K,n,r,mi"))]
   "TARGET_ARM
    && arm_arch4
    && (register_operand (operands[0], HImode)
        || register_operand (operands[1], HImode))"
   "@
    mov%?\\t%0, %1\\t%@ movhi
+   mov%?\\t%0, %1\\t%@ movhi
    mvn%?\\t%0, #%B1\\t%@ movhi
    movw%?\\t%0, %L1\\t%@ movhi
    strh%?\\t%1, %0\\t%@ movhi
    ldrh%?\\t%0, %1\\t%@ movhi"
   [(set_attr "predicable" "yes")
-   (set_attr "pool_range" "*,*,*,*,256")
-   (set_attr "neg_pool_range" "*,*,*,*,244")
-   (set_attr "arch" "*,*,v6t2,*,*")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 1 "const_int_operand" "")
-                                        (const_string "mov_imm" )
-                                        (const_string "mov_reg"))
-                          (const_string "mvn_imm")
-                          (const_string "mov_imm")
-                          (const_string "store1")
-                          (const_string "load1")])]
+   (set_attr "pool_range" "*,*,*,*,*,256")
+   (set_attr "neg_pool_range" "*,*,*,*,*,244")
+   (set_attr "arch" "*,*,*,v6t2,*,*")
+   (set_attr "type" "mov_reg,mov_imm,mvn_imm,mov_imm,store1,load1")]
 )
 
 (define_insn "*movhi_bytes"
@@ -6964,15 +6946,13 @@
   [(set (reg:CC_Z CC_REGNUM)
 	(compare:CC_Z
 	 (neg:SI (match_operator:SI 1 "shift_operator"
-		    [(match_operand:SI 2 "s_register_operand" "r")
-		     (match_operand:SI 3 "reg_or_int_operand" "rM")]))
-	 (match_operand:SI 0 "s_register_operand" "r")))]
+		    [(match_operand:SI 2 "s_register_operand" "r,r")
+		     (match_operand:SI 3 "reg_or_int_operand" "r,M")]))
+	 (match_operand:SI 0 "s_register_operand" "r,r")))]
   "TARGET_ARM"
   "cmn%?\\t%0, %2%S1"
   [(set_attr "conds" "set")
-   (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
-				    (const_string "alus_shift_imm")
-				    (const_string "alus_shift_reg")))
+   (set_attr "type" "alus_shift_reg,alus_shift_imm")
    (set_attr "predicable" "yes")]
 )
 
@@ -7489,17 +7469,19 @@
 )
 
 (define_insn_and_split "*movsicc_insn"
-  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r,r,r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r,r,r,r,r")
 	(if_then_else:SI
 	 (match_operator 3 "arm_comparison_operator"
 	  [(match_operand 4 "cc_register" "") (const_int 0)])
-	 (match_operand:SI 1 "arm_not_operand" "0,0,rI,K,rI,rI,K,K")
-	 (match_operand:SI 2 "arm_not_operand" "rI,K,0,0,rI,K,rI,K")))]
+	 (match_operand:SI 1 "arm_not_operand" "0,0,0,r,I,K,rI,rI,K,K")
+	 (match_operand:SI 2 "arm_not_operand" "r,I,K,0,0,0,rI,K,rI,K")))]
   "TARGET_ARM"
   "@
    mov%D3\\t%0, %2
+   mov%D3\\t%0, %2
    mvn%D3\\t%0, #%B2
    mov%d3\\t%0, %1
+   mov%d3\\t%0, %1
    mvn%d3\\t%0, #%B1
    #
    #
@@ -7536,21 +7518,9 @@
                                   gen_rtx_SET (operands[0], operands[2])));
     DONE;
   }
-  [(set_attr "length" "4,4,4,4,8,8,8,8")
+  [(set_attr "length" "4,4,4,4,4,4,8,8,8,8")
    (set_attr "conds" "use")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 2 "const_int_operand" "")
-                                        (const_string "mov_imm")
-                                        (const_string "mov_reg"))
-                          (const_string "mvn_imm")
-                          (if_then_else (match_operand 1 "const_int_operand" "")
-                                        (const_string "mov_imm")
-                                        (const_string "mov_reg"))
-                          (const_string "mvn_imm")
-                          (const_string "multiple")
-                          (const_string "multiple")
-                          (const_string "multiple")
-                          (const_string "multiple")])]
+   (set_attr "type" "mov_reg,mov_imm,mvn_imm,mov_reg,mov_imm,mvn_imm,multiple,multiple,multiple,multiple")]
 )
 
 (define_insn "*movsfcc_soft_insn"
@@ -8713,39 +8683,32 @@
   ")
 
 (define_insn "*cond_move"
-  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r")
 	(if_then_else:SI (match_operator 3 "equality_operator"
 			  [(match_operator 4 "arm_comparison_operator"
 			    [(match_operand 5 "cc_register" "") (const_int 0)])
 			   (const_int 0)])
-			 (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI")
-			 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))]
+			 (match_operand:SI 1 "arm_rhs_operand" "0,0,r,I,?rI")
+			 (match_operand:SI 2 "arm_rhs_operand" "r,I,0,0,rI")))]
   "TARGET_ARM"
   "*
     if (GET_CODE (operands[3]) == NE)
       {
-        if (which_alternative != 1)
+        if (which_alternative != 2 && which_alternative != 3)
 	  output_asm_insn (\"mov%D4\\t%0, %2\", operands);
-        if (which_alternative != 0)
+        if (which_alternative != 0 && which_alternative != 1)
 	  output_asm_insn (\"mov%d4\\t%0, %1\", operands);
         return \"\";
       }
-    if (which_alternative != 0)
+    if (which_alternative != 0 && which_alternative != 1)
       output_asm_insn (\"mov%D4\\t%0, %1\", operands);
-    if (which_alternative != 1)
+    if (which_alternative != 2 && which_alternative != 3)
       output_asm_insn (\"mov%d4\\t%0, %2\", operands);
     return \"\";
   "
   [(set_attr "conds" "use")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 2 "const_int_operand" "")
-                                        (const_string "mov_imm")
-                                        (const_string "mov_reg"))
-                          (if_then_else (match_operand 1 "const_int_operand" "")
-                                        (const_string "mov_imm")
-                                        (const_string "mov_reg"))
-                          (const_string "multiple")])
-   (set_attr "length" "4,4,8")]
+   (set_attr "type" "mov_reg,mov_imm,mov_reg,mov_imm,multiple")
+   (set_attr "length" "4,4,4,4,8")]
 )
 
 (define_insn "*cond_arith"
@@ -9515,29 +9478,24 @@
 )
 
 (define_insn "*if_plus_move"
-  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r")
 	(if_then_else:SI
 	 (match_operator 4 "arm_comparison_operator"
 	  [(match_operand 5 "cc_register" "") (const_int 0)])
 	 (plus:SI
-	  (match_operand:SI 2 "s_register_operand" "r,r,r,r")
-	  (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L"))
-	 (match_operand:SI 1 "arm_rhs_operand" "0,0,?rI,?rI")))]
+	  (match_operand:SI 2 "s_register_operand" "r,r,r,r,r")
+	  (match_operand:SI 3 "arm_add_operand" "r,I,L,rI,L"))
+	 (match_operand:SI 1 "arm_rhs_operand" "0,0,0,?rI,?rI")))]
   "TARGET_ARM"
   "@
    add%d4\\t%0, %2, %3
+   add%d4\\t%0, %2, %3
    sub%d4\\t%0, %2, #%n3
    add%d4\\t%0, %2, %3\;mov%D4\\t%0, %1
    sub%d4\\t%0, %2, #%n3\;mov%D4\\t%0, %1"
   [(set_attr "conds" "use")
-   (set_attr "length" "4,4,8,8")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 3 "const_int_operand" "")
-                                        (const_string "alu_imm" )
-                                        (const_string "alu_sreg"))
-                          (const_string "alu_imm")
-                          (const_string "multiple")
-                          (const_string "multiple")])]
+   (set_attr "length" "4,4,4,8,8")
+   (set_attr "type" "alu_sreg,alu_imm,alu_imm,multiple,multiple")]
 )
 
 (define_insn "*ifcompare_move_plus"
@@ -9558,29 +9516,24 @@
 )
 
 (define_insn "*if_move_plus"
-  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r")
 	(if_then_else:SI
 	 (match_operator 4 "arm_comparison_operator"
 	  [(match_operand 5 "cc_register" "") (const_int 0)])
-	 (match_operand:SI 1 "arm_rhs_operand" "0,0,?rI,?rI")
+	 (match_operand:SI 1 "arm_rhs_operand" "0,0,0,?rI,?rI")
 	 (plus:SI
-	  (match_operand:SI 2 "s_register_operand" "r,r,r,r")
-	  (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L"))))]
+	  (match_operand:SI 2 "s_register_operand" "r,r,r,r,r")
+	  (match_operand:SI 3 "arm_add_operand" "r,I,L,rI,L"))))]
   "TARGET_ARM"
   "@
    add%D4\\t%0, %2, %3
+   add%D4\\t%0, %2, %3
    sub%D4\\t%0, %2, #%n3
    add%D4\\t%0, %2, %3\;mov%d4\\t%0, %1
    sub%D4\\t%0, %2, #%n3\;mov%d4\\t%0, %1"
   [(set_attr "conds" "use")
-   (set_attr "length" "4,4,8,8")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 3 "const_int_operand" "")
-                                        (const_string "alu_imm" )
-                                        (const_string "alu_sreg"))
-                          (const_string "alu_imm")
-                          (const_string "multiple")
-                          (const_string "multiple")])]
+   (set_attr "length" "4,4,4,8,8")
+   (set_attr "type" "alu_sreg,alu_imm,alu_imm,multiple,multiple")]
 )
 
 (define_insn "*ifcompare_arith_arith"
@@ -9662,24 +9615,21 @@
 )
 
 (define_insn "*if_arith_move"
-  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
 	(if_then_else:SI (match_operator 4 "arm_comparison_operator"
 			  [(match_operand 6 "cc_register" "") (const_int 0)])
 			 (match_operator:SI 5 "shiftable_operator"
-			  [(match_operand:SI 2 "s_register_operand" "r,r")
-			   (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
-			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")))]
+			  [(match_operand:SI 2 "s_register_operand" "r,r,r")
+			   (match_operand:SI 3 "arm_rhs_operand" "r,I,rI")])
+			 (match_operand:SI 1 "arm_rhs_operand" "0,0,?rI")))]
   "TARGET_ARM"
   "@
    %I5%d4\\t%0, %2, %3
+   %I5%d4\\t%0, %2, %3
    %I5%d4\\t%0, %2, %3\;mov%D4\\t%0, %1"
   [(set_attr "conds" "use")
-   (set_attr "length" "4,8")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 3 "const_int_operand" "")
-                                        (const_string "alu_shift_imm" )
-                                        (const_string "alu_shift_reg"))
-                          (const_string "multiple")])]
+   (set_attr "length" "4,4,8")
+   (set_attr "type" "alu_shift_reg,alu_shift_imm,multiple")]
 )
 
 (define_insn "*ifcompare_move_arith"
@@ -9726,25 +9676,22 @@
 )
 
 (define_insn "*if_move_arith"
-  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
 	(if_then_else:SI
 	 (match_operator 4 "arm_comparison_operator"
 	  [(match_operand 6 "cc_register" "") (const_int 0)])
-	 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
+	 (match_operand:SI 1 "arm_rhs_operand" "0,0,?rI")
 	 (match_operator:SI 5 "shiftable_operator"
-	  [(match_operand:SI 2 "s_register_operand" "r,r")
-	   (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))]
+	  [(match_operand:SI 2 "s_register_operand" "r,r,r")
+	   (match_operand:SI 3 "arm_rhs_operand" "r,I,rI")])))]
   "TARGET_ARM"
   "@
    %I5%D4\\t%0, %2, %3
+   %I5%D4\\t%0, %2, %3
    %I5%D4\\t%0, %2, %3\;mov%d4\\t%0, %1"
   [(set_attr "conds" "use")
-   (set_attr "length" "4,8")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 3 "const_int_operand" "")
-                                        (const_string "alu_shift_imm" )
-                                        (const_string "alu_shift_reg"))
-                          (const_string "multiple")])]
+   (set_attr "length" "4,4,8")
+   (set_attr "type" "alu_shift_reg,alu_shift_imm,multiple")]
 )
 
 (define_insn "*ifcompare_move_not"
@@ -9835,28 +9782,24 @@
 )
 
 (define_insn "*if_shift_move"
-  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r")
 	(if_then_else:SI
 	 (match_operator 5 "arm_comparison_operator"
 	  [(match_operand 6 "cc_register" "") (const_int 0)])
 	 (match_operator:SI 4 "shift_operator"
-	  [(match_operand:SI 2 "s_register_operand" "r,r,r")
-	   (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])
-	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
+	  [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
+	   (match_operand:SI 3 "arm_rhs_operand" "r,M,rM,rM")])
+	 (match_operand:SI 1 "arm_not_operand" "0,0,?rI,K")))]
   "TARGET_ARM"
   "@
    mov%d5\\t%0, %2%S4
+   mov%d5\\t%0, %2%S4
    mov%D5\\t%0, %1\;mov%d5\\t%0, %2%S4
    mvn%D5\\t%0, #%B1\;mov%d5\\t%0, %2%S4"
   [(set_attr "conds" "use")
    (set_attr "shift" "2")
-   (set_attr "length" "4,8,8")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 3 "const_int_operand" "")
-                                        (const_string "mov_shift" )
-                                        (const_string "mov_shift_reg"))
-                          (const_string "multiple")
-                          (const_string "multiple")])]
+   (set_attr "length" "4,4,8,8")
+   (set_attr "type" "mov_shift_reg,mov_shift,multiple,multiple")]
 )
 
 (define_insn "*ifcompare_move_shift"
@@ -9878,28 +9821,24 @@
 )
 
 (define_insn "*if_move_shift"
-  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r")
 	(if_then_else:SI
 	 (match_operator 5 "arm_comparison_operator"
 	  [(match_operand 6 "cc_register" "") (const_int 0)])
-	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
+	 (match_operand:SI 1 "arm_not_operand" "0,0,?rI,K")
 	 (match_operator:SI 4 "shift_operator"
-	  [(match_operand:SI 2 "s_register_operand" "r,r,r")
-	   (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])))]
+	  [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
+	   (match_operand:SI 3 "arm_rhs_operand" "r,M,rM,rM")])))]
   "TARGET_ARM"
   "@
    mov%D5\\t%0, %2%S4
+   mov%D5\\t%0, %2%S4
    mov%d5\\t%0, %1\;mov%D5\\t%0, %2%S4
    mvn%d5\\t%0, #%B1\;mov%D5\\t%0, %2%S4"
   [(set_attr "conds" "use")
    (set_attr "shift" "2")
-   (set_attr "length" "4,8,8")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 3 "const_int_operand" "")
-                                        (const_string "mov_shift" )
-                                        (const_string "mov_shift_reg"))
-                          (const_string "multiple")
-                          (const_string "multiple")])]
+   (set_attr "length" "4,4,8,8")
+   (set_attr "type" "mov_shift_reg,mov_shift,multiple,multiple")]
 )
 
 (define_insn "*ifcompare_shift_shift"
@@ -9923,26 +9862,22 @@
 )
 
 (define_insn "*if_shift_shift"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r")
 	(if_then_else:SI
 	 (match_operator 5 "arm_comparison_operator"
 	  [(match_operand 8 "cc_register" "") (const_int 0)])
 	 (match_operator:SI 6 "shift_operator"
-	  [(match_operand:SI 1 "s_register_operand" "r")
-	   (match_operand:SI 2 "arm_rhs_operand" "rM")])
+	  [(match_operand:SI 1 "s_register_operand" "r,r,r,r")
+	   (match_operand:SI 2 "arm_rhs_operand" "r,r,M,M")])
 	 (match_operator:SI 7 "shift_operator"
-	  [(match_operand:SI 3 "s_register_operand" "r")
-	   (match_operand:SI 4 "arm_rhs_operand" "rM")])))]
+	  [(match_operand:SI 3 "s_register_operand" "r,r,r,r")
+	   (match_operand:SI 4 "arm_rhs_operand" "r,M,r,M")])))]
   "TARGET_ARM"
   "mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7"
   [(set_attr "conds" "use")
    (set_attr "shift" "1")
    (set_attr "length" "8")
-   (set (attr "type") (if_then_else
-		        (and (match_operand 2 "const_int_operand" "")
-                             (match_operand 4 "const_int_operand" ""))
-		      (const_string "mov_shift")
-		      (const_string "mov_shift_reg")))]
+   (set_attr "type" "mov_shift_reg,mov_shift_reg,mov_shift_reg,mov_shift")]
 )
 
 (define_insn "*ifcompare_not_arith"
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index 62fb6da..a346927 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -2196,10 +2196,7 @@
     output_asm_insn (pattern, operands);
     return "";
   }
-  [(set (attr "type")
-        (if_then_else (match_operand 2 "zero_operand")
-                      (const_string "neon_compare_zero<q>")
-                      (const_string "neon_compare<q>")))]
+  [(set_attr "type" "neon_compare<q>,neon_compare_zero<q>")]
 )
 
 (define_insn "neon_vc<cmp_op_unsp><mode>_insn_unspec"
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index a724752..c7beda4 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -478,19 +478,23 @@
 )
 
 (define_insn_and_split "*thumb2_movsicc_insn"
-  [(set (match_operand:SI 0 "s_register_operand" "=l,l,r,r,r,r,r,r,r,r,r,r")
+  [(set (match_operand:SI 0 "s_register_operand" "=l,l,l,l,r,r,r,r,r,r,r,r,r,r,r,r")
 	(if_then_else:SI
 	 (match_operator 3 "arm_comparison_operator"
 	  [(match_operand 4 "cc_register" "") (const_int 0)])
-	 (match_operand:SI 1 "arm_not_operand" "0 ,lPy,0 ,0,rI,K,I ,r,rI,K ,K,r")
-	 (match_operand:SI 2 "arm_not_operand" "lPy,0 ,rI,K,0 ,0,rI,I,K ,rI,K,r")))]
+	 (match_operand:SI 1 "arm_not_operand" "0,0 ,l,Py,0,0,0,r,I,K,I ,r,rI,K ,K,r")
+	 (match_operand:SI 2 "arm_not_operand" "l,Py,0,0 ,r,I,K,0,0,0,rI,I,K ,rI,K,r")))]
   "TARGET_THUMB2"
   "@
    it\\t%D3\;mov%D3\\t%0, %2
+   it\\t%D3\;mov%D3\\t%0, %2
+   it\\t%d3\;mov%d3\\t%0, %1
    it\\t%d3\;mov%d3\\t%0, %1
    it\\t%D3\;mov%D3\\t%0, %2
+   it\\t%D3\;mov%D3\\t%0, %2
    it\\t%D3\;mvn%D3\\t%0, #%B2
    it\\t%d3\;mov%d3\\t%0, %1
+   it\\t%d3\;mov%d3\\t%0, %1
    it\\t%d3\;mvn%d3\\t%0, #%B1
    #
    #
@@ -530,30 +534,10 @@
                                   gen_rtx_SET (operands[0], operands[2])));
     DONE;
   }
-  [(set_attr "length" "4,4,6,6,6,6,10,8,10,10,10,6")
-   (set_attr "enabled_for_depr_it" "yes,yes,no,no,no,no,no,no,no,no,no,yes")
+  [(set_attr "length" "4,4,4,4,6,6,6,6,6,6,10,8,10,10,10,6")
+   (set_attr "enabled_for_depr_it" "yes,yes,yes,yes,no,no,no,no,no,no,no,no,no,no,no,yes")
    (set_attr "conds" "use")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 2 "const_int_operand" "")
-                                        (const_string "mov_imm")
-                                        (const_string "mov_reg"))
-                          (if_then_else (match_operand 1 "const_int_operand" "")
-                                        (const_string "mov_imm")
-                                        (const_string "mov_reg"))
-                          (if_then_else (match_operand 2 "const_int_operand" "")
-                                        (const_string "mov_imm")
-                                        (const_string "mov_reg"))
-                          (const_string "mvn_imm")
-                          (if_then_else (match_operand 1 "const_int_operand" "")
-                                        (const_string "mov_imm")
-                                        (const_string "mov_reg"))
-                          (const_string "mvn_imm")
-                          (const_string "multiple")
-                          (const_string "multiple")
-                          (const_string "multiple")
-                          (const_string "multiple")
-                          (const_string "multiple")
-                          (const_string "multiple")])]
+   (set_attr "type" "mov_reg,mov_imm,mov_reg,mov_imm,mov_reg,mov_imm,mvn_imm,mov_reg,mov_imm,mvn_imm,multiple,multiple,multiple,multiple,multiple,multiple")]
 )
 
 (define_insn "*thumb2_movsfcc_soft_insn"
@@ -1152,9 +1136,7 @@
   [(set_attr "predicable" "yes")
    (set_attr "shift" "1")
    (set_attr "length" "2")
-   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
-		      (const_string "alu_shift_imm")
-		      (const_string "alu_shift_reg")))]
+   (set_attr "type" "alu_shift_reg,alu_shift_imm")]
 )
 
 (define_insn "*thumb2_mov<mode>_shortim"
@@ -1169,9 +1151,9 @@
 )
 
 (define_insn "*thumb2_addsi_short"
-  [(set (match_operand:SI 0 "low_register_operand" "=l,l")
-	(plus:SI (match_operand:SI 1 "low_register_operand" "l,0")
-		 (match_operand:SI 2 "low_reg_or_int_operand" "lPt,Ps")))
+  [(set (match_operand:SI 0 "low_register_operand" "=l,l,l")
+	(plus:SI (match_operand:SI 1 "low_register_operand" "l,l,0")
+		 (match_operand:SI 2 "low_reg_or_int_operand" "l,Pt,Ps")))
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_THUMB2 && reload_completed"
   "*
@@ -1190,11 +1172,7 @@
   "
   [(set_attr "predicable" "yes")
    (set_attr "length" "2")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 2 "const_int_operand" "")
-                                        (const_string "alu_imm")
-                                        (const_string "alu_sreg"))
-                          (const_string "alu_imm")])]
+   (set_attr "type" "alu_sreg,alu_imm,alu_imm")]
 )
 
 (define_insn "*thumb2_subsi_short"
@@ -1238,10 +1216,10 @@
 (define_insn "thumb2_addsi3_compare0"
   [(set (reg:CC_NOOV CC_REGNUM)
 	(compare:CC_NOOV
-	  (plus:SI (match_operand:SI 1 "s_register_operand" "l,  0, r")
-		   (match_operand:SI 2 "arm_add_operand"    "lPt,Ps,rIL"))
+	  (plus:SI (match_operand:SI 1 "s_register_operand" "l,l, 0, r,r")
+		   (match_operand:SI 2 "arm_add_operand"    "l,Pt,Ps,r,IL"))
 	  (const_int 0)))
-   (set (match_operand:SI 0 "s_register_operand" "=l,l,r")
+   (set (match_operand:SI 0 "s_register_operand" "=l,l,l,r,r")
 	(plus:SI (match_dup 1) (match_dup 2)))]
   "TARGET_THUMB2"
   "*
@@ -1258,22 +1236,15 @@
       return \"adds\\t%0, %1, %2\";
   "
   [(set_attr "conds" "set")
-   (set_attr "length" "2,2,4")
-   (set_attr_alternative "type"
-                         [(if_then_else (match_operand 2 "const_int_operand" "")
-                                        (const_string "alus_imm")
-                                        (const_string "alus_sreg"))
-                          (const_string "alus_imm")
-                          (if_then_else (match_operand 2 "const_int_operand" "")
-                                        (const_string "alus_imm")
-                                        (const_string "alus_sreg"))])]
+   (set_attr "length" "2,2,2,4,4")
+   (set_attr "type" "alus_sreg,alus_imm,alus_imm,alus_sreg,alus_imm")]
 )
 
 (define_insn "*thumb2_addsi3_compare0_scratch"
   [(set (reg:CC_NOOV CC_REGNUM)
 	(compare:CC_NOOV
-	  (plus:SI (match_operand:SI 0 "s_register_operand" "l,  r")
-		   (match_operand:SI 1 "arm_add_operand"    "lPv,rIL"))
+	  (plus:SI (match_operand:SI 0 "s_register_operand" "l,l, r,r")
+		   (match_operand:SI 1 "arm_add_operand"    "l,Pv,r,IL"))
 	  (const_int 0)))]
   "TARGET_THUMB2"
   "*
@@ -1290,10 +1261,8 @@
       return \"cmn\\t%0, %1\";
   "
   [(set_attr "conds" "set")
-   (set_attr "length" "2,4")
-   (set (attr "type") (if_then_else (match_operand 1 "const_int_operand" "")
-                                    (const_string "alus_imm")
-                                    (const_string "alus_sreg")))]
+   (set_attr "length" "2,2,4,4")
+   (set_attr "type" "alus_sreg,alus_imm,alus_sreg,alus_imm")]
 )
 
 (define_insn "*thumb2_mulsi_short"

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 02/22][ARM] Remove operand dependency from use_literal_pool
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
  2015-11-25 12:23 ` [PR68432 01/22][ARM] Remove operand dependency from "type" attribute Richard Sandiford
@ 2015-11-25 12:24 ` Richard Sandiford
  2015-11-25 12:26 ` [PR68432 03/22][NDS32] Remove "length" dependency from "enabled" attribute Richard Sandiford
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:24 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, richard.earnshaw, ramana.radhakrishnan, kyrylo.tkachov

This patch is like the previous one in the series, but removes the
dependence of use_literal_pool on match_operand.  I think this fixes a
genuine bug.  If we cache the enabled attribute on an insn that happens
to have a nonimmediate operand, we'll treat it as enabled for all
subsequent insns, regardless of arm_disable_literal_pool.  Similarly if
we cache the enabled attribute on an insn that happens to have an
immediate operand, we'll always treat that alternative as disabled for
arm_disable_literal_pool, even if we later see a memory operand.

Splitting the alternatives means that we'll always treat the memory
alternative as enabled.  We'll treat the immediate alternative as
enabled iff arm_disable_literal_pool is false.

The immediate alternative still has to accept memories because that's
how arm_reorg tells whether it can use a constant pool.

Tested as described in the covering note.

gcc/
	* config/arm/arm.md (use_literal_pool): Remove operands test.
	* config/arm/iwmmxt.md (*iwmmxt_arm_movdi): Split immediate and
	memory f_load* alternatives.
	(*iwmmxt_movsi_insn): Likewise.
	* config/arm/vfp.md (*arm_movsi_vfp): Likewise.
	(*thumb2_movsi_vfp): Likewise.
	(*movdi_vfp): Likewise.
	(*movdi_vfp_cortexa8): Likewise.
	(*movsf_vfp): Likewise.
	(*thumb2_movsf_vfp): Likewise.
	(*movdf_vfp): Likewise.
	(*thumb2_movdf_vfp): Likewise.

diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 40666b4..8812d07 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -197,11 +197,7 @@
 	 (const_string "yes")]
 	(const_string "no")))
 
-(define_attr "use_literal_pool" "no,yes"
-   (cond [(and (eq_attr "type" "f_loads,f_loadd")
-	       (match_test "CONSTANT_P (operands[1])"))
-	  (const_string "yes")]
-	 (const_string "no")))
+(define_attr "use_literal_pool" "no,yes" (const_string "no"))
 
 ; Enable all alternatives that are both arch_enabled and insn_enabled.
 ; FIXME:: opt_enabled has been temporarily removed till the time we have
diff --git a/gcc/config/arm/iwmmxt.md b/gcc/config/arm/iwmmxt.md
index d1a60ff..ae30868 100644
--- a/gcc/config/arm/iwmmxt.md
+++ b/gcc/config/arm/iwmmxt.md
@@ -107,8 +107,8 @@
 )
 
 (define_insn "*iwmmxt_arm_movdi"
-  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, r, r, m,y,y,r, y,Uy,*w, r,*w,*w, *Uv")
-        (match_operand:DI 1 "di_operand"              "rDa,Db,Dc,mi,r,y,r,y,Uy,y,  r,*w,*w,*Uvi,*w"))]
+  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, r, r, m,y,y,r, y,Uy,*w, r,*w,*w, *w,  *Uv")
+        (match_operand:DI 1 "di_operand"              "rDa,Db,Dc,mi,r,y,r,y,Uy,y,  r,*w,*w,*Uv,*Uvi,*w"))]
   "TARGET_REALLY_IWMMXT
    && (   register_operand (operands[0], DImode)
        || register_operand (operands[1], DImode))"
@@ -140,7 +140,7 @@
 	return \"fcpys%?\\t%0, %1\\t%@ int\;fcpys%?\\t%p0, %p1\\t%@ int\";
       else
 	return \"fcpyd%?\\t%P0, %P1\\t%@ int\";
-    case 13: case 14:
+    case 13: case 14: case 15:
       return output_move_vfp (operands);
     default:
       gcc_unreachable ();
@@ -156,14 +156,15 @@
                                  (const_int 4))]
                               (const_int 4)))
    (set_attr "type" "*,*,*,load2,store2,*,*,*,*,*,f_mcrr,f_mrrc,\
-                     ffarithd,f_loadd,f_stored")
-   (set_attr "arm_pool_range" "*,*,*,1020,*,*,*,*,*,*,*,*,*,1020,*")
-   (set_attr "arm_neg_pool_range" "*,*,*,1008,*,*,*,*,*,*,*,*,*,1008,*")]
+                     ffarithd,f_loadd,f_loadd,f_stored")
+   (set_attr "use_literal_pool" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,yes,*")
+   (set_attr "arm_pool_range" "*,*,*,1020,*,*,*,*,*,*,*,*,*,*,1020,*")
+   (set_attr "arm_neg_pool_range" "*,*,*,1008,*,*,*,*,*,*,*,*,*,*,1008,*")]
 )
 
 (define_insn "*iwmmxt_movsi_insn"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,r,r,rk, m,z,r,?z,?Uy,*t, r,*t,*t  ,*Uv")
-	(match_operand:SI 1 "general_operand"      " rk,I,K,j,mi,rk,r,z,Uy,  z, r,*t,*t,*Uvi, *t"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,r,r,rk, m,z,r,?z,?Uy,*t, r,*t,*t, *t,  *Uv")
+	(match_operand:SI 1 "general_operand"      " rk,I,K,j,mi,rk,r,z,Uy,  z, r,*t,*t,*Uv,*Uvi,*t"))]
   "TARGET_REALLY_IWMMXT
    && (   register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))"
@@ -183,16 +184,17 @@
      case 10:return \"fmsr\\t%0, %1\";
      case 11:return \"fmrs\\t%0, %1\";
      case 12:return \"fcpys\\t%0, %1\\t%@ int\";
-     case 13: case 14:
+     case 13: case 14: case 15:
        return output_move_vfp (operands);
      default:
        gcc_unreachable ();
      }"
   [(set_attr "type"           "*,*,*,*,load1,store1,*,*,*,*,f_mcr,f_mrc,\
-                               fmov,f_loads,f_stores")
-   (set_attr "length"         "*,*,*,*,*,        *,*,*,  16,     *,*,*,*,*,*")
-   (set_attr "pool_range"     "*,*,*,*,4096,     *,*,*,1024,     *,*,*,*,1020,*")
-   (set_attr "neg_pool_range" "*,*,*,*,4084,     *,*,*,   *,  1012,*,*,*,1008,*")
+                               fmov,f_loads,f_loads,f_stores")
+   (set_attr "length"         "*,*,*,*,*,        *,*,*,  16,     *,*,*,*,*,*,*")
+   (set_attr "use_literal_pool" "*,*,*,*,*,      *,*,*,*,        *,*,*,*,*,yes, *")
+   (set_attr "pool_range"     "*,*,*,*,4096,     *,*,*,1024,     *,*,*,*,*,1020,*")
+   (set_attr "neg_pool_range" "*,*,*,*,4084,     *,*,*,   *,  1012,*,*,*,*,1008,*")
    ;; Note - the "predicable" attribute is not allowed to have alternatives.
    ;; Since the wSTRw wCx instruction is not predicable, we cannot support
    ;; predicating any of the alternatives in this template.  Instead,
diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
index baeac62..b3017fb 100644
--- a/gcc/config/arm/vfp.md
+++ b/gcc/config/arm/vfp.md
@@ -22,8 +22,8 @@
 ;; ??? For now do not allow loading constants into vfp regs.  This causes
 ;; problems because small constants get converted into adds.
 (define_insn "*arm_movsi_vfp"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,r,r,rk,m ,*t,r,*t,*t, *Uv")
-      (match_operand:SI 1 "general_operand"	   "rk, I,K,j,mi,rk,r,*t,*t,*Uvi,*t"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,r,r,rk,m ,*t,r,*t,*t, *t,  *Uv")
+      (match_operand:SI 1 "general_operand"	   "rk, I,K,j,mi,rk,r,*t,*t,*Uv,*Uvi,*t"))]
   "TARGET_ARM && TARGET_VFP && TARGET_HARD_FLOAT
    && (   s_register_operand (operands[0], SImode)
        || s_register_operand (operands[1], SImode))"
@@ -46,16 +46,17 @@
       return \"vmov%?\\t%0, %1\\t%@ int\";
     case 8:
       return \"vmov%?.f32\\t%0, %1\\t%@ int\";
-    case 9: case 10:
+    case 9: case 10: case 11:
       return output_move_vfp (operands);
     default:
       gcc_unreachable ();
     }
   "
   [(set_attr "predicable" "yes")
-   (set_attr "type" "mov_reg,mov_reg,mvn_imm,mov_imm,load1,store1,f_mcr,f_mrc,fmov,f_loads,f_stores")
-   (set_attr "pool_range"     "*,*,*,*,4096,*,*,*,*,1020,*")
-   (set_attr "neg_pool_range" "*,*,*,*,4084,*,*,*,*,1008,*")]
+   (set_attr "type" "mov_reg,mov_reg,mvn_imm,mov_imm,load1,store1,f_mcr,f_mrc,fmov,f_loads,f_loads,f_stores")
+   (set_attr "use_literal_pool" "*,*,*,*,*,*,*,*,*,*,yes,*")
+   (set_attr "pool_range"     "*,*,*,*,4096,*,*,*,*,*,1020,*")
+   (set_attr "neg_pool_range" "*,*,*,*,4084,*,*,*,*,*,1008,*")]
 )
 
 ;; See thumb2.md:thumb2_movsi_insn for an explanation of the split
@@ -64,8 +65,8 @@
 ;; is chosen with length 2 when the instruction is predicated for
 ;; arm_restrict_it.
 (define_insn "*thumb2_movsi_vfp"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,l,r,r, l,*hk,m, *m,*t, r,*t,*t,  *Uv")
-	(match_operand:SI 1 "general_operand"	   "rk,I,Py,K,j,mi,*mi,l,*hk, r,*t,*t,*Uvi,*t"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,l,r,r, l,*hk,m, *m,*t, r,*t,*t, *t,  *Uv")
+	(match_operand:SI 1 "general_operand"	   "rk,I,Py,K,j,mi,*mi,l,*hk, r,*t,*t,*Uv,*Uvi,*t"))]
   "TARGET_THUMB2 && TARGET_VFP && TARGET_HARD_FLOAT
    && (   s_register_operand (operands[0], SImode)
        || s_register_operand (operands[1], SImode))"
@@ -92,26 +93,27 @@
       return \"vmov%?\\t%0, %1\\t%@ int\";
     case 11:
       return \"vmov%?.f32\\t%0, %1\\t%@ int\";
-    case 12: case 13:
+    case 12: case 13: case 14:
       return output_move_vfp (operands);
     default:
       gcc_unreachable ();
     }
   "
   [(set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "yes,no,yes,no,no,no,no,no,no,no,no,no,no,no")
-   (set_attr "type" "mov_reg,mov_reg,mov_reg,mvn_reg,mov_imm,load1,load1,store1,store1,f_mcr,f_mrc,fmov,f_loads,f_stores")
-   (set_attr "length" "2,4,2,4,4,4,4,4,4,4,4,4,4,4")
-   (set_attr "pool_range"     "*,*,*,*,*,1018,4094,*,*,*,*,*,1018,*")
-   (set_attr "neg_pool_range" "*,*,*,*,*,   0,   0,*,*,*,*,*,1008,*")]
+   (set_attr "predicable_short_it" "yes,no,yes,no,no,no,no,no,no,no,no,no,no,no,no")
+   (set_attr "type" "mov_reg,mov_reg,mov_reg,mvn_reg,mov_imm,load1,load1,store1,store1,f_mcr,f_mrc,fmov,f_loads,f_loads,f_stores")
+   (set_attr "length" "2,4,2,4,4,4,4,4,4,4,4,4,4,4,4")
+   (set_attr "use_literal_pool" "*,*,*,*,*,*,*,*,*,*,*,*,*,yes,*")
+   (set_attr "pool_range"     "*,*,*,*,*,1018,4094,*,*,*,*,*,*,1018,*")
+   (set_attr "neg_pool_range" "*,*,*,*,*,   0,   0,*,*,*,*,*,*,1008,*")]
 )
 
 
 ;; DImode moves
 
 (define_insn "*movdi_vfp"
-  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,r,r,q,q,m,w,r,w,w, Uv")
-       (match_operand:DI 1 "di_operand"              "r,rDa,Db,Dc,mi,mi,q,r,w,w,Uvi,w"))]
+  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,r,r,q,q,m,w,r,w,w,w,Uv")
+       (match_operand:DI 1 "di_operand"              "r,rDa,Db,Dc,mi,mi,q,r,w,w,Uv,Uvi,w"))]
   "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP && arm_tune != cortexa8
    && (   register_operand (operands[0], DImode)
        || register_operand (operands[1], DImode))
@@ -138,13 +140,13 @@
 	return \"vmov%?.f32\\t%0, %1\\t%@ int\;vmov%?.f32\\t%p0, %p1\\t%@ int\";
       else
 	return \"vmov%?.f64\\t%P0, %P1\\t%@ int\";
-    case 10: case 11:
+    case 10: case 11: case 12:
       return output_move_vfp (operands);
     default:
       gcc_unreachable ();
     }
   "
-  [(set_attr "type" "multiple,multiple,multiple,multiple,load2,load2,store2,f_mcrr,f_mrrc,ffarithd,f_loadd,f_stored")
+  [(set_attr "type" "multiple,multiple,multiple,multiple,load2,load2,store2,f_mcrr,f_mrrc,ffarithd,f_loadd,f_loadd,f_stored")
    (set (attr "length") (cond [(eq_attr "alternative" "1,4,5,6") (const_int 8)
                               (eq_attr "alternative" "2") (const_int 12)
                               (eq_attr "alternative" "3") (const_int 16)
@@ -154,15 +156,16 @@
                                  (const_int 8)
                                  (const_int 4))]
                               (const_int 4)))
-   (set_attr "arm_pool_range"     "*,*,*,*,1020,4096,*,*,*,*,1020,*")
-   (set_attr "thumb2_pool_range"     "*,*,*,*,1018,4094,*,*,*,*,1018,*")
-   (set_attr "neg_pool_range" "*,*,*,*,1004,0,*,*,*,*,1004,*")
-   (set_attr "arch"           "t2,any,any,any,a,t2,any,any,any,any,any,any")]
+   (set_attr "arm_pool_range"     "*,*,*,*,1020,4096,*,*,*,*,*,1020,*")
+   (set_attr "thumb2_pool_range"     "*,*,*,*,1018,4094,*,*,*,*,*,1018,*")
+   (set_attr "neg_pool_range" "*,*,*,*,1004,0,*,*,*,*,*,1004,*")
+   (set_attr "use_literal_pool" "*,*,*,*,*,*,*,*,*,*,*,yes,*")
+   (set_attr "arch"           "t2,any,any,any,a,t2,any,any,any,any,any,any,any")]
 )
 
 (define_insn "*movdi_vfp_cortexa8"
-  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,r,r,r,r,m,w,!r,w,w, Uv")
-       (match_operand:DI 1 "di_operand"              "r,rDa,Db,Dc,mi,mi,r,r,w,w,Uvi,w"))]
+  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,r,r,r,r,m,w,!r,w,w,w,Uv")
+       (match_operand:DI 1 "di_operand"              "r,rDa,Db,Dc,mi,mi,r,r,w,w,Uv,Uvi,w"))]
   "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP && arm_tune == cortexa8
     && (   register_operand (operands[0], DImode)
         || register_operand (operands[1], DImode))
@@ -186,13 +189,13 @@
       return \"vmov%?\\t%Q0, %R0, %P1\\t%@ int\";
     case 9:
       return \"vmov%?.f64\\t%P0, %P1\\t%@ int\";
-    case 10: case 11:
+    case 10: case 11: case 12:
       return output_move_vfp (operands);
     default:
       gcc_unreachable ();
     }
   "
-  [(set_attr "type" "multiple,multiple,multiple,multiple,load2,load2,store2,f_mcrr,f_mrrc,ffarithd,f_loadd,f_stored")
+  [(set_attr "type" "multiple,multiple,multiple,multiple,load2,load2,store2,f_mcrr,f_mrrc,ffarithd,f_loadd,f_loadd,f_stored")
    (set (attr "length") (cond [(eq_attr "alternative" "1") (const_int 8)
                                (eq_attr "alternative" "2") (const_int 12)
                                (eq_attr "alternative" "3") (const_int 16)
@@ -202,12 +205,13 @@
                                  * 4")]
                               (const_int 4)))
    (set_attr "predicable"    "yes")
-   (set_attr "arm_pool_range"     "*,*,*,*,1018,4094,*,*,*,*,1018,*")
-   (set_attr "thumb2_pool_range"     "*,*,*,*,1018,4094,*,*,*,*,1018,*")
-   (set_attr "neg_pool_range" "*,*,*,*,1004,0,*,*,*,*,1004,*")
+   (set_attr "use_literal_pool" "*,*,*,*,*,*,*,*,*,*,*,yes,*")
+   (set_attr "arm_pool_range"     "*,*,*,*,1018,4094,*,*,*,*,*,1018,*")
+   (set_attr "thumb2_pool_range"     "*,*,*,*,1018,4094,*,*,*,*,*,1018,*")
+   (set_attr "neg_pool_range" "*,*,*,*,1004,0,*,*,*,*,*,1004,*")
    (set (attr "ce_count") 
 	(symbol_ref "get_attr_length (insn) / 4"))
-   (set_attr "arch"           "t2,any,any,any,a,t2,any,any,any,any,any,any")]
+   (set_attr "arch"           "t2,any,any,any,a,t2,any,any,any,any,any,any,any")]
  )
 
 ;; HFmode moves
@@ -319,8 +323,8 @@
 ;; preferable to loading the value via integer registers.
 
 (define_insn "*movsf_vfp"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=t,?r,t ,t  ,Uv,r ,m,t,r")
-        (match_operand:SF 1 "general_operand"	   " ?r,t,Dv,UvE,t, mE,r,t,r"))]
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=t,?r,t ,t, t,  Uv,r ,m,t,r")
+        (match_operand:SF 1 "general_operand"	   " ?r,t,Dv,Uv,UvE,t, mE,r,t,r"))]
   "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP
    && (   s_register_operand (operands[0], SFmode)
        || s_register_operand (operands[1], SFmode))"
@@ -333,15 +337,15 @@
       return \"vmov%?\\t%0, %1\";
     case 2:
       return \"vmov%?.f32\\t%0, %1\";
-    case 3: case 4:
+    case 3: case 4: case 5:
       return output_move_vfp (operands);
-    case 5:
-      return \"ldr%?\\t%0, %1\\t%@ float\";
     case 6:
-      return \"str%?\\t%1, %0\\t%@ float\";
+      return \"ldr%?\\t%0, %1\\t%@ float\";
     case 7:
-      return \"vmov%?.f32\\t%0, %1\";
+      return \"str%?\\t%1, %0\\t%@ float\";
     case 8:
+      return \"vmov%?.f32\\t%0, %1\";
+    case 9:
       return \"mov%?\\t%0, %1\\t%@ float\";
     default:
       gcc_unreachable ();
@@ -349,14 +353,15 @@
   "
   [(set_attr "predicable" "yes")
    (set_attr "type"
-     "f_mcr,f_mrc,fconsts,f_loads,f_stores,load1,store1,fmov,mov_reg")
-   (set_attr "pool_range" "*,*,*,1020,*,4096,*,*,*")
-   (set_attr "neg_pool_range" "*,*,*,1008,*,4080,*,*,*")]
+     "f_mcr,f_mrc,fconsts,f_loads,f_loads,f_stores,load1,store1,fmov,mov_reg")
+   (set_attr "use_literal_pool" "*,*,*,*,yes,*,*,*,*,*")
+   (set_attr "pool_range" "*,*,*,*,1020,*,4096,*,*,*")
+   (set_attr "neg_pool_range" "*,*,*,*,1008,*,4080,*,*,*")]
 )
 
 (define_insn "*thumb2_movsf_vfp"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=t,?r,t, t  ,Uv,r ,m,t,r")
-	(match_operand:SF 1 "general_operand"	   " ?r,t,Dv,UvE,t, mE,r,t,r"))]
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=t,?r,t, t, t,  Uv,r ,m,t,r")
+	(match_operand:SF 1 "general_operand"	   " ?r,t,Dv,Uv,UvE,t, mE,r,t,r"))]
   "TARGET_THUMB2 && TARGET_HARD_FLOAT && TARGET_VFP
    && (   s_register_operand (operands[0], SFmode)
        || s_register_operand (operands[1], SFmode))"
@@ -369,15 +374,15 @@
       return \"vmov%?\\t%0, %1\";
     case 2:
       return \"vmov%?.f32\\t%0, %1\";
-    case 3: case 4:
+    case 3: case 4: case 5:
       return output_move_vfp (operands);
-    case 5:
-      return \"ldr%?\\t%0, %1\\t%@ float\";
     case 6:
-      return \"str%?\\t%1, %0\\t%@ float\";
+      return \"ldr%?\\t%0, %1\\t%@ float\";
     case 7:
-      return \"vmov%?.f32\\t%0, %1\";
+      return \"str%?\\t%1, %0\\t%@ float\";
     case 8:
+      return \"vmov%?.f32\\t%0, %1\";
+    case 9:
       return \"mov%?\\t%0, %1\\t%@ float\";
     default:
       gcc_unreachable ();
@@ -386,16 +391,17 @@
   [(set_attr "predicable" "yes")
    (set_attr "predicable_short_it" "no")
    (set_attr "type"
-     "f_mcr,f_mrc,fconsts,f_loads,f_stores,load1,store1,fmov,mov_reg")
-   (set_attr "pool_range" "*,*,*,1018,*,4090,*,*,*")
-   (set_attr "neg_pool_range" "*,*,*,1008,*,0,*,*,*")]
+     "f_mcr,f_mrc,fconsts,f_loads,f_loads,f_stores,load1,store1,fmov,mov_reg")
+   (set_attr "use_literal_pool" "*,*,*,*,yes,*,*,*,*,*")
+   (set_attr "pool_range" "*,*,*,*,1018,*,4090,*,*,*")
+   (set_attr "neg_pool_range" "*,*,*,*,1008,*,0,*,*,*")]
 )
 
 ;; DFmode moves
 
 (define_insn "*movdf_vfp"
-  [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,w  ,Uv,r, m,w,r")
-	(match_operand:DF 1 "soft_df_operand"		   " ?r,w,Dy,UvF,w ,mF,r,w,r"))]
+  [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,w, w,  Uv,r, m,w,r")
+	(match_operand:DF 1 "soft_df_operand"		   " ?r,w,Dy,Uv,UvF,w ,mF,r,w,r"))]
   "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP
    && (   register_operand (operands[0], DFmode)
        || register_operand (operands[1], DFmode))"
@@ -410,39 +416,40 @@
       case 2:
 	gcc_assert (TARGET_VFP_DOUBLE);
         return \"vmov%?.f64\\t%P0, %1\";
-      case 3: case 4:
+      case 3: case 4: case 5:
 	return output_move_vfp (operands);
-      case 5: case 6:
+      case 6: case 7:
 	return output_move_double (operands, true, NULL);
-      case 7:
+      case 8:
 	if (TARGET_VFP_SINGLE)
 	  return \"vmov%?.f32\\t%0, %1\;vmov%?.f32\\t%p0, %p1\";
 	else
 	  return \"vmov%?.f64\\t%P0, %P1\";
-      case 8:
+      case 9:
         return \"#\";
       default:
 	gcc_unreachable ();
       }
     }
   "
-  [(set_attr "type" "f_mcrr,f_mrrc,fconstd,f_loadd,f_stored,\
+  [(set_attr "type" "f_mcrr,f_mrrc,fconstd,f_loadd,f_loadd,f_stored,\
                      load2,store2,ffarithd,multiple")
-   (set (attr "length") (cond [(eq_attr "alternative" "5,6,8") (const_int 8)
-			       (eq_attr "alternative" "7")
+   (set (attr "length") (cond [(eq_attr "alternative" "6,7,9") (const_int 8)
+			       (eq_attr "alternative" "8")
 				(if_then_else
 				 (match_test "TARGET_VFP_SINGLE")
 				 (const_int 8)
 				 (const_int 4))]
 			      (const_int 4)))
    (set_attr "predicable" "yes")
-   (set_attr "pool_range" "*,*,*,1020,*,1020,*,*,*")
-   (set_attr "neg_pool_range" "*,*,*,1004,*,1004,*,*,*")]
+   (set_attr "use_literal_pool" "*,*,*,*,yes,*,*,*,*,*")
+   (set_attr "pool_range" "*,*,*,*,1020,*,1020,*,*,*")
+   (set_attr "neg_pool_range" "*,*,*,*,1004,*,1004,*,*,*")]
 )
 
 (define_insn "*thumb2_movdf_vfp"
-  [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,w  ,Uv,r ,m,w,r")
-	(match_operand:DF 1 "soft_df_operand"		   " ?r,w,Dy,UvF,w, mF,r, w,r"))]
+  [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,w, w,  Uv,r ,m,w,r")
+	(match_operand:DF 1 "soft_df_operand"		   " ?r,w,Dy,Uv,UvF,w, mF,r, w,r"))]
   "TARGET_THUMB2 && TARGET_HARD_FLOAT && TARGET_VFP
    && (   register_operand (operands[0], DFmode)
        || register_operand (operands[1], DFmode))"
@@ -457,11 +464,11 @@
       case 2:
 	gcc_assert (TARGET_VFP_DOUBLE);
 	return \"vmov%?.f64\\t%P0, %1\";
-      case 3: case 4:
+      case 3: case 4: case 5:
 	return output_move_vfp (operands);
-      case 5: case 6: case 8:
+      case 6: case 7: case 9:
 	return output_move_double (operands, true, NULL);
-      case 7:
+      case 8:
 	if (TARGET_VFP_SINGLE)
 	  return \"vmov%?.f32\\t%0, %1\;vmov%?.f32\\t%p0, %p1\";
 	else
@@ -471,17 +478,18 @@
       }
     }
   "
-  [(set_attr "type" "f_mcrr,f_mrrc,fconstd,f_loadd,\
+  [(set_attr "type" "f_mcrr,f_mrrc,fconstd,f_loadd,f_loadd,\
                      f_stored,load2,store2,ffarithd,multiple")
-   (set (attr "length") (cond [(eq_attr "alternative" "5,6,8") (const_int 8)
-			       (eq_attr "alternative" "7")
+   (set (attr "length") (cond [(eq_attr "alternative" "6,7,9") (const_int 8)
+			       (eq_attr "alternative" "8")
 				(if_then_else
 				 (match_test "TARGET_VFP_SINGLE")
 				 (const_int 8)
 				 (const_int 4))]
 			      (const_int 4)))
-   (set_attr "pool_range" "*,*,*,1018,*,4094,*,*,*")
-   (set_attr "neg_pool_range" "*,*,*,1008,*,0,*,*,*")]
+   (set_attr "use_literal_pool" "*,*,*,*,yes,*,*,*,*,*")
+   (set_attr "pool_range" "*,*,*,*,1018,*,4094,*,*,*")
+   (set_attr "neg_pool_range" "*,*,*,*,1008,*,0,*,*,*")]
 )
 
 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 03/22][NDS32] Remove "length" dependency from "enabled" attribute
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
  2015-11-25 12:23 ` [PR68432 01/22][ARM] Remove operand dependency from "type" attribute Richard Sandiford
  2015-11-25 12:24 ` [PR68432 02/22][ARM] Remove operand dependency from use_literal_pool Richard Sandiford
@ 2015-11-25 12:26 ` Richard Sandiford
  2015-11-25 12:28 ` [PR68432 04/22] Remove global which_alternative Richard Sandiford
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: jasonwucj, shiva0217

The "enabled" attribute is supposed to be an invariant property of an
alternative and shouldn't depend on having access to a particular insn.
Although I think the port honours that, it's not really enforceable at
compile time because "enabled" depends on "length", which in turn requires
access to an insn in order to calculate branch lengths.  This patch
introduces a second attribute to indicate whether a single-instruction
pattern is 16-bit or not.

Tested as described in the covering note.

gcc/
	* config/nds32/nd32.md (is_16bit): New attribute.
	(length, enabled): Use it.
	(*mov<mode>): Use "is_16bit" instead of "length".
	(*sethi, *lo_sum, zero_extend<mode>si2, extend<mode>si2, add<mode>3)
	(sub<mode>3, *add_slli, *add_srli, *sub_slli, *sub_srli, mulsi3)
	(mulsidi3, umulsidi3, *maddr32_0, *maddr32_1, *msubr32, divmodsi4)
	(udivmodsi4, bitc, andsi3, *and_slli, *and_srli, iorsi3, *or_slli)
	(*or_srli, xorsi3, *xor_slli, *xor_srli, rotrsi3, negsi2)
	(one_cmplsi2, ashlsi3, ashrsi3, lshrsi3, cmovz, cmovn, slts_compare)
	(slt_compare, indirect_jump, *call_register, *call_value_register)
	(*sibcall_register, *sibcall_value_register, clzsi2, smaxsi3)
	(sminsi3, *btst): Likewise.

diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md
index 3dc1ce8..89c0391 100644
--- a/gcc/config/nds32/nds32.md
+++ b/gcc/config/nds32/nds32.md
@@ -56,8 +56,15 @@
   (const_string "unknown"))
 
 
+;; True if the instruction requires TARGET_16_BIT.
+(define_attr "is_16bit" "no,yes" (const_string "no"))
+
+
 ;; Length, in bytes, default is 4-bytes.
-(define_attr "length" "" (const_int 4))
+(define_attr "length" ""
+  (cond [(eq_attr "is_16bit" "yes")
+	 (const_int 2)]
+	(const_int 4)))
 
 
 ;; Enabled, which is used to enable/disable insn alternatives.
@@ -66,7 +73,7 @@
 ;; determine the length by itself, its enabled attribute should be
 ;; always 1 to avoid the conflict with the settings here.
 (define_attr "enabled" ""
-  (cond [(and (eq_attr "length" "2")
+  (cond [(and (eq_attr "is_16bit" "yes")
 	      (match_test "!TARGET_16_BIT"))
 	 (const_int 0)]
 	(const_int 1)))
@@ -169,8 +176,8 @@
       gcc_unreachable ();
     }
 }
-  [(set_attr "type"   "alu,alu,store,store,store,store,store,load,load,load,load,load,alu,alu,alu,alu")
-   (set_attr "length" "  2,  4,    2,    2,    2,    2,    4,   2,   2,   2,   2,   4,  2,  2,  4,  4")])
+  [(set_attr "type"     "alu,alu,store,store,store,store,store,load,load,load,load,load,alu,alu,alu,alu")
+   (set_attr "is_16bit" "yes, no,  yes,  yes,  yes,  yes,   no, yes, yes, yes, yes,  no,yes,yes, no, no")])
 
 
 ;; We use nds32_symbolic_operand to limit that only CONST/SYMBOL_REF/LABEL_REF
@@ -190,7 +197,7 @@
   ""
   "sethi\t%0, hi20(%1)"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 
 (define_insn "*lo_sum"
@@ -200,7 +207,7 @@
   ""
   "ori\t%0, %1, lo12(%2)"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -227,8 +234,8 @@
       gcc_unreachable ();
     }
 }
-  [(set_attr "type"   "alu,alu,load,load")
-   (set_attr "length" "  2,  4,   2,   4")])
+  [(set_attr "type"     "alu,alu,load,load")
+   (set_attr "is_16bit" "yes, no, yes,  no")])
 
 
 ;; Sign extension instructions.
@@ -251,8 +258,8 @@
       gcc_unreachable ();
     }
 }
-  [(set_attr "type"   "alu,alu,load")
-   (set_attr "length" "  2,  4,   4")])
+  [(set_attr "type"     "alu,alu,load")
+   (set_attr "is_16bit" "yes, no,  no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -298,8 +305,8 @@
       gcc_unreachable ();
     }
 }
-  [(set_attr "type"   "alu,alu,alu,alu,alu,alu,alu,alu,alu,alu")
-   (set_attr "length" "  2,  2,  2,  2,  2,  2,  2,  2,  4,  4")])
+  [(set_attr "type"     "alu,alu,alu,alu,alu,alu,alu,alu,alu,alu")
+   (set_attr "is_16bit" "yes,yes,yes,yes,yes,yes,yes,yes, no, no")])
 
 (define_insn "sub<mode>3"
   [(set (match_operand:QIHISI 0 "register_operand"                    "=d, l,    r, r")
@@ -311,8 +318,8 @@
   sub333\t%0, %1, %2
   subri\t%0, %2, %1
   sub\t%0, %1, %2"
-  [(set_attr "type"   "alu,alu,alu,alu")
-   (set_attr "length" "  2,  2,  4,  4")])
+  [(set_attr "type"     "alu,alu,alu,alu")
+   (set_attr "is_16bit" "yes,yes, no, no")])
 
 
 ;; GCC intends to simplify (plus (ashift ...) (reg))
@@ -334,7 +341,7 @@
   return "add_slli\t%0, %3, %1, %2";
 }
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 (define_insn "*add_srli"
   [(set (match_operand:SI 0 "register_operand"                        "=   r")
@@ -344,7 +351,7 @@
   "TARGET_ISA_V3"
   "add_srli\t%0, %3, %1, %2"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 
 ;; GCC intends to simplify (minus (reg) (ashift ...))
@@ -366,7 +373,7 @@
   return "sub_slli\t%0, %1, %2, %3";
 }
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 (define_insn "*sub_srli"
   [(set (match_operand:SI 0 "register_operand"                         "=   r")
@@ -376,7 +383,7 @@
   "TARGET_ISA_V3"
   "sub_srli\t%0, %1, %2, %3"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 
 ;; Multiplication instructions.
@@ -389,8 +396,8 @@
   "@
   mul33\t%0, %2
   mul\t%0, %1, %2"
-  [(set_attr "type"   "alu,alu")
-   (set_attr "length" "  2,  4")])
+  [(set_attr "type"     "alu,alu")
+   (set_attr "is_16bit" "yes, no")])
 
 (define_insn "mulsidi3"
   [(set (match_operand:DI 0 "register_operand"                          "=r")
@@ -398,8 +405,8 @@
 		 (sign_extend:DI (match_operand:SI 2 "register_operand" " r"))))]
   "TARGET_ISA_V2 || TARGET_ISA_V3"
   "mulsr64\t%0, %1, %2"
-  [(set_attr "type"   "alu")
-   (set_attr "length"   "4")])
+  [(set_attr "type" "alu")
+   (set_attr "is_16bit" "no")])
 
 (define_insn "umulsidi3"
   [(set (match_operand:DI 0 "register_operand"                          "=r")
@@ -407,8 +414,8 @@
 		 (zero_extend:DI (match_operand:SI 2 "register_operand" " r"))))]
   "TARGET_ISA_V2 || TARGET_ISA_V3"
   "mulr64\t%0, %1, %2"
-  [(set_attr "type"   "alu")
-   (set_attr "length"   "4")])
+  [(set_attr "type" "alu")
+   (set_attr "is_16bit" "no")])
 
 
 ;; Multiply-accumulate instructions.
@@ -420,8 +427,8 @@
                           (match_operand:SI 2 "register_operand" " r"))))]
   ""
   "maddr32\t%0, %1, %2"
-  [(set_attr "type"   "alu")
-   (set_attr "length"   "4")])
+  [(set_attr "type" "alu")
+   (set_attr "is_16bit" "no")])
 
 (define_insn "*maddr32_1"
   [(set (match_operand:SI 0 "register_operand"                   "=r")
@@ -430,8 +437,8 @@
                  (match_operand:SI 3 "register_operand"          " 0")))]
   ""
   "maddr32\t%0, %1, %2"
-  [(set_attr "type"   "alu")
-   (set_attr "length"   "4")])
+  [(set_attr "type" "alu")
+   (set_attr "is_16bit" "no")])
 
 (define_insn "*msubr32"
   [(set (match_operand:SI 0 "register_operand"                    "=r")
@@ -440,8 +447,8 @@
                            (match_operand:SI 2 "register_operand" " r"))))]
   ""
   "msubr32\t%0, %1, %2"
-  [(set_attr "type"   "alu")
-   (set_attr "length"   "4")])
+  [(set_attr "type" "alu")
+   (set_attr "is_16bit" "no")])
 
 
 ;; Div Instructions.
@@ -454,8 +461,8 @@
         (mod:SI (match_dup 1) (match_dup 2)))]
   ""
   "divsr\t%0, %3, %1, %2"
-  [(set_attr "type"   "alu")
-   (set_attr "length"   "4")])
+  [(set_attr "type" "alu")
+   (set_attr "is_16bit" "no")])
 
 (define_insn "udivmodsi4"
   [(set (match_operand:SI 0 "register_operand"          "=r")
@@ -465,8 +472,8 @@
         (umod:SI (match_dup 1) (match_dup 2)))]
   ""
   "divr\t%0, %3, %1, %2"
-  [(set_attr "type"   "alu")
-   (set_attr "length"   "4")])
+  [(set_attr "type" "alu")
+   (set_attr "is_16bit" "no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -485,8 +492,7 @@
   "TARGET_ISA_V3"
   "bitc\t%0, %2, %1"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")]
-)
+   (set_attr "is_16bit" "no")])
 
 (define_insn "andsi3"
   [(set (match_operand:SI 0 "register_operand"         "=w, r,    l,    l,    l,    l,    l,    l,    r,   r,     r,    r,    r")
@@ -554,8 +560,8 @@
       gcc_unreachable ();
     }
 }
-  [(set_attr "type"   "alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu")
-   (set_attr "length" "  2,  4,  2,  2,  2,  2,  2,  2,  4,  4,  4,  4,  4")])
+  [(set_attr "type"     "alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu")
+   (set_attr "is_16bit" "yes, no,yes,yes,yes,yes,yes,yes, no, no, no, no, no")])
 
 (define_insn "*and_slli"
   [(set (match_operand:SI 0 "register_operand"                      "=   r")
@@ -565,7 +571,7 @@
   "TARGET_ISA_V3"
   "and_slli\t%0, %3, %1, %2"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 (define_insn "*and_srli"
   [(set (match_operand:SI 0 "register_operand"                       "=   r")
@@ -575,7 +581,7 @@
   "TARGET_ISA_V3"
   "and_srli\t%0, %3, %1, %2"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -614,8 +620,8 @@
       gcc_unreachable ();
     }
 }
-  [(set_attr "type"   "alu,alu,alu,alu")
-   (set_attr "length" "  2,  4,  4,  4")])
+  [(set_attr "type"     "alu,alu,alu,alu")
+   (set_attr "is_16bit" "yes, no, no, no")])
 
 (define_insn "*or_slli"
   [(set (match_operand:SI 0 "register_operand"                     "=   r")
@@ -625,7 +631,7 @@
   "TARGET_ISA_V3"
   "or_slli\t%0, %3, %1, %2"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 (define_insn "*or_srli"
   [(set (match_operand:SI 0 "register_operand"                       "=   r")
@@ -635,7 +641,7 @@
   "TARGET_ISA_V3"
   "or_srli\t%0, %3, %1, %2"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -674,8 +680,8 @@
       gcc_unreachable ();
     }
 }
-  [(set_attr "type"   "alu,alu,alu,alu")
-   (set_attr "length" "  2,  4,  4,  4")])
+  [(set_attr "type"     "alu,alu,alu,alu")
+   (set_attr "is_16bit" "yes, no, no, no")])
 
 (define_insn "*xor_slli"
   [(set (match_operand:SI 0 "register_operand"                     "=   r")
@@ -685,7 +691,7 @@
   "TARGET_ISA_V3"
   "xor_slli\t%0, %3, %1, %2"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 (define_insn "*xor_srli"
   [(set (match_operand:SI 0 "register_operand"                       "=   r")
@@ -695,7 +701,7 @@
   "TARGET_ISA_V3"
   "xor_srli\t%0, %3, %1, %2"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 ;; Rotate Right Instructions.
 
@@ -707,8 +713,8 @@
   "@
   rotri\t%0, %1, %2
   rotr\t%0, %1, %2"
-  [(set_attr "type"   "alu,alu")
-   (set_attr "length" "  4,  4")])
+  [(set_attr "type"     "alu,alu")
+   (set_attr "is_16bit" " no, no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -726,8 +732,8 @@
   "@
    neg33\t%0, %1
    subri\t%0, %1, 0"
-  [(set_attr "type"   "alu,alu")
-   (set_attr "length" "  2,  4")])
+  [(set_attr "type"     "alu,alu")
+   (set_attr "is_16bit" "yes, no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -743,8 +749,8 @@
   "@
    not33\t%0, %1
    nor\t%0, %1, %1"
-  [(set_attr "type"   "alu,alu")
-   (set_attr "length" "  2,  4")])
+  [(set_attr "type"     "alu,alu")
+   (set_attr "is_16bit" "yes, no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -760,8 +766,8 @@
   slli333\t%0, %1, %2
   slli\t%0, %1, %2
   sll\t%0, %1, %2"
-  [(set_attr "type"   "alu,alu,alu")
-   (set_attr "length" "  2,  4,  4")])
+  [(set_attr "type"     "alu,alu,alu")
+   (set_attr "is_16bit" "yes, no, no")])
 
 (define_insn "ashrsi3"
   [(set (match_operand:SI 0 "register_operand"               "=   d,    r, r")
@@ -772,8 +778,8 @@
   srai45\t%0, %2
   srai\t%0, %1, %2
   sra\t%0, %1, %2"
-  [(set_attr "type"   "alu,alu,alu")
-   (set_attr "length" "  2,  4,  4")])
+  [(set_attr "type"     "alu,alu,alu")
+   (set_attr "is_16bit" "yes, no, no")])
 
 (define_insn "lshrsi3"
   [(set (match_operand:SI 0 "register_operand"               "=   d,    r, r")
@@ -784,8 +790,8 @@
   srli45\t%0, %2
   srli\t%0, %1, %2
   srl\t%0, %1, %2"
-  [(set_attr "type"   "alu,alu,alu")
-   (set_attr "length" "  2,  4,  4")])
+  [(set_attr "type"     "alu,alu,alu")
+   (set_attr "is_16bit" "yes, no, no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -921,7 +927,7 @@ create_template:
    cmovz\t%0, %2, %1
    cmovn\t%0, %3, %1"
   [(set_attr "type" "move")
-   (set_attr "length"  "4")])
+   (set_attr "is_16bit" "no")])
 
 (define_insn "cmovn"
   [(set (match_operand:SI 0 "register_operand"                      "=r, r")
@@ -934,7 +940,7 @@ create_template:
    cmovn\t%0, %2, %1
    cmovz\t%0, %3, %1"
   [(set_attr "type" "move")
-   (set_attr "length"  "4")])
+   (set_attr "is_16bit" "no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -1827,8 +1833,8 @@ create_template:
    sltsi45\t%1, %2
    slts\t%0, %1, %2
    sltsi\t%0, %1, %2"
-  [(set_attr "type"   "compare,compare,compare,compare")
-   (set_attr "length" "      2,      2,      4,      4")])
+  [(set_attr "type"     "compare,compare,compare,compare")
+   (set_attr "is_16bit" "    yes,    yes,     no,     no")])
 
 (define_insn "slt_compare"
   [(set (match_operand:SI 0 "register_operand"          "=t,    t, r,    r")
@@ -1840,8 +1846,8 @@ create_template:
    slti45\t%1, %2
    slt\t%0, %1, %2
    slti\t%0, %1, %2"
-  [(set_attr "type"   "compare,compare,compare,compare")
-   (set_attr "length" "      2,      2,      4,      4")])
+  [(set_attr "type"     "compare,compare,compare,compare")
+   (set_attr "is_16bit" "    yes,    yes,     no,     no")])
 
 
 ;; ----------------------------------------------------------------------------
@@ -1889,8 +1895,8 @@ create_template:
   "@
   jr5\t%0
   jr\t%0"
-  [(set_attr "type"   "branch,branch")
-   (set_attr "length" "     2,     4")])
+  [(set_attr "type"     "branch,branch")
+   (set_attr "is_16bit" "   yes,    no")])
 
 ;; Subroutine call instruction returning no value.
 ;;   operands[0]: It should be a mem RTX whose address is
@@ -1916,8 +1922,8 @@ create_template:
   "@
   jral5\t%0
   jral\t%0"
-  [(set_attr "type"   "branch,branch")
-   (set_attr "length" "     2,     4")])
+  [(set_attr "type"     "branch,branch")
+   (set_attr "is_16bit" "   yes,    no")])
 
 (define_insn "*call_immediate"
   [(parallel [(call (mem (match_operand:SI 0 "immediate_operand" "i"))
@@ -1964,8 +1970,8 @@ create_template:
   "@
   jral5\t%1
   jral\t%1"
-  [(set_attr "type"   "branch,branch")
-   (set_attr "length" "     2,     4")])
+  [(set_attr "type"     "branch,branch")
+   (set_attr "is_16bit" "   yes,    no")])
 
 (define_insn "*call_value_immediate"
   [(parallel [(set (match_operand 0)
@@ -2013,8 +2019,8 @@ create_template:
   "@
    jr5\t%0
    jr\t%0"
-  [(set_attr "type"   "branch,branch")
-   (set_attr "length" "     2,     4")])
+  [(set_attr "type"     "branch,branch")
+   (set_attr "is_16bit" "   yes,    no")])
 
 (define_insn "*sibcall_immediate"
   [(parallel [(call (mem (match_operand:SI 0 "immediate_operand" "i"))
@@ -2058,8 +2064,8 @@ create_template:
   "@
    jr5\t%1
    jr\t%1"
-  [(set_attr "type"   "branch,branch")
-   (set_attr "length" "     2,     4")])
+  [(set_attr "type"     "branch,branch")
+   (set_attr "is_16bit" "   yes,    no")])
 
 (define_insn "*sibcall_value_immediate"
   [(parallel [(set (match_operand 0)
@@ -2341,7 +2347,7 @@ create_template:
   "TARGET_PERF_EXT"
   "clz\t%0, %1"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 (define_insn "smaxsi3"
   [(set (match_operand:SI 0 "register_operand"          "=r")
@@ -2350,7 +2356,7 @@ create_template:
   "TARGET_PERF_EXT"
   "max\t%0, %1, %2"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 (define_insn "sminsi3"
   [(set (match_operand:SI 0 "register_operand"          "=r")
@@ -2359,7 +2365,7 @@ create_template:
   "TARGET_PERF_EXT"
   "min\t%0, %1, %2"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 (define_insn "*btst"
   [(set (match_operand:SI 0 "register_operand"                   "=   r")
@@ -2369,7 +2375,7 @@ create_template:
   "TARGET_PERF_EXT"
   "btst\t%0, %1, %2"
   [(set_attr "type" "alu")
-   (set_attr "length" "4")])
+   (set_attr "is_16bit" "no")])
 
 ;; ----------------------------------------------------------------------------
 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 04/22] Remove global which_alternative
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (2 preceding siblings ...)
  2015-11-25 12:26 ` [PR68432 03/22][NDS32] Remove "length" dependency from "enabled" attribute Richard Sandiford
@ 2015-11-25 12:28 ` Richard Sandiford
  2015-11-25 16:09   ` Bernd Schmidt
  2015-11-25 12:29 ` [PR68432 05/22] Add support attributes that operate on insn codes Richard Sandiford
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:28 UTC (permalink / raw)
  To: gcc-patches

Later patches in the series add a new form of attribute that takes the
attribute number as an argument, rather than it being stored in the
global which_alternative variable.

Having both a local alternative number and a global alternative number
is likely to cause confusion.  This patch therefore gets rid of the
global variable.

The main change is to get functions like constrain_operands to return
the number of the matching alternative, or -1 if none.  The cached
versions still use static state, but at least that state is now local
to recog.c and has a different name.

Tested as described in the covering note.

gcc/
	* recog.h (extract_constrain_insn): Return an int.
	(extract_constrain_insn_cached): Likewise.
	(which_alternative): Delete.
	(which_op_alt): Delete in favor of...
	(get_opt_alt): ...this new function.
	(insn_output_fn): Add an alternative number as argument.
	* recog.c (which_alternative): Delete in favor of...
	(cached_which_alternative): ...this.
	(get_bool_attr_mask_uncached): Update accordingly.
	(extract_insn): Likewise.
	(check_asm_operands): Check the return value of constrain_operands
	directly.
	(insn_invalid_p): Update check for whether constrain_operands was
	successful.
	(extract_constrain_insn): Return the matching alternative.
	(extract_constrain_insn_cached): Likewise.
	(constrain_operands_cached): Return the alternative number,
	or -1 on failure.  Use cached_which_alternative as the cache.
	(preprocess_insn_constraints): Update comment.
	(constrain_operands): Return the alternative number on success
	and -1 on failure.  Don't assign to which_alternative.
	* genattrtab.c (write_attr_case): Make which_alternative a local
	variable, set from the result of extract_constrain_insn_cached.
	* genoutput.c (process_template): Make the output functions take
	which_alternative as argument.
	* output.h (get_insn_template): Pass the alternative number too.
	Put the instruction argument first.
	* final.c (get_insn_template): Likewise.  Pass the alternative
	number down to the output function.
	(final_scan_insn): Update call accordingly.
	(output_asm_name): Use constrain_operands_cached instead of
	which_alternative.
	* postreload.c (reload_cse_simplify_operands): Use the return
	value of extract_constrain_insn instead of which_alternative.
	* config/s390/predicates.md (execute_operation): Likewise.
	* config/m68k/m68k.md (*movdf_internal, *addsi3_5200): Likewise.
	* regrename.c (hide_operands): Take the alternative number as
	argument.  Replace use of which_op_alt with get_op_alt.
	(record_out_operands): Likewise.
	(build_def_use): Update accordingly.  Also replace which_op_alt
	with get_op_alt here.
	* caller-save.c (reg_save_code): Update check for whether
	constrain_operands was successful.
	* ira.c (setup_prohibited_mode_move_regs): Likewise.
	* postreload-gcse.c (eliminate_partially_redundant_load): Likewise.
	* ree.c (combine_reaching_defs): Likewise.
	* reload.c (can_reload_into): Likewise.
	* reload1.c (reload): Likewise.
	(reload_as_needed): Likewise.
	(gen_reload_chain_without_interm_reg_p): Likewise.
	(emit_input_reload_insns): Likewise.
	(emit_insn_if_valid_for_reload): Likewise.
	(inc_for_reload): Likewise.
	* reorg.c (fill_slots_from_thread): Likewise.
	* config/pa/pa.c (pa_can_combine_p): Likewise.
	* config/rl78/rl78.c (insn_ok_now): Likewise.
	* config/alpha/alpha.c (alpha_end_function): Update call to
	get_insn_template.
	* config/rs6000/rs6000.c (rs6000_final_prescan_insn): Likewise.
	* reg-stack.c (check_asm_stack_operands): Replace use of
	which_op_alt with get_op_alt.
	(subst_asm_stack_regs): Likewise.
	* regcprop.c (copyprop_hardreg_forward_1): Likewise.
	* sel-sched.c (get_reg_class): Likewise.
	* config/arm/arm.c (note_invalid_constants): Likewise.
	* config/i386/i386.c (ix86_attr_length_address_default): Remove
	use of global which_alternative.
	(ix86_mitigate_rop): Replace use of which_op_alt with get_op_alt.
	* config/sparc/sparc-protos.h (output_v8plus_shift)
	(output_v8plus_mult): Add which_alternative argument.
	* config/sparc/sparc.c (output_v8plus_shift, output_v8plus_mult):
	Likewise.
	* config/sparc/sparc.md (muldi3_v8plus, umulxhi_v8plus, xmulx_v8plus)
	(xmulxhi_v8plus, ashldi3_v8plus, ashrdi3_v8plus, lshrdi3_v8plus):
	Update accordingly.
	* config/vax/vax-protos.h (vax_output_int_add): Add an alternative
	number as argument.
	(vax_output_int_subtract): Likewise.
	* config/vax/vax.c (vax_output_int_add): Update accordingly.
	(vax_output_int_subtract): Likewise.  Update calls to
	get_insn_template.
	* config/vax/vax.md (add<mode>3, adcdi3, adddi3_old, sbcdi3)
	(subdi3_old): Update accordingly.

diff --git a/gcc/caller-save.c b/gcc/caller-save.c
index 084d079..5a648c1 100644
--- a/gcc/caller-save.c
+++ b/gcc/caller-save.c
@@ -142,9 +142,9 @@ reg_save_code (int reg, machine_mode mode)
   if (ok)
     {
       extract_insn (saveinsn);
-      ok = constrain_operands (1, get_enabled_alternatives (saveinsn));
+      ok = constrain_operands (1, get_enabled_alternatives (saveinsn)) >= 0;
       extract_insn (restinsn);
-      ok &= constrain_operands (1, get_enabled_alternatives (restinsn));
+      ok &= constrain_operands (1, get_enabled_alternatives (restinsn)) >= 0;
     }
 
   if (! ok)
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 4cfae82..a85c836 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -8335,7 +8335,7 @@ alpha_end_function (FILE *file, const char *fnname, tree decl ATTRIBUTE_UNUSED)
   if (!INSN_P (insn))
     insn = prev_active_insn (insn);
   if (insn && CALL_P (insn))
-    output_asm_insn (get_insn_template (CODE_FOR_nop, NULL), NULL);
+    output_asm_insn (get_insn_template (NULL, CODE_FOR_nop, 0), NULL);
 
 #if TARGET_ABI_OPEN_VMS
   /* Write the linkage entries.  */
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index e0cdc20..ae3bfee 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17105,7 +17105,7 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
 {
   int opno;
 
-  extract_constrain_insn (insn);
+  int alt = extract_constrain_insn (insn);
 
   if (recog_data.n_alternatives == 0)
     return;
@@ -17114,7 +17114,7 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
      this insn.  */
   preprocess_constraints (insn);
 
-  const operand_alternative *op_alt = which_op_alt ();
+  const operand_alternative *op_alt = get_op_alt (alt);
   for (opno = 0; opno < recog_data.n_operands; opno++)
     {
       /* Things we need to fix can only occur in inputs.  */
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index cc42544..e81a368 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -27630,11 +27630,10 @@ ix86_attr_length_address_default (rtx_insn *insn)
       rtx op = recog_data.operand[i];
       if (MEM_P (op))
 	{
-	  constrain_operands_cached (insn, reload_completed);
-	  if (which_alternative != -1)
+	  int alt = constrain_operands_cached (insn, reload_completed);
+	  if (alt != -1)
 	    {
 	      const char *constraints = recog_data.constraints[i];
-	      int alt = which_alternative;
 
 	      while (*constraints == '=' || *constraints == '+')
 		constraints++;
@@ -45354,7 +45353,7 @@ ix86_mitigate_rop (void)
 	    continue;
 
 	  extract_insn (insn);
-	  constrain_operands_cached (insn, reload_completed);
+	  int alt = constrain_operands_cached (insn, reload_completed);
 	  int opno0, opno1;
 	  int modrm = ix86_get_modrm_for_rop (insn, recog_data.operand,
 					      recog_data.n_operands, &opno0,
@@ -45366,12 +45365,12 @@ ix86_mitigate_rop (void)
 
 	  rtx oldreg = recog_data.operand[opno1];
 	  preprocess_constraints (insn);
-	  const operand_alternative *alt = which_op_alt ();
+	  const operand_alternative *op_alt = get_op_alt (alt);
 
 	  int i;
 	  for (i = 0; i < recog_data.n_operands; i++)
 	    if (i != opno1
-		&& alt[i].earlyclobber
+		&& op_alt[i].earlyclobber
 		&& reg_overlap_mentioned_p (recog_data.operand[i],
 					    oldreg))
 	      break;
@@ -45383,7 +45382,7 @@ ix86_mitigate_rop (void)
 	    fprintf (dump_file,
 		     "attempting to fix modrm byte in insn %d:"
 		     " reg %d class %s", INSN_UID (insn), REGNO (oldreg),
-		     reg_class_names[alt[opno1].cl]);
+		     reg_class_names[op_alt[opno1].cl]);
 
 	  HARD_REG_SET unavailable;
 	  REG_SET_TO_HARD_REG_SET (unavailable, &live);
@@ -45392,7 +45391,7 @@ ix86_mitigate_rop (void)
 	  IOR_HARD_REG_SET (unavailable, fixed_reg_set);
 	  IOR_HARD_REG_SET (unavailable, output_risky);
 	  IOR_COMPL_HARD_REG_SET (unavailable,
-				  reg_class_contents[alt[opno1].cl]);
+				  reg_class_contents[op_alt[opno1].cl]);
 
 	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	      if (!TEST_HARD_REG_BIT (unavailable, i))
diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md
index 1eaf58f..1c7309b 100644
--- a/gcc/config/m68k/m68k.md
+++ b/gcc/config/m68k/m68k.md
@@ -283,7 +283,7 @@
   "@
    fmove%.d %f1,%0
    #"
-  "&& reload_completed && (extract_constrain_insn_cached (insn), which_alternative == 1)"
+  "&& reload_completed && extract_constrain_insn_cached (insn) == 1"
   [(const_int 0)]
 {
   m68k_emit_move_double (operands);
@@ -2514,7 +2514,9 @@
       return "";
     }
 }
-  "&& reload_completed && (extract_constrain_insn_cached (insn), which_alternative == 5) && !operands_match_p (operands[0], operands[1])"
+  "&& reload_completed
+   && extract_constrain_insn_cached (insn) == 5
+   && !operands_match_p (operands[0], operands[1])"
   [(set (match_dup 0)
 	(match_dup 2))
    (set (match_dup 0)
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index b8caab5..4b5d275 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -9133,7 +9133,8 @@ pa_can_combine_p (rtx_insn *new_rtx, rtx_insn *anchor, rtx_insn *floater,
   basic_block bb = BLOCK_FOR_INSN (anchor);
   if (insn_code_number < 0
       || (extract_insn (new_rtx),
-	  !constrain_operands (1, get_preferred_alternatives (new_rtx, bb))))
+	  (constrain_operands
+	   (1, get_preferred_alternatives (new_rtx, bb)) < 0)))
     return 0;
 
   if (reversed)
diff --git a/gcc/config/rl78/rl78.c b/gcc/config/rl78/rl78.c
index 9d136a4..f44dc3b 100644
--- a/gcc/config/rl78/rl78.c
+++ b/gcc/config/rl78/rl78.c
@@ -2494,7 +2494,7 @@ insn_ok_now (rtx_insn * insn)
   if (recog (pattern, insn, 0) > -1)
     {
       extract_insn (insn);
-      if (constrain_operands (1, get_preferred_alternatives (insn)))
+      if (constrain_operands (1, get_preferred_alternatives (insn)) >= 0)
 	{
 #if DEBUG_ALLOC
 	  fprintf (stderr, "\033[32m");
@@ -2523,7 +2523,7 @@ insn_ok_now (rtx_insn * insn)
       if (recog (pattern, insn, 0) > -1)
 	{
 	  extract_insn (insn);
-	  if (constrain_operands (0, get_preferred_alternatives (insn)))
+	  if (constrain_operands (0, get_preferred_alternatives (insn)) >= 0)
 	    {
 	      cfun->machine->virt_insns_ok = 0;
 	      return false;
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 457e9442..44f2075 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -34021,7 +34021,8 @@ rs6000_final_prescan_insn (rtx_insn *insn, rtx *operand ATTRIBUTE_UNUSED,
       if (insn_code_number < 0)
 	return;
 
-      temp = get_insn_template (insn_code_number, insn);
+      int alt = extract_constrain_insn_cached (insn);
+      temp = get_insn_template (insn, insn_code_number, alt);
 
       if (get_attr_cell_micro (insn) == CELL_MICRO_ALWAYS)
 	warning_at (location, OPT_mwarn_cell_microcode,
diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md
index 893092b..0718028 100644
--- a/gcc/config/s390/predicates.md
+++ b/gcc/config/s390/predicates.md
@@ -414,9 +414,7 @@
   if (icode < 0)
     return false;
 
-  extract_constrain_insn (insn);
-
-  return which_alternative >= 0;
+  return extract_constrain_insn (insn) >= 0;
 })
 
 ;; Return true if OP is a store multiple operation.  It is known to be a
diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h
index 1431437..39c2909 100644
--- a/gcc/config/sparc/sparc-protos.h
+++ b/gcc/config/sparc/sparc-protos.h
@@ -73,8 +73,8 @@ extern const char *output_ubranch (rtx, rtx_insn *);
 extern const char *output_cbranch (rtx, rtx, int, int, int, rtx_insn *);
 extern const char *output_return (rtx_insn *);
 extern const char *output_sibcall (rtx_insn *, rtx);
-extern const char *output_v8plus_shift (rtx_insn *, rtx *, const char *);
-extern const char *output_v8plus_mult (rtx_insn *, rtx *, const char *);
+extern const char *output_v8plus_shift (rtx_insn *, rtx *, const char *, int);
+extern const char *output_v8plus_mult (rtx_insn *, rtx *, const char *, int);
 extern const char *output_v9branch (rtx, rtx, int, int, int, int, rtx_insn *);
 extern const char *output_probe_stack_range (rtx, rtx);
 extern const char *output_cbcond (rtx, rtx, rtx_insn *);
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 9328723..c0bb126 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -9781,7 +9781,8 @@ sparc_check_64 (rtx x, rtx_insn *insn)
    OPERANDS are its operands and OPCODE is the mnemonic to be used.  */
 
 const char *
-output_v8plus_shift (rtx_insn *insn, rtx *operands, const char *opcode)
+output_v8plus_shift (rtx_insn *insn, rtx *operands, const char *opcode,
+		     int which_alternative)
 {
   static char asm_code[60];
 
@@ -12011,7 +12012,8 @@ sparc_preferred_reload_class (rtx x, reg_class_t rclass)
    OPERANDS are its operands and OPCODE is the mnemonic to be used.  */
 
 const char *
-output_v8plus_mult (rtx_insn *insn, rtx *operands, const char *opcode)
+output_v8plus_mult (rtx_insn *insn, rtx *operands, const char *opcode,
+		    int which_alternative)
 {
   char mulstr[32];
 
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index 9cc74f1..5c32689 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -4044,7 +4044,7 @@
    (clobber (match_scratch:SI 3 "=&h,X"))
    (clobber (match_scratch:SI 4 "=&h,X"))]
   "TARGET_V8PLUS"
-  "* return output_v8plus_mult (insn, operands, \"mulx\");"
+  "* return output_v8plus_mult (insn, operands, \"mulx\", which_alternative);"
   [(set_attr "type" "multi")
    (set_attr "length" "9,8")])
 
@@ -4484,7 +4484,7 @@
    (clobber (match_scratch:SI 3 "=&h,X"))
    (clobber (match_scratch:SI 4 "=&h,X"))]
   "TARGET_VIS3 && ! TARGET_ARCH64"
-  "* return output_v8plus_mult (insn, operands, \"umulxhi\");"
+  "* return output_v8plus_mult (insn, operands, \"umulxhi\", which_alternative);"
   [(set_attr "type" "imul")
    (set_attr "length" "9,8")])
 
@@ -4528,7 +4528,7 @@
    (clobber (match_scratch:SI 3 "=&h,X"))
    (clobber (match_scratch:SI 4 "=&h,X"))]
   "TARGET_VIS3 && ! TARGET_ARCH64"
-  "* return output_v8plus_mult (insn, operands, \"xmulx\");"
+  "* return output_v8plus_mult (insn, operands, \"xmulx\", which_alternative);"
   [(set_attr "type" "imul")
    (set_attr "length" "9,8")])
 
@@ -4578,7 +4578,7 @@
    (clobber (match_scratch:SI 3 "=&h,X"))
    (clobber (match_scratch:SI 4 "=&h,X"))]
   "TARGET_VIS3 && !TARGET_ARCH64"
-  "* return output_v8plus_mult (insn, operands, \"xmulxhi\");"
+  "* return output_v8plus_mult (insn, operands, \"xmulxhi\", which_alternative);"
   [(set_attr "type" "imul")
    (set_attr "length" "9,8")])
 
@@ -5952,7 +5952,7 @@
 		   (match_operand:SI 2 "arith_operand" "rI,rI,rI")))
    (clobber (match_scratch:SI 3 "=X,X,&h"))]
   "TARGET_V8PLUS"
-  "* return output_v8plus_shift (insn ,operands, \"sllx\");"
+  "* return output_v8plus_shift (insn ,operands, \"sllx\", which_alternative);"
   [(set_attr "type" "multi")
    (set_attr "length" "5,5,6")])
 
@@ -6061,7 +6061,7 @@
 		     (match_operand:SI 2 "arith_operand" "rI,rI,rI")))
    (clobber (match_scratch:SI 3 "=X,X,&h"))]
   "TARGET_V8PLUS"
-  "* return output_v8plus_shift (insn, operands, \"srax\");"
+  "* return output_v8plus_shift (insn, operands, \"srax\", which_alternative);"
   [(set_attr "type" "multi")
    (set_attr "length" "5,5,6")])
 
@@ -6150,7 +6150,7 @@
 		     (match_operand:SI 2 "arith_operand" "rI,rI,rI")))
    (clobber (match_scratch:SI 3 "=X,X,&h"))]
   "TARGET_V8PLUS"
-  "* return output_v8plus_shift (insn, operands, \"srlx\");"
+  "* return output_v8plus_shift (insn, operands, \"srlx\", which_alternative);"
   [(set_attr "type" "multi")
    (set_attr "length" "5,5,6")])
 
diff --git a/gcc/config/vax/vax-protos.h b/gcc/config/vax/vax-protos.h
index b9d0e5d..bf5347d 100644
--- a/gcc/config/vax/vax-protos.h
+++ b/gcc/config/vax/vax-protos.h
@@ -29,8 +29,8 @@ extern void print_operand (FILE *, rtx, int);
 extern void vax_notice_update_cc (rtx, rtx);
 extern void vax_expand_addsub_di_operands (rtx *, enum rtx_code);
 extern const char * vax_output_int_move (rtx, rtx *, machine_mode);
-extern const char * vax_output_int_add (rtx, rtx *, machine_mode);
-extern const char * vax_output_int_subtract (rtx, rtx *, machine_mode);
+extern const char * vax_output_int_add (rtx, int, rtx *, machine_mode);
+extern const char * vax_output_int_subtract (rtx, int, rtx *, machine_mode);
 extern const char * vax_output_movmemsi (rtx, rtx *);
 #endif /* RTX_CODE */
 
diff --git a/gcc/config/vax/vax.c b/gcc/config/vax/vax.c
index c059751..f323bf9 100644
--- a/gcc/config/vax/vax.c
+++ b/gcc/config/vax/vax.c
@@ -1340,7 +1340,7 @@ vax_output_int_move (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
    which are not modified very often.  */
 
 const char *
-vax_output_int_add (rtx insn, rtx *operands, machine_mode mode)
+vax_output_int_add (rtx insn, int alt, rtx *operands, machine_mode mode)
 {
   switch (mode)
     {
@@ -1367,7 +1367,7 @@ vax_output_int_add (rtx insn, rtx *operands, machine_mode mode)
 	    /* No reason to add a 0 to the low part and thus no carry, so just
 	       emit the appropriate add/sub instruction.  */
 	    if (low[2] == const0_rtx)
-	      return vax_output_int_add (NULL, operands, SImode);
+	      return vax_output_int_add (NULL, alt, operands, SImode);
 
 	    /* Are we doing addition or subtraction?  */
 	    sub = CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0;
@@ -1421,7 +1421,7 @@ vax_output_int_add (rtx insn, rtx *operands, machine_mode mode)
 	  output_asm_insn (pattern, low);
 	if (!carry)
 	  /* If CARRY is 0, we don't have any carry value to worry about.  */
-	  return get_insn_template (CODE_FOR_addsi3, insn);
+	  return get_insn_template (insn, CODE_FOR_addsi3, alt);
 	/* %0 = C + %1 + %2 */
 	if (!rtx_equal_p (operands[0], operands[1]))
 	  output_asm_insn ((operands[1] == const0_rtx
@@ -1550,7 +1550,7 @@ vax_output_int_add (rtx insn, rtx *operands, machine_mode mode)
 }
 
 const char *
-vax_output_int_subtract (rtx insn, rtx *operands, machine_mode mode)
+vax_output_int_subtract (rtx insn, int alt, rtx *operands, machine_mode mode)
 {
   switch (mode)
     {
@@ -1603,7 +1603,10 @@ vax_output_int_subtract (rtx insn, rtx *operands, machine_mode mode)
 	    if (low[2] == constm1_rtx)
 	      pattern = "decl %0";
 	    else if (low[2] == const0_rtx)
-	      pattern = get_insn_template (CODE_FOR_movsi, insn), carry = 0;
+	      {
+		pattern = get_insn_template (insn, CODE_FOR_movsi, alt);
+		carry = 0;
+	      }
 	    else
 	      pattern = "subl3 %2,%1,%0";
 	  }
@@ -1616,7 +1619,7 @@ vax_output_int_subtract (rtx insn, rtx *operands, machine_mode mode)
 	    return "sbwc %2,%0";
 	    /* %0 = %2 - %1 - C */
 	  }
-	return get_insn_template (CODE_FOR_subsi3, insn);
+	return get_insn_template (insn, CODE_FOR_subsi3, alt);
       }
 
     default:
diff --git a/gcc/config/vax/vax.md b/gcc/config/vax/vax.md
index d5caa15..8ac4663 100644
--- a/gcc/config/vax/vax.md
+++ b/gcc/config/vax/vax.md
@@ -371,7 +371,8 @@
 	(plus:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")
 		     (match_operand:VAXint 2 "general_operand" "nrmT")))]
   ""
-  "* return vax_output_int_add (insn, operands, <MODE>mode);")
+  "* return vax_output_int_add (insn, which_alternative, operands,
+				<MODE>mode);")
 
 (define_expand "adddi3"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
@@ -385,7 +386,7 @@
 	(plus:DI (match_operand:DI 1 "general_addsub_di_operand" "%0")
 		 (match_operand:DI 2 "general_addsub_di_operand" "nRr")))]
   "TARGET_QMATH"
-  "* return vax_output_int_add (insn, operands, DImode);")
+  "* return vax_output_int_add (insn, which_alternative, operands, DImode);")
 
 ;; The add-with-carry (adwc) instruction only accepts two operands.
 (define_insn "adddi3_old"
@@ -393,7 +394,7 @@
 	(plus:DI (match_operand:DI 1 "general_operand" "%0,ro>")
 		 (match_operand:DI 2 "general_operand" "Fsro,Fs")))]
   "!TARGET_QMATH"
-  "* return vax_output_int_add (insn, operands, DImode);")
+  "* return vax_output_int_add (insn, which_alternative, operands, DImode);")
 \f
 ;;- All kinds of subtract instructions.
 
@@ -427,7 +428,8 @@
 	(minus:DI (match_operand:DI 1 "general_addsub_di_operand" "0,I")
 		  (match_operand:DI 2 "general_addsub_di_operand" "nRr,Rr")))]
   "TARGET_QMATH"
-  "* return vax_output_int_subtract (insn, operands, DImode);")
+  "* return vax_output_int_subtract (insn, which_alternative,
+				     operands, DImode);")
 
 ;; The subtract-with-carry (sbwc) instruction only takes two operands.
 (define_insn "subdi3_old"
@@ -435,7 +437,8 @@
 	(minus:DI (match_operand:DI 1 "general_operand" "0,or>")
 		  (match_operand:DI 2 "general_operand" "Fsor,Fs")))]
   "!TARGET_QMATH"
-  "* return vax_output_int_subtract (insn, operands, DImode);")
+  "* return vax_output_int_subtract (insn, which_alternative,
+				     operands, DImode);")
 \f
 ;;- Multiply instructions.
 
diff --git a/gcc/final.c b/gcc/final.c
index 2f57b1b..1a081e8 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -2061,19 +2061,27 @@ final (rtx_insn *first, FILE *file, int optimize_p)
     }
 }
 \f
+/* Return the output code for alternative ALT of insn_code CODE.
+   If CODE uses an output function, INSN is the specific instruction
+   we want to generate, otherwise it is unused and can be null.
+
+   Note that an output function might write text directly to the
+   asm output file and simply return "".  */
+
 const char *
-get_insn_template (int code, rtx insn)
+get_insn_template (rtx insn, int code, int alt)
 {
   switch (insn_data[code].output_format)
     {
     case INSN_OUTPUT_FORMAT_SINGLE:
       return insn_data[code].output.single;
     case INSN_OUTPUT_FORMAT_MULTI:
-      return insn_data[code].output.multi[which_alternative];
+      return insn_data[code].output.multi[alt];
     case INSN_OUTPUT_FORMAT_FUNCTION:
       gcc_assert (insn);
       return (*insn_data[code].output.function) (recog_data.operand,
-						 as_a <rtx_insn *> (insn));
+						 as_a <rtx_insn *> (insn),
+						 alt);
 
     default:
       gcc_unreachable ();
@@ -2916,7 +2924,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    print_rtx_head = "";
 	  }
 
-	if (! constrain_operands_cached (insn, 1))
+	int alt = constrain_operands_cached (insn, 1);
+	if (alt < 0)
 	  fatal_insn_not_found (insn);
 
 	/* Some target machines need to prescan each insn before
@@ -2944,7 +2953,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	current_output_insn = debug_insn = insn;
 
 	/* Find the proper template for this insn.  */
-	templ = get_insn_template (insn_code_number, insn);
+	templ = get_insn_template (insn, insn_code_number, alt);
 
 	/* If the C code returns 0, it means that it is a jump insn
 	   which follows a deleted test insn, and that test insn
@@ -3422,7 +3431,8 @@ output_asm_name (void)
 	       ASM_COMMENT_START, INSN_UID (debug_insn),
 	       insn_data[num].name);
       if (insn_data[num].n_alternatives > 1)
-	fprintf (asm_out_file, "/%d", which_alternative + 1);
+	fprintf (asm_out_file, "/%d",
+		 constrain_operands_cached (debug_insn, 1) + 1);
 
       if (HAVE_ATTR_length)
 	fprintf (asm_out_file, "\t[length = %d]",
diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c
index 2caf8f6..36fdf8b 100644
--- a/gcc/genattrtab.c
+++ b/gcc/genattrtab.c
@@ -4278,31 +4278,41 @@ write_attr_case (FILE *outf, struct attr_desc *attr, struct attr_value *av,
   must_extract = must_constrain = address_used = 0;
   walk_attr_value (av->value);
 
+  int code_indent = indent + 2;
   if (must_constrain)
     {
+      code_indent += 2;
       write_indent (outf, indent + 2);
-      fprintf (outf, "extract_constrain_insn_cached (insn);\n");
+      fprintf (outf, "{\n");
+      write_indent (outf, code_indent);
+      fprintf (outf, "int which_alternative ATTRIBUTE_UNUSED = "
+	       "extract_constrain_insn_cached (insn);\n");
     }
   else if (must_extract)
     {
-      write_indent (outf, indent + 2);
+      write_indent (outf, code_indent);
       fprintf (outf, "extract_insn_cached (insn);\n");
     }
 
   attrs_to_cache = 0;
   if (av->num_insns == 1)
-    write_attr_set (outf, attr, indent + 2, av->value, prefix, suffix,
+    write_attr_set (outf, attr, code_indent, av->value, prefix, suffix,
 		    known_true, av->first_insn->def->insn_code,
 		    av->first_insn->def->insn_index, 0);
   else
-    write_attr_set (outf, attr, indent + 2, av->value, prefix, suffix,
+    write_attr_set (outf, attr, code_indent, av->value, prefix, suffix,
 		    known_true, -2, 0, 0);
 
   if (strncmp (prefix, "return", 6))
     {
-      write_indent (outf, indent + 2);
+      write_indent (outf, code_indent);
       fprintf (outf, "break;\n");
     }
+  if (code_indent != indent + 2)
+    {
+      write_indent (outf, indent + 2);
+      fprintf (outf, "}\n");
+    }
   fprintf (outf, "\n");
 }
 
diff --git a/gcc/genoutput.c b/gcc/genoutput.c
index ed9540d..d2e7dbc 100644
--- a/gcc/genoutput.c
+++ b/gcc/genoutput.c
@@ -627,7 +627,9 @@ process_template (struct data *d, const char *template_code)
       d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;
 
       puts ("\nstatic const char *");
-      printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n",
+      printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED,"
+	      " rtx_insn *insn ATTRIBUTE_UNUSED,"
+	      " int which_alternative ATTRIBUTE_UNUSED)\n",
 	      d->code_number);
       puts ("{");
       print_md_ptr_loc (template_code);
@@ -656,7 +658,9 @@ process_template (struct data *d, const char *template_code)
 	  d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;
 	  puts ("\nstatic const char *");
 	  printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, "
-		  "rtx_insn *insn ATTRIBUTE_UNUSED)\n", d->code_number);
+		  "rtx_insn *insn ATTRIBUTE_UNUSED, "
+		  "int which_alternative ATTRIBUTE_UNUSED)\n",
+		  d->code_number);
 	  puts ("{");
 	  puts ("  switch (which_alternative)\n    {");
 	}
diff --git a/gcc/ira.c b/gcc/ira.c
index 97edf8c..eae63a4 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -1755,7 +1755,7 @@ setup_prohibited_mode_move_regs (void)
 	  extract_insn (move_insn);
 	  /* We don't know whether the move will be in code that is optimized
 	     for size or speed, so consider all enabled alternatives.  */
-	  if (! constrain_operands (1, get_enabled_alternatives (move_insn)))
+	  if (constrain_operands (1, get_enabled_alternatives (move_insn)) < 0)
 	    continue;
 	  CLEAR_HARD_REG_BIT (ira_prohibited_mode_move_regs[i], j);
 	}
diff --git a/gcc/output.h b/gcc/output.h
index d485cd6..27c8df9 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -149,7 +149,7 @@ extern int only_leaf_regs_used (void);
 extern void leaf_renumber_regs_insn (rtx);
 
 /* Locate the proper template for the given insn-code.  */
-extern const char *get_insn_template (int, rtx);
+extern const char *get_insn_template (rtx, int, int);
 
 /* Functions in varasm.c.  */
 
diff --git a/gcc/postreload-gcse.c b/gcc/postreload-gcse.c
index f8a770e..d63e7969 100644
--- a/gcc/postreload-gcse.c
+++ b/gcc/postreload-gcse.c
@@ -1087,8 +1087,8 @@ eliminate_partially_redundant_load (basic_block bb, rtx_insn *insn,
 	  rtx_insn *move = gen_move_insn (copy_rtx (dest),
 					  copy_rtx (avail_reg));
 	  extract_insn (move);
-	  if (! constrain_operands (1, get_preferred_alternatives (insn,
-								   pred_bb))
+	  if (constrain_operands (1, get_preferred_alternatives (insn,
+								 pred_bb)) < 0
 	      || reg_killed_on_edge (avail_reg, pred)
 	      || reg_used_on_edge (dest, pred))
 	    {
diff --git a/gcc/postreload.c b/gcc/postreload.c
index 1186bc0..f8df2d7 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -391,7 +391,7 @@ reload_cse_simplify_operands (rtx_insn *insn, rtx testreg)
   /* Array of alternatives, sorted in order of decreasing desirability.  */
   int *alternative_order;
 
-  extract_constrain_insn (insn);
+  int alt = extract_constrain_insn (insn);
 
   if (recog_data.n_alternatives == 0 || recog_data.n_operands == 0)
     return 0;
@@ -583,7 +583,7 @@ reload_cse_simplify_operands (rtx_insn *insn, rtx testreg)
   /* Record all alternatives which are better or equal to the currently
      matching one in the alternative_order array.  */
   for (i = j = 0; i < recog_data.n_alternatives; i++)
-    if (alternative_reject[i] <= alternative_reject[which_alternative])
+    if (alternative_reject[i] <= alternative_reject[alt])
       alternative_order[j++] = i;
   recog_data.n_alternatives = j;
 
diff --git a/gcc/recog.c b/gcc/recog.c
index 028190a..04228f8 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -78,10 +78,10 @@ const operand_alternative *recog_op_alt;
 static operand_alternative asm_op_alt[MAX_RECOG_OPERANDS
 				      * MAX_RECOG_ALTERNATIVES];
 
-/* On return from `constrain_operands', indicate which alternative
-   was satisfied.  */
+/* Used by constrain_operands_cached to record the matching alternative.
+   Only valid if nonnegative.  */
 
-int which_alternative;
+static int cached_which_alternative;
 
 /* Nonzero after end of reload pass.
    Set to 1 or 0 by toplev.c.
@@ -148,8 +148,7 @@ check_asm_operands (rtx x)
       /* ??? Doh!  We've not got the wrapping insn.  Cook one up.  */
       rtx_insn *insn = make_insn_raw (x);
       extract_insn (insn);
-      constrain_operands (1, get_enabled_alternatives (insn));
-      return which_alternative >= 0;
+      return constrain_operands (1, get_enabled_alternatives (insn)) >= 0;
     }
 
   noperands = asm_noperands (x);
@@ -352,7 +351,7 @@ insn_invalid_p (rtx_insn *insn, bool in_group)
     {
       extract_insn (insn);
 
-      if (! constrain_operands (1, get_preferred_alternatives (insn)))
+      if (constrain_operands (1, get_preferred_alternatives (insn)) < 0)
 	return 1;
     }
 
@@ -2070,20 +2069,20 @@ get_bool_attr_mask_uncached (rtx_insn *insn, bool_attr attr)
      mustn't depend on the values of operands, so we don't provide their
      real values here.  */
   rtx_insn *old_insn = recog_data.insn;
-  int old_alternative = which_alternative;
+  int old_alternative = cached_which_alternative;
 
   recog_data.insn = insn;
   alternative_mask mask = ALL_ALTERNATIVES;
   int n_alternatives = insn_data[INSN_CODE (insn)].n_alternatives;
   for (int i = 0; i < n_alternatives; i++)
     {
-      which_alternative = i;
+      cached_which_alternative = i;
       if (!get_bool_attr (insn, attr))
 	mask &= ~ALTERNATIVE_BIT (i);
     }
 
   recog_data.insn = old_insn;
-  which_alternative = old_alternative;
+  cached_which_alternative = old_alternative;
   return mask;
 }
 
@@ -2179,36 +2178,43 @@ extract_insn_cached (rtx_insn *insn)
 }
 
 /* Do uncached extract_insn, constrain_operands and complain about failures.
+   Return the number of the matching alternative.
+
    This should be used when extracting a pre-existing constrained instruction
    if the caller wants to know which alternative was chosen.  */
-void
+int
 extract_constrain_insn (rtx_insn *insn)
 {
   extract_insn (insn);
-  if (!constrain_operands (reload_completed, get_enabled_alternatives (insn)))
+  int alt = constrain_operands (reload_completed,
+				get_enabled_alternatives (insn));
+  if (alt < 0)
     fatal_insn_not_found (insn);
+  return alt;
 }
 
 /* Do cached extract_insn, constrain_operands and complain about failures.
+   Return the number of the matching alternative.
+
    Used by insn_attrtab.  */
-void
+int
 extract_constrain_insn_cached (rtx_insn *insn)
 {
   extract_insn_cached (insn);
-  if (which_alternative == -1
-      && !constrain_operands (reload_completed,
-			      get_enabled_alternatives (insn)))
+  int alt = constrain_operands_cached (insn, reload_completed);
+  if (alt < 0)
     fatal_insn_not_found (insn);
+  return alt;
 }
 
-/* Do cached constrain_operands on INSN and complain about failures.  */
+/* Do cached constrain_operands on INSN.  Return -1 on failure.  */
 int
 constrain_operands_cached (rtx_insn *insn, int strict)
 {
-  if (which_alternative == -1)
-    return constrain_operands (strict, get_enabled_alternatives (insn));
-  else
-    return 1;
+  if (cached_which_alternative == -1)
+    cached_which_alternative
+      = constrain_operands (strict, get_enabled_alternatives (insn));
+  return cached_which_alternative;
 }
 \f
 /* Analyze INSN and fill in recog_data.  */
@@ -2310,7 +2316,7 @@ extract_insn (rtx_insn *insn)
   gcc_assert (recog_data.n_alternatives <= MAX_RECOG_ALTERNATIVES);
 
   recog_data.insn = NULL;
-  which_alternative = -1;
+  cached_which_alternative = -1;
 }
 
 /* Fill in OP_ALT_BASE for an instruction that has N_OPERANDS operands,
@@ -2439,7 +2445,7 @@ preprocess_insn_constraints (unsigned int icode)
   int n_operands = insn_data[icode].n_operands;
   if (n_operands == 0)
     return 0;
-  /* Always provide at least one alternative so that which_op_alt ()
+  /* Always provide at least one alternative so that get_op_alt ()
      works correctly.  If the instruction has 0 alternatives (i.e. all
      constraint strings are empty) then each operand in this alternative
      will have anything_ok set.  */
@@ -2479,16 +2485,12 @@ preprocess_constraints (rtx_insn *insn)
     }
 }
 
-/* Check the operands of an insn against the insn's operand constraints
-   and return 1 if they match any of the alternatives in ALTERNATIVES.
+/* Check the operands of an insn against the insn's operand constraints.
+   Return the matching alternative number on success, otherwise return -1.
 
    The information about the insn's operands, constraints, operand modes
    etc. is obtained from the global variables set up by extract_insn.
 
-   WHICH_ALTERNATIVE is set to a number which indicates which
-   alternative of constraints was matched: 0 for the first alternative,
-   1 for the next, etc.
-
    In addition, when two operands are required to match
    and it happens that the output operand is (reg) while the
    input operand is --(reg) or ++(reg) (a pre-inc or pre-dec),
@@ -2523,9 +2525,8 @@ constrain_operands (int strict, alternative_mask alternatives)
   struct funny_match funny_match[MAX_RECOG_OPERANDS];
   int funny_match_index;
 
-  which_alternative = 0;
   if (recog_data.n_operands == 0 || recog_data.n_alternatives == 0)
-    return 1;
+    return 0;
 
   for (c = 0; c < recog_data.n_operands; c++)
     {
@@ -2533,6 +2534,7 @@ constrain_operands (int strict, alternative_mask alternatives)
       matching_operands[c] = -1;
     }
 
+  int which_alternative = 0;
   do
     {
       int seen_earlyclobber_at = -1;
@@ -2806,14 +2808,14 @@ constrain_operands (int strict, alternative_mask alternatives)
 			  if (strchr (recog_data.constraints[opno], '<') == NULL
 			      && strchr (recog_data.constraints[opno], '>')
 				 == NULL)
-			    return 0;
+			    return -1;
 			  break;
 			default:
 			  break;
 			}
 		}
 
-	      return 1;
+	      return which_alternative;
 	    }
 	}
 
@@ -2821,13 +2823,12 @@ constrain_operands (int strict, alternative_mask alternatives)
     }
   while (which_alternative < recog_data.n_alternatives);
 
-  which_alternative = -1;
   /* If we are about to reject this, but we are not to test strictly,
      try a very loose test.  Only return failure if it fails also.  */
   if (strict == 0)
     return constrain_operands (-1, alternatives);
   else
-    return 0;
+    return -1;
 }
 
 /* Return true iff OPERAND (assumed to be a REG rtx)
diff --git a/gcc/recog.h b/gcc/recog.h
index 327d6c0..b15140b 100644
--- a/gcc/recog.h
+++ b/gcc/recog.h
@@ -132,8 +132,8 @@ extern void add_clobbers (rtx, int);
 extern int added_clobbers_hard_reg_p (int);
 extern void insn_extract (rtx_insn *);
 extern void extract_insn (rtx_insn *);
-extern void extract_constrain_insn (rtx_insn *insn);
-extern void extract_constrain_insn_cached (rtx_insn *);
+extern int extract_constrain_insn (rtx_insn *insn);
+extern int extract_constrain_insn_cached (rtx_insn *);
 extern void extract_insn_cached (rtx_insn *);
 extern void preprocess_constraints (int, int, const char **,
 				    operand_alternative *);
@@ -186,10 +186,6 @@ skip_alternative (const char *p)
 /* Nonzero means volatile operands are recognized.  */
 extern int volatile_ok;
 
-/* Set by constrain_operands to the number of the alternative that
-   matched.  */
-extern int which_alternative;
-
 /* The following vectors hold the results from insn_extract.  */
 
 struct recog_data_d
@@ -257,22 +253,21 @@ extern struct recog_data_d recog_data;
 extern const operand_alternative *recog_op_alt;
 
 /* Return a pointer to an array in which index OP describes the constraints
-   on operand OP of the current instruction alternative (which_alternative).
+   on operand OP for alternative ALT of the current instruction.
    Only valid after calling preprocess_constraints and constrain_operands.  */
 
 inline static const operand_alternative *
-which_op_alt ()
+get_op_alt (int alt)
 {
-  gcc_checking_assert (IN_RANGE (which_alternative, 0,
-				 recog_data.n_alternatives - 1));
-  return &recog_op_alt[which_alternative * recog_data.n_operands];
+  gcc_checking_assert (IN_RANGE (alt, 0, recog_data.n_alternatives - 1));
+  return &recog_op_alt[alt * recog_data.n_operands];
 }
 
 /* A table defined in insn-output.c that give information about
    each insn-code value.  */
 
 typedef int (*insn_operand_predicate_fn) (rtx, machine_mode);
-typedef const char * (*insn_output_fn) (rtx *, rtx_insn *);
+typedef const char * (*insn_output_fn) (rtx *, rtx_insn *, int);
 
 struct insn_gen_fn
 {
diff --git a/gcc/ree.c b/gcc/ree.c
index f3b79e0..c641ba7 100644
--- a/gcc/ree.c
+++ b/gcc/ree.c
@@ -840,7 +840,7 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
       if (recog_memoized (insn) == -1)
 	return false;
       extract_insn (insn);
-      if (!constrain_operands (1, get_preferred_alternatives (insn, bb)))
+      if (constrain_operands (1, get_preferred_alternatives (insn, bb)) < 0)
 	return false;
     }
 
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index 8cc0fa4..be9e1b2 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -467,20 +467,20 @@ check_asm_stack_operands (rtx_insn *insn)
 
   /* Find out what the constraints require.  If no constraint
      alternative matches, this asm is malformed.  */
-  extract_constrain_insn (insn);
+  int alt = extract_constrain_insn (insn);
 
   preprocess_constraints (insn);
 
   get_asm_operands_in_out (body, &n_outputs, &n_inputs);
 
-  if (which_alternative < 0)
+  if (alt < 0)
     {
       malformed_asm = 1;
       /* Avoid further trouble with this insn.  */
       PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
       return 0;
     }
-  const operand_alternative *op_alt = which_op_alt ();
+  const operand_alternative *op_alt = get_op_alt (alt);
 
   /* Strip SUBREGs here to make the following code simpler.  */
   for (i = 0; i < recog_data.n_operands; i++)
@@ -2002,10 +2002,10 @@ subst_asm_stack_regs (rtx_insn *insn, stack_ptr regstack)
   /* Find out what the constraints required.  If no constraint
      alternative matches, that is a compiler bug: we should have caught
      such an insn in check_asm_stack_operands.  */
-  extract_constrain_insn (insn);
+  int alt = extract_constrain_insn (insn);
 
   preprocess_constraints (insn);
-  const operand_alternative *op_alt = which_op_alt ();
+  const operand_alternative *op_alt = get_op_alt (alt);
 
   get_asm_operands_in_out (body, &n_outputs, &n_inputs);
 
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index f0723a1..833fe6c 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -769,9 +769,9 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
 	}
 
       set = single_set (insn);
-      extract_constrain_insn (insn);
+      int alt = extract_constrain_insn (insn);
       preprocess_constraints (insn);
-      const operand_alternative *op_alt = which_op_alt ();
+      const operand_alternative *op_alt = get_op_alt (alt);
       n_ops = recog_data.n_operands;
       is_asm = asm_noperands (PATTERN (insn)) >= 0;
 
@@ -870,8 +870,9 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
 		}
 	      /* We need to re-extract as validate_change clobbers
 		 recog_data.  */
-	      extract_constrain_insn (insn);
+	      alt = extract_constrain_insn (insn);
 	      preprocess_constraints (insn);
+	      op_alt = get_op_alt (alt);
 	    }
 
 	  /* Otherwise, try all valid registers and see if its valid.  */
@@ -896,8 +897,9 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
 		    }
 		  /* We need to re-extract as validate_change clobbers
 		     recog_data.  */
-		  extract_constrain_insn (insn);
+		  alt = extract_constrain_insn (insn);
 		  preprocess_constraints (insn);
+		  op_alt = get_op_alt (alt);
 		}
 	    }
 	}
diff --git a/gcc/regrename.c b/gcc/regrename.c
index e2a1e83..4f223ab 100644
--- a/gcc/regrename.c
+++ b/gcc/regrename.c
@@ -1480,18 +1480,18 @@ scan_rtx (rtx_insn *insn, rtx *loc, enum reg_class cl, enum scan_actions action,
 }
 
 /* Hide operands of the current insn (of which there are N_OPS) by
-   substituting cc0 for them.
-   Previous values are stored in the OLD_OPERANDS and OLD_DUPS.
-   For every bit set in DO_NOT_HIDE, we leave the operand alone.
-   If INOUT_AND_EC_ONLY is set, we only do this for OP_INOUT type operands
-   and earlyclobbers.  */
+   substituting cc0 for them.  ALT is the number of the matching
+   alternative.  Previous values are stored in the OLD_OPERANDS and
+   OLD_DUPS.  For every bit set in DO_NOT_HIDE, we leave the operand
+   alone.  If INOUT_AND_EC_ONLY is set, we only do this for OP_INOUT
+   type operands and earlyclobbers.  */
 
 static void
-hide_operands (int n_ops, rtx *old_operands, rtx *old_dups,
+hide_operands (int alt, int n_ops, rtx *old_operands, rtx *old_dups,
 	       unsigned HOST_WIDE_INT do_not_hide, bool inout_and_ec_only)
 {
   int i;
-  const operand_alternative *op_alt = which_op_alt ();
+  const operand_alternative *op_alt = get_op_alt (alt);
   for (i = 0; i < n_ops; i++)
     {
       old_operands[i] = recog_data.operand[i];
@@ -1536,13 +1536,15 @@ restore_operands (rtx_insn *insn, int n_ops, rtx *old_operands, rtx *old_dups)
 /* For each output operand of INSN, call scan_rtx to create a new
    open chain.  Do this only for normal or earlyclobber outputs,
    depending on EARLYCLOBBER.  If INSN_INFO is nonnull, use it to
-   record information about the operands in the insn.  */
+   record information about the operands in the insn.  ALT is the
+   number of the matching alternative.  */
 
 static void
-record_out_operands (rtx_insn *insn, bool earlyclobber, insn_rr_info *insn_info)
+record_out_operands (rtx_insn *insn, int alt, bool earlyclobber,
+		     insn_rr_info *insn_info)
 {
   int n_ops = recog_data.n_operands;
-  const operand_alternative *op_alt = which_op_alt ();
+  const operand_alternative *op_alt = get_op_alt (alt);
 
   int i;
 
@@ -1634,9 +1636,9 @@ build_def_use (basic_block bb)
 	     to be marked unrenamable or even cause us to abort the entire
 	     basic block.  */
 
-	  extract_constrain_insn (insn);
+	  int alt = extract_constrain_insn (insn);
 	  preprocess_constraints (insn);
-	  const operand_alternative *op_alt = which_op_alt ();
+	  const operand_alternative *op_alt = get_op_alt (alt);
 	  n_ops = recog_data.n_operands;
 	  untracked_operands = 0;
 
@@ -1692,22 +1694,22 @@ build_def_use (basic_block bb)
 
 	  /* Step 1a: Mark hard registers that are clobbered in this insn,
 	     outside an operand, as live.  */
-	  hide_operands (n_ops, old_operands, old_dups, untracked_operands,
-			 false);
+	  hide_operands (alt, n_ops, old_operands, old_dups,
+			 untracked_operands, false);
 	  note_stores (PATTERN (insn), note_sets_clobbers, &clobber_code);
 	  restore_operands (insn, n_ops, old_operands, old_dups);
 
 	  /* Step 1b: Begin new chains for earlyclobbered writes inside
 	     operands.  */
-	  record_out_operands (insn, true, insn_info);
+	  record_out_operands (insn, alt, true, insn_info);
 
 	  /* Step 2: Mark chains for which we have reads outside operands
 	     as unrenamable.
 	     We do this by munging all operands into CC0, and closing
 	     everything remaining.  */
 
-	  hide_operands (n_ops, old_operands, old_dups, untracked_operands,
-			 false);
+	  hide_operands (alt, n_ops, old_operands, old_dups,
+			 untracked_operands, false);
 	  scan_rtx (insn, &PATTERN (insn), NO_REGS, mark_all_read, OP_IN);
 	  restore_operands (insn, n_ops, old_operands, old_dups);
 
@@ -1801,20 +1803,20 @@ build_def_use (basic_block bb)
 	     the previous insn at the latest, as such operands cannot
 	     possibly overlap with any input operands.  */
 
-	  hide_operands (n_ops, old_operands, old_dups, untracked_operands,
-			 true);
+	  hide_operands (alt, n_ops, old_operands, old_dups,
+			 untracked_operands, true);
 	  scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_write, OP_IN);
 	  restore_operands (insn, n_ops, old_operands, old_dups);
 
 	  /* Step 6a: Mark hard registers that are set in this insn,
 	     outside an operand, as live.  */
-	  hide_operands (n_ops, old_operands, old_dups, untracked_operands,
-			 false);
+	  hide_operands (alt, n_ops, old_operands, old_dups,
+			 untracked_operands, false);
 	  note_stores (PATTERN (insn), note_sets_clobbers, &set_code);
 	  restore_operands (insn, n_ops, old_operands, old_dups);
 
 	  /* Step 6b: Begin new chains for writes inside operands.  */
-	  record_out_operands (insn, false, insn_info);
+	  record_out_operands (insn, alt, false, insn_info);
 
 	  /* Step 6c: Record destination regs in REG_FRAME_RELATED_EXPR
 	     notes for update.  */
diff --git a/gcc/reload.c b/gcc/reload.c
index 1e96dfc..c41a7b1 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -910,7 +910,7 @@ can_reload_into (rtx in, int regno, machine_mode mode)
   if (recog_memoized (test_insn) >= 0)
     {
       extract_insn (test_insn);
-      r = constrain_operands (1, get_enabled_alternatives (test_insn));
+      r = constrain_operands (1, get_enabled_alternatives (test_insn)) >= 0;
     }
   recog_data = save_recog_data;
   return r;
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 4f1910b..92a0050 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -1248,7 +1248,7 @@ reload (rtx_insn *first, int global)
 	if (asm_noperands (PATTERN (insn)) >= 0)
 	  {
 	    extract_insn (insn);
-	    if (!constrain_operands (1, get_enabled_alternatives (insn)))
+	    if (constrain_operands (1, get_enabled_alternatives (insn)) < 0)
 	      {
 		error_for_asm (insn,
 			       "%<asm%> operand has impossible constraints");
@@ -4712,8 +4712,8 @@ reload_as_needed (int live_known)
 		      && GET_CODE (PATTERN (p)) != USE
 		      && (recog_memoized (p) < 0
 			  || (extract_insn (p),
-			      !(constrain_operands (1,
-				  get_enabled_alternatives (p))))))
+			      (constrain_operands
+			       (1, get_enabled_alternatives (p)) < 0))))
 		    {
 		      error_for_asm (insn,
 				     "%<asm%> operand requires "
@@ -4796,8 +4796,8 @@ reload_as_needed (int live_known)
 			      if (n)
 				{
 				  extract_insn (p);
-				  n = constrain_operands (1,
-				    get_enabled_alternatives (p));
+				  n = constrain_operands
+				    (1, get_enabled_alternatives (p)) >= 0;
 				}
 
 			      /* If the constraints were not met, then
@@ -5717,7 +5717,8 @@ gen_reload_chain_without_interm_reg_p (int r1, int r2)
 	  /* We want constrain operands to treat this insn strictly in
 	     its validity determination, i.e., the way it would after
 	     reload has completed.  */
-	  result = constrain_operands (1, get_enabled_alternatives (insn));
+	  result =
+	    constrain_operands (1, get_enabled_alternatives (insn)) >= 0;
 	}
 
       delete_insns_since (last);
@@ -7387,7 +7388,7 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
 	     autoincrement addressing mode, then the resulting insn
 	     is ill-formed and we must reject this optimization.  */
 	  extract_insn (temp);
-	  if (constrain_operands (1, get_enabled_alternatives (temp))
+	  if (constrain_operands (1, get_enabled_alternatives (temp)) >= 0
 	      && (!AUTO_INC_DEC || ! find_reg_note (temp, REG_INC, reloadreg)))
 	    {
 	      /* If the previous insn is an output reload, the source is
@@ -8571,7 +8572,7 @@ emit_insn_if_valid_for_reload (rtx pat)
       /* We want constrain operands to treat this insn strictly in its
 	 validity determination, i.e., the way it would after reload has
 	 completed.  */
-      if (constrain_operands (1, get_enabled_alternatives (insn)))
+      if (constrain_operands (1, get_enabled_alternatives (insn)) >= 0)
 	return insn;
     }
 
@@ -9204,7 +9205,7 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount)
       if (code >= 0)
 	{
 	  extract_insn (add_insn);
-	  if (constrain_operands (1, get_enabled_alternatives (add_insn)))
+	  if (constrain_operands (1, get_enabled_alternatives (add_insn)) >= 0)
 	    {
 	      /* If this is a pre-increment and we have incremented the value
 		 where it lives, copy the incremented value to RELOADREG to
diff --git a/gcc/reorg.c b/gcc/reorg.c
index cc68d6b..96a6a97 100644
--- a/gcc/reorg.c
+++ b/gcc/reorg.c
@@ -2708,7 +2708,8 @@ fill_slots_from_thread (rtx_jump_insn *insn, rtx condition,
 
 	  if (recog_memoized (ninsn) < 0
 	      || (extract_insn (ninsn),
-		  !constrain_operands (1, get_preferred_alternatives (ninsn))))
+		  (constrain_operands
+		   (1, get_preferred_alternatives (ninsn)) < 0)))
 	    {
 	      delete_related_insns (ninsn);
 	      return;
diff --git a/gcc/sel-sched.c b/gcc/sel-sched.c
index aebc2d9..f4966ee 100644
--- a/gcc/sel-sched.c
+++ b/gcc/sel-sched.c
@@ -985,11 +985,11 @@ get_reg_class (rtx_insn *insn)
 {
   int i, n_ops;
 
-  extract_constrain_insn (insn);
+  int alt = extract_constrain_insn (insn);
   preprocess_constraints (insn);
   n_ops = recog_data.n_operands;
 
-  const operand_alternative *op_alt = which_op_alt ();
+  const operand_alternative *op_alt = get_op_alt (alt);
   if (asm_noperands (PATTERN (insn)) > 0)
     {
       for (i = 0; i < n_ops; i++)

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 06/22] Use code,alternative attributes for aarch64
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (4 preceding siblings ...)
  2015-11-25 12:29 ` [PR68432 05/22] Add support attributes that operate on insn codes Richard Sandiford
@ 2015-11-25 12:29 ` Richard Sandiford
  2015-11-25 12:30 ` [PR68432 07/22] Use code,alternative attributes for alpha Richard Sandiford
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:29 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/aarch64/aarch64.md (fp): Turn into a code,alternative
	attribute.
	(simd, enabled): Likewise.

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index d46f837..a6f312f 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -166,12 +166,12 @@
 ;; Attribute that specifies whether or not the instruction touches fp
 ;; registers.  When this is set to yes for an alternative, that alternative
 ;; will be disabled when !TARGET_FLOAT.
-(define_attr "fp" "no,yes" (const_string "no"))
+(define_attr "fp" "no,yes" (const_string "no") "code,alternative")
 
 ;; Attribute that specifies whether or not the instruction touches simd
 ;; registers.  When this is set to yes for an alternative, that alternative
 ;; will be disabled when !TARGET_SIMD.
-(define_attr "simd" "no,yes" (const_string "no"))
+(define_attr "simd" "no,yes" (const_string "no") "code,alternative")
 
 (define_attr "length" ""
   (const_int 4))
@@ -186,7 +186,8 @@
 	(and (eq_attr "simd" "yes")
 	     (eq (symbol_ref "TARGET_SIMD") (const_int 0))))
 	     (const_string "no")
-	] (const_string "yes")))
+	] (const_string "yes"))
+  "code,alternative")
 
 ;; Attribute that specifies whether we are dealing with a branch to a
 ;; label that is far away, i.e. further away than the maximum/minimum

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 05/22] Add support attributes that operate on insn codes
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (3 preceding siblings ...)
  2015-11-25 12:28 ` [PR68432 04/22] Remove global which_alternative Richard Sandiford
@ 2015-11-25 12:29 ` Richard Sandiford
  2015-11-25 12:29 ` [PR68432 06/22] Use code,alternative attributes for aarch64 Richard Sandiford
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:29 UTC (permalink / raw)
  To: gcc-patches

This patch adds a new type of attribute whose function takes only
the instruction code and alternative number as argument, rather than
an rtx_insn *.  This makes it possible to call the functions from
the gimple level without having to construct rtl first.  For convenience
(and consistency) the new attributes still provide an rtx_insn * interface
too.

The patch adds a new optional type operand to DEFINE_ATTR and
DEFINE_ENUM_ATTR.  "" or "insn" selects the general rtx_insn * style
and "code,alternative" selects the new more limited form.

The patch also uses _Pragma ("GCC error ...") to trap uses of recog_data
in the new functions.  This isn't a particularly strong safety net but
should be much better than nothing (and what we have now).

enabled, preferred_for_size and preferred_for_speed were already supposed
to be suitable for "code,alternative", we just never enforced it until now.
Later patches in the series make this change to each port in turn.

Tested as described in the covering note.  I think this comes under
the gen* maintainership, but I'd welcome comments all the same.

gcc/
	* doc/md.texi: Document new define_attr field.
	* rtl.def (DEFINE_ATTR, DEFINE_ENUM_ATTR): Add a string type.
	* genattr.c (declare_function): New function.
	(gen_attr): Use it.  Call parse_attr_type.  Declare a code/alternative
	function if appropriate.  Do not output a prototype for constant
	attributes.
	* genattrtab.c (attr_desc): Replace the boolean is_const field with
	an attr_type field.
	(attr_desc::is_const): New function.
	(check_attr_value): Update accordingly.  Use get_attr_type_name.
	Make sure that attributes don't refer to other attributes with
	a higher type.
	(match_attr_test): Likewise.  Make sure that only AT_INSN attributes
	use match_operand.
	(make_canonical): Update after changes to attr_desc.
	(fill_attr, make_length_attrs, get_attr_order, make_internal_attr)
	(find_tune_attr, make_automaton_attrs, main): Likewise.
	(gen_attr): Use parse_attr_type.
	(find_attrs_to_cache): Only cache AT_INSN attributes.
	(write_test_expr): Pass the code and alternative number when
	calling an AT_CODE_ALT function.
	(walk_attr_value): Require an alternative number when calling
	an AT_CODE_ALT function.
	(write_attr_return_type): New function.
	(write_attr_get): Remove constant handling and assert that it
	isn't needed instead.  Handle AT_CODE_ALT functions.
	Use write_attr_return_type.  Make sure that the instruction
	code is always available in a variable called "icode".
	(write_attr_case): Limit asm handling to AT_INSN.  Likewise
	must_constrain and must_extract.
	(write_attr_value): Use write_attr_return_type.
	(find_attr): Use memset to clear the structure, rather than
	writing zero values.  Initialize the type field.
	(gen_insn_reserv): Initialize the type field.
	* read-rtl.c (add_define_attr_for_define_subst): Initialize the
	fourth DEFINE_ATTR field.
	* gensupport.h (attr_type): New enum.
	(parse_attr_type, get_attr_type_name): Declare.
	* gensupport.c (add_define_attr): Take a type argument and use it
	to initialize the fourth DEFINE_ATTR field.
	(alter_attrs_for_insn): Set the ce_enabled and noce_enabled
	attributes to the same type as "enabled".
	(parse_attr_type, get_attr_type_name): New functions.

diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index de1b58a..5d3736c 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -8070,7 +8070,7 @@ The @code{define_attr} expression is used to define each attribute required
 by the target machine.  It looks like:
 
 @smallexample
-(define_attr @var{name} @var{list-of-values} @var{default})
+(define_attr @var{name} @var{list-of-values} @var{default} @var{type})
 @end smallexample
 
 @var{name} is a string specifying the name of the attribute being
@@ -8095,6 +8095,25 @@ an explicit value for this attribute.  @xref{Attr Example}, for more
 information on the handling of defaults.  @xref{Constant Attributes},
 for information on attributes that do not depend on any particular insn.
 
+@var{type} is an optional string that specifies the type of the attribute.
+The possible values are:
+
+@table @code
+@item code,alternative
+The attribute is a function of the instruction code and the alternative
+number.  It does not need need access to a particular rtx instruction
+or to a particular set of operands.
+
+@item insn
+The attribute is a function of an rtx instruction.  It can depend on
+things like operand values.
+@end table
+
+If @var{type} is omitted, the default type is @code{insn}.
+@code{insn} attributes may refer to both @code{insn} and
+@code{code,alternative} attributes, but @code{code,alternative} attributes
+may only refer to other @code{code,alternative} attributes.
+
 @findex insn-attr.h
 For each defined attribute, a number of definitions are written to the
 @file{insn-attr.h} file.  For cases where an explicit set of values is
@@ -8110,14 +8129,21 @@ elements of the form @samp{@var{upper-name}_@var{upper-value}} where
 the attribute name and value are first converted to uppercase.
 
 @item
-A function @samp{get_attr_@var{name}} is defined that is passed an insn and
+For @code{code,alternative} attributes, a function @samp{get_attr_@var{name}}
+is defined that takes an @code{int} instruction code number and an
+@code{int} alternative number and returns the associated attribute value.
+
+@item
+For both @code{code,alternative} and @var{insn} attributes, a function
+@samp{get_attr_@var{name}} is defined that is passed an insn and
 returns the attribute value for that insn.
 @end itemize
 
 For example, if the following is present in the @file{md} file:
 
 @smallexample
-(define_attr "type" "branch,fp,load,store,arith" @dots{})
+(define_attr "type" "branch,fp,load,store,arith" @dots{}
+  "code,alternative")
 @end smallexample
 
 @noindent
@@ -8127,7 +8153,8 @@ the following lines will be written to the file @file{insn-attr.h}.
 #define HAVE_ATTR_type 1
 enum attr_type @{TYPE_BRANCH, TYPE_FP, TYPE_LOAD,
                  TYPE_STORE, TYPE_ARITH@};
-extern enum attr_type get_attr_type ();
+extern enum attr_type get_attr_type (int, int);
+extern enum attr_type get_attr_type (rtx_insn *);
 @end smallexample
 
 If the attribute takes numeric values, no @code{enum} type will be
@@ -8163,7 +8190,7 @@ attribute is not defined; in that case, it is defined as @samp{0}.
 Another way of defining an attribute is to use:
 
 @smallexample
-(define_enum_attr "@var{attr}" "@var{enum}" @var{default})
+(define_enum_attr "@var{attr}" "@var{enum}" @var{default} @var{type})
 @end smallexample
 
 This works in just the same way as @code{define_attr}, except that
diff --git a/gcc/genattr.c b/gcc/genattr.c
index e45f87c..c08c4af 100644
--- a/gcc/genattr.c
+++ b/gcc/genattr.c
@@ -31,34 +31,42 @@ along with GCC; see the file COPYING3.  If not see
 
 static vec<rtx> const_attrs, reservations;
 
+/* Declare a get_attr_*-style function for ATTR with the argument
+   types specified in string PROTOTYPE.  */
+
+static void
+declare_function (rtx attr, const char *prototype)
+{
+  if (GET_CODE (attr) == DEFINE_ENUM_ATTR)
+    printf ("extern enum %s get_attr_%s (%s);\n",
+	    XSTR (attr, 1), XSTR (attr, 0), prototype);
+  else
+    {
+      const char *p = XSTR (attr, 1);
+      if (*p == '\0')
+	printf ("extern int get_attr_%s (%s);\n", XSTR (attr, 0), prototype);
+      else
+	printf ("extern enum attr_%s get_attr_%s (%s);\n",
+		XSTR (attr, 0), XSTR (attr, 0), prototype);
+    }
+}
+
 
 static void
 gen_attr (md_rtx_info *info)
 {
-  const char *p;
   rtx attr = info->def;
-  int is_const = GET_CODE (XEXP (attr, 2)) == CONST;
-
-  if (is_const)
-    const_attrs.safe_push (attr);
+  attr_type type = parse_attr_type (info->loc, attr);
 
   printf ("#define HAVE_ATTR_%s 1\n", XSTR (attr, 0));
 
-  /* If numeric attribute, don't need to write an enum.  */
-  if (GET_CODE (attr) == DEFINE_ENUM_ATTR)
-    printf ("extern enum %s get_attr_%s (%s);\n\n",
-	    XSTR (attr, 1), XSTR (attr, 0),
-	    (is_const ? "void" : "rtx_insn *"));
+  if (type == AT_CONST)
+    const_attrs.safe_push (attr);
   else
     {
-      p = XSTR (attr, 1);
-      if (*p == '\0')
-	printf ("extern int get_attr_%s (%s);\n", XSTR (attr, 0),
-		(is_const ? "void" : "rtx_insn *"));
-      else
-	printf ("extern enum attr_%s get_attr_%s (%s);\n\n",
-		XSTR (attr, 0), XSTR (attr, 0),
-		(is_const ? "void" : "rtx_insn *"));
+      if (type == AT_CODE_ALT)
+	declare_function (attr, "int, int");
+      declare_function (attr, "rtx_insn *");
     }
 
   /* If `length' attribute, write additional function definitions and define
diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c
index 36fdf8b..6f797bf 100644
--- a/gcc/genattrtab.c
+++ b/gcc/genattrtab.c
@@ -177,9 +177,12 @@ struct attr_desc
   struct attr_value *first_value; /* First value of this attribute.  */
   struct attr_value *default_val; /* Default value for this attribute.  */
   file_location loc;		/* Where in the .md files it occurs.  */
-  unsigned is_numeric	: 1;	/* Values of this attribute are numeric.  */
-  unsigned is_const	: 1;	/* Attribute value constant for each run.  */
-  unsigned is_special	: 1;	/* Don't call `write_attr_set'.  */
+  ENUM_BITFIELD (attr_type) type : 2;
+				/* Type of attribute.  */
+  unsigned is_numeric  : 1;	/* Values of this attribute are numeric.  */
+  unsigned is_special  : 1;	/* Don't call `write_attr_set'.  */
+
+  bool is_const () const { return type == AT_CONST; }
 };
 
 /* Structure for each DEFINE_DELAY.  */
@@ -772,9 +775,10 @@ check_attr_test (file_location loc, rtx exp, attr_desc *attr)
 			  " attribute `%s'", XSTR (exp, 0), attr->name);
 	    }
 
-	  if (attr->is_const && ! attr2->is_const)
-	    fatal_at (loc, "constant attribute `%s' cannot test non-constant"
-		      " attribute `%s'", attr->name, attr2->name);
+	  if (attr->type < attr2->type)
+	    fatal_at (loc, "%s attribute `%s' cannot test %s attribute `%s'",
+		      get_attr_type_name (attr->type), attr->name,
+		      get_attr_type_name (attr2->type), attr2->name);
 
 	  /* Copy this just to make it permanent,
 	     so expressions using it can be permanent too.  */
@@ -783,7 +787,7 @@ check_attr_test (file_location loc, rtx exp, attr_desc *attr)
 	  /* It shouldn't be possible to simplify the value given to a
 	     constant attribute, so don't expand this until it's time to
 	     write the test expression.  */
-	  if (attr2->is_const)
+	  if (attr2->is_const ())
 	    ATTR_IND_SIMPLIFIED_P (exp) = 1;
 
 	  if (attr2->is_numeric)
@@ -859,10 +863,10 @@ check_attr_test (file_location loc, rtx exp, attr_desc *attr)
       break;
 
     case MATCH_OPERAND:
-      if (attr->is_const)
-	fatal_at (loc, "invalid operator `%s' in definition of constant"
+      if (attr->type < AT_INSN)
+	fatal_at (loc, "invalid operator `%s' in definition of %s"
 		  " attribute `%s'", GET_RTX_NAME (GET_CODE (exp)),
-		  attr->name);
+		  get_attr_type_name (attr->type), attr->name);
       /* These cases can't be simplified.  */
       ATTR_IND_SIMPLIFIED_P (exp) = 1;
       break;
@@ -880,7 +884,7 @@ check_attr_test (file_location loc, rtx exp, attr_desc *attr)
       break;
 
     case SYMBOL_REF:
-      if (attr->is_const)
+      if (attr->is_const ())
 	{
 	  /* These cases are valid for constant attributes, but can't be
 	     simplified.  */
@@ -1017,10 +1021,11 @@ check_attr_value (file_location loc, rtx exp, struct attr_desc *attr)
 	if (attr2 == NULL)
 	  error_at (loc, "unknown attribute `%s' in ATTR",
 		    XSTR (exp, 0));
-	else if (attr->is_const && ! attr2->is_const)
-	  error_at (attr->loc,
-		    "constant attribute `%s' cannot refer to non-constant"
-		    " attribute `%s'", attr->name, attr2->name);
+	else if (attr->type < attr2->type)
+	  error_at (loc,
+		    "%s attribute `%s' cannot refer to %s attribute `%s'",
+		    get_attr_type_name (attr->type), attr->name,
+		    get_attr_type_name (attr2->type), attr2->name);
 	else if (attr->is_numeric != attr2->is_numeric)
 	  error_at (loc,
 		    "numeric attribute mismatch calling `%s' from `%s'",
@@ -1199,7 +1204,7 @@ make_canonical (file_location loc, struct attr_desc *attr, rtx exp)
       break;
 
     case SYMBOL_REF:
-      if (!attr->is_const || ATTR_IND_SIMPLIFIED_P (exp))
+      if (!attr->is_const () || ATTR_IND_SIMPLIFIED_P (exp))
 	break;
       /* The SYMBOL_REF is constant for a given run, so mark it as unchanging.
 	 This makes the COND something that won't be considered an arbitrary
@@ -1425,7 +1430,7 @@ fill_attr (struct attr_desc *attr)
 
   /* Don't fill constant attributes.  The value is independent of
      any particular insn.  */
-  if (attr->is_const)
+  if (attr->is_const ())
     return;
 
   for (id = defs; id; id = id->next)
@@ -1557,7 +1562,7 @@ make_length_attrs (void)
   if (! length_attr->is_numeric)
     fatal_at (length_attr->loc, "length attribute must be numeric");
 
-  length_attr->is_const = 0;
+  length_attr->type = AT_INSN;
   length_attr->is_special = 1;
 
   /* Make each new attribute, in turn.  */
@@ -2889,7 +2894,7 @@ get_attr_order (struct attr_desc ***ret)
 
   j = 0;
   for (i = 0; i < num; i++)
-    if (all[i]->is_const)
+    if (all[i]->is_const ())
       handled[i] = 1, sorted[j++] = all[i];
 
   /* We have only few attributes hence we can live with the inner
@@ -2917,7 +2922,7 @@ get_attr_order (struct attr_desc ***ret)
 		}
 	    if (k == num)
 	      {
-		/* Nothing in I depended on anything intersting, so
+		/* Nothing in I depended on anything interesting, so
 		   it's done.  */
 		handled[i] = 1;
 		sorted[j++] = all[i];
@@ -2935,7 +2940,7 @@ get_attr_order (struct attr_desc ***ret)
 	fprintf (stderr, "%s depends on: ", attr->name);
 	for (i = 0; i < MAX_ATTRS_INDEX; ++i)
 	  for (attr2 = attrs[i]; attr2; attr2 = attr2->next)
-	    if (!attr2->is_const)
+	    if (!attr2->is_const ())
 	      for (av = attr->first_value; av; av = av->next)
 		if (av->num_insns != 0)
 		  if (tests_attr_p (av->value, attr2))
@@ -3152,6 +3157,8 @@ gen_attr (md_rtx_info *info)
     }
   attr->loc = info->loc;
 
+  attr->type = parse_attr_type (info->loc, def);
+
   if (GET_CODE (def) == DEFINE_ENUM_ATTR)
     {
       attr->enum_name = XSTR (def, 1);
@@ -3172,9 +3179,8 @@ gen_attr (md_rtx_info *info)
 	add_attr_value (attr, p);
     }
 
-  if (GET_CODE (XEXP (def, 2)) == CONST)
+  if (attr->type == AT_CONST)
     {
-      attr->is_const = 1;
       if (attr->is_numeric)
 	error_at (info->loc,
 		  "constant attributes may not take numeric values");
@@ -3389,7 +3395,7 @@ find_attrs_to_cache (rtx exp, bool create)
 	return;
       attr = find_attr (&name, 0);
       gcc_assert (attr);
-      if (attr->is_const)
+      if (attr->type != AT_INSN)
 	return;
       if (cached_attr_count == 32)
 	return;
@@ -3688,13 +3694,17 @@ write_test_expr (FILE *outf, rtx exp, unsigned int attrs_cached, int flags)
       gcc_assert (attr);
 
       /* Now is the time to expand the value of a constant attribute.  */
-      if (attr->is_const)
+      if (attr->type == AT_CONST)
+	write_test_expr (outf,
+			 evaluate_eq_attr (exp, attr,
+					   attr->default_val->value,
+					   -2, -2),
+			 attrs_cached, 0);
+      else if (attr->type == AT_CODE_ALT)
 	{
-	  write_test_expr (outf,
-			   evaluate_eq_attr (exp, attr,
-					     attr->default_val->value,
-					     -2, -2),
-			   attrs_cached, 0);
+	  fprintf (outf, "get_attr_%s (icode, which_alternative)", attr->name);
+	  fprintf (outf, " == ");
+	  write_attr_valueq (outf, attr, XSTR (exp, 1));
 	}
       else
 	{
@@ -3932,6 +3942,7 @@ walk_attr_value (rtx exp)
   int i, j;
   const char *fmt;
   RTX_CODE code;
+  attr_desc *attr;
 
   if (exp == NULL)
     return;
@@ -3957,6 +3968,9 @@ walk_attr_value (rtx exp)
       break;
 
     case EQ_ATTR:
+      attr = find_attr (&XSTR (exp, 0), 0);
+      if (attr->type == AT_CODE_ALT)
+	must_constrain = 1;
       if (XSTR (exp, 0) == alternative_name)
 	must_extract = must_constrain = 1;
       else if (strcmp_check (XSTR (exp, 0), length_str) == 0)
@@ -3995,6 +4009,19 @@ walk_attr_value (rtx exp)
       }
 }
 
+/* Write the return type of ATTR's function to OUTF.  */
+
+static void
+write_attr_return_type (FILE *outf, struct attr_desc *attr)
+{
+ if (attr->enum_name)
+    fprintf (outf, "enum %s", attr->enum_name);
+  else if (!attr->is_numeric)
+    fprintf (outf, "enum attr_%s", attr->name);
+  else
+    fprintf (outf, "int");
+}
+
 /* Write out a function to obtain the attribute for a given INSN.  */
 
 static void
@@ -4009,39 +4036,30 @@ write_attr_get (FILE *outf, struct attr_desc *attr)
 
   /* Write out start of function, then all values with explicit `case' lines,
      then a `default', then the value with the most uses.  */
-  if (attr->enum_name)
-    fprintf (outf, "enum %s\n", attr->enum_name);
-  else if (!attr->is_numeric)
-    fprintf (outf, "enum attr_%s\n", attr->name);
+  write_attr_return_type (outf, attr);
+
+  if (attr->type == AT_CONST)
+    gcc_unreachable ();
+  else if (attr->type == AT_CODE_ALT)
+    fprintf (outf, "\nget_attr_%s (int icode,"
+	     " int which_alternative ATTRIBUTE_UNUSED)\n",
+	     attr->name);
+  else if (attr->name[0] == '*')
+    /* If the attribute name starts with a star, the remainder is the name of
+       the subroutine to use, instead of `get_attr_...'.  */
+    fprintf (outf, "\n%s (rtx_insn *insn ATTRIBUTE_UNUSED)\n", &attr->name[1]);
   else
-    fprintf (outf, "int\n");
-
-  /* If the attribute name starts with a star, the remainder is the name of
-     the subroutine to use, instead of `get_attr_...'.  */
-  if (attr->name[0] == '*')
-    fprintf (outf, "%s (rtx_insn *insn ATTRIBUTE_UNUSED)\n", &attr->name[1]);
-  else if (attr->is_const == 0)
-    fprintf (outf, "get_attr_%s (rtx_insn *insn ATTRIBUTE_UNUSED)\n", attr->name);
-  else
-    {
-      fprintf (outf, "get_attr_%s (void)\n", attr->name);
-      fprintf (outf, "{\n");
-
-      for (av = attr->first_value; av; av = av->next)
-	if (av->num_insns == 1)
-	  write_attr_set (outf, attr, 2, av->value, "return", ";",
-			  true_rtx, av->first_insn->def->insn_code,
-			  av->first_insn->def->insn_index, 0);
-	else if (av->num_insns != 0)
-	  write_attr_set (outf, attr, 2, av->value, "return", ";",
-			  true_rtx, -2, 0, 0);
-
-      fprintf (outf, "}\n\n");
-      return;
-    }
+    fprintf (outf, "\nget_attr_%s (rtx_insn *insn ATTRIBUTE_UNUSED)\n",
+	     attr->name);
 
   fprintf (outf, "{\n");
 
+  if (attr->type == AT_CODE_ALT)
+    fprintf (outf, "#define recog_data _Pragma ("
+	     "\"GCC error \\\"recog_data cannot be used"
+	     " in %s attributes\\\"\") recog_data\n",
+	     get_attr_type_name (attr->type));
+
   /* Find attributes that are worth caching in the conditions.  */
   cached_attr_count = 0;
   attrs_seen_more_than_once = 0;
@@ -4059,13 +4077,9 @@ write_attr_get (FILE *outf, struct attr_desc *attr)
 	if (i != j)
 	  cached_attrs[j] = name;
 	cached_attr = find_attr (&name, 0);
-	gcc_assert (cached_attr && cached_attr->is_const == 0);
-	if (cached_attr->enum_name)
-	  fprintf (outf, "  enum %s", cached_attr->enum_name);
-	else if (!cached_attr->is_numeric)
-	  fprintf (outf, "  enum attr_%s", cached_attr->name);
-	else
-	  fprintf (outf, "  int");
+	gcc_assert (cached_attr && cached_attr->type == AT_INSN);
+	fprintf (outf, "  ");
+	write_attr_return_type (outf, cached_attr);
 	fprintf (outf, " cached_%s ATTRIBUTE_UNUSED;\n", name);
 	j++;
       }
@@ -4073,7 +4087,9 @@ write_attr_get (FILE *outf, struct attr_desc *attr)
   if (cached_attr_count)
     fprintf (outf, "\n");
 
-  fprintf (outf, "  switch (recog_memoized (insn))\n");
+  if (attr->type == AT_INSN)
+    fprintf (outf, "  int icode = recog_memoized (insn);\n");
+  fprintf (outf, "  switch (icode)\n");
   fprintf (outf, "    {\n");
 
   for (av = attr->first_value; av; av = av->next)
@@ -4081,8 +4097,22 @@ write_attr_get (FILE *outf, struct attr_desc *attr)
       write_attr_case (outf, attr, av, 1, "return", ";", 4, true_rtx);
 
   write_attr_case (outf, attr, common_av, 0, "return", ";", 4, true_rtx);
-  fprintf (outf, "    }\n}\n\n");
+  fprintf (outf, "    }\n");
+  if (attr->type == AT_CODE_ALT)
+    fprintf (outf, "#undef recog_data\n");
+  fprintf (outf, "}\n\n");
   cached_attr_count = 0;
+  if (attr->type == AT_CODE_ALT)
+    {
+      write_attr_return_type (outf, attr);
+      fprintf (outf, "\nget_attr_%s (rtx_insn *insn)\n", attr->name);
+      fprintf (outf, "{\n");
+      fprintf (outf, "  int which_alternative = "
+	       "extract_constrain_insn_cached (insn);\n");
+      fprintf (outf, "  return get_attr_%s (INSN_CODE (insn),"
+	       " which_alternative);\n", attr->name);
+      fprintf (outf, "}\n\n");
+    }
 }
 
 /* Given an AND tree of known true terms (because we are inside an `if' with
@@ -4254,7 +4284,7 @@ write_attr_case (FILE *outf, struct attr_desc *attr, struct attr_value *av,
   if (av->num_insns == 0)
     return;
 
-  if (av->has_asm_insn)
+  if (attr->type == AT_INSN && av->has_asm_insn)
     {
       write_indent (outf, indent);
       fprintf (outf, "case -1:\n");
@@ -4279,19 +4309,22 @@ write_attr_case (FILE *outf, struct attr_desc *attr, struct attr_value *av,
   walk_attr_value (av->value);
 
   int code_indent = indent + 2;
-  if (must_constrain)
-    {
-      code_indent += 2;
-      write_indent (outf, indent + 2);
-      fprintf (outf, "{\n");
-      write_indent (outf, code_indent);
-      fprintf (outf, "int which_alternative ATTRIBUTE_UNUSED = "
-	       "extract_constrain_insn_cached (insn);\n");
-    }
-  else if (must_extract)
+  if (attr->type == AT_INSN)
     {
-      write_indent (outf, code_indent);
-      fprintf (outf, "extract_insn_cached (insn);\n");
+      if (must_constrain)
+	{
+	  code_indent += 2;
+	  write_indent (outf, indent + 2);
+	  fprintf (outf, "{\n");
+	  write_indent (outf, code_indent);
+	  fprintf (outf, "int which_alternative ATTRIBUTE_UNUSED = "
+		   "extract_constrain_insn_cached (insn);\n");
+	}
+      else if (must_extract)
+	{
+	  write_indent (outf, code_indent);
+	  fprintf (outf, "extract_insn_cached (insn);\n");
+	}
     }
 
   attrs_to_cache = 0;
@@ -4360,15 +4393,17 @@ write_attr_value (FILE *outf, struct attr_desc *attr, rtx value)
     case ATTR:
       {
 	struct attr_desc *attr2 = find_attr (&XSTR (value, 0), 0);
-	if (attr->enum_name)
-	  fprintf (outf, "(enum %s)", attr->enum_name);
-	else if (!attr->is_numeric)
-	  fprintf (outf, "(enum attr_%s)", attr->name);
-	else if (!attr2->is_numeric)
-	  fprintf (outf, "(int)");
-
-	fprintf (outf, "get_attr_%s (%s)", attr2->name,
-		 (attr2->is_const ? "" : "insn"));
+	fprintf (outf, "(");
+	write_attr_return_type (outf, attr);
+	fprintf (outf, ")");
+
+	fprintf (outf, "get_attr_%s", attr2->name);
+	if (attr->type == AT_CONST)
+	  gcc_unreachable ();
+	else if (attr->type == AT_CODE_ALT)
+	  fprintf (outf, " (icode, which_alternative)\n");
+	else
+	  fprintf (outf, " (insn)\n");
       }
       break;
 
@@ -4623,11 +4658,10 @@ find_attr (const char **name_p, int create)
     return NULL;
 
   attr = oballoc (struct attr_desc);
+  memset (attr, 0, sizeof (*attr));
   attr->name = DEF_ATTR_STRING (name);
-  attr->enum_name = 0;
-  attr->first_value = attr->default_val = NULL;
-  attr->is_numeric = attr->is_const = attr->is_special = 0;
   attr->next = attrs[index];
+  attr->type = AT_INSN;
   attrs[index] = attr;
 
   *name_p = attr->name;
@@ -4646,7 +4680,7 @@ make_internal_attr (const char *name, rtx value, int special)
   gcc_assert (!attr->default_val);
 
   attr->is_numeric = 1;
-  attr->is_const = 0;
+  attr->type = AT_INSN;
   attr->is_special = (special & ATTR_SPECIAL) != 0;
   attr->default_val = get_attr_value (file_location ("<internal>", 0),
 				      value, attr, -2);
@@ -4770,6 +4804,7 @@ gen_insn_reserv (md_rtx_info *info)
   memset (&attr, 0, sizeof (attr));
   attr.name = DEF_ATTR_STRING (XSTR (def, 0));
   attr.loc = info->loc;
+  attr.type = AT_INSN;
 
   decl->name            = DEF_ATTR_STRING (XSTR (def, 0));
   decl->default_latency = XINT (def, 1);
@@ -4904,7 +4939,7 @@ find_tune_attr (rtx exp)
       attr = find_attr (&XSTR (exp, 0), 0);
       gcc_assert (attr);
 
-      if (attr->is_const && !attr->is_special)
+      if (attr->is_const () && !attr->is_special)
 	{
 	  struct insn_reserv *decl;
 
@@ -4942,7 +4977,7 @@ make_automaton_attrs (void)
       struct attr_value *val;
       bool first = true;
 
-      gcc_assert (tune_attr->is_const
+      gcc_assert (tune_attr->is_const ()
 		  && !tune_attr->is_special
 		  && !tune_attr->is_numeric);
 
@@ -5335,7 +5370,7 @@ main (int argc, char **argv)
 	  outf = attr_file;
 #undef IS_ATTR_GROUP
 
-	if (! attr->is_special && ! attr->is_const)
+	if (! attr->is_special && !attr->is_const ())
 	  write_attr_get (outf, attr);
       }
 
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 484ead2..7f737a2 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -434,10 +434,10 @@ remove_from_queue (struct queue_elem *elem, struct queue_elem **queue)
     *queue = elem->next;
 }
 
-/* Build a define_attr for an binary attribute with name NAME and
-   possible values "yes" and "no", and queue it.  */
+/* Build a define_attr for a binary attribute with name NAME, type TYPE,
+   and possible values "yes" and "no", then queue it.  */
 static void
-add_define_attr (const char *name)
+add_define_attr (const char *name, const char *type)
 {
   struct queue_elem *e = XNEW (struct queue_elem);
   rtx t1 = rtx_alloc (DEFINE_ATTR);
@@ -445,6 +445,7 @@ add_define_attr (const char *name)
   XSTR (t1, 1) = "no,yes";
   XEXP (t1, 2) = rtx_alloc (CONST_STRING);
   XSTR (XEXP (t1, 2), 0) = "yes";
+  XSTR (t1, 3) = type;
   e->data = t1;
   e->loc = file_location ("built-in", -1);
   e->next = define_attr_queue;
@@ -1372,15 +1373,21 @@ alter_attrs_for_insn (rtx insn)
       struct queue_elem *elem;
 
       global_changes_made = true;
-      add_define_attr ("ce_enabled");
-      add_define_attr ("nonce_enabled");
 
       for (elem = define_attr_queue; elem ; elem = elem->next)
 	if (strcmp (XSTR (elem->data, 0), "enabled") == 0)
 	  {
+	    add_define_attr ("ce_enabled", XSTR (elem->data, 3));
+	    add_define_attr ("nonce_enabled", XSTR (elem->data, 3));
 	    XEXP (elem->data, 2)
 	      = modify_attr_enabled_ce (XEXP (elem->data, 2));
+	    break;
 	  }
+      if (!elem)
+	{
+	  add_define_attr ("ce_enabled", "code,alternative");
+	  add_define_attr ("nonce_enabled", "code,alternative");
+	}
     }
   if (enabled_idx == -1)
     return;
@@ -3061,3 +3068,44 @@ needs_barrier_p (rtx x)
 	  && GET_CODE (SET_DEST (x)) == PC
 	  && GET_CODE (SET_SRC (x)) == LABEL_REF);
 }
+
+/* Parse the attribute type for DEFINE_ATTR or DEFINE_ENUM_ATTR definition
+   DEF, which was found at location LOC.  */
+
+attr_type
+parse_attr_type (file_location loc, rtx def)
+{
+  const char *type = XSTR (def, 3);
+  if (GET_CODE (XEXP (def, 2)) == CONST)
+    {
+      if (type[0])
+	error_at (loc, "constant attributes cannot have type `%s'", type);
+      return AT_CONST;
+    }
+
+  if (type[0] == 0 || strcmp (type, "insn") == 0)
+    return AT_INSN;
+
+  if (strcmp (type, "code,alternative") == 0)
+    return AT_CODE_ALT;
+
+  error_at (loc, "unknown attribute type `%s'", type);
+  return AT_INSN;
+}
+
+/* Return an English description of TYPE, for error messages.  */
+
+const char *
+get_attr_type_name (attr_type type)
+{
+  switch (type)
+    {
+    case AT_CONST:
+      return "constant";
+    case AT_CODE_ALT:
+      return "code-and-alternative";
+    case AT_INSN:
+      return "instruction";
+    }
+  gcc_unreachable ();
+}
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index 0199e39..b330a0d 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -25,6 +25,24 @@ along with GCC; see the file COPYING3.  If not see
 struct obstack;
 extern struct obstack *rtl_obstack;
 
+/* Classifies the type of a DEFINE_ATTR or DEFINE_ENUM_ATTR.
+   The enum is in increasing order of generality, so that attributes
+   with a higher type can refer to attributes with a lower type, but not
+   vice versa.  */
+enum attr_type {
+  /* The attribute depends only on global state; it is not a property
+     of a specific instruction.  These attributes have traditionally
+     been called "constant" and are associated with a (const ...) rtx.  */
+  AT_CONST,
+
+  /* The attribute depends on an instruction code and alternative number.  */
+  AT_CODE_ALT,
+
+  /* The attribute depends on an rtx instruction, and may examine the
+     operands of that instruction.  */
+  AT_INSN
+};
+
 /* Information about an .md define_* rtx.  */
 struct md_rtx_info {
   /* The rtx itself.  */
@@ -135,5 +153,7 @@ extern void compute_test_codes (rtx, file_location, char *);
 extern file_location get_file_location (rtx);
 extern const char *get_emit_function (rtx);
 extern bool needs_barrier_p (rtx);
+attr_type parse_attr_type (file_location, rtx);
+const char *get_attr_type_name (attr_type);
 
 #endif /* GCC_GENSUPPORT_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 36e42cd..2b5e7a2 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -944,6 +944,7 @@ add_define_attr_for_define_subst (const char *attr_name, vec<rtx> *queue)
   XSTR (return_rtx, 0) = xstrdup (attr_name);
   XSTR (return_rtx, 1) = xstrdup ("no,yes");
   XEXP (return_rtx, 2) = const_str;
+  XSTR (return_rtx, 3) = "code,alternative";
 
   queue->safe_push (return_rtx);
 }
diff --git a/gcc/rtl.def b/gcc/rtl.def
index cca469d..5a46829 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -1246,14 +1246,16 @@ DEF_RTL_EXPR(DEFINE_INSN_RESERVATION, "define_insn_reservation", "sies", RTX_EXT
 /* Definition of an insn attribute.
    1st operand: name of the attribute
    2nd operand: comma-separated list of possible attribute values
-   3rd operand: expression for the default value of the attribute.  */
-DEF_RTL_EXPR(DEFINE_ATTR, "define_attr", "sse", RTX_EXTRA)
+   3rd operand: expression for the default value of the attribute.
+   4th operand: optional type.  */
+DEF_RTL_EXPR(DEFINE_ATTR, "define_attr", "sses", RTX_EXTRA)
 
 /* Definition of an insn attribute that uses an existing enumerated type.
    1st operand: name of the attribute
    2nd operand: the name of the enumerated type
-   3rd operand: expression for the default value of the attribute.  */
-DEF_RTL_EXPR(DEFINE_ENUM_ATTR, "define_enum_attr", "sse", RTX_EXTRA)
+   3rd operand: expression for the default value of the attribute.
+   4th operand: optional type.  */
+DEF_RTL_EXPR(DEFINE_ENUM_ATTR, "define_enum_attr", "sses", RTX_EXTRA)
 
 /* Marker for the name of an attribute.  */
 DEF_RTL_EXPR(ATTR, "attr", "s", RTX_EXTRA)

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 07/22] Use code,alternative attributes for alpha
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (5 preceding siblings ...)
  2015-11-25 12:29 ` [PR68432 06/22] Use code,alternative attributes for aarch64 Richard Sandiford
@ 2015-11-25 12:30 ` Richard Sandiford
  2015-11-25 12:30 ` [PR68432 10/22] Use code,alternative attributes for avr Richard Sandiford
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:30 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/alpha/alpha.md (isa): Turn into a code,alternative
	attribute.
	(enabled): Likewise.

diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md
index 5068f60..7f440d3 100644
--- a/gcc/config/alpha/alpha.md
+++ b/gcc/config/alpha/alpha.md
@@ -196,7 +196,8 @@
 ;; For convenience, conflate ABI issues re loading of addresses with
 ;; an "isa".
 (define_attr "isa" "base,bwx,max,fix,cix,vms,ner,er"
-  (const_string "base"))
+  (const_string "base")
+  "code,alternative")
 
 (define_attr "enabled" ""
   (cond [(eq_attr "isa" "bwx")	(symbol_ref "TARGET_BWX")
@@ -207,7 +208,8 @@
 	 (eq_attr "isa" "ner")	(symbol_ref "!TARGET_EXPLICIT_RELOCS")
 	 (eq_attr "isa" "er")	(symbol_ref "TARGET_EXPLICIT_RELOCS")
 	]
-	(const_int 1)))
+	(const_int 1))
+  "code,alternative")
 \f
 ;; Include scheduling descriptions.
   

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 10/22] Use code,alternative attributes for avr
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (6 preceding siblings ...)
  2015-11-25 12:30 ` [PR68432 07/22] Use code,alternative attributes for alpha Richard Sandiford
@ 2015-11-25 12:30 ` Richard Sandiford
  2015-11-25 12:31 ` [PR68432 11/22] Use code,alternative attributes for c6x Richard Sandiford
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:30 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/avr/avr.md (isa): Turn into a code,alternative attribute.
	(enabled): Likewise.

diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 1b39ddb..eb200ce 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -173,7 +173,8 @@
 (define_attr "isa"
   "mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx, no_xmega,xmega, no_tiny,tiny,
    standard"
-  (const_string "standard"))
+  (const_string "standard")
+  "code,alternative")
 
 (define_attr "enabled" ""
   (cond [(eq_attr "isa" "standard")
@@ -235,7 +236,8 @@
               (match_test "!AVR_TINY"))
          (const_int 1)
 
-         ] (const_int 0)))
+         ] (const_int 0))
+  "code,alternative")
 
 
 ;; Define mode iterators

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 11/22] Use code,alternative attributes for c6x
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (7 preceding siblings ...)
  2015-11-25 12:30 ` [PR68432 10/22] Use code,alternative attributes for avr Richard Sandiford
@ 2015-11-25 12:31 ` Richard Sandiford
  2015-11-25 12:31 ` [PR68432 08/22] Use code,alternative attributes for arc Richard Sandiford
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:31 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/c6x/c6x (enabled): Turn into a code,alternative attribute.

diff --git a/gcc/config/c6x/c6x.md b/gcc/config/c6x/c6x.md
index fa89587..8297514 100644
--- a/gcc/config/c6x/c6x.md
+++ b/gcc/config/c6x/c6x.md
@@ -216,7 +216,8 @@
   (const_string "yes"))
 
 (define_attr "enabled" "no,yes"
-  (const_string "yes"))
+  (const_string "yes")
+  "code,alternative")
 
 ;; Specify which units can be used by a given instruction.  Normally,
 ;; dest_regfile is used to select between the two halves of the machine.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 08/22] Use code,alternative attributes for arc
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (8 preceding siblings ...)
  2015-11-25 12:31 ` [PR68432 11/22] Use code,alternative attributes for c6x Richard Sandiford
@ 2015-11-25 12:31 ` Richard Sandiford
  2015-11-25 12:31 ` [PR68432 09/22] Use code,alternative attributes for arm Richard Sandiford
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:31 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/arc/arc.md (cpu_facility): Turn into a code,alternative
	attribute.
	(enabled): Likewise.

diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 1d070a3..5477260 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -231,7 +231,8 @@
 
 ; for ARCv2 we need to disable/enable different instruction alternatives
 (define_attr "cpu_facility" "std,av1,av2"
-  (const_string "std"))
+  (const_string "std")
+  "code,alternative")
 
 ; We should consider all the instructions enabled until otherwise
 (define_attr "enabled" "no,yes"
@@ -243,7 +244,8 @@
 	      (not (match_test "TARGET_V2")))
 	 (const_string "no")
 	 ]
-	(const_string "yes")))
+	(const_string "yes"))
+  "code,alternative")
 
 (define_attr "predicable" "no,yes" (const_string "no"))
 ;; if 'predicable' were not so brain-dead, we would specify:

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 12/22] Use code,alternative attributes for i386
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (10 preceding siblings ...)
  2015-11-25 12:31 ` [PR68432 09/22] Use code,alternative attributes for arm Richard Sandiford
@ 2015-11-25 12:31 ` Richard Sandiford
  2015-11-25 12:32 ` [PR68432 13/22] Use code,alternative attributes for m68k Richard Sandiford
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:31 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/i386/i386.md (isa): Turn into a code,alternative attribute.
	(enabled, preferred_for_size, preferred_for_speed): Likewise.

diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index a57d165..87f60c0 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -798,7 +798,8 @@
 		    avx2,noavx2,bmi,bmi2,fma4,fma,avx512f,noavx512f,
 		    fma_avx512f,avx512bw,noavx512bw,avx512dq,noavx512dq,
 		    avx512vl,noavx512vl"
-  (const_string "base"))
+  (const_string "base")
+  "code,alternative")
 
 (define_attr "enabled" ""
   (cond [(eq_attr "isa" "x64") (symbol_ref "TARGET_64BIT")
@@ -835,10 +836,11 @@
 	 (eq_attr "isa" "avx512vl") (symbol_ref "TARGET_AVX512VL")
 	 (eq_attr "isa" "noavx512vl") (symbol_ref "!TARGET_AVX512VL")
 	]
-	(const_int 1)))
+	(const_int 1))
+  "code,alternative")
 
-(define_attr "preferred_for_size" "" (const_int 1))
-(define_attr "preferred_for_speed" "" (const_int 1))
+(define_attr "preferred_for_size" "" (const_int 1) "code,alternative")
+(define_attr "preferred_for_speed" "" (const_int 1) "code,alternative")
 
 ;; Describe a user's asm statement.
 (define_asm_attributes

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 09/22] Use code,alternative attributes for arm
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (9 preceding siblings ...)
  2015-11-25 12:31 ` [PR68432 08/22] Use code,alternative attributes for arc Richard Sandiford
@ 2015-11-25 12:31 ` Richard Sandiford
  2015-11-25 12:31 ` [PR68432 12/22] Use code,alternative attributes for i386 Richard Sandiford
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:31 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/arm/arm.md (enabled_for_depr_it): Turn into a
	code,alternative attribute.
	(predicable_short_it, predicated, arch, arch_enabled): Likewise.
	(use_literal_pool, enabled): Likewise.
	* config/arm/types.md (type): Likewise.

diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 8812d07..cff5de7 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -84,11 +84,15 @@
 ; We use this attribute to disable alternatives that can produce 32-bit
 ; instructions inside an IT-block in Thumb2 state.  ARMv8 deprecates IT blocks
 ; that contain 32-bit instructions.
-(define_attr "enabled_for_depr_it" "no,yes" (const_string "yes"))
+(define_attr "enabled_for_depr_it" "no,yes"
+  (const_string "yes")
+  "code,alternative")
 
 ; This attribute is used to disable a predicated alternative when we have
 ; arm_restrict_it.
-(define_attr "predicable_short_it" "no,yes" (const_string "yes"))
+(define_attr "predicable_short_it" "no,yes"
+  (const_string "yes")
+  "code,alternative")
 
 ;; Operand number of an input operand that is shifted.  Zero if the
 ;; given instruction does not shift one of its input operands.
@@ -108,7 +112,7 @@
 ; Predicated means that the insn form is conditionally executed based on a
 ; predicate.  We default to 'no' because no Thumb patterns match this rule
 ; and not all ARM insns do.
-(define_attr "predicated" "yes,no" (const_string "no"))
+(define_attr "predicated" "yes,no" (const_string "no") "code,alternative")
 
 ; LENGTH of an instruction (in bytes)
 (define_attr "length" ""
@@ -122,7 +126,8 @@
 ; used to compute attribute "enabled", use type "any" to enable an
 ; alternative in all cases.
 (define_attr "arch" "any,a,t,32,t1,t2,v6,nov6,v6t2,neon_for_64bits,avoid_neon_for_64bits,iwmmxt,iwmmxt2,armv6_or_vfpv3"
-  (const_string "any"))
+  (const_string "any")
+  "code,alternative")
 
 (define_attr "arch_enabled" "no,yes"
   (cond [(eq_attr "arch" "any")
@@ -179,7 +184,8 @@
 	 (const_string "yes")
 	]
 
-	(const_string "no")))
+	(const_string "no"))
+  "code,alternative")
 
 (define_attr "opt" "any,speed,size"
   (const_string "any"))
@@ -197,7 +203,9 @@
 	 (const_string "yes")]
 	(const_string "no")))
 
-(define_attr "use_literal_pool" "no,yes" (const_string "no"))
+(define_attr "use_literal_pool" "no,yes"
+  (const_string "no")
+  "code,alternative")
 
 ; Enable all alternatives that are both arch_enabled and insn_enabled.
 ; FIXME:: opt_enabled has been temporarily removed till the time we have
@@ -227,7 +235,8 @@
 
 	  (eq_attr "arch_enabled" "no")
 	  (const_string "no")]
-	 (const_string "yes")))
+	 (const_string "yes"))
+  "code,alternative")
 
 ; POOL_RANGE is how far away from a constant pool entry that this insn
 ; can be placed.  If the distance is zero, then this insn will never
diff --git a/gcc/config/arm/types.md b/gcc/config/arm/types.md
index 73f482d..91872a1 100644
--- a/gcc/config/arm/types.md
+++ b/gcc/config/arm/types.md
@@ -1069,7 +1069,8 @@
   crypto_sha1_slow,\
   crypto_sha256_fast,\
   crypto_sha256_slow"
-   (const_string "untyped"))
+   (const_string "untyped")
+   "code,alternative")
 
 ; Is this an (integer side) multiply with a 32-bit (or smaller) result?
 (define_attr "mul32" "no,yes"

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 13/22] Use code,alternative attributes for m68k
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (11 preceding siblings ...)
  2015-11-25 12:31 ` [PR68432 12/22] Use code,alternative attributes for i386 Richard Sandiford
@ 2015-11-25 12:32 ` Richard Sandiford
  2015-11-25 12:32 ` [PR68432 14/22] Use code,alternative attributes for mips Richard Sandiford
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:32 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/m68k/m68k.md (ok_for_coldfire): Turn into a code,alternative
	attribute.
	(enabled): Likewise.

diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md
index 1c7309b..e391927 100644
--- a/gcc/config/m68k/m68k.md
+++ b/gcc/config/m68k/m68k.md
@@ -248,14 +248,17 @@
   (symbol_ref "m68k_sched_attr_size (insn)"))
 
 ;; Alternative is OK for ColdFire.
-(define_attr "ok_for_coldfire" "yes,no" (const_string "yes"))
+(define_attr "ok_for_coldfire" "yes,no"
+  (const_string "yes")
+  "code,alternative")
 
 ;; Define 'enabled' attribute.
 (define_attr "enabled" ""
   (cond [(and (match_test "TARGET_COLDFIRE")
 	      (eq_attr "ok_for_coldfire" "no"))
 	 (const_int 0)]
- 	(const_int 1)))
+ 	(const_int 1))
+  "code,alternative")
 \f
 ;; Mode macros for integer operations.
 (define_mode_iterator I [QI HI SI])

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 15/22] Use code,alternative attributes for mn10300
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (13 preceding siblings ...)
  2015-11-25 12:32 ` [PR68432 14/22] Use code,alternative attributes for mips Richard Sandiford
@ 2015-11-25 12:32 ` Richard Sandiford
  2015-11-25 12:33 ` [PR68432 17/22] Use code,alternative attributes for s390 Richard Sandiford
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:32 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/mn10300/mn10300.md (isa): Turn into a code,alternative
	attribute.
	(enabled): Likewise.

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 7cd5306..e1ae283 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -54,7 +54,8 @@
 
 ;; Used to control the "enabled" attribute on a per-instruction basis.
 (define_attr "isa" "base,am33,am33_2,am34"
-  (const_string "base"))
+  (const_string "base")
+  "code,alternative")
 
 (define_attr "enabled" ""
   (cond [(eq_attr "isa" "base")
@@ -73,6 +74,7 @@
          (const_int 1)
 	]
 	(const_int 0))
+  "code,alternative"
 )
 
 (define_mode_iterator INT [QI HI SI])

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 14/22] Use code,alternative attributes for mips
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (12 preceding siblings ...)
  2015-11-25 12:32 ` [PR68432 13/22] Use code,alternative attributes for m68k Richard Sandiford
@ 2015-11-25 12:32 ` Richard Sandiford
  2015-11-25 12:32 ` [PR68432 15/22] Use code,alternative attributes for mn10300 Richard Sandiford
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:32 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/mips/mips.md (move_type): Turn into a code,alternative
	attribute.
	(mode, dword_mode, compression, enabled): Likewise.

diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index d24dcfe..2f8dfbd 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -223,14 +223,16 @@
   "unknown,load,fpload,store,fpstore,mtc,mfc,mtlo,mflo,imul,move,fmove,
    const,constN,signext,ext_ins,logical,arith,sll0,andi,loadpool,
    shift_shift"
-  (const_string "unknown"))
+  (const_string "unknown")
+  "code,alternative")
 
 (define_attr "alu_type" "unknown,add,sub,not,nor,and,or,xor"
   (const_string "unknown"))
 
 ;; Main data type used by the insn
 (define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,TF,FPSW"
-  (const_string "unknown"))
+  (const_string "unknown")
+  "code,alternative")
 
 ;; True if the main data type is twice the size of a word.
 (define_attr "dword_mode" "no,yes"
@@ -241,7 +243,8 @@
 	 (and (eq_attr "mode" "TI,TF")
 	      (match_test "TARGET_64BIT"))
 	 (const_string "yes")]
-	(const_string "no")))
+	(const_string "no"))
+  "code,alternative")
 
 ;; Attributes describing a sync loop.  These loops have the form:
 ;;
@@ -441,7 +444,8 @@
 		(const_string "no")))
 
 (define_attr "compression" "none,all,micromips32,micromips"
-  (const_string "none"))
+  (const_string "none")
+  "code,alternative")
 
 (define_attr "enabled" "no,yes"
   (cond [;; The o32 FPXX and FP64A ABI extensions prohibit direct moves between
@@ -454,7 +458,8 @@
 	 (and (eq_attr "compression" "micromips32,micromips")
 	      (match_test "!TARGET_MICROMIPS"))
 	 (const_string "no")]
-	(const_string "yes")))
+	(const_string "yes"))
+  "code,alternative")
 
 ;; The number of individual instructions that a non-branch pattern generates,
 ;; using units of BASE_INSN_LENGTH.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 17/22] Use code,alternative attributes for s390
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (14 preceding siblings ...)
  2015-11-25 12:32 ` [PR68432 15/22] Use code,alternative attributes for mn10300 Richard Sandiford
@ 2015-11-25 12:33 ` Richard Sandiford
  2015-11-25 12:33 ` [PR68432 16/22] Use code,alternative attributes for nds32 Richard Sandiford
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:33 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/s390/s390.md (cpu_facility): Turn into a code,alternative
	attribute.
	(enabled): Likewise.

diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index a5335ca..aca5233 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -437,7 +437,8 @@
 
 (define_attr "cpu_facility"
   "standard,ieee,zarch,cpu_zarch,longdisp,extimm,dfp,z10,z196,zEC12,vec"
-  (const_string "standard"))
+  (const_string "standard")
+  "code,alternative")
 
 (define_attr "enabled" ""
   (cond [(eq_attr "cpu_facility" "standard")
@@ -482,7 +483,8 @@
          (and (eq_attr "cpu_facility" "vec")
               (match_test "TARGET_VX"))
 	 (const_int 1)]
-	(const_int 0)))
+	(const_int 0))
+  "code,alternative")
 
 ;; Pipeline description for z900.  For lack of anything better,
 ;; this description is also used for the g5 and g6.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 16/22] Use code,alternative attributes for nds32
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (15 preceding siblings ...)
  2015-11-25 12:33 ` [PR68432 17/22] Use code,alternative attributes for s390 Richard Sandiford
@ 2015-11-25 12:33 ` Richard Sandiford
  2015-11-25 12:34 ` [PR68432 18/22] Use code,alternative attributes for sparc Richard Sandiford
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:33 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/nds32/nds32.md (is_16bit): Turn into a code,alternative
	attribute.
	(enabled): Likewise.

diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md
index 89c0391..dbe2a2d 100644
--- a/gcc/config/nds32/nds32.md
+++ b/gcc/config/nds32/nds32.md
@@ -57,7 +57,7 @@
 
 
 ;; True if the instruction requires TARGET_16_BIT.
-(define_attr "is_16bit" "no,yes" (const_string "no"))
+(define_attr "is_16bit" "no,yes" (const_string "no") "code,alternative")
 
 
 ;; Length, in bytes, default is 4-bytes.
@@ -76,7 +76,8 @@
   (cond [(and (eq_attr "is_16bit" "yes")
 	      (match_test "!TARGET_16_BIT"))
 	 (const_int 0)]
-	(const_int 1)))
+	(const_int 1))
+  "code,alternative")
 
 
 ;; ----------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 18/22] Use code,alternative attributes for sparc
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (16 preceding siblings ...)
  2015-11-25 12:33 ` [PR68432 16/22] Use code,alternative attributes for nds32 Richard Sandiford
@ 2015-11-25 12:34 ` Richard Sandiford
  2015-11-25 12:35 ` [PR68432 19/22] Use code,alternative for bool_attrs Richard Sandiford
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:34 UTC (permalink / raw)
  To: gcc-patches

Tested as described in the covering note.  I plan to commit this as obvious
if the prerequisites are approved.

gcc/
	* config/sparc/sparc.md (cpu_feature): Turn into a code,alternative
	attribute.
	(enabled): Likewise.

diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index 5c32689..56c1227 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -247,7 +247,9 @@
 	 (symbol_ref "TARGET_SPARCLET") (const_string "sparclet")]
 	(const_string "v7"))))
 
-(define_attr "cpu_feature" "none,fpu,fpunotv9,v9,vis,vis3" (const_string "none"))
+(define_attr "cpu_feature" "none,fpu,fpunotv9,v9,vis,vis3"
+  (const_string "none")
+  "code,alternative")
 
 (define_attr "enabled" ""
   (cond [(eq_attr "cpu_feature" "none") (const_int 1)
@@ -256,7 +258,8 @@
          (eq_attr "cpu_feature" "v9") (symbol_ref "TARGET_V9")
          (eq_attr "cpu_feature" "vis") (symbol_ref "TARGET_VIS")
          (eq_attr "cpu_feature" "vis3") (symbol_ref "TARGET_VIS3")]
-        (const_int 0)))
+        (const_int 0))
+  "code,alternative")
 
 ;; Insn type.
 (define_attr "type"

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 19/22] Use code,alternative for bool_attrs
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (17 preceding siblings ...)
  2015-11-25 12:34 ` [PR68432 18/22] Use code,alternative attributes for sparc Richard Sandiford
@ 2015-11-25 12:35 ` Richard Sandiford
  2015-11-25 12:36 ` [PR68432 20/22] Record attributes for define_expand Richard Sandiford
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:35 UTC (permalink / raw)
  To: gcc-patches

Now that all ports that use the "enabled", "preferred_for_size"
and "preferred_for_speed" attributes have been converted to use
"code,alternative", we can use them for the bool_attr code in recog.

The patch also exports the new form of get_bool_attr_mask for use
by patch 21.

Tested as described in the covering note.

gcc/
	* doc/md.texi: Require enabled, preferred_for_size and
	preferred_for_speed to be code,alternative attributes.
	* genattr.c (main): Use hook_int_int_int_1 as the default for
	get_attr_enabled, get_attr_preferred_for_size and
	get_attr_preferred_for_speed.
	* hooks.h (hook_int_int_int_1): Declare.
	* hooks.c (hook_int_int_int_1): New function.
	* recog.h (get_bool_attr_mask): Declare.
	* recog.c (get_bool_attr): Take an icode and alternative instead
	of an rtx_insn *.
	(get_bool_attr_mask_uncached): Take an icode instead of an rtx_insn *.
	Update call to get_bool_attr.
	(get_bool_attr_mask): Take an icode instead of an rtx_insn *.
	Update call to get_bool_attr_mask_uncached.  Make public.
	(get_enabled_alternatives): Update accordingly.
	(get_preferred_alternatives): Likewise.
	(check_bool_attrs): Likewise.

diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 5d3736c..fb0e7fb 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -4226,11 +4226,11 @@ optimized for speed.
 @end table
 
 All these attributes should use @code{(const_int 1)} to allow an alternative
-or @code{(const_int 0)} to disallow it.  The attributes must be a static
-property of the subtarget; they cannot for example depend on the
-current operands, on the current optimization level, on the location
-of the insn within the body of a loop, on whether register allocation
-has finished, or on the current compiler pass.
+or @code{(const_int 0)} to disallow it.  The attributes must have
+type @code{code,alternative} and be a static property of the
+subtarget; they cannot for example depend on the current operands, on
+the current optimization level, on whether register allocation has
+finished, or on the current compiler pass.
 
 The @code{enabled} attribute is a correctness property.  It tells GCC to act
 as though the disabled alternatives were never defined in the first place.
@@ -4295,14 +4295,16 @@ with the @code{enabled} attribute defined like this:
 
 @smallexample
 
-(define_attr "cpu_facility" "standard,new" (const_string "standard"))
+(define_attr "cpu_facility" "standard,new" (const_string "standard")
+  "code,alternative")
 
 (define_attr "enabled" ""
   (cond [(eq_attr "cpu_facility" "standard") (const_int 1)
          (and (eq_attr "cpu_facility" "new")
               (ne (symbol_ref "TARGET_NEW") (const_int 0)))
          (const_int 1)]
-        (const_int 0)))
+        (const_int 0))
+  "code,alternative")
 
 @end smallexample
 
@@ -8173,7 +8175,8 @@ distances. @xref{Insn Lengths}.
 @item enabled
 The @code{enabled} attribute can be defined to prevent certain
 alternatives of an insn definition from being used during code
-generation. @xref{Disable Insn Alternatives}.
+generation. @xref{Disable Insn Alternatives}.  This attribute must
+have type @code{code,alternative}.
 
 @item mnemonic
 The @code{mnemonic} attribute can be defined to implement instruction
diff --git a/gcc/genattr.c b/gcc/genattr.c
index c08c4af..3be3e38 100644
--- a/gcc/genattr.c
+++ b/gcc/genattr.c
@@ -355,15 +355,15 @@ main (int argc, char **argv)
 	"#define insn_current_length hook_int_rtx_insn_unreachable\n"
 	"#include \"insn-addr.h\"\n"
 	"#endif\n"
-	"extern int hook_int_rtx_1 (rtx);\n"
+	"extern int hook_int_int_int_1 (int, int);\n"
 	"#if !HAVE_ATTR_enabled\n"
-	"#define get_attr_enabled hook_int_rtx_1\n"
+	"#define get_attr_enabled hook_int_int_int_1\n"
 	"#endif\n"
 	"#if !HAVE_ATTR_preferred_for_size\n"
-	"#define get_attr_preferred_for_size hook_int_rtx_1\n"
+	"#define get_attr_preferred_for_size hook_int_int_int_1\n"
 	"#endif\n"
 	"#if !HAVE_ATTR_preferred_for_speed\n"
-	"#define get_attr_preferred_for_speed hook_int_rtx_1\n"
+	"#define get_attr_preferred_for_speed hook_int_int_int_1\n"
 	"#endif\n");
 
   /* Output flag masks for use by reorg.
diff --git a/gcc/hooks.c b/gcc/hooks.c
index 0fb9add..6b02b6f 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -191,6 +191,12 @@ default_can_output_mi_thunk_no_vcall (const_tree a ATTRIBUTE_UNUSED,
 }
 
 int
+hook_int_int_int_1 (int, int)
+{
+  return 1;
+}
+
+int
 hook_int_uint_mode_1 (unsigned int a ATTRIBUTE_UNUSED,
 		      machine_mode b ATTRIBUTE_UNUSED)
 {
diff --git a/gcc/hooks.h b/gcc/hooks.h
index c3d4bd3..15bede9 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -77,6 +77,7 @@ extern void hook_void_tree_treeptr (tree, tree *);
 extern void hook_void_int_int (int, int);
 extern void hook_void_gcc_optionsp (struct gcc_options *);
 
+extern int hook_int_int_int_1 (int, int);
 extern int hook_int_uint_mode_1 (unsigned int, machine_mode);
 extern int hook_int_const_tree_0 (const_tree);
 extern int hook_int_const_tree_const_tree_1 (const_tree, const_tree);
diff --git a/gcc/recog.c b/gcc/recog.c
index 04228f8..c42f82f 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -2042,19 +2042,22 @@ have_bool_attr (bool_attr attr)
   gcc_unreachable ();
 }
 
-/* Return the value of ATTR for instruction INSN.  */
+/* Return the value of ATTR for alternative ALTERNATIVE of the instruction
+   with code ICODE.  */
 
 static bool
-get_bool_attr (rtx_insn *insn, bool_attr attr)
+get_bool_attr (int icode, int alternative, bool_attr attr)
 {
   switch (attr)
     {
     case BA_ENABLED:
-      return get_attr_enabled (insn);
+      return get_attr_enabled (icode, alternative);
     case BA_PREFERRED_FOR_SIZE:
-      return get_attr_enabled (insn) && get_attr_preferred_for_size (insn);
+      return (get_attr_enabled (icode, alternative)
+	      && get_attr_preferred_for_size (icode, alternative));
     case BA_PREFERRED_FOR_SPEED:
-      return get_attr_enabled (insn) && get_attr_preferred_for_speed (insn);
+      return (get_attr_enabled (icode, alternative)
+	      && get_attr_preferred_for_speed (icode, alternative));
     }
   gcc_unreachable ();
 }
@@ -2062,49 +2065,35 @@ get_bool_attr (rtx_insn *insn, bool_attr attr)
 /* Like get_bool_attr_mask, but don't use the cache.  */
 
 static alternative_mask
-get_bool_attr_mask_uncached (rtx_insn *insn, bool_attr attr)
+get_bool_attr_mask_uncached (int icode, bool_attr attr)
 {
-  /* Temporarily install enough information for get_attr_<foo> to assume
-     that the insn operands are already cached.  As above, the attribute
-     mustn't depend on the values of operands, so we don't provide their
-     real values here.  */
-  rtx_insn *old_insn = recog_data.insn;
-  int old_alternative = cached_which_alternative;
-
-  recog_data.insn = insn;
   alternative_mask mask = ALL_ALTERNATIVES;
-  int n_alternatives = insn_data[INSN_CODE (insn)].n_alternatives;
+  int n_alternatives = MAX (insn_data[icode].n_alternatives, 1);
   for (int i = 0; i < n_alternatives; i++)
     {
-      cached_which_alternative = i;
-      if (!get_bool_attr (insn, attr))
+      if (!get_bool_attr (icode, i, attr))
 	mask &= ~ALTERNATIVE_BIT (i);
     }
 
-  recog_data.insn = old_insn;
-  cached_which_alternative = old_alternative;
   return mask;
 }
 
-/* Return the mask of operand alternatives that are allowed for INSN
-   by boolean attribute ATTR.  This mask depends only on INSN and on
-   the current target; it does not depend on things like the values of
-   operands.  */
+/* Return the mask of operand alternatives that are allowed for instruction
+   code ICODE by boolean attribute ATTR.  */
 
-static alternative_mask
-get_bool_attr_mask (rtx_insn *insn, bool_attr attr)
+alternative_mask
+get_bool_attr_mask (int icode, bool_attr attr)
 {
   /* Quick exit for asms and for targets that don't use these attributes.  */
-  int code = INSN_CODE (insn);
-  if (code < 0 || !have_bool_attr (attr))
+  if (icode < 0 || !have_bool_attr (attr))
     return ALL_ALTERNATIVES;
 
   /* Calling get_attr_<foo> can be expensive, so cache the mask
      for speed.  */
-  if (!this_target_recog->x_bool_attr_masks[code][attr])
-    this_target_recog->x_bool_attr_masks[code][attr]
-      = get_bool_attr_mask_uncached (insn, attr);
-  return this_target_recog->x_bool_attr_masks[code][attr];
+  if (!this_target_recog->x_bool_attr_masks[icode][attr])
+    this_target_recog->x_bool_attr_masks[icode][attr]
+      = get_bool_attr_mask_uncached (icode, attr);
+  return this_target_recog->x_bool_attr_masks[icode][attr];
 }
 
 /* Return the set of alternatives of INSN that are allowed by the current
@@ -2113,7 +2102,7 @@ get_bool_attr_mask (rtx_insn *insn, bool_attr attr)
 alternative_mask
 get_enabled_alternatives (rtx_insn *insn)
 {
-  return get_bool_attr_mask (insn, BA_ENABLED);
+  return get_bool_attr_mask (INSN_CODE (insn), BA_ENABLED);
 }
 
 /* Return the set of alternatives of INSN that are allowed by the current
@@ -2124,9 +2113,9 @@ alternative_mask
 get_preferred_alternatives (rtx_insn *insn)
 {
   if (optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)))
-    return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SPEED);
+    return get_bool_attr_mask (INSN_CODE (insn), BA_PREFERRED_FOR_SPEED);
   else
-    return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SIZE);
+    return get_bool_attr_mask (INSN_CODE (insn), BA_PREFERRED_FOR_SIZE);
 }
 
 /* Return the set of alternatives of INSN that are allowed by the current
@@ -2139,9 +2128,9 @@ alternative_mask
 get_preferred_alternatives (rtx_insn *insn, basic_block bb)
 {
   if (optimize_bb_for_speed_p (bb))
-    return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SPEED);
+    return get_bool_attr_mask (INSN_CODE (insn), BA_PREFERRED_FOR_SPEED);
   else
-    return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SIZE);
+    return get_bool_attr_mask (INSN_CODE (insn), BA_PREFERRED_FOR_SIZE);
 }
 
 /* Assert that the cached boolean attributes for INSN are still accurate.
@@ -2159,7 +2148,7 @@ check_bool_attrs (rtx_insn *insn)
 	enum bool_attr attr = (enum bool_attr) i;
 	if (this_target_recog->x_bool_attr_masks[code][attr])
 	  gcc_assert (this_target_recog->x_bool_attr_masks[code][attr]
-		      == get_bool_attr_mask_uncached (insn, attr));
+		      == get_bool_attr_mask_uncached (code, attr));
       }
   return true;
 }
diff --git a/gcc/recog.h b/gcc/recog.h
index b15140b..c8422f5 100644
--- a/gcc/recog.h
+++ b/gcc/recog.h
@@ -399,6 +399,7 @@ extern struct target_recog *this_target_recog;
 #define this_target_recog (&default_target_recog)
 #endif
 
+alternative_mask get_bool_attr_mask (int, bool_attr);
 alternative_mask get_enabled_alternatives (rtx_insn *);
 alternative_mask get_preferred_alternatives (rtx_insn *);
 alternative_mask get_preferred_alternatives (rtx_insn *, basic_block);

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 20/22] Record attributes for define_expand
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (18 preceding siblings ...)
  2015-11-25 12:35 ` [PR68432 19/22] Use code,alternative for bool_attrs Richard Sandiford
@ 2015-11-25 12:36 ` Richard Sandiford
  2015-11-25 15:55   ` Bernd Schmidt
  2015-11-25 12:37 ` [PR68432 21/22] Pass optimization type to direct_internal_fn_supported_p Richard Sandiford
                   ` (3 subsequent siblings)
  23 siblings, 1 reply; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:36 UTC (permalink / raw)
  To: gcc-patches

The define_subst support made it syntactically possible to add
attributes to a define_expand, but until now they had been ignored
by genattrtab.c.  This patch allows define_expands to have
"code,alternative" attributes but raises an error for general
"insn" attributes.   (Insn attributes would create a chicken-and-egg
problem because you'd need to call the expander to get the insn.)

The point is to allow define_expands to have preferred_for_size
and preferred_for_speed attributes.

Tested as described in the covering note.

gcc/
	* genattrtab.c (insn_def): Add max_type field.
	(check_defs): Check that the type of a define_expand attribute
	is acceptable.
	(gen_insn): Handle DEFINE_EXPAND.  Initialize the max_type field.
	(main): Handle DEFINE_EXPAND.

diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c
index 6f797bf..42f6dc5 100644
--- a/gcc/genattrtab.c
+++ b/gcc/genattrtab.c
@@ -142,6 +142,7 @@ struct insn_def
   file_location loc;		/* Where in the .md files it occurs.  */
   int num_alternatives;		/* Number of alternatives.  */
   int vec_idx;			/* Index of attribute vector in `def'.  */
+  attr_type max_type;		/* Maximum allowable type.  */
 };
 
 /* Once everything has been read in, we store in each attribute value a list
@@ -1167,6 +1168,14 @@ check_defs (void)
 			XSTR (XEXP (value, 0), 0));
 	      continue;
 	    }
+	  if (id->max_type < attr->type)
+	    {
+	      error_at (id->loc, "`%s's cannot have %s attribute `%s'",
+			GET_RTX_NAME (GET_CODE (id->def)),
+			get_attr_type_name (attr->type),
+			attr->name);
+	      continue;
+	    }
 
 	  XVECEXP (id->def, id->vec_idx, i) = value;
 	  XEXP (value, 1) = check_attr_value (id->loc, XEXP (value, 1), attr);
@@ -3283,6 +3292,14 @@ gen_insn (md_rtx_info *info)
 
   switch (GET_CODE (def))
     {
+    case DEFINE_EXPAND:
+      id->insn_code = info->index;
+      id->insn_index = insn_index_number;
+      id->num_alternatives = 1;
+      id->vec_idx = 4;
+      id->max_type = AT_CODE_ALT;
+      break;
+
     case DEFINE_INSN:
       id->insn_code = info->index;
       id->insn_index = insn_index_number;
@@ -3290,6 +3307,7 @@ gen_insn (md_rtx_info *info)
       if (id->num_alternatives == 0)
 	id->num_alternatives = 1;
       id->vec_idx = 4;
+      id->max_type = AT_INSN;
       break;
 
     case DEFINE_PEEPHOLE:
@@ -3299,6 +3317,7 @@ gen_insn (md_rtx_info *info)
       if (id->num_alternatives == 0)
 	id->num_alternatives = 1;
       id->vec_idx = 3;
+      id->max_type = AT_INSN;
       break;
 
     case DEFINE_ASM_ATTRIBUTES:
@@ -3306,6 +3325,7 @@ gen_insn (md_rtx_info *info)
       id->insn_index = -1;
       id->num_alternatives = 1;
       id->vec_idx = 0;
+      id->max_type = AT_INSN;
       got_define_asm_attributes = 1;
       break;
 
@@ -5266,6 +5286,7 @@ main (int argc, char **argv)
     {
       switch (GET_CODE (info.def))
 	{
+	case DEFINE_EXPAND:
 	case DEFINE_INSN:
 	case DEFINE_PEEPHOLE:
 	case DEFINE_ASM_ATTRIBUTES:

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 21/22] Pass optimization type to direct_internal_fn_supported_p
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (19 preceding siblings ...)
  2015-11-25 12:36 ` [PR68432 20/22] Record attributes for define_expand Richard Sandiford
@ 2015-11-25 12:37 ` Richard Sandiford
  2015-11-25 12:38 ` [PR68432 22/22] Use preferred_for_size in i386 internal fn optabs Richard Sandiford
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:37 UTC (permalink / raw)
  To: gcc-patches

This adds an argument to direct_internal_fn_supported_p that says
whether the function is going to be used in code optimised for size
or speed.  It also has a "both" option for cases where we want code
that is optimised for both size and speed.

At the moment the match-and-simplify code doesn't have direct access
to the target block, so for now I've used "both" there.

Tested as described in the covering note.

gcc/
	* coretypes.h (optimization_type): New enum.
	* predict.h (function_optimization_type): Declare.
	(bb_optimization_type): Likewise.
	* predict.c (function_optimization_type): New function.
	(bb_optimization_type): Likewise.
	* optabs-query.h (optab_supported_p): Declare.
	* optabs-query.c (optab_supported_p): New function.
	* internal-fn.h (direct_internal_fn_supported_p): Take an
	optimization_type argument.
	* internal-fn.c (direct_optab_supported_p): Likewise.
	(multi_vector_optab_supported_p): Likewise.
	(direct_internal_fn_supported_p): Likewise.
	* builtins.c (replacement_internal_fn): Update call to
	direct_internal_fn_supported_p.
	* gimple-match-head.c (build_call_internal): Likewise.
	* tree-vect-patterns.c (vect_recog_pow_pattern): Likewise.
	* tree-vect-stmts.c (vectorizable_internal_function): Likewise.
	* tree.c (maybe_build_call_expr_loc): Likewise.

diff --git a/gcc/builtins.c b/gcc/builtins.c
index df5c493..7c614e6 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -1962,7 +1962,8 @@ replacement_internal_fn (gcall *call)
       if (ifn != IFN_LAST)
 	{
 	  tree_pair types = direct_internal_fn_types (ifn, call);
-	  if (direct_internal_fn_supported_p (ifn, types))
+	  optimization_type opt_type = bb_optimization_type (gimple_bb (call));
+	  if (direct_internal_fn_supported_p (ifn, types, opt_type))
 	    return ifn;
 	}
     }
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index d4a75db..5a9fb63 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -200,6 +200,18 @@ enum node_frequency {
   NODE_FREQUENCY_HOT
 };
 
+/* Ways of optimizing code.  */
+enum optimization_type {
+  /* Prioritize speed over size.  */
+  OPTIMIZE_FOR_SPEED,
+
+  /* Only do things that are good for both size and speed.  */
+  OPTIMIZE_FOR_BOTH,
+
+  /* Prioritize size over speed.  */
+  OPTIMIZE_FOR_SIZE
+};
+
 /* Possible initialization status of a variable.   When requested
    by the user, this information is tracked and recorded in the DWARF
    debug information, along with the variable's location.  */
diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c
index bdc1f98..049ebab 100644
--- a/gcc/gimple-match-head.c
+++ b/gcc/gimple-match-head.c
@@ -261,7 +261,7 @@ build_call_internal (internal_fn fn, tree type, unsigned int nargs, tree *ops)
   if (direct_internal_fn_p (fn))
     {
       tree_pair types = direct_internal_fn_types (fn, type, ops);
-      if (!direct_internal_fn_supported_p (fn, types))
+      if (!direct_internal_fn_supported_p (fn, types, OPTIMIZE_FOR_BOTH))
 	return NULL;
     }
   return gimple_build_call_internal (fn, nargs, ops[0], ops[1], ops[2]);
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index b15657f..c6d2c9a 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -2214,23 +2214,28 @@ direct_internal_fn_types (internal_fn fn, gcall *call)
 }
 
 /* Return true if OPTAB is supported for TYPES (whose modes should be
-   the same).  Used for simple direct optabs.  */
+   the same) when the optimization type is OPT_TYPE.  Used for simple
+   direct optabs.  */
 
 static bool
-direct_optab_supported_p (direct_optab optab, tree_pair types)
+direct_optab_supported_p (direct_optab optab, tree_pair types,
+			  optimization_type opt_type)
 {
   machine_mode mode = TYPE_MODE (types.first);
   gcc_checking_assert (mode == TYPE_MODE (types.second));
-  return direct_optab_handler (optab, mode) != CODE_FOR_nothing;
+  insn_code icode = direct_optab_handler (optab, mode);
+  return optab_supported_p (icode, opt_type);
 }
 
 /* Return true if load/store lanes optab OPTAB is supported for
-   array type TYPES.first.  */
+   array type TYPES.first when the optimization type is OPT_TYPE.  */
 
 static bool
-multi_vector_optab_supported_p (convert_optab optab, tree_pair types)
+multi_vector_optab_supported_p (convert_optab optab, tree_pair types,
+				optimization_type opt_type)
 {
-  return get_multi_vector_move (types.first, optab) != CODE_FOR_nothing;
+  insn_code icode = get_multi_vector_move (types.first, optab);
+  return optab_supported_p (icode, opt_type);
 }
 
 #define direct_unary_optab_supported_p direct_optab_supported_p
@@ -2240,12 +2245,14 @@ multi_vector_optab_supported_p (convert_optab optab, tree_pair types)
 #define direct_mask_store_optab_supported_p direct_optab_supported_p
 #define direct_store_lanes_optab_supported_p multi_vector_optab_supported_p
 
-/* Return true if FN is supported for the types in TYPES.  The types
-   are those associated with the "type0" and "type1" fields of FN's
-   direct_internal_fn_info structure.  */
+/* Return true if FN is supported for the types in TYPES when the
+   optimization type is OPT_TYPE.  The types are those associated with
+   the "type0" and "type1" fields of FN's direct_internal_fn_info
+   structure.  */
 
 bool
-direct_internal_fn_supported_p (internal_fn fn, tree_pair types)
+direct_internal_fn_supported_p (internal_fn fn, tree_pair types,
+				optimization_type opt_type)
 {
   switch (fn)
     {
@@ -2253,7 +2260,8 @@ direct_internal_fn_supported_p (internal_fn fn, tree_pair types)
     case IFN_##CODE: break;
 #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
     case IFN_##CODE: \
-      return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types);
+      return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types, \
+						opt_type);
 #include "internal-fn.def"
 
     case IFN_LAST:
@@ -2262,16 +2270,17 @@ direct_internal_fn_supported_p (internal_fn fn, tree_pair types)
   gcc_unreachable ();
 }
 
-/* Return true if FN is supported for type TYPE.  The caller knows that
-   the "type0" and "type1" fields of FN's direct_internal_fn_info
-   structure are the same.  */
+/* Return true if FN is supported for type TYPE when the optimization
+   type is OPT_TYPE.  The caller knows that the "type0" and "type1"
+   fields of FN's direct_internal_fn_info structure are the same.  */
 
 bool
-direct_internal_fn_supported_p (internal_fn fn, tree type)
+direct_internal_fn_supported_p (internal_fn fn, tree type,
+				optimization_type opt_type)
 {
   const direct_internal_fn_info &info = direct_internal_fn (fn);
   gcc_checking_assert (info.type0 == info.type1);
-  return direct_internal_fn_supported_p (fn, tree_pair (type, type));
+  return direct_internal_fn_supported_p (fn, tree_pair (type, type), opt_type);
 }
 
 /* Return true if IFN_SET_EDOM is supported.  */
diff --git a/gcc/internal-fn.h b/gcc/internal-fn.h
index aea6abd..ef27f09 100644
--- a/gcc/internal-fn.h
+++ b/gcc/internal-fn.h
@@ -166,8 +166,10 @@ direct_internal_fn (internal_fn fn)
 
 extern tree_pair direct_internal_fn_types (internal_fn, tree, tree *);
 extern tree_pair direct_internal_fn_types (internal_fn, gcall *);
-extern bool direct_internal_fn_supported_p (internal_fn, tree_pair);
-extern bool direct_internal_fn_supported_p (internal_fn, tree);
+extern bool direct_internal_fn_supported_p (internal_fn, tree_pair,
+					    optimization_type);
+extern bool direct_internal_fn_supported_p (internal_fn, tree,
+					    optimization_type);
 extern bool set_edom_supported_p (void);
 
 extern void expand_internal_call (gcall *);
diff --git a/gcc/optabs-query.c b/gcc/optabs-query.c
index c20597c..a059aa2 100644
--- a/gcc/optabs-query.c
+++ b/gcc/optabs-query.c
@@ -35,6 +35,36 @@ struct target_optabs *this_fn_optabs = &default_target_optabs;
 struct target_optabs *this_target_optabs = &default_target_optabs;
 #endif
 
+/* Return true if ICODE is a valid instruction number and the instruction
+   is supported for optimization type OPT_TYPE.  We allow CODE_FOR_nothing
+   to be passed so that callers can use this function instead of, rather
+   than as well as, an explicit check for CODE_nothing.  */
+
+bool
+optab_supported_p (insn_code icode, optimization_type opt_type)
+{
+  if (icode == CODE_FOR_nothing)
+    return false;
+
+  switch (opt_type)
+    {
+    case OPTIMIZE_FOR_SPEED:
+      return (get_bool_attr_mask (icode, BA_PREFERRED_FOR_SPEED)
+	      == get_bool_attr_mask (icode, BA_ENABLED));
+
+    case OPTIMIZE_FOR_SIZE:
+      return (get_bool_attr_mask (icode, BA_PREFERRED_FOR_SIZE)
+	      == get_bool_attr_mask (icode, BA_ENABLED));
+
+    case OPTIMIZE_FOR_BOTH:
+      /* Require the choice to be good for both size and speed.  */
+      return ((get_bool_attr_mask (icode, BA_PREFERRED_FOR_SIZE)
+	       & get_bool_attr_mask (icode, BA_PREFERRED_FOR_SPEED))
+	      == get_bool_attr_mask (icode, BA_ENABLED));
+    }
+  gcc_unreachable ();
+}
+
 /* Enumerates the possible types of structure operand to an
    extraction_insn.  */
 enum extraction_type { ET_unaligned_mem, ET_reg };
diff --git a/gcc/optabs-query.h b/gcc/optabs-query.h
index 48bcf7c..1898b57 100644
--- a/gcc/optabs-query.h
+++ b/gcc/optabs-query.h
@@ -136,6 +136,7 @@ bool get_best_mem_extraction_insn (extraction_insn *,
 				   enum extraction_pattern,
 				   HOST_WIDE_INT, HOST_WIDE_INT, machine_mode);
 
+bool optab_supported_p (insn_code, optimization_type);
 enum insn_code can_extend_p (machine_mode, machine_mode, int);
 enum insn_code can_float_p (machine_mode, machine_mode, int);
 enum insn_code can_fix_p (machine_mode, machine_mode, int, bool *);
diff --git a/gcc/predict.c b/gcc/predict.c
index 7e0f848..d5c40de 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -269,6 +269,16 @@ optimize_function_for_speed_p (struct function *fun)
   return !optimize_function_for_size_p (fun);
 }
 
+/* Return the optimization type that should be used for the function FUN.  */
+
+optimization_type
+function_optimization_type (struct function *fun)
+{
+  return (optimize_function_for_speed_p (fun)
+	  ? OPTIMIZE_FOR_SPEED
+	  : OPTIMIZE_FOR_SIZE);
+}
+
 /* Return TRUE when BB should be optimized for size.  */
 
 bool
@@ -286,6 +296,16 @@ optimize_bb_for_speed_p (const_basic_block bb)
   return !optimize_bb_for_size_p (bb);
 }
 
+/* Return the optimization type that should be used for block BB.  */
+
+optimization_type
+bb_optimization_type (const_basic_block bb)
+{
+  return (optimize_bb_for_speed_p (bb)
+	  ? OPTIMIZE_FOR_SPEED
+	  : OPTIMIZE_FOR_SIZE);
+}
+
 /* Return TRUE when BB should be optimized for size.  */
 
 bool
diff --git a/gcc/predict.h b/gcc/predict.h
index 85150fe..486ce17 100644
--- a/gcc/predict.h
+++ b/gcc/predict.h
@@ -54,8 +54,10 @@ extern bool probably_never_executed_bb_p (struct function *, const_basic_block);
 extern bool probably_never_executed_edge_p (struct function *, edge);
 extern bool optimize_function_for_size_p (struct function *);
 extern bool optimize_function_for_speed_p (struct function *);
+extern optimization_type function_optimization_type (struct function *);
 extern bool optimize_bb_for_size_p (const_basic_block);
 extern bool optimize_bb_for_speed_p (const_basic_block);
+extern optimization_type bb_optimization_type (const_basic_block);
 extern bool optimize_edge_for_size_p (edge);
 extern bool optimize_edge_for_speed_p (edge);
 extern bool optimize_insn_for_size_p (void);
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index 5bab1f5..cd142e1 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -1056,7 +1056,9 @@ vect_recog_pow_pattern (vec<gimple *> *stmts, tree *type_in,
       && real_equal (&TREE_REAL_CST (exp), &dconsthalf))
     {
       *type_in = get_vectype_for_scalar_type (TREE_TYPE (base));
-      if (*type_in && direct_internal_fn_supported_p (IFN_SQRT, *type_in))
+      if (*type_in
+	  && direct_internal_fn_supported_p (IFN_SQRT, *type_in,
+					     OPTIMIZE_FOR_SPEED))
 	{
 	  gcall *stmt = gimple_build_call_internal (IFN_SQRT, 1, base);
 	  var = vect_recog_temp_ssa_var (TREE_TYPE (base), stmt);
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 687f982..fe6f44b 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -1663,7 +1663,8 @@ vectorizable_internal_function (combined_fn cfn, tree fndecl,
 	{
 	  tree type0 = (info.type0 < 0 ? vectype_out : vectype_in);
 	  tree type1 = (info.type1 < 0 ? vectype_out : vectype_in);
-	  if (direct_internal_fn_supported_p (ifn, tree_pair (type0, type1)))
+	  if (direct_internal_fn_supported_p (ifn, tree_pair (type0, type1),
+					      OPTIMIZE_FOR_SPEED))
 	    return ifn;
 	}
     }
diff --git a/gcc/tree.c b/gcc/tree.c
index 779fe93..e367030 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -11124,7 +11124,8 @@ maybe_build_call_expr_loc (location_t loc, combined_fn fn, tree type,
       if (direct_internal_fn_p (ifn))
 	{
 	  tree_pair types = direct_internal_fn_types (ifn, type, argarray);
-	  if (!direct_internal_fn_supported_p (ifn, types))
+	  if (!direct_internal_fn_supported_p (ifn, types,
+					       OPTIMIZE_FOR_BOTH))
 	    return NULL_TREE;
 	}
       return build_call_expr_internal_loc_array (loc, ifn, type, n, argarray);

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PR68432 22/22] Use preferred_for_size in i386 internal fn optabs
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (20 preceding siblings ...)
  2015-11-25 12:37 ` [PR68432 21/22] Pass optimization type to direct_internal_fn_supported_p Richard Sandiford
@ 2015-11-25 12:38 ` Richard Sandiford
  2015-11-25 12:51 ` [PR68432 00/26] Handle size/speed choices for internal functions Richard Biener
  2015-11-26 14:21 ` Bernd Schmidt
  23 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 12:38 UTC (permalink / raw)
  To: gcc-patches

After all the set-up, this patch fixes the PR by converting
the internal-fn-related optimize_insn_for_size_p checks into
preferred_for_size attributes.

Tested as described in the covering note.

gcc/
	PR tree-optimization/68432
	* config/i386/i386.md (asinxf2): Replace optimize_insn_for_size_p
	check with a preferred_for_size attribute.
	(asin<mode>2, acosxf2, acos<mode>2, log1pxf2, log1p<mode>2)
	(expxf2, exp<mode>2, exp10xf2, exp10<mode>2, exp2xf2, exp2<mode>2)
	(expm1xf2, expm1<mode>2, ldexpxf3, ldexp<mode>3, scalbxf3)
	(scalb<mode>3, rint<mode>2, round<mode>2, <rounding_insn>xf2)
	(<rounding_insn><mode>2): Likewise.
	(expNcorexf3): Remove optimize_insn_for_size_p check.

gcc/testsuite/
	* gcc.target/i386/pr68432-1.c: New test.
	* gcc.target/i386/pr68432-2.c: Likewise.
	* gcc.target/i386/pr68432-3.c: Likewise.

diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 87f60c0..be04a65 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -14725,14 +14725,12 @@
 {
   int i;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   for (i = 2; i < 6; i++)
     operands[i] = gen_reg_rtx (XFmode);
 
   emit_move_insn (operands[3], CONST1_RTX (XFmode));  /* fld1 */
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "asin<mode>2"
   [(use (match_operand:MODEF 0 "register_operand"))
@@ -14745,14 +14743,12 @@
   rtx op0 = gen_reg_rtx (XFmode);
   rtx op1 = gen_reg_rtx (XFmode);
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   emit_insn (gen_extend<mode>xf2 (op1, operands[1]));
   emit_insn (gen_asinxf2 (op0, op1));
   emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "acosxf2"
   [(set (match_dup 2)
@@ -14769,14 +14765,12 @@
 {
   int i;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   for (i = 2; i < 6; i++)
     operands[i] = gen_reg_rtx (XFmode);
 
   emit_move_insn (operands[3], CONST1_RTX (XFmode));  /* fld1 */
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "acos<mode>2"
   [(use (match_operand:MODEF 0 "register_operand"))
@@ -14789,14 +14783,12 @@
   rtx op0 = gen_reg_rtx (XFmode);
   rtx op1 = gen_reg_rtx (XFmode);
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   emit_insn (gen_extend<mode>xf2 (op1, operands[1]));
   emit_insn (gen_acosxf2 (op0, op1));
   emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_insn "fyl2xxf3_i387"
   [(set (match_operand:XF 0 "register_operand" "=f")
@@ -14952,12 +14944,10 @@
   "TARGET_USE_FANCY_MATH_387
    && flag_unsafe_math_optimizations"
 {
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   ix86_emit_i387_log1p (operands[0], operands[1]);
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "log1p<mode>2"
   [(use (match_operand:MODEF 0 "register_operand"))
@@ -14969,9 +14959,6 @@
 {
   rtx op0;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   op0 = gen_reg_rtx (XFmode);
 
   operands[1] = gen_rtx_FLOAT_EXTEND (XFmode, operands[1]);
@@ -14979,7 +14966,8 @@
   ix86_emit_i387_log1p (op0, operands[1]);
   emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_insn "fxtractxf3_i387"
   [(set (match_operand:XF 0 "register_operand" "=f")
@@ -15065,9 +15053,6 @@
 {
   rtx op0, op1;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   op0 = gen_reg_rtx (XFmode);
   op1 = gen_reg_rtx (XFmode);
 
@@ -15120,9 +15105,6 @@
 {
   int i;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   for (i = 3; i < 10; i++)
     operands[i] = gen_reg_rtx (XFmode);
 
@@ -15137,15 +15119,13 @@
 {
   rtx op2;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   op2 = gen_reg_rtx (XFmode);
   emit_move_insn (op2, standard_80387_constant_rtx (5)); /* fldl2e */
 
   emit_insn (gen_expNcorexf3 (operands[0], operands[1], op2));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "exp<mode>2"
   [(use (match_operand:MODEF 0 "register_operand"))
@@ -15157,9 +15137,6 @@
 {
   rtx op0, op1;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   op0 = gen_reg_rtx (XFmode);
   op1 = gen_reg_rtx (XFmode);
 
@@ -15167,7 +15144,8 @@
   emit_insn (gen_expxf2 (op0, op1));
   emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "exp10xf2"
   [(use (match_operand:XF 0 "register_operand"))
@@ -15177,15 +15155,13 @@
 {
   rtx op2;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   op2 = gen_reg_rtx (XFmode);
   emit_move_insn (op2, standard_80387_constant_rtx (6)); /* fldl2t */
 
   emit_insn (gen_expNcorexf3 (operands[0], operands[1], op2));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "exp10<mode>2"
   [(use (match_operand:MODEF 0 "register_operand"))
@@ -15197,9 +15173,6 @@
 {
   rtx op0, op1;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   op0 = gen_reg_rtx (XFmode);
   op1 = gen_reg_rtx (XFmode);
 
@@ -15207,7 +15180,8 @@
   emit_insn (gen_exp10xf2 (op0, op1));
   emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "exp2xf2"
   [(use (match_operand:XF 0 "register_operand"))
@@ -15217,15 +15191,13 @@
 {
   rtx op2;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   op2 = gen_reg_rtx (XFmode);
   emit_move_insn (op2, CONST1_RTX (XFmode));  /* fld1 */
 
   emit_insn (gen_expNcorexf3 (operands[0], operands[1], op2));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "exp2<mode>2"
   [(use (match_operand:MODEF 0 "register_operand"))
@@ -15237,9 +15209,6 @@
 {
   rtx op0, op1;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   op0 = gen_reg_rtx (XFmode);
   op1 = gen_reg_rtx (XFmode);
 
@@ -15247,7 +15216,8 @@
   emit_insn (gen_exp2xf2 (op0, op1));
   emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "expm1xf2"
   [(set (match_dup 3) (mult:XF (match_operand:XF 1 "register_operand")
@@ -15277,9 +15247,6 @@
 {
   int i;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   for (i = 2; i < 13; i++)
     operands[i] = gen_reg_rtx (XFmode);
 
@@ -15287,7 +15254,8 @@
     = validize_mem (force_const_mem (SFmode, CONST1_RTX (SFmode))); /* fld1 */
 
   emit_move_insn (operands[2], standard_80387_constant_rtx (5)); /* fldl2e */
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "expm1<mode>2"
   [(use (match_operand:MODEF 0 "register_operand"))
@@ -15299,9 +15267,6 @@
 {
   rtx op0, op1;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   op0 = gen_reg_rtx (XFmode);
   op1 = gen_reg_rtx (XFmode);
 
@@ -15309,7 +15274,8 @@
   emit_insn (gen_expm1xf2 (op0, op1));
   emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "ldexpxf3"
   [(match_operand:XF 0 "register_operand")
@@ -15319,8 +15285,6 @@
    && flag_unsafe_math_optimizations"
 {
   rtx tmp1, tmp2;
-  if (optimize_insn_for_size_p ())
-    FAIL;
 
   tmp1 = gen_reg_rtx (XFmode);
   tmp2 = gen_reg_rtx (XFmode);
@@ -15329,7 +15293,8 @@
   emit_insn (gen_fscalexf4_i387 (operands[0], tmp2,
                                  operands[1], tmp1));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "ldexp<mode>3"
   [(use (match_operand:MODEF 0 "register_operand"))
@@ -15352,7 +15317,8 @@
   emit_insn (gen_ldexpxf3 (op0, op1, operands[2]));
   emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "scalbxf3"
   [(parallel [(set (match_operand:XF 0 " register_operand")
@@ -15365,11 +15331,9 @@
   "TARGET_USE_FANCY_MATH_387
    && flag_unsafe_math_optimizations"
 {
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   operands[3] = gen_reg_rtx (XFmode);
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "scalb<mode>3"
   [(use (match_operand:MODEF 0 "register_operand"))
@@ -15382,9 +15346,6 @@
 {
   rtx op0, op1, op2;
 
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   op0 = gen_reg_rtx (XFmode);
   op1 = gen_reg_rtx (XFmode);
   op2 = gen_reg_rtx (XFmode);
@@ -15394,7 +15355,8 @@
   emit_insn (gen_scalbxf3 (op0, op1, op2));
   emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "significandxf2"
   [(parallel [(set (match_operand:XF 0 "register_operand")
@@ -15462,8 +15424,6 @@
       if (TARGET_ROUND)
 	emit_insn (gen_sse4_1_round<mode>2
 		   (operands[0], operands[1], GEN_INT (ROUND_MXCSR)));
-      else if (optimize_insn_for_size_p ())
-        FAIL;
       else
 	ix86_expand_rint (operands[0], operands[1]);
     }
@@ -15478,7 +15438,12 @@
       emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
     }
   DONE;
-})
+}
+  [(set (attr "preferred_for_size")
+	(symbol_ref "!(SSE_FLOAT_MODE_P (<MODE>mode)
+		       && TARGET_SSE_MATH
+		       && !flag_trapping_math)
+		      || TARGET_ROUND"))])
 
 (define_expand "round<mode>2"
   [(match_operand:X87MODEF 0 "register_operand")
@@ -15490,9 +15455,6 @@
    || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
        && !flag_trapping_math && !flag_rounding_math)"
 {
-  if (optimize_insn_for_size_p ())
-    FAIL;
-
   if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
       && !flag_trapping_math && !flag_rounding_math)
     {
@@ -15512,7 +15474,8 @@
       ix86_emit_i387_round (operands[0], operands[1]);
     }
   DONE;
-})
+}
+  [(set_attr "preferred_for_size" "0")])
 
 (define_insn_and_split "*fistdi2_1"
   [(set (match_operand:DI 0 "nonimmediate_operand")
@@ -15746,8 +15709,9 @@
 			      FRNDINT_ROUNDING))
 	      (clobber (reg:CC FLAGS_REG))])]
   "TARGET_USE_FANCY_MATH_387
-   && flag_unsafe_math_optimizations
-   && !optimize_insn_for_size_p ()")
+   && flag_unsafe_math_optimizations"
+  ""
+  [(set_attr "preferred_for_size" "0")])
 
 (define_expand "<rounding_insn><mode>2"
   [(parallel [(set (match_operand:MODEF 0 "register_operand")
@@ -15767,8 +15731,6 @@
       if (TARGET_ROUND)
 	emit_insn (gen_sse4_1_round<mode>2
 		   (operands[0], operands[1], GEN_INT (ROUND_<ROUNDING>)));
-      else if (optimize_insn_for_size_p ())
-	FAIL;
       else if (TARGET_64BIT || (<MODE>mode != DFmode))
 	{
 	  if (ROUND_<ROUNDING> == ROUND_FLOOR)
@@ -15796,9 +15758,6 @@
     {
       rtx op0, op1;
 
-      if (optimize_insn_for_size_p ())
-	FAIL;
-
       op0 = gen_reg_rtx (XFmode);
       op1 = gen_reg_rtx (XFmode);
       emit_insn (gen_extend<mode>xf2 (op1, operands[1]));
@@ -15807,7 +15766,12 @@
       emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
     }
   DONE;
-})
+}
+  [(set (attr "preferred_for_size")
+	(symbol_ref "SSE_FLOAT_MODE_P (<MODE>mode)
+		     && TARGET_SSE_MATH
+		     && TARGET_ROUND
+		     && !flag_trapping_math"))])
 
 ;; Rounding mode control word calculation could clobber FLAGS_REG.
 (define_insn_and_split "frndintxf2_mask_pm"
diff --git a/gcc/testsuite/gcc.target/i386/pr68432-1.c b/gcc/testsuite/gcc.target/i386/pr68432-1.c
new file mode 100644
index 0000000..8493652
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr68432-1.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-math-errno -fno-trapping-math -msse2 -mfpmath=sse" } */
+
+float
+f1 (float f)
+{
+  return __builtin_rintf (f);
+}
+
+double
+f2 (double f)
+{
+  return __builtin_rint (f);
+}
+
+/* { dg-final { scan-assembler-times "\tucomiss\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tucomisd\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr68432-2.c b/gcc/testsuite/gcc.target/i386/pr68432-2.c
new file mode 100644
index 0000000..8a0c295
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr68432-2.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fno-math-errno -fno-trapping-math -msse2 -mfpmath=sse" } */
+
+float
+f1 (float f)
+{
+  return __builtin_rintf (f);
+}
+
+double
+f2 (double f)
+{
+  return __builtin_rint (f);
+}
+
+/* { dg-final { scan-assembler-not "\tucomiss\t" } } */
+/* { dg-final { scan-assembler-not "\tucomisd\t" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr68432-3.c b/gcc/testsuite/gcc.target/i386/pr68432-3.c
new file mode 100644
index 0000000..5f22972
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr68432-3.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-math-errno -fno-trapping-math -msse2 -mfpmath=sse" } */
+
+float __attribute__ ((cold))
+f1 (float f)
+{
+  return __builtin_rintf (f);
+}
+
+double __attribute__ ((cold))
+f2 (double f)
+{
+  return __builtin_rint (f);
+}
+
+/* { dg-final { scan-assembler-not "\tucomiss\t" } } */
+/* { dg-final { scan-assembler-not "\tucomisd\t" } } */

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (21 preceding siblings ...)
  2015-11-25 12:38 ` [PR68432 22/22] Use preferred_for_size in i386 internal fn optabs Richard Sandiford
@ 2015-11-25 12:51 ` Richard Biener
  2015-11-25 13:47   ` Richard Sandiford
  2015-11-26 14:21 ` Bernd Schmidt
  23 siblings, 1 reply; 45+ messages in thread
From: Richard Biener @ 2015-11-25 12:51 UTC (permalink / raw)
  To: GCC Patches, richard.sandiford

On Wed, Nov 25, 2015 at 1:20 PM, Richard Sandiford
<richard.sandiford@arm.com> wrote:
> This series fixes PR 68432, a regression caused by my internal-functions-
> for-optabs series.  Some of the libm optabs in i386.md have a true HAVE_*
> condition but conditionally FAIL if we're optimising for size:
>
>   if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
>       && !flag_trapping_math)
>     {
>       if (TARGET_ROUND)
>         emit_insn (gen_sse4_1_round<mode>2
>                    (operands[0], operands[1], GEN_INT (ROUND_MXCSR)));
>       else if (optimize_insn_for_size_p ())
>         FAIL;
>       else
>         ix86_expand_rint (operands[0], operands[1]);
>     }
>
> This is going to cause problems if we want to make more decisions
> related to optabs at the gimple level.
>
> We've already had the same problem in rtl, where some patterns used
> to check optimize_insn_for_size_p in their C condition, and would then
> fail to match if an instruction were moved from a hot block to a cold
> block.  Now rtl has two attributes, preferred_for_size and
> preferred_for_speed, that say whether a particular alternative of a
> particular instruction should be used when optimising for size or speed
> respectively.  We try to honour a "false" value as much as possible,
> but it's not an absolute guarantee.
>
> The point of this series is to extend preferred_for_size and
> preferred_for_speed to define_expands, so that the attributes
> can be tested for optabs too.

So to not re-introduce the same position issue at GIMPLE (passes
querying optimize_bb_for_speed/size and with that querying
the optab for IFN support) when expanding an internal function
you ignore whether it actually "exists"?  That is, IFN expansion
will skip the define_expand (which is maybe disabled)?

Otherwise cleaning this things up is nice.  The question is whether
it really solves all the issues ;)

Richard.

> enabled, preferred_for_size and preferred_for_speed are supposed
> to be an inavariant property of a given (code, alternative) pair.
> They're not supposed to depend on a particular insn or its operands.
> However, the attribute functions still take an rtx_insn * as argument,
> so mistakes are only caught at runtime if we see a specific instruction
> for which the attributes conflict with the cached ones
> (recog.c:check_bool_attrs).
>
> Extending the attributes to define_expands means that we finally
> need to "fix" that and make the attributes take a (code, alternative)
> pair instead.  Most ports were already structured to allow that.
> The two exceptions are ARM and NDS32.
>
> The problem for NDS32 is that "enabled" depends on "length", which
> needs access to an instruction in order to calculate branch lengths.
> This isn't a problem in practice because all instructions with
> operand-dependent lengths force "enabled" to 1.  However,
> it's easier to enforce the restriction at compile time if we
> have an "is_16bit" attribute, to go along with the TARGET_16_BIT
> condition that controls whether 16-bit instructions can be used.
>
> The problem for ARM is that "enabled" depends on "type" and
> "use_literal_pool", both of which use match_operand tests in some cases.
> I think the "type" match_operands were actually OK for "enabled" in
> practice, but I think the "use_literal_pool" ones are a genuine bug.
> They are used when we have one alternative that accepts both memory and
> immediate operands.  The alternative is supposed to be disabled for
> immediate operands when arm_disable_literal_pool is true, but not
> disabled for memory operands.  However, the "enabled" cache only cares
> about the alternative number, so we can end up disabling memory operands
> if we cached based on an immediate operand, or allow immediate operands
> if we cached based on a memory operand.  The series fixes that by
> splitting alternatives where necessary.
>
> Due to the define_subst patches, it's already syntactically possible to
> attach attributes to define_expands, but genattrtab.c currently ignores
> them.  The series restricts these attributes to the new "code,alternative"
> style and then handles them in the same way as define_insn attributes.
>
> I realise this is rather invasive for stage 3, but I think it's
> worth fixing the bug "properly" rather than papering over it.
> The ARM "use_literal_pool" bug described above shows how easy
> it is for the enabled attribute to go wrong in subtle ways.
>
> The series is split into five parts:
>
>   (1) Make the ARM and NDS32 changes described above
>   (2) Add support for "code,alternative" attributes
>   (3) Make all ports use them for enabled, preferred_for_size and
>       preferred_for_speed
>   (4) Use preferred_for_size and preferred_for_speed to decide whether
>       to use internal functions
>   (5) Convert the internal-function-related i386 patterns to use
>       preferred_for_size instead of FAILing.
>
> (3) is a purely mechanical change.  I think it counts as obvious if the
> other parts are OK.
>
> Tested by building GCC before and after the series on:
>
>     aarch64-linux-gnueabi alpha-linux-gnu arc-elf arm-linux-gnueabi
>     arm-linux-gnueabihf avr-rtems bfin-elf c6x-elf cr16-elf cris-elf
>     epiphany-elf fr30-elf frv-linux-gnu ft32-elf h8300-elf
>     ia64-linux-gnu iq2000-elf lm32-elf m32c-elf m32r-elf
>     m68k-linux-gnu mcore-elf mep-elf microblaze-elf mips-linux-gnu
>     mmix mn10300-elf moxie-elf msp430-elf nds32le-elf
>     hppa64-hp-hpux11.23 nios2-linux-gnu nvptx-none pdp11
>     powerpc-linux-gnu powerpc-eabispe rl78-elf rx-elf s390-linux-gnu
>     sh-linux-gnu sparc-linux-gnu spu-elf tilegx-elf tilepro-elf
>     xstormy16-elf v850-elf vax-netbsdelf visium-elf xtensa-elf
>     x86_64-darwin
>
> and comparing the assembly output for gcc.dg, g++.dg and gcc.c-torture
> at -O2.  There were no differences besides the usual timestamps.
>
> Also tested on x86_64-linux-gnu and arm-linux-gnueabihf.  I will test
> on powerpc64-linux-gnu as well before committing.  OK to install?
>
> Thanks,
> Richard
>

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-11-25 12:51 ` [PR68432 00/26] Handle size/speed choices for internal functions Richard Biener
@ 2015-11-25 13:47   ` Richard Sandiford
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 13:47 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

Richard Biener <richard.guenther@gmail.com> writes:
> On Wed, Nov 25, 2015 at 1:20 PM, Richard Sandiford
> <richard.sandiford@arm.com> wrote:
>> This series fixes PR 68432, a regression caused by my internal-functions-
>> for-optabs series.  Some of the libm optabs in i386.md have a true HAVE_*
>> condition but conditionally FAIL if we're optimising for size:
>>
>>   if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
>>       && !flag_trapping_math)
>>     {
>>       if (TARGET_ROUND)
>>         emit_insn (gen_sse4_1_round<mode>2
>>                    (operands[0], operands[1], GEN_INT (ROUND_MXCSR)));
>>       else if (optimize_insn_for_size_p ())
>>         FAIL;
>>       else
>>         ix86_expand_rint (operands[0], operands[1]);
>>     }
>>
>> This is going to cause problems if we want to make more decisions
>> related to optabs at the gimple level.
>>
>> We've already had the same problem in rtl, where some patterns used
>> to check optimize_insn_for_size_p in their C condition, and would then
>> fail to match if an instruction were moved from a hot block to a cold
>> block.  Now rtl has two attributes, preferred_for_size and
>> preferred_for_speed, that say whether a particular alternative of a
>> particular instruction should be used when optimising for size or speed
>> respectively.  We try to honour a "false" value as much as possible,
>> but it's not an absolute guarantee.
>>
>> The point of this series is to extend preferred_for_size and
>> preferred_for_speed to define_expands, so that the attributes
>> can be tested for optabs too.
>
> So to not re-introduce the same position issue at GIMPLE (passes
> querying optimize_bb_for_speed/size and with that querying
> the optab for IFN support) when expanding an internal function
> you ignore whether it actually "exists"?  That is, IFN expansion
> will skip the define_expand (which is maybe disabled)?

We ignore the size and speed attributes when expanding an existing
function call, yeah.  But to me "exists" means the C condition in the
define_expand or define_insn, which we check even when expanding.
(We effectively check it whenever direct_optab or convert_optab
is called, thanks to caching by init_optabs.)  We should never generate
an expand or insn if the C condition is false.

In other words, the size and speed attributes are additional information
on top of the "exists" condition that we check when deciding whether to
create a call, but not when expanding an existing call.

I forgot to say that the patch only handles optabs that are mapped
to internal functions.  I think in next stage 1 it would make sense to
do the same for all optabs, but that would be quite invasive and I don't
think it would fix a bug as such.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 01/22][ARM] Remove operand dependency from "type" attribute
  2015-11-25 12:23 ` [PR68432 01/22][ARM] Remove operand dependency from "type" attribute Richard Sandiford
@ 2015-11-25 13:55   ` Bernd Schmidt
  2015-11-25 14:11     ` Yvan Roux
  0 siblings, 1 reply; 45+ messages in thread
From: Bernd Schmidt @ 2015-11-25 13:55 UTC (permalink / raw)
  To: gcc-patches, nickc, richard.earnshaw, ramana.radhakrishnan,
	kyrylo.tkachov, richard.sandiford

On 11/25/2015 01:21 PM, Richard Sandiford wrote:
> -	  (plus:SI (match_operand:SI 0 "s_register_operand" "l,  r")
> -		   (match_operand:SI 1 "arm_add_operand"    "lPv,rIL"))
> +	  (plus:SI (match_operand:SI 0 "s_register_operand" "l,l, r,r")
> +		   (match_operand:SI 1 "arm_add_operand"    "l,Pv,r,IL"))

I'll leave it to ARM maintainers to approve or reject, but I want to 
point out one thing: IMO this sort of thing is better written as 
"l,lPv,r,rIL", allowing a larger set of inputs for the later 
alternatives while still returning the more specific earlier one if it 
matches. I don't know whether LRA takes advantage of that, but it could 
help reload, and any post-reload pass might look at the current 
alternative for a given insn to see whether it can be replaced by a 
register.


Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 01/22][ARM] Remove operand dependency from "type" attribute
  2015-11-25 13:55   ` Bernd Schmidt
@ 2015-11-25 14:11     ` Yvan Roux
  0 siblings, 0 replies; 45+ messages in thread
From: Yvan Roux @ 2015-11-25 14:11 UTC (permalink / raw)
  To: Bernd Schmidt
  Cc: gcc-patches, nickc, Richard Earnshaw, Ramana Radhakrishnan,
	Kyrylo Tkachov, richard.sandiford

Hi,

On 25 November 2015 at 14:54, Bernd Schmidt <bschmidt@redhat.com> wrote:
> On 11/25/2015 01:21 PM, Richard Sandiford wrote:
>>
>> -         (plus:SI (match_operand:SI 0 "s_register_operand" "l,  r")
>> -                  (match_operand:SI 1 "arm_add_operand"    "lPv,rIL"))
>> +         (plus:SI (match_operand:SI 0 "s_register_operand" "l,l, r,r")
>> +                  (match_operand:SI 1 "arm_add_operand"    "l,Pv,r,IL"))
>
>
> I'll leave it to ARM maintainers to approve or reject, but I want to point
> out one thing: IMO this sort of thing is better written as "l,lPv,r,rIL",
> allowing a larger set of inputs for the later alternatives while still
> returning the more specific earlier one if it matches. I don't know whether
> LRA takes advantage of that, but it could help reload, and any post-reload
> pass might look at the current alternative for a given insn to see whether
> it can be replaced by a register.

I don't remember the PR number (I can dig if needed) but I remember
that we had an LRA ICE due to redundancy in patterns alternative
description.  Thus, if it is beneficial to give larger set of inputs
in later alternatives, we have to strengthen the support in LRA.

> Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 20/22] Record attributes for define_expand
  2015-11-25 12:36 ` [PR68432 20/22] Record attributes for define_expand Richard Sandiford
@ 2015-11-25 15:55   ` Bernd Schmidt
  2015-11-25 16:09     ` Richard Sandiford
  0 siblings, 1 reply; 45+ messages in thread
From: Bernd Schmidt @ 2015-11-25 15:55 UTC (permalink / raw)
  To: gcc-patches, richard.sandiford

On 11/25/2015 01:35 PM, Richard Sandiford wrote:
> The define_subst support made it syntactically possible to add
> attributes to a define_expand, but until now they had been ignored
> by genattrtab.c.  This patch allows define_expands to have
> "code,alternative" attributes but raises an error for general
> "insn" attributes.

This seems a little strange because define_expands don't really have 
alternatives. Also, using a string like that rather than some kind of 
identifier or a define_icode_attr maybe isn't the best approach?


Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 04/22] Remove global which_alternative
  2015-11-25 12:28 ` [PR68432 04/22] Remove global which_alternative Richard Sandiford
@ 2015-11-25 16:09   ` Bernd Schmidt
  2015-11-25 16:21     ` Richard Sandiford
  0 siblings, 1 reply; 45+ messages in thread
From: Bernd Schmidt @ 2015-11-25 16:09 UTC (permalink / raw)
  To: gcc-patches, richard.sandiford

On 11/25/2015 01:26 PM, Richard Sandiford wrote:
> Later patches in the series add a new form of attribute that takes the
> attribute number as an argument, rather than it being stored in the
> global which_alternative variable.
>
> Having both a local alternative number and a global alternative number
> is likely to cause confusion.  This patch therefore gets rid of the
> global variable.

I don't really feel that this is appropriate for this stage, and some of 
the formatting changes are pretty ugly. I'd put this pattern
   constrain_operands (1, get_enabled_alternatives (temp)) >= 0
into an inline function
   constraints_ok_p (temp).
and possibly also have a variant with an extract_insn call, similar to 
extract_constrain_insn.

Do any of the subsequent patches actually depend on this?


Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 20/22] Record attributes for define_expand
  2015-11-25 15:55   ` Bernd Schmidt
@ 2015-11-25 16:09     ` Richard Sandiford
  2015-11-26 14:29       ` Bernd Schmidt
  0 siblings, 1 reply; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 16:09 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches

Bernd Schmidt <bschmidt@redhat.com> writes:
> On 11/25/2015 01:35 PM, Richard Sandiford wrote:
>> The define_subst support made it syntactically possible to add
>> attributes to a define_expand, but until now they had been ignored
>> by genattrtab.c.  This patch allows define_expands to have
>> "code,alternative" attributes but raises an error for general
>> "insn" attributes.
>
> This seems a little strange because define_expands don't really have 
> alternatives.

Yeah, but since an optab can be either a define_expand or a define_insn,
we have to support the case where there could more than one alternative.
For define_expands the alternative is always 0.

This is in some ways like an asm or define_insn with no constraints,
which also don't really have alternatives as such.  We just treat them
as having one alternative for consistency.  There's already an explicit
MAX in recog.c to force that.

> Also, using a string like that rather than some kind of 
> identifier or a define_icode_attr maybe isn't the best approach?

By "some kind of identifier" do you just mean replacing "code,alternative"
with a string that doesn't have a comma?  If so, I can do that, but what
should the string be?

The problem with define_icode_attr is that you get combinatorial
explosion with the type of the return value.  At the moment we just have
integers and enums (which can be defined by define_enum_attr as well as
define_attr), but who knows what we'll have in future? :-)

Also, I didn't want to call them "icode" attributes because in future
we might want attributes that really do depend only on the code, not on
the alternative.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 04/22] Remove global which_alternative
  2015-11-25 16:09   ` Bernd Schmidt
@ 2015-11-25 16:21     ` Richard Sandiford
  2015-11-25 16:42       ` Bernd Schmidt
  0 siblings, 1 reply; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 16:21 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches

Bernd Schmidt <bschmidt@redhat.com> writes:
> On 11/25/2015 01:26 PM, Richard Sandiford wrote:
>> Later patches in the series add a new form of attribute that takes the
>> attribute number as an argument, rather than it being stored in the
>> global which_alternative variable.
>>
>> Having both a local alternative number and a global alternative number
>> is likely to cause confusion.  This patch therefore gets rid of the
>> global variable.
>
> I don't really feel that this is appropriate for this stage, and some of 
> the formatting changes are pretty ugly. I'd put this pattern
>    constrain_operands (1, get_enabled_alternatives (temp)) >= 0
> into an inline function
>    constraints_ok_p (temp).
> and possibly also have a variant with an extract_insn call, similar to 
> extract_constrain_insn.

The idea is to force callers to think about whether they're asking:

  (1) Can I constrain this instruction to match any enabled alternative?
  (2) Can I constrain this instruction to match an alternative that is
      good for size?
  (3) Can I constrain this instruction to match an alternative that is
      good for speed?

Perhaps we could use the optimization_type added in patch 21 for this,
with a new enum value to mean "ignore optimisation".

I'm just worried that if we have a constraints_ok_p that hides the
decision altogether, it will get used by optimisation passes when
testing the result of a transform, whereas really they should be
taking the containing block's size/speed choice into account.

> Do any of the subsequent patches actually depend on this?

I guess not, but without it we have both local and global variables
called which_alternative.  The new-style attributes will use a local
which_alternative and the old-style ones will use a global
which_alternative.  The global which_alternative will still be visible
to arch.c files, so there's an obvious danger of confusion.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 04/22] Remove global which_alternative
  2015-11-25 16:21     ` Richard Sandiford
@ 2015-11-25 16:42       ` Bernd Schmidt
  2015-11-25 16:50         ` Richard Sandiford
  0 siblings, 1 reply; 45+ messages in thread
From: Bernd Schmidt @ 2015-11-25 16:42 UTC (permalink / raw)
  To: gcc-patches, richard.sandiford

On 11/25/2015 05:19 PM, Richard Sandiford wrote:

> I guess not, but without it we have both local and global variables
> called which_alternative.

So call the local ones something else (alt_to_check, requested_alt or 
attr_alt)?


Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 04/22] Remove global which_alternative
  2015-11-25 16:42       ` Bernd Schmidt
@ 2015-11-25 16:50         ` Richard Sandiford
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-25 16:50 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches

Bernd Schmidt <bschmidt@redhat.com> writes:
> On 11/25/2015 05:19 PM, Richard Sandiford wrote:
>> I guess not, but without it we have both local and global variables
>> called which_alternative.
>
> So call the local ones something else (alt_to_check, requested_alt or 
> attr_alt)?

Well, having two names for the same concept seems just as bad.
Especially since the traditional which_alternative will still
be defined and accessible.

We could have another #define hack to insert a _Pragma("GCC error ...")
if which_alternative is used in new-style attributes, but that's only
going to avoid some of the problems.

I don't think we should spend too much effort finding a reason not
to fix this...

Thanks,
Richard

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
                   ` (22 preceding siblings ...)
  2015-11-25 12:51 ` [PR68432 00/26] Handle size/speed choices for internal functions Richard Biener
@ 2015-11-26 14:21 ` Bernd Schmidt
  2015-11-26 15:43   ` Richard Sandiford
  23 siblings, 1 reply; 45+ messages in thread
From: Bernd Schmidt @ 2015-11-26 14:21 UTC (permalink / raw)
  To: gcc-patches, richard.sandiford

On 11/25/2015 01:20 PM, Richard Sandiford wrote:
> This series fixes PR 68432, a regression caused by my internal-functions-
> for-optabs series.  Some of the libm optabs in i386.md have a true HAVE_*
> condition but conditionally FAIL if we're optimising for size:
>
>    if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
>        && !flag_trapping_math)
>      {
>        if (TARGET_ROUND)
> 	emit_insn (gen_sse4_1_round<mode>2
> 		   (operands[0], operands[1], GEN_INT (ROUND_MXCSR)));
>        else if (optimize_insn_for_size_p ())
>          FAIL;
>        else
> 	ix86_expand_rint (operands[0], operands[1]);
>      }

How many such cases are there? Is it just the ix86 patterns? And, could 
the same effect be achieved by just moving the optimize_insn_for_size_p 
test into the predicate (as some existing patterns already do), and then 
testing the predicate while ensuring that optimize_insn_for_x returns 
the right value? That seems like a minimal fix, and I think one that 
would be vastly more appropriate for stage 3. The alternative splitting 
looks error-prone and may not be optimal, and I still have misgivings 
about the new attribute syntax and its application to define_expands.


Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 20/22] Record attributes for define_expand
  2015-11-25 16:09     ` Richard Sandiford
@ 2015-11-26 14:29       ` Bernd Schmidt
  0 siblings, 0 replies; 45+ messages in thread
From: Bernd Schmidt @ 2015-11-26 14:29 UTC (permalink / raw)
  To: gcc-patches, richard.sandiford

On 11/25/2015 05:08 PM, Richard Sandiford wrote:
>> Also, using a string like that rather than some kind of
>> identifier or a define_icode_attr maybe isn't the best approach?
>
> By "some kind of identifier" do you just mean replacing "code,alternative"
> with a string that doesn't have a comma?

Yeah. It really looks too much like the definition of attribute values IMO.

> The problem with define_icode_attr is that you get combinatorial
> explosion with the type of the return value.  At the moment we just have
> integers and enums (which can be defined by define_enum_attr as well as
> define_attr), but who knows what we'll have in future? :-)

Maybe

(define_typed_attr {enum,int} {insn,icode,icodealt}
  [all the usual stuff])


Bernd


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-11-26 14:21 ` Bernd Schmidt
@ 2015-11-26 15:43   ` Richard Sandiford
  2015-11-26 16:10     ` Bernd Schmidt
  0 siblings, 1 reply; 45+ messages in thread
From: Richard Sandiford @ 2015-11-26 15:43 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches

Bernd Schmidt <bschmidt@redhat.com> writes:
> On 11/25/2015 01:20 PM, Richard Sandiford wrote:
>> This series fixes PR 68432, a regression caused by my internal-functions-
>> for-optabs series.  Some of the libm optabs in i386.md have a true HAVE_*
>> condition but conditionally FAIL if we're optimising for size:
>>
>>    if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
>>        && !flag_trapping_math)
>>      {
>>        if (TARGET_ROUND)
>> 	emit_insn (gen_sse4_1_round<mode>2
>> 		   (operands[0], operands[1], GEN_INT (ROUND_MXCSR)));
>>        else if (optimize_insn_for_size_p ())
>>          FAIL;
>>        else
>> 	ix86_expand_rint (operands[0], operands[1]);
>>      }
>
> How many such cases are there? Is it just the ix86 patterns?

Yeah, just x86 AFAICT.

> And, could the same effect be achieved by just moving the
> optimize_insn_for_size_p test into the predicate (as some existing
> patterns already do), and then testing the predicate while ensuring
> that optimize_insn_for_x returns the right value?

That would mean that the validity of a gimple call would depend on both
the target predicates and whether the block containing the statement
is optimised for size or speed.  So whenever we want to test whether
a gimple call is valid, we'd need to generate rtl for its arguments
and pass them to the target predicates.  We'd also need to be aware
that moving a call between blocks could make it invalid (because
we might be moving a call from a block optimised for speed to a block
optimised for size).  I don't think those are the kinds of thing that
gimple passes would normally expect.

It seems better to use FAILs and predicates for correctness only
and use other ways of representing size/speed decisions.  And since we
already have another way for rtl, it seems like a good idea to use it
for gimple too.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-11-26 15:43   ` Richard Sandiford
@ 2015-11-26 16:10     ` Bernd Schmidt
  2015-11-26 16:26       ` Richard Sandiford
  0 siblings, 1 reply; 45+ messages in thread
From: Bernd Schmidt @ 2015-11-26 16:10 UTC (permalink / raw)
  To: gcc-patches, richard.sandiford

On 11/26/2015 04:13 PM, Richard Sandiford wrote:

> That would mean that the validity of a gimple call would depend on both
> the target predicates and whether the block containing the statement
> is optimised for size or speed.  So whenever we want to test whether
> a gimple call is valid, we'd need to generate rtl for its arguments
> and pass them to the target predicates.  We'd also need to be aware
> that moving a call between blocks could make it invalid (because
> we might be moving a call from a block optimised for speed to a block
> optimised for size).  I don't think those are the kinds of thing that
> gimple passes would normally expect.

In your world, would we move such calls into places where we currently 
would reject expanding them? I.e., would the expanders no longer fail, 
even if the target does not want to expand something when optimizing for 
size?

The other question is, you mention the need to generate rtl. I don't 
quite see why - the predicates (or insn conditions, to follow the 
terminology in the manual) for a named pattern aren't allowed to look at 
operands. Surely these conditions are already taken into account in your 
internal_fn work?

> It seems better to use FAILs and predicates for correctness only
> and use other ways of representing size/speed decisions.  And since we
> already have another way for rtl, it seems like a good idea to use it
> for gimple too.

I'm looking for a minimal fix for gcc-6, and a 22-patch series that 
rewrites lots of target patterns isn't that. If someone else wants to 
approve it then fine, but I think this is not a good approach for now.

To avoid having to retest validity when moving an internal function, 
could you just make the availability test run the predicate with both 
for_speed and for_size options, and require that the pattern is valid 
for both? That should give you a definitive answer as to whether you can 
later expand the insn, and I'd call that good enough for now.

I wish we'd taken some more time to think through the consequences of 
the original internal_fn patchset.


Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-11-26 16:10     ` Bernd Schmidt
@ 2015-11-26 16:26       ` Richard Sandiford
  2015-11-26 16:45         ` Bernd Schmidt
  2015-12-01 11:54         ` Bernd Schmidt
  0 siblings, 2 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-26 16:26 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches

Bernd Schmidt <bschmidt@redhat.com> writes:
> On 11/26/2015 04:13 PM, Richard Sandiford wrote:
>> That would mean that the validity of a gimple call would depend on both
>> the target predicates and whether the block containing the statement
>> is optimised for size or speed.  So whenever we want to test whether
>> a gimple call is valid, we'd need to generate rtl for its arguments
>> and pass them to the target predicates.  We'd also need to be aware
>> that moving a call between blocks could make it invalid (because
>> we might be moving a call from a block optimised for speed to a block
>> optimised for size).  I don't think those are the kinds of thing that
>> gimple passes would normally expect.
>
> In your world, would we move such calls into places where we currently 
> would reject expanding them? I.e., would the expanders no longer fail, 
> even if the target does not want to expand something when optimizing for 
> size?

Yeah, that could happen in theory, though should be rare in practice.
We already had this problem in rtl when patterns tried to test
optimize_insn_for_size/speed_p in their insn conditions.  See e.g.:

  https://gcc.gnu.org/ml/gcc-patches/2014-04/msg00697.html

> The other question is, you mention the need to generate rtl. I don't 
> quite see why - the predicates (or insn conditions, to follow the 
> terminology in the manual) for a named pattern aren't allowed to look at 
> operands. Surely these conditions are already taken into account in your 
> internal_fn work?

Ah, when you said "predicate" I assumed you meant the match_operand
predicates.  We'd need to generate rtl to check those.  But checking
size/speed in the insn condition doesn't work for the reason above: we
could move an instruction between blocks after deciding to generate it.

It also isn't suitable for optabs because the conditions are cached
by init_optabs.  I suppose we could have a separate cache for size
and speed though.

>> It seems better to use FAILs and predicates for correctness only
>> and use other ways of representing size/speed decisions.  And since we
>> already have another way for rtl, it seems like a good idea to use it
>> for gimple too.
>
> I'm looking for a minimal fix for gcc-6, and a 22-patch series that 
> rewrites lots of target patterns isn't that. If someone else wants to 
> approve it then fine, but I think this is not a good approach for now.

OK.  But I'd also like to avoid a hacky solution just because of the
stage.  Although we're in stage 3, we're still early stage 3,
so I'm hoping there's a bit of leeway.

> To avoid having to retest validity when moving an internal function, 
> could you just make the availability test run the predicate with both 
> for_speed and for_size options, and require that the pattern is valid 
> for both? That should give you a definitive answer as to whether you can 
> later expand the insn, and I'd call that good enough for now.

That would mean we'd never use rint for x86 before expand.

> I wish we'd taken some more time to think through the consequences of 
> the original internal_fn patchset.

I don't think this PR shows that the approach was wrong.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-11-26 16:26       ` Richard Sandiford
@ 2015-11-26 16:45         ` Bernd Schmidt
  2015-11-26 17:10           ` Richard Sandiford
  2015-12-01 11:54         ` Bernd Schmidt
  1 sibling, 1 reply; 45+ messages in thread
From: Bernd Schmidt @ 2015-11-26 16:45 UTC (permalink / raw)
  To: gcc-patches, richard.sandiford

On 11/26/2015 05:22 PM, Richard Sandiford wrote:
> It also isn't suitable for optabs because the conditions are cached
> by init_optabs.  I suppose we could have a separate cache for size
> and speed though.

That sounds necessary given the existence of such insn conditions, 
unless we want to disallow this practice.

>> To avoid having to retest validity when moving an internal function,
>> could you just make the availability test run the predicate with both
>> for_speed and for_size options, and require that the pattern is valid
>> for both? That should give you a definitive answer as to whether you can
>> later expand the insn, and I'd call that good enough for now.
>
> That would mean we'd never use rint for x86 before expand.

How does this compare to the situation before your internal_fn patches? 
What are cases where behaviour differs and how?


Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-11-26 16:45         ` Bernd Schmidt
@ 2015-11-26 17:10           ` Richard Sandiford
  0 siblings, 0 replies; 45+ messages in thread
From: Richard Sandiford @ 2015-11-26 17:10 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches

Bernd Schmidt <bschmidt@redhat.com> writes:
> On 11/26/2015 05:22 PM, Richard Sandiford wrote:
>> It also isn't suitable for optabs because the conditions are cached
>> by init_optabs.  I suppose we could have a separate cache for size
>> and speed though.
>
> That sounds necessary given the existence of such insn conditions, 
> unless we want to disallow this practice.

Does that work though?  (Before my internal_fn patches I mean.)

>>> To avoid having to retest validity when moving an internal function,
>>> could you just make the availability test run the predicate with both
>>> for_speed and for_size options, and require that the pattern is valid
>>> for both? That should give you a definitive answer as to whether you can
>>> later expand the insn, and I'd call that good enough for now.
>>
>> That would mean we'd never use rint for x86 before expand.
>
> How does this compare to the situation before your internal_fn patches? 
> What are cases where behaviour differs and how?

Ok, for rint I guess it doesn't matter.  It's the TARGET_USE_FANCY_MATH_387
that would change, since tree-call-cdce.c would no longer convert (say):

  y = acos(x);

into

  y = ifn_acos(x);
  if (...)
    acos (x);

Maybe noone cares about TARGET_USE_FANCY_MATH_387 these days though.

I still think insn conditions are the wrong place to check this.
We shouldn't have a different rule for rtl insn conditions and gimple
insn conditions.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-11-26 16:26       ` Richard Sandiford
  2015-11-26 16:45         ` Bernd Schmidt
@ 2015-12-01 11:54         ` Bernd Schmidt
  2015-12-01 12:17           ` Richard Biener
  2015-12-01 13:43           ` Richard Sandiford
  1 sibling, 2 replies; 45+ messages in thread
From: Bernd Schmidt @ 2015-12-01 11:54 UTC (permalink / raw)
  To: gcc-patches, richard.sandiford

On 11/26/2015 05:22 PM, Richard Sandiford wrote:
> Bernd Schmidt <bschmidt@redhat.com> writes:
>
>> I wish we'd taken some more time to think through the consequences of
>> the original internal_fn patchset.
>
> I don't think this PR shows that the approach was wrong.

I think it does. Internal functions make a new assumptions, that 
expanders don't FAIL - but as we've now seen, they do. The optimize_size 
thing is reasonably easy to grep for and it looks like only i386 is 
affected, but have you looked at every expander in every port that could 
be used by an internal function to ensure it does not FAIL for a 
different reason?

Is there a simple way to disable the entire internal_fn machinery and 
get us back to where we were in gcc-5, without taking out all the code 
immediately? That would give us time until next stage 1 to think through 
the issues.


Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-12-01 11:54         ` Bernd Schmidt
@ 2015-12-01 12:17           ` Richard Biener
  2015-12-01 12:21             ` Bernd Schmidt
  2015-12-01 13:43           ` Richard Sandiford
  1 sibling, 1 reply; 45+ messages in thread
From: Richard Biener @ 2015-12-01 12:17 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: GCC Patches, richard.sandiford

On Tue, Dec 1, 2015 at 12:54 PM, Bernd Schmidt <bschmidt@redhat.com> wrote:
> On 11/26/2015 05:22 PM, Richard Sandiford wrote:
>>
>> Bernd Schmidt <bschmidt@redhat.com> writes:
>>
>>> I wish we'd taken some more time to think through the consequences of
>>> the original internal_fn patchset.
>>
>>
>> I don't think this PR shows that the approach was wrong.
>
>
> I think it does. Internal functions make a new assumptions, that expanders
> don't FAIL - but as we've now seen, they do. The optimize_size thing is
> reasonably easy to grep for and it looks like only i386 is affected, but
> have you looked at every expander in every port that could be used by an
> internal function to ensure it does not FAIL for a different reason?

Of course we are not sure.  But I think the approach in the series is the only
reasonable one.  I view the internal_fn support for optabs as a great way to
provide sth like instruction selection to GIMPLE with the goal to simplify
RTL expansion itself (which since quite some time cannot rely on seeing
"large" expressions anymore and with TER has the limitation of seeing
only some under the constraint TER and out-of-SSA operate).

> Is there a simple way to disable the entire internal_fn machinery and get us
> back to where we were in gcc-5, without taking out all the code immediately?
> That would give us time until next stage 1 to think through the issues.

Do you have even a guess as to how to approach the issue differently?

Yes, I think we can rip out uses of the new machinery quite easily but I don't
think we're at the point declaring failure yet.

Richard.

>
> Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-12-01 12:17           ` Richard Biener
@ 2015-12-01 12:21             ` Bernd Schmidt
  0 siblings, 0 replies; 45+ messages in thread
From: Bernd Schmidt @ 2015-12-01 12:21 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, richard.sandiford

On 12/01/2015 01:16 PM, Richard Biener wrote:
> On Tue, Dec 1, 2015 at 12:54 PM, Bernd Schmidt <bschmidt@redhat.com> wrote:
>> On 11/26/2015 05:22 PM, Richard Sandiford wrote:
>>>
>>> Bernd Schmidt <bschmidt@redhat.com> writes:
>>>
>>>> I wish we'd taken some more time to think through the consequences of
>>>> the original internal_fn patchset.
>>>
>>>
>>> I don't think this PR shows that the approach was wrong.
>>
>>
>> I think it does. Internal functions make a new assumptions, that expanders
>> don't FAIL - but as we've now seen, they do. The optimize_size thing is
>> reasonably easy to grep for and it looks like only i386 is affected, but
>> have you looked at every expander in every port that could be used by an
>> internal function to ensure it does not FAIL for a different reason?
>
> Of course we are not sure.

Hence, the correct approach for gcc-6 is to recognize that these patches 
were not ready, and disable the new functionality IMO. I'm not 
suggesting reverting the patches just yet, maybe we can solve these 
issues for gcc-7.

> Do you have even a guess as to how to approach the issue differently?

Not off-hand. That's not a question we're facing for stage3 though, and 
I'd rather take a cautious approach than go deeper into the hole.


Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-12-01 11:54         ` Bernd Schmidt
  2015-12-01 12:17           ` Richard Biener
@ 2015-12-01 13:43           ` Richard Sandiford
  2015-12-01 13:59             ` Bernd Schmidt
  1 sibling, 1 reply; 45+ messages in thread
From: Richard Sandiford @ 2015-12-01 13:43 UTC (permalink / raw)
  To: Bernd Schmidt; +Cc: gcc-patches

Bernd Schmidt <bschmidt@redhat.com> writes:
> On 11/26/2015 05:22 PM, Richard Sandiford wrote:
>> Bernd Schmidt <bschmidt@redhat.com> writes:
>>
>>> I wish we'd taken some more time to think through the consequences of
>>> the original internal_fn patchset.
>>
>> I don't think this PR shows that the approach was wrong.
>
> I think it does. Internal functions make a new assumptions, that 
> expanders don't FAIL - but as we've now seen, they do. The optimize_size 
> thing is reasonably easy to grep for and it looks like only i386 is 
> affected, but have you looked at every expander in every port that could 
> be used by an internal function to ensure it does not FAIL for a 
> different reason?

I've tried and I couldn't see any other problems.

I don't think what you say is an argument that the approach is wrong.
The C conditions for optabs have always been more restricted than
other define_expands and define_insns, since they cannot refer
to operands.  When caching of optabs was added, they also lost
the ability to test for size/speed choices.  There have also
always been optabs that are not allowed to FAIL (such as moves,
get_thread_pointer, widening multiplication, vec_cond, etc.).
This series is extending that list, but it's in the spirit
of restrictions that have always existed.  I don't see that
that's an argument that the approach is wrong.

The current approach to FAILs dated from a time when expand was
the first code-generation pass.  The FAILs aren't a good fit for
gimple optimisers that are trying to find out what the target
can do (and how cheaply it can do it).

> Is there a simple way to disable the entire internal_fn machinery and 
> get us back to where we were in gcc-5, without taking out all the code 
> immediately? That would give us time until next stage 1 to think through 
> the issues.

That seems like an overreaction.

I went for the 22-patch series because I think it's the best fix for
this problem.  It also makes the existing enabled, preferred_for_size
and preferred_for_speed handling more robust (as shown by the ARM bug
that the structural changes exposed at compile time).  But there are
other less-invasive ways of fixing it too, as described in the thread
about rsqrt.  I'm going to work on that today.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PR68432 00/26] Handle size/speed choices for internal functions
  2015-12-01 13:43           ` Richard Sandiford
@ 2015-12-01 13:59             ` Bernd Schmidt
  0 siblings, 0 replies; 45+ messages in thread
From: Bernd Schmidt @ 2015-12-01 13:59 UTC (permalink / raw)
  To: gcc-patches, richard.sandiford

On 12/01/2015 02:43 PM, Richard Sandiford wrote:
> I don't think what you say is an argument that the approach is wrong.
> The C conditions for optabs have always been more restricted than
> other define_expands and define_insns, since they cannot refer
> to operands.  When caching of optabs was added, they also lost
> the ability to test for size/speed choices.  There have also
> always been optabs that are not allowed to FAIL (such as moves,
> get_thread_pointer, widening multiplication, vec_cond, etc.).
> This series is extending that list, but it's in the spirit
> of restrictions that have always existed.  I don't see that
> that's an argument that the approach is wrong.

Ok, you can of course change the rules, but that means the following 
needs to be done as a minimum (and it should have been done initially):
  * the new rules must be documented
  * all existing expanders need to be examined to see whether they
    comply.

At the moment we don't know how widespread the problem is. If you're 
willing to do the audit of all ports then I'd be more willing to 
consider this suitable for gcc-6.


Bernd

^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2015-12-01 13:59 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-25 12:22 [PR68432 00/26] Handle size/speed choices for internal functions Richard Sandiford
2015-11-25 12:23 ` [PR68432 01/22][ARM] Remove operand dependency from "type" attribute Richard Sandiford
2015-11-25 13:55   ` Bernd Schmidt
2015-11-25 14:11     ` Yvan Roux
2015-11-25 12:24 ` [PR68432 02/22][ARM] Remove operand dependency from use_literal_pool Richard Sandiford
2015-11-25 12:26 ` [PR68432 03/22][NDS32] Remove "length" dependency from "enabled" attribute Richard Sandiford
2015-11-25 12:28 ` [PR68432 04/22] Remove global which_alternative Richard Sandiford
2015-11-25 16:09   ` Bernd Schmidt
2015-11-25 16:21     ` Richard Sandiford
2015-11-25 16:42       ` Bernd Schmidt
2015-11-25 16:50         ` Richard Sandiford
2015-11-25 12:29 ` [PR68432 05/22] Add support attributes that operate on insn codes Richard Sandiford
2015-11-25 12:29 ` [PR68432 06/22] Use code,alternative attributes for aarch64 Richard Sandiford
2015-11-25 12:30 ` [PR68432 07/22] Use code,alternative attributes for alpha Richard Sandiford
2015-11-25 12:30 ` [PR68432 10/22] Use code,alternative attributes for avr Richard Sandiford
2015-11-25 12:31 ` [PR68432 11/22] Use code,alternative attributes for c6x Richard Sandiford
2015-11-25 12:31 ` [PR68432 08/22] Use code,alternative attributes for arc Richard Sandiford
2015-11-25 12:31 ` [PR68432 09/22] Use code,alternative attributes for arm Richard Sandiford
2015-11-25 12:31 ` [PR68432 12/22] Use code,alternative attributes for i386 Richard Sandiford
2015-11-25 12:32 ` [PR68432 13/22] Use code,alternative attributes for m68k Richard Sandiford
2015-11-25 12:32 ` [PR68432 14/22] Use code,alternative attributes for mips Richard Sandiford
2015-11-25 12:32 ` [PR68432 15/22] Use code,alternative attributes for mn10300 Richard Sandiford
2015-11-25 12:33 ` [PR68432 17/22] Use code,alternative attributes for s390 Richard Sandiford
2015-11-25 12:33 ` [PR68432 16/22] Use code,alternative attributes for nds32 Richard Sandiford
2015-11-25 12:34 ` [PR68432 18/22] Use code,alternative attributes for sparc Richard Sandiford
2015-11-25 12:35 ` [PR68432 19/22] Use code,alternative for bool_attrs Richard Sandiford
2015-11-25 12:36 ` [PR68432 20/22] Record attributes for define_expand Richard Sandiford
2015-11-25 15:55   ` Bernd Schmidt
2015-11-25 16:09     ` Richard Sandiford
2015-11-26 14:29       ` Bernd Schmidt
2015-11-25 12:37 ` [PR68432 21/22] Pass optimization type to direct_internal_fn_supported_p Richard Sandiford
2015-11-25 12:38 ` [PR68432 22/22] Use preferred_for_size in i386 internal fn optabs Richard Sandiford
2015-11-25 12:51 ` [PR68432 00/26] Handle size/speed choices for internal functions Richard Biener
2015-11-25 13:47   ` Richard Sandiford
2015-11-26 14:21 ` Bernd Schmidt
2015-11-26 15:43   ` Richard Sandiford
2015-11-26 16:10     ` Bernd Schmidt
2015-11-26 16:26       ` Richard Sandiford
2015-11-26 16:45         ` Bernd Schmidt
2015-11-26 17:10           ` Richard Sandiford
2015-12-01 11:54         ` Bernd Schmidt
2015-12-01 12:17           ` Richard Biener
2015-12-01 12:21             ` Bernd Schmidt
2015-12-01 13:43           ` Richard Sandiford
2015-12-01 13:59             ` Bernd Schmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).