[gcc] Use new constraint for LEA address operands.

The problem of processing LEA address operands is that it requires original, non-nacl address decomposition. Before this change, an original "p" constraint was used, and a global variable NACL_LEA_MATCH_ADDRESS_OPERAND signaled LEA decomposition mode to x86_decompose_address. That solution required appropriate setting of NACL_LEA_MATCH_ADDRESS_OPERAND before every call to constrain_operands.

Here I introduce new "T" constraint, and use custom decomposition function to process it. NACL_LEA_ADDRESS_OPERAND is still here, but it is not checked any more. Next change will cleanup it completely.

In fact, new address decomposition function is an original, non-nacl x86_decompose_address. For now, I just copy-paste it. Perhaps it is better to split x86_decompose_address into pieces and reuse them, but this better goes in a separate change.

Review URL: http://codereview.chromium.org/2873014
diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
index 89722bb..c954852 100644
--- a/gcc/config/i386/constraints.md
+++ b/gcc/config/i386/constraints.md
@@ -169,3 +169,7 @@
    to fit that range (for immediate operands in zero-extending x86-64
    instructions)."
   (match_operand 0 "x86_64_zext_immediate_operand"))
+
+(define_address_constraint "T"
+  "Address operand of LEA instruction."
+  (match_operand 0 "lea_address_operand"))
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 24a9cf0..1d91ca0 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -1818,6 +1818,9 @@
 static bool ix86_valid_target_attribute_inner_p (tree, char *[]);
 static bool ix86_can_inline_p (tree, tree);
 static void ix86_set_current_function (tree);
+static int ix86_lea_decompose_address (rtx, struct ix86_address *);
+static int legitimate_address_parts_p (const struct ix86_address *, int);
+static void print_operand_address_parts (FILE *, const struct ix86_address *);
 
 
 /* The svr4 ABI for the i386 says that records and unions are returned
@@ -6593,7 +6596,7 @@
 	 sse_prologue_save insn template that produces computed jump across
 	 SSE saves.  We need some preparation work to get this working.  */
 
