1 /*
2  * gauche/bytesP.h - Some speed-sensitive byte-swapping routines
3  *
4  *   Copyright (c) 2009-2020  Shiro Kawai  <shiro@acm.org>
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *   1. Redistributions of source code must retain the above copyright
11  *      notice, this list of conditions and the following disclaimer.
12  *
13  *   2. Redistributions in binary form must reproduce the above copyright
14  *      notice, this list of conditions and the following disclaimer in the
15  *      documentation and/or other materials provided with the distribution.
16  *
17  *   3. Neither the name of the authors nor the names of its contributors
18  *      may be used to endorse or promote products derived from this
19  *      software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef GAUCHE_PRIV_BYTESP_H
35 #define GAUCHE_PRIV_BYTESP_H
36 
37 #include "gauche/priv/builtin-syms.h"
38 
39 /* Gauche use big-endian / little-endian.   scheme.bytevector requires
40    big / little.   We recognize both.  */
41 #define SCM_IS_BE(endian)                               \
42     (SCM_EQ(SCM_OBJ(endian), SCM_SYM_BIG_ENDIAN)        \
43      || (SCM_EQ(SCM_OBJ(endian), SCM_SYM_BIG)))
44 #define SCM_IS_LE(endian)                               \
45     (SCM_EQ(SCM_OBJ(endian), SCM_SYM_LITTLE_ENDIAN)     \
46      || SCM_EQ(SCM_OBJ(endian), SCM_SYM_LITTLE))
47 #define SCM_IS_ARM_LE(endian)                           \
48     (SCM_EQ(SCM_OBJ(endian), SCM_SYM_ARM_LITTLE_ENDIAN))
49 
50 #if WORDS_BIGENDIAN
51 #define SWAP_REQUIRED(endian)   (!SCM_IS_BE(endian))
52 #else  /*!WORDS_BIGENDIAN.  Covers both little-endian and arm-little-endian. */
53 #define SWAP_REQUIRED(endian)   SCM_IS_BE(endian)
54 #endif
55 
56 
57 /*
58  * Swapping macros.   They can be used both ways (native <-> external)
59  */
60 
61 typedef union { char buf[2]; int16_t val; }      swap_s16_t;
62 typedef union { char buf[2]; uint16_t val; }     swap_u16_t;
63 typedef union { char buf[4]; int32_t val; }      swap_s32_t;
64 typedef union { char buf[4]; uint32_t val; }     swap_u32_t;
65 typedef union { char buf[8]; int64_t val; }      swap_s64_t;
66 typedef union { char buf[8]; uint64_t val; }     swap_u64_t;
67 
68 typedef union { char buf[2]; ScmHalfFloat val; } swap_f16_t;
69 typedef union { char buf[4]; float val; }        swap_f32_t;
70 typedef union { char buf[8]; double val; }       swap_f64_t;
71 
72 #define CSWAP(buf, tmp, n, m) (tmp=buf[n], buf[n]=buf[m], buf[m]=tmp)
73 
74 /* In the following macros, 'v' is of type one of the suitable swap_*_t. */
75 
76 #define SWAP_2(v) \
77     do { char tmp; CSWAP(v.buf, tmp, 0, 1); } while (0)
78 
79 #define SWAP_4(v)                                               \
80     do { char tmp;                                              \
81         CSWAP(v.buf, tmp, 0, 3); CSWAP(v.buf, tmp, 1, 2);       \
82     } while (0)
83 
84 #define SWAP_8(v)                                               \
85     do { char tmp;                                              \
86         CSWAP(v.buf, tmp, 0, 7); CSWAP(v.buf, tmp, 1, 6);       \
87         CSWAP(v.buf, tmp, 2, 5); CSWAP(v.buf, tmp, 3, 4);       \
88     } while (0)
89 
90 /* Swapping for double float is a bit tricky for ARM_LE case:
91      BE<->ARM : [01234567] -> [32107654]
92      LE<->ARM : [01234567] -> [45670123]
93 */
94 #define SWAP_ARM2BE(v)                                          \
95     do { char tmp;                                              \
96         CSWAP(v.buf, tmp, 0, 3); CSWAP(v.buf, tmp, 1, 2);       \
97         CSWAP(v.buf, tmp, 4, 7); CSWAP(v.buf, tmp, 5, 6);       \
98     } while (0)
99 
100 #define SWAP_ARM2LE(v)                                          \
101     do { char tmp;                                              \
102         CSWAP(v.buf, tmp, 0, 4); CSWAP(v.buf, tmp, 1, 5);       \
103         CSWAP(v.buf, tmp, 2, 6); CSWAP(v.buf, tmp, 3, 7);       \
104     } while (0)
105 
106 
107 #endif /*GAUCHE_PRIV_BYTESP_H*/
108