From 20f0a1fc7d3349b326456c16297278dccd2686c9 Mon Sep 17 00:00:00 2001
From: Nick Clifton <nickc@redhat.com>
Date: Wed, 21 Jul 2004 16:09:43 +0000
Subject: Corrections for x86_64 assembly.

---
 gas/ChangeLog                          |  18 +++++
 gas/config/tc-i386.c                   | 116 ++++++++++++++-------------------
 gas/testsuite/ChangeLog                |   8 +++
 gas/testsuite/gas/i386/i386.exp        |   2 +
 gas/testsuite/gas/i386/x86-64-addr32.d |  13 ++++
 gas/testsuite/gas/i386/x86-64-addr32.s |   5 ++
 gas/testsuite/gas/i386/x86-64-rip.d    |  13 ++++
 gas/testsuite/gas/i386/x86-64-rip.s    |   5 ++
 gas/testsuite/gas/i386/x86_64.d        |   2 +-
 9 files changed, 115 insertions(+), 67 deletions(-)
 create mode 100644 gas/testsuite/gas/i386/x86-64-addr32.d
 create mode 100644 gas/testsuite/gas/i386/x86-64-addr32.s
 create mode 100644 gas/testsuite/gas/i386/x86-64-rip.d
 create mode 100644 gas/testsuite/gas/i386/x86-64-rip.s

(limited to 'gas')

diff --git a/gas/ChangeLog b/gas/ChangeLog
index 33ac7fc..977d0d9 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,21 @@
+2004-07-21  Jan Beulich <jbeulich@novell.com>
+
+	* config/tc-i386.c (optimize_imm): Adjust immediates to only those
+	permissible for the selected instruction suffix.
+	(match_template): Don't permit 64-bit general purpose operands in
+	32-bit mode.
+	(finalize_imm): Permit 64-bit immediates.
+	(build_modrm_byte): Don't treat 32-bit addressing in 64-bit mode
+	specially except for the width of the used base and/or index
+	registers.  For 32-bit displacements, use sign-extended
+	relocations only when using 64-bit addressing.
+	Force zero displacement on rip-relative addressing when there is
+	no other displacement.
+	(i386_index_check): Don't treat 32-bit addressing in 64-bit mode
+	specially except for the width of the used base and/or index
+	registers.
+	(parse_register): Disallow Reg64 registers in 32-bit mode.
+
 2004-07-20  Maciej W. Rozycki  <macro@linux-mips.org>
 
 	* config/tc-mips.c (append_insn): Handle constant expressions with
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 2dd834e..e73aa95 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -1922,15 +1922,13 @@ optimize_imm ()
 		i.types[op] = Imm64 | Imm32S;
 		break;
 	      case LONG_MNEM_SUFFIX:
-		i.types[op] = Imm32 | Imm64;
+		i.types[op] = Imm32;
 		break;
 	      case WORD_MNEM_SUFFIX:
-		i.types[op] = Imm16 | Imm32 | Imm64;
-		break;
+		i.types[op] = Imm16;
 		break;
 	      case BYTE_MNEM_SUFFIX:
-		i.types[op] = Imm8 | Imm8S | Imm16 | Imm32S | Imm32;
-		break;
+		i.types[op] = Imm8 | Imm8S;
 		break;
 	      }
 	    break;
@@ -2018,9 +2016,18 @@ match_template ()
 			      : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX
 				 ? No_xSuf : 0))))));
 
-  for (t = current_templates->start;
-       t < current_templates->end;
-       t++)
+  t = current_templates->start;
+  if (i.suffix == QWORD_MNEM_SUFFIX
+      && flag_code != CODE_64BIT
+      && (!intel_syntax
+	  || (!(t->opcode_modifier & IgnoreSize)
+	      && ! intel_float_operand (t->name)))
+      && (!(t->operand_types[0] & (RegMMX | RegXMM))
+	  || !(t->operand_types[t->operands > 1] & (RegMMX | RegXMM)))
+      && (t->base_opcode != 0x0fc7
+	  || t->extension_opcode != 1 /* cmpxchg8b */))
+    t = current_templates->end;
+  for (; t < current_templates->end; t++)
     {
       /* Must have right number of operands.  */
       if (i.operands != t->operands)
@@ -2504,7 +2511,7 @@ finalize_imm ()
   unsigned int overlap0, overlap1, overlap2;
 
   overlap0 = i.types[0] & i.tm.operand_types[0];
-  if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S))
+  if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S | Imm64))
       && overlap0 != Imm8 && overlap0 != Imm8S
       && overlap0 != Imm16 && overlap0 != Imm32S
       && overlap0 != Imm32 && overlap0 != Imm64)
