/* Return non-zero if the consumer (a multiply-accumulate instruction) has an accumulator dependency on the result of the producer (a multiplication instruction) and no other dependency on that result. */ int arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer) { rtx mul = PATTERN (producer); rtx mac = PATTERN (consumer); rtx mul_result; rtx mac_op0, mac_op1, mac_acc; if (GET_CODE (mul) == COND_EXEC) mul = COND_EXEC_CODE (mul); if (GET_CODE (mac) == COND_EXEC) mac = COND_EXEC_CODE (mac); /* Check that mul is of the form (set (...) (mult ...)) and mla is of the form (set (...) (plus (mult ...) (...))). */ if ((GET_CODE (mul) != SET || GET_CODE (XEXP (mul, 1)) != MULT) || (GET_CODE (mac) != SET || GET_CODE (XEXP (mac, 1)) != PLUS || GET_CODE (XEXP (XEXP (mac, 1), 0)) != MULT)) return 0; mul_result = XEXP (mul, 0); mac_op0 = XEXP (XEXP (XEXP (mac, 1), 0), 0); mac_op1 = XEXP (XEXP (XEXP (mac, 1), 0), 1); mac_acc = XEXP (XEXP (mac, 1), 1); return (reg_overlap_mentioned_p (mul_result, mac_acc) && !reg_overlap_mentioned_p (mul_result, mac_op0) && !reg_overlap_mentioned_p (mul_result, mac_op1)); }
/* Return non-zero iff the consumer (a multiply-accumulate or a multiple-subtract instruction) has an accumulator dependency on the result of the producer and no other dependency on that result. It does not check if the producer is multiply-accumulate instruction. */ int arm_mac_accumulator_is_result (rtx producer, rtx consumer) { rtx result; rtx op0, op1, acc; producer = PATTERN (producer); consumer = PATTERN (consumer); if (GET_CODE (producer) == COND_EXEC) producer = COND_EXEC_CODE (producer); if (GET_CODE (consumer) == COND_EXEC) consumer = COND_EXEC_CODE (consumer); if (GET_CODE (producer) != SET) return 0; result = XEXP (producer, 0); if (GET_CODE (consumer) != SET) return 0; /* Check that the consumer is of the form (set (...) (plus (mult ...) (...))) or (set (...) (minus (...) (mult ...))). */ if (GET_CODE (XEXP (consumer, 1)) == PLUS) { if (GET_CODE (XEXP (XEXP (consumer, 1), 0)) != MULT) return 0; op0 = XEXP (XEXP (XEXP (consumer, 1), 0), 0); op1 = XEXP (XEXP (XEXP (consumer, 1), 0), 1); acc = XEXP (XEXP (consumer, 1), 1); } else if (GET_CODE (XEXP (consumer, 1)) == MINUS) { if (GET_CODE (XEXP (XEXP (consumer, 1), 1)) != MULT) return 0; op0 = XEXP (XEXP (XEXP (consumer, 1), 1), 0); op1 = XEXP (XEXP (XEXP (consumer, 1), 1), 1); acc = XEXP (XEXP (consumer, 1), 0); } else return 0; return (reg_overlap_mentioned_p (result, acc) && !reg_overlap_mentioned_p (result, op0) && !reg_overlap_mentioned_p (result, op1)); }
void print_pattern (pretty_printer *pp, const_rtx x, int verbose) { if (! x) { pp_string (pp, "(nil)"); return; } switch (GET_CODE (x)) { case SET: print_value (pp, SET_DEST (x), verbose); pp_equal (pp); print_value (pp, SET_SRC (x), verbose); break; case RETURN: case SIMPLE_RETURN: case EH_RETURN: pp_string (pp, GET_RTX_NAME (GET_CODE (x))); break; case CALL: print_exp (pp, x, verbose); break; case CLOBBER: case USE: pp_printf (pp, "%s ", GET_RTX_NAME (GET_CODE (x))); print_value (pp, XEXP (x, 0), verbose); break; case VAR_LOCATION: pp_string (pp, "loc "); print_value (pp, PAT_VAR_LOCATION_LOC (x), verbose); break; case COND_EXEC: pp_left_paren (pp); if (GET_CODE (COND_EXEC_TEST (x)) == NE && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx) print_value (pp, XEXP (COND_EXEC_TEST (x), 0), verbose); else if (GET_CODE (COND_EXEC_TEST (x)) == EQ && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx) { pp_exclamation (pp); print_value (pp, XEXP (COND_EXEC_TEST (x), 0), verbose); } else print_value (pp, COND_EXEC_TEST (x), verbose); pp_string (pp, ") "); print_pattern (pp, COND_EXEC_CODE (x), verbose); break; case PARALLEL: { int i; pp_left_brace (pp); for (i = 0; i < XVECLEN (x, 0); i++) { print_pattern (pp, XVECEXP (x, 0, i), verbose); pp_semicolon (pp); } pp_right_brace (pp); } break; case SEQUENCE: { pp_string (pp, "sequence{"); if (INSN_P (XVECEXP (x, 0, 0))) { /* Print the sequence insns indented. */ const char * save_print_rtx_head = print_rtx_head; char indented_print_rtx_head[32]; pp_newline (pp); gcc_assert (strlen (print_rtx_head) < sizeof (indented_print_rtx_head) - 4); snprintf (indented_print_rtx_head, sizeof (indented_print_rtx_head), "%s ", print_rtx_head); print_rtx_head = indented_print_rtx_head; for (int i = 0; i < XVECLEN (x, 0); i++) print_insn_with_notes (pp, XVECEXP (x, 0, i)); pp_printf (pp, "%s ", save_print_rtx_head); print_rtx_head = save_print_rtx_head; } else { for (int i = 0; i < XVECLEN (x, 0); i++) { print_pattern (pp, XVECEXP (x, 0, i), verbose); pp_semicolon (pp); } } pp_right_brace (pp); } break; case ASM_INPUT: pp_printf (pp, "asm {%s}", XSTR (x, 0)); break; case ADDR_VEC: /* Fall through. */ case ADDR_DIFF_VEC: print_value (pp, XEXP (x, 0), verbose); break; case TRAP_IF: pp_string (pp, "trap_if "); print_value (pp, TRAP_CONDITION (x), verbose); break; case UNSPEC: case UNSPEC_VOLATILE: /* Fallthru -- leave UNSPECs to print_exp. */ default: print_value (pp, x, verbose); } } /* print_pattern */
void print_pattern (char *buf, const_rtx x, int verbose) { char t1[BUF_LEN], t2[BUF_LEN], t3[BUF_LEN]; switch (GET_CODE (x)) { case SET: print_value (t1, SET_DEST (x), verbose); print_value (t2, SET_SRC (x), verbose); sprintf (buf, "%s=%s", t1, t2); break; case RETURN: sprintf (buf, "return"); break; case SIMPLE_RETURN: sprintf (buf, "simple_return"); break; case CALL: print_exp (buf, x, verbose); break; case CLOBBER: print_value (t1, XEXP (x, 0), verbose); sprintf (buf, "clobber %s", t1); break; case USE: print_value (t1, XEXP (x, 0), verbose); sprintf (buf, "use %s", t1); break; case VAR_LOCATION: print_value (t1, PAT_VAR_LOCATION_LOC (x), verbose); sprintf (buf, "loc %s", t1); break; case COND_EXEC: if (GET_CODE (COND_EXEC_TEST (x)) == NE && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx) print_value (t1, XEXP (COND_EXEC_TEST (x), 0), verbose); else if (GET_CODE (COND_EXEC_TEST (x)) == EQ && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx) { t1[0] = '!'; print_value (t1 + 1, XEXP (COND_EXEC_TEST (x), 0), verbose); } else print_value (t1, COND_EXEC_TEST (x), verbose); print_pattern (t2, COND_EXEC_CODE (x), verbose); sprintf (buf, "(%s) %s", t1, t2); break; case PARALLEL: { int i; sprintf (t1, "{"); for (i = 0; i < XVECLEN (x, 0); i++) { print_pattern (t2, XVECEXP (x, 0, i), verbose); sprintf (t3, "%s%s;", t1, t2); strcpy (t1, t3); } sprintf (buf, "%s}", t1); } break; case SEQUENCE: /* Should never see SEQUENCE codes until after reorg. */ gcc_unreachable (); case ASM_INPUT: sprintf (buf, "asm {%s}", XSTR (x, 0)); break; case ADDR_VEC: /* Fall through. */ case ADDR_DIFF_VEC: print_value (buf, XEXP (x, 0), verbose); break; case TRAP_IF: print_value (t1, TRAP_CONDITION (x), verbose); sprintf (buf, "trap_if %s", t1); break; case UNSPEC: { int i; sprintf (t1, "unspec{"); for (i = 0; i < XVECLEN (x, 0); i++) { print_pattern (t2, XVECEXP (x, 0, i), verbose); sprintf (t3, "%s%s;", t1, t2); strcpy (t1, t3); } sprintf (buf, "%s}", t1); } break; case UNSPEC_VOLATILE: { int i; sprintf (t1, "unspec/v{"); for (i = 0; i < XVECLEN (x, 0); i++) { print_pattern (t2, XVECEXP (x, 0, i), verbose); sprintf (t3, "%s%s;", t1, t2); strcpy (t1, t3); } sprintf (buf, "%s}", t1); } break; default: print_value (buf, x, verbose); } } /* print_pattern */