x86: replace Reg8, Reg16, Reg32, and Reg64
[deliverable/binutils-gdb.git] / gas / config / tc-riscv.c
index 68b28f7525e47bb79f904d6b56c33d0212316ab8..c2e5f30e506e3a4b4d4530565bd6d05e9c7bd5a7 100644 (file)
@@ -120,6 +120,18 @@ riscv_subset_supports (const char *feature)
   return FALSE;
 }
 
+static void
+riscv_clear_subsets (void)
+{
+  while (riscv_subsets != NULL)
+    {
+      struct riscv_subset *next = riscv_subsets->next;
+      free ((void *) riscv_subsets->name);
+      free (riscv_subsets);
+      riscv_subsets = next;
+    }
+}
+
 static void
 riscv_add_subset (const char *subset)
 {
@@ -135,10 +147,12 @@ riscv_add_subset (const char *subset)
 static void
 riscv_set_arch (const char *s)
 {
-  const char *all_subsets = "imafdc";
-  const char *extension = NULL;
+  const char *all_subsets = "imafdqc";
+  char *extension = NULL;
   const char *p = s;
 
+  riscv_clear_subsets();
+
   if (strncmp (p, "rv32", 4) == 0)
     {
       xlen = 32;
@@ -159,7 +173,7 @@ riscv_set_arch (const char *s)
 
       case 'g':
        p++;
-       for ( ; *all_subsets != 'c'; all_subsets++)
+       for ( ; *all_subsets != 'q'; all_subsets++)
          {
            const char subset[] = {*all_subsets, '\0'};
            riscv_add_subset (subset);
@@ -174,7 +188,8 @@ riscv_set_arch (const char *s)
     {
       if (*p == 'x')
        {
-         char *subset = xstrdup (p), *q = subset;
+         char *subset = xstrdup (p);
+         char *q = subset;
 
          while (*++q != '\0' && *q != '_')
            ;
@@ -186,7 +201,6 @@ riscv_set_arch (const char *s)
          extension = subset;
          riscv_add_subset (subset);
          p += strlen (subset);
-         free (subset);
        }
       else if (*p == '_')
        p++;
@@ -197,15 +211,11 @@ riscv_set_arch (const char *s)
          all_subsets++;
          p++;
        }
-      else if (*p == 'q')
-       {
-         const char subset[] = {*p, 0};
-         riscv_add_subset (subset);
-         p++;
-       }
       else
        as_fatal ("-march=%s: unsupported ISA subset `%c'", s, *p);
     }
+
+  free (extension);
 }
 
 /* Handle of the OPCODE hash table.  */
@@ -633,6 +643,7 @@ md_begin (void)
   hash_reg_names (RCLASS_FPR, riscv_fpr_names_abi, NFPR);
 
 #define DECLARE_CSR(name, num) hash_reg_name (RCLASS_CSR, #name, num);
+#define DECLARE_CSR_ALIAS(name, num) DECLARE_CSR(name, num);
 #include "opcode/riscv-opc.h"
 #undef DECLARE_CSR
 
@@ -705,6 +716,21 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr,
 
   add_fixed_insn (ip);
   install_insn (ip);
+
+  /* We need to start a new frag after any instruction that can be
+     optimized away or compressed by the linker during relaxation, to prevent
+     the assembler from computing static offsets across such an instruction.
+     This is necessary to get correct EH info.  */
+  if (reloc_type == BFD_RELOC_RISCV_CALL
+      || reloc_type == BFD_RELOC_RISCV_CALL_PLT
+      || reloc_type == BFD_RELOC_RISCV_HI20
+      || reloc_type == BFD_RELOC_RISCV_PCREL_HI20
+      || reloc_type == BFD_RELOC_RISCV_TPREL_HI20
+      || reloc_type == BFD_RELOC_RISCV_TPREL_ADD)
+    {
+      frag_wane (frag_now);
+      frag_new (0);
+    }
 }
 
 /* Build an instruction created by a macro expansion.  This is passed
@@ -1159,6 +1185,25 @@ my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
   return reloc_index;
 }
 
+/* Detect and handle implicitly zero load-store offsets.  For example,
+   "lw t0, (t1)" is shorthand for "lw t0, 0(t1)".  Return TRUE iff such
+   an implicit offset was detected.  */
+
+static bfd_boolean
+riscv_handle_implicit_zero_offset (expressionS *expr, const char *s)
+{
+  /* Check whether there is only a single bracketed expression left.
+     If so, it must be the base register and the constant must be zero.  */
+  if (*s == '(' && strchr (s + 1, '(') == 0)
+    {
+      expr->X_op = O_constant;
+      expr->X_add_number = 0;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 /* This routine assembles an instruction into its binary format.  As a
    side effect, it sets the global variable imm_reloc to the type of
    relocation to do if one of the operands is an address expression.  */
@@ -1299,6 +1344,8 @@ rvc_imm_done:
                  ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'k':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_LW_IMM (imm_expr->X_add_number))
@@ -1306,6 +1353,8 @@ rvc_imm_done:
                  ip->insn_opcode |= ENCODE_RVC_LW_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'l':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_LD_IMM (imm_expr->X_add_number))
@@ -1313,6 +1362,8 @@ rvc_imm_done:
                  ip->insn_opcode |= ENCODE_RVC_LD_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'm':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_LWSP_IMM (imm_expr->X_add_number))
