Message ID | 20131204165948.GA21551@msticlxl57.ims.intel.com |
---|---|
State | New |
Headers | show |
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
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.
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.
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; +} +