bug#32644: bytevector bug

2018-10-14 Thread Mark H Weaver
Stefan Israelsson Tampe  writes:
> The code velow does not compile when the define-inlinable of id is active. If 
> in stead
> id defined by define is used it all compiles just fine.

The problem was that, in some cases, the type inferrer would call 'ash'
with (- 1 (expt 2 64)) as the second argument during compilation.  The
implementation of 'ash' would raise an exception unless its second
argument (the shift count) fits in a C 'long'.

This is fixed in commit 011aec7e240ef987931548d90c53e6692c85d01c on the
stable-2.2 branch.  That commit extends 'ash' and 'round-ash' to
gracefully handle several cases where the shift count is too large to
fit in a 'long'.

Thanks for the report.

  Mark





bug#21883: unnecessary bit shifting range limits

2018-10-14 Thread Mark H Weaver
Zefram  writes:

> Not really outright bugs, but these responses are less than awesome:
>
> $ guile -c '(write (logbit? (ash 1 100) 123))'
> ERROR: Value out of range 0 to 18446744073709551615: 
> 1267650600228229401496703205376
> $ guile -c '(write (ash 0 (ash 1 100)))'
> ERROR: Value out of range -9223372036854775808 to 9223372036854775807: 
> 1267650600228229401496703205376
> $ guile -c '(write (ash 123 (ash -1 100)))'
> ERROR: Value out of range -9223372036854775808 to 9223372036854775807: 
> -1267650600228229401496703205376
>
> In all three cases, the theoretically-correct result of the expression
> is not only representable but easily computed.

Commit 011aec7e240ef987931548d90c53e6692c85d01c on the stable-2.2 branch
extends 'ash' and 'round-ash' to handle the easily computed cases of
huge shifts.

