From 6af385b22805cc2e8cee5c0a5f3506361afbe961 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Magnus=20L=C3=A5ng?= <margnus1@telia.com>
Date: Fri, 23 Oct 2015 15:27:22 +0200
Subject: Fix hipe_rtl_binary_construct:floorlog2/1

Relying on double-precision floating-point arithmetic to compute the
log2 of an integer up to 64 bits long leads to rounding errors.
---
 lib/hipe/rtl/hipe_rtl_binary_construct.erl | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

(limited to 'lib')

diff --git a/lib/hipe/rtl/hipe_rtl_binary_construct.erl b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
index 692bad7d96..d01625b4f9 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_construct.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
@@ -1330,7 +1330,19 @@ number2list(X, Acc) ->
   number2list(X-(1 bsl F), [F|Acc]).
 
 floorlog2(X) ->
-  round(math:log(X)/math:log(2)-0.5). 
+  %% Double-precision floats do not have enough precision to make floorlog2
+  %% exact for integers larger than 2^47.
+  Approx = round(math:log(X)/math:log(2)-0.5),
+  floorlog2_refine(X, Approx).
+
+floorlog2_refine(X, Approx) ->
+  if (1 bsl Approx) > X ->
+      floorlog2_refine(X, Approx - 1);
+     (1 bsl (Approx+1)) > X ->
+      Approx;
+     true ->
+      floorlog2_refine(X, Approx + 1)
+  end.
 
 set_high(X) ->
   set_high(X, 0).
-- 
cgit v1.2.3