Pliant talk forum

Pliant talk forum

Discussion: Compiler internals

Questions I have about Pliant compiler internals.
Message posted by maybe Michael FIG on 2006/04/27 04:49:00
Why does the following code produce "Failed to compile tgt"?

In my investigation, I found that every subexpression of e in the host meta
was already bound to the current module, so that's probably why the substitute failed.
Why is this so?  In my former experience with Pliant, the subexpressions
didn't get bound and you had to use "near" often.

Thanks,
Michael.

module "/pliant/language/compiler.pli"

public

# Evaluate a body in the compiler's host with the target module as an
# argument.  This allows cross-compiled modules to explicitly
# manipulate the target module.
meta host e
 if e:size <> 2
  return
 var Str targetIdent := e:0 ident
 if targetIdent = ""
  return
 var Link:Expression body :> e:1 substitute targetIdent (expression constant "test")
 body execute
 e set_void_result

host tgt
 console "tgt: " tgt eol
console "back in the program" eol

Message posted by hubert.tonneau on 2006/04/27 08:53:49
All this is implemented in /pliant/language/compiler/expression/expression2.pli

Let's assume that your program manipulates an expression 'e'
through:
e substitute "v1" f1
e substitute "v2" f2
where of course, 'f1' and 'f2' are expressions that you previously computed.

Now, what appends if 'f1' is a complex tree that contains a node with an
indentifier named ... "f2"

With no care, it would be substituted with 'f2' and it would probably be an
unwanted side effect.

So, the binding rule is just protecting agains that:
1. any node of an expression that is an identifier designed to mark a position
   for later be substituted with another expression must not be bounded to a
   module
2. any expression that is substituted must have all it's nodes bounded
3. the 'near' method which is often used just before compiling the final
   expression is used to bound the remaining unbounded nodes
Message posted by maybe Michael FIG on 2006/04/27 11:32:14
Okay, I'm going to need some more help to get this meta going.

I want

host tgt
 console "tgt: " tgt:name eol
 console "host: " this_module:name eol

to execute the body in a fresh module (with /pliant/language/compiler.pli loaded,
and tgt defined to be the prior module).  Here is my last attempt (which dies
horribly with a reference count violation):

module "/pliant/language/compiler.pli"

# Rewrite an expression to be completely within a different module.
method e force_near mod
 arg_rw Expression e; arg Module mod
 e module :> mod
 for (var Int i) 0 e:size-1
  e:i force_near mod

public

# Evaluate a body in the compiler's host with the name of the target
# module as an argument.  This allows cross-compiled modules to
# explicitly manipulate the target module.
meta host e
 if e:size <> 2 or not e:0:is_pure_ident
  return
 var Str targetIdent := e:0 ident
 if targetIdent = ""
  return

 # Put the body into the compiler's module.
 var Link:Module mod :> new Module
 mod name :> new Str "pliant compiler host module"
 mod include the_module:"/pliant/language/compiler.pli" 0
 e:1 force_near mod

 # Define the expression's target module as a variable in the module.
 var Link:GlobalVariable gv :> new GlobalVariable
 gv name := targetIdent
 gv variable := addressof e:module
 gv access := access_read .or. access_write

 host_module define targetIdent (addressof gv)
 e:1 execute
 host_module undefine targetIdent (addressof gv)

 # We're done.
 e set_void_result


BTW, I've translated about half of expression.c into Pliant so far.  Interesting.
Message posted by hubert.tonneau on 2006/04/27 11:53:25
What is 'host_module' ?

PS: Please use double char indentation.
Message posted by maybe Michael FIG on 2006/04/27 12:15:13
host_module was a typo... it's actually `mod'.
Message posted by hubert.tonneau on 2006/04/27 12:52:20
> var Link:Module mod :> new Module
> mod name :> new Str "pliant compiler host module"
> mod include the_module:"/pliant/language/compiler.pli" 0

You are probably crashing in 'this_module' because it looks for the
external module associated with 'mod' and there is none.

You should very carrefully study the 'load_module'
function in /pliant/language/compiler/module/module.c
as a way to learn the extra details initialised by the standard engine when it
creates a new module.


Also, I'm interested to read an overview of your cross compiler plan.
Some issues are complex so it may save time to exchange about the framework
before too much code is written.

On the other hand, what ever solution you select, translating line by line
the C code to Pliant code is required (except if someone decides to write
a Pliant C syntax parser) at some point, so it's ok to start that part without
futher talks.
Message posted by maybe Michael FIG on 2006/05/04 04:44:44
Thanks, the meta is now working the way I want it to.

My next question is about /pliant/language/optimizer/extra.pli, the
optimize_constant_instruction function.  I am trying to define a constant
as follows:

constant access_nocompile 80000000h

Now, technically, I could just define it to be 40000000h, but I would still
like to solve the problem.  I get the following error when I run at debug level
2:

----------------------------------------------------------------
The value is too large to fit in an Int
execute
run code generator function optimize_constant /pliant/language/optimizer/extra.pli (internals) 71 1 \
in section pliant optimizer rewrite instructions0

How can I define this constant?

Thanks,
Michael.
Message posted by hubert.tonneau on 2006/05/04 09:11:33
Pliant does arithmetic overflow tests when running at debugging levele 2.

The Pliant parser parses 80000000h as an uInt with value 2^31

Now, when you use this value on some computations, it will be casted to Int,
and on a 32 bits system the final value will be -2^31 so there is an overflow.

Pliant provides operator to prevent overflows to raise error.
As an example:
cast 2^30 Int # no overflow, so no error
cast 2^31 Int # overflow, so error
2^30*2 # the result is uInt so there is no overflow, so no error
(cast 2^30 Int)*2 # overflow, so error
(cast 2^30 Int).*.2 # overflow, but no error

We have introduced '.*.' operator, which is the same as '*' but does not raise
an error in case of overflow
We also have .+. operator

On the other hand, I have not yet defined a special cast operator that would
not raise an overflow.
Basically, it would be implemented as
function no_overflow_cast_int u -> i
  arg uInt u ; arg Int i
  i := addressof:u map Int

So, without this cast with no overflow operator, the simpler is propably to
define your constant as something like:
constant access_nocompile 80h.*.(cast 2^24 Int)
Message posted by maybe Michael FIG on 2006/05/05 03:14:50
Thank you.

Though I knew about the .*. operator, I didn't think of using it in the
constant declaration.  That seemed to work.

Michael.