@@ -1321,6 +1372,8 @@ rvc_imm_done:
                    ENCODE_RVC_LWSP_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'n':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_LDSP_IMM (imm_expr->X_add_number))
@@ -1354,6 +1407,8 @@ rvc_imm_done:
                    ENCODE_RVC_ADDI16SP_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'M':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_SWSP_IMM (imm_expr->X_add_number))
@@ -1362,6 +1417,8 @@ rvc_imm_done:
                    ENCODE_RVC_SWSP_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'N':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_SDSP_IMM (imm_expr->X_add_number))
@@ -1431,8 +1488,8 @@ rvc_lui:
              my_getExpression (imm_expr, s);
              check_absolute_expr (ip, imm_expr);
              if ((unsigned long) imm_expr->X_add_number > 31)
-               as_warn (_("Improper shift amount (%lu)"),
-                        (unsigned long) imm_expr->X_add_number);
+               as_bad (_("Improper shift amount (%lu)"),
+                       (unsigned long) imm_expr->X_add_number);
              INSERT_OPERAND (SHAMTW, *ip, imm_expr->X_add_number);
              imm_expr->X_op = O_absent;
              s = expr_end;
@@ -1442,8 +1499,8 @@ rvc_lui:
              my_getExpression (imm_expr, s);
              check_absolute_expr (ip, imm_expr);
              if ((unsigned long) imm_expr->X_add_number >= xlen)
-               as_warn (_("Improper shift amount (%lu)"),
-                        (unsigned long) imm_expr->X_add_number);
+               as_bad (_("Improper shift amount (%lu)"),
+                       (unsigned long) imm_expr->X_add_number);
              INSERT_OPERAND (SHAMT, *ip, imm_expr->X_add_number);
              imm_expr->X_op = O_absent;
              s = expr_end;
@@ -1453,8 +1510,8 @@ rvc_lui:
              my_getExpression (imm_expr, s);
              check_absolute_expr (ip, imm_expr);
              if ((unsigned long) imm_expr->X_add_number > 31)
-               as_warn (_("Improper CSRxI immediate (%lu)"),
-                        (unsigned long) imm_expr->X_add_number);
+               as_bad (_("Improper CSRxI immediate (%lu)"),
+                       (unsigned long) imm_expr->X_add_number);
              INSERT_OPERAND (RS1, *ip, imm_expr->X_add_number);
              imm_expr->X_op = O_absent;
              s = expr_end;
@@ -1468,8 +1525,8 @@ rvc_lui:
                  my_getExpression (imm_expr, s);
                  check_absolute_expr (ip, imm_expr);
                  if ((unsigned long) imm_expr->X_add_number > 0xfff)
-                   as_warn (_("Improper CSR address (%lu)"),
-                            (unsigned long) imm_expr->X_add_number);
+                   as_bad (_("Improper CSR address (%lu)"),
+                           (unsigned long) imm_expr->X_add_number);
                  INSERT_OPERAND (CSR, *ip, imm_expr->X_add_number);
                  imm_expr->X_op = O_absent;
                  s = expr_end;
@@ -1592,12 +1649,7 @@ rvc_lui:
              p = percent_op_rtype;
              *imm_reloc = BFD_RELOC_UNUSED;
 load_store:
-             /* Check whether there is only a single bracketed expression
-                left.  If so, it must be the base register and the
-                constant must be zero.  */
-             imm_expr->X_op = O_constant;
-             imm_expr->X_add_number = 0;
-             if (*s == '(' && strchr (s + 1, '(') == 0)
+             if (riscv_handle_implicit_zero_offset (imm_expr, s))
                continue;
 alu_op:
              /* If this value won't fit into a 16 bit offset, then go
@@ -1808,6 +1860,7 @@ riscv_after_parse_args (void)
     riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");
 
   /* Add the RVC extension, regardless of -march, to support .option rvc.  */
