/* tc-sparc.c -- Assemble for the SPARC
Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
/* The currently selected v9 memory model. Currently only used for
ELF. */
static enum { MM_TSO, MM_PSO, MM_RMO } sparc_memory_model = MM_RMO;
+
+#ifndef TE_SOLARIS
+/* Bitmask of instruction types seen so far, used to populate the
+ GNU attributes section with hwcap information. */
+static int hwcap_seen;
+#endif
#endif
+static int hwcap_allowed;
+
static int architecture_requested;
static int warn_on_bump;
int default_arch_size;
/* Allowable arg to -A? */
int user_option_p;
+ int hwcap_allowed;
} sparc_arch_table[] = {
- { "v6", "v6", v6, 0, 1 },
- { "v7", "v7", v7, 0, 1 },
- { "v8", "v8", v8, 32, 1 },
- { "sparclet", "sparclet", sparclet, 32, 1 },
- { "sparclite", "sparclite", sparclite, 32, 1 },
- { "sparc86x", "sparclite", sparc86x, 32, 1 },
- { "v8plus", "v9", v9, 0, 1 },
- { "v8plusa", "v9a", v9, 0, 1 },
- { "v8plusb", "v9b", v9, 0, 1 },
- { "v9", "v9", v9, 0, 1 },
- { "v9a", "v9a", v9, 0, 1 },
- { "v9b", "v9b", v9, 0, 1 },
+ { "v6", "v6", v6, 0, 1, 0 },
+ { "v7", "v7", v7, 0, 1, 0 },
+ { "v8", "v8", v8, 32, 1, F_MUL32|F_DIV32|F_FSMULD },
+ { "v8a", "v8", v8, 32, 1, F_MUL32|F_DIV32|F_FSMULD },
+ { "sparc", "v9", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS },
+ { "sparcvis", "v9a", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS },
+ { "sparcvis2", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2 },
+ { "sparcfmaf", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_FMAF },
+ { "sparcima", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_FMAF|F_IMA },
+ { "sparcvis3", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_FMAF|F_VIS3|F_HPC },
+ { "sparcvis3r", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_FMAF|F_VIS3|F_HPC|F_RANDOM|F_TRANS|F_FJFMAU },
+ { "sparclet", "sparclet", sparclet, 32, 1, F_MUL32|F_DIV32|F_FSMULD },
+ { "sparclite", "sparclite", sparclite, 32, 1, F_MUL32|F_DIV32|F_FSMULD },
+ { "sparc86x", "sparclite", sparc86x, 32, 1, F_MUL32|F_DIV32|F_FSMULD },
+ { "v8plus", "v9", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS },
+ { "v8plusa", "v9a", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS|F_VIS },
+ { "v8plusb", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS|F_VIS|F_VIS2 },
+ { "v8plusc", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS|F_VIS|F_VIS2|F_ASI_BLK_INIT },
+ { "v8plusd", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS|F_VIS|F_VIS2|F_ASI_BLK_INIT|F_FMAF|F_VIS3|F_HPC },
+ { "v8plusv", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_V8PLUS|F_VIS|F_VIS2|F_ASI_BLK_INIT|F_FMAF|F_VIS3|F_HPC|F_RANDOM|F_TRANS|F_FJFMAU|F_IMA|F_ASI_CACHE_SPARING },
+ { "v9", "v9", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC },
+ { "v9a", "v9a", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS },
+ { "v9b", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2 },
+ { "v9c", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_ASI_BLK_INIT },
+ { "v9d", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_ASI_BLK_INIT|F_FMAF|F_VIS3|F_HPC },
+ { "v9v", "v9b", v9, 0, 1, F_MUL32|F_DIV32|F_FSMULD|F_POPC|F_VIS|F_VIS2|F_ASI_BLK_INIT|F_FMAF|F_VIS3|F_HPC|F_RANDOM|F_TRANS|F_FJFMAU|F_IMA|F_ASI_CACHE_SPARING },
/* This exists to allow configure.in/Makefile.in to pass one
value to specify both the default machine and default word size. */
- { "v9-64", "v9", v9, 64, 0 },
- { NULL, NULL, v8, 0, 0 }
+ { "v9-64", "v9", v9, 64, 0, F_MUL32|F_DIV32|F_FSMULD|F_POPC },
+ { NULL, NULL, v8, 0, 0, 0 }
};
/* Variant of default_arch */
if (opcode_arch == SPARC_OPCODE_ARCH_BAD)
as_fatal (_("Bad opcode table, broken assembler."));
- max_architecture = opcode_arch;
+ if (!architecture_requested
+ || opcode_arch > max_architecture)
+ max_architecture = opcode_arch;
+ hwcap_allowed |= sa->hwcap_allowed;
architecture_requested = 1;
}
break;
{"pcr", 16},
{"gsr", 19},
{"dcr", 18},
+ {"cps", 28},
{"clear_softint", 21},
{"", -1}, /* End marker. */
};
default: break;
}
bfd_set_arch_mach (stdoutput, bfd_arch_sparc, mach);
+
+#if defined(OBJ_ELF) && !defined(TE_SOLARIS)
+ if (hwcap_seen)
+ {
+ int bits = 0;
+
+ if (hwcap_seen & F_MUL32)
+ bits |= ELF_SPARC_HWCAP_MUL32;
+ if (hwcap_seen & F_DIV32)
+ bits |= ELF_SPARC_HWCAP_DIV32;
+ if (hwcap_seen & F_FSMULD)
+ bits |= ELF_SPARC_HWCAP_FSMULD;
+ if (hwcap_seen & F_V8PLUS)
+ bits |= ELF_SPARC_HWCAP_V8PLUS;
+ if (hwcap_seen & F_POPC)
+ bits |= ELF_SPARC_HWCAP_POPC;
+ if (hwcap_seen & F_VIS)
+ bits |= ELF_SPARC_HWCAP_VIS;
+ if (hwcap_seen & F_VIS2)
+ bits |= ELF_SPARC_HWCAP_VIS2;
+ if (hwcap_seen & F_ASI_BLK_INIT)
+ bits |= ELF_SPARC_HWCAP_ASI_BLK_INIT;
+ if (hwcap_seen & F_FMAF)
+ bits |= ELF_SPARC_HWCAP_FMAF;
+ if (hwcap_seen & F_VIS3)
+ bits |= ELF_SPARC_HWCAP_VIS3;
+ if (hwcap_seen & F_HPC)
+ bits |= ELF_SPARC_HWCAP_HPC;
+ if (hwcap_seen & F_RANDOM)
+ bits |= ELF_SPARC_HWCAP_RANDOM;
+ if (hwcap_seen & F_TRANS)
+ bits |= ELF_SPARC_HWCAP_TRANS;
+ if (hwcap_seen & F_FJFMAU)
+ bits |= ELF_SPARC_HWCAP_FJFMAU;
+ if (hwcap_seen & F_IMA)
+ bits |= ELF_SPARC_HWCAP_IMA;
+ if (hwcap_seen & F_ASI_CACHE_SPARING)
+ bits |= ELF_SPARC_HWCAP_ASI_CACHE_SPARING;
+
+ bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_Sparc_HWCAPS, bits);
+ }
+#endif
}
\f
/* Return non-zero if VAL is in the range -(MAX+1) to MAX. */
}
}
+static const char *
+get_hwcap_name (int mask)
+{
+ if (mask & F_MUL32)
+ return "mul32";
+ if (mask & F_DIV32)
+ return "div32";
+ if (mask & F_FSMULD)
+ return "fsmuld";
+ if (mask & F_V8PLUS)
+ return "v8plus";
+ if (mask & F_POPC)
+ return "popc";
+ if (mask & F_VIS)
+ return "vis";
+ if (mask & F_VIS2)
+ return "vis2";
+ if (mask & F_ASI_BLK_INIT)
+ return "ASIBlkInit";
+ if (mask & F_FMAF)
+ return "fmaf";
+ if (mask & F_VIS3)
+ return "vis3";
+ if (mask & F_HPC)
+ return "hpc";
+ if (mask & F_RANDOM)
+ return "random";
+ if (mask & F_TRANS)
+ return "trans";
+ if (mask & F_FJFMAU)
+ return "fjfmau";
+ if (mask & F_IMA)
+ return "ima";
+ if (mask & F_ASI_CACHE_SPARING)
+ return "cspare";
+ return "UNKNOWN";
+}
+
/* Subroutine of md_assemble to do the actual parsing. */
static int
case 'B':
case 'R':
+ case '4':
+ case '5':
+
case 'g':
case 'H':
case 'J':
if ((*args == 'v'
|| *args == 'B'
+ || *args == '5'
|| *args == 'H')
&& (mask & 1))
{
opcode |= RS2 (mask);
continue;
+ case '4':
+ case '5':
+ opcode |= RS3 (mask);
+ continue;
+
case 'g':
case 'H':
case 'J':
}
break;
+ case '(':
+ if (strncmp (s, "%efsr", 5) == 0)
+ {
+ s += 5;
+ continue;
+ }
+ break;
+
case '0': /* 64 bit immediate (set, setsw, setx insn) */
the_insn.reloc = BFD_RELOC_NONE; /* reloc handled elsewhere */
goto immediate;
{
if (s1[-2] == '%' && s1[-3] == '+')
s1 -= 3;
- else if (strchr ("goli0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+')
+ else if (strchr ("golir0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+')
s1 -= 4;
+ else if (s1[-3] == 'r' && s1[-4] == '%' && s1[-5] == '+')
+ s1 -= 5;
else
s1 = NULL;
if (s1)
{
/* We have a match. Now see if the architecture is OK. */
int needed_arch_mask = insn->architecture;
+ int hwcaps = insn->flags & F_HWCAP_MASK;
+#if defined(OBJ_ELF) && !defined(TE_SOLARIS)
+ if (hwcaps)
+ hwcap_seen |= hwcaps;
+#endif
if (v9_arg_p)
{
needed_arch_mask &=
sparc_opcode_archs[max_architecture].name);
return special_case;
}
+
+ /* Make sure the the hwcaps used by the instruction are
+ currently enabled. */
+ if (hwcaps & ~hwcap_allowed)
+ {
+ const char *hwcap_name = get_hwcap_name(hwcaps & ~hwcap_allowed);
+
+ as_bad (_("Hardware capability \"%s\" not enabled for \"%s\"."),
+ hwcap_name, str);
+ return special_case;
+ }
} /* If no match. */
break;