|
|
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.