diff mbox

RFA: patch to fix PR69299

Message ID 56A93023.8020201@redhat.com
State New
Headers show

Commit Message

Vladimir Makarov Jan. 27, 2016, 9:01 p.m. UTC
The following patch fixes PR69299.

   The details of the problem is described on

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69299

   The patch was successfully bootstrapped and tested on x86/x86-64.

   The patch introduces a new type of constraints 
define_special_memory_constraint for memory constraints whose address 
reload can not make memory to satisfy the constraint.  It is useful when 
specifically aligned memory is necessary or desirable. I don't know what 
is the best name for this constraint.  I use special_memory_constraint 
but it could be more specific, e.g. aligned_memory_constraint.  Please 
let me know what is the best name for you.

   Is the patch ok to commit?

Comments

Jakub Jelinek Jan. 28, 2016, 1:05 p.m. UTC | #1
On Wed, Jan 27, 2016 at 04:01:23PM -0500, Vladimir Makarov wrote:
>   The following patch fixes PR69299.
> 
>   The details of the problem is described on
> 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69299
> 
>   The patch was successfully bootstrapped and tested on x86/x86-64.
> 
>   The patch introduces a new type of constraints
> define_special_memory_constraint for memory constraints whose address reload
> can not make memory to satisfy the constraint.  It is useful when
> specifically aligned memory is necessary or desirable. I don't know what is
> the best name for this constraint.  I use special_memory_constraint but it
> could be more specific, e.g. aligned_memory_constraint.  Please let me know
> what is the best name for you.
> 
>   Is the patch ok to commit?

I support the general idea and for naming will defer to Jeff, just have some
nits below.  But it is your code and area of expertise, so I don't claim to
be an expert here...

