| /* 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); |
| } |
| }; |