blob: 226f109bec49e385bfdc456080cae876f88749ba [file] [log] [blame]
Scott Wakelingfe885462016-09-22 10:24:38 +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 "code_generator_arm_vixl.h"
18
19#include "arch/arm/instruction_set_features_arm.h"
20#include "art_method.h"
21#include "code_generator_utils.h"
22#include "common_arm.h"
23#include "compiled_method.h"
24#include "entrypoints/quick/quick_entrypoints.h"
25#include "gc/accounting/card_table.h"
26#include "mirror/array-inl.h"
27#include "mirror/class-inl.h"
28#include "thread.h"
29#include "utils/arm/assembler_arm_vixl.h"
30#include "utils/arm/managed_register_arm.h"
31#include "utils/assembler.h"
32#include "utils/stack_checks.h"
33
34namespace art {
35namespace arm {
36
37namespace vixl32 = vixl::aarch32;
38using namespace vixl32; // NOLINT(build/namespaces)
39
40using helpers::DWARFReg;
41using helpers::FromLowSToD;
42using helpers::OutputRegister;
43using helpers::InputRegisterAt;
44using helpers::InputOperandAt;
45using helpers::OutputSRegister;
46using helpers::InputSRegisterAt;
47
48using RegisterList = vixl32::RegisterList;
49
50static bool ExpectedPairLayout(Location location) {
51 // We expected this for both core and fpu register pairs.
52 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
53}
54
55static constexpr size_t kArmInstrMaxSizeInBytes = 4u;
56
57#ifdef __
58#error "ARM Codegen VIXL macro-assembler macro already defined."
59#endif
60
61// TODO: Remove with later pop when codegen complete.
62#pragma GCC diagnostic push
63#pragma GCC diagnostic ignored "-Wunused-parameter"
64
65// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
66#define __ down_cast<CodeGeneratorARMVIXL*>(codegen)->GetVIXLAssembler()-> // NOLINT
67#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmPointerSize, x).Int32Value()
68
69// Marker that code is yet to be, and must, be implemented.
70#define TODO_VIXL32(level) LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
71
72class DivZeroCheckSlowPathARMVIXL : public SlowPathCodeARMVIXL {
73 public:
74 explicit DivZeroCheckSlowPathARMVIXL(HDivZeroCheck* instruction)
75 : SlowPathCodeARMVIXL(instruction) {}
76
77 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
78 CodeGeneratorARMVIXL* armvixl_codegen = down_cast<CodeGeneratorARMVIXL*>(codegen);
79 __ Bind(GetEntryLabel());
80 if (instruction_->CanThrowIntoCatchBlock()) {
81 // Live registers will be restored in the catch block if caught.
82 SaveLiveRegisters(codegen, instruction_->GetLocations());
83 }
84 armvixl_codegen->InvokeRuntime(kQuickThrowDivZero,
85 instruction_,
86 instruction_->GetDexPc(),
87 this);
88 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
89 }
90
91 bool IsFatal() const OVERRIDE { return true; }
92
93 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARMVIXL"; }
94
95 private:
96 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARMVIXL);
97};
98
99inline vixl32::Condition ARMCondition(IfCondition cond) {
100 switch (cond) {
101 case kCondEQ: return eq;
102 case kCondNE: return ne;
103 case kCondLT: return lt;
104 case kCondLE: return le;
105 case kCondGT: return gt;
106 case kCondGE: return ge;
107 case kCondB: return lo;
108 case kCondBE: return ls;
109 case kCondA: return hi;
110 case kCondAE: return hs;
111 }
112 LOG(FATAL) << "Unreachable";
113 UNREACHABLE();
114}
115
116// Maps signed condition to unsigned condition.
117inline vixl32::Condition ARMUnsignedCondition(IfCondition cond) {
118 switch (cond) {
119 case kCondEQ: return eq;
120 case kCondNE: return ne;
121 // Signed to unsigned.
122 case kCondLT: return lo;
123 case kCondLE: return ls;
124 case kCondGT: return hi;
125 case kCondGE: return hs;
126 // Unsigned remain unchanged.
127 case kCondB: return lo;
128 case kCondBE: return ls;
129 case kCondA: return hi;
130 case kCondAE: return hs;
131 }
132 LOG(FATAL) << "Unreachable";
133 UNREACHABLE();
134}
135
136inline vixl32::Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
137 // The ARM condition codes can express all the necessary branches, see the
138 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
139 // There is no dex instruction or HIR that would need the missing conditions
140 // "equal or unordered" or "not equal".
141 switch (cond) {
142 case kCondEQ: return eq;
143 case kCondNE: return ne /* unordered */;
144 case kCondLT: return gt_bias ? cc : lt /* unordered */;
145 case kCondLE: return gt_bias ? ls : le /* unordered */;
146 case kCondGT: return gt_bias ? hi /* unordered */ : gt;
147 case kCondGE: return gt_bias ? cs /* unordered */ : ge;
148 default:
149 LOG(FATAL) << "UNREACHABLE";
150 UNREACHABLE();
151 }
152}
153
154void SlowPathCodeARMVIXL::SaveLiveRegisters(CodeGenerator* codegen ATTRIBUTE_UNUSED,
155 LocationSummary* locations ATTRIBUTE_UNUSED) {
156 TODO_VIXL32(FATAL);
157}
158
159void SlowPathCodeARMVIXL::RestoreLiveRegisters(CodeGenerator* codegen ATTRIBUTE_UNUSED,
160 LocationSummary* locations ATTRIBUTE_UNUSED) {
161 TODO_VIXL32(FATAL);
162}
163
164void CodeGeneratorARMVIXL::DumpCoreRegister(std::ostream& stream, int reg) const {
165 stream << vixl32::Register(reg);
166}
167
168void CodeGeneratorARMVIXL::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
169 stream << vixl32::SRegister(reg);
170}
171
172static uint32_t ComputeSRegisterMask(const SRegisterList& regs) {
173 uint32_t mask = 0;
174 for (uint32_t i = regs.GetFirstSRegister().GetCode();
175 i <= regs.GetLastSRegister().GetCode();
176 ++i) {
177 mask |= (1 << i);
178 }
179 return mask;
180}
181
182#undef __
183
184CodeGeneratorARMVIXL::CodeGeneratorARMVIXL(HGraph* graph,
185 const ArmInstructionSetFeatures& isa_features,
186 const CompilerOptions& compiler_options,
187 OptimizingCompilerStats* stats)
188 : CodeGenerator(graph,
189 kNumberOfCoreRegisters,
190 kNumberOfSRegisters,
191 kNumberOfRegisterPairs,
192 kCoreCalleeSaves.GetList(),
193 ComputeSRegisterMask(kFpuCalleeSaves),
194 compiler_options,
195 stats),
196 block_labels_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
197 location_builder_(graph, this),
198 instruction_visitor_(graph, this),
199 move_resolver_(graph->GetArena(), this),
200 assembler_(graph->GetArena()),
201 isa_features_(isa_features) {
202 // Always save the LR register to mimic Quick.
203 AddAllocatedRegister(Location::RegisterLocation(LR));
204}
205
206#define __ reinterpret_cast<ArmVIXLAssembler*>(GetAssembler())->GetVIXLAssembler()->
207
208void CodeGeneratorARMVIXL::Finalize(CodeAllocator* allocator) {
209 GetAssembler()->FinalizeCode();
210 CodeGenerator::Finalize(allocator);
211}
212
213void CodeGeneratorARMVIXL::SetupBlockedRegisters() const {
214 // Don't allocate the dalvik style register pair passing.
215 blocked_register_pairs_[R1_R2] = true;
216
217 // Stack register, LR and PC are always reserved.
218 blocked_core_registers_[SP] = true;
219 blocked_core_registers_[LR] = true;
220 blocked_core_registers_[PC] = true;
221
222 // Reserve thread register.
223 blocked_core_registers_[TR] = true;
224
225 // Reserve temp register.
226 blocked_core_registers_[IP] = true;
227
228 if (GetGraph()->IsDebuggable()) {
229 // Stubs do not save callee-save floating point registers. If the graph
230 // is debuggable, we need to deal with these registers differently. For
231 // now, just block them.
232 for (uint32_t i = kFpuCalleeSaves.GetFirstSRegister().GetCode();
233 i <= kFpuCalleeSaves.GetLastSRegister().GetCode();
234 ++i) {
235 blocked_fpu_registers_[i] = true;
236 }
237 }
238
239 UpdateBlockedPairRegisters();
240}
241
242// Blocks all register pairs containing blocked core registers.
243void CodeGeneratorARMVIXL::UpdateBlockedPairRegisters() const {
244 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
245 ArmManagedRegister current =
246 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
247 if (blocked_core_registers_[current.AsRegisterPairLow()]
248 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
249 blocked_register_pairs_[i] = true;
250 }
251 }
252}
253
254void InstructionCodeGeneratorARMVIXL::GenerateSuspendCheck(HSuspendCheck* instruction,
255 HBasicBlock* successor) {
256 TODO_VIXL32(FATAL);
257}
258
259InstructionCodeGeneratorARMVIXL::InstructionCodeGeneratorARMVIXL(HGraph* graph,
260 CodeGeneratorARMVIXL* codegen)
261 : InstructionCodeGenerator(graph, codegen),
262 assembler_(codegen->GetAssembler()),
263 codegen_(codegen) {}
264
265void CodeGeneratorARMVIXL::ComputeSpillMask() {
266 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
267 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
268 // There is no easy instruction to restore just the PC on thumb2. We spill and
269 // restore another arbitrary register.
270 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister.GetCode());
271 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
272 // We use vpush and vpop for saving and restoring floating point registers, which take
273 // a SRegister and the number of registers to save/restore after that SRegister. We
274 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
275 // but in the range.
276 if (fpu_spill_mask_ != 0) {
277 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
278 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
279 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
280 fpu_spill_mask_ |= (1 << i);
281 }
282 }
283}
284
285void CodeGeneratorARMVIXL::GenerateFrameEntry() {
286 bool skip_overflow_check =
287 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
288 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
289 __ Bind(&frame_entry_label_);
290
291 if (HasEmptyFrame()) {
292 return;
293 }
294
295 UseScratchRegisterScope temps(GetVIXLAssembler());
296 vixl32::Register temp = temps.Acquire();
297 if (!skip_overflow_check) {
298 __ Sub(temp, sp, static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
299 // The load must immediately precede RecordPcInfo.
300 {
301 AssemblerAccurateScope aas(GetVIXLAssembler(),
302 kArmInstrMaxSizeInBytes,
303 CodeBufferCheckScope::kMaximumSize);
304 __ ldr(temp, MemOperand(temp));
305 RecordPcInfo(nullptr, 0);
306 }
307 }
308
309 __ Push(RegisterList(core_spill_mask_));
310 GetAssembler()->cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
311 GetAssembler()->cfi().RelOffsetForMany(DWARFReg(kMethodRegister),
312 0,
313 core_spill_mask_,
314 kArmWordSize);
315 if (fpu_spill_mask_ != 0) {
316 uint32_t first = LeastSignificantBit(fpu_spill_mask_);
317
318 // Check that list is contiguous.
319 DCHECK_EQ(fpu_spill_mask_ >> CTZ(fpu_spill_mask_), ~0u >> (32 - POPCOUNT(fpu_spill_mask_)));
320
321 __ Vpush(SRegisterList(vixl32::SRegister(first), POPCOUNT(fpu_spill_mask_)));
322 GetAssembler()->cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
323 GetAssembler()->cfi().RelOffsetForMany(DWARFReg(s0),
324 0,
325 fpu_spill_mask_,
326 kArmWordSize);
327 }
328 int adjust = GetFrameSize() - FrameEntrySpillSize();
329 __ Sub(sp, sp, adjust);
330 GetAssembler()->cfi().AdjustCFAOffset(adjust);
331 GetAssembler()->StoreToOffset(kStoreWord, kMethodRegister, sp, 0);
332}
333
334void CodeGeneratorARMVIXL::GenerateFrameExit() {
335 if (HasEmptyFrame()) {
336 __ Bx(lr);
337 return;
338 }
339 GetAssembler()->cfi().RememberState();
340 int adjust = GetFrameSize() - FrameEntrySpillSize();
341 __ Add(sp, sp, adjust);
342 GetAssembler()->cfi().AdjustCFAOffset(-adjust);
343 if (fpu_spill_mask_ != 0) {
344 uint32_t first = LeastSignificantBit(fpu_spill_mask_);
345
346 // Check that list is contiguous.
347 DCHECK_EQ(fpu_spill_mask_ >> CTZ(fpu_spill_mask_), ~0u >> (32 - POPCOUNT(fpu_spill_mask_)));
348
349 __ Vpop(SRegisterList(vixl32::SRegister(first), POPCOUNT(fpu_spill_mask_)));
350 GetAssembler()->cfi().AdjustCFAOffset(
351 -static_cast<int>(kArmWordSize) * POPCOUNT(fpu_spill_mask_));
352 GetAssembler()->cfi().RestoreMany(DWARFReg(vixl32::SRegister(0)),
353 fpu_spill_mask_);
354 }
355 // Pop LR into PC to return.
356 DCHECK_NE(core_spill_mask_ & (1 << kLrCode), 0U);
357 uint32_t pop_mask = (core_spill_mask_ & (~(1 << kLrCode))) | 1 << kPcCode;
358 __ Pop(RegisterList(pop_mask));
359 GetAssembler()->cfi().RestoreState();
360 GetAssembler()->cfi().DefCFAOffset(GetFrameSize());
361}
362
363void CodeGeneratorARMVIXL::Bind(HBasicBlock* block) {
364 __ Bind(GetLabelOf(block));
365}
366
367void CodeGeneratorARMVIXL::MoveConstant(Location destination, int32_t value) {
368 TODO_VIXL32(FATAL);
369}
370
371void CodeGeneratorARMVIXL::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
372 TODO_VIXL32(FATAL);
373}
374
375void CodeGeneratorARMVIXL::AddLocationAsTemp(Location location, LocationSummary* locations) {
376 TODO_VIXL32(FATAL);
377}
378
379uintptr_t CodeGeneratorARMVIXL::GetAddressOf(HBasicBlock* block) {
380 TODO_VIXL32(FATAL);
381 return 0;
382}
383
384void CodeGeneratorARMVIXL::GenerateImplicitNullCheck(HNullCheck* null_check) {
385 TODO_VIXL32(FATAL);
386}
387
388void CodeGeneratorARMVIXL::GenerateExplicitNullCheck(HNullCheck* null_check) {
389 TODO_VIXL32(FATAL);
390}
391
392void CodeGeneratorARMVIXL::InvokeRuntime(QuickEntrypointEnum entrypoint,
393 HInstruction* instruction,
394 uint32_t dex_pc,
395 SlowPathCode* slow_path) {
396 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
397 GenerateInvokeRuntime(GetThreadOffset<kArmPointerSize>(entrypoint).Int32Value());
398 if (EntrypointRequiresStackMap(entrypoint)) {
399 RecordPcInfo(instruction, dex_pc, slow_path);
400 }
401}
402
403void CodeGeneratorARMVIXL::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
404 HInstruction* instruction,
405 SlowPathCode* slow_path) {
406 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
407 GenerateInvokeRuntime(entry_point_offset);
408}
409
410void CodeGeneratorARMVIXL::GenerateInvokeRuntime(int32_t entry_point_offset) {
411 GetAssembler()->LoadFromOffset(kLoadWord, lr, tr, entry_point_offset);
412 __ Blx(lr);
413}
414
415// Check if the desired_string_load_kind is supported. If it is, return it,
416// otherwise return a fall-back kind that should be used instead.
417HLoadString::LoadKind CodeGeneratorARMVIXL::GetSupportedLoadStringKind(
418 HLoadString::LoadKind desired_string_load_kind) {
419 TODO_VIXL32(FATAL);
420 return desired_string_load_kind;
421}
422
423// Check if the desired_class_load_kind is supported. If it is, return it,
424// otherwise return a fall-back kind that should be used instead.
425HLoadClass::LoadKind CodeGeneratorARMVIXL::GetSupportedLoadClassKind(
426 HLoadClass::LoadKind desired_class_load_kind) {
427 TODO_VIXL32(FATAL);
428 return desired_class_load_kind;
429}
430
431// Check if the desired_dispatch_info is supported. If it is, return it,
432// otherwise return a fall-back info that should be used instead.
433HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARMVIXL::GetSupportedInvokeStaticOrDirectDispatch(
434 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100435 HInvokeStaticOrDirect* invoke) {
Scott Wakelingfe885462016-09-22 10:24:38 +0100436 TODO_VIXL32(FATAL);
437 return desired_dispatch_info;
438}
439
440// Generate a call to a static or direct method.
441void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
442 Location temp) {
443 TODO_VIXL32(FATAL);
444}
445
446// Generate a call to a virtual method.
447void CodeGeneratorARMVIXL::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) {
448 TODO_VIXL32(FATAL);
449}
450
451// Copy the result of a call into the given target.
452void CodeGeneratorARMVIXL::MoveFromReturnRegister(Location trg, Primitive::Type type) {
453 TODO_VIXL32(FATAL);
454}
455
456void InstructionCodeGeneratorARMVIXL::HandleGoto(HInstruction* got, HBasicBlock* successor) {
457 DCHECK(!successor->IsExitBlock());
458 HBasicBlock* block = got->GetBlock();
459 HInstruction* previous = got->GetPrevious();
460 HLoopInformation* info = block->GetLoopInformation();
461
462 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
463 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
464 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
465 return;
466 }
467 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
468 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
469 }
470 if (!codegen_->GoesToNextBlock(block, successor)) {
471 __ B(codegen_->GetLabelOf(successor));
472 }
473}
474
475void LocationsBuilderARMVIXL::VisitGoto(HGoto* got) {
476 got->SetLocations(nullptr);
477}
478
479void InstructionCodeGeneratorARMVIXL::VisitGoto(HGoto* got) {
480 HandleGoto(got, got->GetSuccessor());
481}
482
483void LocationsBuilderARMVIXL::VisitExit(HExit* exit) {
484 exit->SetLocations(nullptr);
485}
486
487void InstructionCodeGeneratorARMVIXL::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
488}
489
490void InstructionCodeGeneratorARMVIXL::GenerateVcmp(HInstruction* instruction) {
491 Primitive::Type type = instruction->InputAt(0)->GetType();
492 Location lhs_loc = instruction->GetLocations()->InAt(0);
493 Location rhs_loc = instruction->GetLocations()->InAt(1);
494 if (rhs_loc.IsConstant()) {
495 // 0.0 is the only immediate that can be encoded directly in
496 // a VCMP instruction.
497 //
498 // Both the JLS (section 15.20.1) and the JVMS (section 6.5)
499 // specify that in a floating-point comparison, positive zero
500 // and negative zero are considered equal, so we can use the
501 // literal 0.0 for both cases here.
502 //
503 // Note however that some methods (Float.equal, Float.compare,
504 // Float.compareTo, Double.equal, Double.compare,
505 // Double.compareTo, Math.max, Math.min, StrictMath.max,
506 // StrictMath.min) consider 0.0 to be (strictly) greater than
507 // -0.0. So if we ever translate calls to these methods into a
508 // HCompare instruction, we must handle the -0.0 case with
509 // care here.
510 DCHECK(rhs_loc.GetConstant()->IsArithmeticZero());
511 if (type == Primitive::kPrimFloat) {
512 __ Vcmp(F32, InputSRegisterAt(instruction, 0), 0.0);
513 } else {
514 DCHECK_EQ(type, Primitive::kPrimDouble);
515 __ Vcmp(F64, FromLowSToD(lhs_loc.AsFpuRegisterPairLow<vixl32::SRegister>()), 0.0);
516 }
517 } else {
518 if (type == Primitive::kPrimFloat) {
519 __ Vcmp(F32, InputSRegisterAt(instruction, 0), InputSRegisterAt(instruction, 1));
520 } else {
521 DCHECK_EQ(type, Primitive::kPrimDouble);
522 __ Vcmp(F64,
523 FromLowSToD(lhs_loc.AsFpuRegisterPairLow<vixl32::SRegister>()),
524 FromLowSToD(rhs_loc.AsFpuRegisterPairLow<vixl32::SRegister>()));
525 }
526 }
527}
528
529void InstructionCodeGeneratorARMVIXL::GenerateFPJumps(HCondition* cond,
530 vixl32::Label* true_label,
531 vixl32::Label* false_label ATTRIBUTE_UNUSED) {
532 // To branch on the result of the FP compare we transfer FPSCR to APSR (encoded as PC in VMRS).
533 __ Vmrs(RegisterOrAPSR_nzcv(kPcCode), FPSCR);
534 __ B(ARMFPCondition(cond->GetCondition(), cond->IsGtBias()), true_label);
535}
536
537void InstructionCodeGeneratorARMVIXL::GenerateLongComparesAndJumps(HCondition* cond,
538 vixl32::Label* true_label,
539 vixl32::Label* false_label) {
540 LocationSummary* locations = cond->GetLocations();
541 Location left = locations->InAt(0);
542 Location right = locations->InAt(1);
543 IfCondition if_cond = cond->GetCondition();
544
545 vixl32::Register left_high = left.AsRegisterPairHigh<vixl32::Register>();
546 vixl32::Register left_low = left.AsRegisterPairLow<vixl32::Register>();
547 IfCondition true_high_cond = if_cond;
548 IfCondition false_high_cond = cond->GetOppositeCondition();
549 vixl32::Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
550
551 // Set the conditions for the test, remembering that == needs to be
552 // decided using the low words.
553 // TODO: consider avoiding jumps with temporary and CMP low+SBC high
554 switch (if_cond) {
555 case kCondEQ:
556 case kCondNE:
557 // Nothing to do.
558 break;
559 case kCondLT:
560 false_high_cond = kCondGT;
561 break;
562 case kCondLE:
563 true_high_cond = kCondLT;
564 break;
565 case kCondGT:
566 false_high_cond = kCondLT;
567 break;
568 case kCondGE:
569 true_high_cond = kCondGT;
570 break;
571 case kCondB:
572 false_high_cond = kCondA;
573 break;
574 case kCondBE:
575 true_high_cond = kCondB;
576 break;
577 case kCondA:
578 false_high_cond = kCondB;
579 break;
580 case kCondAE:
581 true_high_cond = kCondA;
582 break;
583 }
584 if (right.IsConstant()) {
585 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
586 int32_t val_low = Low32Bits(value);
587 int32_t val_high = High32Bits(value);
588
589 __ Cmp(left_high, val_high);
590 if (if_cond == kCondNE) {
591 __ B(ARMCondition(true_high_cond), true_label);
592 } else if (if_cond == kCondEQ) {
593 __ B(ARMCondition(false_high_cond), false_label);
594 } else {
595 __ B(ARMCondition(true_high_cond), true_label);
596 __ B(ARMCondition(false_high_cond), false_label);
597 }
598 // Must be equal high, so compare the lows.
599 __ Cmp(left_low, val_low);
600 } else {
601 vixl32::Register right_high = right.AsRegisterPairHigh<vixl32::Register>();
602 vixl32::Register right_low = right.AsRegisterPairLow<vixl32::Register>();
603
604 __ Cmp(left_high, right_high);
605 if (if_cond == kCondNE) {
606 __ B(ARMCondition(true_high_cond), true_label);
607 } else if (if_cond == kCondEQ) {
608 __ B(ARMCondition(false_high_cond), false_label);
609 } else {
610 __ B(ARMCondition(true_high_cond), true_label);
611 __ B(ARMCondition(false_high_cond), false_label);
612 }
613 // Must be equal high, so compare the lows.
614 __ Cmp(left_low, right_low);
615 }
616 // The last comparison might be unsigned.
617 // TODO: optimize cases where this is always true/false
618 __ B(final_condition, true_label);
619}
620
621void InstructionCodeGeneratorARMVIXL::GenerateCompareTestAndBranch(HCondition* condition,
622 vixl32::Label* true_target_in,
623 vixl32::Label* false_target_in) {
624 // Generated branching requires both targets to be explicit. If either of the
625 // targets is nullptr (fallthrough) use and bind `fallthrough` instead.
626 vixl32::Label fallthrough;
627 vixl32::Label* true_target = (true_target_in == nullptr) ? &fallthrough : true_target_in;
628 vixl32::Label* false_target = (false_target_in == nullptr) ? &fallthrough : false_target_in;
629
630 Primitive::Type type = condition->InputAt(0)->GetType();
631 switch (type) {
632 case Primitive::kPrimLong:
633 GenerateLongComparesAndJumps(condition, true_target, false_target);
634 break;
635 case Primitive::kPrimFloat:
636 case Primitive::kPrimDouble:
637 GenerateVcmp(condition);
638 GenerateFPJumps(condition, true_target, false_target);
639 break;
640 default:
641 LOG(FATAL) << "Unexpected compare type " << type;
642 }
643
644 if (false_target != &fallthrough) {
645 __ B(false_target);
646 }
647
648 if (true_target_in == nullptr || false_target_in == nullptr) {
649 __ Bind(&fallthrough);
650 }
651}
652
653void InstructionCodeGeneratorARMVIXL::GenerateTestAndBranch(HInstruction* instruction,
654 size_t condition_input_index,
655 vixl32::Label* true_target,
656 vixl32::Label* false_target) {
657 HInstruction* cond = instruction->InputAt(condition_input_index);
658
659 if (true_target == nullptr && false_target == nullptr) {
660 // Nothing to do. The code always falls through.
661 return;
662 } else if (cond->IsIntConstant()) {
663 // Constant condition, statically compared against "true" (integer value 1).
664 if (cond->AsIntConstant()->IsTrue()) {
665 if (true_target != nullptr) {
666 __ B(true_target);
667 }
668 } else {
669 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
670 if (false_target != nullptr) {
671 __ B(false_target);
672 }
673 }
674 return;
675 }
676
677 // The following code generates these patterns:
678 // (1) true_target == nullptr && false_target != nullptr
679 // - opposite condition true => branch to false_target
680 // (2) true_target != nullptr && false_target == nullptr
681 // - condition true => branch to true_target
682 // (3) true_target != nullptr && false_target != nullptr
683 // - condition true => branch to true_target
684 // - branch to false_target
685 if (IsBooleanValueOrMaterializedCondition(cond)) {
686 // Condition has been materialized, compare the output to 0.
687 if (kIsDebugBuild) {
688 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
689 DCHECK(cond_val.IsRegister());
690 }
691 if (true_target == nullptr) {
692 __ Cbz(InputRegisterAt(instruction, condition_input_index), false_target);
693 } else {
694 __ Cbnz(InputRegisterAt(instruction, condition_input_index), true_target);
695 }
696 } else {
697 // Condition has not been materialized. Use its inputs as the comparison and
698 // its condition as the branch condition.
699 HCondition* condition = cond->AsCondition();
700
701 // If this is a long or FP comparison that has been folded into
702 // the HCondition, generate the comparison directly.
703 Primitive::Type type = condition->InputAt(0)->GetType();
704 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
705 GenerateCompareTestAndBranch(condition, true_target, false_target);
706 return;
707 }
708
709 LocationSummary* locations = cond->GetLocations();
710 DCHECK(locations->InAt(0).IsRegister());
711 vixl32::Register left = InputRegisterAt(cond, 0);
712 Location right = locations->InAt(1);
713 if (right.IsRegister()) {
714 __ Cmp(left, InputRegisterAt(cond, 1));
715 } else {
716 DCHECK(right.IsConstant());
717 __ Cmp(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
718 }
719 if (true_target == nullptr) {
720 __ B(ARMCondition(condition->GetOppositeCondition()), false_target);
721 } else {
722 __ B(ARMCondition(condition->GetCondition()), true_target);
723 }
724 }
725
726 // If neither branch falls through (case 3), the conditional branch to `true_target`
727 // was already emitted (case 2) and we need to emit a jump to `false_target`.
728 if (true_target != nullptr && false_target != nullptr) {
729 __ B(false_target);
730 }
731}
732
733void LocationsBuilderARMVIXL::VisitIf(HIf* if_instr) {
734 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
735 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
736 locations->SetInAt(0, Location::RequiresRegister());
737 }
738}
739
740void InstructionCodeGeneratorARMVIXL::VisitIf(HIf* if_instr) {
741 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
742 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
743 vixl32::Label* true_target =
744 codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
745 nullptr : codegen_->GetLabelOf(true_successor);
746 vixl32::Label* false_target =
747 codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
748 nullptr : codegen_->GetLabelOf(false_successor);
749 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
750}
751
752void CodeGeneratorARMVIXL::GenerateNop() {
753 __ Nop();
754}
755
756void LocationsBuilderARMVIXL::HandleCondition(HCondition* cond) {
757 LocationSummary* locations =
758 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
759 // Handle the long/FP comparisons made in instruction simplification.
760 switch (cond->InputAt(0)->GetType()) {
761 case Primitive::kPrimLong:
762 locations->SetInAt(0, Location::RequiresRegister());
763 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
764 if (!cond->IsEmittedAtUseSite()) {
765 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
766 }
767 break;
768
769 // TODO: https://android-review.googlesource.com/#/c/252265/
770 case Primitive::kPrimFloat:
771 case Primitive::kPrimDouble:
772 locations->SetInAt(0, Location::RequiresFpuRegister());
773 locations->SetInAt(1, Location::RequiresFpuRegister());
774 if (!cond->IsEmittedAtUseSite()) {
775 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
776 }
777 break;
778
779 default:
780 locations->SetInAt(0, Location::RequiresRegister());
781 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
782 if (!cond->IsEmittedAtUseSite()) {
783 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
784 }
785 }
786}
787
788void InstructionCodeGeneratorARMVIXL::HandleCondition(HCondition* cond) {
789 if (cond->IsEmittedAtUseSite()) {
790 return;
791 }
792
793 LocationSummary* locations = cond->GetLocations();
794 Location right = locations->InAt(1);
795 vixl32::Register out = OutputRegister(cond);
796 vixl32::Label true_label, false_label;
797
798 switch (cond->InputAt(0)->GetType()) {
799 default: {
800 // Integer case.
801 if (right.IsRegister()) {
802 __ Cmp(InputRegisterAt(cond, 0), InputRegisterAt(cond, 1));
803 } else {
804 DCHECK(right.IsConstant());
805 __ Cmp(InputRegisterAt(cond, 0), CodeGenerator::GetInt32ValueOf(right.GetConstant()));
806 }
807 {
808 AssemblerAccurateScope aas(GetVIXLAssembler(),
809 kArmInstrMaxSizeInBytes * 3u,
810 CodeBufferCheckScope::kMaximumSize);
811 __ ite(ARMCondition(cond->GetCondition()));
812 __ mov(ARMCondition(cond->GetCondition()), OutputRegister(cond), 1);
813 __ mov(ARMCondition(cond->GetOppositeCondition()), OutputRegister(cond), 0);
814 }
815 return;
816 }
817 case Primitive::kPrimLong:
818 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
819 break;
820 case Primitive::kPrimFloat:
821 case Primitive::kPrimDouble:
822 GenerateVcmp(cond);
823 GenerateFPJumps(cond, &true_label, &false_label);
824 break;
825 }
826
827 // Convert the jumps into the result.
828 vixl32::Label done_label;
829
830 // False case: result = 0.
831 __ Bind(&false_label);
832 __ Mov(out, 0);
833 __ B(&done_label);
834
835 // True case: result = 1.
836 __ Bind(&true_label);
837 __ Mov(out, 1);
838 __ Bind(&done_label);
839}
840
841void LocationsBuilderARMVIXL::VisitEqual(HEqual* comp) {
842 HandleCondition(comp);
843}
844
845void InstructionCodeGeneratorARMVIXL::VisitEqual(HEqual* comp) {
846 HandleCondition(comp);
847}
848
849void LocationsBuilderARMVIXL::VisitNotEqual(HNotEqual* comp) {
850 HandleCondition(comp);
851}
852
853void InstructionCodeGeneratorARMVIXL::VisitNotEqual(HNotEqual* comp) {
854 HandleCondition(comp);
855}
856
857void LocationsBuilderARMVIXL::VisitLessThan(HLessThan* comp) {
858 HandleCondition(comp);
859}
860
861void InstructionCodeGeneratorARMVIXL::VisitLessThan(HLessThan* comp) {
862 HandleCondition(comp);
863}
864
865void LocationsBuilderARMVIXL::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
866 HandleCondition(comp);
867}
868
869void InstructionCodeGeneratorARMVIXL::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
870 HandleCondition(comp);
871}
872
873void LocationsBuilderARMVIXL::VisitGreaterThan(HGreaterThan* comp) {
874 HandleCondition(comp);
875}
876
877void InstructionCodeGeneratorARMVIXL::VisitGreaterThan(HGreaterThan* comp) {
878 HandleCondition(comp);
879}
880
881void LocationsBuilderARMVIXL::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
882 HandleCondition(comp);
883}
884
885void InstructionCodeGeneratorARMVIXL::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
886 HandleCondition(comp);
887}
888
889void LocationsBuilderARMVIXL::VisitBelow(HBelow* comp) {
890 HandleCondition(comp);
891}
892
893void InstructionCodeGeneratorARMVIXL::VisitBelow(HBelow* comp) {
894 HandleCondition(comp);
895}
896
897void LocationsBuilderARMVIXL::VisitBelowOrEqual(HBelowOrEqual* comp) {
898 HandleCondition(comp);
899}
900
901void InstructionCodeGeneratorARMVIXL::VisitBelowOrEqual(HBelowOrEqual* comp) {
902 HandleCondition(comp);
903}
904
905void LocationsBuilderARMVIXL::VisitAbove(HAbove* comp) {
906 HandleCondition(comp);
907}
908
909void InstructionCodeGeneratorARMVIXL::VisitAbove(HAbove* comp) {
910 HandleCondition(comp);
911}
912
913void LocationsBuilderARMVIXL::VisitAboveOrEqual(HAboveOrEqual* comp) {
914 HandleCondition(comp);
915}
916
917void InstructionCodeGeneratorARMVIXL::VisitAboveOrEqual(HAboveOrEqual* comp) {
918 HandleCondition(comp);
919}
920
921void LocationsBuilderARMVIXL::VisitIntConstant(HIntConstant* constant) {
922 LocationSummary* locations =
923 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
924 locations->SetOut(Location::ConstantLocation(constant));
925}
926
927void InstructionCodeGeneratorARMVIXL::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
928 // Will be generated at use site.
929}
930
931void LocationsBuilderARMVIXL::VisitLongConstant(HLongConstant* constant) {
932 LocationSummary* locations =
933 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
934 locations->SetOut(Location::ConstantLocation(constant));
935}
936
937void InstructionCodeGeneratorARMVIXL::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
938 // Will be generated at use site.
939}
940
941void LocationsBuilderARMVIXL::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
942 memory_barrier->SetLocations(nullptr);
943}
944
945void InstructionCodeGeneratorARMVIXL::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
946 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
947}
948
949void LocationsBuilderARMVIXL::VisitReturnVoid(HReturnVoid* ret) {
950 ret->SetLocations(nullptr);
951}
952
953void InstructionCodeGeneratorARMVIXL::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
954 codegen_->GenerateFrameExit();
955}
956
957void LocationsBuilderARMVIXL::VisitReturn(HReturn* ret) {
958 LocationSummary* locations =
959 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
960 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
961}
962
963void InstructionCodeGeneratorARMVIXL::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
964 codegen_->GenerateFrameExit();
965}
966
967void LocationsBuilderARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
968 Primitive::Type result_type = conversion->GetResultType();
969 Primitive::Type input_type = conversion->GetInputType();
970 DCHECK_NE(result_type, input_type);
971
972 // The float-to-long, double-to-long and long-to-float type conversions
973 // rely on a call to the runtime.
974 LocationSummary::CallKind call_kind =
975 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
976 && result_type == Primitive::kPrimLong)
977 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
978 ? LocationSummary::kCallOnMainOnly
979 : LocationSummary::kNoCall;
980 LocationSummary* locations =
981 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
982
983 // The Java language does not allow treating boolean as an integral type but
984 // our bit representation makes it safe.
985
986 switch (result_type) {
987 case Primitive::kPrimByte:
988 switch (input_type) {
989 case Primitive::kPrimLong:
990 // Type conversion from long to byte is a result of code transformations.
991 case Primitive::kPrimBoolean:
992 // Boolean input is a result of code transformations.
993 case Primitive::kPrimShort:
994 case Primitive::kPrimInt:
995 case Primitive::kPrimChar:
996 // Processing a Dex `int-to-byte' instruction.
997 locations->SetInAt(0, Location::RequiresRegister());
998 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
999 break;
1000
1001 default:
1002 LOG(FATAL) << "Unexpected type conversion from " << input_type
1003 << " to " << result_type;
1004 }
1005 break;
1006
1007 case Primitive::kPrimShort:
1008 switch (input_type) {
1009 case Primitive::kPrimLong:
1010 // Type conversion from long to short is a result of code transformations.
1011 case Primitive::kPrimBoolean:
1012 // Boolean input is a result of code transformations.
1013 case Primitive::kPrimByte:
1014 case Primitive::kPrimInt:
1015 case Primitive::kPrimChar:
1016 // Processing a Dex `int-to-short' instruction.
1017 locations->SetInAt(0, Location::RequiresRegister());
1018 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1019 break;
1020
1021 default:
1022 LOG(FATAL) << "Unexpected type conversion from " << input_type
1023 << " to " << result_type;
1024 }
1025 break;
1026
1027 case Primitive::kPrimInt:
1028 switch (input_type) {
1029 case Primitive::kPrimLong:
1030 // Processing a Dex `long-to-int' instruction.
1031 locations->SetInAt(0, Location::Any());
1032 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1033 break;
1034
1035 case Primitive::kPrimFloat:
1036 // Processing a Dex `float-to-int' instruction.
1037 locations->SetInAt(0, Location::RequiresFpuRegister());
1038 locations->SetOut(Location::RequiresRegister());
1039 locations->AddTemp(Location::RequiresFpuRegister());
1040 break;
1041
1042 case Primitive::kPrimDouble:
1043 // Processing a Dex `double-to-int' instruction.
1044 locations->SetInAt(0, Location::RequiresFpuRegister());
1045 locations->SetOut(Location::RequiresRegister());
1046 locations->AddTemp(Location::RequiresFpuRegister());
1047 break;
1048
1049 default:
1050 LOG(FATAL) << "Unexpected type conversion from " << input_type
1051 << " to " << result_type;
1052 }
1053 break;
1054
1055 case Primitive::kPrimLong:
1056 switch (input_type) {
1057 case Primitive::kPrimBoolean:
1058 // Boolean input is a result of code transformations.
1059 case Primitive::kPrimByte:
1060 case Primitive::kPrimShort:
1061 case Primitive::kPrimInt:
1062 case Primitive::kPrimChar:
1063 // Processing a Dex `int-to-long' instruction.
1064 locations->SetInAt(0, Location::RequiresRegister());
1065 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1066 break;
1067
1068 case Primitive::kPrimFloat: {
1069 // Processing a Dex `float-to-long' instruction.
1070 InvokeRuntimeCallingConvention calling_convention;
1071 locations->SetInAt(0, Location::FpuRegisterLocation(
1072 calling_convention.GetFpuRegisterAt(0)));
1073 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1074 break;
1075 }
1076
1077 case Primitive::kPrimDouble: {
1078 // Processing a Dex `double-to-long' instruction.
1079 InvokeRuntimeCallingConvention calling_convention;
1080 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1081 calling_convention.GetFpuRegisterAt(0),
1082 calling_convention.GetFpuRegisterAt(1)));
1083 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1084 break;
1085 }
1086
1087 default:
1088 LOG(FATAL) << "Unexpected type conversion from " << input_type
1089 << " to " << result_type;
1090 }
1091 break;
1092
1093 case Primitive::kPrimChar:
1094 switch (input_type) {
1095 case Primitive::kPrimLong:
1096 // Type conversion from long to char is a result of code transformations.
1097 case Primitive::kPrimBoolean:
1098 // Boolean input is a result of code transformations.
1099 case Primitive::kPrimByte:
1100 case Primitive::kPrimShort:
1101 case Primitive::kPrimInt:
1102 // Processing a Dex `int-to-char' instruction.
1103 locations->SetInAt(0, Location::RequiresRegister());
1104 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1105 break;
1106
1107 default:
1108 LOG(FATAL) << "Unexpected type conversion from " << input_type
1109 << " to " << result_type;
1110 }
1111 break;
1112
1113 case Primitive::kPrimFloat:
1114 switch (input_type) {
1115 case Primitive::kPrimBoolean:
1116 // Boolean input is a result of code transformations.
1117 case Primitive::kPrimByte:
1118 case Primitive::kPrimShort:
1119 case Primitive::kPrimInt:
1120 case Primitive::kPrimChar:
1121 // Processing a Dex `int-to-float' instruction.
1122 locations->SetInAt(0, Location::RequiresRegister());
1123 locations->SetOut(Location::RequiresFpuRegister());
1124 break;
1125
1126 case Primitive::kPrimLong: {
1127 // Processing a Dex `long-to-float' instruction.
1128 InvokeRuntimeCallingConvention calling_convention;
1129 locations->SetInAt(0, Location::RegisterPairLocation(
1130 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
1131 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
1132 break;
1133 }
1134
1135 case Primitive::kPrimDouble:
1136 // Processing a Dex `double-to-float' instruction.
1137 locations->SetInAt(0, Location::RequiresFpuRegister());
1138 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1139 break;
1140
1141 default:
1142 LOG(FATAL) << "Unexpected type conversion from " << input_type
1143 << " to " << result_type;
1144 };
1145 break;
1146
1147 case Primitive::kPrimDouble:
1148 switch (input_type) {
1149 case Primitive::kPrimBoolean:
1150 // Boolean input is a result of code transformations.
1151 case Primitive::kPrimByte:
1152 case Primitive::kPrimShort:
1153 case Primitive::kPrimInt:
1154 case Primitive::kPrimChar:
1155 // Processing a Dex `int-to-double' instruction.
1156 locations->SetInAt(0, Location::RequiresRegister());
1157 locations->SetOut(Location::RequiresFpuRegister());
1158 break;
1159
1160 case Primitive::kPrimLong:
1161 // Processing a Dex `long-to-double' instruction.
1162 locations->SetInAt(0, Location::RequiresRegister());
1163 locations->SetOut(Location::RequiresFpuRegister());
1164 locations->AddTemp(Location::RequiresFpuRegister());
1165 locations->AddTemp(Location::RequiresFpuRegister());
1166 break;
1167
1168 case Primitive::kPrimFloat:
1169 // Processing a Dex `float-to-double' instruction.
1170 locations->SetInAt(0, Location::RequiresFpuRegister());
1171 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1172 break;
1173
1174 default:
1175 LOG(FATAL) << "Unexpected type conversion from " << input_type
1176 << " to " << result_type;
1177 };
1178 break;
1179
1180 default:
1181 LOG(FATAL) << "Unexpected type conversion from " << input_type
1182 << " to " << result_type;
1183 }
1184}
1185
1186void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
1187 LocationSummary* locations = conversion->GetLocations();
1188 Location out = locations->Out();
1189 Location in = locations->InAt(0);
1190 Primitive::Type result_type = conversion->GetResultType();
1191 Primitive::Type input_type = conversion->GetInputType();
1192 DCHECK_NE(result_type, input_type);
1193 switch (result_type) {
1194 case Primitive::kPrimByte:
1195 switch (input_type) {
1196 case Primitive::kPrimLong:
1197 // Type conversion from long to byte is a result of code transformations.
1198 __ Sbfx(OutputRegister(conversion), in.AsRegisterPairLow<vixl32::Register>(), 0, 8);
1199 break;
1200 case Primitive::kPrimBoolean:
1201 // Boolean input is a result of code transformations.
1202 case Primitive::kPrimShort:
1203 case Primitive::kPrimInt:
1204 case Primitive::kPrimChar:
1205 // Processing a Dex `int-to-byte' instruction.
1206 __ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 8);
1207 break;
1208
1209 default:
1210 LOG(FATAL) << "Unexpected type conversion from " << input_type
1211 << " to " << result_type;
1212 }
1213 break;
1214
1215 case Primitive::kPrimShort:
1216 switch (input_type) {
1217 case Primitive::kPrimLong:
1218 // Type conversion from long to short is a result of code transformations.
1219 __ Sbfx(OutputRegister(conversion), in.AsRegisterPairLow<vixl32::Register>(), 0, 16);
1220 break;
1221 case Primitive::kPrimBoolean:
1222 // Boolean input is a result of code transformations.
1223 case Primitive::kPrimByte:
1224 case Primitive::kPrimInt:
1225 case Primitive::kPrimChar:
1226 // Processing a Dex `int-to-short' instruction.
1227 __ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 16);
1228 break;
1229
1230 default:
1231 LOG(FATAL) << "Unexpected type conversion from " << input_type
1232 << " to " << result_type;
1233 }
1234 break;
1235
1236 case Primitive::kPrimInt:
1237 switch (input_type) {
1238 case Primitive::kPrimLong:
1239 // Processing a Dex `long-to-int' instruction.
1240 DCHECK(out.IsRegister());
1241 if (in.IsRegisterPair()) {
1242 __ Mov(OutputRegister(conversion), in.AsRegisterPairLow<vixl32::Register>());
1243 } else if (in.IsDoubleStackSlot()) {
1244 GetAssembler()->LoadFromOffset(kLoadWord,
1245 OutputRegister(conversion),
1246 sp,
1247 in.GetStackIndex());
1248 } else {
1249 DCHECK(in.IsConstant());
1250 DCHECK(in.GetConstant()->IsLongConstant());
1251 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
1252 __ Mov(OutputRegister(conversion), static_cast<int32_t>(value));
1253 }
1254 break;
1255
1256 case Primitive::kPrimFloat: {
1257 // Processing a Dex `float-to-int' instruction.
1258 vixl32::SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<vixl32::SRegister>();
1259 __ Vcvt(I32, F32, temp, InputSRegisterAt(conversion, 0));
1260 __ Vmov(OutputRegister(conversion), temp);
1261 break;
1262 }
1263
1264 case Primitive::kPrimDouble: {
1265 // Processing a Dex `double-to-int' instruction.
1266 vixl32::SRegister temp_s =
1267 locations->GetTemp(0).AsFpuRegisterPairLow<vixl32::SRegister>();
1268 __ Vcvt(I32, F64, temp_s, FromLowSToD(in.AsFpuRegisterPairLow<vixl32::SRegister>()));
1269 __ Vmov(OutputRegister(conversion), temp_s);
1270 break;
1271 }
1272
1273 default:
1274 LOG(FATAL) << "Unexpected type conversion from " << input_type
1275 << " to " << result_type;
1276 }
1277 break;
1278
1279 case Primitive::kPrimLong:
1280 switch (input_type) {
1281 case Primitive::kPrimBoolean:
1282 // Boolean input is a result of code transformations.
1283 case Primitive::kPrimByte:
1284 case Primitive::kPrimShort:
1285 case Primitive::kPrimInt:
1286 case Primitive::kPrimChar:
1287 // Processing a Dex `int-to-long' instruction.
1288 DCHECK(out.IsRegisterPair());
1289 DCHECK(in.IsRegister());
1290 __ Mov(out.AsRegisterPairLow<vixl32::Register>(), InputRegisterAt(conversion, 0));
1291 // Sign extension.
1292 __ Asr(out.AsRegisterPairHigh<vixl32::Register>(),
1293 out.AsRegisterPairLow<vixl32::Register>(),
1294 31);
1295 break;
1296
1297 case Primitive::kPrimFloat:
1298 // Processing a Dex `float-to-long' instruction.
1299 codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
1300 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
1301 break;
1302
1303 case Primitive::kPrimDouble:
1304 // Processing a Dex `double-to-long' instruction.
1305 codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
1306 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
1307 break;
1308
1309 default:
1310 LOG(FATAL) << "Unexpected type conversion from " << input_type
1311 << " to " << result_type;
1312 }
1313 break;
1314
1315 case Primitive::kPrimChar:
1316 switch (input_type) {
1317 case Primitive::kPrimLong:
1318 // Type conversion from long to char is a result of code transformations.
1319 __ Ubfx(OutputRegister(conversion), in.AsRegisterPairLow<vixl32::Register>(), 0, 16);
1320 break;
1321 case Primitive::kPrimBoolean:
1322 // Boolean input is a result of code transformations.
1323 case Primitive::kPrimByte:
1324 case Primitive::kPrimShort:
1325 case Primitive::kPrimInt:
1326 // Processing a Dex `int-to-char' instruction.
1327 __ Ubfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 16);
1328 break;
1329
1330 default:
1331 LOG(FATAL) << "Unexpected type conversion from " << input_type
1332 << " to " << result_type;
1333 }
1334 break;
1335
1336 case Primitive::kPrimFloat:
1337 switch (input_type) {
1338 case Primitive::kPrimBoolean:
1339 // Boolean input is a result of code transformations.
1340 case Primitive::kPrimByte:
1341 case Primitive::kPrimShort:
1342 case Primitive::kPrimInt:
1343 case Primitive::kPrimChar: {
1344 // Processing a Dex `int-to-float' instruction.
1345 __ Vmov(OutputSRegister(conversion), InputRegisterAt(conversion, 0));
1346 __ Vcvt(F32, I32, OutputSRegister(conversion), OutputSRegister(conversion));
1347 break;
1348 }
1349
1350 case Primitive::kPrimLong:
1351 // Processing a Dex `long-to-float' instruction.
1352 codegen_->InvokeRuntime(kQuickL2f, conversion, conversion->GetDexPc());
1353 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
1354 break;
1355
1356 case Primitive::kPrimDouble:
1357 // Processing a Dex `double-to-float' instruction.
1358 __ Vcvt(F32,
1359 F64,
1360 OutputSRegister(conversion),
1361 FromLowSToD(in.AsFpuRegisterPairLow<vixl32::SRegister>()));
1362 break;
1363
1364 default:
1365 LOG(FATAL) << "Unexpected type conversion from " << input_type
1366 << " to " << result_type;
1367 };
1368 break;
1369
1370 case Primitive::kPrimDouble:
1371 switch (input_type) {
1372 case Primitive::kPrimBoolean:
1373 // Boolean input is a result of code transformations.
1374 case Primitive::kPrimByte:
1375 case Primitive::kPrimShort:
1376 case Primitive::kPrimInt:
1377 case Primitive::kPrimChar: {
1378 // Processing a Dex `int-to-double' instruction.
1379 __ Vmov(out.AsFpuRegisterPairLow<vixl32::SRegister>(), InputRegisterAt(conversion, 0));
1380 __ Vcvt(F64,
1381 I32,
1382 FromLowSToD(out.AsFpuRegisterPairLow<vixl32::SRegister>()),
1383 out.AsFpuRegisterPairLow<vixl32::SRegister>());
1384 break;
1385 }
1386
1387 case Primitive::kPrimLong: {
1388 // Processing a Dex `long-to-double' instruction.
1389 vixl32::Register low = in.AsRegisterPairLow<vixl32::Register>();
1390 vixl32::Register high = in.AsRegisterPairHigh<vixl32::Register>();
1391
1392 vixl32::SRegister out_s = out.AsFpuRegisterPairLow<vixl32::SRegister>();
1393 vixl32::DRegister out_d = FromLowSToD(out_s);
1394
1395 vixl32::SRegister temp_s =
1396 locations->GetTemp(0).AsFpuRegisterPairLow<vixl32::SRegister>();
1397 vixl32::DRegister temp_d = FromLowSToD(temp_s);
1398
1399 vixl32::SRegister constant_s =
1400 locations->GetTemp(1).AsFpuRegisterPairLow<vixl32::SRegister>();
1401 vixl32::DRegister constant_d = FromLowSToD(constant_s);
1402
1403 // temp_d = int-to-double(high)
1404 __ Vmov(temp_s, high);
1405 __ Vcvt(F64, I32, temp_d, temp_s);
1406 // constant_d = k2Pow32EncodingForDouble
1407 __ Vmov(F64,
1408 constant_d,
1409 vixl32::DOperand(bit_cast<double, int64_t>(k2Pow32EncodingForDouble)));
1410 // out_d = unsigned-to-double(low)
1411 __ Vmov(out_s, low);
1412 __ Vcvt(F64, U32, out_d, out_s);
1413 // out_d += temp_d * constant_d
1414 __ Vmla(F64, out_d, temp_d, constant_d);
1415 break;
1416 }
1417
1418 case Primitive::kPrimFloat:
1419 // Processing a Dex `float-to-double' instruction.
1420 __ Vcvt(F64,
1421 F32,
1422 FromLowSToD(out.AsFpuRegisterPairLow<vixl32::SRegister>()),
1423 InputSRegisterAt(conversion, 0));
1424 break;
1425
1426 default:
1427 LOG(FATAL) << "Unexpected type conversion from " << input_type
1428 << " to " << result_type;
1429 };
1430 break;
1431
1432 default:
1433 LOG(FATAL) << "Unexpected type conversion from " << input_type
1434 << " to " << result_type;
1435 }
1436}
1437
1438void LocationsBuilderARMVIXL::VisitAdd(HAdd* add) {
1439 LocationSummary* locations =
1440 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
1441 switch (add->GetResultType()) {
1442 case Primitive::kPrimInt: {
1443 locations->SetInAt(0, Location::RequiresRegister());
1444 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1445 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1446 break;
1447 }
1448
1449 // TODO: https://android-review.googlesource.com/#/c/254144/
1450 case Primitive::kPrimLong: {
1451 locations->SetInAt(0, Location::RequiresRegister());
1452 locations->SetInAt(1, Location::RequiresRegister());
1453 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1454 break;
1455 }
1456
1457 case Primitive::kPrimFloat:
1458 case Primitive::kPrimDouble: {
1459 locations->SetInAt(0, Location::RequiresFpuRegister());
1460 locations->SetInAt(1, Location::RequiresFpuRegister());
1461 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1462 break;
1463 }
1464
1465 default:
1466 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1467 }
1468}
1469
1470void InstructionCodeGeneratorARMVIXL::VisitAdd(HAdd* add) {
1471 LocationSummary* locations = add->GetLocations();
1472 Location out = locations->Out();
1473 Location first = locations->InAt(0);
1474 Location second = locations->InAt(1);
1475
1476 switch (add->GetResultType()) {
1477 case Primitive::kPrimInt: {
1478 __ Add(OutputRegister(add), InputRegisterAt(add, 0), InputOperandAt(add, 1));
1479 }
1480 break;
1481
1482 // TODO: https://android-review.googlesource.com/#/c/254144/
1483 case Primitive::kPrimLong: {
1484 DCHECK(second.IsRegisterPair());
1485 __ Adds(out.AsRegisterPairLow<vixl32::Register>(),
1486 first.AsRegisterPairLow<vixl32::Register>(),
1487 Operand(second.AsRegisterPairLow<vixl32::Register>()));
1488 __ Adc(out.AsRegisterPairHigh<vixl32::Register>(),
1489 first.AsRegisterPairHigh<vixl32::Register>(),
1490 second.AsRegisterPairHigh<vixl32::Register>());
1491 break;
1492 }
1493
1494 case Primitive::kPrimFloat: {
1495 __ Vadd(F32, OutputSRegister(add), InputSRegisterAt(add, 0), InputSRegisterAt(add, 1));
1496 }
1497 break;
1498
1499 case Primitive::kPrimDouble:
1500 __ Vadd(F64,
1501 FromLowSToD(out.AsFpuRegisterPairLow<vixl32::SRegister>()),
1502 FromLowSToD(first.AsFpuRegisterPairLow<vixl32::SRegister>()),
1503 FromLowSToD(second.AsFpuRegisterPairLow<vixl32::SRegister>()));
1504 break;
1505
1506 default:
1507 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1508 }
1509}
1510
1511void LocationsBuilderARMVIXL::VisitSub(HSub* sub) {
1512 LocationSummary* locations =
1513 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
1514 switch (sub->GetResultType()) {
1515 case Primitive::kPrimInt: {
1516 locations->SetInAt(0, Location::RequiresRegister());
1517 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
1518 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1519 break;
1520 }
1521
1522 // TODO: https://android-review.googlesource.com/#/c/254144/
1523 case Primitive::kPrimLong: {
1524 locations->SetInAt(0, Location::RequiresRegister());
1525 locations->SetInAt(1, Location::RequiresRegister());
1526 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1527 break;
1528 }
1529 case Primitive::kPrimFloat:
1530 case Primitive::kPrimDouble: {
1531 locations->SetInAt(0, Location::RequiresFpuRegister());
1532 locations->SetInAt(1, Location::RequiresFpuRegister());
1533 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1534 break;
1535 }
1536 default:
1537 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1538 }
1539}
1540
1541void InstructionCodeGeneratorARMVIXL::VisitSub(HSub* sub) {
1542 LocationSummary* locations = sub->GetLocations();
1543 Location out = locations->Out();
1544 Location first = locations->InAt(0);
1545 Location second = locations->InAt(1);
1546 switch (sub->GetResultType()) {
1547 case Primitive::kPrimInt: {
1548 if (second.IsRegister()) {
1549 __ Sub(OutputRegister(sub), InputRegisterAt(sub, 0), InputRegisterAt(sub, 1));
1550 } else {
1551 __ Sub(OutputRegister(sub),
1552 InputRegisterAt(sub, 0),
1553 second.GetConstant()->AsIntConstant()->GetValue());
1554 }
1555 break;
1556 }
1557
1558 // TODO: https://android-review.googlesource.com/#/c/254144/
1559 case Primitive::kPrimLong: {
1560 DCHECK(second.IsRegisterPair());
1561 __ Subs(out.AsRegisterPairLow<vixl32::Register>(),
1562 first.AsRegisterPairLow<vixl32::Register>(),
1563 Operand(second.AsRegisterPairLow<vixl32::Register>()));
1564 __ Sbc(out.AsRegisterPairHigh<vixl32::Register>(),
1565 first.AsRegisterPairHigh<vixl32::Register>(),
1566 Operand(second.AsRegisterPairHigh<vixl32::Register>()));
1567 break;
1568 }
1569
1570 case Primitive::kPrimFloat: {
1571 __ Vsub(F32, OutputSRegister(sub), InputSRegisterAt(sub, 0), InputSRegisterAt(sub, 1));
1572 break;
1573 }
1574
1575 case Primitive::kPrimDouble: {
1576 __ Vsub(F64,
1577 FromLowSToD(out.AsFpuRegisterPairLow<vixl32::SRegister>()),
1578 FromLowSToD(first.AsFpuRegisterPairLow<vixl32::SRegister>()),
1579 FromLowSToD(second.AsFpuRegisterPairLow<vixl32::SRegister>()));
1580 break;
1581 }
1582
1583 default:
1584 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1585 }
1586}
1587
1588void LocationsBuilderARMVIXL::VisitMul(HMul* mul) {
1589 LocationSummary* locations =
1590 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1591 switch (mul->GetResultType()) {
1592 case Primitive::kPrimInt:
1593 case Primitive::kPrimLong: {
1594 locations->SetInAt(0, Location::RequiresRegister());
1595 locations->SetInAt(1, Location::RequiresRegister());
1596 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1597 break;
1598 }
1599
1600 case Primitive::kPrimFloat:
1601 case Primitive::kPrimDouble: {
1602 locations->SetInAt(0, Location::RequiresFpuRegister());
1603 locations->SetInAt(1, Location::RequiresFpuRegister());
1604 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1605 break;
1606 }
1607
1608 default:
1609 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1610 }
1611}
1612
1613void InstructionCodeGeneratorARMVIXL::VisitMul(HMul* mul) {
1614 LocationSummary* locations = mul->GetLocations();
1615 Location out = locations->Out();
1616 Location first = locations->InAt(0);
1617 Location second = locations->InAt(1);
1618 switch (mul->GetResultType()) {
1619 case Primitive::kPrimInt: {
1620 __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
1621 break;
1622 }
1623 case Primitive::kPrimLong: {
1624 vixl32::Register out_hi = out.AsRegisterPairHigh<vixl32::Register>();
1625 vixl32::Register out_lo = out.AsRegisterPairLow<vixl32::Register>();
1626 vixl32::Register in1_hi = first.AsRegisterPairHigh<vixl32::Register>();
1627 vixl32::Register in1_lo = first.AsRegisterPairLow<vixl32::Register>();
1628 vixl32::Register in2_hi = second.AsRegisterPairHigh<vixl32::Register>();
1629 vixl32::Register in2_lo = second.AsRegisterPairLow<vixl32::Register>();
1630
1631 // Extra checks to protect caused by the existence of R1_R2.
1632 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
1633 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
1634 DCHECK_NE(out_hi.GetCode(), in1_lo.GetCode());
1635 DCHECK_NE(out_hi.GetCode(), in2_lo.GetCode());
1636
1637 // input: in1 - 64 bits, in2 - 64 bits
1638 // output: out
1639 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
1640 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
1641 // parts: out.lo = (in1.lo * in2.lo)[31:0]
1642
1643 UseScratchRegisterScope temps(GetVIXLAssembler());
1644 vixl32::Register temp = temps.Acquire();
1645 // temp <- in1.lo * in2.hi
1646 __ Mul(temp, in1_lo, in2_hi);
1647 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
1648 __ Mla(out_hi, in1_hi, in2_lo, temp);
1649 // out.lo <- (in1.lo * in2.lo)[31:0];
1650 __ Umull(out_lo, temp, in1_lo, in2_lo);
1651 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
1652 __ Add(out_hi, out_hi, Operand(temp));
1653 break;
1654 }
1655
1656 case Primitive::kPrimFloat: {
1657 __ Vmul(F32, OutputSRegister(mul), InputSRegisterAt(mul, 0), InputSRegisterAt(mul, 1));
1658 break;
1659 }
1660
1661 case Primitive::kPrimDouble: {
1662 __ Vmul(F64,
1663 FromLowSToD(out.AsFpuRegisterPairLow<vixl32::SRegister>()),
1664 FromLowSToD(first.AsFpuRegisterPairLow<vixl32::SRegister>()),
1665 FromLowSToD(second.AsFpuRegisterPairLow<vixl32::SRegister>()));
1666 break;
1667 }
1668
1669 default:
1670 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1671 }
1672}
1673
1674void LocationsBuilderARMVIXL::VisitNot(HNot* not_) {
1675 LocationSummary* locations =
1676 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
1677 locations->SetInAt(0, Location::RequiresRegister());
1678 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1679}
1680
1681void InstructionCodeGeneratorARMVIXL::VisitNot(HNot* not_) {
1682 LocationSummary* locations = not_->GetLocations();
1683 Location out = locations->Out();
1684 Location in = locations->InAt(0);
1685 switch (not_->GetResultType()) {
1686 case Primitive::kPrimInt:
1687 __ Mvn(OutputRegister(not_), InputRegisterAt(not_, 0));
1688 break;
1689
1690 case Primitive::kPrimLong:
1691 __ Mvn(out.AsRegisterPairLow<vixl32::Register>(),
1692 Operand(in.AsRegisterPairLow<vixl32::Register>()));
1693 __ Mvn(out.AsRegisterPairHigh<vixl32::Register>(),
1694 Operand(in.AsRegisterPairHigh<vixl32::Register>()));
1695 break;
1696
1697 default:
1698 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
1699 }
1700}
1701
1702void CodeGeneratorARMVIXL::GenerateMemoryBarrier(MemBarrierKind kind) {
1703 // TODO (ported from quick): revisit ARM barrier kinds.
1704 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
1705 switch (kind) {
1706 case MemBarrierKind::kAnyStore:
1707 case MemBarrierKind::kLoadAny:
1708 case MemBarrierKind::kAnyAny: {
1709 flavor = DmbOptions::ISH;
1710 break;
1711 }
1712 case MemBarrierKind::kStoreStore: {
1713 flavor = DmbOptions::ISHST;
1714 break;
1715 }
1716 default:
1717 LOG(FATAL) << "Unexpected memory barrier " << kind;
1718 }
1719 __ Dmb(flavor);
1720}
1721
1722void InstructionCodeGeneratorARMVIXL::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
1723 DCHECK(instruction->IsDiv() || instruction->IsRem());
1724 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
1725
1726 LocationSummary* locations = instruction->GetLocations();
1727 Location second = locations->InAt(1);
1728 DCHECK(second.IsConstant());
1729
1730 vixl32::Register out = OutputRegister(instruction);
1731 vixl32::Register dividend = InputRegisterAt(instruction, 0);
1732 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
1733 DCHECK(imm == 1 || imm == -1);
1734
1735 if (instruction->IsRem()) {
1736 __ Mov(out, 0);
1737 } else {
1738 if (imm == 1) {
1739 __ Mov(out, dividend);
1740 } else {
1741 __ Rsb(out, dividend, 0);
1742 }
1743 }
1744}
1745
1746void InstructionCodeGeneratorARMVIXL::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
1747 DCHECK(instruction->IsDiv() || instruction->IsRem());
1748 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
1749
1750 LocationSummary* locations = instruction->GetLocations();
1751 Location second = locations->InAt(1);
1752 DCHECK(second.IsConstant());
1753
1754 vixl32::Register out = OutputRegister(instruction);
1755 vixl32::Register dividend = InputRegisterAt(instruction, 0);
1756 vixl32::Register temp = locations->GetTemp(0).AsRegister<vixl32::Register>();
1757 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
1758 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
1759 int ctz_imm = CTZ(abs_imm);
1760
1761 if (ctz_imm == 1) {
1762 __ Lsr(temp, dividend, 32 - ctz_imm);
1763 } else {
1764 __ Asr(temp, dividend, 31);
1765 __ Lsr(temp, temp, 32 - ctz_imm);
1766 }
1767 __ Add(out, temp, Operand(dividend));
1768
1769 if (instruction->IsDiv()) {
1770 __ Asr(out, out, ctz_imm);
1771 if (imm < 0) {
1772 __ Rsb(out, out, Operand(0));
1773 }
1774 } else {
1775 __ Ubfx(out, out, 0, ctz_imm);
1776 __ Sub(out, out, Operand(temp));
1777 }
1778}
1779
1780void InstructionCodeGeneratorARMVIXL::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
1781 DCHECK(instruction->IsDiv() || instruction->IsRem());
1782 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
1783
1784 LocationSummary* locations = instruction->GetLocations();
1785 Location second = locations->InAt(1);
1786 DCHECK(second.IsConstant());
1787
1788 vixl32::Register out = OutputRegister(instruction);
1789 vixl32::Register dividend = InputRegisterAt(instruction, 0);
1790 vixl32::Register temp1 = locations->GetTemp(0).AsRegister<vixl32::Register>();
1791 vixl32::Register temp2 = locations->GetTemp(1).AsRegister<vixl32::Register>();
1792 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
1793
1794 int64_t magic;
1795 int shift;
1796 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
1797
1798 __ Mov(temp1, magic);
1799 __ Smull(temp2, temp1, dividend, temp1);
1800
1801 if (imm > 0 && magic < 0) {
1802 __ Add(temp1, temp1, Operand(dividend));
1803 } else if (imm < 0 && magic > 0) {
1804 __ Sub(temp1, temp1, Operand(dividend));
1805 }
1806
1807 if (shift != 0) {
1808 __ Asr(temp1, temp1, shift);
1809 }
1810
1811 if (instruction->IsDiv()) {
1812 __ Sub(out, temp1, Operand(temp1, vixl32::Shift(ASR), 31));
1813 } else {
1814 __ Sub(temp1, temp1, Operand(temp1, vixl32::Shift(ASR), 31));
1815 // TODO: Strength reduction for mls.
1816 __ Mov(temp2, imm);
1817 __ Mls(out, temp1, temp2, dividend);
1818 }
1819}
1820
1821void InstructionCodeGeneratorARMVIXL::GenerateDivRemConstantIntegral(
1822 HBinaryOperation* instruction) {
1823 DCHECK(instruction->IsDiv() || instruction->IsRem());
1824 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
1825
1826 LocationSummary* locations = instruction->GetLocations();
1827 Location second = locations->InAt(1);
1828 DCHECK(second.IsConstant());
1829
1830 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
1831 if (imm == 0) {
1832 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
1833 } else if (imm == 1 || imm == -1) {
1834 DivRemOneOrMinusOne(instruction);
1835 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
1836 DivRemByPowerOfTwo(instruction);
1837 } else {
1838 DCHECK(imm <= -2 || imm >= 2);
1839 GenerateDivRemWithAnyConstant(instruction);
1840 }
1841}
1842
1843void LocationsBuilderARMVIXL::VisitDiv(HDiv* div) {
1844 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
1845 if (div->GetResultType() == Primitive::kPrimLong) {
1846 // pLdiv runtime call.
1847 call_kind = LocationSummary::kCallOnMainOnly;
1848 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
1849 // sdiv will be replaced by other instruction sequence.
1850 } else if (div->GetResultType() == Primitive::kPrimInt &&
1851 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
1852 // pIdivmod runtime call.
1853 call_kind = LocationSummary::kCallOnMainOnly;
1854 }
1855
1856 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
1857
1858 switch (div->GetResultType()) {
1859 case Primitive::kPrimInt: {
1860 if (div->InputAt(1)->IsConstant()) {
1861 locations->SetInAt(0, Location::RequiresRegister());
1862 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
1863 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1864 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
1865 if (value == 1 || value == 0 || value == -1) {
1866 // No temp register required.
1867 } else {
1868 locations->AddTemp(Location::RequiresRegister());
1869 if (!IsPowerOfTwo(AbsOrMin(value))) {
1870 locations->AddTemp(Location::RequiresRegister());
1871 }
1872 }
1873 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
1874 locations->SetInAt(0, Location::RequiresRegister());
1875 locations->SetInAt(1, Location::RequiresRegister());
1876 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1877 } else {
1878 TODO_VIXL32(FATAL);
1879 }
1880 break;
1881 }
1882 case Primitive::kPrimLong: {
1883 TODO_VIXL32(FATAL);
1884 break;
1885 }
1886 case Primitive::kPrimFloat:
1887 case Primitive::kPrimDouble: {
1888 locations->SetInAt(0, Location::RequiresFpuRegister());
1889 locations->SetInAt(1, Location::RequiresFpuRegister());
1890 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1891 break;
1892 }
1893
1894 default:
1895 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1896 }
1897}
1898
1899void InstructionCodeGeneratorARMVIXL::VisitDiv(HDiv* div) {
1900 LocationSummary* locations = div->GetLocations();
1901 Location out = locations->Out();
1902 Location first = locations->InAt(0);
1903 Location second = locations->InAt(1);
1904
1905 switch (div->GetResultType()) {
1906 case Primitive::kPrimInt: {
1907 if (second.IsConstant()) {
1908 GenerateDivRemConstantIntegral(div);
1909 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
1910 __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
1911 } else {
1912 TODO_VIXL32(FATAL);
1913 }
1914 break;
1915 }
1916
1917 case Primitive::kPrimLong: {
1918 TODO_VIXL32(FATAL);
1919 break;
1920 }
1921
1922 case Primitive::kPrimFloat: {
1923 __ Vdiv(F32, OutputSRegister(div), InputSRegisterAt(div, 0), InputSRegisterAt(div, 1));
1924 break;
1925 }
1926
1927 case Primitive::kPrimDouble: {
1928 __ Vdiv(F64,
1929 FromLowSToD(out.AsFpuRegisterPairLow<vixl32::SRegister>()),
1930 FromLowSToD(first.AsFpuRegisterPairLow<vixl32::SRegister>()),
1931 FromLowSToD(second.AsFpuRegisterPairLow<vixl32::SRegister>()));
1932 break;
1933 }
1934
1935 default:
1936 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1937 }
1938}
1939
1940void LocationsBuilderARMVIXL::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1941 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
1942 ? LocationSummary::kCallOnSlowPath
1943 : LocationSummary::kNoCall;
1944 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
1945 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
1946 if (instruction->HasUses()) {
1947 locations->SetOut(Location::SameAsFirstInput());
1948 }
1949}
1950
1951void InstructionCodeGeneratorARMVIXL::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1952 DivZeroCheckSlowPathARMVIXL* slow_path =
1953 new (GetGraph()->GetArena()) DivZeroCheckSlowPathARMVIXL(instruction);
1954 codegen_->AddSlowPath(slow_path);
1955
1956 LocationSummary* locations = instruction->GetLocations();
1957 Location value = locations->InAt(0);
1958
1959 switch (instruction->GetType()) {
1960 case Primitive::kPrimBoolean:
1961 case Primitive::kPrimByte:
1962 case Primitive::kPrimChar:
1963 case Primitive::kPrimShort:
1964 case Primitive::kPrimInt: {
1965 if (value.IsRegister()) {
1966 __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
1967 } else {
1968 DCHECK(value.IsConstant()) << value;
1969 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
1970 __ B(slow_path->GetEntryLabel());
1971 }
1972 }
1973 break;
1974 }
1975 case Primitive::kPrimLong: {
1976 if (value.IsRegisterPair()) {
1977 UseScratchRegisterScope temps(GetVIXLAssembler());
1978 vixl32::Register temp = temps.Acquire();
1979 __ Orrs(temp,
1980 value.AsRegisterPairLow<vixl32::Register>(),
1981 Operand(value.AsRegisterPairHigh<vixl32::Register>()));
1982 __ B(eq, slow_path->GetEntryLabel());
1983 } else {
1984 DCHECK(value.IsConstant()) << value;
1985 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
1986 __ B(slow_path->GetEntryLabel());
1987 }
1988 }
1989 break;
1990 }
1991 default:
1992 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
1993 }
1994}
1995
1996void LocationsBuilderARMVIXL::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
1997 LOG(FATAL) << "Unreachable";
1998}
1999
2000void InstructionCodeGeneratorARMVIXL::VisitParallelMove(HParallelMove* instruction) {
2001 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
2002}
2003
2004ArmVIXLAssembler* ParallelMoveResolverARMVIXL::GetAssembler() const {
2005 return codegen_->GetAssembler();
2006}
2007
2008void ParallelMoveResolverARMVIXL::EmitMove(size_t index) {
2009 MoveOperands* move = moves_[index];
2010 Location source = move->GetSource();
2011 Location destination = move->GetDestination();
2012
2013 if (source.IsRegister()) {
2014 if (destination.IsRegister()) {
2015 __ Mov(destination.AsRegister<vixl32::Register>(), source.AsRegister<vixl32::Register>());
2016 } else if (destination.IsFpuRegister()) {
2017 __ Vmov(destination.AsFpuRegister<vixl32::SRegister>(),
2018 source.AsRegister<vixl32::Register>());
2019 } else {
2020 DCHECK(destination.IsStackSlot());
2021 GetAssembler()->StoreToOffset(kStoreWord,
2022 source.AsRegister<vixl32::Register>(),
2023 sp,
2024 destination.GetStackIndex());
2025 }
2026 } else if (source.IsStackSlot()) {
2027 TODO_VIXL32(FATAL);
2028 } else if (source.IsFpuRegister()) {
2029 TODO_VIXL32(FATAL);
2030 } else if (source.IsDoubleStackSlot()) {
2031 TODO_VIXL32(FATAL);
2032 } else if (source.IsRegisterPair()) {
2033 if (destination.IsRegisterPair()) {
2034 __ Mov(destination.AsRegisterPairLow<vixl32::Register>(),
2035 source.AsRegisterPairLow<vixl32::Register>());
2036 __ Mov(destination.AsRegisterPairHigh<vixl32::Register>(),
2037 source.AsRegisterPairHigh<vixl32::Register>());
2038 } else if (destination.IsFpuRegisterPair()) {
2039 __ Vmov(FromLowSToD(destination.AsFpuRegisterPairLow<vixl32::SRegister>()),
2040 source.AsRegisterPairLow<vixl32::Register>(),
2041 source.AsRegisterPairHigh<vixl32::Register>());
2042 } else {
2043 DCHECK(destination.IsDoubleStackSlot()) << destination;
2044 DCHECK(ExpectedPairLayout(source));
2045 GetAssembler()->StoreToOffset(kStoreWordPair,
2046 source.AsRegisterPairLow<vixl32::Register>(),
2047 sp,
2048 destination.GetStackIndex());
2049 }
2050 } else if (source.IsFpuRegisterPair()) {
2051 TODO_VIXL32(FATAL);
2052 } else {
2053 DCHECK(source.IsConstant()) << source;
2054 HConstant* constant = source.GetConstant();
2055 if (constant->IsIntConstant() || constant->IsNullConstant()) {
2056 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
2057 if (destination.IsRegister()) {
2058 __ Mov(destination.AsRegister<vixl32::Register>(), value);
2059 } else {
2060 DCHECK(destination.IsStackSlot());
2061 UseScratchRegisterScope temps(GetAssembler()->GetVIXLAssembler());
2062 vixl32::Register temp = temps.Acquire();
2063 __ Mov(temp, value);
2064 GetAssembler()->StoreToOffset(kStoreWord, temp, sp, destination.GetStackIndex());
2065 }
2066 } else if (constant->IsLongConstant()) {
2067 int64_t value = constant->AsLongConstant()->GetValue();
2068 if (destination.IsRegisterPair()) {
2069 __ Mov(destination.AsRegisterPairLow<vixl32::Register>(), Low32Bits(value));
2070 __ Mov(destination.AsRegisterPairHigh<vixl32::Register>(), High32Bits(value));
2071 } else {
2072 DCHECK(destination.IsDoubleStackSlot()) << destination;
2073 UseScratchRegisterScope temps(GetAssembler()->GetVIXLAssembler());
2074 vixl32::Register temp = temps.Acquire();
2075 __ Mov(temp, Low32Bits(value));
2076 GetAssembler()->StoreToOffset(kStoreWord, temp, sp, destination.GetStackIndex());
2077 __ Mov(temp, High32Bits(value));
2078 GetAssembler()->StoreToOffset(kStoreWord,
2079 temp,
2080 sp,
2081 destination.GetHighStackIndex(kArmWordSize));
2082 }
2083 } else if (constant->IsDoubleConstant()) {
2084 double value = constant->AsDoubleConstant()->GetValue();
2085 if (destination.IsFpuRegisterPair()) {
2086 __ Vmov(F64, FromLowSToD(destination.AsFpuRegisterPairLow<vixl32::SRegister>()), value);
2087 } else {
2088 DCHECK(destination.IsDoubleStackSlot()) << destination;
2089 uint64_t int_value = bit_cast<uint64_t, double>(value);
2090 UseScratchRegisterScope temps(GetAssembler()->GetVIXLAssembler());
2091 vixl32::Register temp = temps.Acquire();
2092 GetAssembler()->LoadImmediate(temp, Low32Bits(int_value));
2093 GetAssembler()->StoreToOffset(kStoreWord, temp, sp, destination.GetStackIndex());
2094 GetAssembler()->LoadImmediate(temp, High32Bits(int_value));
2095 GetAssembler()->StoreToOffset(kStoreWord,
2096 temp,
2097 sp,
2098 destination.GetHighStackIndex(kArmWordSize));
2099 }
2100 } else {
2101 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
2102 float value = constant->AsFloatConstant()->GetValue();
2103 if (destination.IsFpuRegister()) {
2104 __ Vmov(F32, destination.AsFpuRegister<vixl32::SRegister>(), value);
2105 } else {
2106 DCHECK(destination.IsStackSlot());
2107 UseScratchRegisterScope temps(GetAssembler()->GetVIXLAssembler());
2108 vixl32::Register temp = temps.Acquire();
2109 GetAssembler()->LoadImmediate(temp, bit_cast<int32_t, float>(value));
2110 GetAssembler()->StoreToOffset(kStoreWord, temp, sp, destination.GetStackIndex());
2111 }
2112 }
2113 }
2114}
2115
2116void ParallelMoveResolverARMVIXL::Exchange(Register reg, int mem) {
2117 TODO_VIXL32(FATAL);
2118}
2119
2120void ParallelMoveResolverARMVIXL::Exchange(int mem1, int mem2) {
2121 TODO_VIXL32(FATAL);
2122}
2123
2124void ParallelMoveResolverARMVIXL::EmitSwap(size_t index) {
2125 TODO_VIXL32(FATAL);
2126}
2127
2128void ParallelMoveResolverARMVIXL::SpillScratch(int reg ATTRIBUTE_UNUSED) {
2129 TODO_VIXL32(FATAL);
2130}
2131
2132void ParallelMoveResolverARMVIXL::RestoreScratch(int reg ATTRIBUTE_UNUSED) {
2133 TODO_VIXL32(FATAL);
2134}
2135
2136
2137// TODO: Remove when codegen complete.
2138#pragma GCC diagnostic pop
2139
2140#undef __
2141#undef QUICK_ENTRY_POINT
2142#undef TODO_VIXL32
2143
2144} // namespace arm
2145} // namespace art