remove unaligned write for #ifdef i386 (it was technically undefined

behavior and the compiler is now smart enough to turn the more elaborate
code into a single store)
master
leitner 11 months ago
parent a71f28fe6c
commit 0dbac6ba02

@ -1,8 +1,8 @@
#include <assert.h> #include <assert.h>
#include <uint16.h> #include <libowfat/uint16.h>
#include <uint32.h> #include <libowfat/uint32.h>
#include <uint64.h> #include <libowfat/uint64.h>
#include <byte.h> #include <libowfat/byte.h>
int main() { int main() {
char buf[8]; char buf[8];
@ -11,36 +11,38 @@ int main() {
uint16 a; uint16 a;
buf[0]=buf[1]=0; buf[0]=buf[1]=0;
uint16_pack_big(buf,0x1234); uint16_pack_big(buf,0xabcd);
assert(buf[0]==0x12 && buf[1]==0x34); assert((unsigned char)buf[0]==0xab && (unsigned char)buf[1]==0xcd);
uint16_unpack_big(buf,&a); uint16_unpack_big(buf,&a);
assert(a==0x1234); assert(a==0xabcd);
assert(uint16_read_big(buf)==0x1234); assert(uint16_read_big(buf)==0xabcd);
buf[0]=buf[1]=0; buf[0]=buf[1]=0;
uint16_pack(buf,0x1234); uint16_pack(buf,0xabcd);
assert(buf[0]==0x34 && buf[1]==0x12); assert((unsigned char)buf[0]==0xcd && (unsigned char)buf[1]==0xab);
uint16_unpack(buf,&a); uint16_unpack(buf,&a);
assert(a==0x1234); assert(a==0xabcd);
assert(uint16_read(buf)==0x1234); assert(uint16_read(buf)==0xabcd);
} }
{ {
uint32 a; uint32 a;
buf[0]=buf[1]=buf[2]=buf[3]=0; buf[0]=buf[1]=buf[2]=buf[3]=0;
uint32_pack_big(buf,0x12345678); uint32_pack_big(buf,0x89abcdef);
assert(buf[0]==0x12 && buf[1]==0x34 && buf[2]==0x56 && buf[3]==0x78); assert((unsigned char)buf[0]==0x89 && (unsigned char)buf[1]==0xab &&
(unsigned char)buf[2]==0xcd && (unsigned char)buf[3]==0xef);
uint32_unpack_big(buf,&a); uint32_unpack_big(buf,&a);
assert(a==0x12345678); assert(a==0x89abcdef);
assert(uint32_read_big(buf)==0x12345678); assert(uint32_read_big(buf)==0x89abcdef);
buf[0]=buf[1]=buf[2]=buf[3]=0; buf[0]=buf[1]=buf[2]=buf[3]=0;
uint32_pack(buf,0x12345678); uint32_pack(buf,0x89abcdef);
assert(buf[0]==0x78 && buf[1]==0x56 && buf[2]==0x34 && buf[3]==0x12); assert((unsigned char)buf[3]==0x89 && (unsigned char)buf[2]==0xab &&
(unsigned char)buf[1]==0xcd && (unsigned char)buf[0]==0xef);
uint32_unpack(buf,&a); uint32_unpack(buf,&a);
assert(a==0x12345678); assert(a==0x89abcdef);
assert(uint32_read(buf)==0x12345678); assert(uint32_read(buf)==0x89abcdef);
} }
{ {
@ -48,18 +50,18 @@ int main() {
unsigned int i; unsigned int i;
byte_zero(buf,sizeof(buf)); byte_zero(buf,sizeof(buf));
uint64_pack_big(buf,0x0102030405060708ull); uint64_pack_big(buf,0x8182838485868788ull);
for (i=0; i<8; ++i) assert(buf[i]==i+1); for (i=0; i<8; ++i) assert((unsigned char)buf[i]==i+0x81);
uint64_unpack_big(buf,&a); uint64_unpack_big(buf,&a);
assert(a==0x0102030405060708ull); assert(a==0x8182838485868788ull);
assert(uint64_read_big(buf)==0x0102030405060708ull); assert(uint64_read_big(buf)==0x8182838485868788ull);
byte_zero(buf,sizeof(buf)); byte_zero(buf,sizeof(buf));
uint64_pack(buf,0x0102030405060708ull); uint64_pack(buf,0x8182838485868788ull);
for (i=0; i<8; ++i) assert(buf[7-i]==i+1); for (i=0; i<8; ++i) assert((unsigned char)buf[7-i]==i+0x81);
uint64_unpack(buf,&a); uint64_unpack(buf,&a);
assert(a==0x0102030405060708ull); assert(a==0x8182838485868788ull);
assert(uint64_read(buf)==0x0102030405060708ull); assert(uint64_read(buf)==0x8182838485868788ull);
} }

@ -14,42 +14,42 @@ typedef int16_t int16;
#if (defined(__i386__) || defined(__x86_64__)) && !defined(NO_UINT16_MACROS) #if (defined(__i386__) || defined(__x86_64__)) && !defined(NO_UINT16_MACROS)
/* On x86 and x64 unaligned access are OK and the compiler knows it and
* will collapse this long-looking code into a single load or store
* instruction, so turn it into inline functions */
static inline void uint16_pack(char* out,uint16 in) { static inline void uint16_pack(char* out,uint16 in) {
*(uint16*)out=in; out[0]=in;
out[1]=in>>8;
} }
static inline void uint16_unpack(const char *in,uint16* out) { static inline void uint16_unpack(const char *in,uint16* out) {
*out=*(const uint16*)in; const unsigned char* i = (const unsigned char*)in;
*out=i[0] | (i[1]<<8);
} }
static inline uint16 uint16_read(const char* in) { static inline uint16 uint16_read(const char* in) {
return *(const uint16*)in; const unsigned char* i = (const unsigned char*)in;
return i[0] | (i[1]<<8);
} }
#if defined(__x86_64__) && defined(__GNUC__)
static inline void uint16_pack_big(char* out,uint16 in) { static inline void uint16_pack_big(char* out,uint16 in) {
*(uint16*)out=__builtin_bswap16(in); out[0]=in>>8;
out[1]=in;
} }
static inline void uint16_unpack_big(const char in[2],uint16* out) { static inline void uint16_unpack_big(const char *in,uint16* out) {
*out=__builtin_bswap16(*(const uint16*)in); const unsigned char* i = (const unsigned char*)in;
*out=(i[0]<<8) | i[1];
} }
static inline uint16 uint16_read_big(const char in[2]) { static inline uint16 uint16_read_big(const char* in) {
return __builtin_bswap16(*(const uint16*)in); const unsigned char* i = (const unsigned char*)in;
return (i[0]<<8) | i[1];
} }
#else #else
void uint16_pack_big(char *out,uint16 in);
void uint16_unpack_big(const char *in,uint16* out);
uint16 uint16_read_big(const char *in);
#endif
#else
void uint16_pack(char *out,uint16 in); void uint16_pack(char *out,uint16 in);
void uint16_pack_big(char *out,uint16 in); void uint16_pack_big(char *out,uint16 in);
void uint16_unpack(const char *in,uint16* out); void uint16_unpack(const char *in,uint16* out);

@ -14,42 +14,46 @@ typedef int32_t int32;
#if (defined(__i386__) || defined(__x86_64__)) && !defined(NO_UINT32_MACROS) #if (defined(__i386__) || defined(__x86_64__)) && !defined(NO_UINT32_MACROS)
/* On x86 and x64 unaligned access are OK and the compiler knows it and
* will collapse this long-looking code into a single load or store
* instruction, so turn it into inline functions */
static inline void uint32_pack(char* out,uint32 in) { static inline void uint32_pack(char* out,uint32 in) {
*(uint32*)out=in; out[0]=in;
out[1]=in>>8;
out[2]=in>>16;
out[3]=in>>24;
} }
static inline void uint32_unpack(const char *in,uint32* out) { static inline void uint32_unpack(const char *in,uint32* out) {
*out=*(const uint32*)in; const unsigned char* i = (const unsigned char*)in;
*out=i[0] | (i[1]<<8) | (i[2]<<16) | (i[3]<<24);
} }
static inline uint32 uint32_read(const char* in) { static inline uint32 uint32_read(const char* in) {
return *(const uint32*)in; const unsigned char* i = (const unsigned char*)in;
return i[0] | (i[1]<<8) | (i[2]<<16) | (i[3]<<24);
} }
#if defined(__x86_64__) && defined(__GNUC__)
static inline void uint32_pack_big(char *out,uint32 in) { static inline void uint32_pack_big(char *out,uint32 in) {
*(uint32*)out=__builtin_bswap32(in); out[0]=in>>24;
out[1]=in>>16;
out[2]=in>>8;
out[3]=in;
} }
static inline void uint32_unpack_big(const char *in,uint32* out) { static inline void uint32_unpack_big(const char *in,uint32* out) {
*out=__builtin_bswap32(*(const uint32*)in); const unsigned char* i = (const unsigned char*)in;
*out=(i[0]<<24) | (i[1]<<16) | (i[2]<<8) | i[3];
} }
static inline uint32 uint32_read_big(const char *in) { static inline uint32 uint32_read_big(const char *in) {
return __builtin_bswap32(*(const uint32*)in); const unsigned char* i = (const unsigned char*)in;
return (i[0]<<24) | (i[1]<<16) | (i[2]<<8) | i[3];
} }
#else #else
void uint32_pack_big(char *out,uint32 in);
void uint32_unpack_big(const char *in,uint32* out);
uint32 uint32_read_big(const char *in);
#endif
#else
void uint32_pack(char *out,uint32 in); void uint32_pack(char *out,uint32 in);
void uint32_pack_big(char *out,uint32 in); void uint32_pack_big(char *out,uint32 in);
void uint32_unpack(const char *in,uint32* out); void uint32_unpack(const char *in,uint32* out);

@ -13,12 +13,61 @@ typedef uint64_t uint64;
typedef int64_t int64; typedef int64_t int64;
#if (defined(__i386__) || defined(__x86_64__)) && !defined(NO_UINT64_MACROS) #if (defined(__i386__) || defined(__x86_64__)) && !defined(NO_UINT64_MACROS)
#define uint64_pack(out,in) (*(uint64*)(out)=(in))
#define uint64_unpack(in,out) (*(out)=*(uint64*)(in)) /* On x86 and x64 unaligned access are OK and the compiler knows it and
#define uint64_read(in) (*(uint64*)(in)) * will collapse this long-looking code into a single load or store
void uint64_pack_big(char *out,uint64 in); * instruction, so turn it into inline functions */
void uint64_unpack_big(const char *in,uint64* out);
uint64 uint64_read_big(const char *in); static inline void uint64_pack(char* out,uint64 in) {
out[0]=in;
out[1]=in>>8;
out[2]=in>>16;
out[3]=in>>24;
out[4]=in>>32;
out[5]=in>>40;
out[6]=in>>48;
out[7]=in>>56;
}
static inline void uint64_unpack(const char *in,uint64* out) {
const unsigned char* i = (const unsigned char*)in;
*out=i[0] | (i[1]<<8) | (i[2]<<16) | ((uint64)i[3]<<24) |
((uint64)i[4]<<32) | ((uint64)i[5]<<40) |
((uint64)i[6]<<48) | ((uint64)i[7]<<56);
}
static inline uint64 uint64_read(const char *in) {
const unsigned char* i = (const unsigned char*)in;
return i[0] | (i[1]<<8) | (i[2]<<16) | ((uint64)i[3]<<24) |
((uint64)i[4]<<32) | ((uint64)i[5]<<40) |
((uint64)i[6]<<48) | ((uint64)i[7]<<56);
}
static inline void uint64_pack_big(char *out,uint64 in) {
out[0]=in>>56;
out[1]=in>>48;
out[2]=in>>40;
out[3]=in>>32;
out[4]=in>>24;
out[5]=in>>16;
out[6]=in>>8;
out[7]=in;
}
static inline void uint64_unpack_big(const char *in,uint64* out) {
const unsigned char* i = (const unsigned char*)in;
*out=(i[7] | (i[6]<<8) | (i[5]<<16) | ((uint64)(i[4])<<24)) |
((uint64)(i[3])<<32) | ((uint64)(i[2])<<40) |
((uint64)(i[1])<<48) | ((uint64)(i[0])<<56);
}
static inline uint64 uint64_read_big(const char *in) {
const unsigned char* i = (const unsigned char*)in;
return (i[7] | (i[6]<<8) | (i[5]<<16) | ((uint64)(i[4])<<24)) |
((uint64)(i[3])<<32) | ((uint64)(i[2])<<40) |
((uint64)(i[1])<<48) | ((uint64)(i[0])<<56);
}
#else #else
void uint64_pack(char *out,uint64 in); void uint64_pack(char *out,uint64 in);

Loading…
Cancel
Save