+  riscv_set_rvc (FALSE);
   if (riscv_subset_supports ("c"))
     riscv_set_rvc (TRUE);
   else
@@ -1856,6 +1909,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   bfd_byte *buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
   bfd_boolean relaxable = FALSE;
   offsetT loc;
+  segT sub_segment;
 
   /* Remember value for tc_gen_reloc.  */
   fixP->fx_addnumber = *valP;
@@ -1873,7 +1927,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       break;
 
     case BFD_RELOC_RISCV_GOT_HI20:
-    case BFD_RELOC_RISCV_PCREL_HI20:
     case BFD_RELOC_RISCV_ADD8:
     case BFD_RELOC_RISCV_ADD16:
     case BFD_RELOC_RISCV_ADD32:
@@ -1904,8 +1957,25 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
                      _("TLS relocation against a constant"));
       break;
 
-    case BFD_RELOC_64:
     case BFD_RELOC_32:
+      /* Use pc-relative relocation for FDE initial location.
+        The symbol address in .eh_frame may be adjusted in
+        _bfd_elf_discard_section_eh_frame, and the content of
+        .eh_frame will be adjusted in _bfd_elf_write_section_eh_frame.
+        Therefore, we cannot insert a relocation whose addend symbol is
+        in .eh_frame. Othrewise, the value may be adjusted twice.*/
+      if (fixP->fx_addsy && fixP->fx_subsy
+         && (sub_segment = S_GET_SEGMENT (fixP->fx_subsy))
+         && strcmp (sub_segment->name, ".eh_frame") == 0
+         && S_GET_VALUE (fixP->fx_subsy)
+            == fixP->fx_frag->fr_address + fixP->fx_where)
+       {
+         fixP->fx_r_type = BFD_RELOC_RISCV_32_PCREL;
+         fixP->fx_subsy = NULL;
+         break;
+       }
+      /* Fall through.  */
+    case BFD_RELOC_64:
     case BFD_RELOC_16:
     case BFD_RELOC_8:
     case BFD_RELOC_RISCV_CFA:
@@ -2049,8 +2119,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       relaxable = TRUE;
       break;
 
+    case BFD_RELOC_RISCV_PCREL_HI20:
     case BFD_RELOC_RISCV_PCREL_LO12_S:
     case BFD_RELOC_RISCV_PCREL_LO12_I:
+      relaxable = riscv_opts.relax;
+      break;
+
     case BFD_RELOC_RISCV_ALIGN:
       break;
 
@@ -2245,30 +2319,29 @@ bfd_boolean
 riscv_frag_align_code (int n)
 {
   bfd_vma bytes = (bfd_vma) 1 << n;
-  bfd_vma min_text_alignment_order = riscv_opts.rvc ? 1 : 2;
-  bfd_vma min_text_alignment = (bfd_vma) 1 << min_text_alignment_order;
+  bfd_vma insn_alignment = riscv_opts.rvc ? 2 : 4;
+  bfd_vma worst_case_bytes = bytes - insn_alignment;
+  char *nops;
+  expressionS ex;
+
+  /* If we are moving to a smaller alignment than the instruction size, then no
+     alignment is required. */
+  if (bytes <= insn_alignment)
+    return TRUE;
 
-  /* First, get back to minimal alignment.  */
-  frag_align_code (min_text_alignment_order, 0);
+  nops = frag_more (worst_case_bytes);
 
   /* When not relaxing, riscv_handle_align handles code alignment.  */
   if (!riscv_opts.relax)
     return FALSE;
 
-  if (bytes > min_text_alignment)
-    {
-      bfd_vma worst_case_bytes = bytes - min_text_alignment;
-      char *nops = frag_more (worst_case_bytes);
-      expressionS ex;
+  ex.X_op = O_constant;
+  ex.X_add_number = worst_case_bytes;
 
-      ex.X_op = O_constant;
-      ex.X_add_number = worst_case_bytes;
+  riscv_make_nops (nops, worst_case_bytes);
 
-      riscv_make_nops (nops, worst_case_bytes);
-
-      fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
-                  &ex, FALSE, BFD_RELOC_RISCV_ALIGN);
-    }
+  fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
+              &ex, FALSE, BFD_RELOC_RISCV_ALIGN);
 
   return TRUE;
 }
This page took 0.031074 seconds and 4 git commands to generate.