#include "dumpfile.h"
#include "hw-doloop.h"
#include "rtl-iter.h"
+#include "insn-attr.h"
/* This file should be included last. */
#include "target-def.h"
static section *xtensa_select_rtx_section (machine_mode, rtx,
unsigned HOST_WIDE_INT);
static bool xtensa_rtx_costs (rtx, machine_mode, int, int, int *, bool);
+static int xtensa_insn_cost (rtx_insn *, bool);
static int xtensa_register_move_cost (machine_mode, reg_class_t,
reg_class_t);
static int xtensa_memory_move_cost (machine_mode, reg_class_t, bool);
#define TARGET_MEMORY_MOVE_COST xtensa_memory_move_cost
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS xtensa_rtx_costs
+#undef TARGET_INSN_COST
+#define TARGET_INSN_COST xtensa_insn_cost
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
static bool
xtensa_rtx_costs (rtx x, machine_mode mode, int outer_code,
int opno ATTRIBUTE_UNUSED,
- int *total, bool speed ATTRIBUTE_UNUSED)
+ int *total, bool speed)
{
int code = GET_CODE (x);
return true;
case CLZ:
+ case CLRSB:
*total = COSTS_N_INSNS (TARGET_NSA ? 1 : 50);
return true;
+ case BSWAP:
+ *total = COSTS_N_INSNS (mode == HImode ? 3 : 5);
+ return true;
+
case NOT:
*total = COSTS_N_INSNS (mode == DImode ? 3 : 2);
return true;
return true;
case ABS:
+ case NEG:
{
if (mode == SFmode)
*total = COSTS_N_INSNS (TARGET_HARD_FLOAT ? 1 : 50);
else if (mode == DFmode)
*total = COSTS_N_INSNS (50);
- else
+ else if (mode == DImode)
*total = COSTS_N_INSNS (4);
+ else
+ *total = COSTS_N_INSNS (1);
return true;
}
return true;
}
- case NEG:
- *total = COSTS_N_INSNS (mode == DImode ? 4 : 2);
- return true;
-
case MULT:
{
if (mode == SFmode)
case UMOD:
{
if (mode == DImode)
- *total = COSTS_N_INSNS (50);
+ *total = COSTS_N_INSNS (speed ? 100 : 50);
else if (TARGET_DIV32)
*total = COSTS_N_INSNS (32);
else
- *total = COSTS_N_INSNS (50);
+ *total = COSTS_N_INSNS (speed ? 100 : 50);
return true;
}
}
}
+static bool
+xtensa_is_insn_L32R_p(const rtx_insn *insn)
+{
+ rtx x = PATTERN (insn);
+
+ if (GET_CODE (x) == SET)
+ {
+ x = XEXP (x, 1);
+ if (GET_CODE (x) == MEM)
+ {
+ x = XEXP (x, 0);
+ return (GET_CODE (x) == SYMBOL_REF || CONST_INT_P (x))
+ && CONSTANT_POOL_ADDRESS_P (x);
+ }
+ }
+
+ return false;
+}
+
+/* Compute a relative costs of RTL insns. This is necessary in order to
+ achieve better RTL insn splitting/combination result. */
+
+static int
+xtensa_insn_cost (rtx_insn *insn, bool speed)
+{
+ if (!(recog_memoized (insn) < 0))
+ {
+ int len = get_attr_length (insn), n = (len + 2) / 3;
+
+ if (len == 0)
+ return COSTS_N_INSNS (0);
+
+ if (speed) /* For speed cost. */
+ {
+ /* "L32R" may be particular slow (implementation-dependent). */
+ if (xtensa_is_insn_L32R_p (insn))
+ return COSTS_N_INSNS (1 + xtensa_extra_l32r_costs);
+
+ /* Cost based on the pipeline model. */
+ switch (get_attr_type (insn))
+ {
+ case TYPE_STORE:
+ case TYPE_MOVE:
+ case TYPE_ARITH:
+ case TYPE_MULTI:
+ case TYPE_NOP:
+ case TYPE_FSTORE:
+ return COSTS_N_INSNS (n);
+
+ case TYPE_LOAD:
+ return COSTS_N_INSNS (n - 1 + 2);
+
+ case TYPE_JUMP:
+ case TYPE_CALL:
+ return COSTS_N_INSNS (n - 1 + 3);
+
+ case TYPE_FCONV:
+ case TYPE_FLOAD:
+ case TYPE_MUL16:
+ case TYPE_MUL32:
+ case TYPE_RSR:
+ return COSTS_N_INSNS (n * 2);
+
+ case TYPE_FMADD:
+ return COSTS_N_INSNS (n * 4);
+
+ case TYPE_DIV32:
+ return COSTS_N_INSNS (n * 16);
+
+ default:
+ break;
+ }
+ }
+ else /* For size cost. */
+ {
+ /* Cost based on the instruction length. */
+ if (get_attr_type (insn) != TYPE_UNKNOWN)
+ {
+ /* "L32R" itself plus constant in litpool. */
+ if (xtensa_is_insn_L32R_p (insn))
+ return COSTS_N_INSNS (2) + 1;
+
+ /* Consider ".n" short instructions. */
+ return COSTS_N_INSNS (n) - (n * 3 - len);
+ }
+ }
+ }
+
+ /* Fall back. */
+ return pattern_cost (PATTERN (insn), speed);
+}
+
/* Worker function for TARGET_RETURN_IN_MEMORY. */
static bool
;; Describe a user's asm statement.
(define_asm_attributes
- [(set_attr "type" "multi")])
+ [(set_attr "type" "multi")
+ (set_attr "mode" "none")
+ (set_attr "length" "3")]) ;; Should be the maximum possible length
+ ;; of a single machine instruction.
\f
;; Pipeline model.
}
[(set_attr "type" "jump")
(set_attr "mode" "none")
- (set_attr "length" "2")])
+ (set (attr "length")
+ (if_then_else (match_test "TARGET_DENSITY")
+ (const_int 2)
+ (const_int 3)))])
\f
;; Miscellaneous instructions.
}
[(set_attr "type" "nop")
(set_attr "mode" "none")
- (set_attr "length" "3")])
+ (set (attr "length")
+ (if_then_else (match_test "TARGET_DENSITY")
+ (const_int 2)
+ (const_int 3)))])
(define_expand "nonlocal_goto"
[(match_operand:SI 0 "general_operand" "")
[(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
""
""
- [(set_attr "length" "0")
- (set_attr "type" "nop")])
+ [(set_attr "type" "nop")
+ (set_attr "mode" "none")
+ (set_attr "length" "0")])
;; Do not schedule instructions accessing memory before this point.
(unspec:BLK [(match_operand:SI 1 "" "")] UNSPEC_FRAME_BLOCKAGE))]
""
""
- [(set_attr "length" "0")])
+ [(set_attr "type" "nop")
+ (set_attr "mode" "none")
+ (set_attr "length" "0")])
(define_insn "trap"
[(trap_if (const_int 1) (const_int 0))]
}
[(set_attr "type" "trap")
(set_attr "mode" "none")
- (set_attr "length" "3")])
+ (set (attr "length")
+ (if_then_else (match_test "!TARGET_DEBUG && TARGET_DENSITY")
+ (const_int 2)
+ (const_int 3)))])
;; Setting up a frame pointer is tricky for Xtensa because GCC doesn't
;; know if a frame pointer is required until the reload pass, and