/* Auxiliary functions for pipeline descriptions pattern of Andes
NDS32 cpu for GNU compiler
- Copyright (C) 2012-2018 Free Software Foundation, Inc.
+ Copyright (C) 2012-2020 Free Software Foundation, Inc.
Contributed by Andes Technology Corporation.
This file is part of GCC.
return true;
}
+bool
+store_offset_reg_p (rtx_insn *insn)
+{
+ if (get_attr_type (insn) != TYPE_STORE)
+ return false;
+
+ rtx offset_rtx = extract_offset_rtx (insn);
+
+ if (offset_rtx == NULL_RTX)
+ return false;
+
+ if (REG_P (offset_rtx))
+ return true;
+
+ return false;
+}
+
/* Determine if INSN is a post update insn. */
bool
post_update_insn_p (rtx_insn *insn)
if (REG_P (XEXP (mem_rtx, 0)))
return XEXP (mem_rtx, 0);
+ /* (mem (lo_sum (reg) (symbol_ref)) */
+ if (GET_CODE (XEXP (mem_rtx, 0)) == LO_SUM)
+ return XEXP (XEXP (mem_rtx, 0), 0);
+
plus_rtx = XEXP (mem_rtx, 0);
if (GET_CODE (plus_rtx) == SYMBOL_REF
|| GET_CODE (plus_rtx) == CONST)
return NULL_RTX;
- gcc_assert (GET_CODE (plus_rtx) == PLUS
- || GET_CODE (plus_rtx) == POST_INC
- || GET_CODE (plus_rtx) == POST_DEC
- || GET_CODE (plus_rtx) == POST_MODIFY);
- gcc_assert (REG_P (XEXP (plus_rtx, 0)));
/* (mem (plus (reg) (const_int))) or
+ (mem (plus (mult (reg) (const_int 4)) (reg))) or
(mem (post_inc (reg))) or
(mem (post_dec (reg))) or
(mem (post_modify (reg) (plus (reg) (reg)))) */
- return XEXP (plus_rtx, 0);
+ gcc_assert (GET_CODE (plus_rtx) == PLUS
+ || GET_CODE (plus_rtx) == POST_INC
+ || GET_CODE (plus_rtx) == POST_DEC
+ || GET_CODE (plus_rtx) == POST_MODIFY);
+
+ if (REG_P (XEXP (plus_rtx, 0)))
+ return XEXP (plus_rtx, 0);
+
+ gcc_assert (REG_P (XEXP (plus_rtx, 1)));
+ return XEXP (plus_rtx, 1);
+}
+
+/* Extract the offset rtx from load/store insns. The function returns
+ NULL_RTX if offset is absent. */
+rtx
+extract_offset_rtx (rtx_insn *insn)
+{
+ rtx mem_rtx;
+ rtx plus_rtx;
+ rtx offset_rtx;
+
+ /* Find the MEM rtx. The multiple load/store insns doens't have
+ the offset field so we can return NULL_RTX here. */
+ switch (get_attr_type (insn))
+ {
+ case TYPE_LOAD_MULTIPLE:
+ case TYPE_STORE_MULTIPLE:
+ return NULL_RTX;
+
+ case TYPE_LOAD:
+ case TYPE_FLOAD:
+ case TYPE_STORE:
+ case TYPE_FSTORE:
+ mem_rtx = extract_mem_rtx (insn);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ gcc_assert (MEM_P (mem_rtx));
+
+ /* (mem (reg)) */
+ if (REG_P (XEXP (mem_rtx, 0)))
+ return NULL_RTX;
+
+ plus_rtx = XEXP (mem_rtx, 0);
+
+ switch (GET_CODE (plus_rtx))
+ {
+ case SYMBOL_REF:
+ case CONST:
+ case POST_INC:
+ case POST_DEC:
+ return NULL_RTX;
+
+ case PLUS:
+ /* (mem (plus (reg) (const_int))) or
+ (mem (plus (mult (reg) (const_int 4)) (reg))) */
+ if (REG_P (XEXP (plus_rtx, 0)))
+ offset_rtx = XEXP (plus_rtx, 1);
+ else
+ {
+ gcc_assert (REG_P (XEXP (plus_rtx, 1)));
+ offset_rtx = XEXP (plus_rtx, 0);
+ }
+
+ if (ARITHMETIC_P (offset_rtx))
+ {
+ gcc_assert (GET_CODE (offset_rtx) == MULT);
+ gcc_assert (REG_P (XEXP (offset_rtx, 0)));
+ offset_rtx = XEXP (offset_rtx, 0);
+ }
+ break;
+
+ case LO_SUM:
+ /* (mem (lo_sum (reg) (symbol_ref)) */
+ offset_rtx = XEXP (plus_rtx, 1);
+ break;
+
+ case POST_MODIFY:
+ /* (mem (post_modify (reg) (plus (reg) (reg / const_int)))) */
+ gcc_assert (REG_P (XEXP (plus_rtx, 0)));
+ plus_rtx = XEXP (plus_rtx, 1);
+ gcc_assert (GET_CODE (plus_rtx) == PLUS);
+ offset_rtx = XEXP (plus_rtx, 0);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return offset_rtx;
}
/* Extract the register of the shift operand from an ALU_SHIFT rtx. */
return false;
}
+/* Extract the second result (odd reg) of a movd44 insn. */
+rtx
+extract_movd44_odd_reg (rtx_insn *insn)
+{
+ gcc_assert (movd44_insn_p (insn));
+
+ rtx def_reg = SET_DEST (PATTERN (insn));
+ machine_mode mode;
+
+ gcc_assert (REG_P (def_reg) || GET_CODE (def_reg) == SUBREG);
+ switch (GET_MODE (def_reg))
+ {
+ case E_DImode:
+ mode = SImode;
+ break;
+
+ case E_DFmode:
+ mode = SFmode;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return gen_highpart (mode, def_reg);
+}
+
/* Extract the rtx representing non-accumulation operands of a MAC insn. */
rtx
extract_mac_non_acc_rtx (rtx_insn *insn)
switch (get_attr_type (insn))
{
case TYPE_MAC:
+ case TYPE_DMAC:
if (REG_P (XEXP (exp, 0)))
return XEXP (exp, 1);
else
}
}
+/* Check if the DIV insn needs two write ports. */
+bool
+divmod_p (rtx_insn *insn)
+{
+ gcc_assert (get_attr_type (insn) == TYPE_DIV);
+
+ if (INSN_CODE (insn) == CODE_FOR_divmodsi4
+ || INSN_CODE (insn) == CODE_FOR_udivmodsi4)
+ return true;
+
+ return false;
+}
+
+/* Extract the rtx representing the branch target to help recognize
+ data hazards. */
+rtx
+extract_branch_target_rtx (rtx_insn *insn)
+{
+ gcc_assert (CALL_P (insn) || JUMP_P (insn));
+
+ rtx body = PATTERN (insn);
+
+ if (GET_CODE (body) == SET)
+ {
+ /* RTXs in IF_THEN_ELSE are branch conditions. */
+ if (GET_CODE (SET_SRC (body)) == IF_THEN_ELSE)
+ return NULL_RTX;
+
+ return SET_SRC (body);
+ }
+
+ if (GET_CODE (body) == CALL)
+ return XEXP (body, 0);
+
+ if (GET_CODE (body) == PARALLEL)
+ {
+ rtx first_rtx = parallel_element (body, 0);
+
+ if (GET_CODE (first_rtx) == SET)
+ return SET_SRC (first_rtx);
+
+ if (GET_CODE (first_rtx) == CALL)
+ return XEXP (first_rtx, 0);
+ }
+
+ /* Handle special cases of bltzal, bgezal and jralnez. */
+ if (GET_CODE (body) == COND_EXEC)
+ {
+ rtx addr_rtx = XEXP (body, 1);
+
+ if (GET_CODE (addr_rtx) == SET)
+ return SET_SRC (addr_rtx);
+
+ if (GET_CODE (addr_rtx) == PARALLEL)
+ {
+ rtx first_rtx = parallel_element (addr_rtx, 0);
+
+ if (GET_CODE (first_rtx) == SET)
+ {
+ rtx call_rtx = SET_SRC (first_rtx);
+ gcc_assert (GET_CODE (call_rtx) == CALL);
+
+ return XEXP (call_rtx, 0);
+ }
+
+ if (GET_CODE (first_rtx) == CALL)
+ return XEXP (first_rtx, 0);
+ }
+ }
+
+ gcc_unreachable ();
+}
+
+/* Extract the rtx representing the branch condition to help recognize
+ data hazards. */
+rtx
+extract_branch_condition_rtx (rtx_insn *insn)
+{
+ gcc_assert (CALL_P (insn) || JUMP_P (insn));
+
+ rtx body = PATTERN (insn);
+
+ if (GET_CODE (body) == SET)
+ {
+ rtx if_then_else_rtx = SET_SRC (body);
+
+ if (GET_CODE (if_then_else_rtx) == IF_THEN_ELSE)
+ return XEXP (if_then_else_rtx, 0);
+
+ return NULL_RTX;
+ }
+
+ if (GET_CODE (body) == COND_EXEC)
+ return XEXP (body, 0);
+
+ return NULL_RTX;
+}
+
} // namespace nds32