forked from igrr/newlib-xtensa
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support and optimize PROGMEM accesses in libc
Move all the pgmspace.(cpp/h) macros and functions from Arduino IDE into newlib as a first-class citizen. All the mem*_P, str*_P, and *printf_P functions are included in this move, as well as the PROGMEM macro and pgm_read_*. Allow for use of PROGMEM based format and parameter strings in all *printf functions. No need for copying PSTR()s into RAM before printing them out. Add "%S" (capital-S) format that I've been told, but cannot verify, is used in Arduino to specify a PROGMEM string parameter in printfs, as an alias for "%s" since plain "%s" can now handle PROGMEM. PSTR() to 4-byte alignment. This results in an average wasted space of 1.5bytes/string (25% @0, 25%@1, 25%@2, 25%@3 == 1.5) but allows for aligned memcpy_P and str(n)cpy_P performance to go up by 4x to 8x by using 32-bit progmem reads instead of 4 single-byte pgm_read_byte macros (which are many instructions in length, too). Optimized the memcpy_P, strnlen_P, and strncpy_P functions to use 32-bit direct reads whenver possible (source and dest alignment mediated), but there is still room for improvement in others in newlib/lib/sys/xtensa/*.c. str(n)cpy now also transparently supports PROGMEM and RAM, only using the slower PROGMEM version when the source is in PROGMEM. This was due to a GCC optimization: When GCC sees a printf("xxxx") or a printf("%s", "string") it silently optimizes out the printf and replaces it with an appropriate strcpy. So the changes to printf to support PROGMEM wouldn't ever be invoked, and instead GCC silently calls strcpy with both RAM and PSTR strings. Finally, move several constant arrays from RODATA into PROGMEM and update their accessors. Among these are the ctype array, ~260 bytes, mprec* arrays, ~300 bytes, and strings/daycounts in the time formatting functions, ~200 bytes.
- Loading branch information
1 parent
e674369
commit 61f08d0
Showing
38 changed files
with
796 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/* This is a dummy <sys/ctype.h> used as a placeholder for | ||
systems that need to have a special header file. */ | ||
|
||
#include <sys/pgmspace.h> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* PGMSPACE.H - Accessor utilities/types for accessing PROGMEM data */ | ||
|
||
#ifndef _PGMSPACE_H_ | ||
#define _PGMSPACE_H_ | ||
|
||
// These are no-ops in anything but the ESP8266, where they are defined in | ||
// a custom sys/pgmspace.h header | ||
|
||
#ifndef ICACHE_RODATA_ATTR | ||
#define ICACHE_RODATA_ATTR | ||
#endif | ||
|
||
#ifndef PROGMEM | ||
#define PROGMEM | ||
#endif | ||
|
||
#ifndef PGM_P | ||
#define PGM_P | ||
#endif | ||
|
||
#ifndef PGM_VOID_P | ||
#define PGM_VOID_P | ||
#endif | ||
|
||
#ifndef PSTR | ||
#define PSTR | ||
#endif | ||
|
||
#ifdef __cplusplus | ||
#define pgm_read_byte(addr) (*reinterpret_cast<const uint8_t*)(addr)> | ||
#define pgm_read_word(addr) (*reinterpret_cast<const uint16_t*)(addr)> | ||
#define pgm_read_dword(addr) (*reinterpret_cast<const uint32_t*)(addr)> | ||
#define pgm_read_float(addr) (*reinterpret_cast<const float)(addr)> | ||
#define pgm_read_ptr(addr) (*reinterpret_cast<const void const *)(addr)> | ||
#else | ||
#define pgm_read_byte(addr) (*(const uint8_t*)(addr)) | ||
#define pgm_read_word(addr) (*(const uint16_t*)(addr)) | ||
#define pgm_read_dword(addr) (*(const uint32_t*)(addr)) | ||
#define pgm_read_float(addr) (*(const float)(addr)) | ||
#define pgm_read_ptr(addr) (*(const void const *)(addr)) | ||
#endif | ||
|
||
#define pgm_read_byte_near(addr) pgm_read_byte(addr) | ||
#define pgm_read_word_near(addr) pgm_read_word(addr) | ||
#define pgm_read_dword_near(addr) pgm_read_dword(addr) | ||
#define pgm_read_float_near(addr) pgm_read_float(addr) | ||
#define pgm_read_ptr_near(addr) pgm_read_ptr(addr) | ||
#define pgm_read_byte_far(addr) pgm_read_byte(addr) | ||
#define pgm_read_word_far(addr) pgm_read_word(addr) | ||
#define pgm_read_dword_far(addr) pgm_read_dword(addr) | ||
#define pgm_read_float_far(addr) pgm_read_float(addr) | ||
#define pgm_read_ptr_far(addr) pgm_read_ptr(addr) | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* strcpy.c - Xtensa code to determine if source is PMEM or RAM and call appropriate strcpy routine. | ||
GCC is a very smart compiler, and it will, in fact, replace printf(), and its | ||
related functions with strcpy() calls in order to optimize speed. This fails | ||
horribly when printf(PSTR("xxx")) is called since the original strcpy can't | ||
handle the PROGMEM source. | ||
See http://www.ciselant.de/projects/gcc_printf/gcc_printf.html for more info. | ||
There are two ways around this: | ||
- Adding -fno-builtin-*printf, which slows down every printf() call that was | ||
being optimized before. GCC won't replace the printf() call with a strcpy() | ||
call, and everything will work since we now support PROGMEM strings in | ||
printf(). | ||
- Make strcpy smarter and fall back on the appropriate routine depending on | ||
the source parameter. Since on the ESP8266 PROGMEM starts at 0x40000000 | ||
this is a simple comparison. In this case speed will be maintained. | ||
*/ | ||
|
||
#include <string.h> | ||
|
||
extern char *__fast_strcpy(char *dest, const char *src); | ||
char *strcpy(char *dest, const char *src) | ||
{ | ||
if (src >= (const char *)0x40000000) return strcpy_P(dest, src); | ||
else return __fast_strcpy(dest, src); | ||
} | ||
|
||
extern char *__fast_strncpy(char *dest, const char *src, size_t n); | ||
char *strncpy(char *dest, const char *src, size_t n) | ||
{ | ||
if (src >= (const char *)0x40000000) return strncpy_P(dest, src, n); | ||
else return __fast_strncpy(dest, src, n); | ||
} |
Oops, something went wrong.