diff mbox

PATCH: PR target/53416: Wrong code when optimising loop involving _rdrand32_step

Message ID 20120520170426.GA7774@intel.com
State New
Headers show

Commit Message

H.J. Lu May 20, 2012, 5:04 p.m. UTC
Hi,

rdrand<mode>_1 must be marked with unspec_volatile since it returns
a different value every time.  OK for trunk, 4.7 and 4.6?

Thanks.

H.J.
----
	PR target/53416
	* config/i386/i386.md (UNSPEC_RDRAND): Renamed to ...
	(UNSPECV_RDRAND): This.
	(rdrand<mode>_1): Updated.

Comments

Jakub Jelinek May 20, 2012, 5:19 p.m. UTC | #1
On Sun, May 20, 2012 at 10:04:26AM -0700, H.J. Lu wrote:
> rdrand<mode>_1 must be marked with unspec_volatile since it returns
> a different value every time.  OK for trunk, 4.7 and 4.6?

A testcase for this would be nice (runtime is not possible, since the
RNG in theory could return the same value twice, but scanning assembly
for a particular number of the rdrand insns would be nice).

> 	PR target/53416
> 	* config/i386/i386.md (UNSPEC_RDRAND): Renamed to ...
> 	(UNSPECV_RDRAND): This.
> 	(rdrand<mode>_1): Updated.

	Jakub
H.J. Lu May 20, 2012, 5:37 p.m. UTC | #2
On Sun, May 20, 2012 at 10:19 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Sun, May 20, 2012 at 10:04:26AM -0700, H.J. Lu wrote:
>> rdrand<mode>_1 must be marked with unspec_volatile since it returns
>> a different value every time.  OK for trunk, 4.7 and 4.6?
>
> A testcase for this would be nice (runtime is not possible, since the
> RNG in theory could return the same value twice, but scanning assembly
> for a particular number of the rdrand insns would be nice).
>

For

 unsigned int number = 0;
 volatile int result = 0;

 for (register int i = 0; i < 4; ++i) {
  result = _rdrand32_step(&number);
  printf("%d: %d\n", result, number);
 }

the issue isn't about number of rdrand insns.  As long as
it isn't hoisted out of the loop, one rdrand insn is OK.
I don't know how to scan for inside or outside of loop.
Jakub Jelinek May 20, 2012, 6:15 p.m. UTC | #3
On Sun, May 20, 2012 at 10:37:13AM -0700, H.J. Lu wrote:
> On Sun, May 20, 2012 at 10:19 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> > On Sun, May 20, 2012 at 10:04:26AM -0700, H.J. Lu wrote:
> >> rdrand<mode>_1 must be marked with unspec_volatile since it returns
> >> a different value every time.  OK for trunk, 4.7 and 4.6?
> >
> > A testcase for this would be nice (runtime is not possible, since the
> > RNG in theory could return the same value twice, but scanning assembly
> > for a particular number of the rdrand insns would be nice).
> >
> 
> For
> 
>  unsigned int number = 0;
>  volatile int result = 0;
> 
>  for (register int i = 0; i < 4; ++i) {
>   result = _rdrand32_step(&number);
>   printf("%d: %d\n", result, number);
>  }

Try it without the loop, unroll it by hand, see if without the patch
the rdrand insns are still CSEd together?

	Jakub
H.J. Lu May 20, 2012, 6:37 p.m. UTC | #4
On Sun, May 20, 2012 at 11:15 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Sun, May 20, 2012 at 10:37:13AM -0700, H.J. Lu wrote:
>> On Sun, May 20, 2012 at 10:19 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>> > On Sun, May 20, 2012 at 10:04:26AM -0700, H.J. Lu wrote:
>> >> rdrand<mode>_1 must be marked with unspec_volatile since it returns
>> >> a different value every time.  OK for trunk, 4.7 and 4.6?
>> >
>> > A testcase for this would be nice (runtime is not possible, since the
>> > RNG in theory could return the same value twice, but scanning assembly
>> > for a particular number of the rdrand insns would be nice).
>> >
>>
>> For
>>
>>  unsigned int number = 0;
>>  volatile int result = 0;
>>
>>  for (register int i = 0; i < 4; ++i) {
>>   result = _rdrand32_step(&number);
>>   printf("%d: %d\n", result, number);
>>  }
>
> Try it without the loop, unroll it by hand, see if without the patch
> the rdrand insns are still CSEd together?
>

It doesn't:

[hjl@gnu-ivb-1 tmp]$ cat x.c
#include <stdio.h>

int
main(int argc, char **argv)
{
 unsigned int number = 0;
 volatile int result = 0;

  result = __builtin_ia32_rdrand32_step (&number);
  printf("%d: %d\n", result, number);
  result = __builtin_ia32_rdrand32_step (&number);
  printf("%d: %d\n", result, number);
  result = __builtin_ia32_rdrand32_step (&number);
  printf("%d: %d\n", result, number);
  result = __builtin_ia32_rdrand32_step (&number);
  printf("%d: %d\n", result, number);
 return 0;
}
[hjl@gnu-ivb-1 tmp]$
/export/gnu/import/git/gcc-regression/master/187369/usr/bin/gcc
-mrdrnd -O3 -S x.c
[hjl@gnu-ivb-1 tmp]$ grep rdrand x.s
	rdrand	%ebx
	rdrand	%eax
	rdrand	%eax
	rdrand	%eax
