OLD | NEW |
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-inl.h" | 7 #include "src/compiler/node-properties-inl.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 26 matching lines...) Expand all Loading... |
37 return false; | 37 return false; |
38 } | 38 } |
39 } | 39 } |
40 | 40 |
41 bool CanBeBetterLeftOperand(Node* node) const { | 41 bool CanBeBetterLeftOperand(Node* node) const { |
42 return !selector()->IsLive(node); | 42 return !selector()->IsLive(node); |
43 } | 43 } |
44 }; | 44 }; |
45 | 45 |
46 | 46 |
| 47 class AddressingModeMatcher { |
| 48 public: |
| 49 AddressingModeMatcher(IA32OperandGenerator* g, Node* base, Node* index) |
| 50 : base_operand_(NULL), |
| 51 index_operand_(NULL), |
| 52 displacement_operand_(NULL), |
| 53 mode_(kMode_None) { |
| 54 Int32Matcher index_imm(index); |
| 55 if (index_imm.HasValue()) { |
| 56 int32_t displacement = index_imm.Value(); |
| 57 // Compute base operand and fold base immediate into displacement. |
| 58 Int32Matcher base_imm(base); |
| 59 if (!base_imm.HasValue()) { |
| 60 base_operand_ = g->UseRegister(base); |
| 61 } else { |
| 62 displacement += base_imm.Value(); |
| 63 } |
| 64 if (displacement != 0 || base_operand_ == NULL) { |
| 65 displacement_operand_ = g->TempImmediate(displacement); |
| 66 } |
| 67 if (base_operand_ == NULL) { |
| 68 mode_ = kMode_MI; |
| 69 } else { |
| 70 if (displacement == 0) { |
| 71 mode_ = kMode_MR; |
| 72 } else { |
| 73 mode_ = kMode_MRI; |
| 74 } |
| 75 } |
| 76 } else { |
| 77 // Compute index and displacement. |
| 78 IndexAndDisplacementMatcher matcher(index); |
| 79 index_operand_ = g->UseRegister(matcher.index_node()); |
| 80 int32_t displacement = matcher.displacement(); |
| 81 // Compute base operand and fold base immediate into displacement. |
| 82 Int32Matcher base_imm(base); |
| 83 if (!base_imm.HasValue()) { |
| 84 base_operand_ = g->UseRegister(base); |
| 85 } else { |
| 86 displacement += base_imm.Value(); |
| 87 } |
| 88 // Compute displacement operand. |
| 89 if (displacement != 0) { |
| 90 displacement_operand_ = g->TempImmediate(displacement); |
| 91 } |
| 92 // Compute mode with scale factor one. |
| 93 if (base_operand_ == NULL) { |
| 94 if (displacement_operand_ == NULL) { |
| 95 mode_ = kMode_M1; |
| 96 } else { |
| 97 mode_ = kMode_M1I; |
| 98 } |
| 99 } else { |
| 100 if (displacement_operand_ == NULL) { |
| 101 mode_ = kMode_MR1; |
| 102 } else { |
| 103 mode_ = kMode_MR1I; |
| 104 } |
| 105 } |
| 106 // Adjust mode to actual scale factor. |
| 107 mode_ = GetMode(mode_, matcher.power()); |
| 108 // Don't emit instructions with scale factor 1 if there's no base. |
| 109 if (mode_ == kMode_M1) { |
| 110 mode_ = kMode_MR; |
| 111 } else if (mode_ == kMode_M1I) { |
| 112 mode_ = kMode_MRI; |
| 113 } |
| 114 } |
| 115 DCHECK_NE(kMode_None, mode_); |
| 116 } |
| 117 |
| 118 AddressingMode GetMode(AddressingMode one, int power) { |
| 119 return static_cast<AddressingMode>(static_cast<int>(one) + power); |
| 120 } |
| 121 |
| 122 size_t SetInputs(InstructionOperand** inputs) { |
| 123 size_t input_count = 0; |
| 124 // Compute inputs_ and input_count. |
| 125 if (base_operand_ != NULL) { |
| 126 inputs[input_count++] = base_operand_; |
| 127 } |
| 128 if (index_operand_ != NULL) { |
| 129 inputs[input_count++] = index_operand_; |
| 130 } |
| 131 if (displacement_operand_ != NULL) { |
| 132 inputs[input_count++] = displacement_operand_; |
| 133 } |
| 134 DCHECK_NE(input_count, 0); |
| 135 return input_count; |
| 136 } |
| 137 |
| 138 static const int kMaxInputCount = 3; |
| 139 InstructionOperand* base_operand_; |
| 140 InstructionOperand* index_operand_; |
| 141 InstructionOperand* displacement_operand_; |
| 142 AddressingMode mode_; |
| 143 }; |
| 144 |
| 145 |
47 void InstructionSelector::VisitLoad(Node* node) { | 146 void InstructionSelector::VisitLoad(Node* node) { |
48 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); | 147 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); |
49 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); | 148 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); |
50 IA32OperandGenerator g(this); | |
51 Node* base = node->InputAt(0); | 149 Node* base = node->InputAt(0); |
52 Node* index = node->InputAt(1); | 150 Node* index = node->InputAt(1); |
53 | 151 |
54 ArchOpcode opcode; | 152 ArchOpcode opcode; |
55 // TODO(titzer): signed/unsigned small loads | 153 // TODO(titzer): signed/unsigned small loads |
56 switch (rep) { | 154 switch (rep) { |
57 case kRepFloat32: | 155 case kRepFloat32: |
58 opcode = kIA32Movss; | 156 opcode = kIA32Movss; |
59 break; | 157 break; |
60 case kRepFloat64: | 158 case kRepFloat64: |
61 opcode = kIA32Movsd; | 159 opcode = kIA32Movsd; |
62 break; | 160 break; |
63 case kRepBit: // Fall through. | 161 case kRepBit: // Fall through. |
64 case kRepWord8: | 162 case kRepWord8: |
65 opcode = typ == kTypeInt32 ? kIA32Movsxbl : kIA32Movzxbl; | 163 opcode = typ == kTypeInt32 ? kIA32Movsxbl : kIA32Movzxbl; |
66 break; | 164 break; |
67 case kRepWord16: | 165 case kRepWord16: |
68 opcode = typ == kTypeInt32 ? kIA32Movsxwl : kIA32Movzxwl; | 166 opcode = typ == kTypeInt32 ? kIA32Movsxwl : kIA32Movzxwl; |
69 break; | 167 break; |
70 case kRepTagged: // Fall through. | 168 case kRepTagged: // Fall through. |
71 case kRepWord32: | 169 case kRepWord32: |
72 opcode = kIA32Movl; | 170 opcode = kIA32Movl; |
73 break; | 171 break; |
74 default: | 172 default: |
75 UNREACHABLE(); | 173 UNREACHABLE(); |
76 return; | 174 return; |
77 } | 175 } |
78 if (g.CanBeImmediate(base)) { | 176 |
79 if (Int32Matcher(index).Is(0)) { // load [#base + #0] | 177 IA32OperandGenerator g(this); |
80 Emit(opcode | AddressingModeField::encode(kMode_MI), | 178 AddressingModeMatcher matcher(&g, base, index); |
81 g.DefineAsRegister(node), g.UseImmediate(base)); | 179 InstructionCode code = opcode | AddressingModeField::encode(matcher.mode_); |
82 } else { // load [#base + %index] | 180 InstructionOperand* outputs[] = {g.DefineAsRegister(node)}; |
83 Emit(opcode | AddressingModeField::encode(kMode_MRI), | 181 InstructionOperand* inputs[AddressingModeMatcher::kMaxInputCount]; |
84 g.DefineAsRegister(node), g.UseRegister(index), | 182 size_t input_count = matcher.SetInputs(inputs); |
85 g.UseImmediate(base)); | 183 Emit(code, 1, outputs, input_count, inputs); |
86 } | |
87 } else if (g.CanBeImmediate(index)) { // load [%base + #index] | |
88 Emit(opcode | AddressingModeField::encode(kMode_MRI), | |
89 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); | |
90 } else { // load [%base + %index + K] | |
91 Emit(opcode | AddressingModeField::encode(kMode_MR1I), | |
92 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index)); | |
93 } | |
94 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] | |
95 } | 184 } |
96 | 185 |
97 | 186 |
98 void InstructionSelector::VisitStore(Node* node) { | 187 void InstructionSelector::VisitStore(Node* node) { |
99 IA32OperandGenerator g(this); | 188 IA32OperandGenerator g(this); |
100 Node* base = node->InputAt(0); | 189 Node* base = node->InputAt(0); |
101 Node* index = node->InputAt(1); | 190 Node* index = node->InputAt(1); |
102 Node* value = node->InputAt(2); | 191 Node* value = node->InputAt(2); |
103 | 192 |
104 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); | 193 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); |
105 MachineType rep = RepresentationOf(store_rep.machine_type()); | 194 MachineType rep = RepresentationOf(store_rep.machine_type()); |
106 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { | 195 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { |
107 DCHECK_EQ(kRepTagged, rep); | 196 DCHECK_EQ(kRepTagged, rep); |
108 // TODO(dcarney): refactor RecordWrite function to take temp registers | 197 // TODO(dcarney): refactor RecordWrite function to take temp registers |
109 // and pass them here instead of using fixed regs | 198 // and pass them here instead of using fixed regs |
110 // TODO(dcarney): handle immediate indices. | 199 // TODO(dcarney): handle immediate indices. |
111 InstructionOperand* temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; | 200 InstructionOperand* temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; |
112 Emit(kIA32StoreWriteBarrier, NULL, g.UseFixed(base, ebx), | 201 Emit(kIA32StoreWriteBarrier, NULL, g.UseFixed(base, ebx), |
113 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), | 202 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), |
114 temps); | 203 temps); |
115 return; | 204 return; |
116 } | 205 } |
117 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); | 206 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); |
118 InstructionOperand* val; | 207 |
119 if (g.CanBeImmediate(value)) { | |
120 val = g.UseImmediate(value); | |
121 } else if (rep == kRepWord8 || rep == kRepBit) { | |
122 val = g.UseByteRegister(value); | |
123 } else { | |
124 val = g.UseRegister(value); | |
125 } | |
126 ArchOpcode opcode; | 208 ArchOpcode opcode; |
127 switch (rep) { | 209 switch (rep) { |
128 case kRepFloat32: | 210 case kRepFloat32: |
129 opcode = kIA32Movss; | 211 opcode = kIA32Movss; |
130 break; | 212 break; |
131 case kRepFloat64: | 213 case kRepFloat64: |
132 opcode = kIA32Movsd; | 214 opcode = kIA32Movsd; |
133 break; | 215 break; |
134 case kRepBit: // Fall through. | 216 case kRepBit: // Fall through. |
135 case kRepWord8: | 217 case kRepWord8: |
136 opcode = kIA32Movb; | 218 opcode = kIA32Movb; |
137 break; | 219 break; |
138 case kRepWord16: | 220 case kRepWord16: |
139 opcode = kIA32Movw; | 221 opcode = kIA32Movw; |
140 break; | 222 break; |
141 case kRepTagged: // Fall through. | 223 case kRepTagged: // Fall through. |
142 case kRepWord32: | 224 case kRepWord32: |
143 opcode = kIA32Movl; | 225 opcode = kIA32Movl; |
144 break; | 226 break; |
145 default: | 227 default: |
146 UNREACHABLE(); | 228 UNREACHABLE(); |
147 return; | 229 return; |
148 } | 230 } |
149 if (g.CanBeImmediate(base)) { | 231 |
150 if (Int32Matcher(index).Is(0)) { // store [#base], %|#value | 232 InstructionOperand* val; |
151 Emit(opcode | AddressingModeField::encode(kMode_MI), NULL, | 233 if (g.CanBeImmediate(value)) { |
152 g.UseImmediate(base), val); | 234 val = g.UseImmediate(value); |
153 } else { // store [#base + %index], %|#value | 235 } else if (rep == kRepWord8 || rep == kRepBit) { |
154 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, | 236 val = g.UseByteRegister(value); |
155 g.UseRegister(index), g.UseImmediate(base), val); | 237 } else { |
156 } | 238 val = g.UseRegister(value); |
157 } else if (g.CanBeImmediate(index)) { // store [%base + #index], %|#value | |
158 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, | |
159 g.UseRegister(base), g.UseImmediate(index), val); | |
160 } else { // store [%base + %index], %|#value | |
161 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL, | |
162 g.UseRegister(base), g.UseRegister(index), val); | |
163 } | 239 } |
164 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] | 240 |
| 241 AddressingModeMatcher matcher(&g, base, index); |
| 242 InstructionCode code = opcode | AddressingModeField::encode(matcher.mode_); |
| 243 InstructionOperand* inputs[AddressingModeMatcher::kMaxInputCount + 1]; |
| 244 size_t input_count = matcher.SetInputs(inputs); |
| 245 inputs[input_count++] = val; |
| 246 Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs); |
165 } | 247 } |
166 | 248 |
167 | 249 |
168 // Shared routine for multiple binary operations. | 250 // Shared routine for multiple binary operations. |
169 static void VisitBinop(InstructionSelector* selector, Node* node, | 251 static void VisitBinop(InstructionSelector* selector, Node* node, |
170 InstructionCode opcode, FlagsContinuation* cont) { | 252 InstructionCode opcode, FlagsContinuation* cont) { |
171 IA32OperandGenerator g(selector); | 253 IA32OperandGenerator g(selector); |
172 Int32BinopMatcher m(node); | 254 Int32BinopMatcher m(node); |
173 Node* left = m.left().node(); | 255 Node* left = m.left().node(); |
174 Node* right = m.right().node(); | 256 Node* right = m.right().node(); |
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
576 call_instr->MarkAsCall(); | 658 call_instr->MarkAsCall(); |
577 if (deoptimization != NULL) { | 659 if (deoptimization != NULL) { |
578 DCHECK(continuation != NULL); | 660 DCHECK(continuation != NULL); |
579 call_instr->MarkAsControl(); | 661 call_instr->MarkAsControl(); |
580 } | 662 } |
581 } | 663 } |
582 | 664 |
583 } // namespace compiler | 665 } // namespace compiler |
584 } // namespace internal | 666 } // namespace internal |
585 } // namespace v8 | 667 } // namespace v8 |
OLD | NEW |