static bool deletable_insn_p (rtx_insn *insn, bool fast, bitmap arg_stores) { rtx body, x; int i; df_ref def; if (CALL_P (insn) /* We cannot delete calls inside of the recursive dce because this may cause basic blocks to be deleted and this messes up the rest of the stack of optimization passes. */ && (!df_in_progress) /* We cannot delete pure or const sibling calls because it is hard to see the result. */ && (!SIBLING_CALL_P (insn)) /* We can delete dead const or pure calls as long as they do not infinite loop. */ && (RTL_CONST_OR_PURE_CALL_P (insn) && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn))) return find_call_stack_args (as_a <rtx_call_insn *> (insn), false, fast, arg_stores); /* Don't delete jumps, notes and the like. */ if (!NONJUMP_INSN_P (insn)) return false; /* Don't delete insns that may throw if we cannot do so. */ if (!(cfun->can_delete_dead_exceptions && can_alter_cfg) && !insn_nothrow_p (insn)) return false; /* If INSN sets a global_reg, leave it untouched. */ FOR_EACH_INSN_DEF (def, insn) if (HARD_REGISTER_NUM_P (DF_REF_REGNO (def)) && global_regs[DF_REF_REGNO (def)]) return false; /* Initialization of pseudo PIC register should never be removed. */ else if (DF_REF_REG (def) == pic_offset_table_rtx && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER) return false; body = PATTERN (insn); switch (GET_CODE (body)) { case USE: case VAR_LOCATION: return false; case CLOBBER: if (fast) { /* A CLOBBER of a dead pseudo register serves no purpose. That is not necessarily true for hard registers until after reload. */ x = XEXP (body, 0); return REG_P (x) && (!HARD_REGISTER_P (x) || reload_completed); } else /* Because of the way that use-def chains are built, it is not possible to tell if the clobber is dead because it can never be the target of a use-def chain. */ return false; case PARALLEL: for (i = XVECLEN (body, 0) - 1; i >= 0; i--) if (!deletable_insn_p_1 (XVECEXP (body, 0, i))) return false; return true; default: return deletable_insn_p_1 (body); } }
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); }