aboutsummaryrefslogtreecommitdiff
path: root/gcc/recog.h
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2020-12-17 00:15:07 +0000
committerRichard Sandiford <richard.sandiford@arm.com>2020-12-17 00:15:07 +0000
commit0d74260a1f6704da869b87d163f4be31fd0f2b41 (patch)
treeecb8e15bf6da3cd0a8a96cc22819679f05ec439c /gcc/recog.h
parenteb74135dd35213f800f434df92b2835ce49f8ea6 (diff)
downloadgcc-0d74260a1f6704da869b87d163f4be31fd0f2b41.zip
gcc-0d74260a1f6704da869b87d163f4be31fd0f2b41.tar.gz
gcc-0d74260a1f6704da869b87d163f4be31fd0f2b41.tar.bz2
recog: Add a class for propagating into insns
This patch adds yet another way of propagating into an instruction and simplifying the result. (The net effect of the series is to keep the total number of propagation approaches the same though, since a later patch removes the fwprop.c routines.) One of the drawbacks of the validate_replace_* routines is that they only do simple simplifications, mostly canonicalisations: /* Do changes needed to keep rtx consistent. Don't do any other simplifications, as it is not our job. */ if (simplify) simplify_while_replacing (loc, to, object, op0_mode); But substituting can often lead to real simplification opportunities. simplify-rtx.c:simplify_replace_rtx does fully simplify the result, but it only operates on specific rvalues rather than full instruction patterns. It is also nondestructive, which means that it returns a new rtx whenever a substitution or simplification was possible. This can create quite a bit of garbage rtl in the context of a speculative recog, where changing the contents of a pointer is often enough. The new routines are therefore supposed to provide simplify_replace_rtx- style substitution in recog. They go to some effort to prevent garbage rtl from being created. At the moment, the new routines fail if the pattern would still refer to the old "from" value in some way. That might be unnecessary in some contexts; if so, it could be put behind a configuration parameter. gcc/ * recog.h (insn_propagation): New class. * recog.c (insn_propagation::apply_to_mem_1): New function. (insn_propagation::apply_to_rvalue_1): Likewise. (insn_propagation::apply_to_lvalue_1): Likewise. (insn_propagation::apply_to_pattern_1): Likewise. (insn_propagation::apply_to_pattern): Likewise. (insn_propagation::apply_to_rvalue): Likewise.
Diffstat (limited to 'gcc/recog.h')
-rw-r--r--gcc/recog.h100
1 files changed, 100 insertions, 0 deletions
diff --git a/gcc/recog.h b/gcc/recog.h
index facf36e..d6af2aa 100644
--- a/gcc/recog.h
+++ b/gcc/recog.h
@@ -82,6 +82,106 @@ alternative_class (const operand_alternative *alt, int i)
return alt[i].matches >= 0 ? alt[alt[i].matches].cl : alt[i].cl;
}
+/* A class for substituting one rtx for another within an instruction,
+ or for recursively simplifying the instruction as-is. Derived classes
+ can record or filter certain decisions. */
+
+class insn_propagation : public simplify_context
+{
+public:
+ /* Assignments for RESULT_FLAGS.
+
+ UNSIMPLIFIED is true if a substitution has been made inside an rtx
+ X and if neither X nor its parent expressions could be simplified.
+
+ FIRST_SPARE_RESULT is the first flag available for derived classes. */
+ static const uint16_t UNSIMPLIFIED = 1U << 0;
+ static const uint16_t FIRST_SPARE_RESULT = 1U << 1;
+
+ insn_propagation (rtx_insn *);
+ insn_propagation (rtx_insn *, rtx, rtx, bool = true);
+ bool apply_to_pattern (rtx *);
+ bool apply_to_rvalue (rtx *);
+
+ /* Return true if we should accept a substitution into the address of
+ memory expression MEM. Undoing changes OLD_NUM_CHANGES and up restores
+ MEM's original address. */
+ virtual bool check_mem (int /*old_num_changes*/,
+ rtx /*mem*/) { return true; }
+
+ /* Note that we've simplified OLD_RTX into NEW_RTX. When substituting,
+ this only happens if a substitution occured within OLD_RTX.
+ Undoing OLD_NUM_CHANGES and up will restore the old form of OLD_RTX.
+ OLD_RESULT_FLAGS is the value that RESULT_FLAGS had before processing
+ OLD_RTX. */
+ virtual void note_simplification (int /*old_num_changes*/,
+ uint16_t /*old_result_flags*/,
+ rtx /*old_rtx*/, rtx /*new_rtx*/) {}
+
+private:
+ bool apply_to_mem_1 (rtx);
+ bool apply_to_lvalue_1 (rtx);
+ bool apply_to_rvalue_1 (rtx *);
+ bool apply_to_pattern_1 (rtx *);
+
+public:
+ /* The instruction that we are simplifying or propagating into. */
+ rtx_insn *insn;
+
+ /* If FROM is nonnull, we're replacing FROM with TO, otherwise we're
+ just doing a recursive simplification. */
+ rtx from;
+ rtx to;
+
+ /* The number of times that we have replaced FROM with TO. */
+ unsigned int num_replacements;
+
+ /* A bitmask of flags that describe the result of the simplificiation;
+ see above for details. */
+ uint16_t result_flags : 16;
+
+ /* True if we should unshare TO when making the next substitution,
+ false if we can use TO itself. */
+ uint16_t should_unshare : 1;
+
+ /* True if we should call check_mem after substituting into a memory. */
+ uint16_t should_check_mems : 1;
+
+ /* True if we should call note_simplification after each simplification. */
+ uint16_t should_note_simplifications : 1;
+
+ /* For future expansion. */
+ uint16_t spare : 13;
+
+ /* Gives the reason that a substitution failed, for debug purposes. */
+ const char *failure_reason;
+};
+
+/* Try to replace FROM with TO in INSN. SHARED_P is true if TO is shared
+ with other instructions, false if INSN can use TO directly. */
+
+inline insn_propagation::insn_propagation (rtx_insn *insn, rtx from, rtx to,
+ bool shared_p)
+ : insn (insn),
+ from (from),
+ to (to),
+ num_replacements (0),
+ result_flags (0),
+ should_unshare (shared_p),
+ should_check_mems (false),
+ should_note_simplifications (false),
+ spare (0),
+ failure_reason (nullptr)
+{
+}
+
+/* Try to simplify INSN without performing a substitution. */
+
+inline insn_propagation::insn_propagation (rtx_insn *insn)
+ : insn_propagation (insn, NULL_RTX, NULL_RTX)
+{
+}
+
extern void init_recog (void);
extern void init_recog_no_volatile (void);
extern int check_asm_operands (rtx);