]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[APX PPX] Support Intel APX PPX
authorHongyu Wang <hongyu.wang@intel.com>
Thu, 16 Nov 2023 07:18:07 +0000 (15:18 +0800)
committerHongyu Wang <hongyu.wang@intel.com>
Tue, 21 Nov 2023 08:00:53 +0000 (16:00 +0800)
PPX stands for Push-Pop Acceleration. PUSH/PUSH2 and its corresponding POP
can be marked with a 1-bit hint to indicate that the POP reads the
value written by the PUSH from the stack. The processor tracks these marked
instructions internally and fast-forwards register data between
matching PUSH and POP instructions, without going through memory or
through the training loop of the Fast Store Forwarding Predictor (FSFP).
This feature can also be adopted to PUSH2/POP2.

For GCC, we emit explicit suffix 'p' (paired) to indicate the push/pop
pair are marked with PPX hint. To separate form original push/pop, we
add an UNSPEC on top of those PUSH/POP patterns.

In the first implementation we only emit them under prologue/epilogue
when saving/restoring callee-saved registers to make sure push/pop are
paired. So an extra flag was added to check if PPX insns can be emitted
for those register save/restore interfaces.

The PPX hint is purely a performance hint. If the 'p' suffix is not
emitted for paired push/pop, the PPX optimization will be disabled,
while program sematic will not be affected at all.

gcc/ChangeLog:

* config/i386/i386-expand.h (gen_push): Add default bool
parameter.
(gen_pop): Likewise.
* config/i386/i386-opts.h (enum apx_features): Add apx_ppx, add
it to apx_all.
* config/i386/i386.cc (ix86_emit_restore_reg_using_pop): Add
ppx_p parameter for function declaration.
(gen_push2): Add ppx_p parameter, emit push2p if ppx_p is true.
(gen_push): Likewise.
(ix86_emit_restore_reg_using_pop2): Likewise for pop2p.
(ix86_emit_save_regs): Emit pushp/push2p under TARGET_APX_PPX.
(ix86_emit_restore_reg_using_pop): Add ppx_p, emit popp insn
and adjust cfi when ppx_p is ture.
(ix86_emit_restore_reg_using_pop2): Add ppx_p and parse to its
callee.
(ix86_emit_restore_regs_using_pop2): Likewise.
(ix86_expand_epilogue): Parse TARGET_APX_PPX to
ix86_emit_restore_reg_using_pop.
* config/i386/i386.h (TARGET_APX_PPX): New.
* config/i386/i386.md (UNSPEC_APX_PPX): New unspec.
(pushp_di): New define_insn.
(popp_di): Likewise.
(push2p_di): Likewise.
(pop2p_di): Likewise.
* config/i386/i386.opt: Add apx_ppx enum.

gcc/testsuite/ChangeLog:

* gcc.target/i386/apx-interrupt-1.c: Adjust option to restrict them
under certain subfeatures.
* gcc.target/i386/apx-push2pop2-1.c: Likewise.
* gcc.target/i386/apx-push2pop2_force_drap-1.c: Likewise.
* gcc.target/i386/apx-push2pop2_interrupt-1.c: Likewise.
* gcc.target/i386/apx-ppx-1.c: New test.

gcc/config/i386/i386-expand.h
gcc/config/i386/i386-opts.h
gcc/config/i386/i386.cc
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/config/i386/i386.opt
gcc/testsuite/gcc.target/i386/apx-interrupt-1.c
gcc/testsuite/gcc.target/i386/apx-ppx-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/apx-push2pop2-1.c
gcc/testsuite/gcc.target/i386/apx-push2pop2_force_drap-1.c
gcc/testsuite/gcc.target/i386/apx-push2pop2_interrupt-1.c

index 1ea789c4c3a2b85c1dad69e9e074ab9d57c133fa..997cb7db0592f9fdd09bc4c9f0fdd080f9da9799 100644 (file)
@@ -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);
index 2ec76a16bceabb17511f43e66ec2a377ee1cf7c3..4d293edb3997b25650b97775f7d2ef7006a598ae 100644 (file)
@@ -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
index 683ac643bc8951c7829a4e06b24914812aa051f8..bd340582a339ac52cf1002a3347643b1a21fee43 100644 (file)
@@ -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,
index 6b27f4862740a9ba5900eca2465cc1507f016c85..9c74b3ebd906e533a24c572974878585449422a8 100644 (file)
@@ -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"
 
index 1b5a794b9e54e311c3ae2279773488b21ed58eaf..03e4ddd3037415b48180fba5363f3531aabe077b 100644 (file)
   ;; 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" [
   [(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"))]
index b81c968876e3c46c380777f3b41aecfa578b7da7..b2edfac0b2aeb1bc921dac0b46edecb53753fc42 100644 (file)
@@ -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)
 
index 5f732d3e3160447e379e3f0c0ebc078428ed01e8..ffcb8fce71cacd19679b963036856f441ae1d79f 100644 (file)
@@ -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 (file)
index 0000000..e9a5953
--- /dev/null
@@ -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" } } */
index 089941d3726b49f85a37a679f64e28652efca7f3..c53112758a53cc024726ecd050d612910b6df613 100644 (file)
@@ -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);
index 656ca91391ae1d35ecd0dd62a231c7b762d9842e..022113bb1e275baccd37acf6fa4d950176c0c978 100644 (file)
@@ -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"
index 747f7aaf191f7c562ce2367dca33a7c91a02b842..a5b4689320862c9466080db37cb2c10ec590449f 100644 (file)
@@ -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));