diff --git a/liba/Makefile b/liba/Makefile index 0abd5ac52..933398b00 100644 --- a/liba/Makefile +++ b/liba/Makefile @@ -67,6 +67,7 @@ liba/src/external/openbsd/s_roundf.o: CFLAGS += -Os endif tests += $(addprefix liba/test/, \ + aeabi.c \ ieee754.c \ stdint.c \ strlcpy.c \ diff --git a/liba/src/aeabi-rt/llsl.c b/liba/src/aeabi-rt/llsl.c index 1a510f689..85b6b0d0c 100644 --- a/liba/src/aeabi-rt/llsl.c +++ b/liba/src/aeabi-rt/llsl.c @@ -1,9 +1,14 @@ /* See the "Run-time ABI for the ARM Architecture", Section 4.2 */ -typedef int uint32_t; +typedef unsigned int uint32_t; long long __aeabi_llsl(long long value, int shift) { uint32_t low = (uint32_t)value << shift; - uint32_t high = ((uint32_t)(value >> 32) << shift) | ((uint32_t)value >> (32 - shift)); + uint32_t high = ((uint32_t)(value >> 32) << shift); + if (shift < 32) { + high |= ((uint32_t)value >> (32 - shift)); + } else { + high |= ((uint32_t)value << (shift - 32)); + } return ((long long)high << 32) | low; } diff --git a/liba/src/aeabi-rt/llsr.c b/liba/src/aeabi-rt/llsr.c index 81c76075a..38c200cce 100644 --- a/liba/src/aeabi-rt/llsr.c +++ b/liba/src/aeabi-rt/llsr.c @@ -1,9 +1,14 @@ /* See the "Run-time ABI for the ARM Architecture", Section 4.2 */ -typedef int uint32_t; +typedef unsigned int uint32_t; long long __aeabi_llsr(long long value, int shift) { - uint32_t low = ((uint32_t)value >> shift) | ((uint32_t)(value >> 32) << (32 - shift)); - uint32_t high = (uint32_t)value >> shift; + uint32_t low = ((uint32_t)value >> shift); + if (shift < 32) { + low |= ((uint32_t)(value >> 32) << (32 - shift)); + } else { + low |= ((uint32_t)(value >> 32) >> (shift - 32)); + } + uint32_t high = (uint32_t)(value >> 32) >> shift; return ((long long)high << 32) | low; } diff --git a/liba/test/aeabi.c b/liba/test/aeabi.c new file mode 100644 index 000000000..d4fc48aa3 --- /dev/null +++ b/liba/test/aeabi.c @@ -0,0 +1,42 @@ +#include +#include +#include + +long long __aeabi_llsl(long long value, int shift); +long long __aeabi_llsr(long long value, int shift); + +QUIZ_CASE(liba_llsl) { + assert(__aeabi_llsl((uint64_t)1, 1) == (uint64_t)0x2); + assert(__aeabi_llsl((uint64_t)1, 2) == (uint64_t)0x4); + assert(__aeabi_llsl((uint64_t)1, 10) == (uint64_t)0x400); + assert(__aeabi_llsl((uint64_t)1, 20) == (uint64_t)0x100000); + assert(__aeabi_llsl((uint64_t)1, 30) == (uint64_t)0x40000000); + assert(__aeabi_llsl((uint64_t)1, 31) == (uint64_t)0x80000000); + assert(__aeabi_llsl((uint64_t)1, 32) == (uint64_t)0x100000000); + assert(__aeabi_llsl((uint64_t)1, 33) == (uint64_t)0x200000000); + assert(__aeabi_llsl((uint64_t)1, 40) == (uint64_t)0x10000000000); + assert(__aeabi_llsl((uint64_t)1, 50) == (uint64_t)0x4000000000000); + assert(__aeabi_llsl((uint64_t)1, 60) == (uint64_t)0x1000000000000000); + assert(__aeabi_llsl((uint64_t)1, 61) == (uint64_t)0x2000000000000000); + assert(__aeabi_llsl((uint64_t)1, 62) == (uint64_t)0x4000000000000000); + assert(__aeabi_llsl((uint64_t)1, 63) == (uint64_t)0x8000000000000000); + assert(__aeabi_llsl((uint64_t)1, 64) == (uint64_t)0); +} + +QUIZ_CASE(liba_llsr) { + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 1) == (uint64_t)0x4000000000000000); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 2) == (uint64_t)0x2000000000000000); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 10) == (uint64_t)0x20000000000000); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 20) == (uint64_t)0x80000000000); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 30) == (uint64_t)0x200000000); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 31) == (uint64_t)0x100000000); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 32) == (uint64_t)0x80000000); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 33) == (uint64_t)0x40000000); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 40) == (uint64_t)0x800000); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 50) == (uint64_t)0x2000); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 60) == (uint64_t)0x8); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 61) == (uint64_t)0x4); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 62) == (uint64_t)0x2); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 63) == (uint64_t)0x1); + assert(__aeabi_llsr((uint64_t)0x8000000000000000, 64) == (uint64_t)0); +}