727 lines
19 KiB
C
727 lines
19 KiB
C
/* Subroutines used for calculate rtx costs of Andes NDS32 cpu for GNU compiler
|
|
Copyright (C) 2012-2021 Free Software Foundation, Inc.
|
|
Contributed by Andes Technology Corporation.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published
|
|
by the Free Software Foundation; either version 3, or (at your
|
|
option) any later version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
#define IN_TARGET_CODE 1
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "backend.h"
|
|
#include "target.h"
|
|
#include "rtl.h"
|
|
#include "tree.h"
|
|
#include "memmodel.h"
|
|
#include "tm_p.h"
|
|
#include "optabs.h" /* For GEN_FCN. */
|
|
#include "recog.h"
|
|
#include "tm-constrs.h"
|
|
#include "tree-pass.h"
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
typedef bool (*rtx_cost_func) (rtx, int, int, int, int*);
|
|
|
|
struct rtx_cost_model_t {
|
|
rtx_cost_func speed_prefer;
|
|
rtx_cost_func size_prefer;
|
|
};
|
|
|
|
static rtx_cost_model_t rtx_cost_model;
|
|
|
|
static int insn_size_16bit; /* Initial at nds32_init_rtx_costs. */
|
|
static const int insn_size_32bit = 4;
|
|
|
|
static bool
|
|
nds32_rtx_costs_speed_prefer (rtx x ATTRIBUTE_UNUSED,
|
|
int code,
|
|
int outer_code ATTRIBUTE_UNUSED,
|
|
int opno ATTRIBUTE_UNUSED,
|
|
int *total)
|
|
{
|
|
rtx op0;
|
|
rtx op1;
|
|
machine_mode mode = GET_MODE (x);
|
|
/* Scale cost by mode size. */
|
|
int cost = COSTS_N_INSNS (GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode));
|
|
|
|
switch (code)
|
|
{
|
|
case USE:
|
|
/* Used in combine.c as a marker. */
|
|
*total = 0;
|
|
return true;
|
|
|
|
case CONST_INT:
|
|
/* When not optimizing for size, we care more about the cost
|
|
of hot code, and hot code is often in a loop. If a constant
|
|
operand needs to be forced into a register, we will often be
|
|
able to hoist the constant load out of the loop, so the load
|
|
should not contribute to the cost. */
|
|
if (outer_code == SET || outer_code == PLUS)
|
|
*total = satisfies_constraint_Is20 (x) ? 0 : 4;
|
|
else if (outer_code == AND || outer_code == IOR || outer_code == XOR
|
|
|| outer_code == MINUS)
|
|
*total = satisfies_constraint_Iu15 (x) ? 0 : 4;
|
|
else if (outer_code == ASHIFT || outer_code == ASHIFTRT
|
|
|| outer_code == LSHIFTRT)
|
|
*total = satisfies_constraint_Iu05 (x) ? 0 : 4;
|
|
else if (GET_RTX_CLASS (outer_code) == RTX_COMPARE
|
|
|| GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE)
|
|
*total = satisfies_constraint_Is16 (x) ? 0 : 4;
|
|
else
|
|
*total = COSTS_N_INSNS (1);
|
|
return true;
|
|
|
|
case CONST:
|
|
case LO_SUM:
|
|
case HIGH:
|
|
case SYMBOL_REF:
|
|
*total = COSTS_N_INSNS (1);
|
|
return true;
|
|
|
|
case MEM:
|
|
*total = COSTS_N_INSNS (1);
|
|
return true;
|
|
|
|
case SET:
|
|
op0 = SET_DEST (x);
|
|
op1 = SET_SRC (x);
|
|
mode = GET_MODE (op0);
|
|
/* Scale cost by mode size. */
|
|
cost = COSTS_N_INSNS (GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode));
|
|
|
|
switch (GET_CODE (op1))
|
|
{
|
|
case REG:
|
|
case SUBREG:
|
|
/* Register move and Store instructions. */
|
|
if ((REG_P (op0) || MEM_P (op0))
|
|
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (DImode))
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
*total = cost;
|
|
return true;
|
|
|
|
case MEM:
|
|
/* Load instructions. */
|
|
if (REG_P (op0) && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (DImode))
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
*total = cost;
|
|
return true;
|
|
|
|
case CONST_INT:
|
|
/* movi instruction. */
|
|
if (REG_P (op0) && GET_MODE_SIZE (mode) < GET_MODE_SIZE (DImode))
|
|
{
|
|
if (satisfies_constraint_Is20 (op1))
|
|
*total = COSTS_N_INSNS (1) - 1;
|
|
else
|
|
*total = COSTS_N_INSNS (2);
|
|
}
|
|
else
|
|
*total = cost;
|
|
return true;
|
|
|
|
case CONST:
|
|
case SYMBOL_REF:
|
|
case LABEL_REF:
|
|
/* la instruction. */
|
|
if (REG_P (op0) && GET_MODE_SIZE (mode) < GET_MODE_SIZE (DImode))
|
|
*total = COSTS_N_INSNS (1) - 1;
|
|
else
|
|
*total = cost;
|
|
return true;
|
|
case VEC_SELECT:
|
|
*total = cost;
|
|
return true;
|
|
|
|
default:
|
|
*total = cost;
|
|
return true;
|
|
}
|
|
|
|
case PLUS:
|
|
op0 = XEXP (x, 0);
|
|
op1 = XEXP (x, 1);
|
|
|
|
if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
|
|
*total = cost;
|
|
else if (GET_CODE (op0) == MULT || GET_CODE (op0) == LSHIFTRT
|
|
|| GET_CODE (op1) == MULT || GET_CODE (op1) == LSHIFTRT)
|
|
/* ALU_SHIFT */
|
|
*total = COSTS_N_INSNS (2);
|
|
|
|
else if ((GET_CODE (op1) == CONST_INT
|
|
&& satisfies_constraint_Is15 (op1))
|
|
|| REG_P (op1))
|
|
/* ADD instructions */
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
/* ADD instructions: IMM out of range. */
|
|
*total = COSTS_N_INSNS (2);
|
|
return true;
|
|
|
|
case MINUS:
|
|
op0 = XEXP (x, 0);
|
|
op1 = XEXP (x, 1);
|
|
|
|
if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
|
|
*total = cost;
|
|
else if (GET_CODE (op0) == MULT || GET_CODE (op0) == LSHIFTRT
|
|
|| GET_CODE (op1) == MULT || GET_CODE (op1) == LSHIFTRT)
|
|
/* ALU_SHIFT */
|
|
*total = COSTS_N_INSNS (2);
|
|
else if ((GET_CODE (op0) == CONST_INT
|
|
&& satisfies_constraint_Is15 (op0))
|
|
|| REG_P (op0))
|
|
/* SUB instructions */
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
/* SUB instructions: IMM out of range. */
|
|
*total = COSTS_N_INSNS (2);
|
|
return true;
|
|
|
|
case TRUNCATE:
|
|
/* TRUNCATE and AND behavior is same. */
|
|
*total = COSTS_N_INSNS (1);
|
|
return true;
|
|
|
|
case AND:
|
|
case IOR:
|
|
case XOR:
|
|
op0 = XEXP (x, 0);
|
|
op1 = XEXP (x, 1);
|
|
|
|
if (NDS32_EXT_DSP_P ())
|
|
{
|
|
/* We prefer (and (ior) (ior)) than (ior (and) (and)) for
|
|
synthetize pk** and insb instruction. */
|
|
if (code == AND && GET_CODE (op0) == IOR && GET_CODE (op1) == IOR)
|
|
return COSTS_N_INSNS (1);
|
|
|
|
if (code == IOR && GET_CODE (op0) == AND && GET_CODE (op1) == AND)
|
|
return COSTS_N_INSNS (10);
|
|
}
|
|
|
|
if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
|
|
*total = cost;
|
|
else if (GET_CODE (op0) == ASHIFT || GET_CODE (op0) == LSHIFTRT)
|
|
*total = COSTS_N_INSNS (2);
|
|
else if ((GET_CODE (op1) == CONST_INT
|
|
&& satisfies_constraint_Iu15 (op1))
|
|
|| REG_P (op1))
|
|
/* AND, OR, XOR instructions */
|
|
*total = COSTS_N_INSNS (1);
|
|
else if (code == AND || GET_CODE (op0) == NOT)
|
|
/* BITC instruction */
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
/* AND, OR, XOR instructions: IMM out of range. */
|
|
*total = COSTS_N_INSNS (2);
|
|
return true;
|
|
|
|
case MULT:
|
|
if (GET_MODE (x) == DImode
|
|
|| GET_CODE (XEXP (x, 1)) == SIGN_EXTEND
|
|
|| GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
|
|
/* MUL instructions */
|
|
*total = COSTS_N_INSNS (1);
|
|
else if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
|
|
*total = cost;
|
|
else if (outer_code == PLUS || outer_code == MINUS)
|
|
*total = COSTS_N_INSNS (2);
|
|
else if ((GET_CODE (XEXP (x, 1)) == CONST_INT
|
|
&& satisfies_constraint_Iu05 (XEXP (x, 1)))
|
|
|| REG_P (XEXP (x, 1)))
|
|
/* MUL instructions */
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
/* MUL instructions: IMM out of range. */
|
|
*total = COSTS_N_INSNS (2);
|
|
|
|
if (TARGET_MUL_SLOW)
|
|
*total += COSTS_N_INSNS (4);
|
|
|
|
return true;
|
|
|
|
case LSHIFTRT:
|
|
if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
|
|
*total = cost;
|
|
else if (outer_code == PLUS || outer_code == MINUS
|
|
|| outer_code == AND || outer_code == IOR
|
|
|| outer_code == XOR)
|
|
*total = COSTS_N_INSNS (2);
|
|
else if ((GET_CODE (XEXP (x, 1)) == CONST_INT
|
|
&& satisfies_constraint_Iu05 (XEXP (x, 1)))
|
|
|| REG_P (XEXP (x, 1)))
|
|
/* SRL instructions */
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
/* SRL instructions: IMM out of range. */
|
|
*total = COSTS_N_INSNS (2);
|
|
return true;
|
|
|
|
case ASHIFT:
|
|
if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
|
|
*total = cost;
|
|
else if (outer_code == AND || outer_code == IOR
|
|
|| outer_code == XOR)
|
|
*total = COSTS_N_INSNS (2);
|
|
else if ((GET_CODE (XEXP (x, 1)) == CONST_INT
|
|
&& satisfies_constraint_Iu05 (XEXP (x, 1)))
|
|
|| REG_P (XEXP (x, 1)))
|
|
/* SLL instructions */
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
/* SLL instructions: IMM out of range. */
|
|
*total = COSTS_N_INSNS (2);
|
|
return true;
|
|
|
|
case ASHIFTRT:
|
|
case ROTATERT:
|
|
if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
|
|
*total = cost;
|
|
else if ((GET_CODE (XEXP (x, 1)) == CONST_INT
|
|
&& satisfies_constraint_Iu05 (XEXP (x, 1)))
|
|
|| REG_P (XEXP (x, 1)))
|
|
/* ROTR, SLL instructions */
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
/* ROTR, SLL instructions: IMM out of range. */
|
|
*total = COSTS_N_INSNS (2);
|
|
return true;
|
|
|
|
case LT:
|
|
case LTU:
|
|
if (outer_code == SET)
|
|
{
|
|
if ((GET_CODE (XEXP (x, 1)) == CONST_INT
|
|
&& satisfies_constraint_Iu15 (XEXP (x, 1)))
|
|
|| REG_P (XEXP (x, 1)))
|
|
/* SLT, SLTI instructions */
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
/* SLT, SLT instructions: IMM out of range. */
|
|
*total = COSTS_N_INSNS (2);
|
|
}
|
|
else
|
|
/* branch */
|
|
*total = COSTS_N_INSNS (2);
|
|
return true;
|
|
|
|
case EQ:
|
|
case NE:
|
|
case GE:
|
|
case LE:
|
|
case GT:
|
|
/* branch */
|
|
*total = COSTS_N_INSNS (2);
|
|
return true;
|
|
|
|
case IF_THEN_ELSE:
|
|
if (GET_CODE (XEXP (x, 1)) == LABEL_REF)
|
|
/* branch */
|
|
*total = COSTS_N_INSNS (2);
|
|
else
|
|
/* cmovz, cmovn instructions */
|
|
*total = COSTS_N_INSNS (1);
|
|
return true;
|
|
|
|
case LABEL_REF:
|
|
if (outer_code == IF_THEN_ELSE)
|
|
/* branch */
|
|
*total = COSTS_N_INSNS (2);
|
|
else
|
|
*total = COSTS_N_INSNS (1);
|
|
return true;
|
|
|
|
case ZERO_EXTEND:
|
|
case SIGN_EXTEND:
|
|
if (MEM_P (XEXP (x, 0)))
|
|
/* Using memory access. */
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
/* Zero extend and sign extend instructions. */
|
|
*total = COSTS_N_INSNS (1);
|
|
return true;
|
|
|
|
case NEG:
|
|
case NOT:
|
|
*total = COSTS_N_INSNS (1);
|
|
return true;
|
|
|
|
case DIV:
|
|
case UDIV:
|
|
case MOD:
|
|
case UMOD:
|
|
*total = COSTS_N_INSNS (20);
|
|
return true;
|
|
|
|
case CALL:
|
|
*total = COSTS_N_INSNS (2);
|
|
return true;
|
|
|
|
case CLZ:
|
|
case SMIN:
|
|
case SMAX:
|
|
case ZERO_EXTRACT:
|
|
if (TARGET_EXT_PERF)
|
|
*total = COSTS_N_INSNS (1);
|
|
else
|
|
*total = COSTS_N_INSNS (3);
|
|
return true;
|
|
case VEC_SELECT:
|
|
*total = COSTS_N_INSNS (1);
|
|
return true;
|
|
|
|
default:
|
|
*total = COSTS_N_INSNS (3);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static bool
|
|
nds32_rtx_costs_size_prefer (rtx x,
|
|
int code,
|
|
int outer_code,
|
|
int opno ATTRIBUTE_UNUSED,
|
|
int *total)
|
|
{
|
|
/* In gcc/rtl.h, the default value of COSTS_N_INSNS(N) is N*4.
|
|
We treat it as 4-byte cost for each instruction
|
|
under code size consideration. */
|
|
switch (code)
|
|
{
|
|
case SET:
|
|
/* For 'SET' rtx, we need to return false
|
|
so that it can recursively calculate costs. */
|
|
return false;
|
|
|
|
case USE:
|
|
/* Used in combine.c as a marker. */
|
|
*total = 0;
|
|
break;
|
|
|
|
case CONST_INT:
|
|
/* All instructions involving constant operation
|
|
need to be considered for cost evaluation. */
|
|
if (outer_code == SET)
|
|
{
|
|
/* (set X imm5s), use movi55, 2-byte cost.
|
|
(set X imm20s), use movi, 4-byte cost.
|
|
(set X BIG_INT), use sethi/ori, 8-byte cost. */
|
|
if (satisfies_constraint_Is05 (x))
|
|
*total = insn_size_16bit;
|
|
else if (satisfies_constraint_Is20 (x))
|
|
*total = insn_size_32bit;
|
|
else
|
|
*total = insn_size_32bit * 2;
|
|
}
|
|
else if (outer_code == PLUS || outer_code == MINUS)
|
|
{
|
|
/* Possible addi333/subi333 or subi45/addi45, 2-byte cost.
|
|
General case, cost 1 instruction with 4-byte. */
|
|
if (satisfies_constraint_Iu05 (x))
|
|
*total = insn_size_16bit;
|
|
else
|
|
*total = insn_size_32bit;
|
|
}
|
|
else if (outer_code == ASHIFT)
|
|
{
|
|
/* Possible slli333, 2-byte cost.
|
|
General case, cost 1 instruction with 4-byte. */
|
|
if (satisfies_constraint_Iu03 (x))
|
|
*total = insn_size_16bit;
|
|
else
|
|
*total = insn_size_32bit;
|
|
}
|
|
else if (outer_code == ASHIFTRT || outer_code == LSHIFTRT)
|
|
{
|
|
/* Possible srai45 or srli45, 2-byte cost.
|
|
General case, cost 1 instruction with 4-byte. */
|
|
if (satisfies_constraint_Iu05 (x))
|
|
*total = insn_size_16bit;
|
|
else
|
|
*total = insn_size_32bit;
|
|
}
|
|
else
|
|
{
|
|
/* For other cases, simply set it 4-byte cost. */
|
|
*total = insn_size_32bit;
|
|
}
|
|
break;
|
|
|
|
case CONST_DOUBLE:
|
|
/* It requires high part and low part processing, set it 8-byte cost. */
|
|
*total = insn_size_32bit * 2;
|
|
break;
|
|
|
|
case CONST:
|
|
case SYMBOL_REF:
|
|
*total = insn_size_32bit * 2;
|
|
break;
|
|
|
|
default:
|
|
/* For other cases, generally we set it 4-byte cost
|
|
and stop resurively traversing. */
|
|
*total = insn_size_32bit;
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
nds32_init_rtx_costs (void)
|
|
{
|
|
rtx_cost_model.speed_prefer = nds32_rtx_costs_speed_prefer;
|
|
rtx_cost_model.size_prefer = nds32_rtx_costs_size_prefer;
|
|
|
|
if (TARGET_16_BIT)
|
|
insn_size_16bit = 2;
|
|
else
|
|
insn_size_16bit = 4;
|
|
}
|
|
|
|
/* This target hook describes the relative costs of RTL expressions.
|
|
Return 'true' when all subexpressions of x have been processed.
|
|
Return 'false' to sum the costs of sub-rtx, plus cost of this operation.
|
|
Refer to gcc/rtlanal.c for more information. */
|
|
bool
|
|
nds32_rtx_costs_impl (rtx x,
|
|
machine_mode mode ATTRIBUTE_UNUSED,
|
|
int outer_code,
|
|
int opno,
|
|
int *total,
|
|
bool speed)
|
|
{
|
|
int code = GET_CODE (x);
|
|
|
|
/* According to 'speed', use suitable cost model section. */
|
|
if (speed)
|
|
return rtx_cost_model.speed_prefer(x, code, outer_code, opno, total);
|
|
else
|
|
return rtx_cost_model.size_prefer(x, code, outer_code, opno, total);
|
|
}
|
|
|
|
|
|
int nds32_address_cost_speed_prefer (rtx address)
|
|
{
|
|
rtx plus0, plus1;
|
|
enum rtx_code code;
|
|
|
|
code = GET_CODE (address);
|
|
|
|
switch (code)
|
|
{
|
|
case POST_MODIFY:
|
|
case POST_INC:
|
|
case POST_DEC:
|
|
/* We encourage that rtx contains
|
|
POST_MODIFY/POST_INC/POST_DEC behavior. */
|
|
return COSTS_N_INSNS (1) - 2;
|
|
|
|
case SYMBOL_REF:
|
|
/* We can have gp-relative load/store for symbol_ref.
|
|
Have it 4-byte cost. */
|
|
return COSTS_N_INSNS (2);
|
|
|
|
case CONST:
|
|
/* It is supposed to be the pattern (const (plus symbol_ref const_int)).
|
|
Have it 4-byte cost. */
|
|
return COSTS_N_INSNS (2);
|
|
|
|
case REG:
|
|
/* Simply return 4-byte costs. */
|
|
return COSTS_N_INSNS (1) - 2;
|
|
|
|
case PLUS:
|
|
/* We do not need to check if the address is a legitimate address,
|
|
because this hook is never called with an invalid address.
|
|
But we better check the range of
|
|
const_int value for cost, if it exists. */
|
|
plus0 = XEXP (address, 0);
|
|
plus1 = XEXP (address, 1);
|
|
|
|
if (REG_P (plus0) && CONST_INT_P (plus1))
|
|
return COSTS_N_INSNS (1) - 2;
|
|
else if (ARITHMETIC_P (plus0) || ARITHMETIC_P (plus1))
|
|
return COSTS_N_INSNS (1) - 1;
|
|
else if (REG_P (plus0) && REG_P (plus1))
|
|
return COSTS_N_INSNS (1);
|
|
|
|
/* For other 'plus' situation, make it cost 4-byte. */
|
|
return COSTS_N_INSNS (1);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return COSTS_N_INSNS (4);
|
|
|
|
}
|
|
|
|
int nds32_address_cost_speed_fwprop (rtx address)
|
|
{
|
|
rtx plus0, plus1;
|
|
enum rtx_code code;
|
|
|
|
code = GET_CODE (address);
|
|
|
|
switch (code)
|
|
{
|
|
case POST_MODIFY:
|
|
case POST_INC:
|
|
case POST_DEC:
|
|
/* We encourage that rtx contains
|
|
POST_MODIFY/POST_INC/POST_DEC behavior. */
|
|
return 0;
|
|
|
|
case SYMBOL_REF:
|
|
/* We can have gp-relative load/store for symbol_ref.
|
|
Have it 4-byte cost. */
|
|
return COSTS_N_INSNS (2);
|
|
|
|
case CONST:
|
|
/* It is supposed to be the pattern (const (plus symbol_ref const_int)).
|
|
Have it 4-byte cost. */
|
|
return COSTS_N_INSNS (2);
|
|
|
|
case REG:
|
|
/* Simply return 4-byte costs. */
|
|
return COSTS_N_INSNS (1);
|
|
|
|
case PLUS:
|
|
/* We do not need to check if the address is a legitimate address,
|
|
because this hook is never called with an invalid address.
|
|
But we better check the range of
|
|
const_int value for cost, if it exists. */
|
|
plus0 = XEXP (address, 0);
|
|
plus1 = XEXP (address, 1);
|
|
|
|
if (REG_P (plus0) && CONST_INT_P (plus1))
|
|
{
|
|
/* If it is possible to be lwi333/swi333 form,
|
|
make it 2-byte cost. */
|
|
if (satisfies_constraint_Iu03 (plus1))
|
|
return (COSTS_N_INSNS (1) - 2);
|
|
else
|
|
return COSTS_N_INSNS (1);
|
|
}
|
|
if (ARITHMETIC_P (plus0) || ARITHMETIC_P (plus1))
|
|
return COSTS_N_INSNS (1) - 2;
|
|
else if (REG_P (plus0) && REG_P (plus1))
|
|
return COSTS_N_INSNS (1);
|
|
|
|
/* For other 'plus' situation, make it cost 4-byte. */
|
|
return COSTS_N_INSNS (1);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return COSTS_N_INSNS (4);
|
|
}
|
|
|
|
|
|
int nds32_address_cost_size_prefer (rtx address)
|
|
{
|
|
rtx plus0, plus1;
|
|
enum rtx_code code;
|
|
|
|
code = GET_CODE (address);
|
|
|
|
switch (code)
|
|
{
|
|
case POST_MODIFY:
|
|
case POST_INC:
|
|
case POST_DEC:
|
|
/* We encourage that rtx contains
|
|
POST_MODIFY/POST_INC/POST_DEC behavior. */
|
|
return 0;
|
|
|
|
case SYMBOL_REF:
|
|
/* We can have gp-relative load/store for symbol_ref.
|
|
Have it 4-byte cost. */
|
|
return COSTS_N_INSNS (2);
|
|
|
|
case CONST:
|
|
/* It is supposed to be the pattern (const (plus symbol_ref const_int)).
|
|
Have it 4-byte cost. */
|
|
return COSTS_N_INSNS (2);
|
|
|
|
case REG:
|
|
/* Simply return 4-byte costs. */
|
|
return COSTS_N_INSNS (1) - 1;
|
|
|
|
case PLUS:
|
|
/* We do not need to check if the address is a legitimate address,
|
|
because this hook is never called with an invalid address.
|
|
But we better check the range of
|
|
const_int value for cost, if it exists. */
|
|
plus0 = XEXP (address, 0);
|
|
plus1 = XEXP (address, 1);
|
|
|
|
if (REG_P (plus0) && CONST_INT_P (plus1))
|
|
{
|
|
/* If it is possible to be lwi333/swi333 form,
|
|
make it 2-byte cost. */
|
|
if (satisfies_constraint_Iu03 (plus1))
|
|
return (COSTS_N_INSNS (1) - 2);
|
|
else
|
|
return COSTS_N_INSNS (1) - 1;
|
|
}
|
|
|
|
/* (plus (reg) (mult (reg) (const))) */
|
|
if (ARITHMETIC_P (plus0) || ARITHMETIC_P (plus1))
|
|
return (COSTS_N_INSNS (1) - 1);
|
|
|
|
/* For other 'plus' situation, make it cost 4-byte. */
|
|
return COSTS_N_INSNS (1);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return COSTS_N_INSNS (4);
|
|
|
|
}
|
|
|
|
int nds32_address_cost_impl (rtx address,
|
|
machine_mode mode ATTRIBUTE_UNUSED,
|
|
addr_space_t as ATTRIBUTE_UNUSED,
|
|
bool speed_p)
|
|
{
|
|
if (speed_p)
|
|
{
|
|
if (current_pass->tv_id == TV_FWPROP)
|
|
return nds32_address_cost_speed_fwprop (address);
|
|
else
|
|
return nds32_address_cost_speed_prefer (address);
|
|
}
|
|
else
|
|
return nds32_address_cost_size_prefer (address);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|