diff options
-rw-r--r-- | gas/ChangeLog | 8 | ||||
-rw-r--r-- | gas/config/tc-sparc.c | 51 |
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; |