1--  C->Haskell Compiler: information about the C implementation
2--
3--  Author : Manuel M T Chakravarty
4--  Created: 5 February 01
5--
6--  Version $Revision: 1.2 $ from $Date: 2005/01/16 21:31:21 $
7--
8--  Copyright (c) 2001 Manuel M T Chakravarty
9--
10--  This file is free software; you can redistribute it and/or modify
11--  it under the terms of the GNU General Public License as published by
12--  the Free Software Foundation; either version 2 of the License, or
13--  (at your option) any later version.
14--
15--  This file is distributed in the hope that it will be useful,
16--  but WITHOUT ANY WARRANTY; without even the implied warranty of
17--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18--  GNU General Public License for more details.
19--
20--- DESCRIPTION ---------------------------------------------------------------
21--
22--  This module provide some information about the specific implementation of
23--  C that we are dealing with.
24--
25--- DOCU ----------------------------------------------------------------------
26--
27--  language: Haskell 98
28--
29--  Bit fields
30--  ~~~~~~~~~~
31--  Bit fields in C can be signed and unsigned.  According to K&R A8.3, they
32--  can only be formed from `int', `signed int', and `unsigned int', where for
33--  `int' it is implementation dependent whether the field is signed or
34--  unsigned.  Moreover, the following parameters are implementation
35--  dependent:
36--
37--  * the direction of packing bits into storage units,
38--  * the size of storage units, and
39--  * whether when a field that doesn't fit a partially filled storage unit
40--    is split across units or the partially filled unit is padded.
41--
42--  Generally, unnamed fields (those without an identifier) with a width of 0
43--  are guaranteed to forces the above padding.  Note that in `CPrimType' we
44--  only represent 0 width fields *if* they imply padding.  In other words,
45--  whenever they are unnamed, they are represented by a `CPrimType', and if
46--  they are named, they are represented by a `CPrimType' only if that
47--  targeted C compiler chooses to let them introduce padding.  If a field
48--  does not have any effect, it is dropped during the conversion of a C type
49--  into a `CPrimType'-based representation.
50--
51--  In the code, we assume that the alignment of a bitfield (as determined by
52--  `bitfieldAlignment') is independent of the size of the bitfield.
53--
54--- TODO ----------------------------------------------------------------------
55--
56
57module CInfo (
58  CPrimType(..), size, alignment,
59  bitfieldDirection, bitfieldPadding, bitfieldIntSigned, bitfieldAlignment
60) where
61
62import Foreign.C
63
64-- we can't rely on the compiler used to compile c2hs already having the new
65-- FFI, so this is system dependent
66--
67import C2HSConfig (Ptr, FunPtr,
68                   bitfieldDirection, bitfieldPadding, bitfieldIntSigned,
69                   bitfieldAlignment)
70import qualified
71       C2HSConfig as Storable
72                  (Storable(sizeOf, alignment))
73
74
75-- calibration of C's primitive types
76-- ----------------------------------
77
78-- C's primitive types (EXPORTED)
79--
80--  * `CFunPtrPT' doesn't occur in Haskell representations of C types, but we
81--   need to know their size, which may be different from `CPtrPT'
82--
83data CPrimType = CPtrPT         -- void *
84               | CFunPtrPT      -- void *()
85               | CCharPT        -- char
86               | CUCharPT       -- unsigned char
87               | CSCharPT       -- signed char
88               | CIntPT         -- int
89               | CShortPT       -- short int
90               | CLongPT        -- long int
91               | CLLongPT       -- long long int
92               | CUIntPT        -- unsigned int
93               | CUShortPT      -- unsigned short int
94               | CULongPT       -- unsigned long int
95               | CULLongPT      -- unsigned long long int
96               | CFloatPT       -- float
97               | CDoublePT      -- double
98               | CLDoublePT     -- long double
99               | CSFieldPT  Int -- signed bit field
100               | CUFieldPT  Int -- unsigned bit field
101               deriving (Eq)
102
103-- size of primitive type of C (EXPORTED)
104--
105--  * negative size implies that it is a bit, not an octet size
106--
107size                :: CPrimType -> Int
108size CPtrPT          = Storable.sizeOf (undefined :: Ptr ())
109size CFunPtrPT       = Storable.sizeOf (undefined :: FunPtr ())
110size CCharPT         = 1
111size CUCharPT        = 1
112size CSCharPT        = 1
113size CIntPT          = Storable.sizeOf (undefined :: CInt)
114size CShortPT        = Storable.sizeOf (undefined :: CShort)
115size CLongPT         = Storable.sizeOf (undefined :: CLong)
116size CLLongPT        = Storable.sizeOf (undefined :: CLLong)
117size CUIntPT         = Storable.sizeOf (undefined :: CUInt)
118size CUShortPT       = Storable.sizeOf (undefined :: CUShort)
119size CULongPT        = Storable.sizeOf (undefined :: CULong)
120size CULLongPT       = Storable.sizeOf (undefined :: CLLong)
121size CFloatPT        = Storable.sizeOf (undefined :: CFloat)
122size CDoublePT       = Storable.sizeOf (undefined :: CDouble)
123--size CLDoublePT      = Storable.sizeOf (undefined :: CLDouble)
124size (CSFieldPT bs)  = -bs
125size (CUFieldPT bs)  = -bs
126
127-- alignment of C's primitive types (EXPORTED)
128--
129--  * more precisely, the padding put before the type's member starts when the
130--   preceding component is a char
131--
132alignment                :: CPrimType -> Int
133alignment CPtrPT          = Storable.alignment (undefined :: Ptr ())
134alignment CFunPtrPT       = Storable.alignment (undefined :: FunPtr ())
135alignment CCharPT         = 1
136alignment CUCharPT        = 1
137alignment CSCharPT        = 1
138alignment CIntPT          = Storable.alignment (undefined :: CInt)
139alignment CShortPT        = Storable.alignment (undefined :: CShort)
140alignment CLongPT         = Storable.alignment (undefined :: CLong)
141alignment CLLongPT        = Storable.alignment (undefined :: CLLong)
142alignment CUIntPT         = Storable.alignment (undefined :: CUInt)
143alignment CUShortPT       = Storable.alignment (undefined :: CUShort)
144alignment CULongPT        = Storable.alignment (undefined :: CULong)
145alignment CULLongPT       = Storable.alignment (undefined :: CULLong)
146alignment CFloatPT        = Storable.alignment (undefined :: CFloat)
147alignment CDoublePT       = Storable.alignment (undefined :: CDouble)
148--alignment CLDoublePT      = Storable.alignment (undefined :: CLDouble)
149alignment (CSFieldPT bs)  = fieldAlignment bs
150alignment (CUFieldPT bs)  = fieldAlignment bs
151
152-- alignment constraint for a C bitfield
153--
154--  * gets the bitfield size (in bits) as an argument
155--
156--  * alignments constraints smaller or equal to zero are reserved for bitfield
157--   alignments
158--
159--  * bitfields of size 0 always trigger padding; thus, they get the maximal
160--   size
161--
162--  * if bitfields whose size exceeds the space that is still available in a
163--   partially filled storage unit trigger padding, the size of a storage unit
164--   is provided as the alignment constraint; otherwise, it is 0 (meaning it
165--   definitely starts at the current position)
166--
167--  * here, alignment constraint /= 0 are somewhat subtle; they mean that is
168--   the given number of bits doesn't fit in what's left in the current
169--   storage unit, alignment to the start of the next storage unit has to be
170--   triggered
171--
172fieldAlignment                      :: Int -> Int
173fieldAlignment 0                     = - (size CIntPT - 1)
174fieldAlignment bs | bitfieldPadding  = - bs
175                  | otherwise        = 0
176