Index: gcc/gcc/config/i386/i386.c |
diff --git a/gcc/gcc/config/i386/i386.c b/gcc/gcc/config/i386/i386.c |
index 24a9cf0e5614205f39b507d335484f697da90f61..1d91ca04b0dae06740554f72266bd8a8e2d34baf 100644 |
--- a/gcc/gcc/config/i386/i386.c |
+++ b/gcc/gcc/config/i386/i386.c |
@@ -1818,6 +1818,9 @@ static bool ix86_valid_target_attribute_p (tree, tree, tree, int); |
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 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum) |
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 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum) |
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 @@ ix86_file_end (void) |
(*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 @@ ix86_file_end (void) |
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 @@ ix86_expand_epilogue (int style) |
+ 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 @@ ix86_expand_epilogue (int style) |
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 @@ ix86_expand_epilogue (int style) |
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 @@ ix86_expand_epilogue (int style) |
} |
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 @@ ix86_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, |
} |
-/* 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 @@ gen_r15(rtx reg) |
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 @@ gen_r15(rtx reg) |
} |
} |
+/* 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 @@ ix86_decompose_address (rtx addr, struct ix86_address *out) |
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 @@ ix86_decompose_address (rtx addr, struct ix86_address *out) |
* 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 @@ legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, |
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 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov) |
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 @@ print_operand (FILE *file, rtx x, int code) |
#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 @@ void |
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 @@ print_operand_address (FILE *file, rtx addr) |
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 @@ print_operand_address (FILE *file, rtx addr) |
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 @@ ix86_attr_length_address_default (rtx insn) |
{ |
int i; |
- if (insn_is_nacl_lea(insn)) |
+ if (get_attr_type (insn) == TYPE_LEA) |
{ |
rtx set = PATTERN (insn); |
@@ -19378,10 +19595,14 @@ ix86_attr_length_address_default (rtx insn) |
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); |