@@ -2733,21 +2740,7 @@ build_modrm_byte ()
 	      if (i.index_reg == 0)
 		{
 		  /* Operand is just <disp>  */
-		  if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)
-		      && (flag_code != CODE_64BIT))
-		    {
-		      i.rm.regmem = NO_BASE_REGISTER_16;
-		      i.types[op] &= ~Disp;
-		      i.types[op] |= Disp16;
-		    }
-		  else if (flag_code != CODE_64BIT
-			   || (i.prefix[ADDR_PREFIX] != 0))
-		    {
-		      i.rm.regmem = NO_BASE_REGISTER;
-		      i.types[op] &= ~Disp;
-		      i.types[op] |= Disp32;
-		    }
-		  else
+		  if (flag_code == CODE_64BIT)
 		    {
 		      /* 64bit mode overwrites the 32bit absolute
 			 addressing by RIP relative addressing and
@@ -2756,8 +2749,17 @@ build_modrm_byte ()
 		      i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
 		      i.sib.base = NO_BASE_REGISTER;
 		      i.sib.index = NO_INDEX_REGISTER;
-		      i.types[op] &= ~Disp;
-		      i.types[op] |= Disp32S;
+		      i.types[op] = ((i.prefix[ADDR_PREFIX] == 0) ? Disp32S : Disp32);
+		    }
+		  else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
+		    {
+		      i.rm.regmem = NO_BASE_REGISTER_16;
+		      i.types[op] = Disp16;
+		    }
+		  else
+		    {
+		      i.rm.regmem = NO_BASE_REGISTER;
+		      i.types[op] = Disp32;
 		    }
 		}
 	      else /* !i.base_reg && i.index_reg  */
@@ -2779,9 +2781,11 @@ build_modrm_byte ()
 	  else if (i.base_reg->reg_type == BaseIndex)
 	    {
 	      i.rm.regmem = NO_BASE_REGISTER;
-	      i.types[op] &= ~Disp;
+	      i.types[op] &= ~ Disp;
 	      i.types[op] |= Disp32S;
 	      i.flags[op] = Operand_PCrel;
+	      if (! i.disp_operands)
+		fake_zero_displacement = 1;
 	    }
 	  else if (i.base_reg->reg_type & Reg16)
 	    {
@@ -2817,12 +2821,8 @@ build_modrm_byte ()
 	    {
 	      if (flag_code == CODE_64BIT
 		  && (i.types[op] & Disp))
-		{
-		  if (i.types[op] & Disp8)
-		    i.types[op] = Disp8 | Disp32S;
-		  else
-		    i.types[op] = Disp32S;
-		}
+		i.types[op] = (i.types[op] & Disp8) | (i.prefix[ADDR_PREFIX] == 0 ? Disp32S : Disp32);
+
 	      i.rm.regmem = i.base_reg->reg_num;
 	      if ((i.base_reg->reg_flags & RegRex) != 0)
 		i.rex |= REX_EXTZ;
@@ -3999,30 +3999,18 @@ i386_index_check (operand_string)
  tryprefix:
 #endif
   ok = 1;
-  if (flag_code == CODE_64BIT)
-    {
-      if (i.prefix[ADDR_PREFIX] == 0)
-	{
-	  /* 64bit checks.  */
-	  if ((i.base_reg
-	       && ((i.base_reg->reg_type & Reg64) == 0)
-		   && (i.base_reg->reg_type != BaseIndex
-		       || i.index_reg))
-	      || (i.index_reg
-		  && ((i.index_reg->reg_type & (Reg64 | BaseIndex))
-		      != (Reg64 | BaseIndex))))
-	    ok = 0;
-	}
-      else
-	{
-	  /* 32bit checks.  */
-	  if ((i.base_reg
-	       && (i.base_reg->reg_type & (Reg32 | RegRex)) != Reg32)
-	      || (i.index_reg
-		  && ((i.index_reg->reg_type & (Reg32 | BaseIndex | RegRex))
-		      != (Reg32 | BaseIndex))))
-	    ok = 0;
-	}
+   if (flag_code == CODE_64BIT)
+     {
+       unsigned RegXX = (i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32);
+
+       if ((i.base_reg
+	    && ((i.base_reg->reg_type & RegXX) == 0)
+	    && (i.base_reg->reg_type != BaseIndex
+		|| i.index_reg))
+	   || (i.index_reg
+	       && ((i.index_reg->reg_type & (RegXX | BaseIndex))
+		   != (RegXX | BaseIndex))))
+	 ok = 0;
     }
   else
     {
@@ -4055,8 +4043,7 @@ i386_index_check (operand_string)
   if (!ok)
     {
 #if INFER_ADDR_PREFIX
-      if (flag_code != CODE_64BIT
-	  && i.prefix[ADDR_PREFIX] == 0 && stackop_size != '\0')
+      if (i.prefix[ADDR_PREFIX] == 0)
 	{
 	  i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
 	  i.prefixes += 1;
@@ -4065,7 +4052,7 @@ i386_index_check (operand_string)
 	     FIXME.  There doesn't seem to be any real need for separate
 	     Disp16 and Disp32 flags.  The same goes for Imm16 and Imm32.
 	     Removing them would probably clean up the code quite a lot.  */
-	  if (i.types[this_operand] & (Disp16 | Disp32))
+	  if (flag_code != CODE_64BIT && (i.types[this_operand] & (Disp16 | Disp32)))
 	     i.types[this_operand] ^= (Disp16 | Disp32);
 	  fudged = 1;
 	  goto tryprefix;
@@ -4078,9 +4065,8 @@ i386_index_check (operand_string)
 	as_bad (_("`%s' is not a valid %s bit base/index expression"),
 		operand_string,
 		flag_code_names[flag_code]);
-      return 0;
     }
-  return 1;
+  return ok;
 }
 
 /* Parse OPERAND_STRING into the i386_insn structure I.  Returns non-zero
@@ -4904,11 +4890,9 @@ parse_register (reg_string, end_op)
     }
 
   if (r != NULL
-      && (r->reg_flags & (RegRex64 | RegRex)) != 0
+      && ((r->reg_flags & (RegRex64 | RegRex)) | (r->reg_type & Reg64)) != 0
       && flag_code != CODE_64BIT)
-    {
-      return (const reg_entry *) NULL;
-    }
+    return (const reg_entry *) NULL;
 
   return r;
 }
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index 81027e4..e5689e6 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2004-07-21  Jan Beulich <jbeulich@novell.com>
+
+	* testsuite/gas/i386/x86-64-addr32.[ds]: New test for x86-64
+	32-bit addressing in 64-bit mode.
+	* testsuite/gas/i386/x86-64-rip.[ds]: New test for x86-64
+	rip-relative addressing.
+	* testsuite/gas/i386/i386.exp: Run the two new tests.
+
 2004-07-20  Maciej W. Rozycki  <macro@linux-mips.org>
 
 	* gas/mips/elf-rel19.d: Pass -march=mips1 to gas as the test
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index 1b8c401..bfd7cd5 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -105,7 +105,9 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t
     set ASFLAGS "$ASFLAGS --64"
 
     run_dump_test "x86_64"
+    run_dump_test "x86-64-addr32"
     run_dump_test "x86-64-opcode"
+    run_dump_test "x86-64-rip"
     run_list_test "x86-64-inval" "-al"
 
     set ASFLAGS "$old_ASFLAGS"
diff --git a/gas/testsuite/gas/i386/x86-64-addr32.d b/gas/testsuite/gas/i386/x86-64-addr32.d
new file mode 100644
index 0000000..c892fb1
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-addr32.d
@@ -0,0 +1,13 @@
+#as: -J
+#objdump: -drw
+#name: x86-64 32-bit addressing
+
+.*: +file format elf64-x86-64
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[	 ]*0:[	 ]+67 48 8d 80 00 00 00 00[	 ]+addr32[	 ]+lea[ 	]+0x0\(%[re]ax\),%rax.*
+[	 ]*8:[	 ]+67 49 8d 80 00 00 00 00[	 ]+addr32[	 ]+lea[ 	]+0x0\(%r8d?\),%rax.*
+[	 ]*10:[	 ]+67 48 8d 05 00 00 00 00[	 ]+addr32[	 ]+lea[ 	]+0\(%[re]ip\),%rax.*
+[	 ]*18:[	 ]+67 48 8d 04 25 00 00 00 00[	 ]+addr32[	 ]+lea[ 	]+0x0,%rax.*
diff --git a/gas/testsuite/gas/i386/x86-64-addr32.s b/gas/testsuite/gas/i386/x86-64-addr32.s
new file mode 100644
index 0000000..d18cbb9
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-addr32.s
@@ -0,0 +1,5 @@
+.text
+	lea		symbol(%eax), %rax
+	lea		symbol(%r8d), %rax
+	addr32 lea	symbol(%rip), %rax
+	addr32 lea	symbol, %rax
diff --git a/gas/testsuite/gas/i386/x86-64-rip.d b/gas/testsuite/gas/i386/x86-64-rip.d
new file mode 100644
index 0000000..1b1d6c8
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-rip.d
@@ -0,0 +1,13 @@
+#as: -J
+#objdump: -drw
+#name: x86-64 rip addressing
+
+.*: +file format elf64-x86-64
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[	 ]*0:[	 ]+8d 05 00 00 00 00[	 ]+lea[	 ]+0\(%rip\),%eax[ 	]*(#.*)?
+[	 ]*6:[	 ]+8d 05 11 11 11 11[	 ]+lea[	 ]+286331153\(%rip\),%eax[ 	]*(#.*)?
+[	 ]*c:[	 ]+8d 05 01 00 00 00[	 ]+lea[	 ]+1\(%rip\),%eax[ 	]*(#.*)?
+[	 ]*12:[	 ]+8d 05 00 00 00 00[	 ]+lea[	 ]+0\(%rip\),%eax[ 	]*(#.*)?
diff --git a/gas/testsuite/gas/i386/x86-64-rip.s b/gas/testsuite/gas/i386/x86-64-rip.s
new file mode 100644
index 0000000..c6ac195
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-rip.s
@@ -0,0 +1,5 @@
+.text
+	leal	symbol(%rip), %eax
+	leal	0x11111111(%rip), %eax
+	leal	1(%rip), %eax
+	leal	(%rip), %eax
diff --git a/gas/testsuite/gas/i386/x86_64.d b/gas/testsuite/gas/i386/x86_64.d
index 1af2278..dd4526b 100644
--- a/gas/testsuite/gas/i386/x86_64.d
+++ b/gas/testsuite/gas/i386/x86_64.d
@@ -37,7 +37,7 @@ Disassembly of section .text:
 [ 	]+5a:	44 0f 20 c0[ 	]+mov[ 	]+%cr8,%rax
 [ 	]+5e:	44 0f 22 c0[ 	]+mov[ 	]+%rax,%cr8
 [ 	]+62:	f3 48 a5[ 	]+repz movsq %ds:\(%rsi\),%es:\(%rdi\)
-[ 	]+65:	f3 66 a5[ 	]+repz movsw %ds:\(%esi\),%es:\(%edi\)
+[ 	]+65:	f3 66 a5[ 	]+repz movsw %ds:\(%rsi\),%es:\(%rdi\)
 [ 	]+68:	f3 48 a5[ 	]+repz movsq %ds:\(%rsi\),%es:\(%rdi\)
 [ 	]+6b:	b0 11[ 	]+mov[ 	]+\$0x11,%al
 [ 	]+6d:	b4 11[ 	]+mov[ 	]+\$0x11,%ah
-- 
cgit v1.1