jdk

Форк
0
/
peephole_x86_64.cpp 
249 строк · 9.6 Кб
1
/*
2
 * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
 *
5
 * This code is free software; you can redistribute it and/or modify it
6
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.
8
 *
9
 * This code is distributed in the hope that it will be useful, but WITHOUT
10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 * version 2 for more details (a copy is included in the LICENSE file that
13
 * accompanied this code).
14
 *
15
 * You should have received a copy of the GNU General Public License version
16
 * 2 along with this work; if not, write to the Free Software Foundation,
17
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
 *
19
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
 * or visit www.oracle.com if you need additional information or have any
21
 * questions.
22
 *
23
 */
24
#include "precompiled.hpp"
25

26
#ifdef COMPILER2
27

28
#include "peephole_x86_64.hpp"
29
#include "adfiles/ad_x86.hpp"
30

31
// This function transforms the shapes
32
// mov d, s1; add d, s2 into
33
// lea d, [s1 + s2]     and
34
// mov d, s1; shl d, s2 into
35
// lea d, [s1 << s2]    with s2 = 1, 2, 3
36
static bool lea_coalesce_helper(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_,
37
                                MachNode* (*new_root)(), uint inst0_rule, bool imm) {
38
  MachNode* inst0 = block->get_node(block_index)->as_Mach();
39
  assert(inst0->rule() == inst0_rule, "sanity");
40

41
  OptoReg::Name dst = ra_->get_reg_first(inst0);
42
  MachNode* inst1 = nullptr;
43
  OptoReg::Name src1 = OptoReg::Bad;
44

45
  if (inst0->in(1)->is_MachSpillCopy()) {
46
    OptoReg::Name in = ra_->get_reg_first(inst0->in(1)->in(1));
47
    if (OptoReg::is_reg(in) && OptoReg::as_VMReg(in)->is_Register()) {
48
      inst1 = inst0->in(1)->as_Mach();
49
      src1 = in;
50
    }
51
  }
52
  if (inst1 == nullptr) {
53
    return false;
54
  }
55
  assert(dst != src1, "");
56

57
  // Only coalesce if inst1 is immediately followed by inst0
58
  // Can be improved for more general cases
59
  if (block_index < 1 || block->get_node(block_index - 1) != inst1) {
60
    return false;
61
  }
62
  int inst1_index = block_index - 1;
63
  Node* inst2;
64
  if (imm) {
65
    inst2 = nullptr;
66
  } else {
67
    inst2 = inst0->in(2);
68
    if (inst2 == inst1) {
69
      inst2 = inst2->in(1);
70
    }
71
  }
72

73
  // See VM_Version::supports_fast_3op_lea()
74
  if (!imm) {
75
    Register rsrc1 = OptoReg::as_VMReg(src1)->as_Register();
76
    Register rsrc2 = OptoReg::as_VMReg(ra_->get_reg_first(inst2))->as_Register();
77
    if ((rsrc1 == rbp || rsrc1 == r13) && (rsrc2 == rbp || rsrc2 == r13)) {
78
      return false;
79
    }
80
  }
81

82
  // Go down the block to find the output proj node (the flag output) of inst0
83
  int proj_index = -1;
84
  Node* proj = nullptr;
85
  for (uint pos = block_index + 1; pos < block->number_of_nodes(); pos++) {
86
    Node* curr = block->get_node(pos);
87
    if (curr->is_MachProj() && curr->in(0) == inst0) {
88
      proj_index = pos;
89
      proj = curr;
90
      break;
91
    }
92
  }
93
  assert(proj != nullptr, "");
94
  // If some node uses the flag, cannot remove
95
  if (proj->outcnt() > 0) {
96
    return false;
97
  }
98

99
  MachNode* root = new_root();
100
  // Assign register for the newly allocated node
101
  ra_->set_oop(root, ra_->is_oop(inst0));
102
  ra_->set_pair(root->_idx, ra_->get_reg_second(inst0), ra_->get_reg_first(inst0));
103

104
  // Set input and output for the node
105
  root->add_req(inst0->in(0));
106
  root->add_req(inst1->in(1));
107
  // No input for constant after matching
108
  if (!imm) {
109
    root->add_req(inst2);
110
  }
111
  inst0->replace_by(root);
112
  proj->set_req(0, inst0);
113

114
  // Initialize the operand array
115
  root->_opnds[0] = inst0->_opnds[0]->clone();
116
  root->_opnds[1] = inst0->_opnds[1]->clone();
117
  root->_opnds[2] = inst0->_opnds[2]->clone();
118

119
  // Modify the block
120
  inst0->set_removed();
121
  inst1->set_removed();
122
  block->remove_node(proj_index);
123
  block->remove_node(block_index);
124
  block->remove_node(inst1_index);
125
  block->insert_node(root, block_index - 1);
126

127
  // Modify the CFG
128
  cfg_->map_node_to_block(inst0, nullptr);
129
  cfg_->map_node_to_block(inst1, nullptr);
130
  cfg_->map_node_to_block(proj, nullptr);
131
  cfg_->map_node_to_block(root, block);
132

133
  return true;
134
}
135

