|
1 // Copyright 2013 Google Inc. All Rights Reserved. |
|
2 // |
|
3 // Licensed under the Apache License, Version 2.0 (the "License"); |
|
4 // you may not use this file except in compliance with the License. |
|
5 // You may obtain a copy of the License at |
|
6 // |
|
7 // http://www.apache.org/licenses/LICENSE-2.0 |
|
8 // |
|
9 // Unless required by applicable law or agreed to in writing, software |
|
10 // distributed under the License is distributed on an "AS IS" BASIS, |
|
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
12 // See the License for the specific language governing permissions and |
|
13 // limitations under the License. |
|
14 |
|
15 // |
|
16 // These are weird things we need to do to get this compiling on |
|
17 // random systems [subset]. |
|
18 |
|
19 #ifndef BASE_PORT_H_ |
|
20 #define BASE_PORT_H_ |
|
21 |
|
22 #include <string.h> // for memcpy() |
|
23 #include "integral_types.h" |
|
24 |
|
25 namespace CLD2 { |
|
26 |
|
27 // Portable handling of unaligned loads, stores, and copies. |
|
28 // On some platforms, like ARM, the copy functions can be more efficient |
|
29 // then a load and a store. |
|
30 |
|
31 #if defined(ARCH_PIII) || defined(ARCH_ATHLON) || defined(ARCH_K8) || defined(_ARCH_PPC) |
|
32 |
|
33 // x86 and x86-64 can perform unaligned loads/stores directly; |
|
34 // modern PowerPC hardware can also do unaligned integer loads and stores; |
|
35 // but note: the FPU still sends unaligned loads and stores to a trap handler! |
|
36 |
|
37 #define UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p)) |
|
38 #define UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p)) |
|
39 #define UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64 *>(_p)) |
|
40 |
|
41 #define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_val)) |
|
42 #define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_val)) |
|
43 #define UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64 *>(_p) = (_val)) |
|
44 |
|
45 #elif defined(__arm__) && \ |
|
46 !defined(__ARM_ARCH_5__) && \ |
|
47 !defined(__ARM_ARCH_5T__) && \ |
|
48 !defined(__ARM_ARCH_5TE__) && \ |
|
49 !defined(__ARM_ARCH_5TEJ__) && \ |
|
50 !defined(__ARM_ARCH_6__) && \ |
|
51 !defined(__ARM_ARCH_6J__) && \ |
|
52 !defined(__ARM_ARCH_6K__) && \ |
|
53 !defined(__ARM_ARCH_6Z__) && \ |
|
54 !defined(__ARM_ARCH_6ZK__) && \ |
|
55 !defined(__ARM_ARCH_6T2__) |
|
56 |
|
57 // ARMv7 and newer support native unaligned accesses, but only of 16-bit |
|
58 // and 32-bit values (not 64-bit); older versions either raise a fatal signal, |
|
59 // do an unaligned read and rotate the words around a bit, or do the reads very |
|
60 // slowly (trip through kernel mode). There's no simple #define that says just |
|
61 // “ARMv7 or higher”, so we have to filter away all ARMv5 and ARMv6 |
|
62 // sub-architectures. Newer gcc (>= 4.6) set an __ARM_FEATURE_ALIGNED #define, |
|
63 // so in time, maybe we can move on to that. |
|
64 // |
|
65 // This is a mess, but there's not much we can do about it. |
|
66 |
|
67 #define UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p)) |
|
68 #define UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p)) |
|
69 |
|
70 #define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_val)) |
|
71 #define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_val)) |
|
72 |
|
73 // TODO(sesse): NEON supports unaligned 64-bit loads and stores. |
|
74 // See if that would be more efficient on platforms supporting it, |
|
75 // at least for copies. |
|
76 |
|
77 inline uint64 UNALIGNED_LOAD64(const void *p) { |
|
78 uint64 t; |
|
79 memcpy(&t, p, sizeof t); |
|
80 return t; |
|
81 } |
|
82 |
|
83 inline void UNALIGNED_STORE64(void *p, uint64 v) { |
|
84 memcpy(p, &v, sizeof v); |
|
85 } |
|
86 |
|
87 #else |
|
88 |
|
89 #define NEED_ALIGNED_LOADS |
|
90 |
|
91 // These functions are provided for architectures that don't support |
|
92 // unaligned loads and stores. |
|
93 |
|
94 inline uint16 UNALIGNED_LOAD16(const void *p) { |
|
95 uint16 t; |
|
96 memcpy(&t, p, sizeof t); |
|
97 return t; |
|
98 } |
|
99 |
|
100 inline uint32 UNALIGNED_LOAD32(const void *p) { |
|
101 uint32 t; |
|
102 memcpy(&t, p, sizeof t); |
|
103 return t; |
|
104 } |
|
105 |
|
106 inline uint64 UNALIGNED_LOAD64(const void *p) { |
|
107 uint64 t; |
|
108 memcpy(&t, p, sizeof t); |
|
109 return t; |
|
110 } |
|
111 |
|
112 inline void UNALIGNED_STORE16(void *p, uint16 v) { |
|
113 memcpy(p, &v, sizeof v); |
|
114 } |
|
115 |
|
116 inline void UNALIGNED_STORE32(void *p, uint32 v) { |
|
117 memcpy(p, &v, sizeof v); |
|
118 } |
|
119 |
|
120 inline void UNALIGNED_STORE64(void *p, uint64 v) { |
|
121 memcpy(p, &v, sizeof v); |
|
122 } |
|
123 |
|
124 #endif |
|
125 |
|
126 } // End namespace CLD2 |
|
127 |
|
128 #endif // BASE_PORT_H_ |