diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 12 | ||||
-rw-r--r-- | gas/config/tc-mips.c | 168 |
2 files changed, 148 insertions, 32 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index eae3817..2c7c0f9 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,17 @@ +Wed Aug 18 15:30:29 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * config/tc-mips.c (append_insn): Don't swap branch instructions + if .set nobopt or .set volatile. + (gp_reference): .lit8 and .lit4 are accessed via the GP register. + (macro): Added cases M_LI_S, M_LI_SS. Fixed M_LI_D and M_LI_DD. + (mips_ip): Added cases 'F', 'L', 'f', 'l' for floating point. + * config/obj-ecoff.c: Renamed some variables to avoid shadow + warnings. + Mon Aug 16 14:16:02 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + * config/obj-coff.h (S_IS_COMMON): add missing backslash + * configure.in (z8k-*-{coff,sim}): use coffbfd for this target Thu Aug 12 11:47:58 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index e0cc5d4..453fa69 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -165,7 +165,7 @@ static void macro_build_lui PARAMS ((int *counter, expressionS * ep, static void set_at PARAMS ((int *counter, int reg)); static void set_at_unsigned PARAMS ((int *counter, int reg)); static void check_absolute_expr PARAMS ((struct mips_cl_insn * ip, - expressionS * expr)); + expressionS *)); static void load_register PARAMS ((int *counter, struct mips_cl_insn * ip, int reg, expressionS * ep)); @@ -635,6 +635,11 @@ append_insn (ip, address_expr, reloc_type) || (ip->insn_mo->pinfo & INSN_COND_BRANCH_DELAY)) { if (mips_optimize < 2 + /* If we have seen .set nobopt, don't optimize. */ + || mips_nobopt != 0 + /* If we have seen .set volatile or .set nomove, don't + optimize. */ + || mips_nomove != 0 /* If we had to emit any NOP instructions, then we already know we can not swap. */ || nops != 0 @@ -878,7 +883,9 @@ gp_reference (ep) return 1; segname = segment_name (S_GET_SEGMENT (ep->X_add_symbol)); return (strcmp (segname, ".sdata") == 0 - || strcmp (segname, ".sbss") == 0); + || strcmp (segname, ".sbss") == 0 + || strcmp (segname, ".lit8") == 0 + || strcmp (segname, ".lit4") == 0); #else /* ! defined (OBJ_ECOFF) */ /* The GP register is only used for ECOFF. */ return 0; @@ -1147,12 +1154,11 @@ set_at_unsigned (counter, reg) } static void -check_absolute_expr (ip, expr) +check_absolute_expr (ip, ex) struct mips_cl_insn *ip; - expressionS *expr; + expressionS *ex; { - - if (expr->X_op != O_constant) + if (ex->X_op != O_constant) as_warn ("Instruction %s requires absolute expression", ip->insn_mo->name); } @@ -1672,6 +1678,7 @@ macro (ip) s = "lwc0"; goto ld; case M_LWC1_AB: + case M_LI_SS: s = "lwc1"; goto ld; case M_LWC2_AB: @@ -1686,7 +1693,12 @@ macro (ip) case M_LWR_AB: s = "lwr"; ld: - if (breg == treg || mask == M_LWC1_AB) + if (breg == treg + || mask == M_LWC0_AB + || mask == M_LWC1_AB + || mask == M_LI_SS + || mask == M_LWC2_AB + || mask == M_LWC3_AB) { tempreg = AT; used_at = 1; @@ -1727,8 +1739,15 @@ macro (ip) tempreg = AT; used_at = 1; ld_st: - if (mask == M_LWC1_AB || mask == M_SWC1_AB) + if (mask == M_LWC1_AB || mask == M_SWC1_AB || mask == M_LI_SS) fmt = "T,o(b)"; + else if (mask == M_LWC0_AB + || mask == M_LWC2_AB + || mask == M_LWC3_AB + || mask == M_SWC0_AB + || mask == M_SWC2_AB + || mask == M_SWC3_AB) + fmt = "E,o(b)"; else fmt = "t,o(b)"; if (gp_reference (&offset_expr)) @@ -1753,21 +1772,18 @@ macro (ip) return; case M_LI: + case M_LI_S: load_register (&icnt, ip, treg, &imm_expr); return; case M_LI_D: - /* - 0x400370 <main>: lui $at,%hi(foo) - 0x400374 <main+4>: lw $v0,%lo(foo)($at) - 0x400378 <main+8>: lw $v1,%lo(foo+4)($at) - .data - <foo>: - .float 3.133435 - */ - /* FIXME: I don't think this is used at present, because the 'F' - format character is not supported. When this is supported, - it should use the GP register. */ + /* lui $at,%hi(foo) + lw $v0,%lo(foo)($at) + lw $v1,%lo(foo+4)($at) + .rdata + foo: + .double 3.133435 + */ macro_build_lui (&icnt, &offset_expr, AT); macro_build (&icnt, &offset_expr, "lw", "t,o(b)", treg, AT); offset_expr.X_add_number = 4; @@ -1775,18 +1791,9 @@ macro (ip) break; case M_LI_DD: - /* - 0x4003a0 <main>: lwc1 $f0,-32752($gp) - 0x4003a4 <main+4>: lwc1 $f1,-32748($gp) - 0x4003a8 <main+8>: nop - */ - /* FIXME: This is nonsense. It isn't used anyhow. */ - sreg = (ip->insn_opcode >> 11) & 0x1f; /* Fs reg */ - macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg, AT); - offset_expr.X_add_number = 4; - macro_build (&icnt, &offset_expr, "lwc1", "T,o(b)", treg + 1, AT); - break; - + /* Load a floating point number from the .lit8 section. */ + breg = GP; + /* Fall through. */ case M_L_DOB: /* Even on a big endian machine $fn comes before $fn+1. We have to adjust when loading from memory. */ @@ -2671,7 +2678,104 @@ mips_ip (str, ip) continue; case 'F': - as_bad ("Floating point constants only implemented for pseudo ops."); + case 'L': + case 'f': + case 'l': + { + int f64; + char *save_in; + char *err; + unsigned char temp[8]; + int length; + segT seg; + subsegT subseg; + char *p; + + /* These only appear as the last operand in an + instruction, and every instruction that accepts + them in any variant accepts them in all variants. + This means we don't have to worry about backing out + any changes if the instruction does not match. + + The difference between them is the size of the + floating point constant and where it goes. For 'F' + and 'L' the constant is 64 bits; for 'f' and 'l' it + is 32 bits. Where the constant is placed is based + on how the MIPS assembler does things: + F -- .rdata + L -- .lit8 + f -- immediate value + l -- .lit4 + */ + + f64 = *args == 'F' || *args == 'L'; + + save_in = input_line_pointer; + input_line_pointer = s; + err = md_atof (f64 ? 'd' : 'f', (char *) temp, &length); + s = input_line_pointer; + input_line_pointer = save_in; + if (err != NULL && *err != '\0') + { + as_bad ("Bad floating point constant: %s", err); + memset (temp, '\0', sizeof temp); + length = f64 ? 8 : 4; + } + + assert (length == (f64 ? 8 : 4)); + + if (*args == 'f') + { + imm_expr.X_op = O_constant; + if (byte_order == LITTLE_ENDIAN) + imm_expr.X_add_number = + (((((((int) temp[3] << 8) + | temp[2]) << 8) + | temp[1]) << 8) + | temp[0]); + else + imm_expr.X_add_number = + (((((((int) temp[0] << 8) + | temp[1]) << 8) + | temp[2]) << 8) + | temp[3]); + } + else + { + /* Switch to the right section. */ + seg = now_seg; + subseg = now_subseg; + switch (*args) + { + case 'F': + subseg_new (".rdata", (subsegT) 0); + break; + case 'L': + subseg_new (".lit8", (subsegT) 0); + break; + case 'l': + subseg_new (".lit4", (subsegT) 0); + break; + } + if (seg == now_seg) + as_bad ("Can't use floating point insn in this section"); + + /* Set the argument to the current address in the + .rdata section. */ + offset_expr.X_op = O_symbol; + offset_expr.X_add_symbol = + symbol_new ("L0\001", now_seg, + (valueT) frag_now_fix (), frag_now); + offset_expr.X_add_number = 0; + + /* Put the floating point number into the section. */ + p = frag_more (length); + memcpy (p, temp, length); + + /* Switch back to the original section. */ + subseg_set (seg, subseg); + } + } continue; case 'i': /* 16 bit unsigned immediate */ |