diff --git a/libstdc++-v3/config/os/newlib/ctype_inline.h b/libstdc++-v3/config/os/newlib/ctype_inline.h index a4714f9bcce..479ceef7191 100644 --- a/libstdc++-v3/config/os/newlib/ctype_inline.h +++ b/libstdc++-v3/config/os/newlib/ctype_inline.h @@ -34,6 +34,26 @@ // ctype bits to be inlined go here. Non-inlinable (ie virtual do_*) // functions go in ctype.cc +#ifndef __ctype__pgm_read_with_offset + +#define __ctype__pgm_read_with_offset(addr, res) \ + asm("extui %0, %1, 0, 2\n" /* Extract offset within word (in bytes) */ \ + "sub %1, %1, %0\n" /* Subtract offset from addr, yielding an aligned address */ \ + "l32i.n %1, %1, 0x0\n" /* Load word from aligned address */ \ + "ssa8l %0\n" /* Prepare to shift by offset (in bits) */ \ + "src %0, %1, %1\n" /* Shift right; now the requested byte is the first one */ \ + :"=r"(res), "=r"(addr) \ + :"1"(addr) \ +:); + +static inline uint8_t __ctype__pgm_read_byte_inlined(const void* addr) { + register uint32_t res; + __ctype__pgm_read_with_offset(addr, res); + return (uint8_t) res; /* This masks the lower byte from the returned word */ +} + +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -41,14 +61,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool ctype:: is(mask __m, char __c) const - { return _M_table[static_cast(__c)] & __m; } + { return __ctype__pgm_read_byte_inlined(&_M_table[static_cast(__c)]) & __m; } const char* ctype:: is(const char* __low, const char* __high, mask* __vec) const { while (__low < __high) - *__vec++ = _M_table[static_cast(*__low++)]; + *__vec++ = __ctype__pgm_read_byte_inlined(&_M_table[static_cast(*__low++)]); return __high; }