aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimplify_reg_info.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gimplify_reg_info.h')
-rw-r--r--gcc/gimplify_reg_info.h182
1 files changed, 182 insertions, 0 deletions
diff --git a/gcc/gimplify_reg_info.h b/gcc/gimplify_reg_info.h
new file mode 100644
index 0000000..b56b225
--- /dev/null
+++ b/gcc/gimplify_reg_info.h
@@ -0,0 +1,182 @@
+/* gimplify_reg_info is used during gimplification while walking over
+ operands and their corresponding constraints of asm statements in order to
+ detect errors.
+
+ m_alt_output is a mapping describing which registers are potentially used in
+ which alternative over all outputs. Similarly for m_alt_input but over all
+ inputs.
+
+ m_early_clobbered_alt is a mapping describing which register is early
+ clobbered in which alternative over all outputs.
+
+ m_early_clobbered_output is the counter part to the prior one, i.e., it
+ is a mapping describing which register is early clobbered in which operand
+ over all alternatives.
+
+ m_reg_asm_output is the set of registers (including register pairs) used for
+ register asm output operands.
+
+ m_reg_asm_input similar as m_reg_asm_output but for inputs. */
+
+#include "regs.h"
+
+class gimplify_reg_info
+{
+ HARD_REG_SET *m_buf;
+ HARD_REG_SET *m_alt_output;
+ HARD_REG_SET *m_alt_input;
+ HARD_REG_SET *m_early_clobbered_alt;
+ HARD_REG_SET *m_early_clobbered_output;
+ HARD_REG_SET m_reg_asm_output;
+ HARD_REG_SET m_reg_asm_input;
+ const unsigned m_num_alternatives;
+ const unsigned m_num_outputs;
+ /* Member m_clobbered describes all the registers marked as clobbered in an
+ asm statement, i.e., this is the clobbers list of an extended asm
+
+ asm asm-qualifiers ( AssemblerTemplate
+ : OutputOperands
+ [ : InputOperands
+ [ : Clobbers ] ])
+
+ and is not to be confused with the early clobbers sets. */
+ HARD_REG_SET m_clobbered;
+
+ /* Return the first overlapping register of REGS and REGNO:MODE or -1. */
+ int test (const HARD_REG_SET &regs, int regno) const
+ {
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+
+ if (TEST_HARD_REG_BIT (regs, regno))
+ return regno;
+
+ int end_regno = end_hard_regno (mode, regno);
+ while (++regno < end_regno)
+ if (TEST_HARD_REG_BIT (regs, regno))
+ return regno;
+
+ return -1;
+ }
+
+public:
+ tree operand;
+
+ gimplify_reg_info (unsigned num_alternatives,
+ unsigned num_outputs)
+ : m_num_alternatives{num_alternatives}
+ , m_num_outputs{num_outputs}
+ {
+ CLEAR_HARD_REG_SET (m_reg_asm_output);
+ CLEAR_HARD_REG_SET (m_reg_asm_input);
+ CLEAR_HARD_REG_SET (m_clobbered);
+
+ /* If there are no alternatives, then there are no outputs/inputs and there
+ is nothing to do on our end. Thus, we are dealing most likely with a
+ basic asm. */
+ if (num_alternatives == 0)
+ return;
+
+ unsigned buf_size = num_alternatives * 3 + num_outputs;
+ m_buf = new HARD_REG_SET[buf_size];
+ for (unsigned i = 0; i < buf_size; ++i)
+ CLEAR_HARD_REG_SET (m_buf[i]);
+ m_alt_output = &m_buf[0];
+ m_alt_input = &m_buf[num_alternatives];
+ m_early_clobbered_alt = &m_buf[num_alternatives * 2];
+ if (num_outputs > 0)
+ m_early_clobbered_output = &m_buf[num_alternatives * 3];
+ else
+ m_early_clobbered_output = nullptr;
+ }
+
+ ~gimplify_reg_info ()
+ {
+ if (m_num_alternatives > 0)
+ delete[] m_buf;
+ }
+
+ void set_output (unsigned alt, int regno)
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ add_to_hard_reg_set (&m_alt_output[alt], mode, regno);
+ }
+
+ void set_input (unsigned alt, int regno)
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ add_to_hard_reg_set (&m_alt_input[alt], mode, regno);
+ }
+
+ int test_alt_output (unsigned alt, int regno) const
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ return test (m_alt_output[alt], regno);
+ }
+
+ int test_alt_input (unsigned alt, int regno) const
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ return test (m_alt_input[alt], regno);
+ }
+
+ void set_reg_asm_output (int regno)
+ {
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ add_to_hard_reg_set (&m_reg_asm_output, mode, regno);
+ }
+
+ int test_reg_asm_output (int regno) const
+ {
+ return test (m_reg_asm_output, regno);
+ }
+
+ void set_reg_asm_input (int regno)
+ {
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ add_to_hard_reg_set (&m_reg_asm_input, mode, regno);
+ }
+
+ int test_reg_asm_input (int regno) const
+ {
+ return test (m_reg_asm_input, regno);
+ }
+
+ void set_early_clobbered (unsigned alt, unsigned output, int regno)
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ gcc_checking_assert (output < m_num_outputs);
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ add_to_hard_reg_set (&m_early_clobbered_alt[alt], mode, regno);
+ add_to_hard_reg_set (&m_early_clobbered_output[output], mode, regno);
+ }
+
+ bool test_early_clobbered_alt (unsigned alt, int regno) const
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ return TEST_HARD_REG_BIT (m_early_clobbered_alt[alt], regno);
+ }
+
+ bool is_early_clobbered_in_any_output_unequal (unsigned operand,
+ int regno) const
+ {
+ gcc_checking_assert (operand < m_num_outputs);
+ for (unsigned op = 0; op < m_num_outputs; ++op)
+ if (op != operand
+ && TEST_HARD_REG_BIT (m_early_clobbered_output[op], regno))
+ return true;
+ return false;
+ }
+
+ void set_clobbered (int regno)
+ {
+ SET_HARD_REG_BIT (m_clobbered, regno);
+ }
+
+ bool is_clobbered (int regno) const
+ {
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ return overlaps_hard_reg_set_p (m_clobbered, mode, regno);
+ }
+};