From: Vineet Gupta <vineetg@rivosinc.com>
To: gcc-patches@gcc.gnu.org
Cc: Jeff Law <jeffreyalaw@gmail.com>,
kito.cheng@gmail.com, Palmer Dabbelt <palmer@rivosinc.com>,
gnu-toolchain@rivosinc.com, Robin Dapp <rdapp.gcc@gmail.com>,
Vineet Gupta <vineetg@rivosinc.com>
Subject: [gcc-15 1/3] RISC-V: avoid LUI based const materialization ... [part of PR/106265]
Date: Sat, 16 Mar 2024 10:35:22 -0700 [thread overview]
Message-ID: <20240316173524.1147760-2-vineetg@rivosinc.com> (raw)
In-Reply-To: <20240316173524.1147760-1-vineetg@rivosinc.com>
... if the constant can be represented as sum of two S12 values.
The two S12 values could instead be fused with subsequent ADD insn.
The helps
- avoid an additional LUI insn
- side benefits of not clobbering a reg
e.g.
w/o patch w/ patch
long | |
plus(unsigned long i) | li a5,4096 |
{ | addi a5,a5,-2032 | addi a0, a0, 2047
return i + 2064; | add a0,a0,a5 | addi a0, a0, 17
} | ret | ret
NOTE: In theory not having const in a standalone reg might seem less
CSE friendly, but for workloads in consideration these mat are
from very late LRA reloads and follow on GCSE is not doing much
currently.
The real benefit however is seen in base+offset computation for array
accesses and especially for stack accesses which are finalized late in
optim pipeline, during LRA register allocation. Often the finalized
offsets trigger LRA reloads resulting in mind boggling repetition of
exact same insn sequence including LUI based constant materialization.
This shaves off 290 billion dynamic instrustions (QEMU icounts) in
SPEC 2017 Cactu benchmark which is over 10% of workload. In the rest of
suite, there additional 10 billion shaved, with both gains and losses
in indiv workloads as is usual with compiler changes.
1,214,172,747,858 | 1,212,530,889,930 | 0.14% <-
740,618,658,160 | 739,515,555,243 | 0.15% <-
692,128,469,436 | 691,175,291,593 | 0.14% <-
190,811,495,310 | 190,854,437,311 | -0.02%
225,751,808,189 | 225,818,881,019 | -0.03%
220,364,237,915 | 220,405,868,038 | -0.02%
179,157,361,261 | 179,186,059,187 | -0.02%
219,313,921,837 | 219,337,232,829 | -0.01%
278,733,265,382 | 278,733,264,380 | 0.00%
442,397,437,578 | 442,397,436,026 | 0.00%
344,112,144,242 | 344,112,142,910 | 0.00%
417,561,390,319 | 417,561,388,877 | 0.00%
669,319,255,911 | 669,318,761,114 | 0.00%
2,852,781,330,203 | 2,564,750,360,011 | 10.10% <--
1,855,884,349,001 | 1,855,881,122,280 | 0.00%
1,653,856,904,409 | 1,653,733,205,926 | 0.01%
2,974,347,350,401 | 2,974,174,999,505 | 0.01%
1,158,337,609,995 | 1,158,337,608,826 | 0.00%
1,021,799,191,806 | 1,021,425,634,319 | 0.04%
1,716,448,413,824 | 1,714,912,501,736 | 0.09%
849,330,283,510 | 849,321,128,484 | 0.00%
276,556,968,005 | 276,232,659,282 | 0.12% <-
913,352,953,686 | 912,822,592,719 | 0.06%
903,792,550,116 | 903,107,637,917 | 0.08%
1,654,904,617,482 | 1,655,327,175,238 | -0.03%
1,495,841,421,311 | 1,493,418,761,599 | 0.16% <-
1,641,969,530,523 | 1,642,126,596,979 | -0.01%
2,546,170,307,385 | 2,546,151,690,122 | 0.00%
1,983,551,321,388 | 1,983,525,296,345 | 0.00%
1,516,077,036,742 | 1,516,076,833,481 | 0.00%
2,055,868,055,165 | 2,055,865,373,175 | 0.00%
1,000,621,723,807 | 1,000,601,360,859 | 0.00%
1,024,149,313,694 | 1,024,127,472,779 | 0.00%
363,827,037,541 | 363,057,012,239 | 0.21% <-
906,649,110,459 | 905,928,886,712 | 0.08%
509,023,896,044 | 508,140,354,911 | 0.17% <-
403,238,430 | 403,238,485 | 0.00%
403,238,430 | 403,238,485 | 0.00%
This should still be considered damage control as the real/deeper fix
would be to reduce number of LRA reloads or CSE/anchor those during
LRA constraint sub-pass (re)runs.
Implementation Details (for posterity)
--------------------------------------
- basic idea is to have a splitter selected via a new predicate for constant
being possible sum of two S12 and provide the transform.
This is however a 2 -> 2 transform which combine can't handle.
So we specify it using a define_insn_and_split.
- the initial loose "i" constraint caused LRA to accept invalid insns thus
needing a tighter new constraint as well.
- An additional fallback alternate with catch-all "r" register
constraint also needed to allow any "reloads" that LRA might
require for ADDI with const larger than S12.
Testing
--------
This is testsuite clean (rv64 only).
I'll rely on post-commit CI multlib run for any possible fallout for
other setups such as rv32.
| | gcc | g++ | gfortran |
| rv64imafdc_zba_zbb_zbs_zicond/ lp64d/ medlow | 181 / 44 | 4 / 1 | 72 / 12 |
| rv64imafdc_zba_zbb_zbs_zicond/ lp64d/ medlow | 181 / 44 | 4 / 1 | 73 / 13 |
|
I also threw this into a buildroot run, it obviously boots Linux to
userspace. bloat-o-meter on glibc and kernel show overall decrease in
staic instruction counts with some minor spot increases.
These are generally in the category of
- LUI + ADDI are 2 byte each vs. two ADD being 4 byte each.
- Knock on effects due to inlining changes.
- Sometimes the slightly shorter 2-insn seq in a mult-exit function
can cause in-place epilogue duplication (vs. a jump back).
This is slightly larger but more efficient in execution.
In summary nothing to fret about.
| linux/scripts/bloat-o-meter build-gcc-240131/target/lib/libc.so.6 \
build-gcc-240131-new-splitter-1-variant/target/lib/libc.so.6
|
| add/remove: 0/0 grow/shrink: 21/49 up/down: 520/-3056 (-2536)
| Function old new delta
| getnameinfo 2756 2892 +136
...
| tempnam 136 144 +8
| padzero 276 284 +8
...
| __GI___register_printf_specifier 284 280 -4
| __EI_xdr_array 468 464 -4
| try_file_lock 268 260 -8
| pthread_create@GLIBC_2 3520 3508 -12
| __pthread_create_2_1 3520 3508 -12
...
| _nss_files_setnetgrent 932 904 -28
| _nss_dns_gethostbyaddr2_r 1524 1480 -44
| build_trtable 3312 3208 -104
| printf_positional 25000 22580 -2420
| Total: Before=2107999, After=2105463, chg -0.12%
gcc/ChangeLog:
PR target/106265 (partially)
* config/riscv/riscv.h: New macros to check for sum of two S12
range.
* config/riscv/constraints.md: New constraint.
* config/riscv/predicates.md: New Predicate.
* config/riscv/riscv.md: New splitter to not materialize
constant in desired range.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/sum-of-two-s12-const-1.c: New test: checks for
new patterns output.
* gcc.target/riscv/sum-of-two-s12-const-2.c: New test: should not
ICE.
Signed-off-by: Vineet Gupta <vineetg@rivosinc.com>
---
gcc/config/riscv/constraints.md | 6 +++
gcc/config/riscv/predicates.md | 6 +++
gcc/config/riscv/riscv.h | 15 +++++++
gcc/config/riscv/riscv.md | 34 ++++++++++++++
.../gcc.target/riscv/sum-of-two-s12-const-1.c | 45 +++++++++++++++++++
.../gcc.target/riscv/sum-of-two-s12-const-2.c | 22 +++++++++
6 files changed, 128 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/riscv/sum-of-two-s12-const-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/sum-of-two-s12-const-2.c
diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index 41acaea04eba..435461180c7e 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -80,6 +80,12 @@
(and (match_code "const_int")
(match_test "LUI_OPERAND (ival)")))
+(define_constraint "MiG"
+ "const can be represented as sum of any S12 values."
+ (and (match_code "const_int")
+ (ior (match_test "IN_RANGE (ival, 2048, 4094)")
+ (match_test "IN_RANGE (ival, -4096, -2049)"))))
+
(define_constraint "Ds3"
"@internal
1, 2 or 3 immediate"
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index 6c87a7bd1f49..89490339c2da 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -420,6 +420,12 @@
return true;
})
+(define_predicate "const_two_s12"
+ (match_code "const_int")
+{
+ return SUM_OF_TWO_S12 (INTVAL (op));
+})
+
;; CORE-V Predicates:
(define_predicate "immediate_register_operand"
(ior (match_operand 0 "register_operand")
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index da089a03e9d1..817661058896 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -624,6 +624,21 @@ enum reg_class
(((VALUE) | ((1UL<<31) - IMM_REACH)) == ((1UL<<31) - IMM_REACH) \
|| ((VALUE) | ((1UL<<31) - IMM_REACH)) + IMM_REACH == 0)
+/* True if a VALUE (constant) can be expressed as sum of two S12 constants
+ (in range -2048 to 2047).
+ Range check logic:
+ from: min S12 + 1 (or -1 depending on what side of zero)
+ to: two times the min S12 value (to max out S12 bits). */
+
+#define SUM_OF_TWO_S12_N(VALUE) \
+ (((VALUE) >= (-2048 * 2)) && ((VALUE) <= (-2048 - 1)))
+
+#define SUM_OF_TWO_S12_P(VALUE) \
+ (((VALUE) >= ( 2047 + 1)) && ((VALUE) <= ( 2047 * 2)))
+
+#define SUM_OF_TWO_S12(VALUE) \
+ (SUM_OF_TWO_S12_N (VALUE) || SUM_OF_TWO_S12_P (VALUE))
+
/* If this is a single bit mask, then we can load it with bseti. Special
handling of SImode 0x80000000 on RV64 is done in riscv_build_integer_1. */
#define SINGLE_BIT_MASK_OPERAND(VALUE) \
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index b16ed97909c0..79fe861ef91f 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -751,6 +751,40 @@
[(set_attr "type" "arith")
(set_attr "mode" "DI")])
+;; Special case of adding a reg and constant if latter is sum of two S12
+;; values (in range -2048 to 2047). Avoid materialized the const and fuse
+;; into the add (with an additional add for 2nd value). Makes a 3 insn
+;; sequence into 2 insn.
+
+(define_insn_and_split "*add<mode>3_const_sum_of_two_s12"
+ [(set (match_operand:P 0 "register_operand" "=r,r")
+ (plus:P (match_operand:P 1 "register_operand" " r,r")
+ (match_operand:P 2 "const_two_s12" " MiG,r")))]
+ ""
+ "add %0,%1,%2"
+ ""
+ [(set (match_dup 0)
+ (plus:P (match_dup 1) (match_dup 3)))
+ (set (match_dup 0)
+ (plus:P (match_dup 0) (match_dup 4)))]
+{
+ int val = INTVAL (operands[2]);
+ if (SUM_OF_TWO_S12_P (val))
+ {
+ operands[3] = GEN_INT (2047);
+ operands[4] = GEN_INT (val - 2047);
+ }
+ else if (SUM_OF_TWO_S12_N (val))
+ {
+ operands[3] = GEN_INT (-2048);
+ operands[4] = GEN_INT (val + 2048);
+ }
+ else
+ gcc_unreachable ();
+}
+ [(set_attr "type" "arith")
+ (set_attr "mode" "<P:MODE>")])
+
(define_expand "addv<mode>4"
[(set (match_operand:GPR 0 "register_operand" "=r,r")
(plus:GPR (match_operand:GPR 1 "register_operand" " r,r")
diff --git a/gcc/testsuite/gcc.target/riscv/sum-of-two-s12-const-1.c b/gcc/testsuite/gcc.target/riscv/sum-of-two-s12-const-1.c
new file mode 100644
index 000000000000..4d6d135de5f5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sum-of-two-s12-const-1.c
@@ -0,0 +1,45 @@
+// TBD: This doesn't quite work for rv32 yet
+/* { dg-do compile } */
+/* { dg-options { -march=rv64gcv -mabi=lp64d } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+/* Ensure that gcc doesn't generate standlone li reg, 4096. */
+long
+plus1(unsigned long i)
+{
+ return i + 2048;
+}
+
+long
+plus2(unsigned long i)
+{
+ return i + 4094;
+}
+
+long
+plus3(unsigned long i)
+{
+ return i + 2064;
+}
+
+/* Ensure that gcc doesn't generate standlone li reg, -4096. */
+long
+minus1(unsigned long i)
+{
+ return i - 4096;
+}
+
+long
+minus2(unsigned long i)
+{
+ return i - 2049;
+}
+
+long
+minus3(unsigned long i)
+{
+ return i - 2064;
+}
+
+/* { dg-final { scan-assembler-not {li\t[a-x0-9]+,-4096} } } */
+/* { dg-final { scan-assembler-not {li\t[a-x0-9]+,4096} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sum-of-two-s12-const-2.c b/gcc/testsuite/gcc.target/riscv/sum-of-two-s12-const-2.c
new file mode 100644
index 000000000000..5dcab52c2610
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sum-of-two-s12-const-2.c
@@ -0,0 +1,22 @@
+/* Reduced version of c-c++-common/torture/builtin-convertvector-1.c. */
+/* This should NOT ICE */
+
+/* { dg-do compile } */
+
+typedef long b __attribute__((vector_size(256 * sizeof(long))));
+typedef double c __attribute__((vector_size(256 * sizeof(double))));
+int d;
+void e(b *f, c *g) { *g = __builtin_convertvector(*f, c); }
+void h() {
+ struct {
+ b i;
+ } j;
+ union {
+ c i;
+ double a[6];
+ } k;
+ e(&j.i, &k.i);
+ if (k.a[d])
+ for (;;)
+ ;
+}
--
2.34.1
next prev parent reply other threads:[~2024-03-16 17:36 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-16 17:35 [gcc-15 0/3] RISC-V improve stack/array access by constant mat tweak Vineet Gupta
2024-03-16 17:35 ` Vineet Gupta [this message]
2024-03-16 20:28 ` [gcc-15 1/3] RISC-V: avoid LUI based const materialization ... [part of PR/106265] Jeff Law
2024-03-19 0:07 ` Vineet Gupta
2024-03-23 5:59 ` Jeff Law
2024-03-16 17:35 ` [gcc-15 2/3] RISC-V: avoid LUI based const mat: keep stack offsets aligned Vineet Gupta
2024-03-16 20:21 ` Jeff Law
2024-03-19 0:27 ` Vineet Gupta
2024-03-19 6:48 ` Andrew Waterman
2024-03-19 13:10 ` Jeff Law
2024-03-19 20:05 ` Vineet Gupta
2024-03-19 20:58 ` Andrew Waterman
2024-03-19 21:17 ` Palmer Dabbelt
2024-03-20 18:57 ` Jeff Law
2024-03-23 6:05 ` Jeff Law
2024-03-16 17:35 ` [gcc-15 3/3] RISC-V: avoid LUI based const mat in prologue/epilogue expansion [PR/105733] Vineet Gupta
2024-03-16 20:27 ` Jeff Law
2024-03-19 4:41 ` [gcc-15 0/3] RISC-V improve stack/array access by constant mat tweak Jeff Law
2024-03-21 0:45 ` Vineet Gupta
2024-03-21 14:36 ` scheduler queue flush (was Re: [gcc-15 0/3] RISC-V improve stack/array access by constant mat tweak) Vineet Gupta
2024-03-21 14:45 ` Jeff Law
2024-03-21 17:19 ` Vineet Gupta
2024-03-21 19:56 ` Jeff Law
2024-03-22 0:34 ` scheduler queue flush Vineet Gupta
2024-03-22 8:47 ` scheduler queue flush (was Re: [gcc-15 0/3] RISC-V improve stack/array access by constant mat tweak) Richard Biener
2024-03-22 12:29 ` Jeff Law
2024-03-22 16:56 ` Vineet Gupta
2024-03-25 3:05 ` Jeff Law
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240316173524.1147760-2-vineetg@rivosinc.com \
--to=vineetg@rivosinc.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=gnu-toolchain@rivosinc.com \
--cc=jeffreyalaw@gmail.com \
--cc=kito.cheng@gmail.com \
--cc=palmer@rivosinc.com \
--cc=rdapp.gcc@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).