ubsan: spu: left shift of negative value
[deliverable/binutils-gdb.git] / gas / config / tc-riscv.c
index f164134470eec022a7c9d3711ab9d8529584c461..21fff8ffab886a6e9a593742c11aa4e903d3b11e 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-riscv.c -- RISC-V assembler
-   Copyright (C) 2011-2018 Free Software Foundation, Inc.
+   Copyright (C) 2011-2020 Free Software Foundation, Inc.
 
    Contributed by Andrew Waterman (andrew@sifive.com).
    Based on MIPS target.
@@ -59,6 +59,10 @@ struct riscv_cl_insn
 #define DEFAULT_ARCH "riscv64"
 #endif
 
+#ifndef DEFAULT_RISCV_ATTR
+#define DEFAULT_RISCV_ATTR 0
+#endif
+
 static const char default_arch[] = DEFAULT_ARCH;
 
 static unsigned xlen = 0; /* width of an x-register */
@@ -78,6 +82,7 @@ struct riscv_set_options
   int rvc; /* Generate RVC code.  */
   int rve; /* Generate RVE code.  */
   int relax; /* Emit relocs the linker is allowed to relax.  */
+  int arch_attr; /* Emit arch attribute.  */
 };
 
 static struct riscv_set_options riscv_opts =
@@ -86,6 +91,7 @@ static struct riscv_set_options riscv_opts =
   0,   /* rvc */
   0,   /* rve */
   1,   /* relax */
+  DEFAULT_RISCV_ATTR, /* arch_attr */
 };
 
 static void
@@ -115,15 +121,28 @@ riscv_subset_supports (const char *feature)
 }
 
 static bfd_boolean
-riscv_multi_subset_supports (const char *features[])
+riscv_multi_subset_supports (enum riscv_insn_class insn_class)
 {
-  unsigned i = 0;
-  bfd_boolean supported = TRUE;
+  switch (insn_class)
+    {
+    case INSN_CLASS_I: return riscv_subset_supports ("i");
+    case INSN_CLASS_C: return riscv_subset_supports ("c");
+    case INSN_CLASS_A: return riscv_subset_supports ("a");
+    case INSN_CLASS_M: return riscv_subset_supports ("m");
+    case INSN_CLASS_F: return riscv_subset_supports ("f");
+    case INSN_CLASS_D: return riscv_subset_supports ("d");
+    case INSN_CLASS_D_AND_C:
+      return riscv_subset_supports ("d") && riscv_subset_supports ("c");
 
-  for (;features[i]; ++i)
-    supported = supported && riscv_subset_supports (features[i]);
+    case INSN_CLASS_F_AND_C:
+      return riscv_subset_supports ("f") && riscv_subset_supports ("c");
 
-  return supported;
+    case INSN_CLASS_Q: return riscv_subset_supports ("q");
+
+    default:
+      as_fatal ("Unreachable");
+      return FALSE;
+    }
 }
 
 /* Set which ISA and extensions are available.  */
@@ -170,6 +189,12 @@ const char EXP_CHARS[] = "eE";
 /* or    0d1.2345e12 */
 const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
+/* Indicate we are already assemble any instructions or not.  */
+static bfd_boolean start_assemble = FALSE;
+
+/* Indicate arch attribute is explictly set.  */
+static bfd_boolean explicit_arch_attr = FALSE;
+
 /* Macros for encoding relaxation state for RVC branches and far jumps.  */
 #define RELAX_BRANCH_ENCODE(uncond, rvc, length)       \
   ((relax_substateT)                                   \
@@ -421,12 +446,6 @@ opcode_name_lookup (char **s)
   return o;
 }
 
