public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] LoongArch: support disassembling certain pseudo-instructions
@ 2022-12-09  9:57 WANG Xuerui
  0 siblings, 0 replies; only message in thread
From: WANG Xuerui @ 2022-12-09  9:57 UTC (permalink / raw)
  To: binutils; +Cc: Chenghua Xu, Zhensong Liu, Xi Ruoyao, WANG Xuerui

From: WANG Xuerui <git@xen0n.name>

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/config/tc-loongarch.c  |  3 ++-
 include/opcode/loongarch.h |  2 ++
 opcodes/loongarch-dis.c    | 24 ++++++++++++++++--------
 opcodes/loongarch-opc.c    | 23 +++++++++++++++++++++--
 4 files changed, 41 insertions(+), 11 deletions(-)

diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index 60149a6d8db..de7f9e26ae3 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -743,7 +743,8 @@ get_loongarch_opcode (struct loongarch_cl_insn *insn)
 	  for (it = ase->opcodes; it->name; it++)
 	    {
 	      if ((!it->include || (it->include && *it->include))
-		  && (!it->exclude || (it->exclude && !(*it->exclude))))
+		  && (!it->exclude || (it->exclude && !(*it->exclude)))
+		  && !(it->pinfo & INSN_DIS_ALIAS))
 		str_hash_insert (ase->name_hash_entry, it->name,
 				 (void *) it, 0);
 	    }
diff --git a/include/opcode/loongarch.h b/include/opcode/loongarch.h
index c3922348a56..251621a239f 100644
--- a/include/opcode/loongarch.h
+++ b/include/opcode/loongarch.h
@@ -118,6 +118,8 @@ dec2 : [1-9][0-9]?
 
     const unsigned long pinfo;
 #define USELESS 0x0l
+/* Instruction is a simple alias only for disassembler use.  */
+#define INSN_DIS_ALIAS		0x00000001l
   };
 
   struct hash_control;
diff --git a/opcodes/loongarch-dis.c b/opcodes/loongarch-dis.c
index 9dcf989d0df..036eb8f2b0f 100644
--- a/opcodes/loongarch-dis.c
+++ b/opcodes/loongarch-dis.c
@@ -25,6 +25,14 @@
 #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_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 +49,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,13 +69,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_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)
 {
@@ -87,6 +90,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;
@@ -301,6 +307,8 @@ print_loongarch_disassembler_options (FILE *stream)
 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 1b510048c29..2ea9effdbf9 100644
--- a/opcodes/loongarch-opc.c
+++ b/opcodes/loongarch-opc.c
@@ -331,9 +331,29 @@ static struct loongarch_opcode loongarch_macro_opcodes[] =
   { 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 },
@@ -354,8 +374,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 },
@@ -848,6 +866,7 @@ static struct loongarch_opcode loongarch_jmp_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 },
-- 
2.38.1


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-12-09  9:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-09  9:57 [PATCH] LoongArch: support disassembling certain pseudo-instructions WANG Xuerui

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).