guile-devel
[Top][All Lists]
Advanced

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

Re: expression


From: Ken Raeburn
Subject: Re: expression
Date: Thu, 24 Jun 2010 02:55:59 -0400

On Jun 23, 2010, at 17:09, Michael Lucy wrote:
> Is there any scheme expression that will just get ignored when the
> scheme code is compiled?
> 
> I'm generating some code with a function like:
> 
> (define (gen-update-ab updatea updateb)
>  `(begin
>     ,(if updatea `(set! a (+ a 1)) `(donothing))
>     ,(if updateb `(set! b (+ b 1)) `(donothing))))
> 
> And ideally I could replace the donothing function with something that
> will get discarded during compilation.

A simple constant like #f or '() or 42 shouldn't cause any evaluation to 
happen, unless it's the last expression and thus the value to be returned (in 
which case you'd just be returning a simple constant).

I don't know if there's a canonical efficient way to generate it, but it looks 
like "(if #f #f)" will be optimized by the current compiler into just pushing 
the magic "undefined value" onto the stack.  Getting rid of the push altogether 
*IF* the result of the expression is unused is up to the optimizer; you 
shouldn't be jumping through hoops in the code you generate to make that 
happen.  But it appears that it does happen at least in simple cases:

scheme@(guile-user)> ,c (begin (if #f #f) (if #f #f) 42)
Disassembly of #<objcode 101678308>:

   0    (assert-nargs-ee/locals 0)      
   2    (make-int8 42)                  ;; 42
   4    (return)                        

Hmm... here's another way, though I've no idea if RnRS lets you not have any 
expressions in here:

scheme@(guile-user)> ,c (begin)                            
Disassembly of #<objcode 10163f848>:

   0    (assert-nargs-ee/locals 0)      
   2    (void)                          
   3    (return)              

scheme@(guile-user)> ,c (begin (begin) (begin) 42)
Disassembly of #<objcode 1016782a8>:

   0    (assert-nargs-ee/locals 0)      
   2    (make-int8 42)                  ;; 42
   4    (return)                        


> There are alternatives, but they're pretty ugly (significantly moreso
> in my actual code than they look below):

Depends how you define ugliness. :-)

Your approach expands each possible update into one S-expression.  So you need 
*something* there for each one, even if it's just a constant, or an empty 
"begin".

The alternative, I think, is rearranging your code so that no expression gets 
added to the list when there's nothing to do; one way to do that, off the top 
of my head, would be to generate a possibly-empty list of expressions rather 
than exactly one for each possible update, and then merge the lists together.  
Or start with an empty list, and tack S-expressions on the front for updates 
that are needed, then add the "begin" and return the result.

But in terms of the generated byte code, the constants should just go away if 
they're not actually used, and nested "begin" lists should get flattened, so I 
don't think it should matter much either way.

If you want the macro expansion to be human-readable for debugging purposes, 
you could also consider putting in some kind of no-op annotation that shouldn't 
generate code, for example a let loop with a meaningful label name and no 
useful body, or wrapping code that actually has effects but doesn't use the 
label:

scheme@(guile-user)> ,c (begin (let no-update-needed-for-a () #f) 42)
Disassembly of #<objcode 1030dc468>:

   0    (assert-nargs-ee/locals 0)      
   2    (br :L171)                      ;; -> 10
   6    (br :L172)                      ;; -> 14
  10    (br :L173)                      ;; -> 6
  14    (make-int8 42)                  ;; 42
  16    (return)                        

Ehh... okay, maybe there's a little work to be done for that one. :-)

Ken


reply via email to

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