From 55560bf382158dcc7d6cb1b4cbebca4e83da7785 Mon Sep 17 00:00:00 2001 From: kai Date: Mon, 21 Jan 2013 08:41:21 +0100 Subject: [PATCH] Make frontend endian-aware. In many parts the DMD frontend assumes a little endian CPU. In some parts there are checks for endianess but they are incomplete and the used definition is wrong. (Test for endianess will be removed in dmd 2.062.) In this commit I add the required #if's and also add a CMake test for endianess because there is no single compiler definition to check for. --- CMakeLists.txt | 13 +++++++++++++ dmd2/constfold.c | 27 +++++++++++++++++++++++++++ dmd2/interpret.c | 18 ++++++++++++++++++ dmd2/module.c | 38 ++++++++++++++++++++++++++++++++++++++ dmd2/root/stringtable.c | 25 +++++++++++++++++++++++++ 5 files changed, 121 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index fadc83d5..280979f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -278,6 +278,19 @@ else() set(EXTRA_CXXFLAGS "-fexceptions") endif() +# +# Check endianess. +# There is no realiable way to delegate the work to the compiler. +# E.g. gcc up to version 4.6 defines __LITTLE_ENDIAN, but not 4.7 +# +include(TestBigEndian) +test_big_endian(BIGENDIAN) +if(${BIGENDIAN}) + add_definitions(-D__BIG_ENDIAN__) +else() + add_definitions(-D__LITTLE_ENDIAN__) +endif() + # # Set up the main ldc/ldc2 target. # diff --git a/dmd2/constfold.c b/dmd2/constfold.c index b114885e..8d60920a 100644 --- a/dmd2/constfold.c +++ b/dmd2/constfold.c @@ -1628,7 +1628,16 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) size_t len = (t->ty == tn->ty) ? 1 : utf_codeLength(sz, v); s = mem.malloc((len + 1) * sz); if (t->ty == tn->ty) +#if IN_LLVM +#if __LITTLE_ENDIAN__ memcpy((unsigned char *)s, &v, sz); +#else + memcpy((unsigned char *)s, + (unsigned char *)&v + (sizeof(dinteger_t) - sz), sz); +#endif +#else + memcpy((unsigned char *)s, &v, sz); +#endif else utf_encode(sz, s, v); @@ -1752,7 +1761,16 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) s = mem.malloc((len + 1) * sz); memcpy(s, es1->string, es1->len * sz); if (homoConcat) +#if IN_LLVM +#if __LITTLE_ENDIAN__ memcpy((unsigned char *)s + (sz * es1->len), &v, sz); +#else + memcpy((unsigned char *)s + (sz * es1->len), + (unsigned char *)&v + (sizeof(dinteger_t) - sz), sz); +#endif +#else + memcpy((unsigned char *)s + (sz * es1->len), &v, sz); +#endif else utf_encode(sz, (unsigned char *)s + (sz * es1->len), v); @@ -1776,7 +1794,16 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) dinteger_t v = e1->toInteger(); s = mem.malloc((len + 1) * sz); +#if IN_LLVM +#if __LITTLE_ENDIAN__ memcpy((unsigned char *)s, &v, sz); +#else + memcpy((unsigned char *)s, + (unsigned char *)&v + (sizeof(dinteger_t) - sz), sz); +#endif +#else + memcpy((unsigned char *)s, &v, sz); +#endif memcpy((unsigned char *)s + sz, es2->string, es2->len * sz); // Add terminating 0 diff --git a/dmd2/interpret.c b/dmd2/interpret.c index b213d624..8627f24f 100644 --- a/dmd2/interpret.c +++ b/dmd2/interpret.c @@ -990,7 +990,16 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) if (es2e->op != TOKint64) return EXP_CANT_INTERPRET; dinteger_t v = es2e->toInteger(); +#if IN_LLVM +#if __LITTLE_ENDIAN__ memcpy((unsigned char *)s + i * sz, &v, sz); +#else + memcpy((unsigned char *)s + i * sz, + (unsigned char *)&v + (sizeof(dinteger_t) - sz), sz); +#endif +#else + memcpy((unsigned char *)s + i * sz, &v, sz); +#endif } // Add terminating 0 @@ -1020,7 +1029,16 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) if (es2e->op != TOKint64) return EXP_CANT_INTERPRET; dinteger_t v = es2e->toInteger(); +#if IN_LLVM +#if __LITTLE_ENDIAN__ memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz); +#else + memcpy((unsigned char *)s + (es1->len + i) * sz, + (unsigned char *) &v + (sizeof(dinteger_t) - sz), sz); +#endif +#else + memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz); +#endif } // Add terminating 0 diff --git a/dmd2/module.c b/dmd2/module.c index 4d363c9d..cbc281f4 100644 --- a/dmd2/module.c +++ b/dmd2/module.c @@ -544,20 +544,46 @@ bool Module::read(Loc loc) inline unsigned readwordLE(unsigned short *p) { +#if IN_LLVM +#if __LITTLE_ENDIAN__ + return *p; +#else + return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0]; +#endif +#else #if LITTLE_ENDIAN return *p; #else return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0]; #endif +#endif } inline unsigned readwordBE(unsigned short *p) { +#if IN_LLVM +#if __BIG_ENDIAN__ + return *p; +#else return (((unsigned char *)p)[0] << 8) | ((unsigned char *)p)[1]; +#endif +#else + return (((unsigned char *)p)[0] << 8) | ((unsigned char *)p)[1]; +#endif } inline unsigned readlongLE(unsigned *p) { +#if IN_LLVM +#if __LITTLE_ENDIAN__ + return *p; +#else + return ((unsigned char *)p)[0] | + (((unsigned char *)p)[1] << 8) | + (((unsigned char *)p)[2] << 16) | + (((unsigned char *)p)[3] << 24); +#endif +#else #if LITTLE_ENDIAN return *p; #else @@ -566,14 +592,26 @@ inline unsigned readlongLE(unsigned *p) (((unsigned char *)p)[2] << 16) | (((unsigned char *)p)[3] << 24); #endif +#endif } inline unsigned readlongBE(unsigned *p) { +#if IN_LLVM +#if __BIG_ENDIAN__ + return *p; +#else return ((unsigned char *)p)[3] | (((unsigned char *)p)[2] << 8) | (((unsigned char *)p)[1] << 16) | (((unsigned char *)p)[0] << 24); +#endif +#else + return ((unsigned char *)p)[3] | + (((unsigned char *)p)[2] << 8) | + (((unsigned char *)p)[1] << 16) | + (((unsigned char *)p)[0] << 24); +#endif } #if IN_LLVM diff --git a/dmd2/root/stringtable.c b/dmd2/root/stringtable.c index 58dcd0b6..edb68c86 100644 --- a/dmd2/root/stringtable.c +++ b/dmd2/root/stringtable.c @@ -35,29 +35,54 @@ hash_t calcHash(const char *str, size_t len) case 2: hash *= 37; +#if IN_LLVM +#if __LITTLE_ENDIAN__ + hash += *(const uint16_t *)str; +#else + hash += str[0] * 256 + str[1]; +#endif +#else #if LITTLE_ENDIAN hash += *(const uint16_t *)str; #else hash += str[0] * 256 + str[1]; +#endif #endif return hash; case 3: hash *= 37; +#if IN_LLVM +#if __LITTLE_ENDIAN__ + hash += (*(const uint16_t *)str << 8) + + ((const uint8_t *)str)[2]; +#else + hash += (str[0] * 256 + str[1]) * 256 + str[2]; +#endif +#else #if LITTLE_ENDIAN hash += (*(const uint16_t *)str << 8) + ((const uint8_t *)str)[2]; #else hash += (str[0] * 256 + str[1]) * 256 + str[2]; +#endif #endif return hash; default: hash *= 37; +#if IN_LLVM +#if __LITTLE_ENDIAN__ + hash += *(const uint32_t *)str; +#else + hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; +#endif +#else #if LITTLE_ENDIAN hash += *(const uint32_t *)str; #else hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; +#endif #endif str += 4; len -= 4;