|
|
1.1 root 1: #ifndef __COMMON__CANON_H__
2: #define __COMMON__CANON_H__
3:
4: /*
5: * This file contains definitions related to canonicalization of numeric
6: * formats. Routines are provided for conversions between the native format
7: * and numerous other canonical forms, with varying argument patterns so that
8: * conversion can be done in a space- and/or time-efficient manner. In
9: * particular, separate versions for each routine exists that operate on an
10: * lvalue to return a converted value, on an rvalue to return a converted
11: * value, and to perform in-place conversion on an lvalue, so that the most
12: * efficient machine idioms can be used for particular target machines.
13: * The routines in this file are oriented towards systems with 32-bit long-
14: * integer arithmetic, but extensions should be trivial.
15: *
16: * canonicalize -> to make canonical
17: * canonical -> according to the canons
18: * canons -> the law
19: * canonize -> to bestow sainthood
20: */
21:
22: #include <common/feature.h>
23: #include <common/_limits.h>
24:
25: #if __CHAR_BIT != 8
26: # error The canonicalization system only applies to octet-oriented machines
27: #endif
28:
29: /*
30: * We begin by defining a basic type for the lvalue-oriented manipulations and
31: * some fundamental concepts and facilities that build on that to create a
32: * bottom layer to the system. We explain the operation of the system entirely
33: * in terms of manipulations of octets.
34: *
35: * We begin by defining the basic notation for describing formats; the basic
36: * parameter for a data format is how the octets in the numbers in that format
37: * are laid out, which we specify relative to the lowest machine address
38: * occupied by the datum (many canonical data formats are based on the notion
39: * of transmission order, and we typically expect that "is transmitted before"
40: * maps directly onto "has a lower address than" for a structure laid out in
41: * machine memory).
42: *
43: * So, for an M68K, the index of the most-significant byte of a native-format
44: * number is always zero, whereas for an Intel-format number the bytes (and
45: * thus their indexes) are reversed. If we encode the index of the byte in the
46: * canonical order as a (machine-independent) number with each index taking
47: * up a byte, then we get a value which when stored in that format will have
48: * the values 0, 1, 2, ... stored in consecutive octets of machine memory.
49: *
50: * The nice thing about this encoding is that is thus reflective; if we have
51: * a way of transforming abstract numbers according to this "map", we can
52: * apply the transformation to the maps themselves to generate new maps which
53: * can be used to encode other numbers or maps. This enables us to better deal
54: * with the potential n^2 nature of the conversions by dynamically composing
55: * the maps.
56: */
57:
58: typedef unsigned char * __canon_t;
59:
60: #define __IDENTITY_16_MAP 0x0100U
61: #define __REVERSE_16_MAP 0x0001U
62: #define __I386_16_MAP __IDENTITY_16_MAP
63: #define __M68K_16_MAP __REVERSE_16_MAP
64: #define __OCOH_16_MAP __IDENTITY_16_MAP
65:
66: #define __IDENTITY_32_MAP 0x03020100UL
67: #define __REVERSE_32_MAP 0x00010203UL
68: #define __SWAP16_32_MAP 0x01000302UL
69: #define __I386_32_MAP __IDENTITY_32_MAP
70: #define __M68K_32_MAP __REVERSE_32_MAP
71: #define __OCOH_32_MAP __SWAP16_32_MAP
72:
73:
74: /*
75: * The following primitive mapping functions use a map, and come in two
76: * flavours; r-value oriented, and l-value oriented. The r-value-oriented
77: * transformations have the special property of using only operations which
78: * are permitted in the restricted form of integral constant expression that
79: * can be used in #if-expressions. Applying the r-value transformations to
80: * constants yields other constants.
81: *
82: * Note that the fundamental transformations have two (nearly) equivalent
83: * forms, of which I find the recursive more aesthetically pleasing, so that
84: * is the default form. We leave both in here for your amusement.
85: */
86:
87: #define __OCTET_N_OF_R(r,n) (((r) >> ((n) * 8)) & 0xFFU)
88: #define __OCTET_N_OF_L(l,n) (((__canon_t) & (l)) [n])
89: #define __MAKE_OCTET_N(o,n) ((o) << ((n) * 8))
90:
91: #define __CONVERT_OCTET_N_OF_R_VIA_MAP0(r,m,n) \
92: __MAKE_OCTET_N (__OCTET_N_OF_R (r, n), __OCTET_N_OF_R (m, n))
93:
94: #define __CONVERT_OCTET_N_OF_R_VIA_MAP1(r,m,n) \
95: __MAKE_OCTET_N (__OCTET_N_OF_R (r, __OCTET_N_OF_R (m, n)), n)
96:
97: #define __CONVERT_OCTET_N_OF_L_VIA_MAP0(l,m,n) \
98: __MAKE_OCTET_N (__OCTET_N_OF_L (l, n), __OCTET_N_OF_R (m, n))
99:
100: #define __CONVERT_OCTET_N_OF_L_VIA_MAP1(l,m,n) \
101: __MAKE_OCTET_N (__OCTET_N_OF_L (l, __OCTET_N_OF_R (m, n)), n)
102:
103: #define __CONVERT_R_16(r,m) \
104: (__CONVERT_OCTET_N_OF_R_VIA_MAP1 (r, m, 0) | \
105: __CONVERT_OCTET_N_OF_R_VIA_MAP1 (r, m, 1))
106:
107: #define __CONVERT_L_16(l,m) \
108: (__CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 0) | \
109: __CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 1))
110:
111: #define __CONVERT_R_32(r,m) \
112: (__CONVERT_OCTET_N_OF_R_VIA_MAP1 (r, m, 0) | \
113: __CONVERT_OCTET_N_OF_R_VIA_MAP1 (r, m, 1) | \
114: __CONVERT_OCTET_N_OF_R_VIA_MAP1 (r, m, 2) | \
115: __CONVERT_OCTET_N_OF_R_VIA_MAP1 (r, m, 3))
116:
117: #define __CONVERT_L_32(l,m) \
118: (__CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 0) | \
119: __CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 1) | \
120: __CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 2) | \
121: __CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 3))
122:
123: /*
124: * Here, we use rather more specific feature-tests to see about escaping to
125: * special hand-coded routines or inlines, which is highly translator-specific
126: * in addition to being machine-specific.
127: */
128:
129: #if __GNUC__ && _I386
130:
131: #if __SHRT_BIT != 16 || __LONG_BIT != 32
132: # error For GCC on i386, short should be 16 bits and a long should be 32.
133: #endif
134:
135: #include <common/ccompat.h>
136: #include <common/xdebug.h>
137:
138: /*
139: * We supply two versions of some of the following depending on whether or not
140: * you care about not being able to use the %ebp, %esi, and %edi registers as
141: * operands or not.
142: */
143:
144: __LOCAL__ __INLINE__ unsigned short __swap_bytes (unsigned short _number) {
145: unsigned short _result;
146: #if 1
147: __NON_ISO (asm) ("rolw $8, %0" : "=r" (_result) : "0" (_number));
148: #else
149: __NON_ISO (asm) ("xchg %h0, %b0" : "=q" (_result) : "0" (_number));
150: #endif
151: return _result;
152: }
153:
154: __LOCAL__ __INLINE__ unsigned long __swap_words (unsigned long _number) {
155: unsigned long _result;
156: __NON_ISO (asm) ("roll $16, %0" : "=r" (_result) : "0" (_number));
157: return _result;
158: }
159:
160: /*
161: * On the i486 processor we have the BSWAP instruction, but the following
162: * works on the i386 as well.
163: */
164:
165: __LOCAL__ __INLINE__ unsigned long __reverse_long (unsigned long _number) {
166: unsigned long _result;
167: #if 1
168: __NON_ISO (asm) ("rolw $8, %0\n"
169: "roll $16, %0\n",
170: "rolw $8, %0\n" : "=r" (_result) : "0" (_number));
171: #else
172: __NON_ISO (asm) ("xchg %h0, %b0\n"
173: "rorl $16, %0\n"
174: "xchg %h0, %b0\n" : "=q" (_result) : "0" (_number));
175: #endif
176: return _result;
177: }
178:
179: #undef __CONVERT_L_16
180: #define __CONVERT_L_16(l,m) \
181: ((m) == __REVERSE_16_MAP ? __swap_bytes (l) : \
182: __CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 0) | \
183: __CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 1))
184:
185: #undef __CONVERT_L_32
186: #define __CONVERT_L_32(l,m) \
187: ((m) == __SWAP16_32_MAP ? __swap_words (l) : \
188: (m) == __REVERSE_32_MAP ? __reverse_long (l) : \
189: __CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 0) | \
190: __CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 1) | \
191: __CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 2) | \
192: __CONVERT_OCTET_N_OF_L_VIA_MAP1 (l, m, 3))
193:
194: #endif /* __GNUC__ && _I386 */
195:
196:
197: /*
198: * Now, use a variety of feature-tests to figure out the native format for the
199: * host we are compiling for.
200: */
201:
202: #if __MSDOS__ || _I386
203:
204: # define __NATIVE_16_MAP __I386_16_MAP
205: # define __NATIVE_32_MAP __I386_32_MAP
206:
207: #else
208:
209: # error What is the native endianness of your system?
210:
211: #endif
212:
213: #define __CANON_FOO(value,l_or_r,type, map,ident) \
214: ((map) == (ident) ? value : \
215: __CONCAT4 (__CONVERT_, l_or_r, _, type) \
216: (value, map))
217:
218: #define __CANONICALIZE(value,l_or_r,machine,type) \
219: __CANON_FOO (value, l_or_r, type, \
220: __CONCAT (__CONVERT_R_, type) \
221: (__CONCAT3 (__NATIVE_, type, _MAP), \
222: __CONCAT4 (machine, _, type, _MAP)), \
223: __CONCAT3 (__IDENTITY_, type, _MAP))
224:
225:
226: #endif /* ! defined (__COMMON__CANON_H__) */
227:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.