From db3b6ecc28a079768dc4661e459c4a68039e8483 Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Tue, 20 Aug 2019 17:47:58 +0800 Subject: 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 | 38 +++++++++++++++++++++++++++++++----- 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, 108 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 (limited to 'gas') diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index f0c1f4c..12047d7 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); } } 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 : +[^:]+:[ ]+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..5421303 --- /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 : +[^:]+:[ ]+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 +[^:]+:[ ]+0505[ ]+addi[ ]+a0,a0,1 +[^:]+:[ ]+00f12537[ ]+lui[ ]+a0,0xf12 +[^:]+:[ ]+3455051b[ ]+addiw[ ]+a0,a0,837 +[^:]+:[ ]+0532[ ]+slli[ ]+a0,a0,0xc +[^:]+:[ ]+0505[ ]+addi[ ]+a0,a0,1 +[^:]+:[ ]+ff010537[ ]+lui[ ]+a0,0xff010 +[^:]+:[ ]+f015051b[ ]+addiw[ ]+a0,a0,-255 +[^:]+:[ ]+054e[ ]+slli[ ]+a0,a0,0x13 +[^:]+:[ ]+80150513[ ]+addi[ ]+a0,a0,-2047 # .* +[^:]+:[ ]+0536[ ]+slli[ ]+a0,a0,0xd +[^:]+:[ ]+f0150513[ ]+addi[ ]+a0,a0,-255 +[^:]+:[ ]+0010051b[ ]+addiw[ ]+a0,zero,1 +[^:]+:[ ]+151a[ ]+slli[ ]+a0,a0,0x26 +[^:]+:[ ]+1565[ ]+addi[ ]+a0,a0,-7 +[^:]+:[ ]+0536[ ]+slli[ ]+a0,a0,0xd +[^:]+:[ ]+34550513[ ]+addi[ ]+a0,a0,837 +[^:]+:[ ]+0532[ ]+slli[ ]+a0,a0,0xc +[^:]+:[ ]+0505[ ]+addi[ ]+a0,a0,1 +[^:]+:[ ]+01fc4537[ ]+lui[ ]+a0,0x1fc4 +[^:]+:[ ]+c915051b[ ]+addiw[ ]+a0,a0,-879 +[^:]+:[ ]+0536[ ]+slli[ ]+a0,a0,0xd +[^:]+:[ ]+1565[ ]+addi[ ]+a0,a0,-7 +[^:]+:[ ]+0536[ ]+slli[ ]+a0,a0,0xd +[^:]+:[ ]+34550513[ ]+addi[ ]+a0,a0,837 # .* +[^:]+:[ ]+0532[ ]+slli[ ]+a0,a0,0xc +[^:]+:[ ]+0505[ ]+addi[ ]+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 -- cgit v1.1