136
// This helper func takes a condition and returns the flags that need to be set for the condition
137
// It uses the same flags as the test instruction, so if the e.g. the overflow bit is required,
138
// this func returns clears_overflow, as that is what the test instruction does and what the downstream path expects
139
static juint map_condition_to_required_test_flags(Assembler::Condition condition) {
140
  switch (condition) {
141
    case Assembler::Condition::zero: // Same value as equal
142
    case Assembler::Condition::notZero: // Same value as notEqual
143
      return Node::PD::Flag_sets_zero_flag;
144
    case Assembler::Condition::less:
145
    case Assembler::Condition::greaterEqual:
146
      return Node::PD::Flag_sets_sign_flag | Node::PD::Flag_clears_overflow_flag;
147
    case Assembler::Condition::lessEqual:
148
    case Assembler::Condition::greater:
149
      return Node::PD::Flag_sets_sign_flag | Node::PD::Flag_clears_overflow_flag | Node::PD::Flag_sets_zero_flag;
150
    case Assembler::Condition::below: // Same value as carrySet
151
    case Assembler::Condition::aboveEqual: // Same value as carryClear
152
      return Node::PD::Flag_clears_carry_flag;
153
    case Assembler::Condition::belowEqual:
154
    case Assembler::Condition::above:
155
      return Node::PD::Flag_clears_carry_flag | Node::PD::Flag_sets_zero_flag;
156
    case Assembler::Condition::overflow:
157
    case Assembler::Condition::noOverflow:
158
      return Node::PD::Flag_clears_overflow_flag;
159
    case Assembler::Condition::negative:
160
    case Assembler::Condition::positive:
161
      return Node::PD::Flag_sets_sign_flag;
162
    case Assembler::Condition::parity:
163
    case Assembler::Condition::noParity:
164
      return Node::PD::Flag_sets_parity_flag;
165
    default:
166
      ShouldNotReachHere();
167
      return 0;
168
  }
169
}
170

171

172
// This function removes the TEST instruction when it detected shapes likes AND r1, r2; TEST r1, r1
173
// It checks the required EFLAGS for the downstream instructions of the TEST
174
// and removes the TEST if the preceding instructions already sets all these flags
175
bool Peephole::test_may_remove(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_,
176
                            MachNode* (*new_root)(), uint inst0_rule) {
177
  MachNode* test_to_check = block->get_node(block_index)->as_Mach();
178
  assert(test_to_check->rule() == inst0_rule, "sanity");
179

180
  Node* inst1 = test_to_check->in(1);
181
  // Only remove test if the block order is inst1 -> MachProjNode (because the node to match must specify KILL cr) -> test_to_check
182
  // So inst1 must be at index - 2
183
  if (block_index < 2 || block->get_node(block_index - 2) != inst1) {
184
    return false;
185
  }
186
  if (inst1 != nullptr) {
187
    MachNode* prevNode = inst1->isa_Mach();
188
    if (prevNode != nullptr) {
189
      // Includes other flags as well, but that doesn't matter here
190
      juint all_node_flags = prevNode->flags();
191
      if (all_node_flags == 0) {
192
        // We can return early - there is no way the test can be removed, the preceding node does not set any flags
193
        return false;
194
      }
195
      juint required_flags = 0;
196
      // Search for the uses of the node and compute which flags are required
197
      for (DUIterator_Fast imax, i = test_to_check->fast_outs(imax); i < imax; i++) {
198
        MachNode* node_out = test_to_check->fast_out(i)->isa_Mach();
199
        bool found_correct_oper = false;
200
        for (uint16_t j = 0; j < node_out->_num_opnds; ++j) {
201
          MachOper* operand = node_out->_opnds[j];
202
          if (operand->opcode() == cmpOp_rule || operand->opcode() == cmpOpU_rule) {
203
            auto condition = static_cast<Assembler::Condition>(operand->ccode());
204
            juint flags_for_inst = map_condition_to_required_test_flags(condition);
205
            required_flags = required_flags | flags_for_inst;
206
            found_correct_oper = true;
207
            break;
208
          }
209
        }
210
        if (!found_correct_oper) {
211
          // We could not find one the required flags for one of the dependencies. Keep the test as it might set flags needed for that node
212
          return false;
213
        }
214
      }
215
      assert(required_flags != 0, "No flags required, should be impossible!");
216
      bool sets_all_required_flags = (required_flags & ~all_node_flags) == 0;
217
      if (sets_all_required_flags) {
218
        // All flags are covered are clear to remove this test
219
        MachProjNode* machProjNode = block->get_node(block_index - 1)->isa_MachProj();
220
        assert(machProjNode != nullptr, "Expected a MachProj node here!");
221
        assert(ra_->get_reg_first(machProjNode) == ra_->get_reg_first(test_to_check), "Test must operate on the same register as its replacement");
222

223
        // Remove the original test node and replace it with the pseudo test node. The AND node already sets ZF
224
        test_to_check->replace_by(machProjNode);
225

226
        // Modify the block
227
        test_to_check->set_removed();
228
        block->remove_node(block_index);
229

230
        // Modify the control flow
231
        cfg_->map_node_to_block(test_to_check, nullptr);
232
        return true;
233
      }
234
    }
235
  }
236
  return false;
237
}
238

239
bool Peephole::lea_coalesce_reg(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_,
240
                                MachNode* (*new_root)(), uint inst0_rule) {
241
  return lea_coalesce_helper(block, block_index, cfg_, ra_, new_root, inst0_rule, false);
242
}
243

244
bool Peephole::lea_coalesce_imm(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_,
245
                                MachNode* (*new_root)(), uint inst0_rule) {
246
  return lea_coalesce_helper(block, block_index, cfg_, ra_, new_root, inst0_rule, true);
247
}
248

249
#endif // COMPILER2
250

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.