aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog8
-rw-r--r--gas/config/tc-sparc.c51
2 files changed, 54 insertions, 5 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index caf2699..520ea70 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,13 @@
Thu Apr 11 12:39:02 1996 Ian Lance Taylor <ian@cygnus.com>
+ * config/tc-sparc.c (last_insn): New static variable.
+ (md_assemble): Warn about putting floating point branches in a
+ delay slot. If architecture is less than v9, insert NOP
+ instructions between floating point instructions and floating
+ point branches. (The SunOS assembler does both these operations.)
+ Save the last instruction opcode.
+ (sparc_ip): Add pinsn parameter. Change caller.
+
* config/tc-m68k.c (md_estimate_size_before_relax): Correct check
for byte jump to next instruction to skip empty frags.
diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c
index 1c241e6..7d7e2c2 100644
--- a/gas/config/tc-sparc.c
+++ b/gas/config/tc-sparc.c
@@ -26,7 +26,7 @@
/* careful, this file includes data *declarations* */
#include "opcode/sparc.h"
-static void sparc_ip PARAMS ((char *));
+static void sparc_ip PARAMS ((char *, const struct sparc_opcode **));
/* Current architecture. We don't bump up unless necessary. */
static enum sparc_opcode_arch_val current_architecture = SPARC_OPCODE_ARCH_V6;
@@ -180,6 +180,9 @@ static int special_case;
#define SPECIAL_CASE_SET 1
#define SPECIAL_CASE_FDIV 2
+/* The last instruction to be assembled. */
+static const struct sparc_opcode *last_insn;
+
/*
* sort of like s_lcomm
*
@@ -660,8 +663,15 @@ sparc_md_end ()
bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_v8plus);
else if (current_architecture == SPARC_OPCODE_ARCH_V9A)
bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_v8plusa);
+ else if (current_architecture == SPARC_OPCODE_ARCH_SPARCLET)
+ bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_sparclet);
else
- bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc);
+ {
+ /* The sparclite is treated like a normal sparc. Perhaps it shouldn't
+ be but for now it is (since that's the way it's always been
+ treated). */
+ bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc);
+ }
#endif
}
@@ -669,11 +679,34 @@ void
md_assemble (str)
char *str;
{
+ const struct sparc_opcode *insn;
char *toP;
int rsd;
know (str);
- sparc_ip (str);
+ sparc_ip (str, &insn);
+
+ /* We warn about attempts to put a floating point branch in a delay
+ slot. */
+ if (insn != NULL
+ && last_insn != NULL
+ && (insn->flags & F_FBR) != 0
+ && (last_insn->flags & F_DELAYED) != 0)
+ as_warn ("FP branch in delay slot");
+
+ /* SPARC before v9 requires a nop instruction between a floating
+ point instruction and a floating point branch. We insert one
+ automatically, with a warning. */
+ if (max_architecture < SPARC_OPCODE_ARCH_V9
+ && insn != NULL
+ && last_insn != NULL
+ && (insn->flags & F_FBR) != 0
+ && (last_insn->flags & F_FLOAT) != 0)
+ {
+ as_warn ("FP branch preceded by FP instruction; NOP inserted");
+ toP = frag_more (4);
+ md_number_to_chars (toP, (valueT) 0x01000000, 4);
+ }
/* See if "set" operand is absolute and small; skip sethi if so. */
if (special_case == SPECIAL_CASE_SET
@@ -705,6 +738,8 @@ md_assemble (str)
the_insn.reloc);
}
+ last_insn = insn;
+
switch (special_case)
{
case SPECIAL_CASE_SET:
@@ -821,8 +856,9 @@ parse_const_expr_arg (input_pointerP, valueP)
}
static void
-sparc_ip (str)
+sparc_ip (str, pinsn)
char *str;
+ const struct sparc_opcode **pinsn;
{
char *error_message = "";
char *s;
@@ -858,6 +894,7 @@ sparc_ip (str)
as_fatal ("Unknown opcode: `%s'", str);
}
insn = (struct sparc_opcode *) hash_find (op_hash, str);
+ *pinsn = insn;
if (insn == NULL)
{
as_bad ("Unknown opcode: `%s'", str);
@@ -1243,6 +1280,7 @@ sparc_ip (str)
break;
case 'r': /* next operand must be a register */
+ case 'O':
case '1':
case '2':
case 'd':
@@ -1337,7 +1375,6 @@ sparc_ip (str)
it goes in the opcode. */
switch (*args)
{
-
case '1':
opcode |= mask << 14;
continue;
@@ -1353,6 +1390,10 @@ sparc_ip (str)
case 'r':
opcode |= (mask << 25) | (mask << 14);
continue;
+
+ case 'O':
+ opcode |= (mask << 25) | (mask << 0);
+ continue;
}
}
break;