diff --git a/gcc/config/i386/i386-expand.h b/gcc/config/i386/i386-expand.h index 1ea789c4c3a..997cb7db059 100644 --- a/gcc/config/i386/i386-expand.h +++ b/gcc/config/i386/i386-expand.h @@ -44,9 +44,9 @@ void ix86_emit_binop (enum rtx_code code, machine_mode mode, rtx dst, rtx src); enum calling_abi ix86_function_abi (const_tree fndecl); bool ix86_function_ms_hook_prologue (const_tree fn); void warn_once_call_ms2sysv_xlogues (const char *feature); -rtx gen_push (rtx arg); +rtx gen_push (rtx arg, bool = false); rtx gen_pushfl (void); -rtx gen_pop (rtx arg); +rtx gen_pop (rtx arg, bool = false); rtx gen_popfl (void); rtx ix86_expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, int ignore); diff --git a/gcc/config/i386/i386-opts.h b/gcc/config/i386/i386-opts.h index 2ec76a16bce..4d293edb399 100644 --- a/gcc/config/i386/i386-opts.h +++ b/gcc/config/i386/i386-opts.h @@ -139,7 +139,8 @@ enum apx_features { apx_egpr = 1 << 0, apx_push2pop2 = 1 << 1, apx_ndd = 1 << 2, - apx_all = apx_egpr | apx_push2pop2 | apx_ndd, + apx_ppx = 1 << 3, + apx_all = apx_egpr | apx_push2pop2 | apx_ndd | apx_ppx, }; #endif diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 683ac643bc8..bd340582a33 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -105,7 +105,7 @@ along with GCC; see the file COPYING3. If not see static rtx legitimize_dllimport_symbol (rtx, bool); static rtx legitimize_pe_coff_extern_decl (rtx, bool); static void ix86_print_operand_address_as (FILE *, rtx, addr_space_t, bool); -static void ix86_emit_restore_reg_using_pop (rtx); +static void ix86_emit_restore_reg_using_pop (rtx, bool = false); #ifndef CHECK_STACK_LIMIT @@ -6448,7 +6448,7 @@ output_set_got (rtx dest, rtx label) /* Generate an "push" pattern for input ARG. */ rtx -gen_push (rtx arg) +gen_push (rtx arg, bool ppx_p) { struct machine_function *m = cfun->machine; @@ -6459,10 +6459,10 @@ gen_push (rtx arg) if (REG_P (arg) && GET_MODE (arg) != word_mode) arg = gen_rtx_REG (word_mode, REGNO (arg)); - return gen_rtx_SET (gen_rtx_MEM (word_mode, - gen_rtx_PRE_DEC (Pmode, - stack_pointer_rtx)), - arg); + rtx stack = gen_rtx_MEM (word_mode, + gen_rtx_PRE_DEC (Pmode, + stack_pointer_rtx)); + return ppx_p ? gen_pushp_di (stack, arg) : gen_rtx_SET (stack, arg); } rtx @@ -6486,15 +6486,16 @@ gen_pushfl (void) /* Generate an "pop" pattern for input ARG. */ rtx -gen_pop (rtx arg) +gen_pop (rtx arg, bool ppx_p) { if (REG_P (arg) && GET_MODE (arg) != word_mode) arg = gen_rtx_REG (word_mode, REGNO (arg)); - return gen_rtx_SET (arg, - gen_rtx_MEM (word_mode, - gen_rtx_POST_INC (Pmode, - stack_pointer_rtx))); + rtx stack = gen_rtx_MEM (word_mode, + gen_rtx_POST_INC (Pmode, + stack_pointer_rtx)); + + return ppx_p ? gen_popp_di (arg, stack) : gen_rtx_SET (arg, stack); } rtx @@ -6512,7 +6513,7 @@ gen_popfl (void) /* Generate a "push2" pattern for input ARG. */ rtx -gen_push2 (rtx mem, rtx reg1, rtx reg2) +gen_push2 (rtx mem, rtx reg1, rtx reg2, bool ppx_p = false) { struct machine_function *m = cfun->machine; const int offset = UNITS_PER_WORD * 2; @@ -6527,7 +6528,8 @@ gen_push2 (rtx mem, rtx reg1, rtx reg2) if (REG_P (reg2) && GET_MODE (reg2) != word_mode) reg2 = gen_rtx_REG (word_mode, REGNO (reg2)); - return gen_push2_di (mem, reg1, reg2); + return ppx_p ? gen_push2p_di (mem, reg1, reg2): + gen_push2_di (mem, reg1, reg2); } /* Return >= 0 if there is an unused call-clobbered register available @@ -7369,7 +7371,8 @@ ix86_emit_save_regs (void) for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) if (GENERAL_REGNO_P (regno) && ix86_save_reg (regno, true, true)) { - insn = emit_insn (gen_push (gen_rtx_REG (word_mode, regno))); + insn = emit_insn (gen_push (gen_rtx_REG (word_mode, regno), + TARGET_APX_PPX)); RTX_FRAME_RELATED_P (insn) = 1; } } @@ -7399,7 +7402,8 @@ ix86_emit_save_regs (void) gen_rtx_REG (word_mode, regno_list[0]), gen_rtx_REG (word_mode, - regno_list[1]))); + regno_list[1]), + TARGET_APX_PPX)); RTX_FRAME_RELATED_P (insn) = 1; rtx dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (3)); @@ -7431,7 +7435,8 @@ ix86_emit_save_regs (void) } else { - insn = emit_insn (gen_push (gen_rtx_REG (word_mode, regno))); + insn = emit_insn (gen_push (gen_rtx_REG (word_mode, regno), + TARGET_APX_PPX)); RTX_FRAME_RELATED_P (insn) = 1; aligned = true; } @@ -7439,7 +7444,8 @@ ix86_emit_save_regs (void) if (loaded_regnum == 1) { insn = emit_insn (gen_push (gen_rtx_REG (word_mode, - regno_list[0]))); + regno_list[0]), + TARGET_APX_PPX)); RTX_FRAME_RELATED_P (insn) = 1; } } @@ -9268,13 +9274,13 @@ ix86_expand_prologue (void) emit_insn (gen_prologue_use (stack_pointer_rtx)); } -/* Emit code to restore REG using a POP insn. */ +/* Emit code to restore REG using a POP or POPP insn. */ static void -ix86_emit_restore_reg_using_pop (rtx reg) +ix86_emit_restore_reg_using_pop (rtx reg, bool ppx_p) { struct machine_function *m = cfun->machine; - rtx_insn *insn = emit_insn (gen_pop (reg)); + rtx_insn *insn = emit_insn (gen_pop (reg, ppx_p)); ix86_add_cfa_restore_note (insn, reg, m->fs.sp_offset); m->fs.sp_offset -= UNITS_PER_WORD; @@ -9328,14 +9334,19 @@ ix86_emit_restore_reg_using_pop (rtx reg) /* Emit code to restore REG using a POP2 insn. */ static void -ix86_emit_restore_reg_using_pop2 (rtx reg1, rtx reg2) +ix86_emit_restore_reg_using_pop2 (rtx reg1, rtx reg2, bool ppx_p = false) { struct machine_function *m = cfun->machine; const int offset = UNITS_PER_WORD * 2; + rtx_insn *insn; rtx mem = gen_rtx_MEM (TImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx)); - rtx_insn *insn = emit_insn (gen_pop2_di (reg1, mem, reg2)); + + if (ppx_p) + insn = emit_insn (gen_pop2p_di (reg1, mem, reg2)); + else + insn = emit_insn (gen_pop2_di (reg1, mem, reg2)); RTX_FRAME_RELATED_P (insn) = 1; @@ -9397,13 +9408,13 @@ ix86_emit_restore_reg_using_pop2 (rtx reg1, rtx reg2) /* Emit code to restore saved registers using POP insns. */ static void -ix86_emit_restore_regs_using_pop (void) +ix86_emit_restore_regs_using_pop (bool ppx_p) { unsigned int regno; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (GENERAL_REGNO_P (regno) && ix86_save_reg (regno, false, true)) - ix86_emit_restore_reg_using_pop (gen_rtx_REG (word_mode, regno)); + ix86_emit_restore_reg_using_pop (gen_rtx_REG (word_mode, regno), ppx_p); } /* Emit code to restore saved registers using POP2 insns. */ @@ -9432,20 +9443,23 @@ ix86_emit_restore_regs_using_pop2 (void) ix86_emit_restore_reg_using_pop2 (gen_rtx_REG (word_mode, regno_list[0]), gen_rtx_REG (word_mode, - regno_list[1])); + regno_list[1]), + TARGET_APX_PPX); loaded_regnum = 0; regno_list[0] = regno_list[1] = -1; } } else { - ix86_emit_restore_reg_using_pop (gen_rtx_REG (word_mode, regno)); + ix86_emit_restore_reg_using_pop (gen_rtx_REG (word_mode, regno), + TARGET_APX_PPX); aligned = true; } } if (loaded_regnum == 1) - ix86_emit_restore_reg_using_pop (gen_rtx_REG (word_mode, regno_list[0])); + ix86_emit_restore_reg_using_pop (gen_rtx_REG (word_mode, regno_list[0]), + TARGET_APX_PPX); } /* Emit code and notes for the LEAVE instruction. If insn is non-null, @@ -9990,7 +10004,7 @@ ix86_expand_epilogue (int style) if (TARGET_APX_PUSH2POP2 && m->func_type == TYPE_NORMAL) ix86_emit_restore_regs_using_pop2 (); else - ix86_emit_restore_regs_using_pop (); + ix86_emit_restore_regs_using_pop (TARGET_APX_PPX); } /* If we used a stack pointer and haven't already got rid of it, diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 6b27f486274..9c74b3ebd90 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -54,6 +54,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define TARGET_APX_EGPR (ix86_apx_features & apx_egpr) #define TARGET_APX_PUSH2POP2 (ix86_apx_features & apx_push2pop2) #define TARGET_APX_NDD (ix86_apx_features & apx_ndd) +#define TARGET_APX_PPX (ix86_apx_features & apx_ppx) #include "config/vxworks-dummy.h" diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 1b5a794b9e5..03e4ddd3037 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -210,10 +210,13 @@ ;; For insn_callee_abi: UNSPEC_CALLEE_ABI - ;; For PUSH2/POP2 support + ;; For APX PUSH2/POP2 support UNSPEC_APXPUSH2 UNSPEC_APXPOP2_LOW UNSPEC_APXPOP2_HIGH + + ;; For APX PPX support + UNSPEC_APX_PPX ]) (define_c_enum "unspecv" [ @@ -3785,6 +3788,46 @@ [(set_attr "mode" "TI") (set_attr "prefix" "evex")]) +(define_insn "pushp_di" + [(set (match_operand:DI 0 "push_operand" "=<") + (match_operand:DI 1 "register_operand" "r")) + (unspec:DI [(const_int 0)] UNSPEC_APX_PPX)] + "TARGET_64BIT" + "pushp\t%1" + [(set_attr "mode" "DI")]) + +(define_insn "popp_di" + [(set (match_operand:DI 0 "register_operand" "=r") + (match_operand:DI 1 "pop_operand" ">")) + (unspec:DI [(const_int 0)] UNSPEC_APX_PPX)] + "TARGET_APX_PPX" + "popp\t%0" + [(set_attr "mode" "DI")]) + +(define_insn "push2p_di" + [(set (match_operand:TI 0 "push_operand" "=<") + (unspec:TI [(match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r")] + UNSPEC_APXPUSH2)) + (unspec:DI [(const_int 0)] UNSPEC_APX_PPX)] + "TARGET_APX_PUSH2POP2 && TARGET_APX_PPX" + "push2p\t%1, %2" + [(set_attr "mode" "TI") + (set_attr "type" "multi") + (set_attr "prefix" "evex")]) + +(define_insn "pop2p_di" + [(parallel [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:TI 1 "pop_operand" ">")] + UNSPEC_APXPOP2_LOW)) + (set (match_operand:DI 2 "register_operand" "=r") + (unspec:DI [(const_int 0)] UNSPEC_APXPOP2_HIGH)) + (unspec:DI [(const_int 0)] UNSPEC_APX_PPX)])] + "TARGET_APX_PUSH2POP2 && TARGET_APX_PPX" + "pop2p\t%0, %2" + [(set_attr "mode" "TI") + (set_attr "prefix" "evex")]) + (define_insn "*pushsf_rex64" [(set (match_operand:SF 0 "push_operand" "=X,X,X") (match_operand:SF 1 "nonmemory_no_elim_operand" "f,rF,v"))] diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt index b81c968876e..b2edfac0b2a 100644 --- a/gcc/config/i386/i386.opt +++ b/gcc/config/i386/i386.opt @@ -1348,6 +1348,9 @@ Enum(apx_features) String(push2pop2) Value(apx_push2pop2) Set(3) EnumValue Enum(apx_features) String(ndd) Value(apx_ndd) Set(4) +EnumValue +Enum(apx_features) String(ppx) Value(apx_ppx) Set(5) + EnumValue Enum(apx_features) String(all) Value(apx_all) Set(1) diff --git a/gcc/testsuite/gcc.target/i386/apx-interrupt-1.c b/gcc/testsuite/gcc.target/i386/apx-interrupt-1.c index 5f732d3e316..ffcb8fce71c 100644 --- a/gcc/testsuite/gcc.target/i386/apx-interrupt-1.c +++ b/gcc/testsuite/gcc.target/i386/apx-interrupt-1.c @@ -1,5 +1,5 @@ /* { dg-do compile { target { ! ia32 } } } */ -/* { dg-options "-mapxf -m64 -O2 -mgeneral-regs-only -mno-cld -mno-push-args -maccumulate-outgoing-args" } */ +/* { dg-options "-mapx-features=egpr -m64 -O2 -mgeneral-regs-only -mno-cld -mno-push-args -maccumulate-outgoing-args" } */ /* { dg-skip-if "does not emit .cfi_xxx" "*-*-darwin*" } */ extern void foo (void *) __attribute__ ((interrupt)); diff --git a/gcc/testsuite/gcc.target/i386/apx-ppx-1.c b/gcc/testsuite/gcc.target/i386/apx-ppx-1.c new file mode 100644 index 00000000000..e9a595381e3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/apx-ppx-1.c @@ -0,0 +1,9 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -mapx-features=egpr,push2pop2,ppx" } */ + +#include "apx-push2pop2-1.c" + +/* { dg-final { scan-assembler "pushp" } } */ +/* { dg-final { scan-assembler "popp" } } */ +/* { dg-final { scan-assembler "push2p" } } */ +/* { dg-final { scan-assembler "pop2p" } } */ diff --git a/gcc/testsuite/gcc.target/i386/apx-push2pop2-1.c b/gcc/testsuite/gcc.target/i386/apx-push2pop2-1.c index 089941d3726..c53112758a5 100644 --- a/gcc/testsuite/gcc.target/i386/apx-push2pop2-1.c +++ b/gcc/testsuite/gcc.target/i386/apx-push2pop2-1.c @@ -1,5 +1,5 @@ /* { dg-do compile { target { ! ia32 } } } */ -/* { dg-options "-O2 -mapxf" } */ +/* { dg-options "-O2 -mapx-features=push2pop2" } */ /* { dg-skip-if "does not emit .cfi_xxx" "*-*-darwin*" } */ extern int bar (int); diff --git a/gcc/testsuite/gcc.target/i386/apx-push2pop2_force_drap-1.c b/gcc/testsuite/gcc.target/i386/apx-push2pop2_force_drap-1.c index 656ca91391a..022113bb1e2 100644 --- a/gcc/testsuite/gcc.target/i386/apx-push2pop2_force_drap-1.c +++ b/gcc/testsuite/gcc.target/i386/apx-push2pop2_force_drap-1.c @@ -1,5 +1,5 @@ /* { dg-do compile { target { ! ia32 } } } */ -/* { dg-options "-O2 -mapxf -mforce-drap" } */ +/* { dg-options "-O2 -mapx-features=push2pop2 -mforce-drap" } */ /* { dg-skip-if "does not emit .cfi_xxx" "*-*-darwin*" } */ #include "apx-push2pop2-1.c" diff --git a/gcc/testsuite/gcc.target/i386/apx-push2pop2_interrupt-1.c b/gcc/testsuite/gcc.target/i386/apx-push2pop2_interrupt-1.c index 747f7aaf191..a5b46893208 100644 --- a/gcc/testsuite/gcc.target/i386/apx-push2pop2_interrupt-1.c +++ b/gcc/testsuite/gcc.target/i386/apx-push2pop2_interrupt-1.c @@ -1,5 +1,5 @@ /* { dg-do compile { target { ! ia32 } } } */ -/* { dg-options "-O2 -mapxf -mgeneral-regs-only -mno-cld -mno-push-args -maccumulate-outgoing-args" } */ +/* { dg-options "-O2 -mapx-features=egpr,push2pop2 -mgeneral-regs-only -mno-cld -mno-push-args -maccumulate-outgoing-args" } */ extern void foo (void *) __attribute__ ((interrupt));