aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKito Cheng <kito.cheng@sifive.com>2019-08-20 17:47:58 +0800
committerKito Cheng <kito.cheng@sifive.com>2019-08-25 19:16:43 -0700
commitdb3b6ecc28a079768dc4661e459c4a68039e8483 (patch)
tree403570cbcf20a4fc6f0c25b53d5fc58b47102a46 /gas/config
parentdwarf2read: fix compilation issue with gcc 4.8 (diff)
downloadbinutils-gdb-db3b6ecc28a079768dc4661e459c4a68039e8483.tar.gz
binutils-gdb-db3b6ecc28a079768dc4661e459c4a68039e8483.tar.bz2
binutils-gdb-db3b6ecc28a079768dc4661e459c4a68039e8483.zip
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.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-riscv.c38
1 files changed, 33 insertions, 5 deletions
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index f0c1f4ca75c..12047d72105 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -928,6 +928,29 @@ 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 = NULL;
+ va_list ap;
+ int r;
+
+ va_start (ap, format);
+
+ r = vasprintf (&buf, format, ap);
+
+ if (r < 0)
+ as_fatal (_("internal error: vasprintf failed"));
+
+ md_assemble (buf);
+ free(buf);
+
+ va_end (ap);
+}
+
/* Sign-extend 32-bit mode constants that have bit 31 set and all higher bits
unset. */
static void
@@ -1013,6 +1036,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 +1056,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 ("addi x%d, x%d, %" BFD_VMA_FMT "d", reg, reg,
+ lower.X_add_number);
}
else
{
@@ -1043,13 +1068,16 @@ load_const (int reg, expressionS *ep)
if (upper.X_add_number != 0)
{
- macro_build (ep, "lui", "d,u", reg, BFD_RELOC_RISCV_HI20);
+ /* Discard low part and zero-extend upper 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);
}
}