blob: ea15790105ddcd652199d84278aa47b50faa63d1 [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
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070017#include "scheduler_arm.h"
18
xueliang.zhongf7caf682017-03-01 16:07:02 +000019#include "arch/arm/instruction_set_features_arm.h"
20#include "code_generator_utils.h"
21#include "common_arm.h"
22#include "mirror/array-inl.h"
xueliang.zhongf7caf682017-03-01 16:07:02 +000023
24namespace art {
25namespace arm {
26
27using helpers::Int32ConstantFrom;
28using helpers::Uint64ConstantFrom;
29
30void SchedulingLatencyVisitorARM::HandleBinaryOperationLantencies(HBinaryOperation* instr) {
31 switch (instr->GetResultType()) {
32 case Primitive::kPrimLong:
33 // HAdd and HSub long operations translate to ADDS+ADC or SUBS+SBC pairs,
34 // so a bubble (kArmNopLatency) is added to represent the internal carry flag
35 // dependency inside these pairs.
36 last_visited_internal_latency_ = kArmIntegerOpLatency + kArmNopLatency;
37 last_visited_latency_ = kArmIntegerOpLatency;
38 break;
39 case Primitive::kPrimFloat:
40 case Primitive::kPrimDouble:
41 last_visited_latency_ = kArmFloatingPointOpLatency;
42 break;
43 default:
44 last_visited_latency_ = kArmIntegerOpLatency;
45 break;
46 }
47}
48
49void SchedulingLatencyVisitorARM::VisitAdd(HAdd* instr) {
50 HandleBinaryOperationLantencies(instr);
51}
52
53void SchedulingLatencyVisitorARM::VisitSub(HSub* instr) {
54 HandleBinaryOperationLantencies(instr);
55}
56
57void SchedulingLatencyVisitorARM::VisitMul(HMul* instr) {
58 switch (instr->GetResultType()) {
59 case Primitive::kPrimLong:
60 last_visited_internal_latency_ = 3 * kArmMulIntegerLatency;
61 last_visited_latency_ = kArmIntegerOpLatency;
62 break;
63 case Primitive::kPrimFloat:
64 case Primitive::kPrimDouble:
65 last_visited_latency_ = kArmMulFloatingPointLatency;
66 break;
67 default:
68 last_visited_latency_ = kArmMulIntegerLatency;
69 break;
70 }
71}
72
73void SchedulingLatencyVisitorARM::HandleBitwiseOperationLantencies(HBinaryOperation* instr) {
74 switch (instr->GetResultType()) {
75 case Primitive::kPrimLong:
76 last_visited_internal_latency_ = kArmIntegerOpLatency;
77 last_visited_latency_ = kArmIntegerOpLatency;
78 break;
79 case Primitive::kPrimFloat:
80 case Primitive::kPrimDouble:
81 last_visited_latency_ = kArmFloatingPointOpLatency;
82 break;
83 default:
84 last_visited_latency_ = kArmIntegerOpLatency;
85 break;
86 }
87}
88
89void SchedulingLatencyVisitorARM::VisitAnd(HAnd* instr) {
90 HandleBitwiseOperationLantencies(instr);
91}
92
93void SchedulingLatencyVisitorARM::VisitOr(HOr* instr) {
94 HandleBitwiseOperationLantencies(instr);
95}
96
97void SchedulingLatencyVisitorARM::VisitXor(HXor* instr) {
98 HandleBitwiseOperationLantencies(instr);
99}
100
101void SchedulingLatencyVisitorARM::VisitRor(HRor* instr) {
102 switch (instr->GetResultType()) {
103 case Primitive::kPrimInt:
104 last_visited_latency_ = kArmIntegerOpLatency;
105 break;
106 case Primitive::kPrimLong: {
107 // HandleLongRotate
108 HInstruction* rhs = instr->GetRight();
109 if (rhs->IsConstant()) {
110 uint64_t rot = Uint64ConstantFrom(rhs->AsConstant()) & kMaxLongShiftDistance;
111 if (rot != 0u) {
112 last_visited_internal_latency_ = 3 * kArmIntegerOpLatency;
113 last_visited_latency_ = kArmIntegerOpLatency;
114 } else {
115 last_visited_internal_latency_ = kArmIntegerOpLatency;
116 last_visited_latency_ = kArmIntegerOpLatency;
117 }
118 } else {
119 last_visited_internal_latency_ = 9 * kArmIntegerOpLatency + kArmBranchLatency;
120 last_visited_latency_ = kArmBranchLatency;
121 }
122 break;
123 }
124 default:
125 LOG(FATAL) << "Unexpected operation type " << instr->GetResultType();
126 UNREACHABLE();
127 }
128}
129
130void SchedulingLatencyVisitorARM::HandleShiftLatencies(HBinaryOperation* instr) {
131 Primitive::Type type = instr->GetResultType();
132 HInstruction* rhs = instr->GetRight();
133 switch (type) {
134 case Primitive::kPrimInt:
135 if (!rhs->IsConstant()) {
136 last_visited_internal_latency_ = kArmIntegerOpLatency;
137 }
138 last_visited_latency_ = kArmIntegerOpLatency;
139 break;
140 case Primitive::kPrimLong:
141 if (!rhs->IsConstant()) {
142 last_visited_internal_latency_ = 8 * kArmIntegerOpLatency;
143 } else {
144 uint32_t shift_value = Int32ConstantFrom(rhs->AsConstant()) & kMaxLongShiftDistance;
145 if (shift_value == 1 || shift_value >= 32) {
146 last_visited_internal_latency_ = kArmIntegerOpLatency;
147 } else {
148 last_visited_internal_latency_ = 2 * kArmIntegerOpLatency;
149 }
150 }
151 last_visited_latency_ = kArmIntegerOpLatency;
152 break;
153 default:
154 LOG(FATAL) << "Unexpected operation type " << type;
155 UNREACHABLE();
156 }
157}
158
159void SchedulingLatencyVisitorARM::VisitShl(HShl* instr) {
160 HandleShiftLatencies(instr);
161}
162
163void SchedulingLatencyVisitorARM::VisitShr(HShr* instr) {
164 HandleShiftLatencies(instr);
165}
166
167void SchedulingLatencyVisitorARM::VisitUShr(HUShr* instr) {
168 HandleShiftLatencies(instr);
169}
170
xueliang.zhongbf9e21a2017-06-15 11:01:11 +0100171void SchedulingLatencyVisitorARM::HandleGenerateConditionWithZero(IfCondition condition) {
172 switch (condition) {
173 case kCondEQ:
174 case kCondBE:
175 case kCondNE:
176 case kCondA:
177 last_visited_internal_latency_ += kArmIntegerOpLatency;
178 last_visited_latency_ = kArmIntegerOpLatency;
xueliang.zhongf7caf682017-03-01 16:07:02 +0000179 break;
xueliang.zhongbf9e21a2017-06-15 11:01:11 +0100180 case kCondGE:
181 // Mvn
182 last_visited_internal_latency_ += kArmIntegerOpLatency;
183 FALLTHROUGH_INTENDED;
184 case kCondLT:
185 // Lsr
186 last_visited_latency_ = kArmIntegerOpLatency;
187 break;
188 case kCondAE:
189 // Trivially true.
190 // Mov
191 last_visited_latency_ = kArmIntegerOpLatency;
192 break;
193 case kCondB:
194 // Trivially false.
195 // Mov
196 last_visited_latency_ = kArmIntegerOpLatency;
xueliang.zhongf7caf682017-03-01 16:07:02 +0000197 break;
198 default:
xueliang.zhongbf9e21a2017-06-15 11:01:11 +0100199 LOG(FATAL) << "Unexpected condition " << condition;
200 UNREACHABLE();
xueliang.zhongf7caf682017-03-01 16:07:02 +0000201 }
xueliang.zhongbf9e21a2017-06-15 11:01:11 +0100202}
203
204void SchedulingLatencyVisitorARM::HandleGenerateLongTestConstant(HCondition* condition) {
205 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
206
207 IfCondition cond = condition->GetCondition();
208
209 HInstruction* right = condition->InputAt(1);
210
211 int64_t value = Uint64ConstantFrom(right);
212
213 // Comparisons against 0 are common enough, so codegen has special handling for them.
214 if (value == 0) {
215 switch (cond) {
216 case kCondNE:
217 case kCondA:
218 case kCondEQ:
219 case kCondBE:
220 // Orrs
221 last_visited_internal_latency_ += kArmIntegerOpLatency;
222 return;
223 case kCondLT:
224 case kCondGE:
225 // Cmp
226 last_visited_internal_latency_ += kArmIntegerOpLatency;
227 return;
228 case kCondB:
229 case kCondAE:
230 // Cmp
231 last_visited_internal_latency_ += kArmIntegerOpLatency;
232 return;
233 default:
234 break;
235 }
236 }
237
238 switch (cond) {
239 case kCondEQ:
240 case kCondNE:
241 case kCondB:
242 case kCondBE:
243 case kCondA:
244 case kCondAE: {
245 // Cmp, IT, Cmp
246 last_visited_internal_latency_ += 3 * kArmIntegerOpLatency;
247 break;
248 }
249 case kCondLE:
250 case kCondGT:
251 // Trivially true or false.
252 if (value == std::numeric_limits<int64_t>::max()) {
253 // Cmp
254 last_visited_internal_latency_ += kArmIntegerOpLatency;
255 break;
256 }
257 FALLTHROUGH_INTENDED;
258 case kCondGE:
259 case kCondLT: {
260 // Cmp, Sbcs
261 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
262 break;
263 }
264 default:
265 LOG(FATAL) << "Unreachable";
266 UNREACHABLE();
267 }
268}
269
270void SchedulingLatencyVisitorARM::HandleGenerateLongTest(HCondition* condition) {
271 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
272
273 IfCondition cond = condition->GetCondition();
274
275 switch (cond) {
276 case kCondEQ:
277 case kCondNE:
278 case kCondB:
279 case kCondBE:
280 case kCondA:
281 case kCondAE: {
282 // Cmp, IT, Cmp
283 last_visited_internal_latency_ += 3 * kArmIntegerOpLatency;
284 break;
285 }
286 case kCondLE:
287 case kCondGT:
288 case kCondGE:
289 case kCondLT: {
290 // Cmp, Sbcs
291 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
292 break;
293 }
294 default:
295 LOG(FATAL) << "Unreachable";
296 UNREACHABLE();
297 }
298}
299
300// The GenerateTest series of function all counted as internal latency.
301void SchedulingLatencyVisitorARM::HandleGenerateTest(HCondition* condition) {
302 const Primitive::Type type = condition->GetLeft()->GetType();
303
304 if (type == Primitive::kPrimLong) {
305 condition->InputAt(1)->IsConstant()
306 ? HandleGenerateLongTestConstant(condition)
307 : HandleGenerateLongTest(condition);
308 } else if (Primitive::IsFloatingPointType(type)) {
309 // GenerateVcmp + Vmrs
310 last_visited_internal_latency_ += 2 * kArmFloatingPointOpLatency;
311 } else {
312 // Cmp
313 last_visited_internal_latency_ += kArmIntegerOpLatency;
314 }
315}
316
317bool SchedulingLatencyVisitorARM::CanGenerateTest(HCondition* condition) {
318 if (condition->GetLeft()->GetType() == Primitive::kPrimLong) {
319 HInstruction* right = condition->InputAt(1);
320
321 if (right->IsConstant()) {
322 IfCondition c = condition->GetCondition();
323 const uint64_t value = Uint64ConstantFrom(right);
324
325 if (c < kCondLT || c > kCondGE) {
326 if (value != 0) {
327 return false;
328 }
329 } else if (c == kCondLE || c == kCondGT) {
330 if (value < std::numeric_limits<int64_t>::max() &&
331 !codegen_->GetAssembler()->ShifterOperandCanHold(SBC, High32Bits(value + 1), kCcSet)) {
332 return false;
333 }
334 } else if (!codegen_->GetAssembler()->ShifterOperandCanHold(SBC, High32Bits(value), kCcSet)) {
335 return false;
336 }
337 }
338 }
339
340 return true;
341}
342
343void SchedulingLatencyVisitorARM::HandleGenerateConditionGeneric(HCondition* cond) {
344 HandleGenerateTest(cond);
345
346 // Unlike codegen pass, we cannot check 'out' register IsLow() here,
347 // because scheduling is before liveness(location builder) and register allocator,
348 // so we can only choose to follow one path of codegen by assuming otu.IsLow() is true.
349 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
xueliang.zhongf7caf682017-03-01 16:07:02 +0000350 last_visited_latency_ = kArmIntegerOpLatency;
351}
352
xueliang.zhongbf9e21a2017-06-15 11:01:11 +0100353void SchedulingLatencyVisitorARM::HandleGenerateEqualLong(HCondition* cond) {
354 DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
355
356 IfCondition condition = cond->GetCondition();
357
358 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
359
360 if (condition == kCondNE) {
361 // Orrs, IT, Mov
362 last_visited_internal_latency_ += 3 * kArmIntegerOpLatency;
363 } else {
364 last_visited_internal_latency_ += kArmIntegerOpLatency;
365 HandleGenerateConditionWithZero(condition);
366 }
367}
368
369void SchedulingLatencyVisitorARM::HandleGenerateLongComparesAndJumps() {
370 last_visited_internal_latency_ += 4 * kArmIntegerOpLatency;
371 last_visited_internal_latency_ += kArmBranchLatency;
372}
373
374void SchedulingLatencyVisitorARM::HandleGenerateConditionLong(HCondition* cond) {
375 DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
376
377 IfCondition condition = cond->GetCondition();
378 HInstruction* right = cond->InputAt(1);
379
380 if (right->IsConstant()) {
381 // Comparisons against 0 are common enough, so codegen has special handling for them.
382 if (Uint64ConstantFrom(right) == 0) {
383 switch (condition) {
384 case kCondNE:
385 case kCondA:
386 case kCondEQ:
387 case kCondBE:
388 // Orr
389 last_visited_internal_latency_ += kArmIntegerOpLatency;
390 HandleGenerateConditionWithZero(condition);
391 return;
392 case kCondLT:
393 case kCondGE:
394 FALLTHROUGH_INTENDED;
395 case kCondAE:
396 case kCondB:
397 HandleGenerateConditionWithZero(condition);
398 return;
399 case kCondLE:
400 case kCondGT:
401 default:
402 break;
403 }
404 }
405 }
406
407 if ((condition == kCondEQ || condition == kCondNE) &&
408 !CanGenerateTest(cond)) {
409 HandleGenerateEqualLong(cond);
410 return;
411 }
412
413 if (CanGenerateTest(cond)) {
414 HandleGenerateConditionGeneric(cond);
415 return;
416 }
417
418 HandleGenerateLongComparesAndJumps();
419
420 last_visited_internal_latency_ += kArmIntegerOpLatency;
421 last_visited_latency_ = kArmBranchLatency;;
422}
423
424void SchedulingLatencyVisitorARM::HandleGenerateConditionIntegralOrNonPrimitive(HCondition* cond) {
425 const Primitive::Type type = cond->GetLeft()->GetType();
426
427 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
428
429 if (type == Primitive::kPrimLong) {
430 HandleGenerateConditionLong(cond);
431 return;
432 }
433
434 IfCondition condition = cond->GetCondition();
435 HInstruction* right = cond->InputAt(1);
436 int64_t value;
437
438 if (right->IsConstant()) {
439 value = Uint64ConstantFrom(right);
440
441 // Comparisons against 0 are common enough, so codegen has special handling for them.
442 if (value == 0) {
443 switch (condition) {
444 case kCondNE:
445 case kCondA:
446 case kCondEQ:
447 case kCondBE:
448 case kCondLT:
449 case kCondGE:
450 case kCondAE:
451 case kCondB:
452 HandleGenerateConditionWithZero(condition);
453 return;
454 case kCondLE:
455 case kCondGT:
456 default:
457 break;
458 }
459 }
460 }
461
462 if (condition == kCondEQ || condition == kCondNE) {
463 if (condition == kCondNE) {
464 // CMP, IT, MOV.ne
465 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
466 last_visited_latency_ = kArmIntegerOpLatency;
467 } else {
468 last_visited_internal_latency_ += kArmIntegerOpLatency;
469 HandleGenerateConditionWithZero(condition);
470 }
471 return;
472 }
473
474 HandleGenerateConditionGeneric(cond);
475}
476
477void SchedulingLatencyVisitorARM::HandleCondition(HCondition* cond) {
478 if (cond->IsEmittedAtUseSite()) {
479 last_visited_latency_ = 0;
480 return;
481 }
482
483 const Primitive::Type type = cond->GetLeft()->GetType();
484
485 if (Primitive::IsFloatingPointType(type)) {
486 HandleGenerateConditionGeneric(cond);
487 return;
488 }
489
490 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
491
492 const IfCondition condition = cond->GetCondition();
493
494 if (type == Primitive::kPrimBoolean &&
495 cond->GetRight()->GetType() == Primitive::kPrimBoolean &&
496 (condition == kCondEQ || condition == kCondNE)) {
497 if (condition == kCondEQ) {
498 last_visited_internal_latency_ = kArmIntegerOpLatency;
499 }
500 last_visited_latency_ = kArmIntegerOpLatency;
501 return;
502 }
503
504 HandleGenerateConditionIntegralOrNonPrimitive(cond);
505}
506
507void SchedulingLatencyVisitorARM::VisitCondition(HCondition* instr) {
508 HandleCondition(instr);
509}
510
xueliang.zhongf7caf682017-03-01 16:07:02 +0000511void SchedulingLatencyVisitorARM::VisitCompare(HCompare* instr) {
512 Primitive::Type type = instr->InputAt(0)->GetType();
513 switch (type) {
514 case Primitive::kPrimBoolean:
515 case Primitive::kPrimByte:
516 case Primitive::kPrimShort:
517 case Primitive::kPrimChar:
518 case Primitive::kPrimInt:
519 last_visited_internal_latency_ = 2 * kArmIntegerOpLatency;
520 break;
521 case Primitive::kPrimLong:
522 last_visited_internal_latency_ = 2 * kArmIntegerOpLatency + 3 * kArmBranchLatency;
523 break;
524 case Primitive::kPrimFloat:
525 case Primitive::kPrimDouble:
526 last_visited_internal_latency_ = kArmIntegerOpLatency + 2 * kArmFloatingPointOpLatency;
527 break;
528 default:
529 last_visited_internal_latency_ = 2 * kArmIntegerOpLatency;
530 break;
531 }
532 last_visited_latency_ = kArmIntegerOpLatency;
533}
534
535void SchedulingLatencyVisitorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
536 if (instruction->GetResultType() == Primitive::kPrimInt) {
537 last_visited_latency_ = kArmIntegerOpLatency;
538 } else {
539 last_visited_internal_latency_ = kArmIntegerOpLatency;
540 last_visited_latency_ = kArmIntegerOpLatency;
541 }
542}
543
544void SchedulingLatencyVisitorARM::HandleGenerateDataProcInstruction(bool internal_latency) {
545 if (internal_latency) {
546 last_visited_internal_latency_ += kArmIntegerOpLatency;
547 } else {
548 last_visited_latency_ = kArmDataProcWithShifterOpLatency;
549 }
550}
551
552void SchedulingLatencyVisitorARM::HandleGenerateDataProc(HDataProcWithShifterOp* instruction) {
553 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
554 if (kind == HInstruction::kAdd) {
555 last_visited_internal_latency_ = kArmIntegerOpLatency;
556 last_visited_latency_ = kArmIntegerOpLatency;
557 } else if (kind == HInstruction::kSub) {
558 last_visited_internal_latency_ = kArmIntegerOpLatency;
559 last_visited_latency_ = kArmIntegerOpLatency;
560 } else {
561 HandleGenerateDataProcInstruction(/* internal_latency */ true);
562 HandleGenerateDataProcInstruction();
563 }
564}
565
566void SchedulingLatencyVisitorARM::HandleGenerateLongDataProc(HDataProcWithShifterOp* instruction) {
567 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
568 DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
569
570 const uint32_t shift_value = instruction->GetShiftAmount();
571 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
572
573 if (shift_value >= 32) {
574 // Different shift types actually generate similar code here,
575 // no need to differentiate shift types like the codegen pass does,
576 // which also avoids handling shift types from different ARM backends.
577 HandleGenerateDataProc(instruction);
578 } else {
579 DCHECK_GT(shift_value, 1U);
580 DCHECK_LT(shift_value, 32U);
581
582 if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
583 HandleGenerateDataProcInstruction(/* internal_latency */ true);
584 HandleGenerateDataProcInstruction(/* internal_latency */ true);
585 HandleGenerateDataProcInstruction();
586 } else {
587 last_visited_internal_latency_ += 2 * kArmIntegerOpLatency;
588 HandleGenerateDataProc(instruction);
589 }
590 }
591}
592
593void SchedulingLatencyVisitorARM::VisitDataProcWithShifterOp(HDataProcWithShifterOp* instruction) {
594 const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
595
596 if (instruction->GetType() == Primitive::kPrimInt) {
xueliang.zhongf7caf682017-03-01 16:07:02 +0000597 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