aboutsummaryrefslogtreecommitdiff
path: root/opcodes
diff options
context:
space:
mode:
authorWANG Xuerui <git@xen0n.name>2023-06-30 00:34:58 +0800
committerliuzhensong <liuzhensong@loongson.cn>2023-06-30 10:17:56 +0800
commit17f9439038257b1de0c130a416a9a7645c653cb0 (patch)
tree309c03231b447bcfbcf30868c54f7d3e3a15cc4f /opcodes
parent69b9300e8789bd720994b2efc6e137139ee8055a (diff)
downloadgdb-17f9439038257b1de0c130a416a9a7645c653cb0.zip
gdb-17f9439038257b1de0c130a416a9a7645c653cb0.tar.gz
gdb-17f9439038257b1de0c130a416a9a7645c653cb0.tar.bz2
LoongArch: support disassembling certain pseudo-instructions
Add a flag in the pinfo field for being able to mark certain specialized matchers as disassembler-only, so some degree of isolation between assembler-side and disassembler-side can be achieved. This isolation is necessary, firstly because some pseudo-instructions cannot be fully described in the opcode table, like `li.[wd]`, so the corresponding opcode entry cannot have meaningful match/mask values. Secondly, some of these pseudo-instructions can be realized in more than one plausible ways; e.g. `li.w rd, <something between 0 and 0x7ff>` can be realized on LA64 with any of `addi.w`, `addi.d` or `ori`. If we tie disassembly of such aliases with the corresponding GAS support, only one canonical form among the above would be recognized as `li.w`, and it would mildly impact the readability of disassembly output. People wanting the exact disassembly can always set `-M no-aliases` to get the original behavior back. In addition, in certain cases, information is irreversibly lost after assembling, so perfect round-trip would not be possible in such cases. For example, `li.w` and `li.d` of immediates within int32_t range produce the same code; in this patch, `addi.d rd, $zero, imm` is treated as `li.d`, while `addi.w` and `ori` immediate loads are shown as `li.w`, due to the expressible value range well within 32 bits. gas/ChangeLog: * config/tc-loongarch.c (get_loongarch_opcode): Ignore disassembler-only aliases. * testsuite/gas/loongarch/64_pcrel.d: Update test case. * testsuite/gas/loongarch/imm_ins.d: Likewise. * testsuite/gas/loongarch/imm_ins_32.d: Likewise. * testsuite/gas/loongarch/jmp_op.d: Likewise. * testsuite/gas/loongarch/li.d: Likewise. * testsuite/gas/loongarch/macro_op.d: Likewise. * testsuite/gas/loongarch/macro_op_32.d: Likewise. * testsuite/gas/loongarch/macro_op_large_abs.d: Likewise. * testsuite/gas/loongarch/macro_op_large_pc.d: Likewise. * testsuite/gas/loongarch/nop.d: Likewise. * testsuite/gas/loongarch/relax_align.d: Likewise. * testsuite/gas/loongarch/reloc.d: Likewise. include/ChangeLog: * opcode/loongarch.h (INSN_DIS_ALIAS): Add. ld/ChangeLog: * testsuite/ld-loongarch-elf/jmp_op.d: Update test case. * testsuite/ld-loongarch-elf/macro_op.d: Likewise. * testsuite/ld-loongarch-elf/macro_op_32.d: Likewise. * testsuite/ld-loongarch-elf/relax-align.dd: Likewise. opcodes/ChangeLog: * loongarch-dis.c: Move register name map declarations to top. (get_loongarch_opcode_by_binfmt): Consider aliases when disassembling without the no-aliases option. (parse_loongarch_dis_option): Support the no-aliases option. * loongarch-opc.c: Collect pseudo instructions into a new dedicated table. Signed-off-by: WANG Xuerui <git@xen0n.name>
Diffstat (limited to 'opcodes')
-rw-r--r--opcodes/loongarch-dis.c26
-rw-r--r--opcodes/loongarch-opc.c23
2 files changed, 38 insertions, 11 deletions
diff --git a/opcodes/loongarch-dis.c b/opcodes/loongarch-dis.c
index 0725270..3a08da1 100644
--- a/opcodes/loongarch-dis.c
+++ b/opcodes/loongarch-dis.c
@@ -25,6 +25,15 @@
#include "libiberty.h"
#include <stdlib.h>
+static bool loongarch_dis_show_aliases = true;
+static const char *const *loongarch_r_disname = NULL;
+static const char *const *loongarch_f_disname = NULL;
+static const char *const *loongarch_fc_disname = NULL;
+static const char *const *loongarch_c_disname = NULL;
+static const char *const *loongarch_cr_disname = NULL;
+static const char *const *loongarch_v_disname = NULL;
+static const char *const *loongarch_x_disname = NULL;
+
static const struct loongarch_opcode *
get_loongarch_opcode_by_binfmt (insn_t insn)
{
@@ -41,7 +50,9 @@ get_loongarch_opcode_by_binfmt (insn_t insn)
{
for (it = ase->opcodes; it->mask; it++)
if (!ase->opc_htab[LARCH_INSN_OPC (it->match)]
- && it->macro == NULL)
+ && it->macro == NULL
+ && (!(it->pinfo & INSN_DIS_ALIAS)
+ || loongarch_dis_show_aliases))
ase->opc_htab[LARCH_INSN_OPC (it->match)] = it;
for (i = 0; i < 16; i++)
if (!ase->opc_htab[i])
@@ -59,14 +70,6 @@ get_loongarch_opcode_by_binfmt (insn_t insn)
return NULL;
}
-static const char *const *loongarch_r_disname = NULL;
-static const char *const *loongarch_f_disname = NULL;
-static const char *const *loongarch_fc_disname = NULL;
-static const char *const *loongarch_c_disname = NULL;
-static const char *const *loongarch_cr_disname = NULL;
-static const char *const *loongarch_v_disname = NULL;
-static const char *const *loongarch_x_disname = NULL;
-
static void
set_default_loongarch_dis_options (void)
{
@@ -89,6 +92,9 @@ set_default_loongarch_dis_options (void)
static int
parse_loongarch_dis_option (const char *option)
{
+ if (strcmp (option, "no-aliases") == 0)
+ loongarch_dis_show_aliases = false;
+
if (strcmp (option, "numeric") == 0)
{
loongarch_r_disname = loongarch_r_normal_name;
@@ -311,6 +317,8 @@ The following LoongArch disassembler options are supported for use\n\
with the -M switch (multiple options should be separated by commas):\n"));
fprintf (stream, _("\n\
+ no-aliases Use canonical instruction forms.\n"));
+ fprintf (stream, _("\n\
numeric Print numeric register names, rather than ABI names.\n"));
fprintf (stream, _("\n"));
}
diff --git a/opcodes/loongarch-opc.c b/opcodes/loongarch-opc.c
index bd10446..3d1d2c7 100644
--- a/opcodes/loongarch-opc.c
+++ b/opcodes/loongarch-opc.c
@@ -344,9 +344,29 @@ static struct loongarch_opcode loongarch_macro_opcodes[] =
{ 0, 0, 0, 0, 0, 0, 0, 0 } /* Terminate the list. */
};
+static struct loongarch_opcode loongarch_alias_opcodes[] =
+{
+ /* match, mask, name, format, macro, include, exclude, pinfo. */
+ { 0x00150000, 0xfffffc00, "move", "r0:5,r5:5", 0, 0, 0, INSN_DIS_ALIAS }, /* or rd, rj, zero */
+ { 0x02800000, 0xffc003e0, "li.w", "r0:5,s10:12", 0, 0, 0, INSN_DIS_ALIAS }, /* addi.w rd, zero, simm */
+ { 0x02c00000, 0xffc003e0, "li.d", "r0:5,s10:12", 0, 0, 0, INSN_DIS_ALIAS }, /* addi.d rd, zero, simm */
+ { 0x03400000, 0xffffffff, "nop", "", 0, 0, 0, INSN_DIS_ALIAS }, /* andi zero, zero, 0 */
+ { 0x03800000, 0xffc003e0, "li.w", "r0:5,u10:12", 0, 0, 0, INSN_DIS_ALIAS }, /* ori rd, zero, uimm */
+ /* ret must come before jr because it is more specific. */
+ { 0x4c000020, 0xffffffff, "ret", "", 0, 0, 0, INSN_DIS_ALIAS }, /* jirl zero, ra, 0 */
+ { 0x4c000000, 0xfffffc1f, "jr", "r5:5", 0, 0, 0, INSN_DIS_ALIAS }, /* jirl zero, rj, 0 */
+ { 0x60000000, 0xfc00001f, "bltz", "r5:5,sb10:16<<2", 0, 0, 0, INSN_DIS_ALIAS }, /* blt rj, zero, offset */
+ { 0x60000000, 0xfc0003e0, "bgtz", "r0:5,sb10:16<<2", 0, 0, 0, INSN_DIS_ALIAS }, /* blt zero, rd, offset */
+ { 0x64000000, 0xfc00001f, "bgez", "r5:5,sb10:16<<2", 0, 0, 0, INSN_DIS_ALIAS }, /* bge rj, zero, offset */
+ { 0x64000000, 0xfc0003e0, "blez", "r0:5,sb10:16<<2", 0, 0, 0, INSN_DIS_ALIAS }, /* bge zero, rd, offset */
+ { 0 } /* Terminate the list. */
+};
+
+
static struct loongarch_opcode loongarch_fix_opcodes[] =
{
/* match, mask, name, format, macro, include, exclude, pinfo. */
+ { 0x0, 0x0, "move", "r,r", "or %1,%2,$r0", 0, 0, 0 },
{ 0x00001000, 0xfffffc00, "clo.w", "r0:5,r5:5", 0, 0, 0, 0 },
{ 0x00001400, 0xfffffc00, "clz.w", "r0:5,r5:5", 0, 0, 0, 0 },
{ 0x00001800, 0xfffffc00, "cto.w", "r0:5,r5:5", 0, 0, 0, 0 },
@@ -367,8 +387,6 @@ static struct loongarch_opcode loongarch_fix_opcodes[] =
{ 0x00005400, 0xfffffc00, "bitrev.d", "r0:5,r5:5", 0, 0, 0, 0 },
{ 0x00005800, 0xfffffc00, "ext.w.h", "r0:5,r5:5", 0, 0, 0, 0 },
{ 0x00005c00, 0xfffffc00, "ext.w.b", "r0:5,r5:5", 0, 0, 0, 0 },
- /* or %1,%2,$r0 */
- { 0x00150000, 0xfffffc00, "move", "r0:5,r5:5", 0, 0, 0, 0 },
{ 0x00006000, 0xfffffc00, "rdtimel.w", "r0:5,r5:5", 0, 0, 0, 0 },
{ 0x00006400, 0xfffffc00, "rdtimeh.w", "r0:5,r5:5", 0, 0, 0, 0 },
{ 0x00006800, 0xfffffc00, "rdtime.d", "r0:5,r5:5", 0, 0, 0, 0 },
@@ -2324,6 +2342,7 @@ static struct loongarch_opcode loongarch_lasx_opcodes[] =
struct loongarch_ase loongarch_ASEs[] =
{
{ &LARCH_opts.ase_ilp32, loongarch_macro_opcodes, 0, 0, { 0 }, 0, 0 },
+ { &LARCH_opts.ase_ilp32, loongarch_alias_opcodes, 0, 0, { 0 }, 0, 0 },
{ &LARCH_opts.ase_ilp32, loongarch_imm_opcodes, 0, 0, { 0 }, 0, 0 },
{ &LARCH_opts.ase_ilp32, loongarch_privilege_opcodes, 0, 0, { 0 }, 0, 0 },
{ &LARCH_opts.ase_ilp32, loongarch_load_store_opcodes, 0, 0, { 0 }, 0, 0 },