This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] RISC-V: Improve li expansion for better code density.
- From: Kito Cheng <kito dot cheng at sifive dot com>
- To: binutils at sourceware dot org, kito dot cheng at gmail dot com, jimw at sifive dot com
- Cc: Kito Cheng <kito dot cheng at sifive dot com>
- Date: Wed, 21 Aug 2019 23:40:17 -0700
- Subject: [PATCH] RISC-V: Improve li expansion for better code density.
li is a pseudo instruction in RISC-V, it might expand to more than one
instructions if the immediate value can’t fit addi or lui, but the
assembler will always using 4-byte instructions during expansion.
For example:
li a0, 0x12345001
will expand into
12345537 lui a0,0x12345
00150513 addi a0,a0,1
but addi could be compress into
0505 addi a0,a0,1
It because load_const use macro_build to emit instructions,
and macro_build call append_insn, and expect it will compress
it if possible, but the fact is append_insn never compress anything,
So this patch redirect the li expansion flow to normal instruction
emission flow via md_assemble, added md_assemblef as an wrapper for
that for easier emit instruction with printf-style argument to build
instruction.
gas/ChangeLog:
* tc-riscv.c (md_assemblef): New.
(load_const) Use md_assemblef instead of macro_build to emit
instructions.
* testsuite/gas/riscv/li32.d: New.
* testsuite/gas/riscv/li32.s: Ditto.
* testsuite/gas/riscv/li64.d: Ditto.
* testsuite/gas/riscv/li64.s: Ditto.
---
gas/config/tc-riscv.c | 47 +++++++++++++++++++++++++++++++++++++-----
gas/testsuite/gas/riscv/li32.d | 17 +++++++++++++++
gas/testsuite/gas/riscv/li32.s | 5 +++++
gas/testsuite/gas/riscv/li64.d | 44 +++++++++++++++++++++++++++++++++++++++
gas/testsuite/gas/riscv/li64.s | 9 ++++++++
5 files changed, 117 insertions(+), 5 deletions(-)
create mode 100644 gas/testsuite/gas/riscv/li32.d
create mode 100644 gas/testsuite/gas/riscv/li32.s
create mode 100644 gas/testsuite/gas/riscv/li64.d
create mode 100644 gas/testsuite/gas/riscv/li64.s
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index f0c1f4c..fb4ce5c 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -928,6 +928,38 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
append_insn (&insn, ep, r);
}
+/* Build an instruction created by a macro expansion. Like md_assemble but
+ accept a printf-style format string and arguments. */
+
+static void
+md_assemblef (const char *format, ...)
+{
+ char buf[1024];
+ char *dynbuf;
+ int dynbuf_len;
+ va_list ap;
+ int r;
+
+ va_start (ap, format);
+
+ r = vsnprintf (buf, sizeof (buf), format, ap);
+
+ if (r < sizeof (buf))
+ md_assemble (buf);
+ else
+ {
+ /* In case buf is not enough, malloc a large enough buffer
+ and try again. */
+ dynbuf_len = r + 1;
+ dynbuf = (char *) xmalloc (dynbuf_len);
+ r = vsnprintf (dynbuf, dynbuf_len, format, ap);
+ md_assemble (dynbuf);
+ xfree (dynbuf);
+ }
+
+ va_end (ap);
+}
+
/* Sign-extend 32-bit mode constants that have bit 31 set and all higher bits
unset. */
static void
@@ -1013,6 +1045,7 @@ static void
load_const (int reg, expressionS *ep)
{
int shift = RISCV_IMM_BITS;
+ bfd_vma upper_imm;
expressionS upper = *ep, lower = *ep;
lower.X_add_number = (int32_t) ep->X_add_number << (32-shift) >> (32-shift);
upper.X_add_number -= lower.X_add_number;
@@ -1032,9 +1065,10 @@ load_const (int reg, expressionS *ep)
upper.X_add_number = (int64_t) upper.X_add_number >> shift;
load_const (reg, &upper);
- macro_build (NULL, "slli", "d,s,>", reg, reg, shift);
+ md_assemblef ("slli x%d, x%d, 0x%x", reg, reg, shift);
if (lower.X_add_number != 0)
- macro_build (&lower, "addi", "d,s,j", reg, reg, BFD_RELOC_RISCV_LO12_I);
+ md_assemblef ("%s x%d, x%d, %" BFD_VMA_FMT "d", ADD32_INSN, reg, reg,
+ lower.X_add_number);
}
else
{
@@ -1043,13 +1077,16 @@ load_const (int reg, expressionS *ep)
if (upper.X_add_number != 0)
{
- macro_build (ep, "lui", "d,u", reg, BFD_RELOC_RISCV_HI20);
+ /* Dicard low part and zero-extend uppper immediate. */
+ upper_imm = ((uint32_t)upper.X_add_number >> shift);
+
+ md_assemblef ("lui x%d, 0x%" BFD_VMA_FMT "x", reg, upper_imm);
hi_reg = reg;
}
if (lower.X_add_number != 0 || hi_reg == 0)
- macro_build (ep, ADD32_INSN, "d,s,j", reg, hi_reg,
- BFD_RELOC_RISCV_LO12_I);
+ md_assemblef ("%s x%d, x%d, %" BFD_VMA_FMT "d", ADD32_INSN, reg, hi_reg,
+ lower.X_add_number);
}
}
diff --git a/gas/testsuite/gas/riscv/li32.d b/gas/testsuite/gas/riscv/li32.d
new file mode 100644
index 0000000..ff0827d
--- /dev/null
+++ b/gas/testsuite/gas/riscv/li32.d
@@ -0,0 +1,17 @@
+#as: -march=rv32ic -mabi=ilp32
+#objdump: -dr
+
+.*: file format elf32-littleriscv
+
+
+Disassembly of section .text:
+
+0+000 <target>:
+[^:]+:[ ]+6521[ ]+lui[ ]+a0,0x8
+[^:]+:[ ]+0505[ ]+addi[ ]+a0,a0,1
+[^:]+:[ ]+6509[ ]+lui[ ]+a0,0x2
+[^:]+:[ ]+f0150513[ ]+addi[ ]+a0,a0,-255 # .*
+[^:]+:[ ]+12345537[ ]+lui[ ]+a0,0x12345
+[^:]+:[ ]+0505[ ]+addi[ ]+a0,a0,1
+[^:]+:[ ]+f2345537[ ]+lui[ ]+a0,0xf2345
+[^:]+:[ ]+0505[ ]+addi[ ]+a0,a0,1
diff --git a/gas/testsuite/gas/riscv/li32.s b/gas/testsuite/gas/riscv/li32.s
new file mode 100644
index 0000000..1930cd8
--- /dev/null
+++ b/gas/testsuite/gas/riscv/li32.s
@@ -0,0 +1,5 @@
+target:
+ li a0, 0x8001
+ li a0, 0x1f01
+ li a0, 0x12345001
+ li a0, 0xf2345001
diff --git a/gas/testsuite/gas/riscv/li64.d b/gas/testsuite/gas/riscv/li64.d
new file mode 100644
index 0000000..1aca62d
--- /dev/null
+++ b/gas/testsuite/gas/riscv/li64.d
@@ -0,0 +1,44 @@
+#as: -march=rv64ic -mabi=lp64
+#objdump: -dr
+
+.*: file format elf64-littleriscv
+
+
+Disassembly of section .text:
+
+0000000000000000 <target>:
+[^:]+:[ ]+6521[ ]+lui[ ]+a0,0x8
+[^:]+:[ ]+2505[ ]+addiw[ ]+a0,a0,1
+[^:]+:[ ]+6509[ ]+lui[ ]+a0,0x2
+[^:]+:[ ]+f015051b[ ]+addiw[ ]+a0,a0,-255
+[^:]+:[ ]+12345537[ ]+lui[ ]+a0,0x12345
+[^:]+:[ ]+2505[ ]+addiw[ ]+a0,a0,1
+[^:]+:[ ]+000f2537[ ]+lui[ ]+a0,0xf2
+[^:]+:[ ]+3455051b[ ]+addiw[ ]+a0,a0,837
+[^:]+:[ ]+0532[ ]+slli[ ]+a0,a0,0xc
+[^:]+:[ ]+2505[ ]+addiw[ ]+a0,a0,1
+[^:]+:[ ]+00f12537[ ]+lui[ ]+a0,0xf12
+[^:]+:[ ]+3455051b[ ]+addiw[ ]+a0,a0,837
+[^:]+:[ ]+0532[ ]+slli[ ]+a0,a0,0xc
+[^:]+:[ ]+2505[ ]+addiw[ ]+a0,a0,1
+[^:]+:[ ]+ff010537[ ]+lui[ ]+a0,0xff010
+[^:]+:[ ]+f015051b[ ]+addiw[ ]+a0,a0,-255
+[^:]+:[ ]+054e[ ]+slli[ ]+a0,a0,0x13
+[^:]+:[ ]+8015051b[ ]+addiw[ ]+a0,a0,-2047
+[^:]+:[ ]+0536[ ]+slli[ ]+a0,a0,0xd
+[^:]+:[ ]+f015051b[ ]+addiw[ ]+a0,a0,-255
+[^:]+:[ ]+0010051b[ ]+addiw[ ]+a0,zero,1
+[^:]+:[ ]+151a[ ]+slli[ ]+a0,a0,0x26
+[^:]+:[ ]+3565[ ]+addiw[ ]+a0,a0,-7
+[^:]+:[ ]+0536[ ]+slli[ ]+a0,a0,0xd
+[^:]+:[ ]+3455051b[ ]+addiw[ ]+a0,a0,837
+[^:]+:[ ]+0532[ ]+slli[ ]+a0,a0,0xc
+[^:]+:[ ]+2505[ ]+addiw[ ]+a0,a0,1
+[^:]+:[ ]+01fc4537[ ]+lui[ ]+a0,0x1fc4
+[^:]+:[ ]+c915051b[ ]+addiw[ ]+a0,a0,-879
+[^:]+:[ ]+0536[ ]+slli[ ]+a0,a0,0xd
+[^:]+:[ ]+3565[ ]+addiw[ ]+a0,a0,-7
+[^:]+:[ ]+0536[ ]+slli[ ]+a0,a0,0xd
+[^:]+:[ ]+3455051b[ ]+addiw[ ]+a0,a0,837
+[^:]+:[ ]+0532[ ]+slli[ ]+a0,a0,0xc
+[^:]+:[ ]+2505[ ]+addiw[ ]+a0,a0,1
diff --git a/gas/testsuite/gas/riscv/li64.s b/gas/testsuite/gas/riscv/li64.s
new file mode 100644
index 0000000..aab19eb
--- /dev/null
+++ b/gas/testsuite/gas/riscv/li64.s
@@ -0,0 +1,9 @@
+target:
+ li a0, 0x8001
+ li a0, 0x1f01
+ li a0, 0x12345001
+ li a0, 0xf2345001
+ li a0, 0xf12345001
+ li a0, 0xff00ff00ff001f01
+ li a0, 0x7ffffffff2345001
+ li a0, 0x7f0f243ff2345001
--
2.7.4