blob: f54d3f3de252bb0874114443f06746115cf734ce [file] [log] [blame]
Alexandre Rames22aa54b2016-10-18 09:32:29 +01001/*
2 * Copyright (C) 2016 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 "scheduler_arm64.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070018
Alexandre Rames22aa54b2016-10-18 09:32:29 +010019#include "code_generator_utils.h"
Artem Serovf0fc4c62017-05-03 15:07:15 +010020#include "mirror/array-inl.h"
Alexandre Rames22aa54b2016-10-18 09:32:29 +010021
22namespace art {
23namespace arm64 {
24
25void SchedulingLatencyVisitorARM64::VisitBinaryOperation(HBinaryOperation* instr) {
26 last_visited_latency_ = Primitive::IsFloatingPointType(instr->GetResultType())
27 ? kArm64FloatingPointOpLatency
28 : kArm64IntegerOpLatency;
29}
30
31void SchedulingLatencyVisitorARM64::VisitBitwiseNegatedRight(
32 HBitwiseNegatedRight* ATTRIBUTE_UNUSED) {
33 last_visited_latency_ = kArm64IntegerOpLatency;
34}
35
Anton Kirilov74234da2017-01-13 14:42:47 +000036void SchedulingLatencyVisitorARM64::VisitDataProcWithShifterOp(
37 HDataProcWithShifterOp* ATTRIBUTE_UNUSED) {
Alexandre Rames22aa54b2016-10-18 09:32:29 +010038 last_visited_latency_ = kArm64DataProcWithShifterOpLatency;
39}
40
41void SchedulingLatencyVisitorARM64::VisitIntermediateAddress(
42 HIntermediateAddress* ATTRIBUTE_UNUSED) {
43 // Although the code generated is a simple `add` instruction, we found through empirical results
44 // that spacing it from its use in memory accesses was beneficial.
45 last_visited_latency_ = kArm64IntegerOpLatency + 2;
46}
47
Artem Serovf0fc4c62017-05-03 15:07:15 +010048void SchedulingLatencyVisitorARM64::VisitIntermediateAddressIndex(
49 HIntermediateAddressIndex* instr ATTRIBUTE_UNUSED) {
50 // Although the code generated is a simple `add` instruction, we found through empirical results
51 // that spacing it from its use in memory accesses was beneficial.
52 last_visited_latency_ = kArm64DataProcWithShifterOpLatency + 2;
53}
54
Alexandre Rames22aa54b2016-10-18 09:32:29 +010055void SchedulingLatencyVisitorARM64::VisitMultiplyAccumulate(HMultiplyAccumulate* ATTRIBUTE_UNUSED) {
56 last_visited_latency_ = kArm64MulIntegerLatency;
57}
58
59void SchedulingLatencyVisitorARM64::VisitArrayGet(HArrayGet* instruction) {
60 if (!instruction->GetArray()->IsIntermediateAddress()) {
61 // Take the intermediate address computation into account.
62 last_visited_internal_latency_ = kArm64IntegerOpLatency;
63 }
64 last_visited_latency_ = kArm64MemoryLoadLatency;
65}
66
67void SchedulingLatencyVisitorARM64::VisitArrayLength(HArrayLength* ATTRIBUTE_UNUSED) {
68 last_visited_latency_ = kArm64MemoryLoadLatency;
69}
70
71void SchedulingLatencyVisitorARM64::VisitArraySet(HArraySet* ATTRIBUTE_UNUSED) {
72 last_visited_latency_ = kArm64MemoryStoreLatency;
73}
74
75void SchedulingLatencyVisitorARM64::VisitBoundsCheck(HBoundsCheck* ATTRIBUTE_UNUSED) {
76 last_visited_internal_latency_ = kArm64IntegerOpLatency;
77 // Users do not use any data results.
78 last_visited_latency_ = 0;
79}
80
81void SchedulingLatencyVisitorARM64::VisitDiv(HDiv* instr) {
82 Primitive::Type type = instr->GetResultType();
83 switch (type) {
84 case Primitive::kPrimFloat:
85 last_visited_latency_ = kArm64DivFloatLatency;
86 break;
87 case Primitive::kPrimDouble:
88 last_visited_latency_ = kArm64DivDoubleLatency;
89 break;
90 default:
91 // Follow the code path used by code generation.
92 if (instr->GetRight()->IsConstant()) {
93 int64_t imm = Int64FromConstant(instr->GetRight()->AsConstant());
94 if (imm == 0) {
95 last_visited_internal_latency_ = 0;
96 last_visited_latency_ = 0;
97 } else if (imm == 1 || imm == -1) {
98 last_visited_internal_latency_ = 0;
99 last_visited_latency_ = kArm64IntegerOpLatency;
100 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
101 last_visited_internal_latency_ = 4 * kArm64IntegerOpLatency;
102 last_visited_latency_ = kArm64IntegerOpLatency;
103 } else {
104 DCHECK(imm <= -2 || imm >= 2);
105 last_visited_internal_latency_ = 4 * kArm64IntegerOpLatency;
106 last_visited_latency_ = kArm64MulIntegerLatency;
107 }
108 } else {
109 last_visited_latency_ = kArm64DivIntegerLatency;
110 }
111 break;
112 }
113}
114
115void SchedulingLatencyVisitorARM64::VisitInstanceFieldGet(HInstanceFieldGet* ATTRIBUTE_UNUSED) {
116 last_visited_latency_ = kArm64MemoryLoadLatency;
117}
118
119void SchedulingLatencyVisitorARM64::VisitInstanceOf(HInstanceOf* ATTRIBUTE_UNUSED) {
120 last_visited_internal_latency_ = kArm64CallInternalLatency;
121 last_visited_latency_ = kArm64IntegerOpLatency;
122}
123
124void SchedulingLatencyVisitorARM64::VisitInvoke(HInvoke* ATTRIBUTE_UNUSED) {
125 last_visited_internal_latency_ = kArm64CallInternalLatency;
126 last_visited_latency_ = kArm64CallLatency;
127}
128
129void SchedulingLatencyVisitorARM64::VisitLoadString(HLoadString* ATTRIBUTE_UNUSED) {
130 last_visited_internal_latency_ = kArm64LoadStringInternalLatency;
131 last_visited_latency_ = kArm64MemoryLoadLatency;
132}
133
134void SchedulingLatencyVisitorARM64::VisitMul(HMul* instr) {
135 last_visited_latency_ = Primitive::IsFloatingPointType(instr->GetResultType())
136 ? kArm64MulFloatingPointLatency
137 : kArm64MulIntegerLatency;
138}
139
140void SchedulingLatencyVisitorARM64::VisitNewArray(HNewArray* ATTRIBUTE_UNUSED) {
141 last_visited_internal_latency_ = kArm64IntegerOpLatency + kArm64CallInternalLatency;
142 last_visited_latency_ = kArm64CallLatency;
143}
144
145void SchedulingLatencyVisitorARM64::VisitNewInstance(HNewInstance* instruction) {
146 if (instruction->IsStringAlloc()) {
147 last_visited_internal_latency_ = 2 + kArm64MemoryLoadLatency + kArm64CallInternalLatency;
148 } else {
149 last_visited_internal_latency_ = kArm64CallInternalLatency;
150 }
151 last_visited_latency_ = kArm64CallLatency;
152}
153
154void SchedulingLatencyVisitorARM64::VisitRem(HRem* instruction) {
155 if (Primitive::IsFloatingPointType(instruction->GetResultType())) {
156 last_visited_internal_latency_ = kArm64CallInternalLatency;
157 last_visited_latency_ = kArm64CallLatency;
158 } else {
159 // Follow the code path used by code generation.
160 if (instruction->GetRight()->IsConstant()) {
161 int64_t imm = Int64FromConstant(instruction->GetRight()->AsConstant());
162 if (imm == 0) {
163 last_visited_internal_latency_ = 0;
164 last_visited_latency_ = 0;
165 } else if (imm == 1 || imm == -1) {
166 last_visited_internal_latency_ = 0;
167 last_visited_latency_ = kArm64IntegerOpLatency;
168 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
169 last_visited_internal_latency_ = 4 * kArm64IntegerOpLatency;
170 last_visited_latency_ = kArm64IntegerOpLatency;
171 } else {
172 DCHECK(imm <= -2 || imm >= 2);
173 last_visited_internal_latency_ = 4 * kArm64IntegerOpLatency;
174 last_visited_latency_ = kArm64MulIntegerLatency;
175 }
176 } else {
177 last_visited_internal_latency_ = kArm64DivIntegerLatency;
178 last_visited_latency_ = kArm64MulIntegerLatency;
179 }
180 }
181}
182
183void SchedulingLatencyVisitorARM64::VisitStaticFieldGet(HStaticFieldGet* ATTRIBUTE_UNUSED) {
184 last_visited_latency_ = kArm64MemoryLoadLatency;
185}
186
187void SchedulingLatencyVisitorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
188 HBasicBlock* block = instruction->GetBlock();
189 DCHECK((block->GetLoopInformation() != nullptr) ||
190 (block->IsEntryBlock() && instruction->GetNext()->IsGoto()));
191 // Users do not use any data results.
192 last_visited_latency_ = 0;
193}
194
195void SchedulingLatencyVisitorARM64::VisitTypeConversion(HTypeConversion* instr) {
196 if (Primitive::IsFloatingPointType(instr->GetResultType()) ||
197 Primitive::IsFloatingPointType(instr->GetInputType())) {
198 last_visited_latency_ = kArm64TypeConversionFloatingPointIntegerLatency;
199 } else {
200 last_visited_latency_ = kArm64IntegerOpLatency;
201 }
202}
203
Artem Serovf0fc4c62017-05-03 15:07:15 +0100204void SchedulingLatencyVisitorARM64::HandleSimpleArithmeticSIMD(HVecOperation *instr) {
205 if (Primitive::IsFloatingPointType(instr->GetPackedType())) {
206 last_visited_latency_ = kArm64SIMDFloatingPointOpLatency;
207 } else {
208 last_visited_latency_ = kArm64SIMDIntegerOpLatency;
209 }
210}
211
212void SchedulingLatencyVisitorARM64::VisitVecReplicateScalar(
213 HVecReplicateScalar* instr ATTRIBUTE_UNUSED) {
214 last_visited_latency_ = kArm64SIMDReplicateOpLatency;
215}
216
217void SchedulingLatencyVisitorARM64::VisitVecSetScalars(HVecSetScalars* instr) {
218 LOG(FATAL) << "Unsupported SIMD instruction " << instr->GetId();
219}
220
221void SchedulingLatencyVisitorARM64::VisitVecSumReduce(HVecSumReduce* instr) {
222 LOG(FATAL) << "Unsupported SIMD instruction " << instr->GetId();
223}
224
225void SchedulingLatencyVisitorARM64::VisitVecCnv(HVecCnv* instr ATTRIBUTE_UNUSED) {
226 last_visited_latency_ = kArm64SIMDTypeConversionInt2FPLatency;
227}
228
229void SchedulingLatencyVisitorARM64::VisitVecNeg(HVecNeg* instr) {
230 HandleSimpleArithmeticSIMD(instr);
231}
232
233void SchedulingLatencyVisitorARM64::VisitVecAbs(HVecAbs* instr) {
234 HandleSimpleArithmeticSIMD(instr);
235}
236
237void SchedulingLatencyVisitorARM64::VisitVecNot(HVecNot* instr) {
238 if (instr->GetPackedType() == Primitive::kPrimBoolean) {
239 last_visited_internal_latency_ = kArm64SIMDIntegerOpLatency;
240 }
241 last_visited_latency_ = kArm64SIMDIntegerOpLatency;
242}
243
244void SchedulingLatencyVisitorARM64::VisitVecAdd(HVecAdd* instr) {
245 HandleSimpleArithmeticSIMD(instr);
246}
247
248void SchedulingLatencyVisitorARM64::VisitVecHalvingAdd(HVecHalvingAdd* instr) {
249 HandleSimpleArithmeticSIMD(instr);
250}
251
252void SchedulingLatencyVisitorARM64::VisitVecSub(HVecSub* instr) {
253 HandleSimpleArithmeticSIMD(instr);
254}
255
256void SchedulingLatencyVisitorARM64::VisitVecMul(HVecMul* instr) {
257 if (Primitive::IsFloatingPointType(instr->GetPackedType())) {
258 last_visited_latency_ = kArm64SIMDMulFloatingPointLatency;
259 } else {
260 last_visited_latency_ = kArm64SIMDMulIntegerLatency;
261 }
262}
263
264void SchedulingLatencyVisitorARM64::VisitVecDiv(HVecDiv* instr) {
265 if (instr->GetPackedType() == Primitive::kPrimFloat) {
266 last_visited_latency_ = kArm64SIMDDivFloatLatency;
267 } else {
268 DCHECK(instr->GetPackedType() == Primitive::kPrimDouble);
269 last_visited_latency_ = kArm64SIMDDivDoubleLatency;
270 }
271}
272
273void SchedulingLatencyVisitorARM64::VisitVecMin(HVecMin* instr) {
274 HandleSimpleArithmeticSIMD(instr);
275}
276
277void SchedulingLatencyVisitorARM64::VisitVecMax(HVecMax* instr) {
278 HandleSimpleArithmeticSIMD(instr);
279}
280
281void SchedulingLatencyVisitorARM64::VisitVecAnd(HVecAnd* instr ATTRIBUTE_UNUSED) {
282 last_visited_latency_ = kArm64SIMDIntegerOpLatency;
283}
284
285void SchedulingLatencyVisitorARM64::VisitVecAndNot(HVecAndNot* instr) {
286 LOG(FATAL) << "Unsupported SIMD instruction " << instr->GetId();
287}
288
289void SchedulingLatencyVisitorARM64::VisitVecOr(HVecOr* instr ATTRIBUTE_UNUSED) {
290 last_visited_latency_ = kArm64SIMDIntegerOpLatency;
291}
292
293void SchedulingLatencyVisitorARM64::VisitVecXor(HVecXor* instr ATTRIBUTE_UNUSED) {
294 last_visited_latency_ = kArm64SIMDIntegerOpLatency;
295}
296
297void SchedulingLatencyVisitorARM64::VisitVecShl(HVecShl* instr) {
298 HandleSimpleArithmeticSIMD(instr);
299}
300
301void SchedulingLatencyVisitorARM64::VisitVecShr(HVecShr* instr) {
302 HandleSimpleArithmeticSIMD(instr);
303}
304
305void SchedulingLatencyVisitorARM64::VisitVecUShr(HVecUShr* instr) {
306 HandleSimpleArithmeticSIMD(instr);
307}
308
309void SchedulingLatencyVisitorARM64::VisitVecMultiplyAccumulate(
310 HVecMultiplyAccumulate* instr ATTRIBUTE_UNUSED) {
311 last_visited_latency_ = kArm64SIMDMulIntegerLatency;
312}
313
314void SchedulingLatencyVisitorARM64::HandleVecAddress(
315 HVecMemoryOperation* instruction,
316 size_t size ATTRIBUTE_UNUSED) {
317 HInstruction* index = instruction->InputAt(1);
318 if (!index->IsConstant()) {
319 last_visited_internal_latency_ += kArm64DataProcWithShifterOpLatency;
320 }
321}
322
323void SchedulingLatencyVisitorARM64::VisitVecLoad(HVecLoad* instr) {
324 last_visited_internal_latency_ = 0;
325 size_t size = Primitive::ComponentSize(instr->GetPackedType());
326
327 if (instr->GetPackedType() == Primitive::kPrimChar
328 && mirror::kUseStringCompression
329 && instr->IsStringCharAt()) {
330 // Set latencies for the uncompressed case.
331 last_visited_internal_latency_ += kArm64MemoryLoadLatency + kArm64BranchLatency;
332 HandleVecAddress(instr, size);
333 last_visited_latency_ = kArm64SIMDMemoryLoadLatency;
334 } else {
335 HandleVecAddress(instr, size);
336 last_visited_latency_ = kArm64SIMDMemoryLoadLatency;
337 }
338}
339
340void SchedulingLatencyVisitorARM64::VisitVecStore(HVecStore* instr) {
341 last_visited_internal_latency_ = 0;
342 size_t size = Primitive::ComponentSize(instr->GetPackedType());
343 HandleVecAddress(instr, size);
344 last_visited_latency_ = kArm64SIMDMemoryStoreLatency;
345}
346
Alexandre Rames22aa54b2016-10-18 09:32:29 +0100347} // namespace arm64
348} // namespace art