diff mbox

[PR68432,04/22] Remove global which_alternative

Message ID 87k2p6i7tr.fsf@e105548-lin.cambridge.arm.com
State New
Headers show

Commit Message

Richard Sandiford Nov. 25, 2015, 12:26 p.m. UTC
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.

Comments

Bernd Schmidt Nov. 25, 2015, 4:06 p.m. UTC | #1
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
Richard Sandiford Nov. 25, 2015, 4:19 p.m. UTC | #2
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
Bernd Schmidt Nov. 25, 2015, 4:29 p.m. UTC | #3
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
Richard Sandiford Nov. 25, 2015, 4:42 p.m. UTC | #4
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
diff mbox

Patch

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);")
 
 ;;- 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);")
 
 ;;- 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)
     }
 }
 
+/* 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;
 }
 
 /* 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++)