Newbie questions about Pliant

Newbie questions about Pliant

C functions returning Int16

Message posted by maybe Todd Fleming on 2001/03/04 20:19:01

Pliant generates an exception after calling Windows DLL functions that return an Int16. It doesn't have a problem with Int.

C++ Code

  #include <windows.h>

  BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
  {
      return TRUE;
  }

  extern "C" _declspec(dllexport) int _stdcall testInt(int i)
  {
      return i + 1;
  }

  extern "C" _declspec(dllexport) short _stdcall testInt16(int i)
  {
      return short(i + 1);
  }

Pliant code

  module "/pliant/language/unsafe.pli"

  function testInt a -> b
    arg Int a b
    external "/Documents and Settings/todd/Desktop/d/Debug/d.dll" "_testInt@4"

  function testInt16 a -> b
    arg Int a 
    arg Int16 b
    external "/Documents and Settings/todd/Desktop/d/Debug/d.dll" "_testInt16@4"

  gvar Int i
  gvar Int16 i16

  i := testInt 5                    # works fine
  console "testInt 5 = " i eol

  i16 := testInt16 5                # generates exception after testInt16 returns
  console "testInt16 5 = " i16 eol

Output

testInt 5 = 6
exception
----------------------------------------------------------------
processor stack content is:
???
----------------------------------------------------------------
Message posted by maybe Hubert Tonneau on 2001/03/04 21:40:19
The prototype of the C and Pliant functions are not matching !

A Pliant 'Int16' data is always passed by address, never by value, because
it's not an atomic data. In Pliant, atomic datas must match the size of an
'Int', whereas in C, they can be smaller.

A C function should never return a 'short' integer. It is stupid because
it will not save any storage.
Message posted by maybe Hubert Tonneau on 2001/03/04 22:16:18
My answer might be a bit short.
Here is more detailed one.

In modern processors, there is only one data type, which I will call 'Int'
because it's exactly what Pliant 'Int' is. In facts, it is so much true that
even 'Address' (void * in C) data type is also an 'Int' from the processor
point of view.

So, why do we have 'Int8', 'Int16' and others ?
Because also in the processor, everything is an 'Int' because everything
is stored in registers which have fixed capacity, in the memory we don't
want to store everything as an 'Int' because it would wast too much space.
So, in the memory, there are 'Int8', 'Int16' and others, and the
immediat an main conclusion is that translatating from 'Int8', 'Int16'
and others to 'Int' and back is performed in the load register from memory
instruction and the store register value in memory instruction.

Now, what's puzzling is that on 64 bits architecture, the C 'int' data type
is often 32 bits, and the reason is that they wanted to have 8 bits, 16 bits,
32 bits and 64 bits available without creating a new name.
C using 'short' and 'long' instead of 8, 16, 32 and 64 was a sad design,
but they decided to make it even worse rather than correct it.
So, with a 64 bits processor, a register is 64 bits anyway, and as a result,
if you declare a C 'int' in a structure, it might be 32 bits, but if
it is a local variable, it will be 64 bits anyway, because it will be
a register.

Pliant convension is simpler and matching the reality: an atomic data is
always the size of a register, so 32 bits on a 32 bits processor, 64 bits on
a 64 bits processor.
Finally, other data types exist such as 'Int8' or 'Int16' that you can use
in stucture fields in order to specify what conversion should be done
when moving to an from the memory.
There is also 'Int16_hi' 'Int16_li' that specify the indianess that should
be used when storing in memory.
But, in any case, they only have meaning when used in structures or through
pointers. Decaring a local variable as 'Int16' is a lie, because in C it
will probably be 'Int' anyway (and it's not a problem since C does not handle
arithmetic overflow issues), and in Pliant, it will be unefficient because
it will never be assigned to a register.
The same applyes for functions result.

Message posted by maybe Todd Fleming on 2001/03/04 22:38:13

How should I handle Windows API functions (like RegisterClassEx) that return unsigned short? Right now I'm declaring them as returning Int, but this requires masking since the high-order bits are undefined. If there are any API functions that return signed short (I don't know off-hand if there are any), the return values will require sign extension.

Message posted by maybe Hubert Tonneau on 2001/03/05 09:22:59
Well, the answer is that the Windows API should be changed because it's
design is wrong in this area. They probably won't, but this is no more
a Pliant issue.

Two possibilities:
- either they used a smart compiler that will always provide an 'int' instead
  of a 'short int' because it's using sign extension, just like any RISC
  processor would, because it costs nothing:
  MOVSX EAX,[...]
- or they use the fact that the i386 truely has 16 bits registers due to
  it's long past:
  MOV AX,[...]

In the first case, specifying an 'Int' in your Pliant function should work
just fine, and in the second case, you will and to filter with an
  .and. 0FFFFh
expression.