| 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);
|
|
|