]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/nds32/nds32-utils.c
Update copyright years.
[thirdparty/gcc.git] / gcc / config / nds32 / nds32-utils.c
index 55d4a9193c2d06fb20c386e5ffab32a1b5f98de7..6973da43b2e9f35e82e29255010529cf4579f658 100644 (file)
@@ -1,6 +1,6 @@
 /* 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.
@@ -142,6 +142,23 @@ store_double_p (rtx_insn *insn)
   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)
@@ -316,22 +333,114 @@ extract_base_reg (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.  */
@@ -377,6 +486,33 @@ movd44_insn_p (rtx_insn *insn)
   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)
@@ -386,6 +522,7 @@ 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
@@ -396,4 +533,102 @@ extract_mac_non_acc_rtx (rtx_insn *insn)
     }
 }
 
+/* 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