-      if (!flag_control_integrity)
+      if (!TARGET_NACL)
 	{
 	  label = gen_label_rtx ();
 	  label_ref = gen_rtx_LABEL_REF (Pmode, label);
@@ -6641,7 +6644,7 @@
       set_mem_align (mem, BITS_PER_WORD);
 
       /* And finally do the dirty job!  */
-      if (flag_control_integrity)
+      if (TARGET_NACL)
 	{
 	  emit_insn (gen_nacl_sse_prologue_save (mem,
 						 GEN_INT (cum->sse_regno)));
@@ -7463,7 +7466,7 @@
 	  (*targetm.asm_out.unique_section) (decl, 0);
 	  switch_to_section (get_named_section (decl, NULL, 0));
 
-	  if (flag_control_integrity && !getenv("NONACLRET"))
+	  if (TARGET_NACL && !getenv("NONACLRET"))
 	    fprintf (asm_out_file, ".p2align %d\n", NACL_ALIGN_POW2);
 	  (*targetm.asm_out.globalize_label) (asm_out_file, name);
 	  fputs ("\t.hidden\t", asm_out_file);
@@ -7474,12 +7477,12 @@
       else
 	{
 	  switch_to_section (text_section);
-	  if (flag_control_integrity && !getenv("NONACLRET"))
+	  if (TARGET_NACL && !getenv("NONACLRET"))
 	    fprintf (asm_out_file, ".p2align %d\n", NACL_ALIGN_POW2);
 	  ASM_OUTPUT_LABEL (asm_out_file, name);
 	}
 
-      if (flag_control_integrity && !getenv("NONACLRET"))
+      if (TARGET_NACL && !getenv("NONACLRET"))
         {
           xops[0] = gen_rtx_REG (Pmode, regno);
           output_asm_insn ("pop{l}\t%0", xops);
@@ -8631,7 +8634,7 @@
 					    + frame.padding0),
 				   style);
       /* If not an i386, mov & pop is faster than "leave".  */
-      else if (!flag_control_integrity &&
+      else if (!TARGET_NACL &&
                (TARGET_USE_LEAVE || optimize_function_for_size_p (cfun)
 	       || !cfun->machine->use_fast_prologue_epilogue))
 	emit_insn ((*ix86_gen_leave) ());
@@ -8728,7 +8731,7 @@
 	 return address, do explicit add, and jump indirectly to the
 	 caller.  */
 
-      if ((flag_control_integrity && !getenv("NONACLRET")) ||
+      if ((TARGET_NACL && !getenv("NONACLRET")) ||
 	  (crtl->args.pops_args >= 65536))
 	{
           /* x86_64 dedicates R11 for call-scratch needs */
@@ -8737,7 +8740,7 @@
 
 	  emit_insn ((*ix86_gen_pop1) (reg1));
 	  emit_insn ((*ix86_gen_add3) (stack_pointer_rtx, stack_pointer_rtx, popc));
-	  if (flag_control_integrity && !getenv("NONACLRET")) {
+	  if (TARGET_NACL && !getenv("NONACLRET")) {
 	    emit_jump_insn (gen_nacl_return_indirectsi (reg2));
 	  } else {
 	    emit_jump_insn (gen_return_indirect_internal (reg1));
@@ -8748,7 +8751,7 @@
     }
   else
     {
-      if (flag_control_integrity && !getenv("NONACLRET"))
+      if (TARGET_NACL && !getenv("NONACLRET"))
         {
 	  /* x86_64 dedicates R11 for call-scratch needs */
 	  rtx reg1 = gen_rtx_REG (Pmode, TARGET_64BIT ? R11_REG : CX_REG);
@@ -8789,20 +8792,192 @@
 
 }
 
-/* Extract the parts of an RTL expression that is a valid memory address
-   for an instruction.  Return 0 if the structure of the address is
-   grossly off.  Return -1 if the address contains ASHIFT, so it is not
-   strictly valid, but still used for computing length of lea instruction.  */
+/* Extract the parts of an RTL expression that is a valid address for lea
+   instruction.
+   WARNING: This is a copy-paste of the original ix86_decompose_address.  */
+
+static int
+ix86_lea_decompose_address (rtx addr, struct ix86_address *out)
+{
+  rtx base = NULL_RTX, index = NULL_RTX, disp = NULL_RTX;
+  rtx base_reg, index_reg;
+  HOST_WIDE_INT scale = 1;
+  rtx scale_rtx = NULL_RTX;
+  int retval = 1;
+  enum ix86_address_seg seg = SEG_DEFAULT;
+
+  if (REG_P (addr) || GET_CODE (addr) == SUBREG)
+    base = addr;
+  else if (GET_CODE (addr) == PLUS)
+    {
+      rtx addends[4], op;
+      int n = 0, i;
+
+      op = addr;
+      do
+	{
+	  if (n >= 4)
+	    return 0;
+	  /* Original version handled nested PLUS only if it was a left child.
+	     Here we also handle nested PLUS that is a right child.
+	     TODO: what if (plus (plus a b) (plus c d)) ?  */
+	  if (GET_CODE (XEXP (op, 1)) == PLUS)
+	    {
+	      addends[n++] = XEXP (op, 0);
+	      op = XEXP (op, 1);
+	    }
+	  else
+	    {
+	      addends[n++] = XEXP (op, 1);
+	      op = XEXP (op, 0);
+	    }
+	}
+      while (GET_CODE (op) == PLUS);
+      if (n >= 4)
+	return 0;
+      addends[n] = op;
+
+      for (i = n; i >= 0; --i)
+	{
+	  op = addends[i];
+	  switch (GET_CODE (op))
+	    {
+	    case MULT:
+	      if (index)
+		return 0;
+	      index = XEXP (op, 0);
+	      scale_rtx = XEXP (op, 1);
+	      break;
+
+	    case UNSPEC:
+	      if (XINT (op, 1) == UNSPEC_TP
+	          && TARGET_TLS_DIRECT_SEG_REFS
+	          && seg == SEG_DEFAULT)
+		seg = TARGET_64BIT ? SEG_FS : SEG_GS;
+	      else
+		return 0;
+	      break;
+
+	    case REG:
+	    case SUBREG:
+	      if (!base)
+		base = op;
+	      else if (!index)
+		index = op;
+	      else
+		return 0;
+	      break;
+
+	    case CONST:
+	    case CONST_INT:
+	    case SYMBOL_REF:
+	    case LABEL_REF:
+	      if (disp)
+		return 0;
+	      disp = op;
+	      break;
+
+	    default:
+	      return 0;
+	    }
+	}
+    }
+  else if (GET_CODE (addr) == MULT)
+    {
+      index = XEXP (addr, 0);		/* index*scale */
+      scale_rtx = XEXP (addr, 1);
+    }
+  else if (GET_CODE (addr) == ASHIFT)
+    {
+      rtx tmp;
+
+      /* We're called for lea too, which implements ashift on occasion.  */
+      index = XEXP (addr, 0);
+      tmp = XEXP (addr, 1);
+      if (!CONST_INT_P (tmp))
+	return 0;
+      scale = INTVAL (tmp);
+      if ((unsigned HOST_WIDE_INT) scale > 3)
+	return 0;
+      scale = 1 << scale;
+      retval = -1;
+    }
+  else
+    disp = addr;			/* displacement */
+
+  /* Extract the integral value of scale.  */
+  if (scale_rtx)
+    {
+      if (!CONST_INT_P (scale_rtx))
+	return 0;
+      scale = INTVAL (scale_rtx);
+    }
+
+  base_reg = base && GET_CODE (base) == SUBREG ? SUBREG_REG (base) : base;
+  index_reg = index && GET_CODE (index) == SUBREG ? SUBREG_REG (index) : index;
+
+  /* Allow arg pointer and stack pointer as index if there is not scaling.  */
+  if (base_reg && index_reg && scale == 1
+      && (index_reg == arg_pointer_rtx
+	  || index_reg == frame_pointer_rtx
+	  || (REG_P (index_reg) && REGNO (index_reg) == STACK_POINTER_REGNUM)))
+    {
+      rtx tmp;
+      tmp = base, base = index, index = tmp;
+      tmp = base_reg, base_reg = index_reg, index_reg = tmp;
+    }
+
+  /* Special case: %ebp cannot be encoded as a base without a displacement.  */
+  if ((base_reg == hard_frame_pointer_rtx
+       || base_reg == frame_pointer_rtx
+       || base_reg == arg_pointer_rtx) && !disp)
+    disp = const0_rtx;
+
+  /* Special case: on K6, [%esi] makes the instruction vector decoded.
+     Avoid this by transforming to [%esi+0].
+     Reload calls address legitimization without cfun defined, so we need
+     to test cfun for being non-NULL. */
+  if (TARGET_K6 && cfun && optimize_function_for_speed_p (cfun)
+      && base_reg && !index_reg && !disp
+      && REG_P (base_reg)
+      && REGNO_REG_CLASS (REGNO (base_reg)) == SIREG)
+    disp = const0_rtx;
+
+  /* Special case: encode reg+reg instead of reg*2.  */
+  if (!base && index && scale && scale == 2)
+    base = index, base_reg = index_reg, scale = 1;
+
+  /* Special case: scaling cannot be encoded without base or displacement.  */
+  if (!base && !disp && index && scale != 1)
+    disp = const0_rtx;
+
+  out->base = base;
+  out->index = index;
+  out->disp = disp;
+  out->scale = scale;
+  out->seg = seg;
+
+  return retval;
+}
 
 int NACL_LEA_MATCH_ADDRESS_OPERAND = 0;
 int
 lea_match_address_operand (rtx op, enum machine_mode mode)
 {
-  int retval;
-  NACL_LEA_MATCH_ADDRESS_OPERAND++;
-  retval = memory_address_p (mode, op);
-  NACL_LEA_MATCH_ADDRESS_OPERAND--;
-  return retval;
+  struct ix86_address parts;
+
+  /* 1 and -1 are valid decompose address results for lea operand.  */
+  if (ix86_lea_decompose_address (op, &parts) == 0)
+    return 0;      
+    
+  if (parts.seg != SEG_DEFAULT)
+    return 0;
+  
+#ifdef REG_OK_STRICT
+  return legitimate_address_parts_p (&parts, 1);
+#else
+  return legitimate_address_parts_p (&parts, 0);
+#endif
 }
 
 /* Check if instruction is a LEA instruction.
@@ -8856,9 +9031,10 @@
   rtx base_reg;
 
   /* In lea mode don't use R15, don't use nacl: prefix */
-  if (NACL_LEA_MATCH_ADDRESS_OPERAND
-      || !flag_control_integrity || !TARGET_64BIT) return 0;
-  if (!reg) return 1;
+  if (!TARGET_NACL || !TARGET_64BIT)
+    return 0;
+  if (!reg)
+    return 1;
   base_reg = GET_CODE (reg) == SUBREG ? SUBREG_REG (reg) : reg;
   switch (REGNO(base_reg))
     {
@@ -8876,6 +9052,11 @@
     }
 }
 
+/* Extract the parts of an RTL expression that is a valid memory address
+   for an instruction.  Return 0 if the structure of the address is
+   grossly off.  Return -1 if the address contains ASHIFT, so it is not
+   strictly valid, but still used for computing length of lea instruction.  */
+
 int
 ix86_decompose_address (rtx addr, struct ix86_address *out)
 {
@@ -8972,12 +9153,11 @@
 	      if (!base)
 		base = op;
 	      else if (!index)
-                {
-		index = op;
-		    if (!NACL_LEA_MATCH_ADDRESS_OPERAND
-		      && flag_control_integrity && TARGET_64BIT)
-                    seg = SEG_NACL;
-                }
+		{
+		  index = op;
+		  if (TARGET_NACL && TARGET_64BIT)
+		    seg = SEG_NACL;
+		}
 	      else
 		return 0;
 	      break;
@@ -9068,8 +9248,7 @@
    *          jne     .L2
    * */
   if (!getenv("NACL_ALLOW_MAGIC_DISP") &&
-      TARGET_64BIT && flag_control_integrity &&
-      !NACL_LEA_MATCH_ADDRESS_OPERAND &&
+      TARGET_64BIT && TARGET_NACL &&
       index_reg &&
       disp && GET_CODE(disp) == CONST)
     {
@@ -9490,21 +9669,27 @@
 		      rtx addr, int strict)
 {
   struct ix86_address parts;
+
+  if (ix86_decompose_address (addr, &parts) <= 0)
+    return FALSE;
+
+  return legitimate_address_parts_p (&parts, strict);
+}
+
+/* Check if the decomposed address is a valid memory address.  */
+
+static int
+legitimate_address_parts_p (const struct ix86_address *parts, int strict)
+{
   rtx base, index, disp;
   HOST_WIDE_INT scale;
   const char *reason = NULL;
   rtx reason_rtx = NULL_RTX;
 
-  if (ix86_decompose_address (addr, &parts) <= 0)
-    {
-      reason = "decomposition failed";
-      goto report_error;
-    }
-
-  base = parts.base;
-  index = parts.index;
-  disp = parts.disp;
-  scale = parts.scale;
+  base = parts->base;
+  index = parts->index;
+  disp = parts->disp;
+  scale = parts->scale;
 
   /* Validate base register.
 
@@ -10121,7 +10306,7 @@
       break;
 
     case TLS_MODEL_LOCAL_EXEC:
-      if (TARGET_64BIT && flag_control_integrity)
+      if (TARGET_64BIT && TARGET_NACL)
 	{
 	  rtx rax = gen_rtx_REG (Pmode, AX_REG);
 	  emit_insn (gen_naclcall_tls (rax, x));
@@ -11572,6 +11757,30 @@
 #endif
 	  return;
 
+	case 'Z':
+	  {
+	    struct ix86_address parts;
+	    int ok;
+
+	    ok = ix86_lea_decompose_address (x, &parts);
+	    gcc_assert (ok);
+
+	    /* final.c:output_address calls walk_alter_subreg before calling
+	       PRINT_OPERAND_ADDRESS. We might want to call it here as well,
+	       but its current implementation does not process ASHIFT (which
+	       matched to LEA).
+	       We should probably fix walk_alter_subreg, but I'm not sure if
+	       allowing ASHIFT there is ok.
+	       For now, just fix decomposed address parts.  */
+	    if (parts.base != NULL_RTX && GET_CODE (parts.base) == SUBREG)
+	        parts.base = alter_subreg (&parts.base);
+	    if (parts.index != NULL_RTX && GET_CODE (parts.index) == SUBREG)
+	        parts.index = alter_subreg (&parts.index);
+
+	    print_operand_address_parts (file, &parts);
+	  }
+	  return;
+
 	default:
 	    output_operand_lossage ("invalid operand code '%c'", code);
 	}
@@ -11701,18 +11910,26 @@
 print_operand_address (FILE *file, rtx addr)
 {
   struct ix86_address parts;
-  rtx base, index, disp;
-  int scale;
   int ok = ix86_decompose_address (addr, &parts);
 
   gcc_assert (ok);
+  print_operand_address_parts (file, &parts);
+}
 
-  base = parts.base;
-  index = parts.index;
-  disp = parts.disp;
-  scale = parts.scale;
+/* Print a memory operand whose decomposed address is PARTS.  */
 
-  switch (parts.seg)
+static void
+print_operand_address_parts (FILE *file, const struct ix86_address *parts)
+{
+  rtx base, index, disp;
+  int scale;
+
+  base = parts->base;
+  index = parts->index;
+  disp = parts->disp;
+  scale = parts->scale;
+
+  switch (parts->seg)
     {
     case SEG_DEFAULT:
       break;
@@ -11721,7 +11938,7 @@
     case SEG_NACL:
       if (ASSEMBLER_DIALECT == ASM_ATT)
 	putc ('%', file);
-      switch (parts.seg)
+      switch (parts->seg)
 	{
 	  case SEG_FS:
 	    fputs ("fs:", file);
@@ -11761,7 +11978,7 @@
 
       if (CONST_INT_P (disp))
 	{
-	  if (ASSEMBLER_DIALECT == ASM_INTEL && parts.seg == SEG_DEFAULT)
+	  if (ASSEMBLER_DIALECT == ASM_INTEL && parts->seg == SEG_DEFAULT)
 	    fputs ("ds:", file);
 	  fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (disp));
 	}
@@ -19369,7 +19586,7 @@
 {
   int i;
 
-  if (insn_is_nacl_lea(insn))
+  if (get_attr_type (insn) == TYPE_LEA)
     {
       rtx set = PATTERN (insn);
 
@@ -19378,10 +19595,14 @@
 
       gcc_assert (GET_CODE (set) == SET);
 
-      NACL_LEA_MATCH_ADDRESS_OPERAND++;
-      i = memory_address_length (SET_SRC (set));
-      NACL_LEA_MATCH_ADDRESS_OPERAND--;
-      return i;
+      /* HACK: this is used to calculate min instruction size. It is probably
+         safe to return 0 from here.
+         TODO: factor out memory_address_parts_length and call it here with
+         x86_lea_decompose_address parts.  */
+      if (TARGET_NACL)
+        return 0;
+
+      return memory_address_length (SET_SRC (set));
     }
 
   extract_insn_cached (insn);
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 602f4b7..6ad93a9 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -5967,34 +5967,34 @@
 
 (define_insn "*lea_1"
   [(set (match_operand:SI 0 "register_operand" "=r")
-	(match_operand:SI 1 "lea_address_operand" "p"))]
+	(match_operand:SI 1 "lea_address_operand" "T"))]
   "!TARGET_64BIT"
-  "lea{l}\t{%a1, %0|%0, %a1}"
+  "lea{l}\t{%Z1, %0|%0, %Z1}"
   [(set_attr "type" "lea")
    (set_attr "mode" "SI")])
 
 (define_insn "*lea_1_rex64"
   [(set (match_operand:SI 0 "register_operand" "=r")
-	(subreg:SI (match_operand:DI 1 "lea_address_operand" "p") 0))]
+	(subreg:SI (match_operand:DI 1 "lea_address_operand" "T") 0))]
   "TARGET_64BIT"
-  "lea{l}\t{%a1, %0|%0, %a1}"
+  "lea{l}\t{%Z1, %0|%0, %Z1}"
   [(set_attr "type" "lea")
    (set_attr "mode" "SI")])
 
 (define_insn "*lea_1_zext"
   [(set (match_operand:DI 0 "register_operand" "=r")
 	(zero_extend:DI
-	 (subreg:SI (match_operand:DI 1 "lea_address_operand" "p") 0)))]
+	 (subreg:SI (match_operand:DI 1 "lea_address_operand" "T") 0)))]
   "TARGET_64BIT"
-  "lea{l}\t{%a1, %k0|%k0, %a1}"
+  "lea{l}\t{%Z1, %k0|%k0, %Z1}"
   [(set_attr "type" "lea")
    (set_attr "mode" "SI")])
 
 (define_insn "*lea_2_rex64"
   [(set (match_operand:DI 0 "register_operand" "=r")
-	(match_operand:DI 1 "lea_address_operand" "p"))]
+	(match_operand:DI 1 "lea_address_operand" "T"))]
   "TARGET_64BIT"
