guile-devel
[Top][All Lists]
Advanced

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

prolog code in guile


From: Stefan Israelsson Tampe
Subject: prolog code in guile
Date: Wed, 14 Nov 2018 00:06:41 +0100

This is a feature request.

Hi all, I am studying the compiling of clpfd finite domain solver from swi prolog. Currently it 
compiles in 10 minutes giving a 14MB large go file. The same code compiles in 1 second in swi. Which means that we do something wring in guile-log. The scanning and parsing of the file takes 30s so the macro expansion and compilation is a huge issue fro me atm. In my experience every lambda you can get rid of in scheme is a net win in compilation time. And previous experience has been that it is worthwhile to make closure making functions and call them than directly insert the lambda to avoid inconvinient compilation times (Actually I tend to make it configurable to do this, the compiller can do marvelss with the closures). Anyway I do not want to remove the optimizer because it does a heck of a work simplifying the prolog code.

So I am tinkering with what is needed to compile prolog code and it turns out that prolog has different needs than scheme. For one thing scheme prolog code compiles to way more lambdas than is needed. And a lot of speed is lost due to this. Also the variables space is somwehat stationary in the predicate while the code path leaves and enters the predicates in multiple ways.

To illustrate see this in action we can have a predicate f(X,Y):- X==1 -> f(),Y==1 ; Y==X.
This currently translates to either a lot of lambdas that is not needed or explodes in the number
lines of expanded lambdas what we would like to do is (vec is a closure var)
(define (f : vec self label)
    (if  label (goto label))
    (tagbody
         (newframe vec.fr)
         (if (== vec.s vec.x 1)
             (let ((p2 (make-p self tag)))
                 (tail-call f vec.s p2 vec.cc))
         tag:
         (unwind vec.fr)
         (if (== vec.s vec.x vec.y)
             (vec.cc vec.s vec.p)
             (vec.p))))

make-p(self tag)
    (let ((closure  (copy self)))
      closure.self   = closure
      closure.vec   = self.vec.
      closure.label =  tag

So the make-p copies the self function without the closure, and adds a link to itself, a continue address. similarly cc closures can be made.

Everything can be kept into guile assembler appart from the ability to store an address and goto to an adress stored in a variable.

Also I need to modify guile slightly for enabling a separate assembler or a manual assebler to come in naturally in the compileation. I made a struct that if it's compiled to a constant as using #`#,struct, we could make sure to typecheck it in types.scm. At compile cps it is checked and a label is added to it. Then in compile-bytecode.scm one can test for it and generate the custom assembler ans also load it as a static procedure in places. Not sure if this is the best way to do this, but sure it was not much work. I use it as
(define f (wrapper custom-assembler)) 

Doing this is good enough and it compiles the assembler into the go file.

So my current request for guile is
1. enable support for writing custom assembler
2. named gotos, getting the address of it relative the procedure start and goto the stored
address relative the function start.

Having named gotos and a tagbody construct would also serve guile well, that would help
writing a vm in guile in a more efficient way. Currently it's a vector of closures that is
the tool of use.

I will continue experimenting.

Regards
Stefan








 
 
  

reply via email to

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