Ticket #3242: gcc-sparc-ticket-3242-v2.patch

File gcc-sparc-ticket-3242-v2.patch, 13.5 KB (added by Sebastian Huber, on Dec 19, 2017 at 8:36:20 AM)
  • gcc/config/sparc/sparc.c

    diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
    index 83ca1dcc617..b9c8dcc57c1 100644
    a b mem_ref (rtx x) 
    914914  return NULL_RTX;
    915915}
    916916
     917/* True if any of INSN's source register(s) is REG.  */
     918
     919static bool
     920insn_uses_reg_p (rtx_insn *insn, unsigned int reg)
     921{
     922  extract_insn (insn);
     923  return ((REG_P (recog_data.operand[1])
     924           && REGNO (recog_data.operand[1]) == reg)
     925          || (recog_data.n_operands == 3
     926              && REG_P (recog_data.operand[2])
     927              && REGNO (recog_data.operand[2]) == reg));
     928}
     929
     930/* True if INSN is a floating-point division or square-root.  */
     931
     932static bool
     933div_sqrt_insn_p (rtx_insn *insn)
     934{
     935  if (GET_CODE (PATTERN (insn)) != SET)
     936    return false;
     937
     938  switch (get_attr_type (insn))
     939    {
     940    case TYPE_FPDIVS:
     941    case TYPE_FPSQRTS:
     942    case TYPE_FPDIVD:
     943    case TYPE_FPSQRTD:
     944      return true;
     945    default:
     946      return false;
     947    }
     948}
     949
     950/* True if INSN is a floating-point instruction.  */
     951
     952static bool
     953fpop_insn_p (rtx_insn *insn)
     954{
     955  if (GET_CODE (PATTERN (insn)) != SET)
     956    return false;
     957
     958  switch (get_attr_type (insn))
     959    {
     960    case TYPE_FPMOVE:
     961    case TYPE_FPCMOVE:
     962    case TYPE_FP:
     963    case TYPE_FPCMP:
     964    case TYPE_FPMUL:
     965    case TYPE_FPDIVS:
     966    case TYPE_FPSQRTS:
     967    case TYPE_FPDIVD:
     968    case TYPE_FPSQRTD:
     969      return true;
     970    default:
     971      return false;
     972    }
     973}
     974
     975/* True if INSN is an atomic instruction.  */
     976
     977static bool
     978atomic_insn_for_leon3_p (rtx_insn *insn)
     979{
     980  switch (INSN_CODE (insn))
     981    {
     982    case CODE_FOR_swapsi:
     983    case CODE_FOR_ldstub:
     984    case CODE_FOR_atomic_compare_and_swap_leon3_1:
     985      return true;
     986    default:
     987      return false;
     988    }
     989}
     990
    917991/* We use a machine specific pass to enable workarounds for errata.
    918992
    919993   We need to have the (essentially) final form of the insn stream in order
    sparc_do_work_around_errata (void) 
    9391013    {
    9401014      bool insert_nop = false;
    9411015      rtx set;
     1016      rtx_insn *jump;
     1017      rtx_sequence *seq;
    9421018
    9431019      /* Look into the instruction in a delay slot.  */
    944       if (NONJUMP_INSN_P (insn))
    945         if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (PATTERN (insn)))
     1020      if (NONJUMP_INSN_P (insn)
     1021          && (seq = dyn_cast <rtx_sequence *> (PATTERN (insn))))
     1022        {
     1023          jump = seq->insn (0);
    9461024          insn = seq->insn (1);
     1025        }
     1026      else if (JUMP_P (insn))
     1027        jump = insn;
     1028      else
     1029        jump = NULL;
     1030
     1031      /* Place a NOP at the branch target of an integer branch if it is a
     1032         floating-point operation or a floating-point branch.  */
     1033      if (sparc_fix_gr712rc
     1034          && jump
     1035          && jump_to_label_p (jump)
     1036          && get_attr_branch_type (jump) == BRANCH_TYPE_ICC)
     1037        {
     1038          rtx_insn *target = next_active_insn (JUMP_LABEL_AS_INSN (jump));
     1039          if (target
     1040              && (fpop_insn_p (target)
     1041                  || (JUMP_P (target)
     1042                      && get_attr_branch_type (target) == BRANCH_TYPE_FCC)))
     1043            emit_insn_before (gen_nop (), target);
     1044        }
     1045
     1046      /* Insert a NOP between load instruction and atomic instruction.  Insert
     1047         a NOP at branch target if there is a load in delay slot and an atomic
     1048         instruction at branch target.  */
     1049      if (sparc_fix_ut700
     1050          && NONJUMP_INSN_P (insn)
     1051          && (set = single_set (insn)) != NULL_RTX
     1052          && mem_ref (SET_SRC (set))
     1053          && REG_P (SET_DEST (set)))
     1054        {
     1055          if (jump && jump_to_label_p (jump))
     1056            {
     1057              rtx_insn *target = next_active_insn (JUMP_LABEL_AS_INSN (jump));
     1058              if (target && atomic_insn_for_leon3_p (target))
     1059                emit_insn_before (gen_nop (), target);
     1060            }
     1061
     1062          next = next_active_insn (insn);
     1063          if (!next)
     1064            break;
     1065
     1066          if (atomic_insn_for_leon3_p (next))
     1067            insert_nop = true;
     1068        }
     1069
     1070      /* Look for a sequence that starts with a fdiv or fsqrt instruction and
     1071         ends with another fdiv or fsqrt instruction with no dependencies on
     1072         the former, along with an appropriate pattern in between.  */
     1073      if (sparc_fix_lost_divsqrt
     1074          && NONJUMP_INSN_P (insn)
     1075          && div_sqrt_insn_p (insn))
     1076        {
     1077          int i;
     1078          int fp_found = 0;
     1079          rtx_insn *after;
     1080
     1081          const unsigned int dest_reg = REGNO (SET_DEST (single_set (insn)));
     1082
     1083          next = next_active_insn (insn);
     1084          if (!next)
     1085            break;
     1086
     1087          for (after = next, i = 0; i < 4; i++)
     1088            {
     1089              /* Count floating-point operations.  */
     1090              if (i != 3 && fpop_insn_p (after))
     1091                {
     1092                  /* If the insn uses the destination register of
     1093                     the div/sqrt, then it cannot be problematic.  */
     1094                  if (insn_uses_reg_p (after, dest_reg))
     1095                    break;
     1096                  fp_found++;
     1097                }
     1098
     1099              /* Count floating-point loads.  */
     1100              if (i != 3
     1101                  && (set = single_set (after)) != NULL_RTX
     1102                  && REG_P (SET_DEST (set))
     1103                  && REGNO (SET_DEST (set)) > 31)
     1104                {
     1105                  /* If the insn uses the destination register of
     1106                     the div/sqrt, then it cannot be problematic.  */
     1107                  if (REGNO (SET_DEST (set)) == dest_reg)
     1108                    break;
     1109                  fp_found++;
     1110                }
     1111
     1112              /* Check if this is a problematic sequence.  */
     1113              if (i > 1
     1114                  && fp_found >= 2
     1115                  && div_sqrt_insn_p (after))
     1116                {
     1117                  /* If this is the short version of the problematic
     1118                     sequence we add two NOPs in a row to also prevent
     1119                     the long version.  */
     1120                  if (i == 2)
     1121                    emit_insn_before (gen_nop (), next);
     1122                  insert_nop = true;
     1123                  break;
     1124                }
     1125
     1126              /* No need to scan past a second div/sqrt.  */
     1127              if (div_sqrt_insn_p (after))
     1128                break;
     1129
     1130              /* Insert NOP before branch.  */
     1131              if (i < 3
     1132                  && (!NONJUMP_INSN_P (after)
     1133                      || GET_CODE (PATTERN (after)) == SEQUENCE))
     1134                {
     1135                  insert_nop = true;
     1136                  break;
     1137                }
     1138
     1139              after = next_active_insn (after);
     1140              if (!after)
     1141                break;
     1142            }
     1143        }
    9471144
    9481145      /* Look for either of these two sequences:
    9491146
    sparc_do_work_around_errata (void) 
    10031200                 then the sequence cannot be problematic.  */
    10041201              if (i == 0)
    10051202                {
    1006                   if (((set = single_set (after)) != NULL_RTX)
    1007                       && (MEM_P (SET_DEST (set)) || MEM_P (SET_SRC (set))))
     1203                  if ((set = single_set (after)) != NULL_RTX
     1204                      && (MEM_P (SET_DEST (set)) || mem_ref (SET_SRC (set))))
    10081205                    break;
    10091206
    10101207                  after = next_active_insn (after);
    sparc_do_work_around_errata (void) 
    10141211
    10151212              /* Add NOP if third instruction is a store.  */
    10161213              if (i == 1
    1017                   && ((set = single_set (after)) != NULL_RTX)
     1214                  && (set = single_set (after)) != NULL_RTX
    10181215                  && MEM_P (SET_DEST (set)))
    10191216                insert_nop = true;
    10201217            }
    10211218        }
    1022       else
     1219
    10231220      /* Look for a single-word load into an odd-numbered FP register.  */
    1024       if (sparc_fix_at697f
    1025           && NONJUMP_INSN_P (insn)
    1026           && (set = single_set (insn)) != NULL_RTX
    1027           && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4
    1028           && MEM_P (SET_SRC (set))
    1029           && REG_P (SET_DEST (set))
    1030           && REGNO (SET_DEST (set)) > 31
    1031           && REGNO (SET_DEST (set)) % 2 != 0)
     1221      else if (sparc_fix_at697f
     1222               && NONJUMP_INSN_P (insn)
     1223               && (set = single_set (insn)) != NULL_RTX
     1224               && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4
     1225               && mem_ref (SET_SRC (set))
     1226               && REG_P (SET_DEST (set))
     1227               && REGNO (SET_DEST (set)) > 31
     1228               && REGNO (SET_DEST (set)) % 2 != 0)
    10321229        {
    10331230          /* The wrong dependency is on the enclosing double register.  */
    10341231          const unsigned int x = REGNO (SET_DEST (set)) - 1;
    sparc_do_work_around_errata (void) 
    10951292               && NONJUMP_INSN_P (insn)
    10961293               && (set = single_set (insn)) != NULL_RTX
    10971294               && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) <= 4
    1098                && mem_ref (SET_SRC (set)) != NULL_RTX
     1295               && (mem_ref (SET_SRC (set)) != NULL_RTX
     1296                   || INSN_CODE (insn) == CODE_FOR_movsi_pic_gotdata_op)
    10991297               && REG_P (SET_DEST (set))
    11001298               && REGNO (SET_DEST (set)) < 32)
    11011299        {
    sparc_do_work_around_errata (void) 
    11331331                               && REGNO (src) != REGNO (x)))
    11341332                       && !reg_mentioned_p (x, XEXP (dest, 0)))
    11351333                insert_nop = true;
     1334
     1335              /* GOT accesses uses LD.  */
     1336              else if (INSN_CODE (next) == CODE_FOR_movsi_pic_gotdata_op
     1337                       && !reg_mentioned_p (x, XEXP (XEXP (src, 0), 1)))
     1338                insert_nop = true;
    11361339            }
    11371340        }
    11381341
    public: 
    12721475  /* opt_pass methods: */
    12731476  virtual bool gate (function *)
    12741477    {
    1275       return sparc_fix_at697f || sparc_fix_ut699 || sparc_fix_b2bst;
     1478      return sparc_fix_at697f || sparc_fix_ut699 || sparc_fix_b2bst
     1479          || sparc_fix_gr712rc || sparc_fix_ut700 || sparc_fix_lost_divsqrt;
    12761480    }
    12771481
    12781482  virtual unsigned int execute (function *)
    sparc_option_override (void) 
    16421846  if (!(target_flags_explicit & MASK_LRA))
    16431847    target_flags |= MASK_LRA;
    16441848
    1645   /* Enable the back-to-back store errata workaround for LEON3FT.  */
     1849  /* Enable applicable errata workarounds for LEON3FT.  */
    16461850  if (sparc_fix_ut699 || sparc_fix_ut700 || sparc_fix_gr712rc)
     1851    {
    16471852    sparc_fix_b2bst = 1;
     1853    sparc_fix_lost_divsqrt = 1;
     1854    }
    16481855
    16491856  /* Disable FsMULd for the UT699 since it doesn't work correctly.  */
    16501857  if (sparc_fix_ut699)
  • gcc/config/sparc/sparc.md

    diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
    index 321c0d8b9fe..4ddbe56fbf4 100644
    a b  
    430430   (symbol_ref "(sparc_fix_b2bst != 0
    431431                 ? FIX_B2BST_TRUE : FIX_B2BST_FALSE)"))
    432432
     433(define_attr "fix_lost_divsqrt" "false,true"
     434   (symbol_ref "(sparc_fix_lost_divsqrt != 0
     435                 ? FIX_LOST_DIVSQRT_TRUE : FIX_LOST_DIVSQRT_FALSE)"))
     436
     437(define_attr "fix_gr712rc" "false,true"
     438   (symbol_ref "(sparc_fix_gr712rc != 0
     439                 ? FIX_GR712RC_TRUE : FIX_GR712RC_FALSE)"))
     440
    433441;; Length (in # of insns).
    434442;; Beware that setting a length greater or equal to 3 for conditional branches
    435443;; has a side-effect (see output_cbranch and output_v9branch).
     
    577585(define_attr "in_branch_delay" "false,true"
    578586  (cond [(eq_attr "type" "uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi")
    579587           (const_string "false")
     588         (and (eq_attr "fix_lost_divsqrt" "true")
     589              (eq_attr "type" "fpdivs,fpsqrts,fpdivd,fpsqrtd"))
     590           (const_string "false")
    580591         (and (eq_attr "fix_b2bst" "true") (eq_attr "type" "store,fpstore"))
    581592           (const_string "false")
    582593         (and (eq_attr "fix_ut699" "true") (eq_attr "type" "load,sload"))
     
    590601           (const_string "true")
    591602        ] (const_string "false")))
    592603
     604(define_attr "in_integer_branch_annul_delay" "false,true"
     605  (cond [(and (eq_attr "fix_gr712rc" "true")
     606              (eq_attr "type" "fp,fpcmp,fpmove,fpcmove,fpmul,
     607                               fpdivs,fpsqrts,fpdivd,fpsqrtd"))
     608           (const_string "false")
     609         (eq_attr "in_branch_delay" "true")
     610           (const_string "true")
     611        ] (const_string "false")))
     612
    593613(define_delay (eq_attr "type" "call")
    594614  [(eq_attr "in_call_delay" "true") (nil) (nil)])
    595615
     
    599619(define_delay (eq_attr "type" "return")
    600620  [(eq_attr "in_return_delay" "true") (nil) (nil)])
    601621
    602 (define_delay (eq_attr "type" "branch")
     622(define_delay (and (eq_attr "type" "branch")
     623              (not (eq_attr "branch_type" "icc")))
    603624  [(eq_attr "in_branch_delay" "true") (nil) (eq_attr "in_branch_delay" "true")])
    604625
     626(define_delay (and (eq_attr "type" "branch")
     627              (eq_attr "branch_type" "icc"))
     628  [(eq_attr "in_branch_delay" "true") (nil)
     629  (eq_attr "in_integer_branch_annul_delay" "true")])
     630
    605631(define_delay (eq_attr "type" "uncond_branch")
    606632  [(eq_attr "in_branch_delay" "true") (nil) (nil)])
    607633
  • gcc/config/sparc/sparc.opt

    diff --git a/gcc/config/sparc/sparc.opt b/gcc/config/sparc/sparc.opt
    index 22267f50e90..71ead75831d 100644
    a b Enable workarounds for the errata of the GR712RC processor. 
    253253TargetVariable
    254254unsigned int sparc_fix_b2bst
    255255
     256;; Enable workaround for GRLIB-TN-0013 errata
     257TargetVariable
     258unsigned int sparc_fix_lost_divsqrt
     259
    256260Mask(LONG_DOUBLE_128)
    257261;; Use 128-bit long double
    258262
  • gcc/config/sparc/sync.md

    diff --git a/gcc/config/sparc/sync.md b/gcc/config/sparc/sync.md
    index 1593bdeb903..43c66e96ba3 100644
    a b  
    212212  "cas<modesuffix>\t%1, %2, %0"
    213213  [(set_attr "type" "multi")])
    214214
    215 (define_insn "*atomic_compare_and_swap_leon3_1"
     215(define_insn "atomic_compare_and_swap_leon3_1"
    216216  [(set (match_operand:SI 0 "register_operand" "=r")
    217217        (match_operand:SI 1 "mem_noofs_operand" "+w"))
    218218   (set (match_dup 1)
     
    222222          UNSPECV_CAS))]
    223223  "TARGET_LEON3"
    224224{
     225  if (sparc_fix_gr712rc)
     226    output_asm_insn (".align\t16", operands);
    225227  if (TARGET_SV_MODE)
    226228    return "casa\t%1 0xb, %2, %0"; /* ASI for supervisor data space.  */
    227229  else
    228230    return "casa\t%1 0xa, %2, %0"; /* ASI for user data space.  */
    229231}
    230   [(set_attr "type" "multi")])
     232  [(set_attr "type" "multi")
     233   (set (attr "length") (if_then_else (eq_attr "fix_gr712rc" "true")
     234                      (const_int 4) (const_int 1)))])
    231235
    232236(define_insn "*atomic_compare_and_swapdi_v8plus"
    233237  [(set (match_operand:DI 0 "register_operand" "=h")
     
    275279   (set (match_dup 1)
    276280        (match_operand:SI 2 "register_operand" "0"))]
    277281  "(TARGET_V8 || TARGET_V9) && !sparc_fix_ut699"
    278   "swap\t%1, %0"
    279   [(set_attr "type" "multi")])
     282{
     283  if (sparc_fix_gr712rc)
     284    return ".align\t16\n\tswap\t%1, %0";
     285  else
     286    return "swap\t%1, %0";
     287}
     288  [(set_attr "type" "multi")
     289   (set (attr "length") (if_then_else (eq_attr "fix_gr712rc" "true")
     290                      (const_int 4) (const_int 1)))])
    280291
    281292(define_expand "atomic_test_and_set"
    282293  [(match_operand:QI 0 "register_operand" "")
     
    307318                            UNSPECV_LDSTUB))
    308319   (set (match_dup 1) (const_int -1))]
    309320  "!sparc_fix_ut699"
    310   "ldstub\t%1, %0"
    311   [(set_attr "type" "multi")])
     321{
     322  if (sparc_fix_gr712rc)
     323    return ".align\t16\n\tldstub\t%1, %0";
     324  else
     325    return "ldstub\t%1, %0";
     326}
     327  [(set_attr "type" "multi")
     328   (set (attr "length") (if_then_else (eq_attr "fix_gr712rc" "true")
     329                      (const_int 4) (const_int 1)))])