TODO for 5.2 v3

Marc Glisse marc.glisse at inria.fr
Wed Jan 15 21:02:11 UTC 2014


On Wed, 15 Jan 2014, Niels Möller wrote:

> Torbjorn Granlund <tg at gmplib.org> writes:
>
>> The volatile qualifier makes sure the number of memory reads and memory
>> writes remain unchanged from the source code.
>
> Question is, when is it useful for our purposes? First example,
> mpn_sec_add_1:
>
>  mp_limb_t
>  mpn_sec_add_1 (mp_limb_t *rp, mp_limb_t *ap, mp_size_t n, mp_limb_t b,
>  	         mp_ptr scratch)
>  {
>    scratch[0] = b;
>    MPN_ZERO (scratch + 1, n-1);
>    return mpn_add_n (rp, ap, scratch, n);
>  }
>
> volatile probably makes no difference here, as far as I see (except
> possibly if there's some global optimization which inlines mpn_add_n).
> But maybe we should still declare some or all of the parameters (rp, ap,
> scratch) as pointing to volatile data?

I doubt that it would help, but I could be wrong.

> Or would that give type conversion warnings when calling mpn_add_n, with
> parameters which aren't volatile-declared? I'm not entirely sure what
> volatile means, if it's only giving the compiler some constraints for
> the *implementation* of a function, or if volatile in a function
> *prototype* also affects type checking or code generation in callers in
> some way.

>From a type POV, volatile works like 'const', you can't strip it away.

> Second example,
>
>  void
>  mpn_cnd_swap (mp_limb_t cnd,
>  	        mp_limb_t *ap, mp_limb_t *bp, mp_size_t n)
>  {
>    mp_limb_t mask = - (mp_limb_t) (cnd != 0);
>    mp_size_t i;
>    for (i = 0; i < n; i++)
>      {
>        mp_limb_t a, b, t;
>        a = ap[i];
>        b = bp[i];
>        t = (a ^ b) & mask;
>        ap[i] = a ^ t;
>        bp[i] = b ^ t;
>      }
>  }
>
> Here a compiler might be tempted to do an initial branch on cnd != 0,
> and skip the loop if cnd is false. Using volatile for ap and bp gives it
> less reason to do so, but I guess even with volatile it may still
> generate code equivalent to
>
>  if (cnd)
>    for (i = 0; i < n; i++)
>      {
>        mp_limb_t a, b, t;
>        a = ap[i];
>        b = bp[i];
>        ap[i] = b;
>        bp[i] = a;
>      }
>  else
>    for (i = 0; i < n; i++)
>      {
>        mp_limb_t a, b, t;
>        a = ap[i];
>        b = bp[i];
>        ap[i] = a;
>        bp[i] = b;
>      }
>
> which leaks through the cache.
>
> So is it useful or not to volatile-declare ap and bp here?

volatile mp_limb_t b = cnd != 0;
mp_limb_t mask = -b;

The compiler is still allowed to do b=cnd?1:0 with a branch, but the 
volatile blocks any kind of constant propagation, the compiler can't 
assume that the value it reads from b is in any way related to what it 
just wrote there.

Note that even if mask doesn't come from a condition, the compiler is 
allowed to test if mask is 0 or -1 and generate special code for those 
cases, so you can't escape either writing asm or compiling with 
not-too-extreme optimizations with your fingers crossed.

-- 
Marc Glisse


More information about the gmp-devel mailing list