[hjl@gnu-ivb-1 tmp]$
Andrew Pinski May 20, 2012, 6:43 p.m. UTC | #5
On Sun, May 20, 2012 at 11:37 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Sun, May 20, 2012 at 11:15 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>> On Sun, May 20, 2012 at 10:37:13AM -0700, H.J. Lu wrote:
>>> On Sun, May 20, 2012 at 10:19 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>>> > On Sun, May 20, 2012 at 10:04:26AM -0700, H.J. Lu wrote:
>>> >> rdrand<mode>_1 must be marked with unspec_volatile since it returns
>>> >> a different value every time.  OK for trunk, 4.7 and 4.6?
>>> >
>>> > A testcase for this would be nice (runtime is not possible, since the
>>> > RNG in theory could return the same value twice, but scanning assembly
>>> > for a particular number of the rdrand insns would be nice).
>>> >
>>>
>>> For
>>>
>>>  unsigned int number = 0;
>>>  volatile int result = 0;
>>>
>>>  for (register int i = 0; i < 4; ++i) {
>>>   result = _rdrand32_step(&number);
>>>   printf("%d: %d\n", result, number);
>>>  }
>>
>> Try it without the loop, unroll it by hand, see if without the patch
>> the rdrand insns are still CSEd together?
>>
>
> It doesn't:
>
> [hjl@gnu-ivb-1 tmp]$ cat x.c
> #include <stdio.h>
>
> int
> main(int argc, char **argv)
> {
>  unsigned int number = 0;
>  volatile int result = 0;
>
>  result = __builtin_ia32_rdrand32_step (&number);
>  printf("%d: %d\n", result, number);
>  result = __builtin_ia32_rdrand32_step (&number);
>  printf("%d: %d\n", result, number);
>  result = __builtin_ia32_rdrand32_step (&number);
>  printf("%d: %d\n", result, number);
>  result = __builtin_ia32_rdrand32_step (&number);
>  printf("%d: %d\n", result, number);
>  return 0;
> }
> [hjl@gnu-ivb-1 tmp]$
> /export/gnu/import/git/gcc-regression/master/187369/usr/bin/gcc
> -mrdrnd -O3 -S x.c
> [hjl@gnu-ivb-1 tmp]$ grep rdrand x.s
>        rdrand  %ebx
>        rdrand  %eax
>        rdrand  %eax
>        rdrand  %eax
> [hjl@gnu-ivb-1 tmp]$

Try:
#include <stdio.h>

 int
 main(int argc, char **argv)
 {
  unsigned int number = 0;
  int result0, result1, result2, result3;

  result0 = __builtin_ia32_rdrand32_step (&number);
  result1 = __builtin_ia32_rdrand32_step (&number);
  result2 = __builtin_ia32_rdrand32_step (&number);
  result3 = __builtin_ia32_rdrand32_step (&number);
  printf("%d: %d\n", result0, number);
  printf("%d: %d\n", result1, number);
  printf("%d: %d\n", result2, number);
  printf("%d: %d\n", result3, number);
  return 0;
 }

Which I Know for a fact fails before the patch:
pinskia@server:~$ grep rdrand t.s
	rdrand	%edx
pinskia@server:~$

Thanks,
Andrew Pinski

>
>
> --
> H.J.
Uros Bizjak May 20, 2012, 7:03 p.m. UTC | #6
On Sun, May 20, 2012 at 8:43 PM, Andrew Pinski <pinskia@gmail.com> wrote:

> #include <stdio.h>
>
>  int
>  main(int argc, char **argv)
>  {
>  unsigned int number = 0;
>  int result0, result1, result2, result3;
>
>  result0 = __builtin_ia32_rdrand32_step (&number);
>  result1 = __builtin_ia32_rdrand32_step (&number);
>  result2 = __builtin_ia32_rdrand32_step (&number);
>  result3 = __builtin_ia32_rdrand32_step (&number);
>  printf("%d: %d\n", result0, number);
>  printf("%d: %d\n", result1, number);
>  printf("%d: %d\n", result2, number);
>  printf("%d: %d\n", result3, number);
>  return 0;
>  }
>

int test (void)
{
  unsigned int number = 0;
  int result0, result1, result2, result3;

  result0 = __builtin_ia32_rdrand32_step (&number);
  result1 = __builtin_ia32_rdrand32_step (&number);
  result2 = __builtin_ia32_rdrand32_step (&number);
  result3 = __builtin_ia32_rdrand32_step (&number);

  return result0 + result1 +result2 + result3;;
}

This is the simplest, and also good test.

Uros.
diff mbox

Patch

diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index cce78b5..9327acf 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -176,9 +176,6 @@ 
   ;; For CRC32 support
   UNSPEC_CRC32
 
-  ;; For RDRAND support
-  UNSPEC_RDRAND
-
   ;; For BMI support
   UNSPEC_BEXTR
 
@@ -208,6 +205,9 @@ 
   UNSPECV_WRFSBASE
   UNSPECV_WRGSBASE
 
+  ;; For RDRAND support
+  UNSPECV_RDRAND
+
   ;; For RTM support
   UNSPECV_XBEGIN
   UNSPECV_XEND
@@ -18399,9 +18399,9 @@ 
 
 (define_insn "rdrand<mode>_1"
   [(set (match_operand:SWI248 0 "register_operand" "=r")
-	(unspec:SWI248 [(const_int 0)] UNSPEC_RDRAND))
+	(unspec_volatile:SWI248 [(const_int 0)] UNSPECV_RDRAND))
    (set (reg:CCC FLAGS_REG)
-	(unspec:CCC [(const_int 0)] UNSPEC_RDRAND))]
+	(unspec_volatile:CCC [(const_int 0)] UNSPECV_RDRAND))]
   "TARGET_RDRND"
   "rdrand\t%0"
   [(set_attr "type" "other")