-struct regname
-{
-  const char *name;
-  unsigned int num;
-};
-
 enum reg_class
 {
   RCLASS_GPR,
@@ -464,7 +483,7 @@ hash_reg_names (enum reg_class class, const char * const names[], unsigned n)
 static unsigned int
 reg_lookup_internal (const char *s, enum reg_class class)
 {
-  struct regname *r = (struct regname *) hash_find (reg_names_hash, s);
+  void *r = hash_find (reg_names_hash, s);
 
   if (r == NULL || DECODE_REG_CLASS (r) != class)
     return -1;
@@ -574,6 +593,7 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
          case 'v': used_bits |= ENCODE_RVC_IMM (-1U); break;
          case 'w': break; /* RS1S, constrained to equal RD */
          case 'x': break; /* RS2S, constrained to equal RD */
+         case 'z': break; /* RS2S, contrained to be x0 */
          case 'K': used_bits |= ENCODE_RVC_ADDI4SPN_IMM (-1U); break;
          case 'L': used_bits |= ENCODE_RVC_ADDI16SP_IMM (-1U); break;
          case 'M': used_bits |= ENCODE_RVC_SWSP_IMM (-1U); break;
@@ -915,6 +935,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
@@ -1000,8 +1043,9 @@ static void
 load_const (int reg, expressionS *ep)
 {
   int shift = RISCV_IMM_BITS;
+  bfd_vma upper_imm, sign = (bfd_vma) 1 << (RISCV_IMM_BITS - 1);
   expressionS upper = *ep, lower = *ep;
-  lower.X_add_number = (int32_t) ep->X_add_number << (32-shift) >> (32-shift);
+  lower.X_add_number = ((ep->X_add_number & (sign + sign - 1)) ^ sign) - sign;
   upper.X_add_number -= lower.X_add_number;
 
   if (ep->X_op != O_constant)
@@ -1019,9 +1063,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
     {
@@ -1030,13 +1075,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);
     }
 }
 
@@ -1386,7 +1434,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
       if ((insn->xlen_requirement != 0) && (xlen != insn->xlen_requirement))
        continue;
 
-      if (!riscv_multi_subset_supports (insn->subset))
+      if (!riscv_multi_subset_supports (insn->insn_class))
        continue;
 
       create_insn (ip, insn);
@@ -1460,6 +1508,11 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                      || regno != X_SP)
                    break;
                  continue;
+               case 'z': /* RS2, contrained to equal x0.  */
+                 if (!reg_lookup (&s, RCLASS_GPR, &regno)
+                     || regno != 0)
+                   break;
+                 continue;
                case '>':
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
@@ -1934,9 +1987,11 @@ branch:
 
            case 'u':           /* Upper 20 bits.  */
              p = percent_op_utype;
-             if (!my_getSmallExpression (imm_expr, imm_reloc, s, p)
-                 && imm_expr->X_op == O_constant)
+             if (!my_getSmallExpression (imm_expr, imm_reloc, s, p))
                {
+                 if (imm_expr->X_op != O_constant)
+                   break;
+
                  if (imm_expr->X_add_number < 0
                      || imm_expr->X_add_number >= (signed)RISCV_BIGIMM_REACH)
                    as_bad (_("lui expression not in range 0..1048575"));
@@ -1944,9 +1999,6 @@ branch:
                  *imm_reloc = BFD_RELOC_RISCV_HI20;
                  imm_expr->X_add_number <<= RISCV_IMM_BITS;
                }
-             /* The 'u' format specifier must be a symbol or a constant.  */
-             if (imm_expr->X_op != O_symbol && imm_expr->X_op != O_constant)
-               break;
              s = expr_end;
              continue;
 
@@ -2097,6 +2149,8 @@ md_assemble (char *str)
 
   const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash);
 
+  start_assemble = TRUE;
+
   if (error)
     {
       as_bad ("%s `%s'", error, str);
@@ -2131,6 +2185,8 @@ enum options
   OPTION_MABI,
   OPTION_RELAX,
   OPTION_NO_RELAX,
+  OPTION_ARCH_ATTR,
+  OPTION_NO_ARCH_ATTR,
   OPTION_END_OF_ENUM
 };
 
@@ -2143,6 +2199,8 @@ struct option md_longopts[] =
   {"mabi", required_argument, NULL, OPTION_MABI},
   {"mrelax", no_argument, NULL, OPTION_RELAX},
   {"mno-relax", no_argument, NULL, OPTION_NO_RELAX},
+  {"march-attr", no_argument, NULL, OPTION_ARCH_ATTR},
+  {"mno-arch-attr", no_argument, NULL, OPTION_NO_ARCH_ATTR},
 
   {NULL, no_argument, NULL, 0}
 };
@@ -2213,6 +2271,14 @@ md_parse_option (int c, const char *arg)
       riscv_opts.relax = FALSE;
       break;
 
+    case OPTION_ARCH_ATTR:
+      riscv_opts.arch_attr = TRUE;
+      break;
+
+    case OPTION_NO_ARCH_ATTR:
+      riscv_opts.arch_attr = FALSE;
+      break;
+
     default:
       return 0;
     }
@@ -2275,6 +2341,12 @@ riscv_after_parse_args (void)
 
   /* Insert float_abi into the EF_RISCV_FLOAT_ABI field of elf_flags.  */
   elf_flags |= float_abi * (EF_RISCV_FLOAT_ABI & ~(EF_RISCV_FLOAT_ABI << 1));