> The functions could be improved to avoid failing in these cases, by
> adding logic amounting to:
>
> (define (better-logbit? b v)
>   (if (>= b (integer-length v)) (< v 0) (logbit? b v)))
>
> (define (better-ash v s)
>   (cond
> ((= v 0) 0)
> ((<= s (- (integer-length v))) (if (< v 0) -1 0))
> (else (ash v s

Unfortunately, simple implementations like the ones above slow down the
common case with expensive checks that are rarely needed.  The
aforementioned commit takes pains to avoid slowing down the common case,
but at the cost of extra code complexity.

In theory we could do something similar with many other procedures that
implement operations on bits and bit fields, but I wonder if it's worth
the extra complexity.

   Mark





bug#21901: bit shift wrong on maximal right shift

2018-10-14 Thread Mark H Weaver
Zefram  writes:

> With Guile 2.0.11:
>
> scheme@(guile-user)> (ash 123 (ash -1 63))
> $1 = 123
>
> Correct result would of course be zero.  Problem only occurs for
> exactly this shift distance: one bit less produces the right answer.

Nice catch!

It's finally fixed in commit 1990aa916382d0afcebd5315a6d6f555949ff654 on
the stable-2.2 branch.  The fix will be in Guile 2.2.5.

Thanks for the report.

  Mark





bug#21883: unnecessary bit shifting range limits

2018-10-14 Thread Stefan Israelsson Tampe
how would this slow down the code. just add the correction where you throw
the exception which should be in a branch outside the hot path.

Den 14 okt 2018 10:19 AM skrev "Mark H Weaver" :

Zefram  writes:

> Not really outright bugs, but these responses are less than awesome:
>
> $ guile -c '(write (logbit? (ash 1 100) 123))'
> ERROR: Value out of range 0 to 18446744073709551615:
1267650600228229401496703205376
> $ guile -c '(write (ash 0 (ash 1 100)))'
> ERROR: Value out of range -9223372036854775808 to 9223372036854775807:
1267650600228229401496703205376
> $ guile -c '(write (ash 123 (ash -1 100)))'
> ERROR: Value out of range -9223372036854775808 to 9223372036854775807: -
1267650600228229401496703205376
>
> In all three cases, the theoretically-correct result of the expression
> is not only representable but easily computed.

Commit 011aec7e240ef987931548d90c53e6692c85d01c on the stable-2.2 branch
extends 'ash' and 'round-ash' to handle the easily computed cases of
huge shifts.

> The functions could be improved to avoid failing in these cases, by
> adding logic amounting to:
>
> (define (better-logbit? b v)
>   (if (>= b (integer-length v)) (< v 0) (logbit? b v)))
>
> (define (better-ash v s)
>   (cond
> ((= v 0) 0)
> ((<= s (- (integer-length v))) (if (< v 0) -1 0))
> (else (ash v s

Unfortunately, simple implementations like the ones above slow down the
common case with expensive checks that are rarely needed.  The
aforementioned commit takes pains to avoid slowing down the common case,
but at the cost of extra code complexity.

In theory we could do something similar with many other procedures that
implement operations on bits and bit fields, but I wonder if it's worth
the extra complexity.

   Mark


bug#21883: unnecessary bit shifting range limits

2018-10-14 Thread Mark H Weaver
Stefan Israelsson Tampe  writes:
> how would this slow down the code. just add the correction where you
> throw the exception which should be in a branch outside the hot path.

If you have a suggestion that's simpler than what I did in commits
011aec7e, 9448a078, and 1990aa91, and just as fast in the common cases,
feel free to propose a patch.  The words above are insufficient.

  Mark





bug#32580: Setting variables %load-should-autocompile and GUILE_AUTO_COMPILE in ~/.guile doesn't prevent compiling

2018-10-14 Thread Maxim Cournoyer
Hello Seamus,

seamus phenetols  writes:

> Setting GUILE_AUTO_COMPILE in ~/.profile and in ~/.bash_profile
> doesn't seem to have any effect.  I'm giving up on guile for now.
> Thank you very much for helping.

I'm sorry it hasn't worked for you! Let's see if we can find out why.

What exactly did you put in your ~/.profile or ~/.bash_profile? What
version of Guile are you using? When launching a new pseudo terminal
(i.e. xterm, gnome-terminal, etc.) and typing 'echo
$GUILE_AUTO_COMPILE', does it return the expected value defined in your
~/.profile or ~/.bash_profile?

Note that you would need to logout then login of your session for new
variable definition to take effect; otherwise you can test it in your
current shell by sourcing it:

--8<---cut here---start->8---
source ~/.bash_profile # or source ~/.profile
--8<---cut here---start->8---

I've put the following Scheme code in a file named
'test-auto-compile.scm' (attached for your convenience):

--8<---cut here---start->8---
#!/usr/bin/env guile
!#

(define (main)
  "Print whether auto-compilation is enabled or not and exit with an
exit status of 1 if it is enabled, 0 otherwise."
  (let ((guile-auto-compile-value (getenv "GUILE_AUTO_COMPILE")))
(display (format #f "The value of GUILE_AUTO_COMPILE is ~s\n"
 guile-auto-compile-value))
(when (and guile-auto-compile-value
   (string=? guile-auto-compile-value "0"))
(display "Auto-compilation is disabled.\n")
(exit 0))
(display "Auto-compilation is enabled.\n")
(exit 1)))

(main)
--8<---cut here---start->8---

Here's a small demonstration of what the above script gives on my system
(guile --version is 2.2.4, but this should work for any Guile version >=
2.0):

--8<---cut here---start->8---
echo $GUILE_AUTO_COMPILE

maxim@apteryx ~/Documents$ guile test-auto-compile.scm
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;   or pass the --no-auto-compile argument to disable.
;;; compiling /home/maxim/Documents/test-auto-compile.scm
;;; compiled 
/home/maxim/.cache/guile/ccache/2.2-LE-8-3.A/home/maxim/Documents/test-auto-compile.scm.go
The value of GUILE_AUTO_COMPILE is #f
Auto-compilation is enabled.
maxim@apteryx ~/Documents$ 
maxim@apteryx ~/Documents$ rm 
/home/maxim/.cache/guile/ccache/2.2-LE-8-3.A/home/maxim/Documents/test-auto-compile.scm.go
maxim@apteryx ~/Documents$ export GUILE_AUTO_COMPILE=0
maxim@apteryx ~/Documents$ guile test-auto-compile.scm
The value of GUILE_AUTO_COMPILE is "0"
Auto-compilation is disabled.
--8<---cut here---end--->8---

I hope this helps,

Maxim

#!/usr/bin/env guile
!#

(define (main)
  "Print whether auto-compilation is enabled or not and exit with an
exit status of 1 if it is enabled, 0 otherwise."
  (let ((guile-auto-compile-value (getenv "GUILE_AUTO_COMPILE")))
(display (format #f "The value of GUILE_AUTO_COMPILE is ~s\n"
 guile-auto-compile-value))
(when (and guile-auto-compile-value
   (string=? guile-auto-compile-value "0"))
(display "Auto-compilation is disabled.\n")
(exit 0))
(display "Auto-compilation is enabled.\n")
(exit 1)))

(main)


bug#26058: utf16->string and utf32->string don't conform to R6RS

2018-10-14 Thread Mark H Weaver
Hi Taylan,

taylanbayi...@gmail.com (Taylan Ulrich "Bayırlı/Kammer") writes:

> Andy Wingo  writes:
>
>> Adopting the behavior is more or less fine.  If it can be done while
>> relying on the existing behavior, that is better than something ad-hoc
>> in a module.

In general, I agree with Andy's sentiment that it would be better to
avoid redundant BOM handling code, and moreover, I appreciate his
reluctance to apply a fix without careful consideration of our existing
BOM semantics.

However, as Taylan discovered, Guile does not provide a mechanism to
specify a default endianness of a UTF-16 or UTF-32 port in case a BOM is
not found.  I see no straightforward way to implement these R6RS
interfaces using ports.

We could certainly add such a mechanism if needed, but I see another
problem with this approach: the expense of creating and later collecting
a bytevector port object would be a very heavy burden to place on these
otherwise fairly lightweight operations.  Therefore, I would prefer to
avoid that implementation strategy for these operations.

Although BOM handling for ports is quite complex with many subtle points
to consider, detecting a BOM at the beginning of a bytevector is so
trivial that I personally have no objection to this tiny duplication of
logic.

Therefore, my preference would be to adopt code similar to that proposed
by Taylan, although I believe it can, and should, be further simplified:

> diff --git a/module/rnrs/bytevectors.scm b/module/rnrs/bytevectors.scm
> index 9744359f0..997a8c9cb 100644
> --- a/module/rnrs/bytevectors.scm
> +++ b/module/rnrs/bytevectors.scm
> @@ -69,7 +69,9 @@
> bytevector-ieee-double-native-set!
>  
> string->utf8 string->utf16 string->utf32
> -   utf8->string utf16->string utf32->string))
> +   utf8->string
> +   (r6rs-utf16->string . utf16->string)
> +   (r6rs-utf32->string . utf32->string)))
>  
>  
>  (load-extension (string-append "libguile-" (effective-version))
> @@ -80,4 +82,52 @@
>`(quote ,sym)
>(error "unsupported endianness" sym)))
>  
> +(define (read-bom16 bv)
> +  (let ((c0 (bytevector-u8-ref bv 0))
> +(c1 (bytevector-u8-ref bv 1)))
> +(cond
> + ((and (= c0 #xFE) (= c1 #xFF))
> +  'big)
> + ((and (= c0 #xFF) (= c1 #xFE))
> +  'little)
> + (else
> +  #f

We should gracefully handle the case of an empty bytevector, returning
an empty string without error in that case.

Also, we should use a single 'bytevector-u16-ref' operation to check for
the BOM.  Pick an arbitrary endianness for the operation (big-endian?),
and compare the resulting integer with both #xFEFF and #xFFFE.  That
way, the code will be simpler and more efficient.  Note that our VM has
dedicated instructions for these multi-byte bytevector accessors, and
there will be fewer comparison operations as well.  Similarly for the
utf32 case.

What do you think?

> +(define r6rs-utf16->string
> +  (case-lambda
> +((bv default-endianness)
> + (let ((bom-endianness (read-bom16 bv)))
> +   (if (not bom-endianness)
> +   (utf16->string bv default-endianness)
> +   (substring/shared (utf16->string bv bom-endianness) 1

Better to use plain 'substring' here, I think.  The machinery of shared
substrings is more expensive, and unnecessary in this case.

Otherwise, it looks good to me.  Would you like to propose a revised
patch?

Andy, what do you think?

   Mark