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

Side by Side Diff: runtime/vm/intermediate_language_x64.cc

Issue 10536145: Fuse comparisons that are used by branches together. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: address review comments Created 8 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « runtime/vm/intermediate_language_ia32.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64.
6 #if defined(TARGET_ARCH_X64) 6 #if defined(TARGET_ARCH_X64)
7 7
8 #include "vm/intermediate_language.h" 8 #include "vm/intermediate_language.h"
9 9
10 #include "lib/error.h" 10 #include "lib/error.h"
11 #include "vm/flow_graph_compiler.h" 11 #include "vm/flow_graph_compiler.h"
12 #include "vm/locations.h" 12 #include "vm/locations.h"
13 #include "vm/object_store.h" 13 #include "vm/object_store.h"
14 #include "vm/parser.h" 14 #include "vm/parser.h"
15 #include "vm/stub_code.h" 15 #include "vm/stub_code.h"
16 16
17 #define __ compiler->assembler()-> 17 #define __ compiler->assembler()->
18 18
19 namespace dart { 19 namespace dart {
20 20
21 DECLARE_FLAG(int, optimization_counter_threshold); 21 DECLARE_FLAG(int, optimization_counter_threshold);
22 DECLARE_FLAG(bool, trace_functions); 22 DECLARE_FLAG(bool, trace_functions);
23 23
24 void BindInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 24 void BindInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
25 computation()->EmitNativeCode(compiler); 25 computation()->EmitNativeCode(compiler);
26 __ pushq(locs()->out().reg()); 26 if (locs()->out().kind() == Location::kRegister) {
27 // TODO(vegorov): this should really happen only for comparisons fused
28 // with branches. Currrently IR does not provide an easy way to remove
29 // instructions from the graph so we just leave fused comparison in it
30 // but change its result location to be NoLocation.
31 __ pushq(locs()->out().reg());
32 }
27 } 33 }
28 34
29 35
30 LocationSummary* ReturnInstr::MakeLocationSummary() const { 36 LocationSummary* ReturnInstr::MakeLocationSummary() const {
31 const intptr_t kNumInputs = 1; 37 const intptr_t kNumInputs = 1;
32 const intptr_t kNumTemps = 1; 38 const intptr_t kNumTemps = 1;
33 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); 39 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps);
34 locs->set_in(0, Location::RegisterLocation(RAX)); 40 locs->set_in(0, Location::RegisterLocation(RAX));
35 locs->set_temp(0, Location::RequiresRegister()); 41 locs->set_temp(0, Location::RequiresRegister());
36 return locs; 42 return locs;
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 } 171 }
166 172
167 173
168 void AssertBooleanComp::EmitNativeCode(FlowGraphCompiler* compiler) { 174 void AssertBooleanComp::EmitNativeCode(FlowGraphCompiler* compiler) {
169 Register obj = locs()->in(0).reg(); 175 Register obj = locs()->in(0).reg();
170 Register result = locs()->out().reg(); 176 Register result = locs()->out().reg();
171 177
172 // Check that the type of the value is allowed in conditional context. 178 // Check that the type of the value is allowed in conditional context.
173 // Call the runtime if the object is not bool::true or bool::false. 179 // Call the runtime if the object is not bool::true or bool::false.
174 Label done; 180 Label done;
175 __ CompareObject(obj, Bool::ZoneHandle(Bool::True())); 181 __ CompareObject(obj, compiler->bool_true());
176 __ j(EQUAL, &done, Assembler::kNearJump); 182 __ j(EQUAL, &done, Assembler::kNearJump);
177 __ CompareObject(obj, Bool::ZoneHandle(Bool::False())); 183 __ CompareObject(obj, compiler->bool_false());
178 __ j(EQUAL, &done, Assembler::kNearJump); 184 __ j(EQUAL, &done, Assembler::kNearJump);
179 185
180 __ pushq(Immediate(Smi::RawValue(token_index()))); // Source location. 186 __ pushq(Immediate(Smi::RawValue(token_index()))); // Source location.
181 __ pushq(obj); // Push the source object. 187 __ pushq(obj); // Push the source object.
182 compiler->GenerateCallRuntime(cid(), 188 compiler->GenerateCallRuntime(cid(),
183 token_index(), 189 token_index(),
184 try_index(), 190 try_index(),
185 kConditionTypeErrorRuntimeEntry); 191 kConditionTypeErrorRuntimeEntry);
186 // We should never return here. 192 // We should never return here.
187 __ int3(); 193 __ int3();
188 194
189 __ Bind(&done); 195 __ Bind(&done);
190 ASSERT(obj == result); 196 ASSERT(obj == result);
191 } 197 }
192 198
193 199
194 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { 200 LocationSummary* EqualityCompareComp::MakeLocationSummary() const {
195 LocationSummary* locs = new LocationSummary(2, 0); 201 LocationSummary* locs = new LocationSummary(2, 0);
196 locs->set_in(0, Location::RequiresRegister()); 202 locs->set_in(0, Location::RequiresRegister());
197 locs->set_in(1, Location::RequiresRegister()); 203 locs->set_in(1, Location::RequiresRegister());
198 locs->set_out(Location::RegisterLocation(RAX)); 204 if (!is_fused_with_branch()) {
205 locs->set_out(Location::RegisterLocation(RAX));
206 }
199 return locs; 207 return locs;
200 } 208 }
201 209
202 210
203 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { 211 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
204 Register left = locs()->in(0).reg(); 212 Register left = locs()->in(0).reg();
205 Register right = locs()->in(1).reg(); 213 Register right = locs()->in(1).reg();
206 Register result = locs()->out().reg();
207 ASSERT(locs()->out().reg() == RAX);
208 214
209 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
210 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
211 const Immediate raw_null = 215 const Immediate raw_null =
212 Immediate(reinterpret_cast<intptr_t>(Object::null())); 216 Immediate(reinterpret_cast<intptr_t>(Object::null()));
213 Label done, load_true, non_null_compare; 217 Label done, non_null_compare;
214 218
215 __ cmpq(left, raw_null); 219 __ cmpq(left, raw_null);
216 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); 220 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump);
217 // Comparison with NULL is "===". 221 // Comparison with NULL is "===".
218 __ cmpq(left, right); 222 __ cmpq(left, right);
219 __ j(EQUAL, &load_true, Assembler::kNearJump); 223 if (!is_fused_with_branch()) {
220 __ LoadObject(result, bool_false); 224 Register result = locs()->out().reg();
221 __ jmp(&done, Assembler::kNearJump); 225 Label load_true;
222 __ Bind(&load_true); 226 __ j(EQUAL, &load_true, Assembler::kNearJump);
223 __ LoadObject(result, bool_true); 227 __ LoadObject(result, compiler->bool_false());
228 __ jmp(&done, Assembler::kNearJump);
229 __ Bind(&load_true);
230 __ LoadObject(result, compiler->bool_true());
231 } else {
232 fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
233 }
224 __ jmp(&done); 234 __ jmp(&done);
225 235
236
226 __ Bind(&non_null_compare); 237 __ Bind(&non_null_compare);
227 __ pushq(left); 238 __ pushq(left);
228 __ pushq(right); 239 __ pushq(right);
229 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); 240 const String& operator_name = String::ZoneHandle(String::NewSymbol("=="));
230 const int kNumberOfArguments = 2; 241 const int kNumberOfArguments = 2;
231 const Array& kNoArgumentNames = Array::Handle(); 242 const Array& kNoArgumentNames = Array::Handle();
232 const int kNumArgumentsChecked = 1; 243 const int kNumArgumentsChecked = 1;
233 244
234 compiler->GenerateInstanceCall(cid(), 245 compiler->GenerateInstanceCall(cid(),
235 token_index(), 246 token_index(),
236 try_index(), 247 try_index(),
237 operator_name, 248 operator_name,
238 kNumberOfArguments, 249 kNumberOfArguments,
239 kNoArgumentNames, 250 kNoArgumentNames,
240 kNumArgumentsChecked); 251 kNumArgumentsChecked);
252 ASSERT(fused_with_branch() != NULL || locs()->out().reg() == RAX);
253
254 if (fused_with_branch() != NULL) {
255 __ CompareObject(RAX, compiler->bool_true());
256 fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
257 }
258
241 __ Bind(&done); 259 __ Bind(&done);
242 } 260 }
243 261
244 262
263 LocationSummary* RelationalOpComp::MakeLocationSummary() const {
264 if (operands_class_id() == kSmi || operands_class_id() == kDouble) {
265 const intptr_t kNumInputs = 2;
266 const intptr_t kNumTemps = 1;
267 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
268 summary->set_in(0, Location::RequiresRegister());
269 summary->set_in(1, Location::RequiresRegister());
270 if (!is_fused_with_branch()) {
271 summary->set_out(Location::RequiresRegister());
272 }
273 summary->set_temp(0, Location::RequiresRegister());
274 return summary;
275 }
276 ASSERT(!is_fused_with_branch());
277 ASSERT(operands_class_id() == kObject);
278 return MakeCallSummary();
279 }
280
281
245 static Condition TokenKindToSmiCondition(Token::Kind kind) { 282 static Condition TokenKindToSmiCondition(Token::Kind kind) {
246 switch (kind) { 283 switch (kind) {
247 case Token::kEQ: return EQUAL; 284 case Token::kEQ: return EQUAL;
248 case Token::kNE: return NOT_EQUAL; 285 case Token::kNE: return NOT_EQUAL;
249 case Token::kLT: return LESS; 286 case Token::kLT: return LESS;
250 case Token::kGT: return GREATER; 287 case Token::kGT: return GREATER;
251 case Token::kLTE: return LESS_EQUAL; 288 case Token::kLTE: return LESS_EQUAL;
252 case Token::kGTE: return GREATER_EQUAL; 289 case Token::kGTE: return GREATER_EQUAL;
253 default: 290 default:
254 UNREACHABLE(); 291 UNREACHABLE();
255 return OVERFLOW; 292 return OVERFLOW;
256 } 293 }
257 } 294 }
258 295
259 296
260 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, 297 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler,
261 RelationalOpComp* comp) { 298 RelationalOpComp* comp) {
262 Register left = comp->locs()->in(0).reg(); 299 Register left = comp->locs()->in(0).reg();
263 Register right = comp->locs()->in(1).reg(); 300 Register right = comp->locs()->in(1).reg();
264 Register result = comp->locs()->out().reg();
265 Register temp = comp->locs()->temp(0).reg(); 301 Register temp = comp->locs()->temp(0).reg();
266 Label* deopt = compiler->AddDeoptStub(comp->cid(), 302 Label* deopt = compiler->AddDeoptStub(comp->cid(),
267 comp->token_index(), 303 comp->token_index(),
268 comp->try_index(), 304 comp->try_index(),
269 kDeoptSmiCompareSmis, 305 kDeoptSmiCompareSmis,
270 left, 306 left,
271 right); 307 right);
272 __ movq(temp, left); 308 __ movq(temp, left);
273 __ orq(temp, right); 309 __ orq(temp, right);
274 __ testq(temp, Immediate(kSmiTagMask)); 310 __ testq(temp, Immediate(kSmiTagMask));
275 __ j(NOT_ZERO, deopt); 311 __ j(NOT_ZERO, deopt);
276 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
277 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
278 Condition condition = TokenKindToSmiCondition(comp->kind());
279 312
280 Label done, is_true; 313 Condition true_condition = TokenKindToSmiCondition(comp->kind());
281 __ cmpq(left, right); 314 __ cmpq(left, right);
282 __ j(condition, &is_true); 315
283 __ LoadObject(result, bool_false); 316 if (comp->is_fused_with_branch()) {
284 __ jmp(&done); 317 comp->fused_with_branch()->EmitBranchOnCondition(compiler, true_condition);
285 __ Bind(&is_true); 318 } else {
286 __ LoadObject(result, bool_true); 319 Register result = comp->locs()->out().reg();
287 __ Bind(&done); 320 Label done, is_true;
321 __ j(true_condition, &is_true);
322 __ LoadObject(result, compiler->bool_false());
323 __ jmp(&done);
324 __ Bind(&is_true);
325 __ LoadObject(result, compiler->bool_true());
326 __ Bind(&done);
327 }
288 } 328 }
289 329
290 330
291 LocationSummary* RelationalOpComp::MakeLocationSummary() const {
292 if (operands_class_id() == kSmi) {
293 const intptr_t kNumInputs = 2;
294 const intptr_t kNumTemps = 1;
295 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
296 summary->set_in(0, Location::RequiresRegister());
297 summary->set_in(1, Location::RequiresRegister());
298 summary->set_out(Location::RequiresRegister());
299 summary->set_temp(0, Location::RequiresRegister());
300 return summary;
301 }
302 if (operands_class_id() == kDouble) {
303 const intptr_t kNumInputs = 2;
304 const intptr_t kNumTemps = 1;
305 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
306 summary->set_in(0, Location::RequiresRegister());
307 summary->set_in(1, Location::RequiresRegister());
308 summary->set_out(Location::RequiresRegister());
309 summary->set_temp(0, Location::RequiresRegister());
310 return summary;
311 }
312 ASSERT(operands_class_id() == kObject);
313 return MakeCallSummary();
314 }
315
316
317
318 static Condition TokenKindToDoubleCondition(Token::Kind kind) { 331 static Condition TokenKindToDoubleCondition(Token::Kind kind) {
319 switch (kind) { 332 switch (kind) {
320 case Token::kEQ: return EQUAL; 333 case Token::kEQ: return EQUAL;
321 case Token::kLT: return BELOW; 334 case Token::kLT: return BELOW;
322 case Token::kGT: return ABOVE; 335 case Token::kGT: return ABOVE;
323 case Token::kLTE: return BELOW_EQUAL; 336 case Token::kLTE: return BELOW_EQUAL;
324 case Token::kGTE: return ABOVE_EQUAL; 337 case Token::kGTE: return ABOVE_EQUAL;
325 default: 338 default:
326 UNREACHABLE(); 339 UNREACHABLE();
327 return OVERFLOW; 340 return OVERFLOW;
328 } 341 }
329 } 342 }
330 343
331 344
332 static void EmitDoubleRelationalOp(FlowGraphCompiler* compiler, 345 static void EmitDoubleRelationalOp(FlowGraphCompiler* compiler,
333 RelationalOpComp* comp) { 346 RelationalOpComp* comp) {
334 Register left = comp->locs()->in(0).reg(); 347 Register left = comp->locs()->in(0).reg();
335 Register right = comp->locs()->in(1).reg(); 348 Register right = comp->locs()->in(1).reg();
336 Register result = comp->locs()->out().reg();
337 // TODO(srdjan): temp is only needed if a conversion Smi->Double occurs. 349 // TODO(srdjan): temp is only needed if a conversion Smi->Double occurs.
338 Register temp = comp->locs()->temp(0).reg(); 350 Register temp = comp->locs()->temp(0).reg();
339 Label* deopt = compiler->AddDeoptStub(comp->cid(), 351 Label* deopt = compiler->AddDeoptStub(comp->cid(),
340 comp->token_index(), 352 comp->token_index(),
341 comp->try_index(), 353 comp->try_index(),
342 kDeoptDoubleComparison, 354 kDeoptDoubleComparison,
343 left, 355 left,
344 right); 356 right);
345 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); 357 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt);
346 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); 358 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt);
347 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 359
348 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
349 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); 360 Condition true_condition = TokenKindToDoubleCondition(comp->kind());
350 Label is_false, is_true, done;
351 __ comisd(XMM0, XMM1); 361 __ comisd(XMM0, XMM1);
352 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; 362
353 __ j(true_condition, &is_true, Assembler::kNearJump); 363 if (comp->is_fused_with_branch()) {
354 __ Bind(&is_false); 364 BranchInstr* branch = comp->fused_with_branch();
355 __ LoadObject(result, bool_false); 365 __ j(PARITY_EVEN, compiler->GetBlockLabel(branch->false_successor()));
356 __ jmp(&done); 366 branch->EmitBranchOnCondition(compiler, true_condition);
357 __ Bind(&is_true); 367 } else {
358 __ LoadObject(result, bool_true); 368 Register result = comp->locs()->out().reg();
359 __ Bind(&done); 369 Label is_false, is_true, done;
370 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump);
371 __ j(true_condition, &is_true, Assembler::kNearJump);
372 __ Bind(&is_false);
373 __ LoadObject(result, compiler->bool_false());
374 __ jmp(&done);
375 __ Bind(&is_true);
376 __ LoadObject(result, compiler->bool_true());
377 __ Bind(&done);
378 }
360 } 379 }
361 380
362 381
363 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { 382 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
364 if (operands_class_id() == kSmi) { 383 if (operands_class_id() == kSmi) {
365 EmitSmiRelationalOp(compiler, this); 384 EmitSmiRelationalOp(compiler, this);
366 return; 385 return;
367 } 386 }
368 if (operands_class_id() == kDouble) { 387 if (operands_class_id() == kDouble) {
369 EmitDoubleRelationalOp(compiler, this); 388 EmitDoubleRelationalOp(compiler, this);
(...skipping 1078 matching lines...) Expand 10 before | Expand all | Expand 10 after
1448 __ DoubleNegate(XMM0); 1467 __ DoubleNegate(XMM0);
1449 __ movsd(FieldAddress(result, Double::value_offset()), XMM0); 1468 __ movsd(FieldAddress(result, Double::value_offset()), XMM0);
1450 } else { 1469 } else {
1451 UNREACHABLE(); 1470 UNREACHABLE();
1452 } 1471 }
1453 } 1472 }
1454 1473
1455 1474
1456 LocationSummary* ToDoubleComp::MakeLocationSummary() const { 1475 LocationSummary* ToDoubleComp::MakeLocationSummary() const {
1457 const intptr_t kNumInputs = 1; 1476 const intptr_t kNumInputs = 1;
1458 const intptr_t kNumTemps = 0;
1459 if (from() == kDouble) { 1477 if (from() == kDouble) {
1478 const intptr_t kNumTemps = 0;
1460 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); 1479 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps);
1461 locs->set_in(0, Location::RequiresRegister()); 1480 locs->set_in(0, Location::RequiresRegister());
1462 locs->set_out(Location::SameAsFirstInput()); 1481 locs->set_out(Location::SameAsFirstInput());
1463 return locs; 1482 return locs;
1464 } else { 1483 } else {
1465 ASSERT(from() == kSmi); 1484 ASSERT(from() == kSmi);
1466 return LocationSummary::Make(kNumInputs, Location::RegisterLocation(RAX)); 1485 return LocationSummary::Make(kNumInputs, Location::RegisterLocation(RAX));
1467 } 1486 }
1468 } 1487 }
1469 1488
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1516 __ cvtsi2sd(XMM0, value); 1535 __ cvtsi2sd(XMM0, value);
1517 __ movsd(FieldAddress(result, Double::value_offset()), XMM0); 1536 __ movsd(FieldAddress(result, Double::value_offset()), XMM0);
1518 } 1537 }
1519 1538
1520 1539
1521 } // namespace dart 1540 } // namespace dart
1522 1541
1523 #undef __ 1542 #undef __
1524 1543
1525 #endif // defined TARGET_ARCH_X64 1544 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language_ia32.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698