Browse Source

binutils: improve GAS's constant-generation code

pull/6/head
Andrew Waterman 12 years ago
parent
commit
410529c4a4
  1. 58
      binutils/gas/config/tc-riscv.c

58
binutils/gas/config/tc-riscv.c

@ -1126,44 +1126,46 @@ check_absolute_expr (struct riscv_cl_insn *ip, expressionS *ex)
normalize_constant_expr (ex);
}
/* load_const generates an unoptimized instruction sequence to load
* an absolute expression into a register. */
/* Load an integer constant into a register. */
static void
load_const (int reg, expressionS *ep)
{
int shift = RISCV_IMM_BITS;
expressionS upper = *ep, lower = *ep;
lower.X_add_number = (int32_t) ep->X_add_number << (32-shift) >> (32-shift);
upper.X_add_number -= lower.X_add_number;
gas_assert (ep->X_op == O_constant);
gas_assert (reg != ZERO);
// this is an awful way to generate arbitrary 64-bit constants.
// fortunately, this is just used for hand-coded assembly programs.
if (rv64 && !IS_SEXT_32BIT_NUM(ep->X_add_number))
{
expressionS upper = *ep, lower = *ep;
upper.X_add_number = (int64_t)ep->X_add_number >> (RISCV_IMM_BITS-1);
load_const(reg, &upper);
macro_build (NULL, "slli", "d,s,>", reg, reg, RISCV_IMM_BITS-1);
{
/* Reduce to a signed 32-bit constant using SLLI and ADDI, which
is not optimal but also not so bad. */
while (((upper.X_add_number >> shift) & 1) == 0)
shift++;
lower.X_add_number = ep->X_add_number & (RISCV_IMM_REACH/2-1);
if (lower.X_add_number != 0)
macro_build (&lower, "addi", "d,s,j", reg, reg, BFD_RELOC_RISCV_LO12_I);
}
else // load a sign-extended 32-bit constant
{
int hi_reg = ZERO;
upper.X_add_number = (int64_t) upper.X_add_number >> shift;
load_const(reg, &upper);
int32_t hi = ep->X_add_number & (RISCV_IMM_REACH-1);
hi = hi << (32-RISCV_IMM_BITS) >> (32-RISCV_IMM_BITS);
hi = (int32_t)ep->X_add_number - hi;
if(hi)
{
macro_build (ep, "lui", "d,u", reg, BFD_RELOC_RISCV_HI20);
hi_reg = reg;
macro_build (NULL, "slli", "d,s,>", reg, reg, shift);
if (lower.X_add_number != 0)
macro_build (&lower, "addi", "d,s,j", reg, reg, BFD_RELOC_RISCV_LO12_I);
}
else
{
int hi_reg = ZERO;
if (upper.X_add_number != 0)
{
macro_build (ep, "lui", "d,u", reg, BFD_RELOC_RISCV_HI20);
hi_reg = reg;
}
if((ep->X_add_number & (RISCV_IMM_REACH-1)) || hi_reg == ZERO)
macro_build (ep, ADD32_INSN, "d,s,j", reg, hi_reg, BFD_RELOC_RISCV_LO12_I);
}
if (lower.X_add_number != 0 || hi_reg == ZERO)
macro_build (ep, ADD32_INSN, "d,s,j", reg, hi_reg,
BFD_RELOC_RISCV_LO12_I);
}
}
/* Expand RISC-V assembly macros into one or more instructions. */

Loading…
Cancel
Save