Using a variable that is declared "const" for this tells the compiler that it may read the value once and assume that it does not change across function calls.
For target_page_size, this means we have only one assert per function, and one read of the variable. This reduces the size of qemu-system-aarch64 by 8k. Reviewed-by: Paolo Bonzini <pbonz...@redhat.com> Signed-off-by: Richard Henderson <richard.hender...@linaro.org> --- include/exec/cpu-all.h | 10 +++++---- exec-vary.c | 46 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index e0c8dc540c..a53b761b48 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -210,10 +210,12 @@ static inline void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val /* page related stuff */ #ifdef TARGET_PAGE_BITS_VARY -extern bool target_page_bits_decided; -extern int target_page_bits; -#define TARGET_PAGE_BITS ({ assert(target_page_bits_decided); \ - target_page_bits; }) +typedef struct { + bool decided; + int bits; +} TargetPageBits; +extern const TargetPageBits target_page; +#define TARGET_PAGE_BITS (assert(target_page.decided), target_page.bits) #else #define TARGET_PAGE_BITS_MIN TARGET_PAGE_BITS #endif diff --git a/exec-vary.c b/exec-vary.c index 48c0ab306c..67cdf57a9c 100644 --- a/exec-vary.c +++ b/exec-vary.c @@ -22,8 +22,38 @@ #include "exec/exec-all.h" #ifdef TARGET_PAGE_BITS_VARY -int target_page_bits; -bool target_page_bits_decided; +/* + * We want to declare the "target_page" variable as const, which tells + * the compiler that it can cache any value that it reads across calls. + * This avoids multiple assertions and multiple reads within any one user. + * + * This works because we initialize the target_page data very early, in a + * location far removed from the functions that require the final results. + * + * This also requires that we have a non-constant symbol by which we can + * perform the actual initialization, and which forces the data to be + * allocated within writable memory. Thus "init_target_page", and we use + * that symbol exclusively in the two functions that initialize this value. + * + * The "target_page" symbol is created as an alias of "init_target_page". + */ +static TargetPageBits init_target_page; + +/* + * Note that this is *not* a redundant decl, this is the definition of + * the "target_page" symbol. The syntax for this definition requires + * the use of the extern keyword. This seems to be a GCC bug in + * either the syntax for the alias attribute or in -Wredundant-decls. + * + * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91765 + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" + +extern const TargetPageBits target_page + __attribute__((alias("init_target_page"))); + +#pragma GCC diagnostic pop #endif bool set_preferred_target_page_bits(int bits) @@ -36,11 +66,11 @@ bool set_preferred_target_page_bits(int bits) */ #ifdef TARGET_PAGE_BITS_VARY assert(bits >= TARGET_PAGE_BITS_MIN); - if (target_page_bits == 0 || target_page_bits > bits) { - if (target_page_bits_decided) { + if (init_target_page.bits == 0 || init_target_page.bits > bits) { + if (init_target_page.decided) { return false; } - target_page_bits = bits; + init_target_page.bits = bits; } #endif return true; @@ -49,9 +79,9 @@ bool set_preferred_target_page_bits(int bits) void finalize_target_page_bits(void) { #ifdef TARGET_PAGE_BITS_VARY - if (target_page_bits == 0) { - target_page_bits = TARGET_PAGE_BITS_MIN; + if (init_target_page.bits == 0) { + init_target_page.bits = TARGET_PAGE_BITS_MIN; } - target_page_bits_decided = true; + init_target_page.decided = true; #endif } -- 2.17.1