Patchwork int128: optimize

login
register
mail settings
Submitter Paolo Bonzini
Date June 20, 2013, 3 p.m.
Message ID <1371740457-27445-1-git-send-email-pbonzini@redhat.com>
Download mbox | patch
Permalink /patch/252992/
State New
Headers show

Comments

Paolo Bonzini - June 20, 2013, 3 p.m.
For add and sub, carry computation only requires checking one of the
arguments (any for add, the LHS for sub because the RHS is negated).
For neg, we can similarly optimize computation of the carry.

For ge, we can just do lexicographic order.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
	Will post unit tests soon.

 include/qemu/int128.h | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)
Richard Henderson - June 20, 2013, 4:46 p.m.
On 06/20/2013 08:00 AM, Paolo Bonzini wrote:
>  static inline Int128 int128_sub(Int128 a, Int128 b)
>  {
> -    return int128_add(a, int128_neg(b));
> +    uint64_t lo = a.lo - b.lo;
> +    return (Int128) { lo, (lo < a.lo) + a.hi - b.hi };

This one isn't right.  Consider { 2, 0 } - { 2, 0 }

  lo = 2 - 2 = 0;
  = { 0, (0 < 2) + 0 - 0 }
  = { 0, 1 }

I'd be happier with a more traditional

  (Int128){ a.lo - b.lo, a.hi - b.hi - (a.lo < b.lo) };


r~
Paolo Bonzini - June 20, 2013, 9:20 p.m.
Il 20/06/2013 18:46, Richard Henderson ha scritto:
> On 06/20/2013 08:00 AM, Paolo Bonzini wrote:
>>  static inline Int128 int128_sub(Int128 a, Int128 b)
>>  {
>> -    return int128_add(a, int128_neg(b));
>> +    uint64_t lo = a.lo - b.lo;
>> +    return (Int128) { lo, (lo < a.lo) + a.hi - b.hi };
> 
> This one isn't right.  Consider { 2, 0 } - { 2, 0 }
> 
>   lo = 2 - 2 = 0;
>   = { 0, (0 < 2) + 0 - 0 }
>   = { 0, 1 }
> 
> I'd be happier with a more traditional
> 
>   (Int128){ a.lo - b.lo, a.hi - b.hi - (a.lo < b.lo) };

Yeah, I wasn't quite sure of this and I was waiting for testcases to
prove me wrong...  To fix it in the style I used you need

   (Int128){ lo, a.hi - b.hi - (lo > a.lo) }

(We have to sum a + ~b + 1.  We have lo = a.lo + ~b.lo + 1, from which
the carry-out is either lo <= a.lo or lo <= ~b.lo, using <= because of
the carry-in.  Then the high part is

       a.hi + ~b.hi       + (lo <= a.lo)
     = a.hi + (-1 - b.hi) + 1 - (lo > a.lo)
     = a.hi - b.hi        - (lo > a.lo)

).  But I'll go with your version, it probably generates better code
too.

Paolo

Patch

diff --git a/include/qemu/int128.h b/include/qemu/int128.h
index bfe7678..d36cc7a 100644
--- a/include/qemu/int128.h
+++ b/include/qemu/int128.h
@@ -55,21 +55,20 @@  static inline Int128 int128_rshift(Int128 a, int n)
 
 static inline Int128 int128_add(Int128 a, Int128 b)
 {
-    Int128 r = { a.lo + b.lo, a.hi + b.hi };
-    r.hi += (r.lo < a.lo) || (r.lo < b.lo);
-    return r;
+    uint64_t lo = a.lo + b.lo;
+    return (Int128) { lo, (lo < a.lo) + a.hi + b.hi };
 }
 
 static inline Int128 int128_neg(Int128 a)
 {
-    a.lo = ~a.lo;
-    a.hi = ~a.hi;
-    return int128_add(a, int128_one());
+    uint64_t lo = -a.lo;
+    return (Int128) { lo, ~a.hi + !lo };
 }
 
 static inline Int128 int128_sub(Int128 a, Int128 b)
 {
-    return int128_add(a, int128_neg(b));
+    uint64_t lo = a.lo - b.lo;
+    return (Int128) { lo, (lo < a.lo) + a.hi - b.hi };
 }
 
 static inline bool int128_nonneg(Int128 a)
@@ -89,7 +88,7 @@  static inline bool int128_ne(Int128 a, Int128 b)
 
 static inline bool int128_ge(Int128 a, Int128 b)
 {
-    return int128_nonneg(int128_sub(a, b));
+    return a.hi > b.hi || (a.hi == b.hi && a.lo >= b.lo);
 }
 
 static inline bool int128_lt(Int128 a, Int128 b)