aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/i386
diff options
context:
space:
mode:
authorRoger Sayle <roger@nextmovesoftware.com>2021-12-18 13:47:52 +0000
committerRoger Sayle <roger@nextmovesoftware.com>2021-12-18 13:47:52 +0000
commite742722f76c70be303248da7ca4842198d4fd1cc (patch)
treecaf44d6eb01f547b4cb58c4d158ddc475bfe4971 /gcc/config/i386
parentcc032ec1ecb34b006f42e170ccb9d76aa42fd8eb (diff)
downloadgcc-e742722f76c70be303248da7ca4842198d4fd1cc.zip
gcc-e742722f76c70be303248da7ca4842198d4fd1cc.tar.gz
gcc-e742722f76c70be303248da7ca4842198d4fd1cc.tar.bz2
PR target/32803: Add -Oz option for improved clang compatibility.
This patch adds support for an -Oz command line option, aggressively optimizing for size at the expense of performance. GCC's current -Os provides a reasonable balance of size and performance, whereas -Oz is probably only useful for code size benchmarks such as CSiBE. Or so I thought until I read in https://news.ycombinator.com/item?id=25408853 that clang's -Oz sometimes outperforms -O[23s]; I suspect modern instruction decode stages can treat "pushq $1; popq %rax" as a short uop encoding. Instead of introducing a new global variable, this patch simply abuses the existing optimize_size by setting its value to 2. The only change in behaviour is the tweak to the i386 backend implementing the suggestion in PR target/32803 to use a short push/pop sequence for loading small immediate values (-128..127) on x86, matching the behaviour of LLVM. On x86_64, the simple function: int foo() { return 25; } currently generates with -Os: foo: movl $25, %eax // 5 bytes ret With the proposed -Oz, it generates: foo: pushq $25 // 2 bytes popq %rax // 1 byte ret On CSiBE, this results in a 0.94% improvement (3703513 bytes total down to 3668516 bytes). 2021-12-18 Roger Sayle <roger@nextmovesoftware.com> gcc/ChangeLog PR target/32803 * common.opt (Oz): New command line option. * doc/invoke.texi: Document the new -Oz option. * lto-wrapper.c (merge_and_complain, append_compiler_options): Treat OPT_Oz as synonymous with OPT_Os. * optc-save-gen.awk: Increase maximum value of optimize_size to 2. * opts.c (default_options_optimization) [OPT_Oz]: Handle OPT_Oz just like OPT_Os, except set opt->x_optimize_size to 2. (common_handle_option): Skip OPT_Oz just like OPT_Os. * config/i386/i386.md (*movdi_internal): Use a push/pop sequence for suitable SImode TYPE_IMOV moves when optimize_size > 1. (*movsi_internal): Likewise. gcc/testsuite/ChangeLog PR target/32803 * gcc.target/i386/pr32803.c: New test case.
Diffstat (limited to 'gcc/config/i386')
-rw-r--r--gcc/config/i386/i386.md17
1 files changed, 16 insertions, 1 deletions
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index f6d9c4b..862d933 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -2213,7 +2213,14 @@
case TYPE_IMOV:
gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1]));
if (get_attr_mode (insn) == MODE_SI)
- return "mov{l}\t{%k1, %k0|%k0, %k1}";
+ {
+ if (optimize_size > 1
+ && TARGET_64BIT
+ && CONST_INT_P (operands[1])
+ && IN_RANGE (INTVAL (operands[1]), -128, 127))
+ return "push{q}\t%1\n\tpop{q}\t%0";
+ return "mov{l}\t{%k1, %k0|%k0, %k1}";
+ }
else if (which_alternative == 4)
return "movabs{q}\t{%1, %0|%0, %1}";
else if (ix86_use_lea_for_mov (insn, operands))
@@ -2431,6 +2438,14 @@
gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1]));
if (ix86_use_lea_for_mov (insn, operands))
return "lea{l}\t{%E1, %0|%0, %E1}";
+ else if (optimize_size > 1
+ && CONST_INT_P (operands[1])
+ && IN_RANGE (INTVAL (operands[1]), -128, 127))
+ {
+ if (TARGET_64BIT)
+ return "push{q}\t%1\n\tpop{q}\t%q0";
+ return "push{l}\t%1\n\tpop{l}\t%0";
+ }
else
return "mov{l}\t{%1, %0|%0, %1}";