-  "lea{q}\t{%a1, %0|%0, %a1}"
+  "lea{q}\t{%Z1, %0|%0, %Z1}"
   [(set_attr "type" "lea")
    (set_attr "mode" "DI")])
 
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index 7038151..0af4c13 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -809,17 +809,7 @@
 ;; Return true if op if a valid address, and does not contain
 ;; a segment override.
 (define_special_predicate "lea_address_operand"
-  (match_operand 0 "lea_match_address_operand")
-{
-  struct ix86_address parts;
-  int ok;
-
-  NACL_LEA_MATCH_ADDRESS_OPERAND++;
-  ok = ix86_decompose_address (op, &parts);
-  gcc_assert (ok);
-  NACL_LEA_MATCH_ADDRESS_OPERAND--;
-  return parts.seg == SEG_DEFAULT;
-})
+  (match_test "lea_match_address_operand (op, mode)"))
 
 ;; Return nonzero if the rtx is known to be at least 32 bits aligned.
 (define_predicate "aligned_operand"
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index c11e4dd..0851596 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -1355,7 +1355,6 @@
 static const struct std_pred_table std_preds[] = {
   {"general_operand", false, true, {SUBREG, REG, MEM}},
   {"address_operand", true, true, {SUBREG, REG, MEM, PLUS, MINUS, MULT}},
-  {"lea_match_address_operand", true, true, {SUBREG, REG, MEM, PLUS, MINUS, MULT}},
   {"register_operand", false, false, {SUBREG, REG}},
   {"pmode_register_operand", true, false, {SUBREG, REG}},
   {"scratch_operand", false, false, {SCRATCH, REG}},