diff options
Diffstat (limited to 'gcc/gimplify_reg_info.h')
-rw-r--r-- | gcc/gimplify_reg_info.h | 182 |
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 ®s, 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); + } +}; |