Newbie questions about Pliant

Newbie questions about Pliant

Incompatible uInt16 and uInt32?!

uInt32 and uInt16 types do not decode properly in C external
functions. Only uInt.
Message posted by mujtaba on 2002/12/31 15:06:47
I know its likely my fault, but I'm having trouble with the uInt32 and uInt16 
types in Pliant. The uInt32 and uInt type are of the same size, but they
decode differently when passed into C external functions:

It appears that uInt (32-bits) works well in the function accepting
a 32-bit unsigned integer, but uInt32 doesn't. Also, the uInt16 doesn't
work in a function accepting a 16-bit unsigned integer. What am I doing
wrong?

Does this mean I shouldn't use uInt16 or uInt32 in "packed" types to
pass as C structures?

--> C library source:

/*uInt.c: gcc -fPIC -c uInt.c; 
gcc -shared -W1,soname,libuInt.so uInt.o -o libuInt.so */

#include <stdio.h>

typedef unsigned int uInt32;
typedef unsigned short uInt16;

void print_uInt32(uInt32 num){
    printf("dec32=%u\nhex32=%X\n",num,num);
}
 
void print_uInt16(uInt16 num){
    printf("dec16=%u\nhex16=%X\n",num,num);


--> Pliant wrapper: 
#uInt.pli
module "/pliant/language/context.pli"

gvar uInt32 OFLAG32 := 00000000h
gvar uInt16 OFLAG16 := 00000000h
gvar uInt OFLAG := 00000000h

function print_uInt32 num
 arg uInt32 num
 external "libuInt.so" "print_uInt32"

function print_uInt16 num
 arg uInt16 num
 external "libuInt.so" "print_uInt16"

function print_uInt num
 arg uInt num
 external "libuInt.so" "print_uInt32"

console "(uInt16 size) = " (uInt16 size) eol
console "(uInt size) = " (uInt size) eol
console "(uInt32 size) = " (uInt32 size) eol

print_uInt16 OFLAG16
print_uInt32 OFLAG32
print_uInt OFLAG


--> Output from uInt.pli:

(uInt16 size) = 2
(uInt size) = 4
(uInt32 size) = 4
dec16=16536
hex16=4098
dec32=1077105472
hex32=40335340
dec32=0
hex32=0
Message posted by hubert.tonneau on 2002/12/31 15:18:06
In Pliant, uInt16 and uInt32 are not atomic data types, so they will always
be passed by address.

As a result:

function print_uInt32 num
 arg uInt32 num

is the same as:

void print_uInt32(unsigned int *num);

not:

void print_uInt32(unsigned int num);

On the other hand:

function print_uInt32 num
 arg uInt num

is the same as:

void print_uInt32(unsigned int num);


In your library, just use 'Int' and 'uInt' in all function prototypes.
Using 'uInt16' and 'uInt32' is ok only for fields in structures (with the
exception of bitfield data types if they will then be passed by value
to functions).


Message posted by mujtaba on 2002/12/31 16:20:48
Okay, but what if I can't change the library functions? Let say I was working 
around an existing library. If I make all my function prototypes in the .pli
file use Int and uInts, will it cast properly to C functions expecting 16 or
32 bit ints? Yet I can use these non-atomic types in structures for their
field size. Is this what you mean?


e.g. (untested)

/*from libfoo.so*/

typedef struct {
 short x, y;
 unsigned char color;
}Point;

void plotPointxyc(short x, short y, unsigned char color){
...


void plotPointP(Point *P){
 ...
}

#Using non-atomic types in struct
type Point
 field Int16 x y
 field uInt8 color
 field (Array Byte 3) padding

#Specifying arguments of Int and uInt only.
function plotPointxyc x y color
 arg Int x y; arg uInt color
 external "libfoo.so" "plotPointxyc"

function plotPointP P
 arg Address P
 external "libfoo.so" "plotPointP"

gvar Point point

plotPointxyc 10 15 255

point:x := 10
point:y := 20
point:color := 122

plotPointP addressof:point



BTW, why can't I print uInt32 on the console, don't they have
a 'to string' method? I get compile errors when I try.
Message posted by hubert.tonneau on 2002/12/31 17:02:18
> Okay, but what if I can't change the library functions?

It will work, because of processors design.
Basically having an 'uInt8' or 'uInt16' has no meaning except when the data
is stored in the memory. The reason is that on a consistent processor, all bits
extension or reduction will append at load from memory or store to memory time.
Processor registers have fixed 'Int' size.

So, a prototype like this:
  void plotPointxyc(short x, short y, unsigned char color);
is just stupid, also not expicitly forbidden in C.
Most processors (probably all) will handle it as:
  void plotPointxyc(int x, int y, unsigned int color);

Also there is a problem with 64 processors, because some (maybe all) C compilers
assumed that 'int' size is 32 bits, which is also stupid, except for history
reasons. So if we want to port Pliant to a 64 bits plateform, I will probably
need to define 'CInt' and 'CuInt' data types and update quite a lot of things
in Pliant existing code in order to interface with the OS and external libraries.

Now, if you want to interface your library, just try:

type Point
  packed # prevents Pliant to reorder fields in order to get better memory alignment
  field Int16 x y
  field uInt8 color

function plotPointxyc x y color
  arg Int x y ; arg uInt color
  external "libfoo.so" "plotPointxyc"

function plotPointP p
  arg Point p
  external "libfoo.so" "plotPointP"

plotPointxyc 10 15 255

gvar Point point
point x := 10
point y := 20
point color := 122
plotPointP point




Message posted by hubert.tonneau on 2002/12/31 17:05:30
> why can't I print uInt32 on the console, don't they have
> a 'to string' method? I get compile errors when I try.

Because I have not defined 'to string' method for 'uInt32',
so you have to explicitely cast it to 'uInt'.

Keep in mind that 'uInt32' is a very special thing that very fiew programs should
use.
Message posted by mujtaba on 2002/12/31 21:07:38
Thanks. Now I have the same trouble with Floats. Float is not an atomic type, so
it only gets passed by address. But now I have a library that expects floats
to be passed by value. Can I force Pliant to pass the Float or any type by value?
I read somewhere that Pliant will pass by value if the true-argument is read-only.

Perhaps when functions contain the "external" attribute they should pass by
value, as is default in C. BTW, I know its inefficient to pass by value and 
I can understand why this was restricted in Pliant.
Message posted by hubert.tonneau on 2002/12/31 22:06:47
Assuming that the C prototype is:

void foo(double f);

then you will have to do something uggly like:

function foo_ f1 f2
  arg Int f1 f2
  external "libfoo.so" "foo"

function foo f
  arg Float f
  foo_ (addressof:f map Int) (addressof:f map Int 1)
  # or maybe foo_ (addressof:f map Int 1) (addressof:f map Int)
  # I don't know which is the right one

The big problem is that it is architecture specific.

Also remember that C 'float' is Pliant 'Float32'
and that C 'double' is Pliant 'Float'

Now, if your C prototype is

void foo(float f);

then it's probably possible to force Pliant to pass by value, through something
like:

module "/pliant/language/compiler.pli"
function foo f
  arg Float32 f
((the_function foo Float32) arg 0) access := ((the_function foo Float32) arg 0):access .or. access_byvalue

Enabling to pass a 'Float' argument by value is something that I
might add at some point, but it requires to extend (since it requires to push
twice on the stack in order to push a single argument) the C part of Pliant
which does not care of 'Float' since it's not defined in the C part of Pliant.
Message posted by mujtaba on 2003/01/02 17:10:19
Thanks, this is sort of the solution I'm using: I use a wrapper function to
cast Float args to Float32, because the literal Float type in Pliant is 64 bits.
Then the lower-level function has its arguments set to pass by value. 
Its not so ugly.

e.g 

module "/pliant/language/compiler.pli"
   
#Lower function
function plot_ x y color
 arg Float32 x y
 arg uInt color
 external "libplot.so" "plot"

#Wrapper
function plot x y color
 arg Float x y
 arg uInt color
 plot_ (cast x Float32) (cast y Float32) color

#For each argument in lower function

((the_function plot_ Float32 Float32) arg 0) access := ((the_function plot_ Float32 Float32) arg 0):access .or. access_byvalue
((the_function plot_ Float32 Float32) arg 1) access := ((the_function plot_ Float32 Float32) arg 0):access .or. access_byvalue


plot 1.3 3.4 255


Message posted by mujtaba on 2003/01/02 17:13:34
Oops!
that should be:
((the_function plot_ Float32 Float32 uInt) ...

I wrote the above spontaneously, Its not tested code and there is no
libplot.
Message posted by hubert.tonneau on 2003/01/02 17:15:10
Two remarks:

. You should move 'For each argument in lower function' before 'Wrapper'
  because if you use 'plot_' in function 'plot' before setting properly it's
  calling convension, the code generated for 'plot' function might be wrong.
  It does not append in reality because Pliant will probably inline 'plot'
  function, but anyway, it's better writting correct code.

. You have a typo error:
  ((the_function plot_ Float32 Float32) arg 1) access := ((the_function plot_ Float32 Float32) arg 0):access .or. access_byvalue
  should be:
  ((the_function plot_ Float32 Float32) arg 1) access := ((the_function plot_ Float32 Float32) arg 1):access .or. access_byvalue