diff options
-rw-r--r-- | gas/ChangeLog | 7 | ||||
-rw-r--r-- | gas/config/tc-mips.c | 303 |
2 files changed, 261 insertions, 49 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 72217a0..04ea31b 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,10 @@ +2001-10-10 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + + * config/tc-mips.c + (load_address): Support both 32- and 64-bit addresses. + (macro): Call load_register correctly. Expand 64-bit loads ans stores. + (macro2): Call load_address correctly. + 2001-10-09 Christian Groessler <cpg@aladdin.de> * config/tc-z8k.c: Include opcodes/z8k-opc.h after bfd.h diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 9a5abb1..712488a 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -663,7 +663,7 @@ static void set_at PARAMS ((int *counter, int reg, int unsignedp)); static void check_absolute_expr PARAMS ((struct mips_cl_insn * ip, expressionS *)); static void load_register PARAMS ((int *, int, expressionS *, int)); -static void load_address PARAMS ((int *counter, int reg, expressionS *ep)); +static void load_address PARAMS ((int *, int, expressionS *, int, int *)); static void move_register PARAMS ((int *, int, int)); static void macro PARAMS ((struct mips_cl_insn * ip)); static void mips16_macro PARAMS ((struct mips_cl_insn * ip)); @@ -3489,10 +3489,12 @@ load_register (counter, reg, ep, dbl) /* Load an address into a register. */ static void -load_address (counter, reg, ep) +load_address (counter, reg, ep, dbl, used_at) int *counter; int reg; expressionS *ep; + int dbl; + int *used_at; { char *p; @@ -3505,7 +3507,7 @@ load_address (counter, reg, ep) if (ep->X_op == O_constant) { - load_register (counter, reg, ep, 0); + load_register (counter, reg, ep, dbl); return; } @@ -3516,27 +3518,86 @@ load_address (counter, reg, ep) Otherwise we want lui $reg,<sym> (BFD_RELOC_HI16_S) addiu $reg,$reg,<sym> (BFD_RELOC_LO16) - If we have an addend, we always use the latter form. */ - if ((valueT) ep->X_add_number > MAX_GPREL_OFFSET - || nopic_need_relax (ep->X_add_symbol, 1)) - p = NULL; + If we have an addend, we always use the latter form. + + With 64bit address space and a usable $at we want + lui $reg,<sym> (BFD_RELOC_MIPS_HIGHEST) + lui $at,<sym> (BFD_RELOC_HI16_S) + daddiu $reg,<sym> (BFD_RELOC_MIPS_HIGHER) + daddiu $at,<sym> (BFD_RELOC_LO16) + dsll32 $reg,0 + dadd $reg,$reg,$at + + If $at is already in use, we use an path which is suboptimal + on superscalar processors. + lui $reg,<sym> (BFD_RELOC_MIPS_HIGHEST) + daddiu $reg,<sym> (BFD_RELOC_MIPS_HIGHER) + dsll $reg,16 + daddiu $reg,<sym> (BFD_RELOC_HI16_S) + dsll $reg,16 + daddiu $reg,<sym> (BFD_RELOC_LO16) + */ + if (HAVE_64BIT_ADDRESSES) + { + p = NULL; + + /* We don't do GP optimization for now because RELAX_ENCODE can't + hold the data for such large chunks. */ + + if (*used_at == 0) + { + macro_build (p, counter, ep, "lui", "t,u", + reg, (int) BFD_RELOC_MIPS_HIGHEST); + macro_build (p, counter, ep, "lui", "t,u", + AT, (int) BFD_RELOC_HI16_S); + macro_build (p, counter, ep, "daddiu", "t,r,j", + reg, reg, (int) BFD_RELOC_MIPS_HIGHER); + macro_build (p, counter, ep, "daddiu", "t,r,j", + AT, AT, (int) BFD_RELOC_LO16); + macro_build (p, counter, NULL, "dsll32", "d,w,<", + reg, reg, 0); + macro_build (p, counter, NULL, "dadd", "d,v,t", + reg, reg, AT); + *used_at = 1; + } + else + { + macro_build (p, counter, ep, "lui", "t,u", + reg, (int) BFD_RELOC_MIPS_HIGHEST); + macro_build (p, counter, ep, "daddiu", "t,r,j", + reg, reg, (int) BFD_RELOC_MIPS_HIGHER); + macro_build (p, counter, NULL, "dsll", "d,w,<", + reg, reg, 16); + macro_build (p, counter, ep, "daddiu", "t,r,j", + reg, reg, (int) BFD_RELOC_HI16_S); + macro_build (p, counter, NULL, "dsll", "d,w,<", + reg, reg, 16); + macro_build (p, counter, ep, "daddiu", "t,r,j", + reg, reg, (int) BFD_RELOC_LO16); + } + } else { - frag_grow (20); - macro_build ((char *) NULL, counter, ep, + p = NULL; + if ((valueT) ep->X_add_number <= MAX_GPREL_OFFSET + && ! nopic_need_relax (ep->X_add_symbol, 1)) + { + frag_grow (20); + macro_build ((char *) NULL, counter, ep, + HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", + "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL); + p = frag_var (rs_machine_dependent, 8, 0, + RELAX_ENCODE (4, 8, 0, 4, 0, + mips_opts.warn_about_macros), + ep->X_add_symbol, (offsetT) 0, (char *) NULL); + } + macro_build_lui (p, counter, ep, reg); + if (p != NULL) + p += 4; + macro_build (p, counter, ep, HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", - "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL); - p = frag_var (rs_machine_dependent, 8, 0, - RELAX_ENCODE (4, 8, 0, 4, 0, - mips_opts.warn_about_macros), - ep->X_add_symbol, (offsetT) 0, (char *) NULL); - } - macro_build_lui (p, counter, ep, reg); - if (p != NULL) - p += 4; - macro_build (p, counter, ep, - HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", - "t,r,j", reg, reg, (int) BFD_RELOC_LO16); + "t,r,j", reg, reg, (int) BFD_RELOC_LO16); + } } else if (mips_pic == SVR4_PIC && ! mips_big_got) { @@ -3801,7 +3862,7 @@ macro (ip) return; } - load_register (&icnt, AT, &imm_expr, 0); + load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS); macro_build ((char *) NULL, &icnt, NULL, s2, "d,v,t", treg, sreg, AT); break; @@ -4406,34 +4467,91 @@ macro (ip) load_register (&icnt, tempreg, &offset_expr, dbl); else if (mips_pic == NO_PIC) { - /* If this is a reference to an GP relative symbol, we want + /* If this is a reference to a GP relative symbol, we want addiu $tempreg,$gp,<sym> (BFD_RELOC_MIPS_GPREL) Otherwise we want lui $tempreg,<sym> (BFD_RELOC_HI16_S) addiu $tempreg,$tempreg,<sym> (BFD_RELOC_LO16) If we have a constant, we need two instructions anyhow, - so we may as well always use the latter form. */ - if ((valueT) offset_expr.X_add_number > MAX_GPREL_OFFSET - || nopic_need_relax (offset_expr.X_add_symbol, 1)) - p = NULL; - else + so we may as well always use the latter form. + + With 64bit address space and a usable $at we want + lui $tempreg,<sym> (BFD_RELOC_MIPS_HIGHEST) + lui $at,<sym> (BFD_RELOC_HI16_S) + daddiu $tempreg,<sym> (BFD_RELOC_MIPS_HIGHER) + daddiu $at,<sym> (BFD_RELOC_LO16) + dsll32 $tempreg,0 + dadd $tempreg,$tempreg,$at + + If $at is already in use, we use an path which is suboptimal + on superscalar processors. + lui $tempreg,<sym> (BFD_RELOC_MIPS_HIGHEST) + daddiu $tempreg,<sym> (BFD_RELOC_MIPS_HIGHER) + dsll $tempreg,16 + daddiu $tempreg,<sym> (BFD_RELOC_HI16_S) + dsll $tempreg,16 + daddiu $tempreg,<sym> (BFD_RELOC_LO16) + */ + p = NULL; + if (HAVE_64BIT_ADDRESSES) { - frag_grow (20); - macro_build ((char *) NULL, &icnt, &offset_expr, - HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", - "t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL); - p = frag_var (rs_machine_dependent, 8, 0, - RELAX_ENCODE (4, 8, 0, 4, 0, - mips_opts.warn_about_macros), - offset_expr.X_add_symbol, (offsetT) 0, - (char *) NULL); - } - macro_build_lui (p, &icnt, &offset_expr, tempreg); - if (p != NULL) - p += 4; - macro_build (p, &icnt, &offset_expr, - HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", - "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16); + /* We don't do GP optimization for now because RELAX_ENCODE can't + hold the data for such large chunks. */ + + if (used_at == 0) + { + macro_build (p, &icnt, &offset_expr, "lui", "t,u", + tempreg, (int) BFD_RELOC_MIPS_HIGHEST); + macro_build (p, &icnt, &offset_expr, "lui", "t,u", + AT, (int) BFD_RELOC_HI16_S); + macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j", + tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER); + macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j", + AT, AT, (int) BFD_RELOC_LO16); + macro_build (p, &icnt, NULL, "dsll32", "d,w,<", + tempreg, tempreg, 0); + macro_build (p, &icnt, NULL, "dadd", "d,v,t", + tempreg, tempreg, AT); + used_at = 1; + } + else + { + macro_build (p, &icnt, &offset_expr, "lui", "t,u", + tempreg, (int) BFD_RELOC_MIPS_HIGHEST); + macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j", + tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER); + macro_build (p, &icnt, NULL, "dsll", "d,w,<", + tempreg, tempreg, 16); + macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j", + tempreg, tempreg, (int) BFD_RELOC_HI16_S); + macro_build (p, &icnt, NULL, "dsll", "d,w,<", + tempreg, tempreg, 16); + macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j", + tempreg, tempreg, (int) BFD_RELOC_LO16); + } + } + else + { + if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET + && ! nopic_need_relax (offset_expr.X_add_symbol, 1)) + { + frag_grow (20); + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", + "t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL); + p = frag_var (rs_machine_dependent, 8, 0, + RELAX_ENCODE (4, 8, 0, 4, 0, + mips_opts.warn_about_macros), + offset_expr.X_add_symbol, (offsetT) 0, + (char *) NULL); + } + macro_build_lui (p, &icnt, &offset_expr, tempreg); + if (p != NULL) + p += 4; + macro_build (p, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", + "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16); + } } else if (mips_pic == SVR4_PIC && ! mips_big_got) { @@ -5164,7 +5282,90 @@ macro (ip) lui $tempreg,<sym> (BFD_RELOC_HI16_S) addu $tempreg,$tempreg,$breg <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16) - With a constant we always use the latter case. */ + With a constant we always use the latter case. + + With 64bit address space and no base register and $at usable, + we want + lui $tempreg,<sym> (BFD_RELOC_MIPS_HIGHEST) + lui $at,<sym> (BFD_RELOC_HI16_S) + daddiu $tempreg,<sym> (BFD_RELOC_MIPS_HIGHER) + dsll32 $tempreg,0 + daddu $tempreg,$at + <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16) + If we have a base register, we want + lui $tempreg,<sym> (BFD_RELOC_MIPS_HIGHEST) + lui $at,<sym> (BFD_RELOC_HI16_S) + daddiu $tempreg,<sym> (BFD_RELOC_MIPS_HIGHER) + daddu $at,$breg + dsll32 $tempreg,0 + daddu $tempreg,$at + <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16) + + Without $at we can't generate the optimal path for superscalar + processors here since this would require two temporary registers. + lui $tempreg,<sym> (BFD_RELOC_MIPS_HIGHEST) + daddiu $tempreg,<sym> (BFD_RELOC_MIPS_HIGHER) + dsll $tempreg,16 + daddiu $tempreg,<sym> (BFD_RELOC_HI16_S) + dsll $tempreg,16 + <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16) + If we have a base register, we want + lui $tempreg,<sym> (BFD_RELOC_MIPS_HIGHEST) + daddiu $tempreg,<sym> (BFD_RELOC_MIPS_HIGHER) + dsll $tempreg,16 + daddiu $tempreg,<sym> (BFD_RELOC_HI16_S) + dsll $tempreg,16 + daddu $tempreg,$tempreg,$breg + <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16) + */ + if (HAVE_64BIT_ADDRESSES) + { + p = NULL; + + /* We don't do GP optimization for now because RELAX_ENCODE can't + hold the data for such large chunks. */ + + if (used_at == 0) + { + macro_build (p, &icnt, &offset_expr, "lui", "t,u", + tempreg, (int) BFD_RELOC_MIPS_HIGHEST); + macro_build (p, &icnt, &offset_expr, "lui", "t,u", + AT, (int) BFD_RELOC_HI16_S); + macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j", + tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER); + if (breg != 0) + macro_build (p, &icnt, NULL, "daddu", "d,v,t", + AT, AT, breg); + macro_build (p, &icnt, NULL, "dsll32", "d,w,<", + tempreg, tempreg, 0); + macro_build (p, &icnt, NULL, "daddu", "d,v,t", + tempreg, tempreg, AT); + macro_build (p, &icnt, &offset_expr, s, + fmt, treg, (int) BFD_RELOC_LO16, tempreg); + used_at = 1; + } + else + { + macro_build (p, &icnt, &offset_expr, "lui", "t,u", + tempreg, (int) BFD_RELOC_MIPS_HIGHEST); + macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j", + tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER); + macro_build (p, &icnt, NULL, "dsll", "d,w,<", + tempreg, tempreg, 16); + macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j", + tempreg, tempreg, (int) BFD_RELOC_HI16_S); + macro_build (p, &icnt, NULL, "dsll", "d,w,<", + tempreg, tempreg, 16); + if (breg != 0) + macro_build (p, &icnt, NULL, "daddu", "d,v,t", + tempreg, tempreg, breg); + macro_build (p, &icnt, &offset_expr, s, + fmt, treg, (int) BFD_RELOC_LO16, tempreg); + } + + return; + } + if (breg == 0) { if ((valueT) offset_expr.X_add_number > MAX_GPREL_OFFSET @@ -6617,7 +6818,8 @@ macro2 (ip) s2 = "lwr"; off = 3; ulwa: - load_address (&icnt, AT, &offset_expr); + used_at = 1; + load_address (&icnt, AT, &offset_expr, HAVE_64BIT_ADDRESSES, &used_at); if (breg != 0) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, HAVE_32BIT_ADDRESSES ? "addu" : "daddu", @@ -6638,7 +6840,8 @@ macro2 (ip) case M_ULH_A: case M_ULHU_A: - load_address (&icnt, AT, &offset_expr); + used_at = 1; + load_address (&icnt, AT, &offset_expr, HAVE_64BIT_ADDRESSES, &used_at); if (breg != 0) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, HAVE_32BIT_ADDRESSES ? "addu" : "daddu", @@ -6710,7 +6913,8 @@ macro2 (ip) s2 = "swr"; off = 3; uswa: - load_address (&icnt, AT, &offset_expr); + used_at = 1; + load_address (&icnt, AT, &offset_expr, HAVE_64BIT_ADDRESSES, &used_at); if (breg != 0) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, HAVE_32BIT_ADDRESSES ? "addu" : "daddu", @@ -6730,7 +6934,8 @@ macro2 (ip) break; case M_USH_A: - load_address (&icnt, AT, &offset_expr); + used_at = 1; + load_address (&icnt, AT, &offset_expr, HAVE_64BIT_ADDRESSES, &used_at); if (breg != 0) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, HAVE_32BIT_ADDRESSES ? "addu" : "daddu", |