Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: src/compiler/arm64/instruction-selector-arm64.cc

Issue 1218103005: [turbofan] Support cmp with shift/extend on ARM64. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/instruction-selector-impl.h" 5 #include "src/compiler/instruction-selector-impl.h"
6 #include "src/compiler/node-matchers.h" 6 #include "src/compiler/node-matchers.h"
7 #include "src/compiler/node-properties.h" 7 #include "src/compiler/node-properties.h"
8 8
9 namespace v8 { 9 namespace v8 {
10 namespace internal { 10 namespace internal {
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 void VisitRRO(InstructionSelector* selector, ArchOpcode opcode, Node* node, 125 void VisitRRO(InstructionSelector* selector, ArchOpcode opcode, Node* node,
126 ImmediateMode operand_mode) { 126 ImmediateMode operand_mode) {
127 Arm64OperandGenerator g(selector); 127 Arm64OperandGenerator g(selector);
128 selector->Emit(opcode, g.DefineAsRegister(node), 128 selector->Emit(opcode, g.DefineAsRegister(node),
129 g.UseRegister(node->InputAt(0)), 129 g.UseRegister(node->InputAt(0)),
130 g.UseOperand(node->InputAt(1), operand_mode)); 130 g.UseOperand(node->InputAt(1), operand_mode));
131 } 131 }
132 132
133 133
134 bool TryMatchAnyShift(InstructionSelector* selector, Node* node, 134 bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
135 InstructionCode* opcode, bool try_ror) { 135 Node* input_node, InstructionCode* opcode, bool try_ror) {
136 Arm64OperandGenerator g(selector); 136 Arm64OperandGenerator g(selector);
137 137
138 if (node->InputCount() != 2) return false; 138 if (!selector->CanCover(node, input_node)) return false;
139 if (!g.IsIntegerConstant(node->InputAt(1))) return false; 139 if (input_node->InputCount() != 2) return false;
140 if (!g.IsIntegerConstant(input_node->InputAt(1))) return false;
140 141
141 switch (node->opcode()) { 142 switch (input_node->opcode()) {
142 case IrOpcode::kWord32Shl: 143 case IrOpcode::kWord32Shl:
143 case IrOpcode::kWord64Shl: 144 case IrOpcode::kWord64Shl:
144 *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I); 145 *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I);
145 return true; 146 return true;
146 case IrOpcode::kWord32Shr: 147 case IrOpcode::kWord32Shr:
147 case IrOpcode::kWord64Shr: 148 case IrOpcode::kWord64Shr:
148 *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_I); 149 *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_I);
149 return true; 150 return true;
150 case IrOpcode::kWord32Sar: 151 case IrOpcode::kWord32Sar:
151 case IrOpcode::kWord64Sar: 152 case IrOpcode::kWord64Sar:
152 *opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_I); 153 *opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_I);
153 return true; 154 return true;
154 case IrOpcode::kWord32Ror: 155 case IrOpcode::kWord32Ror:
155 case IrOpcode::kWord64Ror: 156 case IrOpcode::kWord64Ror:
156 if (try_ror) { 157 if (try_ror) {
157 *opcode |= AddressingModeField::encode(kMode_Operand2_R_ROR_I); 158 *opcode |= AddressingModeField::encode(kMode_Operand2_R_ROR_I);
158 return true; 159 return true;
159 } 160 }
160 return false; 161 return false;
161 default: 162 default:
162 return false; 163 return false;
163 } 164 }
164 } 165 }
165 166
166 167
167 bool TryMatchAnyExtend(Arm64OperandGenerator* g, InstructionSelector* selector, 168 bool TryMatchAnyExtend(Arm64OperandGenerator* g, InstructionSelector* selector,
168 Node* left_node, Node* right_node, 169 Node* node, Node* left_node, Node* right_node,
169 InstructionOperand* left_op, 170 InstructionOperand* left_op,
170 InstructionOperand* right_op, InstructionCode* opcode) { 171 InstructionOperand* right_op, InstructionCode* opcode) {
172 if (!selector->CanCover(node, right_node)) return false;
173
171 NodeMatcher nm(right_node); 174 NodeMatcher nm(right_node);
172 175
173 if (nm.IsWord32And()) { 176 if (nm.IsWord32And()) {
174 Int32BinopMatcher mright(right_node); 177 Int32BinopMatcher mright(right_node);
175 if (mright.right().Is(0xff) || mright.right().Is(0xffff)) { 178 if (mright.right().Is(0xff) || mright.right().Is(0xffff)) {
176 int32_t mask = mright.right().Value(); 179 int32_t mask = mright.right().Value();
177 *left_op = g->UseRegister(left_node); 180 *left_op = g->UseRegister(left_node);
178 *right_op = g->UseRegister(mright.left().node()); 181 *right_op = g->UseRegister(mright.left().node());
179 *opcode |= AddressingModeField::encode( 182 *opcode |= AddressingModeField::encode(
180 (mask == 0xff) ? kMode_Operand2_R_UXTB : kMode_Operand2_R_UXTH); 183 (mask == 0xff) ? kMode_Operand2_R_UXTB : kMode_Operand2_R_UXTH);
(...skipping 19 matching lines...) Expand all
200 } 203 }
201 204
202 205
203 // Shared routine for multiple binary operations. 206 // Shared routine for multiple binary operations.
204 template <typename Matcher> 207 template <typename Matcher>
205 void VisitBinop(InstructionSelector* selector, Node* node, 208 void VisitBinop(InstructionSelector* selector, Node* node,
206 InstructionCode opcode, ImmediateMode operand_mode, 209 InstructionCode opcode, ImmediateMode operand_mode,
207 FlagsContinuation* cont) { 210 FlagsContinuation* cont) {
208 Arm64OperandGenerator g(selector); 211 Arm64OperandGenerator g(selector);
209 Matcher m(node); 212 Matcher m(node);
210 InstructionOperand inputs[4]; 213 InstructionOperand inputs[5];
211 size_t input_count = 0; 214 size_t input_count = 0;
212 InstructionOperand outputs[2]; 215 InstructionOperand outputs[2];
213 size_t output_count = 0; 216 size_t output_count = 0;
214 bool is_add_sub = false; 217 bool is_cmp = opcode == kArm64Cmp32;
215 218
216 if (m.IsInt32Add() || m.IsInt64Add() || m.IsInt32Sub() || m.IsInt64Sub()) { 219 // We can commute cmp by switching the inputs and commuting the flags
217 is_add_sub = true; 220 // continuation.
218 } 221 bool can_commute = m.HasProperty(Operator::kCommutative) || is_cmp;
222
223 // The cmp instruction is encoded as sub with zero output register, and
224 // therefore supports the same operand modes.
225 bool is_add_sub = m.IsInt32Add() || m.IsInt64Add() || m.IsInt32Sub() ||
226 m.IsInt64Sub() || is_cmp;
219 227
220 Node* left_node = m.left().node(); 228 Node* left_node = m.left().node();
221 Node* right_node = m.right().node(); 229 Node* right_node = m.right().node();
222 230
223 if (g.CanBeImmediate(right_node, operand_mode)) { 231 if (g.CanBeImmediate(right_node, operand_mode)) {
224 inputs[input_count++] = g.UseRegister(left_node); 232 inputs[input_count++] = g.UseRegister(left_node);
225 inputs[input_count++] = g.UseImmediate(right_node); 233 inputs[input_count++] = g.UseImmediate(right_node);
234 } else if (is_cmp && g.CanBeImmediate(left_node, operand_mode)) {
235 cont->Commute();
236 inputs[input_count++] = g.UseRegister(right_node);
237 inputs[input_count++] = g.UseImmediate(left_node);
226 } else if (is_add_sub && 238 } else if (is_add_sub &&
227 TryMatchAnyExtend(&g, selector, left_node, right_node, &inputs[0], 239 TryMatchAnyExtend(&g, selector, node, left_node, right_node,
228 &inputs[1], &opcode)) { 240 &inputs[0], &inputs[1], &opcode)) {
229 input_count += 2; 241 input_count += 2;
230 } else if (is_add_sub && m.HasProperty(Operator::kCommutative) && 242 } else if (is_add_sub && can_commute &&
231 TryMatchAnyExtend(&g, selector, right_node, left_node, &inputs[0], 243 TryMatchAnyExtend(&g, selector, node, right_node, left_node,
232 &inputs[1], &opcode)) { 244 &inputs[0], &inputs[1], &opcode)) {
245 if (is_cmp) cont->Commute();
233 input_count += 2; 246 input_count += 2;
234 } else if (TryMatchAnyShift(selector, right_node, &opcode, !is_add_sub)) { 247 } else if (TryMatchAnyShift(selector, node, right_node, &opcode,
248 !is_add_sub)) {
235 Matcher m_shift(right_node); 249 Matcher m_shift(right_node);
236 inputs[input_count++] = g.UseRegister(left_node); 250 inputs[input_count++] = g.UseRegister(left_node);
237 inputs[input_count++] = g.UseRegister(m_shift.left().node()); 251 inputs[input_count++] = g.UseRegister(m_shift.left().node());
238 inputs[input_count++] = g.UseImmediate(m_shift.right().node()); 252 inputs[input_count++] = g.UseImmediate(m_shift.right().node());
239 } else if (m.HasProperty(Operator::kCommutative) && 253 } else if (can_commute && TryMatchAnyShift(selector, node, left_node, &opcode,
240 TryMatchAnyShift(selector, left_node, &opcode, !is_add_sub)) { 254 !is_add_sub)) {
255 if (is_cmp) cont->Commute();
241 Matcher m_shift(left_node); 256 Matcher m_shift(left_node);
242 inputs[input_count++] = g.UseRegister(right_node); 257 inputs[input_count++] = g.UseRegister(right_node);
243 inputs[input_count++] = g.UseRegister(m_shift.left().node()); 258 inputs[input_count++] = g.UseRegister(m_shift.left().node());
244 inputs[input_count++] = g.UseImmediate(m_shift.right().node()); 259 inputs[input_count++] = g.UseImmediate(m_shift.right().node());
245 } else { 260 } else {
246 inputs[input_count++] = g.UseRegister(left_node); 261 inputs[input_count++] = g.UseRegister(left_node);
247 inputs[input_count++] = g.UseRegister(right_node); 262 inputs[input_count++] = g.UseRegister(right_node);
248 } 263 }
249 264
250 if (cont->IsBranch()) { 265 if (cont->IsBranch()) {
251 inputs[input_count++] = g.Label(cont->true_block()); 266 inputs[input_count++] = g.Label(cont->true_block());
252 inputs[input_count++] = g.Label(cont->false_block()); 267 inputs[input_count++] = g.Label(cont->false_block());
253 } 268 }
254 269
255 outputs[output_count++] = g.DefineAsRegister(node); 270 if (!is_cmp) {
271 outputs[output_count++] = g.DefineAsRegister(node);
272 }
273
256 if (cont->IsSet()) { 274 if (cont->IsSet()) {
257 outputs[output_count++] = g.DefineAsRegister(cont->result()); 275 outputs[output_count++] = g.DefineAsRegister(cont->result());
258 } 276 }
259 277
260 DCHECK_NE(0u, input_count); 278 DCHECK_NE(0u, input_count);
261 DCHECK_NE(0u, output_count); 279 DCHECK((output_count != 0) || is_cmp);
262 DCHECK_GE(arraysize(inputs), input_count); 280 DCHECK_GE(arraysize(inputs), input_count);
263 DCHECK_GE(arraysize(outputs), output_count); 281 DCHECK_GE(arraysize(outputs), output_count);
264 282
265 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, 283 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
266 inputs); 284 inputs);
267 } 285 }
268 286
269 287
270 // Shared routine for multiple binary operations. 288 // Shared routine for multiple binary operations.
271 template <typename Matcher> 289 template <typename Matcher>
(...skipping 1318 matching lines...) Expand 10 before | Expand all | Expand 10 after
1590 cont); 1608 cont);
1591 } else { 1609 } else {
1592 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), 1610 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
1593 cont); 1611 cont);
1594 } 1612 }
1595 } 1613 }
1596 1614
1597 1615
1598 void VisitWord32Compare(InstructionSelector* selector, Node* node, 1616 void VisitWord32Compare(InstructionSelector* selector, Node* node,
1599 FlagsContinuation* cont) { 1617 FlagsContinuation* cont) {
1600 VisitWordCompare(selector, node, kArm64Cmp32, cont, false, kArithmeticImm); 1618 VisitBinop<Int32BinopMatcher>(selector, node, kArm64Cmp32, kArithmeticImm,
1619 cont);
1601 } 1620 }
1602 1621
1603 1622
1604 void VisitWordTest(InstructionSelector* selector, Node* node, 1623 void VisitWordTest(InstructionSelector* selector, Node* node,
1605 InstructionCode opcode, FlagsContinuation* cont) { 1624 InstructionCode opcode, FlagsContinuation* cont) {
1606 Arm64OperandGenerator g(selector); 1625 Arm64OperandGenerator g(selector);
1607 VisitCompare(selector, opcode, g.UseRegister(node), g.UseRegister(node), 1626 VisitCompare(selector, opcode, g.UseRegister(node), g.UseRegister(node),
1608 cont); 1627 cont);
1609 } 1628 }
1610 1629
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
1749 default: 1768 default:
1750 break; 1769 break;
1751 } 1770 }
1752 } 1771 }
1753 } 1772 }
1754 break; 1773 break;
1755 case IrOpcode::kInt32Add: 1774 case IrOpcode::kInt32Add:
1756 return VisitWordCompare(this, value, kArm64Cmn32, &cont, true, 1775 return VisitWordCompare(this, value, kArm64Cmn32, &cont, true,
1757 kArithmeticImm); 1776 kArithmeticImm);
1758 case IrOpcode::kInt32Sub: 1777 case IrOpcode::kInt32Sub:
1759 return VisitWordCompare(this, value, kArm64Cmp32, &cont, false, 1778 return VisitWord32Compare(this, value, &cont);
1760 kArithmeticImm);
1761 case IrOpcode::kWord32And: { 1779 case IrOpcode::kWord32And: {
1762 Int32BinopMatcher m(value); 1780 Int32BinopMatcher m(value);
1763 if (m.right().HasValue() && 1781 if (m.right().HasValue() &&
1764 (base::bits::CountPopulation32(m.right().Value()) == 1)) { 1782 (base::bits::CountPopulation32(m.right().Value()) == 1)) {
1765 // If the mask has only one bit set, we can use tbz/tbnz. 1783 // If the mask has only one bit set, we can use tbz/tbnz.
1766 DCHECK((cont.condition() == kEqual) || 1784 DCHECK((cont.condition() == kEqual) ||
1767 (cont.condition() == kNotEqual)); 1785 (cont.condition() == kNotEqual));
1768 Emit(cont.Encode(kArm64TestAndBranch32), g.NoOutput(), 1786 Emit(cont.Encode(kArm64TestAndBranch32), g.NoOutput(),
1769 g.UseRegister(m.left().node()), 1787 g.UseRegister(m.left().node()),
1770 g.TempImmediate( 1788 g.TempImmediate(
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after
2036 MachineOperatorBuilder::kFloat64RoundTruncate | 2054 MachineOperatorBuilder::kFloat64RoundTruncate |
2037 MachineOperatorBuilder::kFloat64RoundTiesAway | 2055 MachineOperatorBuilder::kFloat64RoundTiesAway |
2038 MachineOperatorBuilder::kWord32ShiftIsSafe | 2056 MachineOperatorBuilder::kWord32ShiftIsSafe |
2039 MachineOperatorBuilder::kInt32DivIsSafe | 2057 MachineOperatorBuilder::kInt32DivIsSafe |
2040 MachineOperatorBuilder::kUint32DivIsSafe; 2058 MachineOperatorBuilder::kUint32DivIsSafe;
2041 } 2059 }
2042 2060
2043 } // namespace compiler 2061 } // namespace compiler
2044 } // namespace internal 2062 } // namespace internal
2045 } // namespace v8 2063 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/arm64/code-generator-arm64.cc ('k') | test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698