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