static bool replace_oldest_value_mem (rtx x, rtx insn, struct value_data *vd) { enum reg_class cl; if (DEBUG_INSN_P (insn)) cl = ALL_REGS; else cl = base_reg_class (GET_MODE (x), MEM_ADDR_SPACE (x), MEM, SCRATCH); return replace_oldest_value_addr (&XEXP (x, 0), cl, GET_MODE (x), MEM_ADDR_SPACE (x), insn, vd); }
rtx gen_lowpart_if_possible (machine_mode mode, rtx x) { rtx result = gen_lowpart_common (mode, x); if (result) return result; else if (MEM_P (x)) { /* This is the only other case we handle. */ poly_int64 offset = byte_lowpart_offset (mode, GET_MODE (x)); rtx new_rtx = adjust_address_nv (x, mode, offset); if (! memory_address_addr_space_p (mode, XEXP (new_rtx, 0), MEM_ADDR_SPACE (x))) return 0; return new_rtx; } else if (mode != GET_MODE (x) && GET_MODE (x) != VOIDmode && validate_subreg (mode, GET_MODE (x), x, subreg_lowpart_offset (mode, GET_MODE (x)))) return gen_lowpart_SUBREG (mode, x); else return 0; }
int rtx_equal_p (const_rtx x, const_rtx y) { int i; int j; enum rtx_code code; const char *fmt; if (x == y) return 1; if (x == 0 || y == 0) return 0; code = GET_CODE (x); /* Rtx's of different codes cannot be equal. */ if (code != GET_CODE (y)) return 0; /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. (REG:SI x) and (REG:HI x) are NOT equivalent. */ if (GET_MODE (x) != GET_MODE (y)) return 0; /* MEMs referring to different address space are not equivalent. */ if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) return 0; /* Some RTL can be compared nonrecursively. */ switch (code) { case REG: return (REGNO (x) == REGNO (y)); case LABEL_REF: return XEXP (x, 0) == XEXP (y, 0); case SYMBOL_REF: return XSTR (x, 0) == XSTR (y, 0); case DEBUG_EXPR: case VALUE: case SCRATCH: case CONST_DOUBLE: case CONST_INT: case CONST_FIXED: return 0; case DEBUG_IMPLICIT_PTR: return DEBUG_IMPLICIT_PTR_DECL (x) == DEBUG_IMPLICIT_PTR_DECL (y); case DEBUG_PARAMETER_REF: return DEBUG_PARAMETER_REF_DECL (x) == DEBUG_PARAMETER_REF_DECL (y); case ENTRY_VALUE: return rtx_equal_p (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y)); default: break; } /* Compare the elements. If any pair of corresponding elements fail to match, return 0 for the whole thing. */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { switch (fmt[i]) { case 'w': if (XWINT (x, i) != XWINT (y, i)) return 0; break; case 'n': case 'i': if (XINT (x, i) != XINT (y, i)) { #ifndef GENERATOR_FILE if (((code == ASM_OPERANDS && i == 6) || (code == ASM_INPUT && i == 1)) && locator_eq (XINT (x, i), XINT (y, i))) break; #endif return 0; } break; case 'V': case 'E': /* Two vectors must have the same length. */ if (XVECLEN (x, i) != XVECLEN (y, i)) return 0; /* And the corresponding elements must match. */ for (j = 0; j < XVECLEN (x, i); j++) if (rtx_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0) return 0; break; case 'e': if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0) return 0; break; case 'S': case 's': if ((XSTR (x, i) || XSTR (y, i)) && (! XSTR (x, i) || ! XSTR (y, i) || strcmp (XSTR (x, i), XSTR (y, i)))) return 0; break; case 'u': /* These are just backpointers, so they don't matter. */ break; case '0': case 't': break; /* It is believed that rtx's at this level will never contain anything but integers and other rtx's, except for within LABEL_REFs and SYMBOL_REFs. */ default: gcc_unreachable (); } } return 1; }
static bool propagate_rtx_1 (rtx *px, rtx old_rtx, rtx new_rtx, int flags) { rtx x = *px, tem = NULL_RTX, op0, op1, op2; enum rtx_code code = GET_CODE (x); machine_mode mode = GET_MODE (x); machine_mode op_mode; bool can_appear = (flags & PR_CAN_APPEAR) != 0; bool valid_ops = true; if (!(flags & PR_HANDLE_MEM) && MEM_P (x) && !MEM_READONLY_P (x)) { /* If unsafe, change MEMs to CLOBBERs or SCRATCHes (to preserve whether they have side effects or not). */ *px = (side_effects_p (x) ? gen_rtx_CLOBBER (GET_MODE (x), const0_rtx) : gen_rtx_SCRATCH (GET_MODE (x))); return false; } /* If X is OLD_RTX, return NEW_RTX. But not if replacing only within an address, and we are *not* inside one. */ if (x == old_rtx) { *px = new_rtx; return can_appear; } /* If this is an expression, try recursive substitution. */ switch (GET_RTX_CLASS (code)) { case RTX_UNARY: op0 = XEXP (x, 0); op_mode = GET_MODE (op0); valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags); if (op0 == XEXP (x, 0)) return true; tem = simplify_gen_unary (code, mode, op0, op_mode); break; case RTX_BIN_ARITH: case RTX_COMM_ARITH: op0 = XEXP (x, 0); op1 = XEXP (x, 1); valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags); valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags); if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1)) return true; tem = simplify_gen_binary (code, mode, op0, op1); break; case RTX_COMPARE: case RTX_COMM_COMPARE: op0 = XEXP (x, 0); op1 = XEXP (x, 1); op_mode = GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1); valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags); valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags); if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1)) return true; tem = simplify_gen_relational (code, mode, op_mode, op0, op1); break; case RTX_TERNARY: case RTX_BITFIELD_OPS: op0 = XEXP (x, 0); op1 = XEXP (x, 1); op2 = XEXP (x, 2); op_mode = GET_MODE (op0); valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags); valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags); valid_ops &= propagate_rtx_1 (&op2, old_rtx, new_rtx, flags); if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1) && op2 == XEXP (x, 2)) return true; if (op_mode == VOIDmode) op_mode = GET_MODE (op0); tem = simplify_gen_ternary (code, mode, op_mode, op0, op1, op2); break; case RTX_EXTRA: /* The only case we try to handle is a SUBREG. */ if (code == SUBREG) { op0 = XEXP (x, 0); valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags); if (op0 == XEXP (x, 0)) return true; tem = simplify_gen_subreg (mode, op0, GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x)); } break; case RTX_OBJ: if (code == MEM && x != new_rtx) { rtx new_op0; op0 = XEXP (x, 0); /* There are some addresses that we cannot work on. */ if (!can_simplify_addr (op0)) return true; op0 = new_op0 = targetm.delegitimize_address (op0); valid_ops &= propagate_rtx_1 (&new_op0, old_rtx, new_rtx, flags | PR_CAN_APPEAR); /* Dismiss transformation that we do not want to carry on. */ if (!valid_ops || new_op0 == op0 || !(GET_MODE (new_op0) == GET_MODE (op0) || GET_MODE (new_op0) == VOIDmode)) return true; canonicalize_address (new_op0); /* Copy propagations are always ok. Otherwise check the costs. */ if (!(REG_P (old_rtx) && REG_P (new_rtx)) && !should_replace_address (op0, new_op0, GET_MODE (x), MEM_ADDR_SPACE (x), flags & PR_OPTIMIZE_FOR_SPEED)) return true; tem = replace_equiv_address_nv (x, new_op0); } else if (code == LO_SUM) { op0 = XEXP (x, 0); op1 = XEXP (x, 1); /* The only simplification we do attempts to remove references to op0 or make it constant -- in both cases, op0's invalidity will not make the result invalid. */ propagate_rtx_1 (&op0, old_rtx, new_rtx, flags | PR_CAN_APPEAR); valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags); if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1)) return true; /* (lo_sum (high x) x) -> x */ if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1)) tem = op1; else tem = gen_rtx_LO_SUM (mode, op0, op1); /* OP1 is likely not a legitimate address, otherwise there would have been no LO_SUM. We want it to disappear if it is invalid, return false in that case. */ return memory_address_p (mode, tem); } else if (code == REG) { if (rtx_equal_p (x, old_rtx)) { *px = new_rtx; return can_appear; } } break; default: break; } /* No change, no trouble. */ if (tem == NULL_RTX) return true; *px = tem; /* Allow replacements that simplify operations on a vector or complex value to a component. The most prominent case is (subreg ([vec_]concat ...)). */ if (REG_P (tem) && !HARD_REGISTER_P (tem) && (VECTOR_MODE_P (GET_MODE (new_rtx)) || COMPLEX_MODE_P (GET_MODE (new_rtx))) && GET_MODE (tem) == GET_MODE_INNER (GET_MODE (new_rtx))) return true; /* The replacement we made so far is valid, if all of the recursive replacements were valid, or we could simplify everything to a constant. */ return valid_ops || can_appear || CONSTANT_P (tem); }
static bool find_inc (bool first_try) { rtx insn; basic_block bb = BLOCK_FOR_INSN (mem_insn.insn); rtx other_insn; df_ref *def_rec; /* Make sure this reg appears only once in this insn. */ if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg0, 1) != 1) { if (dump_file) fprintf (dump_file, "mem count failure\n"); return false; } if (dump_file) dump_mem_insn (dump_file); /* Find the next use that is an inc. */ insn = get_next_ref (REGNO (mem_insn.reg0), BLOCK_FOR_INSN (mem_insn.insn), reg_next_inc_use); if (!insn) return false; /* Even though we know the next use is an add or inc because it came from the reg_next_inc_use, we must still reparse. */ if (!parse_add_or_inc (insn, false)) { /* Next use was not an add. Look for one extra case. It could be that we have: *(a + b) ...= a; ...= b + a if we reverse the operands in the mem ref we would find this. Only try it once though. */ if (first_try && !mem_insn.reg1_is_const) { reverse_mem (); return find_inc (false); } else return false; } /* Need to assure that none of the operands of the inc instruction are assigned to by the mem insn. */ for (def_rec = DF_INSN_DEFS (mem_insn.insn); *def_rec; def_rec++) { df_ref def = *def_rec; unsigned int regno = DF_REF_REGNO (def); if ((regno == REGNO (inc_insn.reg0)) || (regno == REGNO (inc_insn.reg_res))) { if (dump_file) fprintf (dump_file, "inc conflicts with store failure.\n"); return false; } if (!inc_insn.reg1_is_const && (regno == REGNO (inc_insn.reg1))) { if (dump_file) fprintf (dump_file, "inc conflicts with store failure.\n"); return false; } } if (dump_file) dump_inc_insn (dump_file); if (inc_insn.form == FORM_POST_ADD) { /* Make sure that there is no insn that assigns to inc_insn.res between the mem_insn and the inc_insn. */ rtx other_insn = get_next_ref (REGNO (inc_insn.reg_res), BLOCK_FOR_INSN (mem_insn.insn), reg_next_def); if (other_insn != inc_insn.insn) { if (dump_file) fprintf (dump_file, "result of add is assigned to between mem and inc insns.\n"); return false; } other_insn = get_next_ref (REGNO (inc_insn.reg_res), BLOCK_FOR_INSN (mem_insn.insn), reg_next_use); if (other_insn && (other_insn != inc_insn.insn) && (DF_INSN_LUID (inc_insn.insn) > DF_INSN_LUID (other_insn))) { if (dump_file) fprintf (dump_file, "result of add is used between mem and inc insns.\n"); return false; } /* For the post_add to work, the result_reg of the inc must not be used in the mem insn since this will become the new index register. */ if (reg_overlap_mentioned_p (inc_insn.reg_res, PATTERN (mem_insn.insn))) { if (dump_file) fprintf (dump_file, "base reg replacement failure.\n"); return false; } } if (mem_insn.reg1_is_const) { if (mem_insn.reg1_val == 0) { if (!inc_insn.reg1_is_const) { /* The mem looks like *r0 and the rhs of the add has two registers. */ int luid = DF_INSN_LUID (inc_insn.insn); if (inc_insn.form == FORM_POST_ADD) { /* The trick is that we are not going to increment r0, we are going to increment the result of the add insn. For this trick to be correct, the result reg of the inc must be a valid addressing reg. */ addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc); if (GET_MODE (inc_insn.reg_res) != targetm.addr_space.address_mode (as)) { if (dump_file) fprintf (dump_file, "base reg mode failure.\n"); return false; } /* We also need to make sure that the next use of inc result is after the inc. */ other_insn = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use); if (other_insn && luid > DF_INSN_LUID (other_insn)) return false; if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0)) reverse_inc (); } other_insn = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); if (other_insn && luid > DF_INSN_LUID (other_insn)) return false; } } /* Both the inc/add and the mem have a constant. Need to check that the constants are ok. */ else if ((mem_insn.reg1_val != inc_insn.reg1_val) && (mem_insn.reg1_val != -inc_insn.reg1_val)) return false; } else { /* The mem insn is of the form *(a + b) where a and b are both regs. It may be that in order to match the add or inc we need to treat it as if it was *(b + a). It may also be that the add is of the form a + c where c does not match b and then we just abandon this. */ int luid = DF_INSN_LUID (inc_insn.insn); rtx other_insn; /* Make sure this reg appears only once in this insn. */ if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg1, 1) != 1) return false; if (inc_insn.form == FORM_POST_ADD) { /* For this trick to be correct, the result reg of the inc must be a valid addressing reg. */ addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc); if (GET_MODE (inc_insn.reg_res) != targetm.addr_space.address_mode (as)) { if (dump_file) fprintf (dump_file, "base reg mode failure.\n"); return false; } if (rtx_equal_p (mem_insn.reg0, inc_insn.reg0)) { if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1)) { /* See comment above on find_inc (false) call. */ if (first_try) { reverse_mem (); return find_inc (false); } else return false; } /* Need to check that there are no assignments to b before the add insn. */ other_insn = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); if (other_insn && luid > DF_INSN_LUID (other_insn)) return false; /* All ok for the next step. */ } else { /* We know that mem_insn.reg0 must equal inc_insn.reg1 or else we would not have found the inc insn. */ reverse_mem (); if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0)) { /* See comment above on find_inc (false) call. */ if (first_try) return find_inc (false); else return false; } /* To have gotten here know that. *(b + a) ... = (b + a) We also know that the lhs of the inc is not b or a. We need to make sure that there are no assignments to b between the mem ref and the inc. */ other_insn = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_def); if (other_insn && luid > DF_INSN_LUID (other_insn)) return false; } /* Need to check that the next use of the add result is later than add insn since this will be the reg incremented. */ other_insn = get_next_ref (REGNO (inc_insn.reg_res), bb, reg_next_use); if (other_insn && luid > DF_INSN_LUID (other_insn)) return false; } else /* FORM_POST_INC. There is less to check here because we know that operands must line up. */ { if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1)) /* See comment above on find_inc (false) call. */ { if (first_try) { reverse_mem (); return find_inc (false); } else return false; } /* To have gotten here know that. *(a + b) ... = (a + b) We also know that the lhs of the inc is not b. We need to make sure that there are no assignments to b between the mem ref and the inc. */ other_insn = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); if (other_insn && luid > DF_INSN_LUID (other_insn)) return false; } } if (inc_insn.form == FORM_POST_INC) { other_insn = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_use); /* When we found inc_insn, we were looking for the next add or inc, not the next insn that used the reg. Because we are going to increment the reg in this form, we need to make sure that there were no intervening uses of reg. */ if (inc_insn.insn != other_insn) return false; } return try_merge (); }
static void print_rtx (const_rtx in_rtx) { int i = 0; int j; const char *format_ptr; int is_insn; if (sawclose) { if (flag_simple) fputc (' ', outfile); else fprintf (outfile, "\n%s%*s", print_rtx_head, indent * 2, ""); sawclose = 0; } if (in_rtx == 0) { fputs ("(nil)", outfile); sawclose = 1; return; } else if (GET_CODE (in_rtx) > NUM_RTX_CODE) { fprintf (outfile, "(??? bad code %d\n%s%*s)", GET_CODE (in_rtx), print_rtx_head, indent * 2, ""); sawclose = 1; return; } is_insn = INSN_P (in_rtx); /* Print name of expression code. */ if (flag_simple && CONST_INT_P (in_rtx)) fputc ('(', outfile); else fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx))); if (! flag_simple) { if (RTX_FLAG (in_rtx, in_struct)) fputs ("/s", outfile); if (RTX_FLAG (in_rtx, volatil)) fputs ("/v", outfile); if (RTX_FLAG (in_rtx, unchanging)) fputs ("/u", outfile); if (RTX_FLAG (in_rtx, frame_related)) fputs ("/f", outfile); if (RTX_FLAG (in_rtx, jump)) fputs ("/j", outfile); if (RTX_FLAG (in_rtx, call)) fputs ("/c", outfile); if (RTX_FLAG (in_rtx, return_val)) fputs ("/i", outfile); /* Print REG_NOTE names for EXPR_LIST and INSN_LIST. */ if ((GET_CODE (in_rtx) == EXPR_LIST || GET_CODE (in_rtx) == INSN_LIST || GET_CODE (in_rtx) == INT_LIST) && (int)GET_MODE (in_rtx) < REG_NOTE_MAX) fprintf (outfile, ":%s", GET_REG_NOTE_NAME (GET_MODE (in_rtx))); /* For other rtl, print the mode if it's not VOID. */ else if (GET_MODE (in_rtx) != VOIDmode) fprintf (outfile, ":%s", GET_MODE_NAME (GET_MODE (in_rtx))); #ifndef GENERATOR_FILE if (GET_CODE (in_rtx) == VAR_LOCATION) { if (TREE_CODE (PAT_VAR_LOCATION_DECL (in_rtx)) == STRING_CST) fputs (" <debug string placeholder>", outfile); else print_mem_expr (outfile, PAT_VAR_LOCATION_DECL (in_rtx)); fputc (' ', outfile); print_rtx (PAT_VAR_LOCATION_LOC (in_rtx)); if (PAT_VAR_LOCATION_STATUS (in_rtx) == VAR_INIT_STATUS_UNINITIALIZED) fprintf (outfile, " [uninit]"); sawclose = 1; i = GET_RTX_LENGTH (VAR_LOCATION); } #endif } #ifndef GENERATOR_FILE if (CONST_DOUBLE_AS_FLOAT_P (in_rtx)) i = 5; #endif /* Get the format string and skip the first elements if we have handled them already. */ format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)) + i; for (; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++) switch (*format_ptr++) { const char *str; case 'T': str = XTMPL (in_rtx, i); goto string; case 'S': case 's': str = XSTR (in_rtx, i); string: if (str == 0) fputs (" \"\"", outfile); else fprintf (outfile, " (\"%s\")", str); sawclose = 1; break; /* 0 indicates a field for internal use that should not be printed. An exception is the third field of a NOTE, where it indicates that the field has several different valid contents. */ case '0': if (i == 1 && REG_P (in_rtx)) { if (REGNO (in_rtx) != ORIGINAL_REGNO (in_rtx)) fprintf (outfile, " [%d]", ORIGINAL_REGNO (in_rtx)); } #ifndef GENERATOR_FILE else if (i == 1 && GET_CODE (in_rtx) == SYMBOL_REF) { int flags = SYMBOL_REF_FLAGS (in_rtx); if (flags) fprintf (outfile, " [flags %#x]", flags); } else if (i == 2 && GET_CODE (in_rtx) == SYMBOL_REF) { tree decl = SYMBOL_REF_DECL (in_rtx); if (decl) print_node_brief (outfile, "", decl, dump_flags); } #endif else if (i == 4 && NOTE_P (in_rtx)) { switch (NOTE_KIND (in_rtx)) { case NOTE_INSN_EH_REGION_BEG: case NOTE_INSN_EH_REGION_END: if (flag_dump_unnumbered) fprintf (outfile, " #"); else fprintf (outfile, " %d", NOTE_EH_HANDLER (in_rtx)); sawclose = 1; break; case NOTE_INSN_BLOCK_BEG: case NOTE_INSN_BLOCK_END: #ifndef GENERATOR_FILE dump_addr (outfile, " ", NOTE_BLOCK (in_rtx)); #endif sawclose = 1; break; case NOTE_INSN_BASIC_BLOCK: { #ifndef GENERATOR_FILE basic_block bb = NOTE_BASIC_BLOCK (in_rtx); if (bb != 0) fprintf (outfile, " [bb %d]", bb->index); #endif break; } case NOTE_INSN_DELETED_LABEL: case NOTE_INSN_DELETED_DEBUG_LABEL: { const char *label = NOTE_DELETED_LABEL_NAME (in_rtx); if (label) fprintf (outfile, " (\"%s\")", label); else fprintf (outfile, " \"\""); } break; case NOTE_INSN_SWITCH_TEXT_SECTIONS: { #ifndef GENERATOR_FILE basic_block bb = NOTE_BASIC_BLOCK (in_rtx); if (bb != 0) fprintf (outfile, " [bb %d]", bb->index); #endif break; } case NOTE_INSN_VAR_LOCATION: case NOTE_INSN_CALL_ARG_LOCATION: #ifndef GENERATOR_FILE fputc (' ', outfile); print_rtx (NOTE_VAR_LOCATION (in_rtx)); #endif break; case NOTE_INSN_CFI: #ifndef GENERATOR_FILE fputc ('\n', outfile); output_cfi_directive (outfile, NOTE_CFI (in_rtx)); fputc ('\t', outfile); #endif break; default: break; } } else if (i == 8 && JUMP_P (in_rtx) && JUMP_LABEL (in_rtx) != NULL) { /* Output the JUMP_LABEL reference. */ fprintf (outfile, "\n%s%*s -> ", print_rtx_head, indent * 2, ""); if (GET_CODE (JUMP_LABEL (in_rtx)) == RETURN) fprintf (outfile, "return"); else if (GET_CODE (JUMP_LABEL (in_rtx)) == SIMPLE_RETURN) fprintf (outfile, "simple_return"); else fprintf (outfile, "%d", INSN_UID (JUMP_LABEL (in_rtx))); } else if (i == 0 && GET_CODE (in_rtx) == VALUE) { #ifndef GENERATOR_FILE cselib_val *val = CSELIB_VAL_PTR (in_rtx); fprintf (outfile, " %u:%u", val->uid, val->hash); dump_addr (outfile, " @", in_rtx); dump_addr (outfile, "/", (void*)val); #endif } else if (i == 0 && GET_CODE (in_rtx) == DEBUG_EXPR) { #ifndef GENERATOR_FILE fprintf (outfile, " D#%i", DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (in_rtx))); #endif } else if (i == 0 && GET_CODE (in_rtx) == ENTRY_VALUE) { indent += 2; if (!sawclose) fprintf (outfile, " "); print_rtx (ENTRY_VALUE_EXP (in_rtx)); indent -= 2; } break; case 'e': do_e: indent += 2; if (i == 7 && INSN_P (in_rtx)) /* Put REG_NOTES on their own line. */ fprintf (outfile, "\n%s%*s", print_rtx_head, indent * 2, ""); if (!sawclose) fprintf (outfile, " "); print_rtx (XEXP (in_rtx, i)); indent -= 2; break; case 'E': case 'V': indent += 2; if (sawclose) { fprintf (outfile, "\n%s%*s", print_rtx_head, indent * 2, ""); sawclose = 0; } fputs (" [", outfile); if (NULL != XVEC (in_rtx, i)) { indent += 2; if (XVECLEN (in_rtx, i)) sawclose = 1; for (j = 0; j < XVECLEN (in_rtx, i); j++) print_rtx (XVECEXP (in_rtx, i, j)); indent -= 2; } if (sawclose) fprintf (outfile, "\n%s%*s", print_rtx_head, indent * 2, ""); fputs ("]", outfile); sawclose = 1; indent -= 2; break; case 'w': if (! flag_simple) fprintf (outfile, " "); fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, XWINT (in_rtx, i)); if (! flag_simple) fprintf (outfile, " [" HOST_WIDE_INT_PRINT_HEX "]", (unsigned HOST_WIDE_INT) XWINT (in_rtx, i)); break; case 'i': if (i == 5 && INSN_P (in_rtx)) { #ifndef GENERATOR_FILE /* Pretty-print insn locations. Ignore scoping as it is mostly redundant with line number information and do not print anything when there is no location information available. */ if (INSN_LOCATION (in_rtx) && insn_file (in_rtx)) fprintf(outfile, " %s:%i", insn_file (in_rtx), insn_line (in_rtx)); #endif } else if (i == 6 && GET_CODE (in_rtx) == ASM_OPERANDS) { #ifndef GENERATOR_FILE fprintf (outfile, " %s:%i", LOCATION_FILE (ASM_OPERANDS_SOURCE_LOCATION (in_rtx)), LOCATION_LINE (ASM_OPERANDS_SOURCE_LOCATION (in_rtx))); #endif } else if (i == 1 && GET_CODE (in_rtx) == ASM_INPUT) { #ifndef GENERATOR_FILE fprintf (outfile, " %s:%i", LOCATION_FILE (ASM_INPUT_SOURCE_LOCATION (in_rtx)), LOCATION_LINE (ASM_INPUT_SOURCE_LOCATION (in_rtx))); #endif } else if (i == 6 && NOTE_P (in_rtx)) { /* This field is only used for NOTE_INSN_DELETED_LABEL, and other times often contains garbage from INSN->NOTE death. */ if (NOTE_KIND (in_rtx) == NOTE_INSN_DELETED_LABEL || NOTE_KIND (in_rtx) == NOTE_INSN_DELETED_DEBUG_LABEL) fprintf (outfile, " %d", XINT (in_rtx, i)); } #if !defined(GENERATOR_FILE) && NUM_UNSPECV_VALUES > 0 else if (i == 1 && GET_CODE (in_rtx) == UNSPEC_VOLATILE && XINT (in_rtx, 1) >= 0 && XINT (in_rtx, 1) < NUM_UNSPECV_VALUES) fprintf (outfile, " %s", unspecv_strings[XINT (in_rtx, 1)]); #endif #if !defined(GENERATOR_FILE) && NUM_UNSPEC_VALUES > 0 else if (i == 1 && (GET_CODE (in_rtx) == UNSPEC || GET_CODE (in_rtx) == UNSPEC_VOLATILE) && XINT (in_rtx, 1) >= 0 && XINT (in_rtx, 1) < NUM_UNSPEC_VALUES) fprintf (outfile, " %s", unspec_strings[XINT (in_rtx, 1)]); #endif else { int value = XINT (in_rtx, i); const char *name; #ifndef GENERATOR_FILE if (REG_P (in_rtx) && (unsigned) value < FIRST_PSEUDO_REGISTER) fprintf (outfile, " %d %s", value, reg_names[value]); else if (REG_P (in_rtx) && (unsigned) value <= LAST_VIRTUAL_REGISTER) { if (value == VIRTUAL_INCOMING_ARGS_REGNUM) fprintf (outfile, " %d virtual-incoming-args", value); else if (value == VIRTUAL_STACK_VARS_REGNUM) fprintf (outfile, " %d virtual-stack-vars", value); else if (value == VIRTUAL_STACK_DYNAMIC_REGNUM) fprintf (outfile, " %d virtual-stack-dynamic", value); else if (value == VIRTUAL_OUTGOING_ARGS_REGNUM) fprintf (outfile, " %d virtual-outgoing-args", value); else if (value == VIRTUAL_CFA_REGNUM) fprintf (outfile, " %d virtual-cfa", value); else if (value == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM) fprintf (outfile, " %d virtual-preferred-stack-boundary", value); else fprintf (outfile, " %d virtual-reg-%d", value, value-FIRST_VIRTUAL_REGISTER); } else #endif if (flag_dump_unnumbered && (is_insn || NOTE_P (in_rtx))) fputc ('#', outfile); else fprintf (outfile, " %d", value); #ifndef GENERATOR_FILE if (REG_P (in_rtx) && REG_ATTRS (in_rtx)) { fputs (" [", outfile); if (ORIGINAL_REGNO (in_rtx) != REGNO (in_rtx)) fprintf (outfile, "orig:%i", ORIGINAL_REGNO (in_rtx)); if (REG_EXPR (in_rtx)) print_mem_expr (outfile, REG_EXPR (in_rtx)); if (REG_OFFSET (in_rtx)) fprintf (outfile, "+" HOST_WIDE_INT_PRINT_DEC, REG_OFFSET (in_rtx)); fputs (" ]", outfile); } #endif if (is_insn && &INSN_CODE (in_rtx) == &XINT (in_rtx, i) && XINT (in_rtx, i) >= 0 && (name = get_insn_name (XINT (in_rtx, i))) != NULL) fprintf (outfile, " {%s}", name); sawclose = 0; } break; /* Print NOTE_INSN names rather than integer codes. */ case 'n': fprintf (outfile, " %s", GET_NOTE_INSN_NAME (XINT (in_rtx, i))); sawclose = 0; break; case 'u': if (XEXP (in_rtx, i) != NULL) { rtx sub = XEXP (in_rtx, i); enum rtx_code subc = GET_CODE (sub); if (GET_CODE (in_rtx) == LABEL_REF) { if (subc == NOTE && NOTE_KIND (sub) == NOTE_INSN_DELETED_LABEL) { if (flag_dump_unnumbered) fprintf (outfile, " [# deleted]"); else fprintf (outfile, " [%d deleted]", INSN_UID (sub)); sawclose = 0; break; } if (subc != CODE_LABEL) goto do_e; } if (flag_dump_unnumbered || (flag_dump_unnumbered_links && (i == 1 || i == 2) && (INSN_P (in_rtx) || NOTE_P (in_rtx) || LABEL_P (in_rtx) || BARRIER_P (in_rtx)))) fputs (" #", outfile); else fprintf (outfile, " %d", INSN_UID (sub)); } else fputs (" 0", outfile); sawclose = 0; break; case 't': #ifndef GENERATOR_FILE if (i == 0 && GET_CODE (in_rtx) == DEBUG_IMPLICIT_PTR) print_mem_expr (outfile, DEBUG_IMPLICIT_PTR_DECL (in_rtx)); else if (i == 0 && GET_CODE (in_rtx) == DEBUG_PARAMETER_REF) print_mem_expr (outfile, DEBUG_PARAMETER_REF_DECL (in_rtx)); else dump_addr (outfile, " ", XTREE (in_rtx, i)); #endif break; case '*': fputs (" Unknown", outfile); sawclose = 0; break; case 'B': #ifndef GENERATOR_FILE if (XBBDEF (in_rtx, i)) fprintf (outfile, " %i", XBBDEF (in_rtx, i)->index); #endif break; default: gcc_unreachable (); } switch (GET_CODE (in_rtx)) { #ifndef GENERATOR_FILE case MEM: if (__builtin_expect (final_insns_dump_p, false)) fprintf (outfile, " ["); else fprintf (outfile, " [" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT) MEM_ALIAS_SET (in_rtx)); if (MEM_EXPR (in_rtx)) print_mem_expr (outfile, MEM_EXPR (in_rtx)); if (MEM_OFFSET_KNOWN_P (in_rtx)) fprintf (outfile, "+" HOST_WIDE_INT_PRINT_DEC, MEM_OFFSET (in_rtx)); if (MEM_SIZE_KNOWN_P (in_rtx)) fprintf (outfile, " S" HOST_WIDE_INT_PRINT_DEC, MEM_SIZE (in_rtx)); if (MEM_ALIGN (in_rtx) != 1) fprintf (outfile, " A%u", MEM_ALIGN (in_rtx)); if (!ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (in_rtx))) fprintf (outfile, " AS%u", MEM_ADDR_SPACE (in_rtx)); fputc (']', outfile); break; case CONST_DOUBLE: if (FLOAT_MODE_P (GET_MODE (in_rtx))) { char s[60]; real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (in_rtx), sizeof (s), 0, 1); fprintf (outfile, " %s", s); real_to_hexadecimal (s, CONST_DOUBLE_REAL_VALUE (in_rtx), sizeof (s), 0, 1); fprintf (outfile, " [%s]", s); } break; #endif case CODE_LABEL: fprintf (outfile, " [%d uses]", LABEL_NUSES (in_rtx)); switch (LABEL_KIND (in_rtx)) { case LABEL_NORMAL: break; case LABEL_STATIC_ENTRY: fputs (" [entry]", outfile); break; case LABEL_GLOBAL_ENTRY: fputs (" [global entry]", outfile); break; case LABEL_WEAK_ENTRY: fputs (" [weak entry]", outfile); break; default: gcc_unreachable (); } break; default: break; } fputc (')', outfile); sawclose = 1; }