blob: 57cc344baed574052bf82bc1df4cf029be5b1be8 [file] [log] [blame]
xueliang.zhongf7caf682017-03-01 16:07:02 +00001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "arch/arm/instruction_set_features_arm.h"
18#include "code_generator_utils.h"
19#include "common_arm.h"
20#include "mirror/array-inl.h"
21#include "scheduler_arm.h"
22
23namespace art {
24namespace arm {
25
26using helpers::Int32ConstantFrom;
27using helpers::Uint64ConstantFrom;
28
29void SchedulingLatencyVisitorARM::HandleBinaryOperationLantencies(HBinaryOperation* instr) {
30 switch (instr->GetResultType()) {
31 case Primitive::kPrimLong:
32 // HAdd and HSub long operations translate to ADDS+ADC or SUBS+SBC pairs,
33 // so a bubble (kArmNopLatency) is added to represent the internal carry flag
34 // dependency inside these pairs.
35 last_visited_internal_latency_ = kArmIntegerOpLatency + kArmNopLatency;
36 last_visited_latency_ = kArmIntegerOpLatency;
37 break;
38 case Primitive::kPrimFloat:
39 case Primitive::kPrimDouble:
40 last_visited_latency_ = kArmFloatingPointOpLatency;
41 break;
42 default:
43 last_visited_latency_ = kArmIntegerOpLatency;
44 break;
45 }
46}
47
48void SchedulingLatencyVisitorARM::VisitAdd(HAdd* instr) {
49 HandleBinaryOperationLantencies(instr);
50}
51
52void SchedulingLatencyVisitorARM::VisitSub(HSub* instr) {
53 HandleBinaryOperationLantencies(instr);
54}
55
56void SchedulingLatencyVisitorARM::VisitMul(HMul* instr) {
57 switch (instr->GetResultType()) {
58 case Primitive::kPrimLong:
59 last_visited_internal_latency_ = 3 * kArmMulIntegerLatency;
60 last_visited_latency_ = kArmIntegerOpLatency;
61 break;
62 case Primitive::kPrimFloat:
63 case Primitive::kPrimDouble:
64 last_visited_latency_ = kArmMulFloatingPointLatency;
65 break;
66 default:
67 last_visited_latency_ = kArmMulIntegerLatency;
68 break;
69 }
70}
71
72void SchedulingLatencyVisitorARM::HandleBitwiseOperationLantencies(HBinaryOperation* instr) {
73 switch (instr->GetResultType()) {
74 case Primitive::kPrimLong:
75 last_visited_internal_latency_ = kArmIntegerOpLatency;
76 last_visited_latency_ = kArmIntegerOpLatency;
77 break;
78 case Primitive::kPrimFloat:
79 case Primitive::kPrimDouble:
80 last_visited_latency_ = kArmFloatingPointOpLatency;
81 break;
82 default:
83 last_visited_latency_ = kArmIntegerOpLatency;
84 break;
85 }
86}
87
88void SchedulingLatencyVisitorARM::VisitAnd(HAnd* instr) {
89 HandleBitwiseOperationLantencies(instr);
90}
91
92void SchedulingLatencyVisitorARM::VisitOr(HOr* instr) {
93 HandleBitwiseOperationLantencies(instr);
94}
95
96void SchedulingLatencyVisitorARM::VisitXor(HXor* instr) {
97 HandleBitwiseOperationLantencies(instr);
98}
99
100void SchedulingLatencyVisitorARM::VisitRor(HRor* instr) {
101 switch (instr->GetResultType()) {
102 case Primitive::kPrimInt:
103 last_visited_latency_ = kArmIntegerOpLatency;
104 break;
105 case Primitive::kPrimLong: {
106 // HandleLongRotate
107 HInstruction* rhs = instr->GetRight();
108 if (rhs->IsConstant()) {
109 uint64_t rot = Uint64ConstantFrom(rhs->AsConstant()) & kMaxLongShiftDistance;
110 if (rot != 0u) {
111 last_visited_internal_latency_ = 3 * kArmIntegerOpLatency;
112 last_visited_latency_ = kArmIntegerOpLatency;
113 } else {
114 last_visited_internal_latency_ = kArmIntegerOpLatency;
115 last_visited_latency_ = kArmIntegerOpLatency;
116 }
117 } else {
118 last_visited_internal_latency_ = 9 * kArmIntegerOpLatency + kArmBranchLatency;
119 last_visited_latency_ = kArmBranchLatency;
120 }
121 break;
122 }
123 default:
124 LOG(FATAL) << "Unexpected operation type " << instr->GetResultType();
125 UNREACHABLE();
126 }
127}
128
129void SchedulingLatencyVisitorARM::HandleShiftLatencies(HBinaryOperation* instr) {
130 Primitive::Type type = instr->GetResultType();
131 HInstruction* rhs = instr->GetRight();
132 switch (type) {
133 case Primitive::kPrimInt:
134 if (!rhs->IsConstant()) {
135 last_visited_internal_latency_ = kArmIntegerOpLatency;
136 }
137 last_visited_latency_ = kArmIntegerOpLatency;
138 break;
139 case Primitive::kPrimLong:
140 if (!rhs->IsConstant()) {
141 last_visited_internal_latency_ = 8 * kArmIntegerOpLatency;
142 } else {
143 uint32_t shift_value = Int32ConstantFrom(rhs->AsConstant()) & kMaxLongShiftDistance;
144 if (shift_value == 1 || shift_value >= 32) {
145 last_visited_internal_latency_ = kArmIntegerOpLatency;
146 } else {
147 last_visited_internal_latency_ = 2 * kArmIntegerOpLatency;
148 }
149 }
150 last_visited_latency_ = kArmIntegerOpLatency;
151 break;
152 default:
153 LOG(FATAL) << "Unexpected operation type " << type;
154 UNREACHABLE();
155 }
156}
157
158void SchedulingLatencyVisitorARM::VisitShl(HShl* instr) {
159 HandleShiftLatencies(instr);
160}
161
162void SchedulingLatencyVisitorARM::VisitShr(HShr* instr) {
163 HandleShiftLatencies(instr);
164}
165
166void SchedulingLatencyVisitorARM::VisitUShr(HUShr* instr) {
167 HandleShiftLatencies(instr);
168}
169
xueliang.zhongbf9e21a2017-06-15 11:01:11 +0100170void SchedulingLatencyVisitorARM::HandleGenerateConditionWithZero(IfCondition condition) {
171 switch (condition) {
172 case kCondEQ:
173 case kCondBE:
174 case kCondNE:
175 case kCondA:
176 last_visited_internal_latency_ += kArmIntegerOpLatency;
177 last_visited_latency_ = kArmIntegerOpLatency;
xueliang.zhongf7caf682017-03-01 16:07:02 +0000178 break;
xueliang.zhongbf9e21a2017-06-15 11:01:11 +0100179 case kCondGE:
180 // Mvn
181 last_visited_internal_latency_ += kArmIntegerOpLatency;
182 FALLTHROUGH_INTENDED;
183 case kCondLT:
184 // Lsr
185 last_visited_latency_ = kArmIntegerOpLatency;
186 break;
187 case kCondAE:
188 // Trivially true.
189 // Mov
190 last_visited_latency_ = kArmIntegerOpLatency;
191 break;
192 case kCondB:
193 // Trivially false.
194 // Mov
195 last_visited_latency_ = kArmIntegerOpLatency;
xueliang.zhongf7caf682017-03-01 16:07:02 +0000196 break;
197 default:
xueliang.zhongbf9e21a2017-06-15 11:01:11 +0100198 LOG(FATAL) << "Unexpected condition " << condition;
199 UNREACHABLE();
xueliang.zhongf7caf682017-03-01 16:07:02 +0000200 }
xueliang.zhongbf9e21a2017-06-15 11:01:11 +0100201}
202
203void SchedulingLatencyVisitorARM::HandleGenerateLongTestConstant(HCondition* condition) {
204 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
205
206 IfCondition cond = condition->GetCondition();
207
208 HInstruction* right = condition->InputAt(1);
209
210 int64_t value = Uint64ConstantFrom(right);
211
212 // Comparisons against 0 are common enough, so codegen has special handling for them.
213 if (value == 0) {
214 switch (cond) {
215 case kCondNE:
216 case kCondA:
217 case kCondEQ:
218 case kCondBE:
219 // Orrs
220 last_visited_internal_latency_ += kArmIntegerOpLatency;
221 return;
222 case kCondLT:
223 case kCondGE:
224 // Cmp
225 last_visited_internal_latency_ += kArmIntegerOpLatency;
226 return;
227 case kCondB:
228 case kCondAE:
229 // Cmp
230 last_visited_internal_latency_ += kArmIntegerOpLatency;
231 return;
232 default:
233 break;
234 }
235 }
236
237 switch (cond) {
238 case kCondEQ:
239 case kCondNE:
240 case kCondB:
241 case kCondBE:
242 case kCondA:
243 case kCondAE: {
244 // Cmp, IT, Cmp
245 last_visited_internal_latency_ += 3 * kArmIntegerOpLatency;
246 break;
247 }
248 case kCondLE:
249 case kCondGT:
250 // Trivially true or false.
251 if (value == std::numeric_limits<int64_t>::max()) {
252 // Cmp
253 last_visited_internal_latency_ += kArmIntegerOpLatency;
254 break;
255 }
256 FALLTHROUGH_INTENDED;
257 case kCondGE:
258 case kCondLT: {
259 // Cmp, Sbcs
260 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
261 break;
262 }
263 default:
264 LOG(FATAL) << "Unreachable";
265 UNREACHABLE();
266 }
267}
268
269void SchedulingLatencyVisitorARM::HandleGenerateLongTest(HCondition* condition) {
270 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
271
272 IfCondition cond = condition->GetCondition();
273
274 switch (cond) {
275 case kCondEQ:
276 case kCondNE:
277 case kCondB:
278 case kCondBE:
279 case kCondA:
280 case kCondAE: {
281 // Cmp, IT, Cmp
282 last_visited_internal_latency_ += 3 * kArmIntegerOpLatency;
283 break;
284 }
285 case kCondLE:
286 case kCondGT:
287 case kCondGE:
288 case kCondLT: {
289 // Cmp, Sbcs
290 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
291 break;
292 }
293 default:
294 LOG(FATAL) << "Unreachable";
295 UNREACHABLE();
296 }
297}
298
299// The GenerateTest series of function all counted as internal latency.
300void SchedulingLatencyVisitorARM::HandleGenerateTest(HCondition* condition) {
301 const Primitive::Type type = condition->GetLeft()->GetType();
302
303 if (type == Primitive::kPrimLong) {
304 condition->InputAt(1)->IsConstant()
305 ? HandleGenerateLongTestConstant(condition)
306 : HandleGenerateLongTest(condition);
307 } else if (Primitive::IsFloatingPointType(type)) {
308 // GenerateVcmp + Vmrs
309 last_visited_internal_latency_ += 2 * kArmFloatingPointOpLatency;
310 } else {
311 // Cmp
312 last_visited_internal_latency_ += kArmIntegerOpLatency;
313 }
314}
315
316bool SchedulingLatencyVisitorARM::CanGenerateTest(HCondition* condition) {
317 if (condition->GetLeft()->GetType() == Primitive::kPrimLong) {
318 HInstruction* right = condition->InputAt(1);
319
320 if (right->IsConstant()) {
321 IfCondition c = condition->GetCondition();
322 const uint64_t value = Uint64ConstantFrom(right);
323
324 if (c < kCondLT || c > kCondGE) {
325 if (value != 0) {
326 return false;
327 }
328 } else if (c == kCondLE || c == kCondGT) {
329 if (value < std::numeric_limits<int64_t>::max() &&
330 !codegen_->GetAssembler()->ShifterOperandCanHold(SBC, High32Bits(value + 1), kCcSet)) {
331 return false;
332 }
333 } else if (!codegen_->GetAssembler()->ShifterOperandCanHold(SBC, High32Bits(value), kCcSet)) {
334 return false;
335 }
336 }
337 }
338
339 return true;
340}
341
342void SchedulingLatencyVisitorARM::HandleGenerateConditionGeneric(HCondition* cond) {
343 HandleGenerateTest(cond);
344
345 // Unlike codegen pass, we cannot check 'out' register IsLow() here,
346 // because scheduling is before liveness(location builder) and register allocator,
347 // so we can only choose to follow one path of codegen by assuming otu.IsLow() is true.
348 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
xueliang.zhongf7caf682017-03-01 16:07:02 +0000349 last_visited_latency_ = kArmIntegerOpLatency;
350}
351
xueliang.zhongbf9e21a2017-06-15 11:01:11 +0100352void SchedulingLatencyVisitorARM::HandleGenerateEqualLong(HCondition* cond) {
353 DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
354
355 IfCondition condition = cond->GetCondition();
356
357 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
358
359 if (condition == kCondNE) {
360 // Orrs, IT, Mov
361 last_visited_internal_latency_ += 3 * kArmIntegerOpLatency;
362 } else {
363 last_visited_internal_latency_ += kArmIntegerOpLatency;
364 HandleGenerateConditionWithZero(condition);
365 }
366}
367
368void SchedulingLatencyVisitorARM::HandleGenerateLongComparesAndJumps() {
369 last_visited_internal_latency_ += 4 * kArmIntegerOpLatency;
370 last_visited_internal_latency_ += kArmBranchLatency;
371}
372
373void SchedulingLatencyVisitorARM::HandleGenerateConditionLong(HCondition* cond) {
374 DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
375
376 IfCondition condition = cond->GetCondition();
377 HInstruction* right = cond->InputAt(1);
378
379 if (right->IsConstant()) {
380 // Comparisons against 0 are common enough, so codegen has special handling for them.
381 if (Uint64ConstantFrom(right) == 0) {
382 switch (condition) {
383 case kCondNE:
384 case kCondA:
385 case kCondEQ:
386 case kCondBE:
387 // Orr
388 last_visited_internal_latency_ += kArmIntegerOpLatency;
389 HandleGenerateConditionWithZero(condition);
390 return;
391 case kCondLT:
392 case kCondGE:
393 FALLTHROUGH_INTENDED;
394 case kCondAE:
395 case kCondB:
396 HandleGenerateConditionWithZero(condition);
397 return;
398 case kCondLE:
399 case kCondGT:
400 default:
401 break;
402 }
403 }
404 }
405
406 if ((condition == kCondEQ || condition == kCondNE) &&
407 !CanGenerateTest(cond)) {
408 HandleGenerateEqualLong(cond);
409 return;
410 }
411
412 if (CanGenerateTest(cond)) {
413 HandleGenerateConditionGeneric(cond);
414 return;
415 }
416
417 HandleGenerateLongComparesAndJumps();
418
419 last_visited_internal_latency_ += kArmIntegerOpLatency;
420 last_visited_latency_ = kArmBranchLatency;;
421}
422
423void SchedulingLatencyVisitorARM::HandleGenerateConditionIntegralOrNonPrimitive(HCondition* cond) {
424 const Primitive::Type type = cond->GetLeft()->GetType();
425
426 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
427
428 if (type == Primitive::kPrimLong) {
429 HandleGenerateConditionLong(cond);
430 return;
431 }
432
433 IfCondition condition = cond->GetCondition();
434 HInstruction* right = cond->InputAt(1);
435 int64_t value;
436
437 if (right->IsConstant()) {
438 value = Uint64ConstantFrom(right);
439
440 // Comparisons against 0 are common enough, so codegen has special handling for them.
441 if (value == 0) {
442 switch (condition) {
443 case kCondNE:
444 case kCondA:
445 case kCondEQ:
446 case kCondBE:
447 case kCondLT:
448 case kCondGE:
449 case kCondAE:
450 case kCondB:
451 HandleGenerateConditionWithZero(condition);
452 return;
453 case kCondLE:
454 case kCondGT:
455 default:
456 break;
457 }
458 }
459 }
460
461 if (condition == kCondEQ || condition == kCondNE) {
462 if (condition == kCondNE) {
463 // CMP, IT, MOV.ne
464 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
465 last_visited_latency_ = kArmIntegerOpLatency;
466 } else {
467 last_visited_internal_latency_ += kArmIntegerOpLatency;
468 HandleGenerateConditionWithZero(condition);
469 }
470 return;
471 }
472
473 HandleGenerateConditionGeneric(cond);
474}
475
476void SchedulingLatencyVisitorARM::HandleCondition(HCondition* cond) {
477 if (cond->IsEmittedAtUseSite()) {
478 last_visited_latency_ = 0;
479 return;
480 }
481
482 const Primitive::Type type = cond->GetLeft()->GetType();
483
484 if (Primitive::IsFloatingPointType(type)) {
485 HandleGenerateConditionGeneric(cond);
486 return;
487 }
488
489 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
490
491 const IfCondition condition = cond->GetCondition();
492
493 if (type == Primitive::kPrimBoolean &&
494 cond->GetRight()->GetType() == Primitive::kPrimBoolean &&
495 (condition == kCondEQ || condition == kCondNE)) {
496 if (condition == kCondEQ) {
497 last_visited_internal_latency_ = kArmIntegerOpLatency;
498 }
499 last_visited_latency_ = kArmIntegerOpLatency;
500 return;
501 }
502
503 HandleGenerateConditionIntegralOrNonPrimitive(cond);
504}
505
506void SchedulingLatencyVisitorARM::VisitCondition(HCondition* instr) {
507 HandleCondition(instr);
508}
509
xueliang.zhongf7caf682017-03-01 16:07:02 +0000510void SchedulingLatencyVisitorARM::VisitCompare(HCompare* instr) {
511 Primitive::Type type = instr->InputAt(0)->GetType();
512 switch (type) {
513 case Primitive::kPrimBoolean:
514 case Primitive::kPrimByte:
515 case Primitive::kPrimShort:
516 case Primitive::kPrimChar:
517 case Primitive::kPrimInt:
518 last_visited_internal_latency_ = 2 * kArmIntegerOpLatency;
519 break;
520 case Primitive::kPrimLong:
521 last_visited_internal_latency_ = 2 * kArmIntegerOpLatency + 3 * kArmBranchLatency;
522 break;
523 case Primitive::kPrimFloat:
524 case Primitive::kPrimDouble:
525 last_visited_internal_latency_ = kArmIntegerOpLatency + 2 * kArmFloatingPointOpLatency;
526 break;
527 default:
528 last_visited_internal_latency_ = 2 * kArmIntegerOpLatency;
529 break;
530 }
531 last_visited_latency_ = kArmIntegerOpLatency;
532}
533
534void SchedulingLatencyVisitorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
535 if (instruction->GetResultType() == Primitive::kPrimInt) {
536 last_visited_latency_ = kArmIntegerOpLatency;
537 } else {
538 last_visited_internal_latency_ = kArmIntegerOpLatency;
539 last_visited_latency_ = kArmIntegerOpLatency;
540 }
541}
542
543void SchedulingLatencyVisitorARM::HandleGenerateDataProcInstruction(bool internal_latency) {
544 if (internal_latency) {
545 last_visited_internal_latency_ += kArmIntegerOpLatency;
546 } else {
547 last_visited_latency_ = kArmDataProcWithShifterOpLatency;
548 }
549}
550
551void SchedulingLatencyVisitorARM::HandleGenerateDataProc(HDataProcWithShifterOp* instruction) {
552 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
553 if (kind == HInstruction::kAdd) {
554 last_visited_internal_latency_ = kArmIntegerOpLatency;
555 last_visited_latency_ = kArmIntegerOpLatency;
556 } else if (kind == HInstruction::kSub) {
557 last_visited_internal_latency_ = kArmIntegerOpLatency;
558 last_visited_latency_ = kArmIntegerOpLatency;
559 } else {
560 HandleGenerateDataProcInstruction(/* internal_latency */ true);
561 HandleGenerateDataProcInstruction();
562 }
563}
564
565void SchedulingLatencyVisitorARM::HandleGenerateLongDataProc(HDataProcWithShifterOp* instruction) {
566 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
567 DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
568
569 const uint32_t shift_value = instruction->GetShiftAmount();
570 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
571
572 if (shift_value >= 32) {
573 // Different shift types actually generate similar code here,
574 // no need to differentiate shift types like the codegen pass does,
575 // which also avoids handling shift types from different ARM backends.
576 HandleGenerateDataProc(instruction);
577 } else {
578 DCHECK_GT(shift_value, 1U);
579 DCHECK_LT(shift_value, 32U);
580
581 if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
582 HandleGenerateDataProcInstruction(/* internal_latency */ true);
583 HandleGenerateDataProcInstruction(/* internal_latency */ true);
584 HandleGenerateDataProcInstruction();
585 } else {
586 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
587 HandleGenerateDataProc(instruction);
588 }
589 }
590}
591
592void SchedulingLatencyVisitorARM::VisitDataProcWithShifterOp(HDataProcWithShifterOp* instruction) {
593 const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
594
595 if (instruction->GetType() == Primitive::kPrimInt) {
596 DCHECK(!HDataProcWithShifterOp::IsExtensionOp(op_kind));
597 HandleGenerateDataProcInstruction();
598 } else {
599 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
600 if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
601 HandleGenerateDataProc(instruction);
602 } else {
603 HandleGenerateLongDataProc(instruction);
604 }
605 }
606}
607
608void SchedulingLatencyVisitorARM::VisitIntermediateAddress(HIntermediateAddress* ATTRIBUTE_UNUSED) {
609 // Although the code generated is a simple `add` instruction, we found through empirical results
610 // that spacing it from its use in memory accesses was beneficial.
611 last_visited_internal_latency_ = kArmNopLatency;
612 last_visited_latency_ = kArmIntegerOpLatency;
613}
614
Artem Serovf0fc4c62017-05-03 15:07:15 +0100615void SchedulingLatencyVisitorARM::VisitIntermediateAddressIndex(
616 HIntermediateAddressIndex* ATTRIBUTE_UNUSED) {
617 UNIMPLEMENTED(FATAL) << "IntermediateAddressIndex is not implemented for ARM";
618}
619
xueliang.zhongf7caf682017-03-01 16:07:02 +0000620void SchedulingLatencyVisitorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* ATTRIBUTE_UNUSED) {
621 last_visited_latency_ = kArmMulIntegerLatency;
622}
623
624void SchedulingLatencyVisitorARM::VisitArrayGet(HArrayGet* instruction) {
625 Primitive::Type type = instruction->GetType();
626 const bool maybe_compressed_char_at =
627 mirror::kUseStringCompression && instruction->IsStringCharAt();
628 HInstruction* array_instr = instruction->GetArray();
629 bool has_intermediate_address = array_instr->IsIntermediateAddress();
630 HInstruction* index = instruction->InputAt(1);
631
632 switch (type) {
633 case Primitive::kPrimBoolean:
634 case Primitive::kPrimByte:
635 case Primitive::kPrimShort:
636 case Primitive::kPrimChar:
637 case Primitive::kPrimInt: {
638 if (maybe_compressed_char_at) {
639 last_visited_internal_latency_ += kArmMemoryLoadLatency;
640 }
641 if (index->IsConstant()) {
642 if (maybe_compressed_char_at) {
643 last_visited_internal_latency_ +=
644 kArmIntegerOpLatency + kArmBranchLatency + kArmMemoryLoadLatency;
645 last_visited_latency_ = kArmBranchLatency;
646 } else {
647 last_visited_latency_ += kArmMemoryLoadLatency;
648 }
649 } else {
650 if (has_intermediate_address) {
651 } else {
652 last_visited_internal_latency_ += kArmIntegerOpLatency;
653 }
654 if (maybe_compressed_char_at) {
655 last_visited_internal_latency_ +=
656 kArmIntegerOpLatency + kArmBranchLatency + kArmMemoryLoadLatency;
657 last_visited_latency_ = kArmBranchLatency;
658 } else {
659 last_visited_latency_ += kArmMemoryLoadLatency;
660 }
661 }
662 break;
663 }
664
665 case Primitive::kPrimNot: {
666 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
667 last_visited_latency_ = kArmLoadWithBakerReadBarrierLatency;
668 } else {
669 if (index->IsConstant()) {
670 last_visited_latency_ = kArmMemoryLoadLatency;
671 } else {
672 if (has_intermediate_address) {
673 } else {
674 last_visited_internal_latency_ += kArmIntegerOpLatency;
675 }
676 last_visited_internal_latency_ = kArmMemoryLoadLatency;
677 }
678 }
679 break;
680 }
681
682 case Primitive::kPrimLong: {
683 if (index->IsConstant()) {
684 last_visited_latency_ = kArmMemoryLoadLatency;
685 } else {
686 last_visited_internal_latency_ += kArmIntegerOpLatency;
687 last_visited_latency_ = kArmMemoryLoadLatency;
688 }
689 break;
690 }
691
692 case Primitive::kPrimFloat: {
693 if (index->IsConstant()) {
694 last_visited_latency_ = kArmMemoryLoadLatency;
695 } else {
696 last_visited_internal_latency_ += kArmIntegerOpLatency;
697 last_visited_latency_ = kArmMemoryLoadLatency;
698 }
699 break;
700 }
701
702 case Primitive::kPrimDouble: {
703 if (index->IsConstant()) {
704 last_visited_latency_ = kArmMemoryLoadLatency;
705 } else {
706 last_visited_internal_latency_ += kArmIntegerOpLatency;
707 last_visited_latency_ = kArmMemoryLoadLatency;
708 }
709 break;
710 }
711
712 default:
713 LOG(FATAL) << "Unreachable type " << type;
714 UNREACHABLE();
715 }
716}
717
718void SchedulingLatencyVisitorARM::VisitArrayLength(HArrayLength* instruction) {
719 last_visited_latency_ = kArmMemoryLoadLatency;
720 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
721 last_visited_internal_latency_ = kArmMemoryLoadLatency;
722 last_visited_latency_ = kArmIntegerOpLatency;
723 }
724}
725
726void SchedulingLatencyVisitorARM::VisitArraySet(HArraySet* instruction) {
727 HInstruction* index = instruction->InputAt(1);
728 Primitive::Type value_type = instruction->GetComponentType();
729 HInstruction* array_instr = instruction->GetArray();
730 bool has_intermediate_address = array_instr->IsIntermediateAddress();
731
732 switch (value_type) {
733 case Primitive::kPrimBoolean:
734 case Primitive::kPrimByte:
735 case Primitive::kPrimShort:
736 case Primitive::kPrimChar:
737 case Primitive::kPrimInt: {
738 if (index->IsConstant()) {
739 last_visited_latency_ = kArmMemoryStoreLatency;
740 } else {
741 if (has_intermediate_address) {
742 } else {
743 last_visited_internal_latency_ = kArmIntegerOpLatency;
744 }
745 last_visited_latency_ = kArmMemoryStoreLatency;
746 }
747 break;
748 }
749
750 case Primitive::kPrimNot: {
751 if (instruction->InputAt(2)->IsNullConstant()) {
752 if (index->IsConstant()) {
753 last_visited_latency_ = kArmMemoryStoreLatency;
754 } else {
755 last_visited_internal_latency_ = kArmIntegerOpLatency;
756 last_visited_latency_ = kArmMemoryStoreLatency;
757 }
758 } else {
759 // Following the exact instructions of runtime type checks is too complicated,
760 // just giving it a simple slow latency.
761 last_visited_latency_ = kArmRuntimeTypeCheckLatency;
762 }
763 break;
764 }
765
766 case Primitive::kPrimLong: {
767 if (index->IsConstant()) {
768 last_visited_latency_ = kArmMemoryLoadLatency;
769 } else {
770 last_visited_internal_latency_ = kArmIntegerOpLatency;
771 last_visited_latency_ = kArmMemoryLoadLatency;
772 }
773 break;
774 }
775
776 case Primitive::kPrimFloat: {
777 if (index->IsConstant()) {
778 last_visited_latency_ = kArmMemoryLoadLatency;
779 } else {
780 last_visited_internal_latency_ = kArmIntegerOpLatency;
781 last_visited_latency_ = kArmMemoryLoadLatency;
782 }
783 break;
784 }
785
786 case Primitive::kPrimDouble: {
787 if (index->IsConstant()) {
788 last_visited_latency_ = kArmMemoryLoadLatency;
789 } else {
790 last_visited_internal_latency_ = kArmIntegerOpLatency;
791 last_visited_latency_ = kArmMemoryLoadLatency;
792 }
793 break;
794 }
795
796 default:
797 LOG(FATAL) << "Unreachable type " << value_type;
798 UNREACHABLE();
799 }
800}
801
802void SchedulingLatencyVisitorARM::VisitBoundsCheck(HBoundsCheck* ATTRIBUTE_UNUSED) {
803 last_visited_internal_latency_ = kArmIntegerOpLatency;
804 // Users do not use any data results.
805 last_visited_latency_ = 0;
806}
807
808void SchedulingLatencyVisitorARM::HandleDivRemConstantIntegralLatencies(int32_t imm) {
809 if (imm == 0) {
810 last_visited_internal_latency_ = 0;
811 last_visited_latency_ = 0;
812 } else if (imm == 1 || imm == -1) {
813 last_visited_latency_ = kArmIntegerOpLatency;
814 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
815 last_visited_internal_latency_ = 3 * kArmIntegerOpLatency;
816 last_visited_latency_ = kArmIntegerOpLatency;
817 } else {
818 last_visited_internal_latency_ = kArmMulIntegerLatency + 2 * kArmIntegerOpLatency;
819 last_visited_latency_ = kArmIntegerOpLatency;
820 }
821}
822
823void SchedulingLatencyVisitorARM::VisitDiv(HDiv* instruction) {
824 Primitive::Type type = instruction->GetResultType();
825 switch (type) {
826 case Primitive::kPrimInt: {
827 HInstruction* rhs = instruction->GetRight();
828 if (rhs->IsConstant()) {
829 int32_t imm = Int32ConstantFrom(rhs->AsConstant());
830 HandleDivRemConstantIntegralLatencies(imm);
831 } else {
832 last_visited_latency_ = kArmDivIntegerLatency;
833 }
834 break;
835 }
836 case Primitive::kPrimFloat:
837 last_visited_latency_ = kArmDivFloatLatency;
838 break;
839 case Primitive::kPrimDouble:
840 last_visited_latency_ = kArmDivDoubleLatency;
841 break;
842 default:
843 last_visited_internal_latency_ = kArmCallInternalLatency;
844 last_visited_latency_ = kArmCallLatency;
845 break;
846 }
847}
848
849void SchedulingLatencyVisitorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
850 HandleFieldGetLatencies(instruction, instruction->GetFieldInfo());
851}
852
853void SchedulingLatencyVisitorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
854 HandleFieldSetLatencies(instruction, instruction->GetFieldInfo());
855}
856
857void SchedulingLatencyVisitorARM::VisitInstanceOf(HInstanceOf* ATTRIBUTE_UNUSED) {
858 last_visited_internal_latency_ = kArmCallInternalLatency;
859 last_visited_latency_ = kArmIntegerOpLatency;
860}
861
862void SchedulingLatencyVisitorARM::VisitInvoke(HInvoke* ATTRIBUTE_UNUSED) {
863 last_visited_internal_latency_ = kArmCallInternalLatency;
864 last_visited_latency_ = kArmCallLatency;
865}
866
867void SchedulingLatencyVisitorARM::VisitLoadString(HLoadString* ATTRIBUTE_UNUSED) {
868 last_visited_internal_latency_ = kArmLoadStringInternalLatency;
869 last_visited_latency_ = kArmMemoryLoadLatency;
870}
871
872void SchedulingLatencyVisitorARM::VisitNewArray(HNewArray* ATTRIBUTE_UNUSED) {
873 last_visited_internal_latency_ = kArmIntegerOpLatency + kArmCallInternalLatency;
874 last_visited_latency_ = kArmCallLatency;
875}
876
877void SchedulingLatencyVisitorARM::VisitNewInstance(HNewInstance* instruction) {
878 if (instruction->IsStringAlloc()) {
879 last_visited_internal_latency_ = 2 * kArmMemoryLoadLatency + kArmCallInternalLatency;
880 } else {
881 last_visited_internal_latency_ = kArmCallInternalLatency;
882 }
883 last_visited_latency_ = kArmCallLatency;
884}
885
886void SchedulingLatencyVisitorARM::VisitRem(HRem* instruction) {
887 Primitive::Type type = instruction->GetResultType();
888 switch (type) {
889 case Primitive::kPrimInt: {
890 HInstruction* rhs = instruction->GetRight();
891 if (rhs->IsConstant()) {
892 int32_t imm = Int32ConstantFrom(rhs->AsConstant());
893 HandleDivRemConstantIntegralLatencies(imm);
894 } else {
895 last_visited_internal_latency_ = kArmDivIntegerLatency;
896 last_visited_latency_ = kArmMulIntegerLatency;
897 }
898 break;
899 }
900 default:
901 last_visited_internal_latency_ = kArmCallInternalLatency;
902 last_visited_latency_ = kArmCallLatency;
903 break;
904 }
905}
906
907void SchedulingLatencyVisitorARM::HandleFieldGetLatencies(HInstruction* instruction,
908 const FieldInfo& field_info) {
909 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
910 DCHECK(codegen_ != nullptr);
911 bool is_volatile = field_info.IsVolatile();
912 Primitive::Type field_type = field_info.GetFieldType();
913 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
914
915 switch (field_type) {
916 case Primitive::kPrimBoolean:
917 case Primitive::kPrimByte:
918 case Primitive::kPrimShort:
919 case Primitive::kPrimChar:
920 case Primitive::kPrimInt:
921 last_visited_latency_ = kArmMemoryLoadLatency;
922 break;
923
924 case Primitive::kPrimNot:
925 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
926 last_visited_internal_latency_ = kArmMemoryLoadLatency + kArmIntegerOpLatency;
927 last_visited_latency_ = kArmMemoryLoadLatency;
928 } else {
929 last_visited_latency_ = kArmMemoryLoadLatency;
930 }
931 break;
932
933 case Primitive::kPrimLong:
934 if (is_volatile && !atomic_ldrd_strd) {
935 last_visited_internal_latency_ = kArmMemoryLoadLatency + kArmIntegerOpLatency;
936 last_visited_latency_ = kArmMemoryLoadLatency;
937 } else {
938 last_visited_latency_ = kArmMemoryLoadLatency;
939 }
940 break;
941
942 case Primitive::kPrimFloat:
943 last_visited_latency_ = kArmMemoryLoadLatency;
944 break;
945
946 case Primitive::kPrimDouble:
947 if (is_volatile && !atomic_ldrd_strd) {
948 last_visited_internal_latency_ =
949 kArmMemoryLoadLatency + kArmIntegerOpLatency + kArmMemoryLoadLatency;
950 last_visited_latency_ = kArmIntegerOpLatency;
951 } else {
952 last_visited_latency_ = kArmMemoryLoadLatency;
953 }
954 break;
955
956 default:
957 last_visited_latency_ = kArmMemoryLoadLatency;
958 break;
959 }
960
961 if (is_volatile) {
962 last_visited_internal_latency_ += kArmMemoryBarrierLatency;
963 }
964}
965
966void SchedulingLatencyVisitorARM::HandleFieldSetLatencies(HInstruction* instruction,
967 const FieldInfo& field_info) {
968 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
969 DCHECK(codegen_ != nullptr);
970 bool is_volatile = field_info.IsVolatile();
971 Primitive::Type field_type = field_info.GetFieldType();
972 bool needs_write_barrier =
973 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
974 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
975
976 switch (field_type) {
977 case Primitive::kPrimBoolean:
978 case Primitive::kPrimByte:
979 case Primitive::kPrimShort:
980 case Primitive::kPrimChar:
981 if (is_volatile) {
982 last_visited_internal_latency_ = kArmMemoryBarrierLatency + kArmMemoryStoreLatency;
983 last_visited_latency_ = kArmMemoryBarrierLatency;
984 } else {
985 last_visited_latency_ = kArmMemoryStoreLatency;
986 }
987 break;
988
989 case Primitive::kPrimInt:
990 case Primitive::kPrimNot:
991 if (kPoisonHeapReferences && needs_write_barrier) {
992 last_visited_internal_latency_ += kArmIntegerOpLatency * 2;
993 }
994 last_visited_latency_ = kArmMemoryStoreLatency;
995 break;
996
997 case Primitive::kPrimLong:
998 if (is_volatile && !atomic_ldrd_strd) {
999 last_visited_internal_latency_ =
1000 kArmIntegerOpLatency + kArmMemoryLoadLatency + kArmMemoryStoreLatency;
1001 last_visited_latency_ = kArmIntegerOpLatency;
1002 } else {
1003 last_visited_latency_ = kArmMemoryStoreLatency;
1004 }
1005 break;
1006
1007 case Primitive::kPrimFloat:
1008 last_visited_latency_ = kArmMemoryStoreLatency;
1009 break;
1010
1011 case Primitive::kPrimDouble:
1012 if (is_volatile && !atomic_ldrd_strd) {
1013 last_visited_internal_latency_ = kArmIntegerOpLatency +
1014 kArmIntegerOpLatency + kArmMemoryLoadLatency + kArmMemoryStoreLatency;
1015 last_visited_latency_ = kArmIntegerOpLatency;
1016 } else {
1017 last_visited_latency_ = kArmMemoryStoreLatency;
1018 }
1019 break;
1020
1021 default:
1022 last_visited_latency_ = kArmMemoryStoreLatency;
1023 break;
1024 }
1025}
1026
1027void SchedulingLatencyVisitorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
1028 HandleFieldGetLatencies(instruction, instruction->GetFieldInfo());
1029}
1030
1031void SchedulingLatencyVisitorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
1032 HandleFieldSetLatencies(instruction, instruction->GetFieldInfo());
1033}
1034
1035void SchedulingLatencyVisitorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1036 HBasicBlock* block = instruction->GetBlock();
1037 DCHECK((block->GetLoopInformation() != nullptr) ||
1038 (block->IsEntryBlock() && instruction->GetNext()->IsGoto()));
1039 // Users do not use any data results.
1040 last_visited_latency_ = 0;
1041}
1042
1043void SchedulingLatencyVisitorARM::VisitTypeConversion(HTypeConversion* instr) {
1044 Primitive::Type result_type = instr->GetResultType();
1045 Primitive::Type input_type = instr->GetInputType();
1046
1047 switch (result_type) {
1048 case Primitive::kPrimByte:
1049 case Primitive::kPrimChar:
1050 case Primitive::kPrimShort:
1051 last_visited_latency_ = kArmIntegerOpLatency; // SBFX or UBFX
1052 break;
1053
1054 case Primitive::kPrimInt:
1055 switch (input_type) {
1056 case Primitive::kPrimLong:
1057 last_visited_latency_ = kArmIntegerOpLatency; // MOV
1058 break;
1059 case Primitive::kPrimFloat:
1060 case Primitive::kPrimDouble:
1061 last_visited_internal_latency_ = kArmTypeConversionFloatingPointIntegerLatency;
1062 last_visited_latency_ = kArmFloatingPointOpLatency;
1063 break;
1064 default:
1065 last_visited_latency_ = kArmIntegerOpLatency;
1066 break;
1067 }
1068 break;
1069
1070 case Primitive::kPrimLong:
1071 switch (input_type) {
1072 case Primitive::kPrimBoolean:
1073 case Primitive::kPrimByte:
1074 case Primitive::kPrimChar:
1075 case Primitive::kPrimShort:
1076 case Primitive::kPrimInt:
1077 // MOV and extension
1078 last_visited_internal_latency_ = kArmIntegerOpLatency;
1079 last_visited_latency_ = kArmIntegerOpLatency;
1080 break;
1081 case Primitive::kPrimFloat:
1082 case Primitive::kPrimDouble:
1083 // invokes runtime
1084 last_visited_internal_latency_ = kArmCallInternalLatency;
1085 break;
1086 default:
1087 last_visited_internal_latency_ = kArmIntegerOpLatency;
1088 last_visited_latency_ = kArmIntegerOpLatency;
1089 break;
1090 }
1091 break;
1092
1093 case Primitive::kPrimFloat:
1094 switch (input_type) {
1095 case Primitive::kPrimBoolean:
1096 case Primitive::kPrimByte:
1097 case Primitive::kPrimChar:
1098 case Primitive::kPrimShort:
1099 case Primitive::kPrimInt:
1100 last_visited_internal_latency_ = kArmTypeConversionFloatingPointIntegerLatency;
1101 last_visited_latency_ = kArmFloatingPointOpLatency;
1102 break;
1103 case Primitive::kPrimLong:
1104 // invokes runtime
1105 last_visited_internal_latency_ = kArmCallInternalLatency;
1106 break;
1107 case Primitive::kPrimDouble:
1108 last_visited_latency_ = kArmFloatingPointOpLatency;
1109 break;
1110 default:
1111 last_visited_latency_ = kArmFloatingPointOpLatency;
1112 break;
1113 }
1114 break;
1115
1116 case Primitive::kPrimDouble:
1117 switch (input_type) {
1118 case Primitive::kPrimBoolean:
1119 case Primitive::kPrimByte:
1120 case Primitive::kPrimChar:
1121 case Primitive::kPrimShort:
1122 case Primitive::kPrimInt:
1123 last_visited_internal_latency_ = kArmTypeConversionFloatingPointIntegerLatency;
1124 last_visited_latency_ = kArmFloatingPointOpLatency;
1125 break;
1126 case Primitive::kPrimLong:
1127 last_visited_internal_latency_ = 5 * kArmFloatingPointOpLatency;
1128 last_visited_latency_ = kArmFloatingPointOpLatency;
1129 break;
1130 case Primitive::kPrimFloat:
1131 last_visited_latency_ = kArmFloatingPointOpLatency;
1132 break;
1133 default:
1134 last_visited_latency_ = kArmFloatingPointOpLatency;
1135 break;
1136 }
1137 break;
1138
1139 default:
1140 last_visited_latency_ = kArmTypeConversionFloatingPointIntegerLatency;
1141 break;
1142 }
1143}
1144
xueliang.zhongf7caf682017-03-01 16:07:02 +00001145} // namespace arm
1146} // namespace art