guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

guile 3 update: better reasoning about fixnums


From: Andy Wingo
Subject: guile 3 update: better reasoning about fixnums
Date: Mon, 13 Nov 2017 15:54:23 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.3 (gnu/linux)

Hi,

An update on Guile 3 hackings over the past couple weeks.

Firstly I made a change to the CPS language.  Before, "primcalls" --
invocations of primitives known to the compiler, some of which
ultimately compile to instructions/bytecode -- took all arguments as CPS
values.  This was even the case for primcalls that took known constant
arguments, for example a primcall that does a vector-ref of a known
index.  I made a change so that all primcalls now have an additional
slot, which is for some constant data associated with the primcall.  (If
you need two pieces of constant data, just cons up a data structure.)

The idea is that constants used by primcalls as immediates don't need to
participate in optimizations in any way -- they should not participate
in CSE, have the same lifetime as the primcall so not part of DCE
either, and don't need slot allocation.  Indirecting them through a
named $const binding is complication for no benefit.  This change should
improve compilation time and memory usage, as the number of labels and
variables goes down.  I didn't measure much though.

I built on that to add set of "throw" primcalls to which all throws and
errors compile, with corresponding VM support.  This reduces the code
size for error branches in functions that do a lot of type checking
using e.g. srfi-9 accessors; for example in Guile 2.2, an internal
procedure in the assembler (encode-X8_S8_S8_S8) compiles to 158 32-bit
words, whereas in 3.0 it is currently 126 words, even after a bit of
instruction explosion, and indeed it's a precondition for facilitating
more instruction explosion.

I also changed the compilation of "ash" to compile to "lsh", "rsh", or a
branch between the two.  This simplifies things later in the compiler.

There are new "tag-fixnum" and "untag-fixnum" instructions, that convert
between uint64_t and SCM values without branches.  Many instances of
scm->u64 etc now compile to these instead.  Some unboxed operations and
comparisons now operate in the signed range, as it's more convenient to
check for fixnums using the fixnum? primcall (which compiles to an
instance of the immediate-tag=? instruction) than it is to e.g. check
ranges of generic integers, and there is now better support throughout
the compiler for s64 values.

I removed the <=, >=, and > comparison operators; they can all be
expressed in terms of <, though looking back on this now I see that I
messed up the behavior with NaN and <= or >=.  Damn.  Will fix.

I added some signed right shift instructions, to do sign-extending right
shifts over unboxed values; and that's about it.  In summary, a lot of
internal plumbing, for what appears to be preparatory work for future
stuff.

My to-do list in the near term has a few more plumbing-type tasks:

 * Remove u64=?, as we can just use s64=? polymorphism

 * Add s64-imm=?, imm-u64<?, u64-imm<?, imm-s64<?, s64-imm<?
   instructions for unboxed comparisons with immediates

 * Fix ursh, srsh, ulsh to take only params < 64; their result should be
   0 otherwise

 * Improve the compilation of (= x (logand x #xff)) to hoist fixnum?
   check

 * Perhaps add some more /imm instructions for e.g. ulogand, based the
   compilation of encode-X8_S8_S8_S8

 * Fix <= and >= with NaN values

 * Continue with instruction explosion, starting with vector-ref

Cheers,

Andy



reply via email to

[Prev in Thread] Current Thread [Next in Thread]