+
+  /* If the CIE to be produced has not been overridden on the command line,
+     then produce version 3 by default.  This allows us to use the full
+     range of registers in a .cfi_return_column directive.  */
+  if (flag_dwarf_cie_version == -1)
+    flag_dwarf_cie_version = 3;
 }
 
 long
@@ -2948,6 +3020,8 @@ RISC-V options:\n\
   -mabi=ABI      set the RISC-V ABI\n\
   -mrelax        enable relax (default)\n\
   -mno-relax     disable relax\n\
+  -march-attr    generate RISC-V arch attribute\n\
+  -mno-arch-attr don't generate RISC-V arch attribute\n\
 "));
 }
 
@@ -2969,6 +3043,10 @@ tc_riscv_regname_to_dw2regnum (char *regname)
   if ((reg = reg_lookup_internal (regname, RCLASS_FPR)) >= 0)
     return reg + 32;
 
+  /* CSRs are numbered 4096 -> 8191.  */
+  if ((reg = reg_lookup_internal (regname, RCLASS_CSR)) >= 0)
+    return reg + 4096;
+
   as_bad (_("unknown register `%s'"), regname);
   return -1;
 }
@@ -3031,6 +3109,104 @@ s_riscv_insn (int x ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* Update arch attributes.  */
+
+static void
+riscv_write_out_arch_attr (void)
+{
+  const char *arch_str = riscv_arch_str (xlen, &riscv_subsets);
+
+  bfd_elf_add_proc_attr_string (stdoutput, Tag_RISCV_arch, arch_str);
+
+  xfree ((void *)arch_str);
+}
+
+/* Add the default contents for the .riscv.attributes section.  */
+
+static void
+riscv_set_public_attributes (void)
+{
+  if (riscv_opts.arch_attr || explicit_arch_attr)
+    /* Re-write arch attribute to normalize the arch string.  */
+    riscv_write_out_arch_attr ();
+}
+
+/* Called after all assembly has been done.  */
+
+void
+riscv_md_end (void)
+{
+  riscv_set_public_attributes ();
+}
+
+/* Given a symbolic attribute NAME, return the proper integer value.
+   Returns -1 if the attribute is not known.  */
+
+int
+riscv_convert_symbolic_attribute (const char *name)
+{
+  static const struct
+  {
+    const char * name;
+    const int    tag;
+  }
+  attribute_table[] =
+    {
+      /* When you modify this table you should
+        also modify the list in doc/c-riscv.texi.  */
+#define T(tag) {#tag, Tag_RISCV_##tag},  {"Tag_RISCV_" #tag, Tag_RISCV_##tag}
+      T(arch),
+      T(priv_spec),
+      T(priv_spec_minor),
+      T(priv_spec_revision),
+      T(unaligned_access),
+      T(stack_align),
+#undef T
+    };
+
+  unsigned int i;
+
+  if (name == NULL)
+    return -1;
+
+  for (i = 0; i < ARRAY_SIZE (attribute_table); i++)
+    if (strcmp (name, attribute_table[i].name) == 0)
+      return attribute_table[i].tag;
+
+  return -1;
+}
+
+/* Parse a .attribute directive.  */
+
+static void
+s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)
+{
+  int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
+
+  if (tag == Tag_RISCV_arch)
+    {
+      unsigned old_xlen = xlen;
+
+      explicit_arch_attr = TRUE;
+      obj_attribute *attr;
+      attr = elf_known_obj_attributes_proc (stdoutput);
+      if (!start_assemble)
+       riscv_set_arch (attr[Tag_RISCV_arch].s);
+      else
+       as_fatal (_(".attribute arch must set before any instructions"));
+
+      if (old_xlen != xlen)
+       {
+         /* We must re-init bfd again if xlen is changed.  */
+         unsigned long mach = xlen == 64 ? bfd_mach_riscv64 : bfd_mach_riscv32;
+         bfd_find_target (riscv_target_format (), stdoutput);
+
+         if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach))
+           as_warn (_("Could not set architecture and machine"));
+       }
+    }
+}
+
 /* Pseudo-op table.  */
 
 static const pseudo_typeS riscv_pseudo_table[] =
@@ -3046,6 +3222,7 @@ static const pseudo_typeS riscv_pseudo_table[] =
   {"uleb128", s_riscv_leb128, 0},
   {"sleb128", s_riscv_leb128, 1},
   {"insn", s_riscv_insn, 0},
+  {"attribute", s_riscv_attribute, 0},
 
   { NULL, NULL, 0 },
 };
This page took 0.034331 seconds and 4 git commands to generate.