> --- ira-costs.c	(revision 232571)
> +++ ira-costs.c	(working copy)
> @@ -777,6 +777,7 @@ record_reg_classes (int n_alts, int n_op
>  		      break;
>  
>  		    case CT_MEMORY:
> +		    case CT_SPECIAL_MEMORY:
>  		      /* Every MEM can be reloaded to fit.  */
>  		      insn_allows_mem[i] = allows_mem[i] = 1;
>  		      if (MEM_P (op))

The comment is true only for CT_MEMORY.  Wonder if it wouldn't be better to
handle CT_SPECIAL_MEMORY separately, perhaps as:

		  case CT_SPECIAL_MEMORY:
		    if (MEM_P (op) && constraint_satisfied_p (op, cn))
		      {
			insn_allows_mem[i] = allows_mem[i] = 1;
			win = 1;
		      }
		    break;

?  I.e. if the constraint is already satisfied, treat it like memory
constraint, otherwise treat like (unsatisfied) fixed form constraint.
Or, if you want to account for the possibility that it doesn't satisfy the
constraint yet due to address that if reloaded would make it satisfy,
consider !memory_operand (op, ...) case as unknown, with no need to
check the constraint.  Because if op satisfies already memory_operand,
but doesn't constraint_satisfied_p, it means it will never satisfy.

> --- ira.c	(revision 232571)
> +++ ira.c	(working copy)
> @@ -1868,6 +1868,7 @@ ira_setup_alts (rtx_insn *insn, HARD_REG
>  
>  			case CT_ADDRESS:
>  			case CT_MEMORY:
> +			case CT_SPECIAL_MEMORY:
>  			  goto op_success;

Perhaps treat it like CT_FIXED_FORM here instead?  I.e. op_success only
if the constraint is satisfied?  Or perhaps treat it as possible op_success
if !memory_operand, as mentioned above.

> --- recog.c	(revision 232571)
> +++ recog.c	(working copy)
> @@ -1791,6 +1791,7 @@ asm_operand_ok (rtx op, const char *cons
>  	      break;
>  
>  	    case CT_MEMORY:
> +	    case CT_SPECIAL_MEMORY:
>  	      /* Every memory operand can be reloaded to fit.  */
>  	      result = result || memory_operand (op, VOIDmode);
>  	      break;

Again, I'd treat it like CT_FIXED_FORM here, or at least if
memory_operand check also constraint_satisfied_p.

	Jakub
Vladimir Makarov Jan. 28, 2016, 5:07 p.m. UTC | #2
On 01/28/2016 08:05 AM, Jakub Jelinek wrote:
> On Wed, Jan 27, 2016 at 04:01:23PM -0500, Vladimir Makarov wrote:
>>    The following patch fixes PR69299.
>>
>>    The details of the problem is described on
>>
>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69299
>>
>>    The patch was successfully bootstrapped and tested on x86/x86-64.
>>
>>    The patch introduces a new type of constraints
>> define_special_memory_constraint for memory constraints whose address reload
>> can not make memory to satisfy the constraint.  It is useful when
>> specifically aligned memory is necessary or desirable. I don't know what is
>> the best name for this constraint.  I use special_memory_constraint but it
>> could be more specific, e.g. aligned_memory_constraint.  Please let me know
>> what is the best name for you.
>>
>>    Is the patch ok to commit?
> I support the general idea and for naming will defer to Jeff, just have some
> nits below.  But it is your code and area of expertise, so I don't claim to
> be an expert here...
Thanks for the comments, Jakub.  I am not sure about all these changes 
-- tt is hard to predict all possible consequences of the decisions 
because of the RA complexity.  But some comments made me rethink the patch.
>> --- ira-costs.c	(revision 232571)
>> +++ ira-costs.c	(working copy)
>> @@ -777,6 +777,7 @@ record_reg_classes (int n_alts, int n_op
>>   		      break;
>>   
>>   		    case CT_MEMORY:
>> +		    case CT_SPECIAL_MEMORY:
>>   		      /* Every MEM can be reloaded to fit.  */
>>   		      insn_allows_mem[i] = allows_mem[i] = 1;
>>   		      if (MEM_P (op))
> The comment is true only for CT_MEMORY.  Wonder if it wouldn't be better to
> handle CT_SPECIAL_MEMORY separately, perhaps as:
>
> 		  case CT_SPECIAL_MEMORY:
> 		    if (MEM_P (op) && constraint_satisfied_p (op, cn))
> 		      {
> 			insn_allows_mem[i] = allows_mem[i] = 1;
> 			win = 1;
> 		      }
> 		    break;
>
> ?  I.e. if the constraint is already satisfied, treat it like memory
> constraint, otherwise treat like (unsatisfied) fixed form constraint.
> Or, if you want to account for the possibility that it doesn't satisfy the
> constraint yet due to address that if reloaded would make it satisfy,
> consider !memory_operand (op, ...) case as unknown, with no need to
> check the constraint.  Because if op satisfies already memory_operand,
> but doesn't constraint_satisfied_p, it means it will never satisfy.
>
The difference in code most probably does not affect generated code 
correctness but may change code quality.  After some thinking, I decided 
to change it to

           case CT_SPECIAL_MEMORY:
              if (MEM_P (op) && constraint_satisfied_p (op, cn))
		win = 1;
              allows_mem[i] = insn_allows_mem[i] = 1;
              break;


>> --- ira.c	(revision 232571)
>> +++ ira.c	(working copy)
>> @@ -1868,6 +1868,7 @@ ira_setup_alts (rtx_insn *insn, HARD_REG
>>   
>>   			case CT_ADDRESS:
>>   			case CT_MEMORY:
>> +			case CT_SPECIAL_MEMORY:
>>   			  goto op_success;
> Perhaps treat it like CT_FIXED_FORM here instead?  I.e. op_success only
> if the constraint is satisfied?  Or perhaps treat it as possible op_success
> if !memory_operand, as mentioned above.
This would exclude consideration of possible transformation: unaligned 
memory -> reg -> aligned memory.  LRA can figure out the profitability 
of this.  But taking complexity of RA we can do unaligned memory -> 
pseudo first assigning a hard reg to the pseudo and on later subpasses 
to spill the pseudo for some reasons.  Removing such RA freedom might 
result in having LRA stuck.
>> --- recog.c	(revision 232571)
>> +++ recog.c	(working copy)
>> @@ -1791,6 +1791,7 @@ asm_operand_ok (rtx op, const char *cons
>>   	      break;
>>   
>>   	    case CT_MEMORY:
>> +	    case CT_SPECIAL_MEMORY:
>>   	      /* Every memory operand can be reloaded to fit.  */
>>   	      result = result || memory_operand (op, VOIDmode);
>>   	      break;
> Again, I'd treat it like CT_FIXED_FORM here, or at least if
> memory_operand check also constraint_satisfied_p.
>
I would not change it.  The reasons are described in the previous comment.

I'll test the change for ira-costs.c.  If I find something wrong I'll 
wrote about it.
Richard Henderson Jan. 29, 2016, 6:23 p.m. UTC | #3
On 01/28/2016 09:07 AM, Vladimir Makarov wrote:
> On 01/28/2016 08:05 AM, Jakub Jelinek wrote:
>> On Wed, Jan 27, 2016 at 04:01:23PM -0500, Vladimir Makarov wrote:
>>>    The following patch fixes PR69299.
>>>
>>>    The details of the problem is described on
>>>
>>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69299
>>>
>>>    The patch was successfully bootstrapped and tested on x86/x86-64.
>>>
>>>    The patch introduces a new type of constraints
>>> define_special_memory_constraint for memory constraints whose address reload
>>> can not make memory to satisfy the constraint.  It is useful when
>>> specifically aligned memory is necessary or desirable. I don't know what is
>>> the best name for this constraint.  I use special_memory_constraint but it
>>> could be more specific, e.g. aligned_memory_constraint.  Please let me know
>>> what is the best name for you.
>>>
>>>    Is the patch ok to commit?
>> I support the general idea and for naming will defer to Jeff,

I actually like the name special_memory_constraint.  I'm sure it will 
eventually be use for more than just aligned memories.  Off the top of my head 
I can imagine constraints for specific address spaces.


>>> --- ira-costs.c    (revision 232571)
>>> +++ ira-costs.c    (working copy)
>>> @@ -777,6 +777,7 @@ record_reg_classes (int n_alts, int n_op
>>>                 break;
>>>               case CT_MEMORY:
>>> +            case CT_SPECIAL_MEMORY:
>>>                 /* Every MEM can be reloaded to fit.  */
>>>                 insn_allows_mem[i] = allows_mem[i] = 1;
>>>                 if (MEM_P (op))
>> The comment is true only for CT_MEMORY.  Wonder if it wouldn't be better to
>> handle CT_SPECIAL_MEMORY separately, perhaps as:
>>
>>           case CT_SPECIAL_MEMORY:
>>             if (MEM_P (op) && constraint_satisfied_p (op, cn))
>>               {
>>             insn_allows_mem[i] = allows_mem[i] = 1;
>>             win = 1;
>>               }
>>             break;
>>
>> ?  I.e. if the constraint is already satisfied, treat it like memory
>> constraint, otherwise treat like (unsatisfied) fixed form constraint.
>> Or, if you want to account for the possibility that it doesn't satisfy the
>> constraint yet due to address that if reloaded would make it satisfy,
>> consider !memory_operand (op, ...) case as unknown, with no need to
>> check the constraint.  Because if op satisfies already memory_operand,
>> but doesn't constraint_satisfied_p, it means it will never satisfy.
>>
> The difference in code most probably does not affect generated code correctness
> but may change code quality.  After some thinking, I decided to change it to
>
>            case CT_SPECIAL_MEMORY:
>               if (MEM_P (op) && constraint_satisfied_p (op, cn))
>                 win = 1;
>               allows_mem[i] = insn_allows_mem[i] = 1;
>               break;
...
> But taking complexity of RA we can do unaligned memory -> pseudo first
> assigning a hard reg to the pseudo and on later subpasses to spill the
> pseudo for some reasons.  Removing such RA freedom might result in having
> LRA stuck.

I believe that I follow your reasoning here, and the possible paths through LRA 
that would make this happen, and I agree that we should allow LRA the freedom 
to spill the pseudo that we just allocated.

The patch with that change looks good to me.


r~
diff mbox

Patch

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 232903)
+++ ChangeLog	(working copy)
@@ -1,3 +1,37 @@ 
+2016-01-27  Vladimir Makarov  <vmakarov@redhat.com>
+
+	PR target/68990
+	* config/i386/constraints.md (Bm): Describe as special memory
+	constraint.
+	* doc/md.texi (DEFINE_SPECIAL_MEMORY_CONSTRAINT): Describe it.
+	* genoutput.c (main): Process DEFINE_SPECIAL_MEMORY_CONSTRAINT.
+	* genpreds.c (struct constraint_data): Add is_special_memory.
+	(have_special_memory_constraints, special_memory_start): New
+	static vars.
+	(special_memory_end): Ditto.
+	(add_constraint): Add new arg is_special_memory.  Add code to
+	process its true value.  Update have_special_memory_constraints.
+	(process_define_constraint): Pass the new arg.
+	(process_define_register_constraint): Ditto.
+	(choose_enum_order): Process special memory.
+	(write_tm_preds_h): Generate enum const CT_SPECIAL_MEMORY and
+	function insn_extra_special_memory_constraint.
+	(main): Process DEFINE_SPECIAL_MEMORY_CONSTRAINT.
+	* gensupport.c (process_rtx): Process
+	DEFINE_SPECIAL_MEMORY_CONSTRAINT.
+	* ira-costs.c (record_reg_classes): Process CT_SPECIAL_MEMORY.
+	* ira-lives.c (single_reg_class): Use
+	insn_extra_special_memory_constraint.
+	* ira.c (ira_setup_alts): Process CT_SPECIAL_MEMORY.
+	* lra-constraints.c (process_alt_operands): Ditto.
+	(curr_insn_transform): Use insn_extra_special_memory_constraint.
+	* recog.c (asm_operand_ok, preprocess_constraints): Process
+	CT_SPECIAL_MEMORY.
+	* reload.c (find_reloads): Ditto.
+	* rtl.def (DEFINE_SPECIFAL_MEMORY_CONSTRAINT): New.
+	* stmt.c (parse_input_constraint): Use
+	insn_extra_special_memory_constraint.
+
 2016-01-27  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR target/68986
Index: config/i386/constraints.md
===================================================================
--- config/i386/constraints.md	(revision 232571)
+++ config/i386/constraints.md	(working copy)
@@ -161,7 +161,7 @@ 
   "@internal GOT memory operand."
   (match_operand 0 "GOT_memory_operand"))
 
-(define_constraint "Bm"
+(define_special_memory_constraint "Bm"
   "@internal Vector memory operand."
   (match_operand 0 "vector_memory_operand"))
 
Index: doc/md.texi
===================================================================
--- doc/md.texi	(revision 232571)
+++ doc/md.texi	(working copy)
@@ -4424,6 +4424,20 @@  The syntax and semantics are otherwise i
 @code{define_constraint}.
 @end deffn
 
+@deffn {MD Expression} define_special_memory_constraint name docstring exp
+Use this expression for constraints that match a subset of all memory
+operands: that is, @code{reload} can not make them match by reloading
+the address as it is described for @code{define_memory_constraint} or
+such address reload is undesirable with the performance point of view.
+
+For example, @code{define_special_memory_constraint} can be useful if
+specifically aligned memory is necessary or desirable for some insn
+operand.
+
+The syntax and semantics are otherwise identical to
+@code{define_constraint}.
+@end deffn
+
 @deffn {MD Expression} define_address_constraint name docstring exp
 Use this expression for constraints that match a subset of all address
 operands: that is, @code{reload} can make the constraint match by
Index: genoutput.c
===================================================================
--- genoutput.c	(revision 232571)
+++ genoutput.c	(working copy)
@@ -1019,6 +1019,7 @@  main (int argc, char **argv)
       case DEFINE_REGISTER_CONSTRAINT:
       case DEFINE_ADDRESS_CONSTRAINT:
       case DEFINE_MEMORY_CONSTRAINT:
+      case DEFINE_SPECIAL_MEMORY_CONSTRAINT:
 	note_constraint (&info);
 	break;
 
Index: genpreds.c
===================================================================
--- genpreds.c	(revision 232571)
+++ genpreds.c	(working copy)
@@ -659,11 +659,11 @@  write_one_predicate_function (struct pre
 
 /* Constraints fall into two categories: register constraints
    (define_register_constraint), and others (define_constraint,
-   define_memory_constraint, define_address_constraint).  We
-   work out automatically which of the various old-style macros
-   they correspond to, and produce appropriate code.  They all
-   go in the same hash table so we can verify that there are no
-   duplicate names.  */
+   define_memory_constraint, define_special_memory_constraint,
+   define_address_constraint).  We work out automatically which of the
+   various old-style macros they correspond to, and produce
+   appropriate code.  They all go in the same hash table so we can
+   verify that there are no duplicate names.  */
 
 /* All data from one constraint definition.  */
 struct constraint_data
@@ -681,6 +681,7 @@  struct constraint_data
   unsigned int is_const_dbl	: 1;
   unsigned int is_extra		: 1;
   unsigned int is_memory	: 1;
+  unsigned int is_special_memory: 1;
   unsigned int is_address	: 1;
   unsigned int maybe_allows_reg : 1;
   unsigned int maybe_allows_mem : 1;
@@ -718,6 +719,7 @@  static const char const_dbl_constraints[
 static unsigned int constraint_max_namelen;
 static bool have_register_constraints;
 static bool have_memory_constraints;
+static bool have_special_memory_constraints;
 static bool have_address_constraints;
 static bool have_extra_constraints;
 static bool have_const_int_constraints;
@@ -728,6 +730,7 @@  static unsigned int register_start, regi
 static unsigned int satisfied_start;
 static unsigned int const_int_start, const_int_end;
 static unsigned int memory_start, memory_end;
+static unsigned int special_memory_start, special_memory_end;
 static unsigned int address_start, address_end;
 static unsigned int maybe_allows_none_start, maybe_allows_none_end;
 static unsigned int maybe_allows_reg_start, maybe_allows_reg_end;
@@ -754,20 +757,22 @@  mangle (const char *name)
 
 /* Add one constraint, of any sort, to the tables.  NAME is its name;
    REGCLASS is the register class, if any; EXP is the expression to
-   test, if any;  IS_MEMORY and IS_ADDRESS indicate memory and address
-   constraints, respectively; LOC is the .md file location.
-
-   Not all combinations of arguments are valid; most importantly, REGCLASS
-   is mutually exclusive with EXP, and IS_MEMORY/IS_ADDRESS are only
-   meaningful for constraints with EXP.
+   test, if any; IS_MEMORY, IS_SPECIAL_MEMORY and IS_ADDRESS indicate
+   memory, special memory, and address constraints, respectively; LOC
+   is the .md file location.
+
+   Not all combinations of arguments are valid; most importantly,
+   REGCLASS is mutually exclusive with EXP, and
+   IS_MEMORY/IS_SPECIAL_MEMORY/IS_ADDRESS are only meaningful for
+   constraints with EXP.
 
    This function enforces all syntactic and semantic rules about what
    constraints can be defined.  */
 
 static void
 add_constraint (const char *name, const char *regclass,
-		rtx exp, bool is_memory, bool is_address,
-		file_location loc)
+		rtx exp, bool is_memory, bool is_special_memory,
+		bool is_address, file_location loc)
 {
   struct constraint_data *c, **iter, **slot;
   const char *p;
@@ -878,6 +883,17 @@  add_constraint (const char *name, const
 		      name, name[0]);
 	  return;
 	}
+      else if (is_special_memory)
+	{
+	  if (name[1] == '\0')
+	    error_at (loc, "constraint letter '%c' cannot be a "
+		      "special memory constraint", name[0]);
+	  else
+	    error_at (loc, "constraint name '%s' begins with '%c', "
+		      "and therefore cannot be a special memory constraint",
+		      name, name[0]);
+	  return;
+	}
       else if (is_address)
 	{
 	  if (name[1] == '\0')
@@ -904,6 +920,7 @@  add_constraint (const char *name, const
   c->is_const_dbl = is_const_dbl;
   c->is_extra = !(regclass || is_const_int || is_const_dbl);
   c->is_memory = is_memory;
+  c->is_special_memory = is_special_memory;
   c->is_address = is_address;
   c->maybe_allows_reg = true;
   c->maybe_allows_mem = true;
@@ -930,17 +947,20 @@  add_constraint (const char *name, const
   have_const_int_constraints |= c->is_const_int;
   have_extra_constraints |= c->is_extra;
   have_memory_constraints |= c->is_memory;
+  have_special_memory_constraints |= c->is_special_memory;
   have_address_constraints |= c->is_address;
   num_constraints += 1;
 }
 
-/* Process a DEFINE_CONSTRAINT, DEFINE_MEMORY_CONSTRAINT, or
-   DEFINE_ADDRESS_CONSTRAINT expression, C.  */
+/* Process a DEFINE_CONSTRAINT, DEFINE_MEMORY_CONSTRAINT,
+   DEFINE_SPECIAL_MEMORY_CONSTRAINT, or DEFINE_ADDRESS_CONSTRAINT
+   expression, C.  */
 static void
 process_define_constraint (md_rtx_info *info)
 {
   add_constraint (XSTR (info->def, 0), 0, XEXP (info->def, 2),
 		  GET_CODE (info->def) == DEFINE_MEMORY_CONSTRAINT,
+		  GET_CODE (info->def) == DEFINE_SPECIAL_MEMORY_CONSTRAINT,
 		  GET_CODE (info->def) == DEFINE_ADDRESS_CONSTRAINT,
 		  info->loc);
 }
@@ -950,7 +970,7 @@  static void
 process_define_register_constraint (md_rtx_info *info)
 {
   add_constraint (XSTR (info->def, 0), XSTR (info->def, 1),
-		  0, false, false, info->loc);
+		  0, false, false, false, info->loc);
 }
 
 /* Put the constraints into enum order.  We want to keep constraints
@@ -984,6 +1004,12 @@  choose_enum_order (void)
       enum_order[next++] = c;
   memory_end = next;
 
+  special_memory_start = next;
+  FOR_ALL_CONSTRAINTS (c)
+    if (c->is_special_memory)
+      enum_order[next++] = c;
+  special_memory_end = next;
+
   address_start = next;
   FOR_ALL_CONSTRAINTS (c)
     if (c->is_address)
@@ -992,27 +1018,31 @@  choose_enum_order (void)
 
   maybe_allows_none_start = next;
   FOR_ALL_CONSTRAINTS (c)
-    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
+    if (!c->is_register && !c->is_const_int && !c->is_memory
+	&& !c->is_special_memory && !c->is_address
 	&& !c->maybe_allows_reg && !c->maybe_allows_mem)
       enum_order[next++] = c;
   maybe_allows_none_end = next;
 
   maybe_allows_reg_start = next;
   FOR_ALL_CONSTRAINTS (c)
-    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
+    if (!c->is_register && !c->is_const_int && !c->is_memory
+	&& !c->is_special_memory && !c->is_address
 	&& c->maybe_allows_reg && !c->maybe_allows_mem)
       enum_order[next++] = c;
   maybe_allows_reg_end = next;
 
   maybe_allows_mem_start = next;
   FOR_ALL_CONSTRAINTS (c)
-    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
+    if (!c->is_register && !c->is_const_int && !c->is_memory
+	&& !c->is_special_memory && !c->is_address
 	&& !c->maybe_allows_reg && c->maybe_allows_mem)
       enum_order[next++] = c;
   maybe_allows_mem_end = next;
 
   FOR_ALL_CONSTRAINTS (c)
-    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
+    if (!c->is_register && !c->is_const_int && !c->is_memory
+	&& !c->is_special_memory && !c->is_address
 	&& c->maybe_allows_reg && c->maybe_allows_mem)
       enum_order[next++] = c;
   gcc_assert (next == num_constraints);
@@ -1431,6 +1461,8 @@  write_tm_preds_h (void)
 			    register_start, register_end);
       write_range_function ("insn_extra_memory_constraint",
 			    memory_start, memory_end);
+      write_range_function ("insn_extra_special_memory_constraint",
+			    special_memory_start, special_memory_end);
       write_range_function ("insn_extra_address_constraint",
 			    address_start, address_end);
       write_allows_reg_mem_function ();
@@ -1479,6 +1511,7 @@  write_tm_preds_h (void)
 	    "  CT_REGISTER,\n"
 	    "  CT_CONST_INT,\n"
 	    "  CT_MEMORY,\n"
+	    "  CT_SPECIAL_MEMORY,\n"
 	    "  CT_ADDRESS,\n"
 	    "  CT_FIXED_FORM\n"
 	    "};\n"
@@ -1491,6 +1524,8 @@  write_tm_preds_h (void)
 	values.safe_push (std::make_pair (const_int_start, "CT_CONST_INT"));
       if (memory_start != memory_end)
 	values.safe_push (std::make_pair (memory_start, "CT_MEMORY"));
+      if (special_memory_start != special_memory_end)
+	values.safe_push (std::make_pair (special_memory_start, "CT_SPECIAL_MEMORY"));
       if (address_start != address_end)
 	values.safe_push (std::make_pair (address_start, "CT_ADDRESS"));
       if (address_end != num_constraints)
@@ -1602,6 +1637,7 @@  main (int argc, char **argv)
 
       case DEFINE_CONSTRAINT:
       case DEFINE_MEMORY_CONSTRAINT:
+      case DEFINE_SPECIAL_MEMORY_CONSTRAINT:
       case DEFINE_ADDRESS_CONSTRAINT:
 	process_define_constraint (&info);
 	break;
Index: gensupport.c
===================================================================
--- gensupport.c	(revision 232571)
+++ gensupport.c	(working copy)
@@ -521,6 +521,7 @@  process_rtx (rtx desc, file_location loc
     case DEFINE_CONSTRAINT:
     case DEFINE_REGISTER_CONSTRAINT:
     case DEFINE_MEMORY_CONSTRAINT:
+    case DEFINE_SPECIAL_MEMORY_CONSTRAINT:
     case DEFINE_ADDRESS_CONSTRAINT:
       queue_pattern (desc, &define_pred_tail, loc);
       break;
Index: ira-costs.c
===================================================================
--- ira-costs.c	(revision 232571)
+++ ira-costs.c	(working copy)
@@ -777,6 +777,7 @@  record_reg_classes (int n_alts, int n_op
 		      break;
 
 		    case CT_MEMORY:
+		    case CT_SPECIAL_MEMORY:
 		      /* Every MEM can be reloaded to fit.  */
 		      insn_allows_mem[i] = allows_mem[i] = 1;
 		      if (MEM_P (op))
Index: ira-lives.c
===================================================================
--- ira-lives.c	(revision 232571)
+++ ira-lives.c	(working copy)
@@ -774,6 +774,7 @@  single_reg_class (const char *constraint
 	  /* ??? Is this the best way to handle memory constraints?  */
 	  cn = lookup_constraint (constraints);
 	  if (insn_extra_memory_constraint (cn)
+	      || insn_extra_special_memory_constraint (cn)
 	      || insn_extra_address_constraint (cn))
 	    return NO_REGS;
 	  if (constraint_satisfied_p (op, cn)
Index: ira.c
===================================================================
--- ira.c	(revision 232571)
+++ ira.c	(working copy)
@@ -1868,6 +1868,7 @@  ira_setup_alts (rtx_insn *insn, HARD_REG
 
 			case CT_ADDRESS:
 			case CT_MEMORY:
+			case CT_SPECIAL_MEMORY:
 			  goto op_success;
 
 			case CT_FIXED_FORM:
Index: lra-constraints.c
===================================================================
--- lra-constraints.c	(revision 232571)
+++ lra-constraints.c	(working copy)
@@ -400,7 +400,7 @@  valid_address_p (struct address_info *ad
 }
 
 /* Return true if the eliminated form of memory reference OP satisfies
-   extra memory constraint CONSTRAINT.  */
+   extra (special) memory constraint CONSTRAINT.  */
 static bool
 satisfies_memory_constraint_p (rtx op, enum constraint_num constraint)
 {
@@ -2038,6 +2038,14 @@  process_alt_operands (int only_alternati
 		      if (constraint_satisfied_p (op, cn))
 			win = true;
 		      break;
+
+		    case CT_SPECIAL_MEMORY:
+		      if (MEM_P (op)
+			  && satisfies_memory_constraint_p (op, cn))
+			win = true;
+		      else if (spilled_pseudo_p (op))
+			win = true;
+		      break;
 		    }
 		  break;
 
@@ -3701,7 +3709,8 @@  curr_insn_transform (bool check_only_p)
 		 constraint += CONSTRAINT_LEN (c, constraint))
 	      {
 		enum constraint_num cn = lookup_constraint (constraint);
-		if (insn_extra_memory_constraint (cn)
+		if ((insn_extra_memory_constraint (cn)
+		     || insn_extra_special_memory_constraint (cn))
 		    && satisfies_memory_constraint_p (tem, cn))
 		  break;
 	      }
Index: recog.c
===================================================================
--- recog.c	(revision 232571)
+++ recog.c	(working copy)
@@ -1791,6 +1791,7 @@  asm_operand_ok (rtx op, const char *cons
 	      break;
 
 	    case CT_MEMORY:
+	    case CT_SPECIAL_MEMORY:
 	      /* Every memory operand can be reloaded to fit.  */
 	      result = result || memory_operand (op, VOIDmode);
 	      break;
@@ -2403,6 +2404,7 @@  preprocess_constraints (int n_operands,
 		      break;
 
 		    case CT_MEMORY:
+		    case CT_SPECIAL_MEMORY:
 		      op_alt[i].memory_ok = 1;
 		      break;
 
Index: reload.c
===================================================================
--- reload.c	(revision 232571)
+++ reload.c	(working copy)
@@ -3471,6 +3471,23 @@  find_reloads (rtx_insn *insn, int replac
 			offmemok = 1;
 			break;
 
+		      case CT_SPECIAL_MEMORY:
+			if (force_reload)
+			  break;
+			if (constraint_satisfied_p (operand, cn))
+			  win = 1;
+			/* Likewise if the address will be reloaded because
+			   reg_equiv_address is nonzero.  For reg_equiv_mem
+			   we have to check.  */
+			else if (REG_P (operand)
+				 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
+				 && reg_renumber[REGNO (operand)] < 0
+				 && reg_equiv_mem (REGNO (operand)) != 0
+				 && (constraint_satisfied_p
+				     (reg_equiv_mem (REGNO (operand)), cn)))
+			  win = 1;
+			break;
+
 		      case CT_ADDRESS:
 			if (constraint_satisfied_p (operand, cn))
 			  win = 1;
Index: rtl.def
===================================================================
--- rtl.def	(revision 232571)
+++ rtl.def	(working copy)
@@ -1035,6 +1035,7 @@  DEF_RTL_EXPR(DEFINE_REGISTER_CONSTRAINT,
       RTL object.  */
 DEF_RTL_EXPR(DEFINE_CONSTRAINT, "define_constraint", "sse", RTX_EXTRA)
 DEF_RTL_EXPR(DEFINE_MEMORY_CONSTRAINT, "define_memory_constraint", "sse", RTX_EXTRA)
+DEF_RTL_EXPR(DEFINE_SPECIAL_MEMORY_CONSTRAINT, "define_special_memory_constraint", "sse", RTX_EXTRA)
 DEF_RTL_EXPR(DEFINE_ADDRESS_CONSTRAINT, "define_address_constraint", "sse", RTX_EXTRA)
 
 
Index: stmt.c
===================================================================
--- stmt.c	(revision 232571)
+++ stmt.c	(working copy)
@@ -434,7 +434,8 @@  parse_input_constraint (const char **con
 	if (reg_class_for_constraint (cn) != NO_REGS
 	    || insn_extra_address_constraint (cn))
 	  *allows_reg = true;
-	else if (insn_extra_memory_constraint (cn))
+	else if (insn_extra_memory_constraint (cn)
+		 || insn_extra_special_memory_constraint (cn))
 	  *allows_mem = true;
 	else
 	  insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);