Patchwork [i386] Introduce __readeflags () and __writeeflags () intrinsics.

login
register
mail settings
Submitter Kirill Yukhin
Date Dec. 4, 2013, 4:59 p.m.
Message ID <20131204165948.GA21551@msticlxl57.ims.intel.com>
Download mbox | patch
Permalink /patch/296587/
State New
Headers show

Comments

Kirill Yukhin - Dec. 4, 2013, 4:59 p.m.
Hello,

MSVC and ICC (currently Windows version, Linux version soon) have
dedicated intrinsics to read/set EFLAGS register ([1], [2]).

Patch introduces these intrinsics and tests for them.

Bootstrapped. New tests pass.
Although gate is closed patch is obvious.
So, is it ok for trunk?

ChangeLog/
	* config/i386/ia32intrin.h (__readeflags): New.
	(__writeeflags): Ditto.

testsuite/ChangeLog/
	* gcc.target/i386/readeflags-1.c: New.
	* gcc.target/i386/writeeflags-1.c: Ditto.

[1] - http://msdn.microsoft.com/en-us/library/aa983406(v=vs.90).aspx
[2] - http://msdn.microsoft.com/en-us/library/aa983392(v=vs.90).aspx

--
Thanks, K
Kirill Yukhin - Dec. 4, 2013, 5:58 p.m.
Hello,
On 04 Dec 19:59, Kirill Yukhin wrote:
> So, is it ok for trunk?

Small correction. I think it is better to use
popfql/pushfql instead of popf/pushf (however they're
encoded equally).

--
Thanks, K
H.J. Lu - Dec. 4, 2013, 6:07 p.m.
On Wed, Dec 4, 2013 at 9:58 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> Hello,
> On 04 Dec 19:59, Kirill Yukhin wrote:
>> So, is it ok for trunk?
>
> Small correction. I think it is better to use
> popfql/pushfql instead of popf/pushf (however they're
> encoded equally).
>

If you define the proper type, you can use pushf/pop
and push/popf in the same readeflags/writeflags
implementation for -m32/-mx32/-m64.
Uros Bizjak - Dec. 4, 2013, 7:16 p.m.
On Wed, Dec 4, 2013 at 5:59 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:

> MSVC and ICC (currently Windows version, Linux version soon) have
> dedicated intrinsics to read/set EFLAGS register ([1], [2]).
>
> Patch introduces these intrinsics and tests for them.
>
> Bootstrapped. New tests pass.
> Although gate is closed patch is obvious.
> So, is it ok for trunk?
>
> ChangeLog/
>         * config/i386/ia32intrin.h (__readeflags): New.
>         (__writeeflags): Ditto.
>
> testsuite/ChangeLog/
>         * gcc.target/i386/readeflags-1.c: New.
>         * gcc.target/i386/writeeflags-1.c: Ditto.
>
> [1] - http://msdn.microsoft.com/en-us/library/aa983406(v=vs.90).aspx
> [2] - http://msdn.microsoft.com/en-us/library/aa983392(v=vs.90).aspx
>
> --
> Thanks, K
>
> diff --git a/gcc/config/i386/ia32intrin.h b/gcc/config/i386/ia32intrin.h
> index b26dc46..c9e68c5 100644
> --- a/gcc/config/i386/ia32intrin.h
> +++ b/gcc/config/i386/ia32intrin.h
> @@ -238,6 +238,34 @@ __rorq (unsigned long long __X, int __C)
>    return (__X >> __C) | (__X << (64 - __C));
>  }
>
> +/* Read flags register */
> +extern __inline unsigned long long
> +__attribute__((__gnu_inline__, __always_inline__, __artificial__))
> +__readeflags (void)
> +{
> +  unsigned long long result = 0;
> +  __asm__ __volatile__ ("pushf\n\t"
> +                       "popq %0\n"
> +                       :"=r"(result)
> +                       :
> +                       :
> +                       );
> +  return result;
> +}
> +
> +/* Write flags register */
> +extern __inline void
> +__attribute__((__gnu_inline__, __always_inline__, __artificial__))
> +__writeeflags (unsigned long long X)
> +{
> +  __asm__ __volatile__ ("pushq %0\n\t"
> +                       "popf\n"
> +                       :
> +                       :"r"(X)
> +                       :"flags"
> +                       );
> +}
> +

Oh, no. We don't want assembly in this century ;)

The proper implementation is to introduce a
__builtin_readflags/__builtin_writeflags that expand the sequence by
calling gen_push and gen_pop functions.

You will need new patterns for pushfl and popfl, something like:

(define_insn "*pushfl<mode>"
  [(set (match_operand:DWIH 0 "push_operand" "=<")
    (match_operand:DWIH 0 "flags_reg_operand"))]
  ""
  "pushf{<mode>}"
  [(set_attr "type" "push")
   (set_attr "mode" "<MODE>")])

(define_insn "*popfl<mode>1"
  [(set (match_operand:DWIH 0 "flags_reg_operand")
    (match_operand:DWIH 1 "pop_operand" ">"))]
  ""
  "popf{<imodesuffix>}\t%0"
  [(set_attr "type" "pop")
   (set_attr "mode" "<MODE>")])

Uros.

Patch

diff --git a/gcc/config/i386/ia32intrin.h b/gcc/config/i386/ia32intrin.h
index b26dc46..c9e68c5 100644
--- a/gcc/config/i386/ia32intrin.h
+++ b/gcc/config/i386/ia32intrin.h
@@ -238,6 +238,34 @@  __rorq (unsigned long long __X, int __C)
   return (__X >> __C) | (__X << (64 - __C));
 }
 
+/* Read flags register */
+extern __inline unsigned long long
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__readeflags (void)
+{
+  unsigned long long result = 0;
+  __asm__ __volatile__ ("pushf\n\t"
+			"popq %0\n"
+			:"=r"(result)
+			:
+			:
+			);
+  return result;
+}
+
+/* Write flags register */
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__writeeflags (unsigned long long X)
+{
+  __asm__ __volatile__ ("pushq %0\n\t"
+			"popf\n"
+			:
+			:"r"(X)
+			:"flags"
+			);
+}
+
 #define _bswap64(a)		__bswapq(a)
 #define _popcnt64(a)		__popcntq(a)
 #define _lrotl(a,b)		__rolq((a), (b))
@@ -245,6 +273,35 @@  __rorq (unsigned long long __X, int __C)
 #else
 #define _lrotl(a,b)		__rold((a), (b))
 #define _lrotr(a,b)		__rord((a), (b))
+
+/* Read flags register */
+extern __inline unsigned int
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__readeflags (void)
+{
+  unsigned int result = 0;
+  __asm__ __volatile__ ("pushf\n\t"
+			"popl %0\n"
+			:"=r"(result)
+			:
+			:
+			);
+  return result;
+}
+
+/* Write flags register */
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__writeeflags (unsigned int X)
+{
+  __asm__ __volatile__ ("pushl %0\n\t"
+			"popf\n"
+			:
+			:"r"(X)
+			:"flags"
+			);
+}
+
 #endif
 
 #define _bit_scan_forward(a)	__bsfd(a)
diff --git a/gcc/testsuite/gcc.target/i386/readeflags-1.c b/gcc/testsuite/gcc.target/i386/readeflags-1.c
new file mode 100644
index 0000000..6b2fa7e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/readeflags-1.c
@@ -0,0 +1,40 @@ 
+/* { dg-do run } */
+/* { dg-options "-O0" } */
+
+#include <x86intrin.h>
+
+#ifdef __x86_64__
+#define EFLAGS_TYPE unsigned long long int
+#else
+#define EFLAGS_TYPE unsigned int
+#endif
+
+static EFLAGS_TYPE
+readeflags_test (unsigned int a, unsigned int b)
+{
+  unsigned x = (a == b);
+  return __readeflags ();
+}
+
+int
+main ()
+{
+  EFLAGS_TYPE flags;
+
+  flags = readeflags_test (100, 100);
+
+  if ((flags & 1) != 0)  /* Read CF */
+    abort ();
+
+  flags = readeflags_test (100, 101);
+
+  if ((flags & 1) == 0)  /* Read CF */
+    abort ();
+
+#ifdef DEBUG
+    printf ("PASSED\n");
+#endif
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/i386/writeeflags-1.c b/gcc/testsuite/gcc.target/i386/writeeflags-1.c
new file mode 100644
index 0000000..446840c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/writeeflags-1.c
@@ -0,0 +1,30 @@ 
+/* { dg-do run } */
+/* { dg-options "-O0" } */
+
+#include <x86intrin.h>
+
+#ifdef __x86_64__
+#define EFLAGS_TYPE unsigned long long int
+#else
+#define EFLAGS_TYPE unsigned int
+#endif
+
+int
+main ()
+{
+  EFLAGS_TYPE flags = 0xD7; /* 111010111b  */
+
+  __writeeflags (flags);
+
+  flags = __readeflags ();
+
+  if ((flags & 0xFF) != 0xD7)
+    abort ();
+
+#ifdef DEBUG
+    printf ("PASSED\n");
+#endif
+
+  return 0;
+}
+