[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}},