Go to the documentation of this file.
13 #ifndef LLVM_SUPPORT_ENDIAN_H
14 #define LLVM_SUPPORT_ENDIAN_H
22 #include <type_traits>
35 template<
class T,
int alignment>
37 enum {
value = alignment == 0 ?
alignof(
T) : alignment };
48 template <
typename value_type>
56 template<
typename value_type, endianness endian>
62 template <
typename value_type, std::
size_t alignment>
70 return byte_swap<value_type>(
ret,
endian);
73 template<
typename value_type,
75 std::size_t alignment>
76 inline value_type
read(
const void *memory) {
77 return read<value_type, alignment>(memory,
endian);
82 template <
typename value_type, std::
size_t alignment,
typename CharT>
84 value_type
ret = read<value_type, alignment>(memory,
endian);
85 memory +=
sizeof(value_type);
91 inline value_type
readNext(
const CharT *&memory) {
92 return readNext<value_type, alignment, CharT>(memory,
endian);
96 template <
typename value_type, std::
size_t alignment>
98 value = byte_swap<value_type>(value,
endian);
101 &value,
sizeof(value_type));
104 template<
typename value_type,
106 std::size_t alignment>
107 inline void write(
void *memory, value_type value) {
108 write<value_type, alignment>(memory, value,
endian);
111 template <
typename value_type>
116 template <
typename value_type, endianness endian, std::
size_t alignment>
120 return read<value_type, endian, alignment>(memory);
127 sizeof(value_type) * 2);
128 val[0] = byte_swap<value_type, endian>(
val[0]);
129 val[1] = byte_swap<value_type, endian>(
val[1]);
135 (
sizeof(value_type) * 8) - startBit;
142 upperVal <<= numBitsFirstVal;
144 return lowerVal | upperVal;
150 template <
typename value_type, endianness endian, std::
size_t alignment>
155 write<value_type, endian, alignment>(memory, value);
162 sizeof(value_type) * 2);
163 val[0] = byte_swap<value_type, endian>(
val[0]);
164 val[1] = byte_swap<value_type, endian>(
val[1]);
170 (
sizeof(value_type) * 8) - startBit;
178 lowerVal <<= startBit;
192 val[0] = byte_swap<value_type, endian>(
val[0]);
193 val[1] = byte_swap<value_type, endian>(
val[1]);
196 &
val[0],
sizeof(value_type) * 2);
216 return endian::read<value_type, endian, alignment>(
217 (
const void*)
Value.buffer);
221 endian::write<value_type, endian, alignment>(
222 (
void*)
Value.buffer, newValue);
226 *
this = *
this + newValue;
231 *
this = *
this - newValue;
236 *
this = *
this | newValue;
241 *
this = *
this & newValue;
255 return endian::read<value_type, endian, alignment>(Ptr);
259 endian::write<value_type, endian, alignment>(Ptr, NewValue);
339 template <
typename T>
341 template <
typename T>
344 template <
typename T>
347 template <
typename T>
353 return read<T, unaligned>(
P,
E);
356 template <
typename T, endianness E>
inline T read(
const void *
P) {
361 return read<uint16_t>(
P,
E);
364 return read<uint32_t>(
P,
E);
367 return read<uint64_t>(
P,
E);
371 return read<uint16_t, E>(
P);
374 return read<uint32_t, E>(
P);
377 return read<uint64_t, E>(
P);
388 write<T, unaligned>(
P, V,
E);
391 template <
typename T, endianness E>
inline void write(
void *
P,
T V) {
396 write<uint16_t>(
P, V,
E);
399 write<uint32_t>(
P, V,
E);
402 write<uint64_t>(
P, V,
E);
406 write<uint16_t, E>(
P, V);
409 write<uint32_t, E>(
P, V);
412 write<uint64_t, E>(
P, V);
427 #endif // LLVM_SUPPORT_ENDIAN_H
This is an optimization pass for GlobalISel generic memory operations.
constexpr bool IsBigEndianHost
uint16_t read16(const void *P, endianness E)
void swapByteOrder(T &Value)
void write32be(void *P, uint32_t V)
uint32_t read32(const void *P, endianness E)
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
value_type readAtBitAlignment(const void *memory, uint64_t startBit)
Read a value of a particular endianness from memory, for a location that starts at the given bit offs...
uint16_t read16le(const void *P)
void write32le(void *P, uint32_t V)
void write16le(void *P, uint16_t V)
to esp esp setne al movzbw ax esp setg cl movzbw cx cmove cx cl jne LBB1_2 esp ret(also really horrible code on ppc). This is due to the expand code for 64-bit compares. GCC produces multiple branches
uint32_t read32be(const void *P)
uint64_t read64be(const void *P)
packed_endian_specific_integral & operator+=(value_type newValue)
void write32(void *P, uint32_t V, endianness E)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
packed_endian_specific_integral()=default
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
The initial backend is deliberately restricted to z10 We should add support for later architectures at some point If an asm ties an i32 r result to an i64 the input will be treated as an leaving the upper bits uninitialised For i64 store i32 val
detail::packed_endian_specific_integral< uint16_t, little, unaligned > ulittle16_t
void write16(void *P, uint16_t V, endianness E)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
value_type readNext(const CharT *&memory, endianness endian)
Read a value of a particular endianness from a buffer, and increment the buffer past that value.
void writeAtBitAlignment(void *memory, value_type value, uint64_t startBit)
Write a value to memory with a particular endianness, for a location that starts at the given bit off...
std::make_unsigned_t< value_type > make_unsigned_t
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
packed_endian_specific_integral & operator|=(value_type newValue)
void write16be(void *P, uint16_t V)
void operator=(value_type newValue)
packed_endian_specific_integral(value_type val)
packed_endian_specific_integral & operator-=(value_type newValue)
value_type read(const void *memory, endianness endian)
Read a value of a particular endianness from memory.
value_type byte_swap(value_type value, endianness endian)
constexpr endianness system_endianness()
void operator=(value_type NewValue)
static constexpr std::size_t alignment
uint64_t read64(const void *P, endianness E)
uint64_t read64le(const void *P)
void write64le(void *P, uint64_t V)
uint32_t read32le(const void *P)
void write64be(void *P, uint64_t V)
Reimplement select in terms of SEL *We would really like to support but we need to prove that the add doesn t need to overflow between the two bit chunks *Implement pre post increment support(e.g. PR935) *Implement smarter const ant generation for binops with large immediates. A few ARMv6T2 ops should be pattern matched
::value is either alignment, or alignof(T) if alignment is 0.
void write64(void *P, uint64_t V, endianness E)
char buffer[sizeof(value_type)]
LLVM Value Representation.
#define LLVM_ASSUME_ALIGNED(p, a)
\macro LLVM_ASSUME_ALIGNED Returns a pointer with an assumed alignment.
packed_endian_specific_integral & operator&=(value_type newValue)
uint16_t read16be(const void *P)