blob: 9c9c604dca7de338f690151c74091e5c6d45b294 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 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.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000018
Calin Juravle34166012014-12-19 17:22:29 +000019#include "arch/arm/instruction_set_features_arm.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070020#include "art_method.h"
Zheng Xuc6667102015-05-15 16:08:45 +080021#include "code_generator_utils.h"
Vladimir Marko58155012015-08-19 12:49:41 +000022#include "compiled_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070023#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010024#include "gc/accounting/card_table.h"
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -080025#include "intrinsics.h"
26#include "intrinsics_arm.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070027#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070028#include "mirror/class-inl.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070029#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010030#include "utils/arm/assembler_arm.h"
31#include "utils/arm/managed_register_arm.h"
Roland Levillain946e1432014-11-11 17:35:19 +000032#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010033#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000034
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010036
Roland Levillain3b359c72015-11-17 19:35:12 +000037template<class MirrorType>
38class GcRoot;
39
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000040namespace arm {
41
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000042static bool ExpectedPairLayout(Location location) {
43 // We expected this for both core and fpu register pairs.
44 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
45}
46
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010047static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010048static constexpr Register kMethodRegisterArgument = R0;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010049
David Brazdil58282f42016-01-14 12:45:10 +000050static constexpr Register kCoreAlwaysSpillRegister = R5;
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000051static constexpr Register kCoreCalleeSaves[] =
Andreas Gampe501fd632015-09-10 16:11:06 -070052 { R5, R6, R7, R8, R10, R11, LR };
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000053static constexpr SRegister kFpuCalleeSaves[] =
54 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010055
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000056// D31 cannot be split into two S registers, and the register allocator only works on
57// S registers. Therefore there is no need to block it.
58static constexpr DRegister DTMP = D31;
59
Vladimir Markof3e0ee22015-12-17 15:23:13 +000060static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070061
Roland Levillain7cbd27f2016-08-11 23:53:33 +010062// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
63#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -070064#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmPointerSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065
Artem Serovf4d6aee2016-07-11 10:41:45 +010066static constexpr int kRegListThreshold = 4;
67
Artem Serovd300d8f2016-07-15 14:00:56 +010068// SaveLiveRegisters and RestoreLiveRegisters from SlowPathCodeARM operate on sets of S registers,
69// for each live D registers they treat two corresponding S registers as live ones.
70//
71// Two following functions (SaveContiguousSRegisterList, RestoreContiguousSRegisterList) build
72// from a list of contiguous S registers a list of contiguous D registers (processing first/last
73// S registers corner cases) and save/restore this new list treating them as D registers.
74// - decreasing code size
75// - avoiding hazards on Cortex-A57, when a pair of S registers for an actual live D register is
76// restored and then used in regular non SlowPath code as D register.
77//
78// For the following example (v means the S register is live):
79// D names: | D0 | D1 | D2 | D4 | ...
80// S names: | S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | ...
81// Live? | | v | v | v | v | v | v | | ...
82//
83// S1 and S6 will be saved/restored independently; D registers list (D1, D2) will be processed
84// as D registers.
85static size_t SaveContiguousSRegisterList(size_t first,
86 size_t last,
87 CodeGenerator* codegen,
88 size_t stack_offset) {
89 DCHECK_LE(first, last);
90 if ((first == last) && (first == 0)) {
91 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first);
92 return stack_offset;
93 }
94 if (first % 2 == 1) {
95 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first++);
96 }
97
98 bool save_last = false;
99 if (last % 2 == 0) {
100 save_last = true;
101 --last;
102 }
103
104 if (first < last) {
105 DRegister d_reg = static_cast<DRegister>(first / 2);
106 DCHECK_EQ((last - first + 1) % 2, 0u);
107 size_t number_of_d_regs = (last - first + 1) / 2;
108
109 if (number_of_d_regs == 1) {
Scott Wakelinga7812ae2016-10-17 10:03:36 +0100110 __ StoreDToOffset(d_reg, SP, stack_offset);
Artem Serovd300d8f2016-07-15 14:00:56 +0100111 } else if (number_of_d_regs > 1) {
112 __ add(IP, SP, ShifterOperand(stack_offset));
113 __ vstmiad(IP, d_reg, number_of_d_regs);
114 }
115 stack_offset += number_of_d_regs * kArmWordSize * 2;
116 }
117
118 if (save_last) {
119 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, last + 1);
120 }
121
122 return stack_offset;
123}
124
125static size_t RestoreContiguousSRegisterList(size_t first,
126 size_t last,
127 CodeGenerator* codegen,
128 size_t stack_offset) {
129 DCHECK_LE(first, last);
130 if ((first == last) && (first == 0)) {
131 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first);
132 return stack_offset;
133 }
134 if (first % 2 == 1) {
135 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first++);
136 }
137
138 bool restore_last = false;
139 if (last % 2 == 0) {
140 restore_last = true;
141 --last;
142 }
143
144 if (first < last) {
145 DRegister d_reg = static_cast<DRegister>(first / 2);
146 DCHECK_EQ((last - first + 1) % 2, 0u);
147 size_t number_of_d_regs = (last - first + 1) / 2;
148 if (number_of_d_regs == 1) {
149 __ LoadDFromOffset(d_reg, SP, stack_offset);
150 } else if (number_of_d_regs > 1) {
151 __ add(IP, SP, ShifterOperand(stack_offset));
152 __ vldmiad(IP, d_reg, number_of_d_regs);
153 }
154 stack_offset += number_of_d_regs * kArmWordSize * 2;
155 }
156
157 if (restore_last) {
158 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, last + 1);
159 }
160
161 return stack_offset;
162}
163
Artem Serovf4d6aee2016-07-11 10:41:45 +0100164void SlowPathCodeARM::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
165 size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
166 size_t orig_offset = stack_offset;
167
168 const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
169 for (uint32_t i : LowToHighBits(core_spills)) {
170 // If the register holds an object, update the stack mask.
171 if (locations->RegisterContainsObject(i)) {
172 locations->SetStackBit(stack_offset / kVRegSize);
173 }
174 DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
175 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
176 saved_core_stack_offsets_[i] = stack_offset;
177 stack_offset += kArmWordSize;
178 }
179
180 int reg_num = POPCOUNT(core_spills);
181 if (reg_num != 0) {
182 if (reg_num > kRegListThreshold) {
183 __ StoreList(RegList(core_spills), orig_offset);
184 } else {
185 stack_offset = orig_offset;
186 for (uint32_t i : LowToHighBits(core_spills)) {
187 stack_offset += codegen->SaveCoreRegister(stack_offset, i);
188 }
189 }
190 }
191
Artem Serovd300d8f2016-07-15 14:00:56 +0100192 uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
193 orig_offset = stack_offset;
Vladimir Marko804b03f2016-09-14 16:26:36 +0100194 for (uint32_t i : LowToHighBits(fp_spills)) {
Artem Serovf4d6aee2016-07-11 10:41:45 +0100195 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
196 saved_fpu_stack_offsets_[i] = stack_offset;
Artem Serovd300d8f2016-07-15 14:00:56 +0100197 stack_offset += kArmWordSize;
Artem Serovf4d6aee2016-07-11 10:41:45 +0100198 }
Artem Serovd300d8f2016-07-15 14:00:56 +0100199
200 stack_offset = orig_offset;
201 while (fp_spills != 0u) {
202 uint32_t begin = CTZ(fp_spills);
203 uint32_t tmp = fp_spills + (1u << begin);
204 fp_spills &= tmp; // Clear the contiguous range of 1s.
205 uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp); // CTZ(0) is undefined.
206 stack_offset = SaveContiguousSRegisterList(begin, end - 1, codegen, stack_offset);
207 }
208 DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
Artem Serovf4d6aee2016-07-11 10:41:45 +0100209}
210
211void SlowPathCodeARM::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
212 size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
213 size_t orig_offset = stack_offset;
214
215 const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
216 for (uint32_t i : LowToHighBits(core_spills)) {
217 DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
218 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
219 stack_offset += kArmWordSize;
220 }
221
222 int reg_num = POPCOUNT(core_spills);
223 if (reg_num != 0) {
224 if (reg_num > kRegListThreshold) {
225 __ LoadList(RegList(core_spills), orig_offset);
226 } else {
227 stack_offset = orig_offset;
228 for (uint32_t i : LowToHighBits(core_spills)) {
229 stack_offset += codegen->RestoreCoreRegister(stack_offset, i);
230 }
231 }
232 }
233
Artem Serovd300d8f2016-07-15 14:00:56 +0100234 uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
235 while (fp_spills != 0u) {
236 uint32_t begin = CTZ(fp_spills);
237 uint32_t tmp = fp_spills + (1u << begin);
238 fp_spills &= tmp; // Clear the contiguous range of 1s.
239 uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp); // CTZ(0) is undefined.
240 stack_offset = RestoreContiguousSRegisterList(begin, end - 1, codegen, stack_offset);
Artem Serovf4d6aee2016-07-11 10:41:45 +0100241 }
Artem Serovd300d8f2016-07-15 14:00:56 +0100242 DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
Artem Serovf4d6aee2016-07-11 10:41:45 +0100243}
244
245class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100246 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100247 explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCodeARM(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100248
Alexandre Rames67555f72014-11-18 10:55:16 +0000249 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100250 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100251 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000252 if (instruction_->CanThrowIntoCatchBlock()) {
253 // Live registers will be restored in the catch block if caught.
254 SaveLiveRegisters(codegen, instruction_->GetLocations());
255 }
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100256 arm_codegen->InvokeRuntime(kQuickThrowNullPointer,
257 instruction_,
258 instruction_->GetDexPc(),
259 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000260 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100261 }
262
Alexandre Rames8158f282015-08-07 10:26:17 +0100263 bool IsFatal() const OVERRIDE { return true; }
264
Alexandre Rames9931f312015-06-19 14:47:01 +0100265 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
266
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100267 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100268 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
269};
270
Artem Serovf4d6aee2016-07-11 10:41:45 +0100271class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
Calin Juravled0d48522014-11-04 16:40:20 +0000272 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100273 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCodeARM(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000274
Alexandre Rames67555f72014-11-18 10:55:16 +0000275 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000276 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
277 __ Bind(GetEntryLabel());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100278 arm_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000279 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +0000280 }
281
Alexandre Rames8158f282015-08-07 10:26:17 +0100282 bool IsFatal() const OVERRIDE { return true; }
283
Alexandre Rames9931f312015-06-19 14:47:01 +0100284 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
285
Calin Juravled0d48522014-11-04 16:40:20 +0000286 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000287 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
288};
289
Artem Serovf4d6aee2016-07-11 10:41:45 +0100290class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000291 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000292 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100293 : SlowPathCodeARM(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000294
Alexandre Rames67555f72014-11-18 10:55:16 +0000295 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100296 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000297 __ Bind(GetEntryLabel());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100298 arm_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000299 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100300 if (successor_ == nullptr) {
301 __ b(GetReturnLabel());
302 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100303 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100304 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000305 }
306
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100307 Label* GetReturnLabel() {
308 DCHECK(successor_ == nullptr);
309 return &return_label_;
310 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000311
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100312 HBasicBlock* GetSuccessor() const {
313 return successor_;
314 }
315
Alexandre Rames9931f312015-06-19 14:47:01 +0100316 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
317
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000318 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100319 // If not null, the block to branch to after the suspend check.
320 HBasicBlock* const successor_;
321
322 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000323 Label return_label_;
324
325 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
326};
327
Artem Serovf4d6aee2016-07-11 10:41:45 +0100328class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100329 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100330 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100331 : SlowPathCodeARM(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100332
Alexandre Rames67555f72014-11-18 10:55:16 +0000333 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100334 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100335 LocationSummary* locations = instruction_->GetLocations();
336
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100337 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000338 if (instruction_->CanThrowIntoCatchBlock()) {
339 // Live registers will be restored in the catch block if caught.
340 SaveLiveRegisters(codegen, instruction_->GetLocations());
341 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000342 // We're moving two locations to locations that could overlap, so we need a parallel
343 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100344 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000345 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100346 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000347 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100348 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100349 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100350 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
351 Primitive::kPrimInt);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100352 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
353 ? kQuickThrowStringBounds
354 : kQuickThrowArrayBounds;
355 arm_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100356 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Roland Levillain888d0672015-11-23 18:53:50 +0000357 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100358 }
359
Alexandre Rames8158f282015-08-07 10:26:17 +0100360 bool IsFatal() const OVERRIDE { return true; }
361
Alexandre Rames9931f312015-06-19 14:47:01 +0100362 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
363
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100364 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100365 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
366};
367
Artem Serovf4d6aee2016-07-11 10:41:45 +0100368class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100369 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000370 LoadClassSlowPathARM(HLoadClass* cls,
371 HInstruction* at,
372 uint32_t dex_pc,
373 bool do_clinit)
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000374 : SlowPathCodeARM(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000375 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
376 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100377
Alexandre Rames67555f72014-11-18 10:55:16 +0000378 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000379 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000380
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100381 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
382 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000383 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100384
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100385 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000386 dex::TypeIndex type_index = cls_->GetTypeIndex();
387 __ LoadImmediate(calling_convention.GetRegisterAt(0), type_index.index_);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100388 QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
389 : kQuickInitializeType;
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000390 arm_codegen->InvokeRuntime(entrypoint, instruction_, dex_pc_, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000391 if (do_clinit_) {
392 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
393 } else {
394 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
395 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000396
397 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000398 Location out = locations->Out();
399 if (out.IsValid()) {
400 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000401 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
402 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000403 RestoreLiveRegisters(codegen, locations);
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000404 // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
405 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
406 if (cls_ == instruction_ && cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry) {
407 DCHECK(out.IsValid());
408 // TODO: Change art_quick_initialize_type/art_quick_initialize_static_storage to
409 // kSaveEverything and use a temporary for the .bss entry address in the fast path,
410 // so that we can avoid another calculation here.
411 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko1998cd02017-01-13 13:02:58 +0000412 arm_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000413 __ BindTrackedLabel(&labels->movw_label);
414 __ movw(IP, /* placeholder */ 0u);
415 __ BindTrackedLabel(&labels->movt_label);
416 __ movt(IP, /* placeholder */ 0u);
417 __ BindTrackedLabel(&labels->add_pc_label);
418 __ add(IP, IP, ShifterOperand(PC));
419 __ str(locations->Out().AsRegister<Register>(), Address(IP));
420 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100421 __ b(GetExitLabel());
422 }
423
Alexandre Rames9931f312015-06-19 14:47:01 +0100424 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
425
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100426 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000427 // The class this slow path will load.
428 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100429
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000430 // The dex PC of `at_`.
431 const uint32_t dex_pc_;
432
433 // Whether to initialize the class.
434 const bool do_clinit_;
435
436 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100437};
438
Vladimir Markoaad75c62016-10-03 08:46:48 +0000439class LoadStringSlowPathARM : public SlowPathCodeARM {
440 public:
441 explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCodeARM(instruction) {}
442
443 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
444 LocationSummary* locations = instruction_->GetLocations();
445 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100446 HLoadString* load = instruction_->AsLoadString();
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000447 const dex::StringIndex string_index = load->GetStringIndex();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100448 Register out = locations->Out().AsRegister<Register>();
449 Register temp = locations->GetTemp(0).AsRegister<Register>();
450 constexpr bool call_saves_everything_except_r0 = (!kUseReadBarrier || kUseBakerReadBarrier);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000451
452 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
453 __ Bind(GetEntryLabel());
454 SaveLiveRegisters(codegen, locations);
455
456 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100457 // In the unlucky case that the `temp` is R0, we preserve the address in `out` across
458 // the kSaveEverything call (or use `out` for the address after non-kSaveEverything call).
459 bool temp_is_r0 = (temp == calling_convention.GetRegisterAt(0));
460 Register entry_address = temp_is_r0 ? out : temp;
461 DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
462 if (call_saves_everything_except_r0 && temp_is_r0) {
463 __ mov(entry_address, ShifterOperand(temp));
464 }
465
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000466 __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index.index_);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000467 arm_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
468 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100469
470 // Store the resolved String to the .bss entry.
471 if (call_saves_everything_except_r0) {
472 // The string entry address was preserved in `entry_address` thanks to kSaveEverything.
473 __ str(R0, Address(entry_address));
474 } else {
475 // For non-Baker read barrier, we need to re-calculate the address of the string entry.
476 CodeGeneratorARM::PcRelativePatchInfo* labels =
477 arm_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
478 __ BindTrackedLabel(&labels->movw_label);
479 __ movw(entry_address, /* placeholder */ 0u);
480 __ BindTrackedLabel(&labels->movt_label);
481 __ movt(entry_address, /* placeholder */ 0u);
482 __ BindTrackedLabel(&labels->add_pc_label);
483 __ add(entry_address, entry_address, ShifterOperand(PC));
484 __ str(R0, Address(entry_address));
485 }
486
Vladimir Markoaad75c62016-10-03 08:46:48 +0000487 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
Vladimir Markoaad75c62016-10-03 08:46:48 +0000488 RestoreLiveRegisters(codegen, locations);
489
Vladimir Markoaad75c62016-10-03 08:46:48 +0000490 __ b(GetExitLabel());
491 }
492
493 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
494
495 private:
496 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
497};
498
Artem Serovf4d6aee2016-07-11 10:41:45 +0100499class TypeCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000500 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000501 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100502 : SlowPathCodeARM(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000503
Alexandre Rames67555f72014-11-18 10:55:16 +0000504 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000505 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000506 DCHECK(instruction_->IsCheckCast()
507 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000508
509 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
510 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000511
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000512 if (!is_fatal_) {
513 SaveLiveRegisters(codegen, locations);
514 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000515
516 // We're moving two locations to locations that could overlap, so we need a parallel
517 // move resolver.
518 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800519 codegen->EmitParallelMoves(locations->InAt(0),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800520 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
521 Primitive::kPrimNot,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800522 locations->InAt(1),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800523 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
524 Primitive::kPrimNot);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000525 if (instruction_->IsInstanceOf()) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100526 arm_codegen->InvokeRuntime(kQuickInstanceofNonTrivial,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100527 instruction_,
528 instruction_->GetDexPc(),
529 this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800530 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000531 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
532 } else {
533 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800534 arm_codegen->InvokeRuntime(kQuickCheckInstanceOf,
535 instruction_,
536 instruction_->GetDexPc(),
537 this);
538 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000539 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000540
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000541 if (!is_fatal_) {
542 RestoreLiveRegisters(codegen, locations);
543 __ b(GetExitLabel());
544 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000545 }
546
Alexandre Rames9931f312015-06-19 14:47:01 +0100547 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
548
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000549 bool IsFatal() const OVERRIDE { return is_fatal_; }
550
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000551 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000552 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000553
554 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
555};
556
Artem Serovf4d6aee2016-07-11 10:41:45 +0100557class DeoptimizationSlowPathARM : public SlowPathCodeARM {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700558 public:
Aart Bik42249c32016-01-07 15:33:50 -0800559 explicit DeoptimizationSlowPathARM(HDeoptimize* instruction)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100560 : SlowPathCodeARM(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700561
562 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800563 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700564 __ Bind(GetEntryLabel());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100565 arm_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000566 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700567 }
568
Alexandre Rames9931f312015-06-19 14:47:01 +0100569 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
570
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700571 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700572 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
573};
574
Artem Serovf4d6aee2016-07-11 10:41:45 +0100575class ArraySetSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100576 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100577 explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCodeARM(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100578
579 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
580 LocationSummary* locations = instruction_->GetLocations();
581 __ Bind(GetEntryLabel());
582 SaveLiveRegisters(codegen, locations);
583
584 InvokeRuntimeCallingConvention calling_convention;
585 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
586 parallel_move.AddMove(
587 locations->InAt(0),
588 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
589 Primitive::kPrimNot,
590 nullptr);
591 parallel_move.AddMove(
592 locations->InAt(1),
593 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
594 Primitive::kPrimInt,
595 nullptr);
596 parallel_move.AddMove(
597 locations->InAt(2),
598 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
599 Primitive::kPrimNot,
600 nullptr);
601 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
602
603 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100604 arm_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000605 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100606 RestoreLiveRegisters(codegen, locations);
607 __ b(GetExitLabel());
608 }
609
610 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
611
612 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100613 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
614};
615
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100616// Slow path marking an object reference `ref` during a read
617// barrier. The field `obj.field` in the object `obj` holding this
618// reference does not get updated by this slow path after marking (see
619// ReadBarrierMarkAndUpdateFieldSlowPathARM below for that).
620//
621// This means that after the execution of this slow path, `ref` will
622// always be up-to-date, but `obj.field` may not; i.e., after the
623// flip, `ref` will be a to-space reference, but `obj.field` will
624// probably still be a from-space reference (unless it gets updated by
625// another thread, or if another thread installed another object
626// reference (different from `ref`) in `obj.field`).
Artem Serovf4d6aee2016-07-11 10:41:45 +0100627class ReadBarrierMarkSlowPathARM : public SlowPathCodeARM {
Roland Levillainc9285912015-12-18 10:38:42 +0000628 public:
Mathieu Chartierfe814e82016-11-09 14:32:49 -0800629 ReadBarrierMarkSlowPathARM(HInstruction* instruction,
630 Location ref,
631 Location entrypoint = Location::NoLocation())
632 : SlowPathCodeARM(instruction), ref_(ref), entrypoint_(entrypoint) {
Roland Levillainc9285912015-12-18 10:38:42 +0000633 DCHECK(kEmitCompilerReadBarrier);
634 }
635
636 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
637
638 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
639 LocationSummary* locations = instruction_->GetLocations();
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100640 Register ref_reg = ref_.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +0000641 DCHECK(locations->CanCall());
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100642 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillainc9285912015-12-18 10:38:42 +0000643 DCHECK(instruction_->IsInstanceFieldGet() ||
644 instruction_->IsStaticFieldGet() ||
645 instruction_->IsArrayGet() ||
Roland Levillain16d9f942016-08-25 17:27:56 +0100646 instruction_->IsArraySet() ||
Roland Levillainc9285912015-12-18 10:38:42 +0000647 instruction_->IsLoadClass() ||
648 instruction_->IsLoadString() ||
649 instruction_->IsInstanceOf() ||
Roland Levillain3d312422016-06-23 13:53:42 +0100650 instruction_->IsCheckCast() ||
Roland Levillain0b671c02016-08-19 12:02:34 +0100651 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
652 (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
Roland Levillainc9285912015-12-18 10:38:42 +0000653 << "Unexpected instruction in read barrier marking slow path: "
654 << instruction_->DebugName();
Roland Levillain19c54192016-11-04 13:44:09 +0000655 // The read barrier instrumentation of object ArrayGet
656 // instructions does not support the HIntermediateAddress
657 // instruction.
658 DCHECK(!(instruction_->IsArrayGet() &&
659 instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
Roland Levillainc9285912015-12-18 10:38:42 +0000660
661 __ Bind(GetEntryLabel());
Roland Levillain4359e612016-07-20 11:32:19 +0100662 // No need to save live registers; it's taken care of by the
663 // entrypoint. Also, there is no need to update the stack mask,
664 // as this runtime call will not trigger a garbage collection.
Roland Levillainc9285912015-12-18 10:38:42 +0000665 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100666 DCHECK_NE(ref_reg, SP);
667 DCHECK_NE(ref_reg, LR);
668 DCHECK_NE(ref_reg, PC);
Roland Levillain0b671c02016-08-19 12:02:34 +0100669 // IP is used internally by the ReadBarrierMarkRegX entry point
670 // as a temporary, it cannot be the entry point's input/output.
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100671 DCHECK_NE(ref_reg, IP);
672 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCoreRegisters) << ref_reg;
Roland Levillain02b75802016-07-13 11:54:35 +0100673 // "Compact" slow path, saving two moves.
674 //
675 // Instead of using the standard runtime calling convention (input
676 // and output in R0):
677 //
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100678 // R0 <- ref
Roland Levillain02b75802016-07-13 11:54:35 +0100679 // R0 <- ReadBarrierMark(R0)
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100680 // ref <- R0
Roland Levillain02b75802016-07-13 11:54:35 +0100681 //
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100682 // we just use rX (the register containing `ref`) as input and output
Roland Levillain02b75802016-07-13 11:54:35 +0100683 // of a dedicated entrypoint:
684 //
685 // rX <- ReadBarrierMarkRegX(rX)
686 //
Mathieu Chartierfe814e82016-11-09 14:32:49 -0800687 if (entrypoint_.IsValid()) {
688 arm_codegen->ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction_, this);
689 __ blx(entrypoint_.AsRegister<Register>());
690 } else {
691 int32_t entry_point_offset =
692 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref_reg);
693 // This runtime call does not require a stack map.
694 arm_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
695 }
Roland Levillainc9285912015-12-18 10:38:42 +0000696 __ b(GetExitLabel());
697 }
698
699 private:
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100700 // The location (register) of the marked object reference.
701 const Location ref_;
Roland Levillainc9285912015-12-18 10:38:42 +0000702
Mathieu Chartierfe814e82016-11-09 14:32:49 -0800703 // The location of the entrypoint if already loaded.
704 const Location entrypoint_;
705
Roland Levillainc9285912015-12-18 10:38:42 +0000706 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
707};
708
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100709// Slow path marking an object reference `ref` during a read barrier,
710// and if needed, atomically updating the field `obj.field` in the
711// object `obj` holding this reference after marking (contrary to
712// ReadBarrierMarkSlowPathARM above, which never tries to update
713// `obj.field`).
714//
715// This means that after the execution of this slow path, both `ref`
716// and `obj.field` will be up-to-date; i.e., after the flip, both will
717// hold the same to-space reference (unless another thread installed
718// another object reference (different from `ref`) in `obj.field`).
719class ReadBarrierMarkAndUpdateFieldSlowPathARM : public SlowPathCodeARM {
720 public:
721 ReadBarrierMarkAndUpdateFieldSlowPathARM(HInstruction* instruction,
722 Location ref,
723 Register obj,
724 Location field_offset,
725 Register temp1,
726 Register temp2)
727 : SlowPathCodeARM(instruction),
728 ref_(ref),
729 obj_(obj),
730 field_offset_(field_offset),
731 temp1_(temp1),
732 temp2_(temp2) {
733 DCHECK(kEmitCompilerReadBarrier);
734 }
735
736 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkAndUpdateFieldSlowPathARM"; }
737
738 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
739 LocationSummary* locations = instruction_->GetLocations();
740 Register ref_reg = ref_.AsRegister<Register>();
741 DCHECK(locations->CanCall());
742 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
743 // This slow path is only used by the UnsafeCASObject intrinsic.
744 DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
745 << "Unexpected instruction in read barrier marking and field updating slow path: "
746 << instruction_->DebugName();
747 DCHECK(instruction_->GetLocations()->Intrinsified());
748 DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
749 DCHECK(field_offset_.IsRegisterPair()) << field_offset_;
750
751 __ Bind(GetEntryLabel());
752
753 // Save the old reference.
754 // Note that we cannot use IP to save the old reference, as IP is
755 // used internally by the ReadBarrierMarkRegX entry point, and we
756 // need the old reference after the call to that entry point.
757 DCHECK_NE(temp1_, IP);
758 __ Mov(temp1_, ref_reg);
759
760 // No need to save live registers; it's taken care of by the
761 // entrypoint. Also, there is no need to update the stack mask,
762 // as this runtime call will not trigger a garbage collection.
763 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
764 DCHECK_NE(ref_reg, SP);
765 DCHECK_NE(ref_reg, LR);
766 DCHECK_NE(ref_reg, PC);
767 // IP is used internally by the ReadBarrierMarkRegX entry point
768 // as a temporary, it cannot be the entry point's input/output.
769 DCHECK_NE(ref_reg, IP);
770 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCoreRegisters) << ref_reg;
771 // "Compact" slow path, saving two moves.
772 //
773 // Instead of using the standard runtime calling convention (input
774 // and output in R0):
775 //
776 // R0 <- ref
777 // R0 <- ReadBarrierMark(R0)
778 // ref <- R0
779 //
780 // we just use rX (the register containing `ref`) as input and output
781 // of a dedicated entrypoint:
782 //
783 // rX <- ReadBarrierMarkRegX(rX)
784 //
785 int32_t entry_point_offset =
786 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref_reg);
787 // This runtime call does not require a stack map.
788 arm_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
789
790 // If the new reference is different from the old reference,
791 // update the field in the holder (`*(obj_ + field_offset_)`).
792 //
793 // Note that this field could also hold a different object, if
794 // another thread had concurrently changed it. In that case, the
795 // LDREX/SUBS/ITNE sequence of instructions in the compare-and-set
796 // (CAS) operation below would abort the CAS, leaving the field
797 // as-is.
798 Label done;
799 __ cmp(temp1_, ShifterOperand(ref_reg));
800 __ b(&done, EQ);
801
802 // Update the the holder's field atomically. This may fail if
803 // mutator updates before us, but it's OK. This is achieved
804 // using a strong compare-and-set (CAS) operation with relaxed
805 // memory synchronization ordering, where the expected value is
806 // the old reference and the desired value is the new reference.
807
808 // Convenience aliases.
809 Register base = obj_;
810 // The UnsafeCASObject intrinsic uses a register pair as field
811 // offset ("long offset"), of which only the low part contains
812 // data.
813 Register offset = field_offset_.AsRegisterPairLow<Register>();
814 Register expected = temp1_;
815 Register value = ref_reg;
816 Register tmp_ptr = IP; // Pointer to actual memory.
817 Register tmp = temp2_; // Value in memory.
818
819 __ add(tmp_ptr, base, ShifterOperand(offset));
820
821 if (kPoisonHeapReferences) {
822 __ PoisonHeapReference(expected);
823 if (value == expected) {
824 // Do not poison `value`, as it is the same register as
825 // `expected`, which has just been poisoned.
826 } else {
827 __ PoisonHeapReference(value);
828 }
829 }
830
831 // do {
832 // tmp = [r_ptr] - expected;
833 // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
834
Roland Levillain24a4d112016-10-26 13:10:46 +0100835 Label loop_head, exit_loop;
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100836 __ Bind(&loop_head);
837
838 __ ldrex(tmp, tmp_ptr);
839
840 __ subs(tmp, tmp, ShifterOperand(expected));
841
Roland Levillain24a4d112016-10-26 13:10:46 +0100842 __ it(NE);
843 __ clrex(NE);
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100844
Roland Levillain24a4d112016-10-26 13:10:46 +0100845 __ b(&exit_loop, NE);
846
847 __ strex(tmp, value, tmp_ptr);
848 __ cmp(tmp, ShifterOperand(1));
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100849 __ b(&loop_head, EQ);
850
Roland Levillain24a4d112016-10-26 13:10:46 +0100851 __ Bind(&exit_loop);
852
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100853 if (kPoisonHeapReferences) {
854 __ UnpoisonHeapReference(expected);
855 if (value == expected) {
856 // Do not unpoison `value`, as it is the same register as
857 // `expected`, which has just been unpoisoned.
858 } else {
859 __ UnpoisonHeapReference(value);
860 }
861 }
862
863 __ Bind(&done);
864 __ b(GetExitLabel());
865 }
866
867 private:
868 // The location (register) of the marked object reference.
869 const Location ref_;
870 // The register containing the object holding the marked object reference field.
871 const Register obj_;
872 // The location of the offset of the marked reference field within `obj_`.
873 Location field_offset_;
874
875 const Register temp1_;
876 const Register temp2_;
877
878 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkAndUpdateFieldSlowPathARM);
879};
880
Roland Levillain3b359c72015-11-17 19:35:12 +0000881// Slow path generating a read barrier for a heap reference.
Artem Serovf4d6aee2016-07-11 10:41:45 +0100882class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCodeARM {
Roland Levillain3b359c72015-11-17 19:35:12 +0000883 public:
884 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
885 Location out,
886 Location ref,
887 Location obj,
888 uint32_t offset,
889 Location index)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100890 : SlowPathCodeARM(instruction),
Roland Levillain3b359c72015-11-17 19:35:12 +0000891 out_(out),
892 ref_(ref),
893 obj_(obj),
894 offset_(offset),
895 index_(index) {
896 DCHECK(kEmitCompilerReadBarrier);
897 // If `obj` is equal to `out` or `ref`, it means the initial object
898 // has been overwritten by (or after) the heap object reference load
899 // to be instrumented, e.g.:
900 //
901 // __ LoadFromOffset(kLoadWord, out, out, offset);
Roland Levillainc9285912015-12-18 10:38:42 +0000902 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain3b359c72015-11-17 19:35:12 +0000903 //
904 // In that case, we have lost the information about the original
905 // object, and the emitted read barrier cannot work properly.
906 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
907 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
908 }
909
910 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
911 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
912 LocationSummary* locations = instruction_->GetLocations();
913 Register reg_out = out_.AsRegister<Register>();
914 DCHECK(locations->CanCall());
915 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillain3d312422016-06-23 13:53:42 +0100916 DCHECK(instruction_->IsInstanceFieldGet() ||
917 instruction_->IsStaticFieldGet() ||
918 instruction_->IsArrayGet() ||
919 instruction_->IsInstanceOf() ||
920 instruction_->IsCheckCast() ||
Roland Levillaindec8f632016-07-22 17:10:06 +0100921 (instruction_->IsInvokeVirtual()) && instruction_->GetLocations()->Intrinsified())
Roland Levillainc9285912015-12-18 10:38:42 +0000922 << "Unexpected instruction in read barrier for heap reference slow path: "
923 << instruction_->DebugName();
Roland Levillain19c54192016-11-04 13:44:09 +0000924 // The read barrier instrumentation of object ArrayGet
925 // instructions does not support the HIntermediateAddress
926 // instruction.
927 DCHECK(!(instruction_->IsArrayGet() &&
928 instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
Roland Levillain3b359c72015-11-17 19:35:12 +0000929
930 __ Bind(GetEntryLabel());
931 SaveLiveRegisters(codegen, locations);
932
933 // We may have to change the index's value, but as `index_` is a
934 // constant member (like other "inputs" of this slow path),
935 // introduce a copy of it, `index`.
936 Location index = index_;
937 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +0100938 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain3b359c72015-11-17 19:35:12 +0000939 if (instruction_->IsArrayGet()) {
940 // Compute the actual memory offset and store it in `index`.
941 Register index_reg = index_.AsRegister<Register>();
942 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
943 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
944 // We are about to change the value of `index_reg` (see the
945 // calls to art::arm::Thumb2Assembler::Lsl and
946 // art::arm::Thumb2Assembler::AddConstant below), but it has
947 // not been saved by the previous call to
948 // art::SlowPathCode::SaveLiveRegisters, as it is a
949 // callee-save register --
950 // art::SlowPathCode::SaveLiveRegisters does not consider
951 // callee-save registers, as it has been designed with the
952 // assumption that callee-save registers are supposed to be
953 // handled by the called function. So, as a callee-save
954 // register, `index_reg` _would_ eventually be saved onto
955 // the stack, but it would be too late: we would have
956 // changed its value earlier. Therefore, we manually save
957 // it here into another freely available register,
958 // `free_reg`, chosen of course among the caller-save
959 // registers (as a callee-save `free_reg` register would
960 // exhibit the same problem).
961 //
962 // Note we could have requested a temporary register from
963 // the register allocator instead; but we prefer not to, as
964 // this is a slow path, and we know we can find a
965 // caller-save register that is available.
966 Register free_reg = FindAvailableCallerSaveRegister(codegen);
967 __ Mov(free_reg, index_reg);
968 index_reg = free_reg;
969 index = Location::RegisterLocation(index_reg);
970 } else {
971 // The initial register stored in `index_` has already been
972 // saved in the call to art::SlowPathCode::SaveLiveRegisters
973 // (as it is not a callee-save register), so we can freely
974 // use it.
975 }
976 // Shifting the index value contained in `index_reg` by the scale
977 // factor (2) cannot overflow in practice, as the runtime is
978 // unable to allocate object arrays with a size larger than
979 // 2^26 - 1 (that is, 2^28 - 4 bytes).
980 __ Lsl(index_reg, index_reg, TIMES_4);
981 static_assert(
982 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
983 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
984 __ AddConstant(index_reg, index_reg, offset_);
985 } else {
Roland Levillain3d312422016-06-23 13:53:42 +0100986 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
987 // intrinsics, `index_` is not shifted by a scale factor of 2
988 // (as in the case of ArrayGet), as it is actually an offset
989 // to an object field within an object.
990 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000991 DCHECK(instruction_->GetLocations()->Intrinsified());
992 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
993 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
994 << instruction_->AsInvoke()->GetIntrinsic();
995 DCHECK_EQ(offset_, 0U);
996 DCHECK(index_.IsRegisterPair());
997 // UnsafeGet's offset location is a register pair, the low
998 // part contains the correct offset.
999 index = index_.ToLow();
1000 }
1001 }
1002
1003 // We're moving two or three locations to locations that could
1004 // overlap, so we need a parallel move resolver.
1005 InvokeRuntimeCallingConvention calling_convention;
1006 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
1007 parallel_move.AddMove(ref_,
1008 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
1009 Primitive::kPrimNot,
1010 nullptr);
1011 parallel_move.AddMove(obj_,
1012 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
1013 Primitive::kPrimNot,
1014 nullptr);
1015 if (index.IsValid()) {
1016 parallel_move.AddMove(index,
1017 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
1018 Primitive::kPrimInt,
1019 nullptr);
1020 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1021 } else {
1022 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1023 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
1024 }
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001025 arm_codegen->InvokeRuntime(kQuickReadBarrierSlow, instruction_, instruction_->GetDexPc(), this);
Roland Levillain3b359c72015-11-17 19:35:12 +00001026 CheckEntrypointTypes<
1027 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
1028 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1029
1030 RestoreLiveRegisters(codegen, locations);
1031 __ b(GetExitLabel());
1032 }
1033
1034 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
1035
1036 private:
1037 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
1038 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
1039 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
1040 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
1041 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
1042 return static_cast<Register>(i);
1043 }
1044 }
1045 // We shall never fail to find a free caller-save register, as
1046 // there are more than two core caller-save registers on ARM
1047 // (meaning it is possible to find one which is different from
1048 // `ref` and `obj`).
1049 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
1050 LOG(FATAL) << "Could not find a free caller-save register";
1051 UNREACHABLE();
1052 }
1053
Roland Levillain3b359c72015-11-17 19:35:12 +00001054 const Location out_;
1055 const Location ref_;
1056 const Location obj_;
1057 const uint32_t offset_;
1058 // An additional location containing an index to an array.
1059 // Only used for HArrayGet and the UnsafeGetObject &
1060 // UnsafeGetObjectVolatile intrinsics.
1061 const Location index_;
1062
1063 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
1064};
1065
1066// Slow path generating a read barrier for a GC root.
Artem Serovf4d6aee2016-07-11 10:41:45 +01001067class ReadBarrierForRootSlowPathARM : public SlowPathCodeARM {
Roland Levillain3b359c72015-11-17 19:35:12 +00001068 public:
1069 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
Artem Serovf4d6aee2016-07-11 10:41:45 +01001070 : SlowPathCodeARM(instruction), out_(out), root_(root) {
Roland Levillainc9285912015-12-18 10:38:42 +00001071 DCHECK(kEmitCompilerReadBarrier);
1072 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001073
1074 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1075 LocationSummary* locations = instruction_->GetLocations();
1076 Register reg_out = out_.AsRegister<Register>();
1077 DCHECK(locations->CanCall());
1078 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillainc9285912015-12-18 10:38:42 +00001079 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
1080 << "Unexpected instruction in read barrier for GC root slow path: "
1081 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +00001082
1083 __ Bind(GetEntryLabel());
1084 SaveLiveRegisters(codegen, locations);
1085
1086 InvokeRuntimeCallingConvention calling_convention;
1087 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1088 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001089 arm_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
Roland Levillain3b359c72015-11-17 19:35:12 +00001090 instruction_,
1091 instruction_->GetDexPc(),
1092 this);
1093 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
1094 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1095
1096 RestoreLiveRegisters(codegen, locations);
1097 __ b(GetExitLabel());
1098 }
1099
1100 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
1101
1102 private:
Roland Levillain3b359c72015-11-17 19:35:12 +00001103 const Location out_;
1104 const Location root_;
1105
1106 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
1107};
1108
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00001109#undef __
Roland Levillain7cbd27f2016-08-11 23:53:33 +01001110// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
1111#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
Dave Allison20dfc792014-06-16 20:44:29 -07001112
Aart Bike9f37602015-10-09 11:15:55 -07001113inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -07001114 switch (cond) {
1115 case kCondEQ: return EQ;
1116 case kCondNE: return NE;
1117 case kCondLT: return LT;
1118 case kCondLE: return LE;
1119 case kCondGT: return GT;
1120 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -07001121 case kCondB: return LO;
1122 case kCondBE: return LS;
1123 case kCondA: return HI;
1124 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -07001125 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001126 LOG(FATAL) << "Unreachable";
1127 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001128}
1129
Aart Bike9f37602015-10-09 11:15:55 -07001130// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001131inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -07001132 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001133 case kCondEQ: return EQ;
1134 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -07001135 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001136 case kCondLT: return LO;
1137 case kCondLE: return LS;
1138 case kCondGT: return HI;
1139 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -07001140 // Unsigned remain unchanged.
1141 case kCondB: return LO;
1142 case kCondBE: return LS;
1143 case kCondA: return HI;
1144 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -07001145 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001146 LOG(FATAL) << "Unreachable";
1147 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001148}
1149
Vladimir Markod6e069b2016-01-18 11:11:01 +00001150inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
1151 // The ARM condition codes can express all the necessary branches, see the
1152 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
1153 // There is no dex instruction or HIR that would need the missing conditions
1154 // "equal or unordered" or "not equal".
1155 switch (cond) {
1156 case kCondEQ: return EQ;
1157 case kCondNE: return NE /* unordered */;
1158 case kCondLT: return gt_bias ? CC : LT /* unordered */;
1159 case kCondLE: return gt_bias ? LS : LE /* unordered */;
1160 case kCondGT: return gt_bias ? HI /* unordered */ : GT;
1161 case kCondGE: return gt_bias ? CS /* unordered */ : GE;
1162 default:
1163 LOG(FATAL) << "UNREACHABLE";
1164 UNREACHABLE();
1165 }
1166}
1167
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001168void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001169 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001170}
1171
1172void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001173 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001174}
1175
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001176size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1177 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
1178 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001179}
1180
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001181size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1182 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
1183 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001184}
1185
Nicolas Geoffray840e5462015-01-07 16:01:24 +00001186size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1187 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
1188 return kArmWordSize;
1189}
1190
1191size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1192 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
1193 return kArmWordSize;
1194}
1195
Calin Juravle34166012014-12-19 17:22:29 +00001196CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +00001197 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +01001198 const CompilerOptions& compiler_options,
1199 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001200 : CodeGenerator(graph,
1201 kNumberOfCoreRegisters,
1202 kNumberOfSRegisters,
1203 kNumberOfRegisterPairs,
1204 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1205 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +00001206 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
1207 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +01001208 compiler_options,
1209 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +01001210 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001211 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001212 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001213 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +01001214 assembler_(graph->GetArena()),
Vladimir Marko58155012015-08-19 12:49:41 +00001215 isa_features_(isa_features),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001216 uint32_literals_(std::less<uint32_t>(),
1217 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001218 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1219 boot_image_string_patches_(StringReferenceValueComparator(),
1220 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1221 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01001222 boot_image_type_patches_(TypeReferenceValueComparator(),
1223 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1224 pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko1998cd02017-01-13 13:02:58 +00001225 type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001226 boot_image_address_patches_(std::less<uint32_t>(),
Nicolas Geoffray132d8362016-11-16 09:19:42 +00001227 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1228 jit_string_patches_(StringReferenceValueComparator(),
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00001229 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1230 jit_class_patches_(TypeReferenceValueComparator(),
1231 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -07001232 // Always save the LR register to mimic Quick.
1233 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +01001234}
1235
Vladimir Markocf93a5c2015-06-16 11:33:24 +00001236void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
1237 // Ensure that we fix up branches and literal loads and emit the literal pool.
1238 __ FinalizeCode();
1239
1240 // Adjust native pc offsets in stack maps.
1241 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
1242 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
1243 uint32_t new_position = __ GetAdjustedPosition(old_position);
1244 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
1245 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +01001246 // Adjust pc offsets for the disassembly information.
1247 if (disasm_info_ != nullptr) {
1248 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
1249 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
1250 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
1251 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
1252 it.second.start = __ GetAdjustedPosition(it.second.start);
1253 it.second.end = __ GetAdjustedPosition(it.second.end);
1254 }
1255 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
1256 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
1257 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
1258 }
1259 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +00001260
1261 CodeGenerator::Finalize(allocator);
1262}
1263
David Brazdil58282f42016-01-14 12:45:10 +00001264void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001265 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01001266 blocked_core_registers_[SP] = true;
1267 blocked_core_registers_[LR] = true;
1268 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001269
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001270 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01001271 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001272
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001273 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01001274 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001275
David Brazdil58282f42016-01-14 12:45:10 +00001276 if (GetGraph()->IsDebuggable()) {
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +01001277 // Stubs do not save callee-save floating point registers. If the graph
1278 // is debuggable, we need to deal with these registers differently. For
1279 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001280 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1281 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
1282 }
1283 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001284}
1285
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001286InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08001287 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001288 assembler_(codegen->GetAssembler()),
1289 codegen_(codegen) {}
1290
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001291void CodeGeneratorARM::ComputeSpillMask() {
1292 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
1293 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
David Brazdil58282f42016-01-14 12:45:10 +00001294 // There is no easy instruction to restore just the PC on thumb2. We spill and
1295 // restore another arbitrary register.
1296 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001297 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
1298 // We use vpush and vpop for saving and restoring floating point registers, which take
1299 // a SRegister and the number of registers to save/restore after that SRegister. We
1300 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
1301 // but in the range.
1302 if (fpu_spill_mask_ != 0) {
1303 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
1304 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
1305 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
1306 fpu_spill_mask_ |= (1 << i);
1307 }
1308 }
1309}
1310
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001311static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01001312 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001313}
1314
1315static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01001316 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001317}
1318
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001319void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +00001320 bool skip_overflow_check =
1321 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001322 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001323 __ Bind(&frame_entry_label_);
1324
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001325 if (HasEmptyFrame()) {
1326 return;
1327 }
1328
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001329 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001330 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
1331 __ LoadFromOffset(kLoadWord, IP, IP, 0);
1332 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001333 }
1334
Andreas Gampe501fd632015-09-10 16:11:06 -07001335 __ PushList(core_spill_mask_);
1336 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
1337 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001338 if (fpu_spill_mask_ != 0) {
1339 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
1340 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001341 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +01001342 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001343 }
Mingyao Yang063fc772016-08-02 11:02:54 -07001344
1345 if (GetGraph()->HasShouldDeoptimizeFlag()) {
1346 // Initialize should_deoptimize flag to 0.
1347 __ mov(IP, ShifterOperand(0));
1348 __ StoreToOffset(kStoreWord, IP, SP, -kShouldDeoptimizeFlagSize);
1349 }
1350
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001351 int adjust = GetFrameSize() - FrameEntrySpillSize();
1352 __ AddConstant(SP, -adjust);
1353 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray96eeb4e2016-10-12 22:03:31 +01001354
1355 // Save the current method if we need it. Note that we do not
1356 // do this in HCurrentMethod, as the instruction might have been removed
1357 // in the SSA graph.
1358 if (RequiresCurrentMethod()) {
1359 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
1360 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001361}
1362
1363void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001364 if (HasEmptyFrame()) {
1365 __ bx(LR);
1366 return;
1367 }
David Srbeckyc34dc932015-04-12 09:27:43 +01001368 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001369 int adjust = GetFrameSize() - FrameEntrySpillSize();
1370 __ AddConstant(SP, adjust);
1371 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001372 if (fpu_spill_mask_ != 0) {
1373 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
1374 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
Andreas Gampe542451c2016-07-26 09:02:02 -07001375 __ cfi().AdjustCFAOffset(-static_cast<int>(kArmPointerSize) * POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001376 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001377 }
Andreas Gampe501fd632015-09-10 16:11:06 -07001378 // Pop LR into PC to return.
1379 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
1380 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
1381 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +01001382 __ cfi().RestoreState();
1383 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001384}
1385
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001386void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07001387 Label* label = GetLabelOf(block);
1388 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001389}
1390
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001391Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001392 switch (type) {
1393 case Primitive::kPrimBoolean:
1394 case Primitive::kPrimByte:
1395 case Primitive::kPrimChar:
1396 case Primitive::kPrimShort:
1397 case Primitive::kPrimInt:
1398 case Primitive::kPrimNot: {
1399 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001400 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001401 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001402 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001403 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001404 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001405 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001406 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001407
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001408 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001409 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001410 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001411 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001412 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001413 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00001414 if (calling_convention.GetRegisterAt(index) == R1) {
1415 // Skip R1, and use R2_R3 instead.
1416 gp_index_++;
1417 index++;
1418 }
1419 }
1420 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
1421 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001422 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01001423
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00001424 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001425 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001426 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001427 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
1428 }
1429 }
1430
1431 case Primitive::kPrimFloat: {
1432 uint32_t stack_index = stack_index_++;
1433 if (float_index_ % 2 == 0) {
1434 float_index_ = std::max(double_index_, float_index_);
1435 }
1436 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
1437 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
1438 } else {
1439 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
1440 }
1441 }
1442
1443 case Primitive::kPrimDouble: {
1444 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
1445 uint32_t stack_index = stack_index_;
1446 stack_index_ += 2;
1447 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
1448 uint32_t index = double_index_;
1449 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001450 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001451 calling_convention.GetFpuRegisterAt(index),
1452 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001453 DCHECK(ExpectedPairLayout(result));
1454 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001455 } else {
1456 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001457 }
1458 }
1459
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001460 case Primitive::kPrimVoid:
1461 LOG(FATAL) << "Unexpected parameter type " << type;
1462 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001463 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001464 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001465}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001466
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001467Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001468 switch (type) {
1469 case Primitive::kPrimBoolean:
1470 case Primitive::kPrimByte:
1471 case Primitive::kPrimChar:
1472 case Primitive::kPrimShort:
1473 case Primitive::kPrimInt:
1474 case Primitive::kPrimNot: {
1475 return Location::RegisterLocation(R0);
1476 }
1477
1478 case Primitive::kPrimFloat: {
1479 return Location::FpuRegisterLocation(S0);
1480 }
1481
1482 case Primitive::kPrimLong: {
1483 return Location::RegisterPairLocation(R0, R1);
1484 }
1485
1486 case Primitive::kPrimDouble: {
1487 return Location::FpuRegisterPairLocation(S0, S1);
1488 }
1489
1490 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00001491 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001492 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001493
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001494 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001495}
1496
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001497Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
1498 return Location::RegisterLocation(kMethodRegisterArgument);
1499}
1500
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001501void CodeGeneratorARM::Move32(Location destination, Location source) {
1502 if (source.Equals(destination)) {
1503 return;
1504 }
1505 if (destination.IsRegister()) {
1506 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001507 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001508 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001509 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001510 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001511 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001512 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001513 } else if (destination.IsFpuRegister()) {
1514 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001515 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001516 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001517 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001518 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001519 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001520 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001521 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001522 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001523 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001524 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001525 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001526 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001527 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001528 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001529 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1530 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001531 }
1532 }
1533}
1534
1535void CodeGeneratorARM::Move64(Location destination, Location source) {
1536 if (source.Equals(destination)) {
1537 return;
1538 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001539 if (destination.IsRegisterPair()) {
1540 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001541 EmitParallelMoves(
1542 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1543 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001544 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001545 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001546 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
1547 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001548 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001549 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001550 } else if (source.IsFpuRegisterPair()) {
1551 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
1552 destination.AsRegisterPairHigh<Register>(),
1553 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001554 } else {
1555 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001556 DCHECK(ExpectedPairLayout(destination));
1557 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
1558 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001559 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001560 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001561 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001562 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1563 SP,
1564 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01001565 } else if (source.IsRegisterPair()) {
1566 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1567 source.AsRegisterPairLow<Register>(),
1568 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001569 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001570 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001571 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001572 } else {
1573 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001574 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001575 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001576 if (source.AsRegisterPairLow<Register>() == R1) {
1577 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001578 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
1579 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001580 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001581 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001582 SP, destination.GetStackIndex());
1583 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001584 } else if (source.IsFpuRegisterPair()) {
1585 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
1586 SP,
1587 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001588 } else {
1589 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001590 EmitParallelMoves(
1591 Location::StackSlot(source.GetStackIndex()),
1592 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001593 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001594 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001595 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
1596 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001597 }
1598 }
1599}
1600
Calin Juravle175dc732015-08-25 15:42:32 +01001601void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1602 DCHECK(location.IsRegister());
1603 __ LoadImmediate(location.AsRegister<Register>(), value);
1604}
1605
Calin Juravlee460d1d2015-09-29 04:52:17 +01001606void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
David Brazdil74eb1b22015-12-14 11:44:01 +00001607 HParallelMove move(GetGraph()->GetArena());
1608 move.AddMove(src, dst, dst_type, nullptr);
1609 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001610}
1611
1612void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1613 if (location.IsRegister()) {
1614 locations->AddTemp(location);
1615 } else if (location.IsRegisterPair()) {
1616 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1617 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1618 } else {
1619 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1620 }
1621}
1622
Calin Juravle175dc732015-08-25 15:42:32 +01001623void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1624 HInstruction* instruction,
1625 uint32_t dex_pc,
1626 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01001627 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001628 GenerateInvokeRuntime(GetThreadOffset<kArmPointerSize>(entrypoint).Int32Value());
Serban Constantinescuda8ffec2016-03-09 12:02:11 +00001629 if (EntrypointRequiresStackMap(entrypoint)) {
1630 RecordPcInfo(instruction, dex_pc, slow_path);
1631 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001632}
1633
Roland Levillaindec8f632016-07-22 17:10:06 +01001634void CodeGeneratorARM::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1635 HInstruction* instruction,
1636 SlowPathCode* slow_path) {
1637 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001638 GenerateInvokeRuntime(entry_point_offset);
1639}
1640
1641void CodeGeneratorARM::GenerateInvokeRuntime(int32_t entry_point_offset) {
Roland Levillaindec8f632016-07-22 17:10:06 +01001642 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1643 __ blx(LR);
1644}
1645
David Brazdilfc6a86a2015-06-26 10:33:45 +00001646void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001647 DCHECK(!successor->IsExitBlock());
1648
1649 HBasicBlock* block = got->GetBlock();
1650 HInstruction* previous = got->GetPrevious();
1651
1652 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001653 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001654 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1655 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1656 return;
1657 }
1658
1659 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1660 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1661 }
1662 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001663 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001664 }
1665}
1666
David Brazdilfc6a86a2015-06-26 10:33:45 +00001667void LocationsBuilderARM::VisitGoto(HGoto* got) {
1668 got->SetLocations(nullptr);
1669}
1670
1671void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1672 HandleGoto(got, got->GetSuccessor());
1673}
1674
1675void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1676 try_boundary->SetLocations(nullptr);
1677}
1678
1679void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1680 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1681 if (!successor->IsExitBlock()) {
1682 HandleGoto(try_boundary, successor);
1683 }
1684}
1685
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001686void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001687 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001688}
1689
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001690void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001691}
1692
Vladimir Marko37dd80d2016-08-01 17:41:45 +01001693void InstructionCodeGeneratorARM::GenerateVcmp(HInstruction* instruction) {
1694 Primitive::Type type = instruction->InputAt(0)->GetType();
1695 Location lhs_loc = instruction->GetLocations()->InAt(0);
1696 Location rhs_loc = instruction->GetLocations()->InAt(1);
1697 if (rhs_loc.IsConstant()) {
1698 // 0.0 is the only immediate that can be encoded directly in
1699 // a VCMP instruction.
1700 //
1701 // Both the JLS (section 15.20.1) and the JVMS (section 6.5)
1702 // specify that in a floating-point comparison, positive zero
1703 // and negative zero are considered equal, so we can use the
1704 // literal 0.0 for both cases here.
1705 //
1706 // Note however that some methods (Float.equal, Float.compare,
1707 // Float.compareTo, Double.equal, Double.compare,
1708 // Double.compareTo, Math.max, Math.min, StrictMath.max,
1709 // StrictMath.min) consider 0.0 to be (strictly) greater than
1710 // -0.0. So if we ever translate calls to these methods into a
1711 // HCompare instruction, we must handle the -0.0 case with
1712 // care here.
1713 DCHECK(rhs_loc.GetConstant()->IsArithmeticZero());
1714 if (type == Primitive::kPrimFloat) {
1715 __ vcmpsz(lhs_loc.AsFpuRegister<SRegister>());
1716 } else {
1717 DCHECK_EQ(type, Primitive::kPrimDouble);
1718 __ vcmpdz(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()));
1719 }
1720 } else {
1721 if (type == Primitive::kPrimFloat) {
1722 __ vcmps(lhs_loc.AsFpuRegister<SRegister>(), rhs_loc.AsFpuRegister<SRegister>());
1723 } else {
1724 DCHECK_EQ(type, Primitive::kPrimDouble);
1725 __ vcmpd(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()),
1726 FromLowSToD(rhs_loc.AsFpuRegisterPairLow<SRegister>()));
1727 }
1728 }
1729}
1730
Roland Levillain4fa13f62015-07-06 18:11:54 +01001731void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1732 Label* true_label,
Vladimir Markod6e069b2016-01-18 11:11:01 +00001733 Label* false_label ATTRIBUTE_UNUSED) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001734 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00001735 __ b(true_label, ARMFPCondition(cond->GetCondition(), cond->IsGtBias()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001736}
1737
1738void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1739 Label* true_label,
1740 Label* false_label) {
1741 LocationSummary* locations = cond->GetLocations();
1742 Location left = locations->InAt(0);
1743 Location right = locations->InAt(1);
1744 IfCondition if_cond = cond->GetCondition();
1745
1746 Register left_high = left.AsRegisterPairHigh<Register>();
1747 Register left_low = left.AsRegisterPairLow<Register>();
1748 IfCondition true_high_cond = if_cond;
1749 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001750 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01001751
1752 // Set the conditions for the test, remembering that == needs to be
1753 // decided using the low words.
Aart Bike9f37602015-10-09 11:15:55 -07001754 // TODO: consider avoiding jumps with temporary and CMP low+SBC high
Roland Levillain4fa13f62015-07-06 18:11:54 +01001755 switch (if_cond) {
1756 case kCondEQ:
1757 case kCondNE:
1758 // Nothing to do.
1759 break;
1760 case kCondLT:
1761 false_high_cond = kCondGT;
1762 break;
1763 case kCondLE:
1764 true_high_cond = kCondLT;
1765 break;
1766 case kCondGT:
1767 false_high_cond = kCondLT;
1768 break;
1769 case kCondGE:
1770 true_high_cond = kCondGT;
1771 break;
Aart Bike9f37602015-10-09 11:15:55 -07001772 case kCondB:
1773 false_high_cond = kCondA;
1774 break;
1775 case kCondBE:
1776 true_high_cond = kCondB;
1777 break;
1778 case kCondA:
1779 false_high_cond = kCondB;
1780 break;
1781 case kCondAE:
1782 true_high_cond = kCondA;
1783 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01001784 }
1785 if (right.IsConstant()) {
1786 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1787 int32_t val_low = Low32Bits(value);
1788 int32_t val_high = High32Bits(value);
1789
Vladimir Markoac6ac102015-12-17 12:14:00 +00001790 __ CmpConstant(left_high, val_high);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001791 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001792 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001793 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001794 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001795 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001796 __ b(true_label, ARMCondition(true_high_cond));
1797 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001798 }
1799 // Must be equal high, so compare the lows.
Vladimir Markoac6ac102015-12-17 12:14:00 +00001800 __ CmpConstant(left_low, val_low);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001801 } else {
1802 Register right_high = right.AsRegisterPairHigh<Register>();
1803 Register right_low = right.AsRegisterPairLow<Register>();
1804
1805 __ cmp(left_high, ShifterOperand(right_high));
1806 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001807 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001808 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001809 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001810 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001811 __ b(true_label, ARMCondition(true_high_cond));
1812 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001813 }
1814 // Must be equal high, so compare the lows.
1815 __ cmp(left_low, ShifterOperand(right_low));
1816 }
1817 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07001818 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01001819 __ b(true_label, final_condition);
1820}
1821
David Brazdil0debae72015-11-12 18:37:00 +00001822void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
1823 Label* true_target_in,
1824 Label* false_target_in) {
1825 // Generated branching requires both targets to be explicit. If either of the
1826 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1827 Label fallthrough_target;
1828 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1829 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1830
Roland Levillain4fa13f62015-07-06 18:11:54 +01001831 Primitive::Type type = condition->InputAt(0)->GetType();
1832 switch (type) {
1833 case Primitive::kPrimLong:
1834 GenerateLongComparesAndJumps(condition, true_target, false_target);
1835 break;
1836 case Primitive::kPrimFloat:
Roland Levillain4fa13f62015-07-06 18:11:54 +01001837 case Primitive::kPrimDouble:
Vladimir Marko37dd80d2016-08-01 17:41:45 +01001838 GenerateVcmp(condition);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001839 GenerateFPJumps(condition, true_target, false_target);
1840 break;
1841 default:
1842 LOG(FATAL) << "Unexpected compare type " << type;
1843 }
1844
David Brazdil0debae72015-11-12 18:37:00 +00001845 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001846 __ b(false_target);
1847 }
David Brazdil0debae72015-11-12 18:37:00 +00001848
1849 if (fallthrough_target.IsLinked()) {
1850 __ Bind(&fallthrough_target);
1851 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001852}
1853
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001854void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001855 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001856 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001857 Label* false_target) {
1858 HInstruction* cond = instruction->InputAt(condition_input_index);
1859
1860 if (true_target == nullptr && false_target == nullptr) {
1861 // Nothing to do. The code always falls through.
1862 return;
1863 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00001864 // Constant condition, statically compared against "true" (integer value 1).
1865 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00001866 if (true_target != nullptr) {
1867 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001868 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001869 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00001870 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00001871 if (false_target != nullptr) {
1872 __ b(false_target);
1873 }
1874 }
1875 return;
1876 }
1877
1878 // The following code generates these patterns:
1879 // (1) true_target == nullptr && false_target != nullptr
1880 // - opposite condition true => branch to false_target
1881 // (2) true_target != nullptr && false_target == nullptr
1882 // - condition true => branch to true_target
1883 // (3) true_target != nullptr && false_target != nullptr
1884 // - condition true => branch to true_target
1885 // - branch to false_target
1886 if (IsBooleanValueOrMaterializedCondition(cond)) {
1887 // Condition has been materialized, compare the output to 0.
1888 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
1889 DCHECK(cond_val.IsRegister());
1890 if (true_target == nullptr) {
1891 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
1892 } else {
1893 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001894 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001895 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001896 // Condition has not been materialized. Use its inputs as the comparison and
1897 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001898 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00001899
1900 // If this is a long or FP comparison that has been folded into
1901 // the HCondition, generate the comparison directly.
1902 Primitive::Type type = condition->InputAt(0)->GetType();
1903 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1904 GenerateCompareTestAndBranch(condition, true_target, false_target);
1905 return;
1906 }
1907
1908 LocationSummary* locations = cond->GetLocations();
1909 DCHECK(locations->InAt(0).IsRegister());
1910 Register left = locations->InAt(0).AsRegister<Register>();
1911 Location right = locations->InAt(1);
1912 if (right.IsRegister()) {
1913 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001914 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001915 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001916 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
David Brazdil0debae72015-11-12 18:37:00 +00001917 }
1918 if (true_target == nullptr) {
1919 __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
1920 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001921 __ b(true_target, ARMCondition(condition->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001922 }
Dave Allison20dfc792014-06-16 20:44:29 -07001923 }
David Brazdil0debae72015-11-12 18:37:00 +00001924
1925 // If neither branch falls through (case 3), the conditional branch to `true_target`
1926 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1927 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001928 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001929 }
1930}
1931
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001932void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001933 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1934 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001935 locations->SetInAt(0, Location::RequiresRegister());
1936 }
1937}
1938
1939void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001940 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1941 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1942 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1943 nullptr : codegen_->GetLabelOf(true_successor);
1944 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1945 nullptr : codegen_->GetLabelOf(false_successor);
1946 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001947}
1948
1949void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1950 LocationSummary* locations = new (GetGraph()->GetArena())
1951 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01001952 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
David Brazdil0debae72015-11-12 18:37:00 +00001953 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001954 locations->SetInAt(0, Location::RequiresRegister());
1955 }
1956}
1957
1958void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01001959 SlowPathCodeARM* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00001960 GenerateTestAndBranch(deoptimize,
1961 /* condition_input_index */ 0,
1962 slow_path->GetEntryLabel(),
1963 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001964}
Dave Allison20dfc792014-06-16 20:44:29 -07001965
Mingyao Yang063fc772016-08-02 11:02:54 -07001966void LocationsBuilderARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
1967 LocationSummary* locations = new (GetGraph()->GetArena())
1968 LocationSummary(flag, LocationSummary::kNoCall);
1969 locations->SetOut(Location::RequiresRegister());
1970}
1971
1972void InstructionCodeGeneratorARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
1973 __ LoadFromOffset(kLoadWord,
1974 flag->GetLocations()->Out().AsRegister<Register>(),
1975 SP,
1976 codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
1977}
1978
David Brazdil74eb1b22015-12-14 11:44:01 +00001979void LocationsBuilderARM::VisitSelect(HSelect* select) {
1980 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
1981 if (Primitive::IsFloatingPointType(select->GetType())) {
1982 locations->SetInAt(0, Location::RequiresFpuRegister());
1983 locations->SetInAt(1, Location::RequiresFpuRegister());
1984 } else {
1985 locations->SetInAt(0, Location::RequiresRegister());
1986 locations->SetInAt(1, Location::RequiresRegister());
1987 }
1988 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
1989 locations->SetInAt(2, Location::RequiresRegister());
1990 }
1991 locations->SetOut(Location::SameAsFirstInput());
1992}
1993
1994void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
1995 LocationSummary* locations = select->GetLocations();
1996 Label false_target;
1997 GenerateTestAndBranch(select,
1998 /* condition_input_index */ 2,
1999 /* true_target */ nullptr,
2000 &false_target);
2001 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
2002 __ Bind(&false_target);
2003}
2004
David Srbecky0cf44932015-12-09 14:09:59 +00002005void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
2006 new (GetGraph()->GetArena()) LocationSummary(info);
2007}
2008
David Srbeckyd28f4a02016-03-14 17:14:24 +00002009void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
2010 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00002011}
2012
2013void CodeGeneratorARM::GenerateNop() {
2014 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00002015}
2016
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002017void LocationsBuilderARM::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002018 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01002019 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002020 // Handle the long/FP comparisons made in instruction simplification.
2021 switch (cond->InputAt(0)->GetType()) {
2022 case Primitive::kPrimLong:
2023 locations->SetInAt(0, Location::RequiresRegister());
2024 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00002025 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002026 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2027 }
2028 break;
2029
2030 case Primitive::kPrimFloat:
2031 case Primitive::kPrimDouble:
2032 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01002033 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00002034 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002035 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2036 }
2037 break;
2038
2039 default:
2040 locations->SetInAt(0, Location::RequiresRegister());
2041 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00002042 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002043 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2044 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002045 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002046}
2047
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002048void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00002049 if (cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002050 return;
Dave Allison20dfc792014-06-16 20:44:29 -07002051 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01002052
2053 LocationSummary* locations = cond->GetLocations();
2054 Location left = locations->InAt(0);
2055 Location right = locations->InAt(1);
2056 Register out = locations->Out().AsRegister<Register>();
2057 Label true_label, false_label;
2058
2059 switch (cond->InputAt(0)->GetType()) {
2060 default: {
2061 // Integer case.
2062 if (right.IsRegister()) {
2063 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
2064 } else {
2065 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00002066 __ CmpConstant(left.AsRegister<Register>(),
2067 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002068 }
Aart Bike9f37602015-10-09 11:15:55 -07002069 __ it(ARMCondition(cond->GetCondition()), kItElse);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002070 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Aart Bike9f37602015-10-09 11:15:55 -07002071 ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002072 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Aart Bike9f37602015-10-09 11:15:55 -07002073 ARMCondition(cond->GetOppositeCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002074 return;
2075 }
2076 case Primitive::kPrimLong:
2077 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
2078 break;
2079 case Primitive::kPrimFloat:
Roland Levillain4fa13f62015-07-06 18:11:54 +01002080 case Primitive::kPrimDouble:
Vladimir Marko37dd80d2016-08-01 17:41:45 +01002081 GenerateVcmp(cond);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002082 GenerateFPJumps(cond, &true_label, &false_label);
2083 break;
2084 }
2085
2086 // Convert the jumps into the result.
2087 Label done_label;
2088
2089 // False case: result = 0.
2090 __ Bind(&false_label);
2091 __ LoadImmediate(out, 0);
2092 __ b(&done_label);
2093
2094 // True case: result = 1.
2095 __ Bind(&true_label);
2096 __ LoadImmediate(out, 1);
2097 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07002098}
2099
2100void LocationsBuilderARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002101 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002102}
2103
2104void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002105 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002106}
2107
2108void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002109 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002110}
2111
2112void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002113 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002114}
2115
2116void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002117 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002118}
2119
2120void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002121 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002122}
2123
2124void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002125 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002126}
2127
2128void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002129 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002130}
2131
2132void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002133 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002134}
2135
2136void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002137 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002138}
2139
2140void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002141 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002142}
2143
2144void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002145 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002146}
2147
Aart Bike9f37602015-10-09 11:15:55 -07002148void LocationsBuilderARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002149 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002150}
2151
2152void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002153 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002154}
2155
2156void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002157 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002158}
2159
2160void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002161 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002162}
2163
2164void LocationsBuilderARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002165 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002166}
2167
2168void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002169 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002170}
2171
2172void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002173 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002174}
2175
2176void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002177 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002178}
2179
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002180void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002181 LocationSummary* locations =
2182 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002183 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00002184}
2185
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002186void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002187 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002188}
2189
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002190void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
2191 LocationSummary* locations =
2192 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2193 locations->SetOut(Location::ConstantLocation(constant));
2194}
2195
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002196void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002197 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002198}
2199
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002200void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002201 LocationSummary* locations =
2202 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002203 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002204}
2205
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002206void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002207 // Will be generated at use site.
2208}
2209
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002210void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
2211 LocationSummary* locations =
2212 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2213 locations->SetOut(Location::ConstantLocation(constant));
2214}
2215
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002216void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002217 // Will be generated at use site.
2218}
2219
2220void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
2221 LocationSummary* locations =
2222 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2223 locations->SetOut(Location::ConstantLocation(constant));
2224}
2225
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002226void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002227 // Will be generated at use site.
2228}
2229
Calin Juravle27df7582015-04-17 19:12:31 +01002230void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
2231 memory_barrier->SetLocations(nullptr);
2232}
2233
2234void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00002235 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01002236}
2237
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002238void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002239 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00002240}
2241
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002242void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002243 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002244}
2245
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002246void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002247 LocationSummary* locations =
2248 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002249 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002250}
2251
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002252void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002253 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002254}
2255
Calin Juravle175dc732015-08-25 15:42:32 +01002256void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2257 // The trampoline uses the same calling convention as dex calling conventions,
2258 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
2259 // the method_idx.
2260 HandleInvoke(invoke);
2261}
2262
2263void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2264 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
2265}
2266
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002267void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00002268 // Explicit clinit checks triggered by static invokes must have been pruned by
2269 // art::PrepareForRegisterAllocation.
2270 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002271
Vladimir Marko68c981f2016-08-26 13:13:33 +01002272 IntrinsicLocationsBuilderARM intrinsic(codegen_);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08002273 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markob4536b72015-11-24 13:45:23 +00002274 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
2275 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
2276 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08002277 return;
2278 }
2279
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002280 HandleInvoke(invoke);
Vladimir Markob4536b72015-11-24 13:45:23 +00002281
2282 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
2283 if (invoke->HasPcRelativeDexCache()) {
2284 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
2285 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002286}
2287
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08002288static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
2289 if (invoke->GetLocations()->Intrinsified()) {
2290 IntrinsicCodeGeneratorARM intrinsic(codegen);
2291 intrinsic.Dispatch(invoke);
2292 return true;
2293 }
2294 return false;
2295}
2296
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002297void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00002298 // Explicit clinit checks triggered by static invokes must have been pruned by
2299 // art::PrepareForRegisterAllocation.
2300 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002301
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08002302 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2303 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00002304 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002305
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002306 LocationSummary* locations = invoke->GetLocations();
2307 codegen_->GenerateStaticOrDirectCall(
2308 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00002309 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002310}
2311
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002312void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002313 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002314 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00002315}
2316
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002317void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Vladimir Marko68c981f2016-08-26 13:13:33 +01002318 IntrinsicLocationsBuilderARM intrinsic(codegen_);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08002319 if (intrinsic.TryDispatch(invoke)) {
2320 return;
2321 }
2322
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002323 HandleInvoke(invoke);
2324}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00002325
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002326void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08002327 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2328 return;
2329 }
2330
Andreas Gampebfb5ba92015-09-01 15:45:02 +00002331 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002332 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002333 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00002334}
2335
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002336void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
2337 HandleInvoke(invoke);
2338 // Add the hidden argument.
2339 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
2340}
2341
2342void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
2343 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00002344 LocationSummary* locations = invoke->GetLocations();
2345 Register temp = locations->GetTemp(0).AsRegister<Register>();
2346 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002347 Location receiver = locations->InAt(0);
2348 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2349
Roland Levillain3b359c72015-11-17 19:35:12 +00002350 // Set the hidden argument. This is safe to do this here, as R12
2351 // won't be modified thereafter, before the `blx` (call) instruction.
2352 DCHECK_EQ(R12, hidden_reg);
2353 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002354
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002355 if (receiver.IsStackSlot()) {
2356 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00002357 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002358 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
2359 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00002360 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00002361 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002362 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002363 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00002364 // Instead of simply (possibly) unpoisoning `temp` here, we should
2365 // emit a read barrier for the previous class reference load.
2366 // However this is not required in practice, as this is an
2367 // intermediate/temporary reference and because the current
2368 // concurrent copying collector keeps the from-space memory
2369 // intact/accessible until the end of the marking phase (the
2370 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01002371 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00002372 __ LoadFromOffset(kLoadWord, temp, temp,
2373 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
2374 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00002375 invoke->GetImtIndex(), kArmPointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002376 // temp = temp->GetImtEntryAt(method_offset);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00002377 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00002378 uint32_t entry_point =
Andreas Gampe542451c2016-07-26 09:02:02 -07002379 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002380 // LR = temp->GetEntryPoint();
2381 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
2382 // LR();
2383 __ blx(LR);
2384 DCHECK(!codegen_->IsLeafMethod());
2385 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2386}
2387
Orion Hodsonac141392017-01-13 11:53:47 +00002388void LocationsBuilderARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
2389 HandleInvoke(invoke);
2390}
2391
2392void InstructionCodeGeneratorARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
2393 codegen_->GenerateInvokePolymorphicCall(invoke);
2394}
2395
Roland Levillain88cb1752014-10-20 16:36:47 +01002396void LocationsBuilderARM::VisitNeg(HNeg* neg) {
2397 LocationSummary* locations =
2398 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2399 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002400 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01002401 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002402 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2403 break;
2404 }
2405 case Primitive::kPrimLong: {
2406 locations->SetInAt(0, Location::RequiresRegister());
2407 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01002408 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002409 }
Roland Levillain88cb1752014-10-20 16:36:47 +01002410
Roland Levillain88cb1752014-10-20 16:36:47 +01002411 case Primitive::kPrimFloat:
2412 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002413 locations->SetInAt(0, Location::RequiresFpuRegister());
2414 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01002415 break;
2416
2417 default:
2418 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2419 }
2420}
2421
2422void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
2423 LocationSummary* locations = neg->GetLocations();
2424 Location out = locations->Out();
2425 Location in = locations->InAt(0);
2426 switch (neg->GetResultType()) {
2427 case Primitive::kPrimInt:
2428 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002429 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01002430 break;
2431
2432 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002433 DCHECK(in.IsRegisterPair());
2434 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
2435 __ rsbs(out.AsRegisterPairLow<Register>(),
2436 in.AsRegisterPairLow<Register>(),
2437 ShifterOperand(0));
2438 // We cannot emit an RSC (Reverse Subtract with Carry)
2439 // instruction here, as it does not exist in the Thumb-2
2440 // instruction set. We use the following approach
2441 // using SBC and SUB instead.
2442 //
2443 // out.hi = -C
2444 __ sbc(out.AsRegisterPairHigh<Register>(),
2445 out.AsRegisterPairHigh<Register>(),
2446 ShifterOperand(out.AsRegisterPairHigh<Register>()));
2447 // out.hi = out.hi - in.hi
2448 __ sub(out.AsRegisterPairHigh<Register>(),
2449 out.AsRegisterPairHigh<Register>(),
2450 ShifterOperand(in.AsRegisterPairHigh<Register>()));
2451 break;
2452
Roland Levillain88cb1752014-10-20 16:36:47 +01002453 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002454 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002455 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002456 break;
2457
Roland Levillain88cb1752014-10-20 16:36:47 +01002458 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002459 DCHECK(in.IsFpuRegisterPair());
2460 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2461 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01002462 break;
2463
2464 default:
2465 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2466 }
2467}
2468
Roland Levillaindff1f282014-11-05 14:15:05 +00002469void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00002470 Primitive::Type result_type = conversion->GetResultType();
2471 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002472 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00002473
Roland Levillain5b3ee562015-04-14 16:02:41 +01002474 // The float-to-long, double-to-long and long-to-float type conversions
2475 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00002476 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01002477 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
2478 && result_type == Primitive::kPrimLong)
2479 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Serban Constantinescu54ff4822016-07-07 18:03:19 +01002480 ? LocationSummary::kCallOnMainOnly
Roland Levillain624279f2014-12-04 11:54:28 +00002481 : LocationSummary::kNoCall;
2482 LocationSummary* locations =
2483 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
2484
David Brazdilb2bd1c52015-03-25 11:17:37 +00002485 // The Java language does not allow treating boolean as an integral type but
2486 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002487
Roland Levillaindff1f282014-11-05 14:15:05 +00002488 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002489 case Primitive::kPrimByte:
2490 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002491 case Primitive::kPrimLong:
2492 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002493 case Primitive::kPrimBoolean:
2494 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002495 case Primitive::kPrimShort:
2496 case Primitive::kPrimInt:
2497 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002498 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002499 locations->SetInAt(0, Location::RequiresRegister());
2500 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2501 break;
2502
2503 default:
2504 LOG(FATAL) << "Unexpected type conversion from " << input_type
2505 << " to " << result_type;
2506 }
2507 break;
2508
Roland Levillain01a8d712014-11-14 16:27:39 +00002509 case Primitive::kPrimShort:
2510 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002511 case Primitive::kPrimLong:
2512 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002513 case Primitive::kPrimBoolean:
2514 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002515 case Primitive::kPrimByte:
2516 case Primitive::kPrimInt:
2517 case Primitive::kPrimChar:
2518 // Processing a Dex `int-to-short' instruction.
2519 locations->SetInAt(0, Location::RequiresRegister());
2520 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2521 break;
2522
2523 default:
2524 LOG(FATAL) << "Unexpected type conversion from " << input_type
2525 << " to " << result_type;
2526 }
2527 break;
2528
Roland Levillain946e1432014-11-11 17:35:19 +00002529 case Primitive::kPrimInt:
2530 switch (input_type) {
2531 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002532 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002533 locations->SetInAt(0, Location::Any());
2534 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2535 break;
2536
2537 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002538 // Processing a Dex `float-to-int' instruction.
2539 locations->SetInAt(0, Location::RequiresFpuRegister());
2540 locations->SetOut(Location::RequiresRegister());
2541 locations->AddTemp(Location::RequiresFpuRegister());
2542 break;
2543
Roland Levillain946e1432014-11-11 17:35:19 +00002544 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002545 // Processing a Dex `double-to-int' instruction.
2546 locations->SetInAt(0, Location::RequiresFpuRegister());
2547 locations->SetOut(Location::RequiresRegister());
2548 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002549 break;
2550
2551 default:
2552 LOG(FATAL) << "Unexpected type conversion from " << input_type
2553 << " to " << result_type;
2554 }
2555 break;
2556
Roland Levillaindff1f282014-11-05 14:15:05 +00002557 case Primitive::kPrimLong:
2558 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002559 case Primitive::kPrimBoolean:
2560 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002561 case Primitive::kPrimByte:
2562 case Primitive::kPrimShort:
2563 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002564 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002565 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002566 locations->SetInAt(0, Location::RequiresRegister());
2567 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2568 break;
2569
Roland Levillain624279f2014-12-04 11:54:28 +00002570 case Primitive::kPrimFloat: {
2571 // Processing a Dex `float-to-long' instruction.
2572 InvokeRuntimeCallingConvention calling_convention;
2573 locations->SetInAt(0, Location::FpuRegisterLocation(
2574 calling_convention.GetFpuRegisterAt(0)));
2575 locations->SetOut(Location::RegisterPairLocation(R0, R1));
2576 break;
2577 }
2578
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002579 case Primitive::kPrimDouble: {
2580 // Processing a Dex `double-to-long' instruction.
2581 InvokeRuntimeCallingConvention calling_convention;
2582 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2583 calling_convention.GetFpuRegisterAt(0),
2584 calling_convention.GetFpuRegisterAt(1)));
2585 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00002586 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002587 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002588
2589 default:
2590 LOG(FATAL) << "Unexpected type conversion from " << input_type
2591 << " to " << result_type;
2592 }
2593 break;
2594
Roland Levillain981e4542014-11-14 11:47:14 +00002595 case Primitive::kPrimChar:
2596 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002597 case Primitive::kPrimLong:
2598 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002599 case Primitive::kPrimBoolean:
2600 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002601 case Primitive::kPrimByte:
2602 case Primitive::kPrimShort:
2603 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002604 // Processing a Dex `int-to-char' instruction.
2605 locations->SetInAt(0, Location::RequiresRegister());
2606 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2607 break;
2608
2609 default:
2610 LOG(FATAL) << "Unexpected type conversion from " << input_type
2611 << " to " << result_type;
2612 }
2613 break;
2614
Roland Levillaindff1f282014-11-05 14:15:05 +00002615 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002616 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002617 case Primitive::kPrimBoolean:
2618 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002619 case Primitive::kPrimByte:
2620 case Primitive::kPrimShort:
2621 case Primitive::kPrimInt:
2622 case Primitive::kPrimChar:
2623 // Processing a Dex `int-to-float' instruction.
2624 locations->SetInAt(0, Location::RequiresRegister());
2625 locations->SetOut(Location::RequiresFpuRegister());
2626 break;
2627
Roland Levillain5b3ee562015-04-14 16:02:41 +01002628 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00002629 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002630 InvokeRuntimeCallingConvention calling_convention;
2631 locations->SetInAt(0, Location::RegisterPairLocation(
2632 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2633 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00002634 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01002635 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002636
Roland Levillaincff13742014-11-17 14:32:17 +00002637 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002638 // Processing a Dex `double-to-float' instruction.
2639 locations->SetInAt(0, Location::RequiresFpuRegister());
2640 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002641 break;
2642
2643 default:
2644 LOG(FATAL) << "Unexpected type conversion from " << input_type
2645 << " to " << result_type;
2646 };
2647 break;
2648
Roland Levillaindff1f282014-11-05 14:15:05 +00002649 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002650 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002651 case Primitive::kPrimBoolean:
2652 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002653 case Primitive::kPrimByte:
2654 case Primitive::kPrimShort:
2655 case Primitive::kPrimInt:
2656 case Primitive::kPrimChar:
2657 // Processing a Dex `int-to-double' instruction.
2658 locations->SetInAt(0, Location::RequiresRegister());
2659 locations->SetOut(Location::RequiresFpuRegister());
2660 break;
2661
2662 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002663 // Processing a Dex `long-to-double' instruction.
2664 locations->SetInAt(0, Location::RequiresRegister());
2665 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01002666 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002667 locations->AddTemp(Location::RequiresFpuRegister());
2668 break;
2669
Roland Levillaincff13742014-11-17 14:32:17 +00002670 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002671 // Processing a Dex `float-to-double' instruction.
2672 locations->SetInAt(0, Location::RequiresFpuRegister());
2673 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002674 break;
2675
2676 default:
2677 LOG(FATAL) << "Unexpected type conversion from " << input_type
2678 << " to " << result_type;
2679 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002680 break;
2681
2682 default:
2683 LOG(FATAL) << "Unexpected type conversion from " << input_type
2684 << " to " << result_type;
2685 }
2686}
2687
2688void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2689 LocationSummary* locations = conversion->GetLocations();
2690 Location out = locations->Out();
2691 Location in = locations->InAt(0);
2692 Primitive::Type result_type = conversion->GetResultType();
2693 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002694 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002695 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002696 case Primitive::kPrimByte:
2697 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002698 case Primitive::kPrimLong:
2699 // Type conversion from long to byte is a result of code transformations.
2700 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
2701 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002702 case Primitive::kPrimBoolean:
2703 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002704 case Primitive::kPrimShort:
2705 case Primitive::kPrimInt:
2706 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002707 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002708 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002709 break;
2710
2711 default:
2712 LOG(FATAL) << "Unexpected type conversion from " << input_type
2713 << " to " << result_type;
2714 }
2715 break;
2716
Roland Levillain01a8d712014-11-14 16:27:39 +00002717 case Primitive::kPrimShort:
2718 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002719 case Primitive::kPrimLong:
2720 // Type conversion from long to short is a result of code transformations.
2721 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2722 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002723 case Primitive::kPrimBoolean:
2724 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002725 case Primitive::kPrimByte:
2726 case Primitive::kPrimInt:
2727 case Primitive::kPrimChar:
2728 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002729 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002730 break;
2731
2732 default:
2733 LOG(FATAL) << "Unexpected type conversion from " << input_type
2734 << " to " << result_type;
2735 }
2736 break;
2737
Roland Levillain946e1432014-11-11 17:35:19 +00002738 case Primitive::kPrimInt:
2739 switch (input_type) {
2740 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002741 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002742 DCHECK(out.IsRegister());
2743 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002744 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002745 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002746 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002747 } else {
2748 DCHECK(in.IsConstant());
2749 DCHECK(in.GetConstant()->IsLongConstant());
2750 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002751 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002752 }
2753 break;
2754
Roland Levillain3f8f9362014-12-02 17:45:01 +00002755 case Primitive::kPrimFloat: {
2756 // Processing a Dex `float-to-int' instruction.
2757 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01002758 __ vcvtis(temp, in.AsFpuRegister<SRegister>());
Roland Levillain3f8f9362014-12-02 17:45:01 +00002759 __ vmovrs(out.AsRegister<Register>(), temp);
2760 break;
2761 }
2762
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002763 case Primitive::kPrimDouble: {
2764 // Processing a Dex `double-to-int' instruction.
2765 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01002766 __ vcvtid(temp_s, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002767 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002768 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002769 }
Roland Levillain946e1432014-11-11 17:35:19 +00002770
2771 default:
2772 LOG(FATAL) << "Unexpected type conversion from " << input_type
2773 << " to " << result_type;
2774 }
2775 break;
2776
Roland Levillaindff1f282014-11-05 14:15:05 +00002777 case Primitive::kPrimLong:
2778 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002779 case Primitive::kPrimBoolean:
2780 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002781 case Primitive::kPrimByte:
2782 case Primitive::kPrimShort:
2783 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002784 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002785 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002786 DCHECK(out.IsRegisterPair());
2787 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002788 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002789 // Sign extension.
2790 __ Asr(out.AsRegisterPairHigh<Register>(),
2791 out.AsRegisterPairLow<Register>(),
2792 31);
2793 break;
2794
2795 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002796 // Processing a Dex `float-to-long' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002797 codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00002798 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00002799 break;
2800
Roland Levillaindff1f282014-11-05 14:15:05 +00002801 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002802 // Processing a Dex `double-to-long' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002803 codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00002804 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00002805 break;
2806
2807 default:
2808 LOG(FATAL) << "Unexpected type conversion from " << input_type
2809 << " to " << result_type;
2810 }
2811 break;
2812
Roland Levillain981e4542014-11-14 11:47:14 +00002813 case Primitive::kPrimChar:
2814 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002815 case Primitive::kPrimLong:
2816 // Type conversion from long to char is a result of code transformations.
2817 __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2818 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002819 case Primitive::kPrimBoolean:
2820 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002821 case Primitive::kPrimByte:
2822 case Primitive::kPrimShort:
2823 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002824 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002825 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002826 break;
2827
2828 default:
2829 LOG(FATAL) << "Unexpected type conversion from " << input_type
2830 << " to " << result_type;
2831 }
2832 break;
2833
Roland Levillaindff1f282014-11-05 14:15:05 +00002834 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002835 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002836 case Primitive::kPrimBoolean:
2837 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002838 case Primitive::kPrimByte:
2839 case Primitive::kPrimShort:
2840 case Primitive::kPrimInt:
2841 case Primitive::kPrimChar: {
2842 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002843 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2844 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002845 break;
2846 }
2847
Roland Levillain5b3ee562015-04-14 16:02:41 +01002848 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002849 // Processing a Dex `long-to-float' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002850 codegen_->InvokeRuntime(kQuickL2f, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00002851 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00002852 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002853
Roland Levillaincff13742014-11-17 14:32:17 +00002854 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002855 // Processing a Dex `double-to-float' instruction.
2856 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2857 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002858 break;
2859
2860 default:
2861 LOG(FATAL) << "Unexpected type conversion from " << input_type
2862 << " to " << result_type;
2863 };
2864 break;
2865
Roland Levillaindff1f282014-11-05 14:15:05 +00002866 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002867 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002868 case Primitive::kPrimBoolean:
2869 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002870 case Primitive::kPrimByte:
2871 case Primitive::kPrimShort:
2872 case Primitive::kPrimInt:
2873 case Primitive::kPrimChar: {
2874 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002875 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002876 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2877 out.AsFpuRegisterPairLow<SRegister>());
2878 break;
2879 }
2880
Roland Levillain647b9ed2014-11-27 12:06:00 +00002881 case Primitive::kPrimLong: {
2882 // Processing a Dex `long-to-double' instruction.
2883 Register low = in.AsRegisterPairLow<Register>();
2884 Register high = in.AsRegisterPairHigh<Register>();
2885 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2886 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002887 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002888 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002889 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2890 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002891
Roland Levillain682393c2015-04-14 15:57:52 +01002892 // temp_d = int-to-double(high)
2893 __ vmovsr(temp_s, high);
2894 __ vcvtdi(temp_d, temp_s);
2895 // constant_d = k2Pow32EncodingForDouble
2896 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2897 // out_d = unsigned-to-double(low)
2898 __ vmovsr(out_s, low);
2899 __ vcvtdu(out_d, out_s);
2900 // out_d += temp_d * constant_d
2901 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002902 break;
2903 }
2904
Roland Levillaincff13742014-11-17 14:32:17 +00002905 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002906 // Processing a Dex `float-to-double' instruction.
2907 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2908 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002909 break;
2910
2911 default:
2912 LOG(FATAL) << "Unexpected type conversion from " << input_type
2913 << " to " << result_type;
2914 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002915 break;
2916
2917 default:
2918 LOG(FATAL) << "Unexpected type conversion from " << input_type
2919 << " to " << result_type;
2920 }
2921}
2922
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002923void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002924 LocationSummary* locations =
2925 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002926 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002927 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002928 locations->SetInAt(0, Location::RequiresRegister());
2929 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002930 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2931 break;
2932 }
2933
2934 case Primitive::kPrimLong: {
2935 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko59751a72016-08-05 14:37:27 +01002936 locations->SetInAt(1, ArmEncodableConstantOrRegister(add->InputAt(1), ADD));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002937 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002938 break;
2939 }
2940
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002941 case Primitive::kPrimFloat:
2942 case Primitive::kPrimDouble: {
2943 locations->SetInAt(0, Location::RequiresFpuRegister());
2944 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002945 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002946 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002947 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002948
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002949 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002950 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002951 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002952}
2953
2954void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2955 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002956 Location out = locations->Out();
2957 Location first = locations->InAt(0);
2958 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002959 switch (add->GetResultType()) {
2960 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002961 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002962 __ add(out.AsRegister<Register>(),
2963 first.AsRegister<Register>(),
2964 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002965 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002966 __ AddConstant(out.AsRegister<Register>(),
2967 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002968 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002969 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002970 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002971
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002972 case Primitive::kPrimLong: {
Vladimir Marko59751a72016-08-05 14:37:27 +01002973 if (second.IsConstant()) {
2974 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
2975 GenerateAddLongConst(out, first, value);
2976 } else {
2977 DCHECK(second.IsRegisterPair());
2978 __ adds(out.AsRegisterPairLow<Register>(),
2979 first.AsRegisterPairLow<Register>(),
2980 ShifterOperand(second.AsRegisterPairLow<Register>()));
2981 __ adc(out.AsRegisterPairHigh<Register>(),
2982 first.AsRegisterPairHigh<Register>(),
2983 ShifterOperand(second.AsRegisterPairHigh<Register>()));
2984 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002985 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002986 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002987
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002988 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002989 __ vadds(out.AsFpuRegister<SRegister>(),
2990 first.AsFpuRegister<SRegister>(),
2991 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002992 break;
2993
2994 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002995 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2996 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2997 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002998 break;
2999
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003000 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003001 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003002 }
3003}
3004
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003005void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003006 LocationSummary* locations =
3007 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003008 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003009 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003010 locations->SetInAt(0, Location::RequiresRegister());
3011 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003012 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3013 break;
3014 }
3015
3016 case Primitive::kPrimLong: {
3017 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko59751a72016-08-05 14:37:27 +01003018 locations->SetInAt(1, ArmEncodableConstantOrRegister(sub->InputAt(1), SUB));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003019 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003020 break;
3021 }
Calin Juravle11351682014-10-23 15:38:15 +01003022 case Primitive::kPrimFloat:
3023 case Primitive::kPrimDouble: {
3024 locations->SetInAt(0, Location::RequiresFpuRegister());
3025 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003026 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003027 break;
Calin Juravle11351682014-10-23 15:38:15 +01003028 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003029 default:
Calin Juravle11351682014-10-23 15:38:15 +01003030 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003031 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003032}
3033
3034void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
3035 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01003036 Location out = locations->Out();
3037 Location first = locations->InAt(0);
3038 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003039 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003040 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01003041 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003042 __ sub(out.AsRegister<Register>(),
3043 first.AsRegister<Register>(),
3044 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003045 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003046 __ AddConstant(out.AsRegister<Register>(),
3047 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01003048 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003049 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003050 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003051 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003052
Calin Juravle11351682014-10-23 15:38:15 +01003053 case Primitive::kPrimLong: {
Vladimir Marko59751a72016-08-05 14:37:27 +01003054 if (second.IsConstant()) {
3055 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
3056 GenerateAddLongConst(out, first, -value);
3057 } else {
3058 DCHECK(second.IsRegisterPair());
3059 __ subs(out.AsRegisterPairLow<Register>(),
3060 first.AsRegisterPairLow<Register>(),
3061 ShifterOperand(second.AsRegisterPairLow<Register>()));
3062 __ sbc(out.AsRegisterPairHigh<Register>(),
3063 first.AsRegisterPairHigh<Register>(),
3064 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3065 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003066 break;
Calin Juravle11351682014-10-23 15:38:15 +01003067 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003068
Calin Juravle11351682014-10-23 15:38:15 +01003069 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00003070 __ vsubs(out.AsFpuRegister<SRegister>(),
3071 first.AsFpuRegister<SRegister>(),
3072 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003073 break;
Calin Juravle11351682014-10-23 15:38:15 +01003074 }
3075
3076 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00003077 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3078 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3079 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01003080 break;
3081 }
3082
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003083
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003084 default:
Calin Juravle11351682014-10-23 15:38:15 +01003085 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003086 }
3087}
3088
Calin Juravle34bacdf2014-10-07 20:23:36 +01003089void LocationsBuilderARM::VisitMul(HMul* mul) {
3090 LocationSummary* locations =
3091 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
3092 switch (mul->GetResultType()) {
3093 case Primitive::kPrimInt:
3094 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003095 locations->SetInAt(0, Location::RequiresRegister());
3096 locations->SetInAt(1, Location::RequiresRegister());
3097 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01003098 break;
3099 }
3100
Calin Juravleb5bfa962014-10-21 18:02:24 +01003101 case Primitive::kPrimFloat:
3102 case Primitive::kPrimDouble: {
3103 locations->SetInAt(0, Location::RequiresFpuRegister());
3104 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003105 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01003106 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003107 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003108
3109 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003110 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003111 }
3112}
3113
3114void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
3115 LocationSummary* locations = mul->GetLocations();
3116 Location out = locations->Out();
3117 Location first = locations->InAt(0);
3118 Location second = locations->InAt(1);
3119 switch (mul->GetResultType()) {
3120 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00003121 __ mul(out.AsRegister<Register>(),
3122 first.AsRegister<Register>(),
3123 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003124 break;
3125 }
3126 case Primitive::kPrimLong: {
3127 Register out_hi = out.AsRegisterPairHigh<Register>();
3128 Register out_lo = out.AsRegisterPairLow<Register>();
3129 Register in1_hi = first.AsRegisterPairHigh<Register>();
3130 Register in1_lo = first.AsRegisterPairLow<Register>();
3131 Register in2_hi = second.AsRegisterPairHigh<Register>();
3132 Register in2_lo = second.AsRegisterPairLow<Register>();
3133
3134 // Extra checks to protect caused by the existence of R1_R2.
3135 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
3136 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
3137 DCHECK_NE(out_hi, in1_lo);
3138 DCHECK_NE(out_hi, in2_lo);
3139
3140 // input: in1 - 64 bits, in2 - 64 bits
3141 // output: out
3142 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
3143 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
3144 // parts: out.lo = (in1.lo * in2.lo)[31:0]
3145
3146 // IP <- in1.lo * in2.hi
3147 __ mul(IP, in1_lo, in2_hi);
3148 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
3149 __ mla(out_hi, in1_hi, in2_lo, IP);
3150 // out.lo <- (in1.lo * in2.lo)[31:0];
3151 __ umull(out_lo, IP, in1_lo, in2_lo);
3152 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
3153 __ add(out_hi, out_hi, ShifterOperand(IP));
3154 break;
3155 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003156
3157 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00003158 __ vmuls(out.AsFpuRegister<SRegister>(),
3159 first.AsFpuRegister<SRegister>(),
3160 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003161 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003162 }
3163
3164 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00003165 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3166 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3167 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01003168 break;
3169 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003170
3171 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003172 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003173 }
3174}
3175
Zheng Xuc6667102015-05-15 16:08:45 +08003176void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
3177 DCHECK(instruction->IsDiv() || instruction->IsRem());
3178 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
3179
3180 LocationSummary* locations = instruction->GetLocations();
3181 Location second = locations->InAt(1);
3182 DCHECK(second.IsConstant());
3183
3184 Register out = locations->Out().AsRegister<Register>();
3185 Register dividend = locations->InAt(0).AsRegister<Register>();
3186 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3187 DCHECK(imm == 1 || imm == -1);
3188
3189 if (instruction->IsRem()) {
3190 __ LoadImmediate(out, 0);
3191 } else {
3192 if (imm == 1) {
3193 __ Mov(out, dividend);
3194 } else {
3195 __ rsb(out, dividend, ShifterOperand(0));
3196 }
3197 }
3198}
3199
3200void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
3201 DCHECK(instruction->IsDiv() || instruction->IsRem());
3202 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
3203
3204 LocationSummary* locations = instruction->GetLocations();
3205 Location second = locations->InAt(1);
3206 DCHECK(second.IsConstant());
3207
3208 Register out = locations->Out().AsRegister<Register>();
3209 Register dividend = locations->InAt(0).AsRegister<Register>();
3210 Register temp = locations->GetTemp(0).AsRegister<Register>();
3211 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003212 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08003213 int ctz_imm = CTZ(abs_imm);
3214
3215 if (ctz_imm == 1) {
3216 __ Lsr(temp, dividend, 32 - ctz_imm);
3217 } else {
3218 __ Asr(temp, dividend, 31);
3219 __ Lsr(temp, temp, 32 - ctz_imm);
3220 }
3221 __ add(out, temp, ShifterOperand(dividend));
3222
3223 if (instruction->IsDiv()) {
3224 __ Asr(out, out, ctz_imm);
3225 if (imm < 0) {
3226 __ rsb(out, out, ShifterOperand(0));
3227 }
3228 } else {
3229 __ ubfx(out, out, 0, ctz_imm);
3230 __ sub(out, out, ShifterOperand(temp));
3231 }
3232}
3233
3234void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3235 DCHECK(instruction->IsDiv() || instruction->IsRem());
3236 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
3237
3238 LocationSummary* locations = instruction->GetLocations();
3239 Location second = locations->InAt(1);
3240 DCHECK(second.IsConstant());
3241
3242 Register out = locations->Out().AsRegister<Register>();
3243 Register dividend = locations->InAt(0).AsRegister<Register>();
3244 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
3245 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
3246 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3247
3248 int64_t magic;
3249 int shift;
3250 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
3251
3252 __ LoadImmediate(temp1, magic);
3253 __ smull(temp2, temp1, dividend, temp1);
3254
3255 if (imm > 0 && magic < 0) {
3256 __ add(temp1, temp1, ShifterOperand(dividend));
3257 } else if (imm < 0 && magic > 0) {
3258 __ sub(temp1, temp1, ShifterOperand(dividend));
3259 }
3260
3261 if (shift != 0) {
3262 __ Asr(temp1, temp1, shift);
3263 }
3264
3265 if (instruction->IsDiv()) {
3266 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
3267 } else {
3268 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
3269 // TODO: Strength reduction for mls.
3270 __ LoadImmediate(temp2, imm);
3271 __ mls(out, temp1, temp2, dividend);
3272 }
3273}
3274
3275void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
3276 DCHECK(instruction->IsDiv() || instruction->IsRem());
3277 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
3278
3279 LocationSummary* locations = instruction->GetLocations();
3280 Location second = locations->InAt(1);
3281 DCHECK(second.IsConstant());
3282
3283 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3284 if (imm == 0) {
3285 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3286 } else if (imm == 1 || imm == -1) {
3287 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003288 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Zheng Xuc6667102015-05-15 16:08:45 +08003289 DivRemByPowerOfTwo(instruction);
3290 } else {
3291 DCHECK(imm <= -2 || imm >= 2);
3292 GenerateDivRemWithAnyConstant(instruction);
3293 }
3294}
3295
Calin Juravle7c4954d2014-10-28 16:57:40 +00003296void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003297 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
3298 if (div->GetResultType() == Primitive::kPrimLong) {
3299 // pLdiv runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003300 call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08003301 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
3302 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003303 } else if (div->GetResultType() == Primitive::kPrimInt &&
3304 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
3305 // pIdivmod runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003306 call_kind = LocationSummary::kCallOnMainOnly;
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003307 }
3308
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003309 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
3310
Calin Juravle7c4954d2014-10-28 16:57:40 +00003311 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00003312 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003313 if (div->InputAt(1)->IsConstant()) {
3314 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00003315 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08003316 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003317 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
3318 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08003319 // No temp register required.
3320 } else {
3321 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003322 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08003323 locations->AddTemp(Location::RequiresRegister());
3324 }
3325 }
3326 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003327 locations->SetInAt(0, Location::RequiresRegister());
3328 locations->SetInAt(1, Location::RequiresRegister());
3329 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3330 } else {
3331 InvokeRuntimeCallingConvention calling_convention;
3332 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3333 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3334 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
3335 // we only need the former.
3336 locations->SetOut(Location::RegisterLocation(R0));
3337 }
Calin Juravled0d48522014-11-04 16:40:20 +00003338 break;
3339 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003340 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003341 InvokeRuntimeCallingConvention calling_convention;
3342 locations->SetInAt(0, Location::RegisterPairLocation(
3343 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3344 locations->SetInAt(1, Location::RegisterPairLocation(
3345 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003346 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00003347 break;
3348 }
3349 case Primitive::kPrimFloat:
3350 case Primitive::kPrimDouble: {
3351 locations->SetInAt(0, Location::RequiresFpuRegister());
3352 locations->SetInAt(1, Location::RequiresFpuRegister());
3353 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3354 break;
3355 }
3356
3357 default:
3358 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3359 }
3360}
3361
3362void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
3363 LocationSummary* locations = div->GetLocations();
3364 Location out = locations->Out();
3365 Location first = locations->InAt(0);
3366 Location second = locations->InAt(1);
3367
3368 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00003369 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003370 if (second.IsConstant()) {
3371 GenerateDivRemConstantIntegral(div);
3372 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003373 __ sdiv(out.AsRegister<Register>(),
3374 first.AsRegister<Register>(),
3375 second.AsRegister<Register>());
3376 } else {
3377 InvokeRuntimeCallingConvention calling_convention;
3378 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3379 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3380 DCHECK_EQ(R0, out.AsRegister<Register>());
3381
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003382 codegen_->InvokeRuntime(kQuickIdivmod, div, div->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003383 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003384 }
Calin Juravled0d48522014-11-04 16:40:20 +00003385 break;
3386 }
3387
Calin Juravle7c4954d2014-10-28 16:57:40 +00003388 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003389 InvokeRuntimeCallingConvention calling_convention;
3390 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
3391 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
3392 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
3393 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
3394 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003395 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003396
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003397 codegen_->InvokeRuntime(kQuickLdiv, div, div->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003398 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00003399 break;
3400 }
3401
3402 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00003403 __ vdivs(out.AsFpuRegister<SRegister>(),
3404 first.AsFpuRegister<SRegister>(),
3405 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003406 break;
3407 }
3408
3409 case Primitive::kPrimDouble: {
3410 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3411 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3412 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
3413 break;
3414 }
3415
3416 default:
3417 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3418 }
3419}
3420
Calin Juravlebacfec32014-11-14 15:54:36 +00003421void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003422 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003423
3424 // Most remainders are implemented in the runtime.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003425 LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08003426 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
3427 // sdiv will be replaced by other instruction sequence.
3428 call_kind = LocationSummary::kNoCall;
3429 } else if ((rem->GetResultType() == Primitive::kPrimInt)
3430 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003431 // Have hardware divide instruction for int, do it with three instructions.
3432 call_kind = LocationSummary::kNoCall;
3433 }
3434
Calin Juravlebacfec32014-11-14 15:54:36 +00003435 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
3436
Calin Juravled2ec87d2014-12-08 14:24:46 +00003437 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003438 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003439 if (rem->InputAt(1)->IsConstant()) {
3440 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00003441 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08003442 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003443 int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
3444 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08003445 // No temp register required.
3446 } else {
3447 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003448 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08003449 locations->AddTemp(Location::RequiresRegister());
3450 }
3451 }
3452 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003453 locations->SetInAt(0, Location::RequiresRegister());
3454 locations->SetInAt(1, Location::RequiresRegister());
3455 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3456 locations->AddTemp(Location::RequiresRegister());
3457 } else {
3458 InvokeRuntimeCallingConvention calling_convention;
3459 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3460 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3461 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
3462 // we only need the latter.
3463 locations->SetOut(Location::RegisterLocation(R1));
3464 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003465 break;
3466 }
3467 case Primitive::kPrimLong: {
3468 InvokeRuntimeCallingConvention calling_convention;
3469 locations->SetInAt(0, Location::RegisterPairLocation(
3470 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3471 locations->SetInAt(1, Location::RegisterPairLocation(
3472 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3473 // The runtime helper puts the output in R2,R3.
3474 locations->SetOut(Location::RegisterPairLocation(R2, R3));
3475 break;
3476 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00003477 case Primitive::kPrimFloat: {
3478 InvokeRuntimeCallingConvention calling_convention;
3479 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3480 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
3481 locations->SetOut(Location::FpuRegisterLocation(S0));
3482 break;
3483 }
3484
Calin Juravlebacfec32014-11-14 15:54:36 +00003485 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003486 InvokeRuntimeCallingConvention calling_convention;
3487 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3488 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
3489 locations->SetInAt(1, Location::FpuRegisterPairLocation(
3490 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
3491 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00003492 break;
3493 }
3494
3495 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003496 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003497 }
3498}
3499
3500void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
3501 LocationSummary* locations = rem->GetLocations();
3502 Location out = locations->Out();
3503 Location first = locations->InAt(0);
3504 Location second = locations->InAt(1);
3505
Calin Juravled2ec87d2014-12-08 14:24:46 +00003506 Primitive::Type type = rem->GetResultType();
3507 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003508 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003509 if (second.IsConstant()) {
3510 GenerateDivRemConstantIntegral(rem);
3511 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003512 Register reg1 = first.AsRegister<Register>();
3513 Register reg2 = second.AsRegister<Register>();
3514 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003515
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003516 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003517 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003518 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003519 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003520 } else {
3521 InvokeRuntimeCallingConvention calling_convention;
3522 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3523 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3524 DCHECK_EQ(R1, out.AsRegister<Register>());
3525
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003526 codegen_->InvokeRuntime(kQuickIdivmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003527 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003528 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003529 break;
3530 }
3531
3532 case Primitive::kPrimLong: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003533 codegen_->InvokeRuntime(kQuickLmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003534 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003535 break;
3536 }
3537
Calin Juravled2ec87d2014-12-08 14:24:46 +00003538 case Primitive::kPrimFloat: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003539 codegen_->InvokeRuntime(kQuickFmodf, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003540 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00003541 break;
3542 }
3543
Calin Juravlebacfec32014-11-14 15:54:36 +00003544 case Primitive::kPrimDouble: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003545 codegen_->InvokeRuntime(kQuickFmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003546 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003547 break;
3548 }
3549
3550 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003551 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003552 }
3553}
3554
Calin Juravled0d48522014-11-04 16:40:20 +00003555void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01003556 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003557 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00003558}
3559
3560void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01003561 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003562 codegen_->AddSlowPath(slow_path);
3563
3564 LocationSummary* locations = instruction->GetLocations();
3565 Location value = locations->InAt(0);
3566
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003567 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00003568 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003569 case Primitive::kPrimByte:
3570 case Primitive::kPrimChar:
3571 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003572 case Primitive::kPrimInt: {
3573 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003574 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003575 } else {
3576 DCHECK(value.IsConstant()) << value;
3577 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3578 __ b(slow_path->GetEntryLabel());
3579 }
3580 }
3581 break;
3582 }
3583 case Primitive::kPrimLong: {
3584 if (value.IsRegisterPair()) {
3585 __ orrs(IP,
3586 value.AsRegisterPairLow<Register>(),
3587 ShifterOperand(value.AsRegisterPairHigh<Register>()));
3588 __ b(slow_path->GetEntryLabel(), EQ);
3589 } else {
3590 DCHECK(value.IsConstant()) << value;
3591 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3592 __ b(slow_path->GetEntryLabel());
3593 }
3594 }
3595 break;
3596 default:
3597 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3598 }
3599 }
Calin Juravled0d48522014-11-04 16:40:20 +00003600}
3601
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003602void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
3603 Register in = locations->InAt(0).AsRegister<Register>();
3604 Location rhs = locations->InAt(1);
3605 Register out = locations->Out().AsRegister<Register>();
3606
3607 if (rhs.IsConstant()) {
3608 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
3609 // so map all rotations to a +ve. equivalent in that range.
3610 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
3611 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
3612 if (rot) {
3613 // Rotate, mapping left rotations to right equivalents if necessary.
3614 // (e.g. left by 2 bits == right by 30.)
3615 __ Ror(out, in, rot);
3616 } else if (out != in) {
3617 __ Mov(out, in);
3618 }
3619 } else {
3620 __ Ror(out, in, rhs.AsRegister<Register>());
3621 }
3622}
3623
3624// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
3625// rotates by swapping input regs (effectively rotating by the first 32-bits of
3626// a larger rotation) or flipping direction (thus treating larger right/left
3627// rotations as sub-word sized rotations in the other direction) as appropriate.
3628void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
3629 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
3630 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
3631 Location rhs = locations->InAt(1);
3632 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
3633 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
3634
3635 if (rhs.IsConstant()) {
3636 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
3637 // Map all rotations to +ve. equivalents on the interval [0,63].
Roland Levillain5b5b9312016-03-22 14:57:31 +00003638 rot &= kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003639 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
3640 // logic below to a simple pair of binary orr.
3641 // (e.g. 34 bits == in_reg swap + 2 bits right.)
3642 if (rot >= kArmBitsPerWord) {
3643 rot -= kArmBitsPerWord;
3644 std::swap(in_reg_hi, in_reg_lo);
3645 }
3646 // Rotate, or mov to out for zero or word size rotations.
3647 if (rot != 0u) {
3648 __ Lsr(out_reg_hi, in_reg_hi, rot);
3649 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
3650 __ Lsr(out_reg_lo, in_reg_lo, rot);
3651 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
3652 } else {
3653 __ Mov(out_reg_lo, in_reg_lo);
3654 __ Mov(out_reg_hi, in_reg_hi);
3655 }
3656 } else {
3657 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
3658 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
3659 Label end;
3660 Label shift_by_32_plus_shift_right;
3661
3662 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
3663 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
3664 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
3665 __ b(&shift_by_32_plus_shift_right, CC);
3666
3667 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
3668 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
3669 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
3670 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3671 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3672 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3673 __ Lsr(shift_left, in_reg_hi, shift_right);
3674 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
3675 __ b(&end);
3676
3677 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
3678 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
3679 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
3680 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
3681 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3682 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3683 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3684 __ Lsl(shift_right, in_reg_hi, shift_left);
3685 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
3686
3687 __ Bind(&end);
3688 }
3689}
Roland Levillain22c49222016-03-18 14:04:28 +00003690
3691void LocationsBuilderARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003692 LocationSummary* locations =
3693 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3694 switch (ror->GetResultType()) {
3695 case Primitive::kPrimInt: {
3696 locations->SetInAt(0, Location::RequiresRegister());
3697 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
3698 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3699 break;
3700 }
3701 case Primitive::kPrimLong: {
3702 locations->SetInAt(0, Location::RequiresRegister());
3703 if (ror->InputAt(1)->IsConstant()) {
3704 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
3705 } else {
3706 locations->SetInAt(1, Location::RequiresRegister());
3707 locations->AddTemp(Location::RequiresRegister());
3708 locations->AddTemp(Location::RequiresRegister());
3709 }
3710 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3711 break;
3712 }
3713 default:
3714 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
3715 }
3716}
3717
Roland Levillain22c49222016-03-18 14:04:28 +00003718void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003719 LocationSummary* locations = ror->GetLocations();
3720 Primitive::Type type = ror->GetResultType();
3721 switch (type) {
3722 case Primitive::kPrimInt: {
3723 HandleIntegerRotate(locations);
3724 break;
3725 }
3726 case Primitive::kPrimLong: {
3727 HandleLongRotate(locations);
3728 break;
3729 }
3730 default:
3731 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00003732 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003733 }
3734}
3735
Calin Juravle9aec02f2014-11-18 23:06:35 +00003736void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3737 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3738
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003739 LocationSummary* locations =
3740 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003741
3742 switch (op->GetResultType()) {
3743 case Primitive::kPrimInt: {
3744 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003745 if (op->InputAt(1)->IsConstant()) {
3746 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3747 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3748 } else {
3749 locations->SetInAt(1, Location::RequiresRegister());
3750 // Make the output overlap, as it will be used to hold the masked
3751 // second input.
3752 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3753 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003754 break;
3755 }
3756 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003757 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003758 if (op->InputAt(1)->IsConstant()) {
3759 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3760 // For simplicity, use kOutputOverlap even though we only require that low registers
3761 // don't clash with high registers which the register allocator currently guarantees.
3762 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3763 } else {
3764 locations->SetInAt(1, Location::RequiresRegister());
3765 locations->AddTemp(Location::RequiresRegister());
3766 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3767 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003768 break;
3769 }
3770 default:
3771 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3772 }
3773}
3774
3775void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3776 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3777
3778 LocationSummary* locations = op->GetLocations();
3779 Location out = locations->Out();
3780 Location first = locations->InAt(0);
3781 Location second = locations->InAt(1);
3782
3783 Primitive::Type type = op->GetResultType();
3784 switch (type) {
3785 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003786 Register out_reg = out.AsRegister<Register>();
3787 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003788 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003789 Register second_reg = second.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +00003790 // ARM doesn't mask the shift count so we need to do it ourselves.
Roland Levillain5b5b9312016-03-22 14:57:31 +00003791 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003792 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003793 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003794 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003795 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003796 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003797 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003798 }
3799 } else {
3800 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003801 uint32_t shift_value = cst & kMaxIntShiftDistance;
Roland Levillainc9285912015-12-18 10:38:42 +00003802 if (shift_value == 0) { // ARM does not support shifting with 0 immediate.
Calin Juravle9aec02f2014-11-18 23:06:35 +00003803 __ Mov(out_reg, first_reg);
3804 } else if (op->IsShl()) {
3805 __ Lsl(out_reg, first_reg, shift_value);
3806 } else if (op->IsShr()) {
3807 __ Asr(out_reg, first_reg, shift_value);
3808 } else {
3809 __ Lsr(out_reg, first_reg, shift_value);
3810 }
3811 }
3812 break;
3813 }
3814 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003815 Register o_h = out.AsRegisterPairHigh<Register>();
3816 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003817
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003818 Register high = first.AsRegisterPairHigh<Register>();
3819 Register low = first.AsRegisterPairLow<Register>();
3820
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003821 if (second.IsRegister()) {
3822 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003823
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003824 Register second_reg = second.AsRegister<Register>();
3825
3826 if (op->IsShl()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003827 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003828 // Shift the high part
3829 __ Lsl(o_h, high, o_l);
3830 // Shift the low part and `or` what overflew on the high part
3831 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3832 __ Lsr(temp, low, temp);
3833 __ orr(o_h, o_h, ShifterOperand(temp));
3834 // If the shift is > 32 bits, override the high part
3835 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3836 __ it(PL);
3837 __ Lsl(o_h, low, temp, PL);
3838 // Shift the low part
3839 __ Lsl(o_l, low, o_l);
3840 } else if (op->IsShr()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003841 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003842 // Shift the low part
3843 __ Lsr(o_l, low, o_h);
3844 // Shift the high part and `or` what underflew on the low part
3845 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3846 __ Lsl(temp, high, temp);
3847 __ orr(o_l, o_l, ShifterOperand(temp));
3848 // If the shift is > 32 bits, override the low part
3849 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3850 __ it(PL);
3851 __ Asr(o_l, high, temp, PL);
3852 // Shift the high part
3853 __ Asr(o_h, high, o_h);
3854 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003855 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003856 // same as Shr except we use `Lsr`s and not `Asr`s
3857 __ Lsr(o_l, low, o_h);
3858 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3859 __ Lsl(temp, high, temp);
3860 __ orr(o_l, o_l, ShifterOperand(temp));
3861 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3862 __ it(PL);
3863 __ Lsr(o_l, high, temp, PL);
3864 __ Lsr(o_h, high, o_h);
3865 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003866 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003867 // Register allocator doesn't create partial overlap.
3868 DCHECK_NE(o_l, high);
3869 DCHECK_NE(o_h, low);
3870 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003871 uint32_t shift_value = cst & kMaxLongShiftDistance;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003872 if (shift_value > 32) {
3873 if (op->IsShl()) {
3874 __ Lsl(o_h, low, shift_value - 32);
3875 __ LoadImmediate(o_l, 0);
3876 } else if (op->IsShr()) {
3877 __ Asr(o_l, high, shift_value - 32);
3878 __ Asr(o_h, high, 31);
3879 } else {
3880 __ Lsr(o_l, high, shift_value - 32);
3881 __ LoadImmediate(o_h, 0);
3882 }
3883 } else if (shift_value == 32) {
3884 if (op->IsShl()) {
3885 __ mov(o_h, ShifterOperand(low));
3886 __ LoadImmediate(o_l, 0);
3887 } else if (op->IsShr()) {
3888 __ mov(o_l, ShifterOperand(high));
3889 __ Asr(o_h, high, 31);
3890 } else {
3891 __ mov(o_l, ShifterOperand(high));
3892 __ LoadImmediate(o_h, 0);
3893 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00003894 } else if (shift_value == 1) {
3895 if (op->IsShl()) {
3896 __ Lsls(o_l, low, 1);
3897 __ adc(o_h, high, ShifterOperand(high));
3898 } else if (op->IsShr()) {
3899 __ Asrs(o_h, high, 1);
3900 __ Rrx(o_l, low);
3901 } else {
3902 __ Lsrs(o_h, high, 1);
3903 __ Rrx(o_l, low);
3904 }
3905 } else {
3906 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003907 if (op->IsShl()) {
3908 __ Lsl(o_h, high, shift_value);
3909 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3910 __ Lsl(o_l, low, shift_value);
3911 } else if (op->IsShr()) {
3912 __ Lsr(o_l, low, shift_value);
3913 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3914 __ Asr(o_h, high, shift_value);
3915 } else {
3916 __ Lsr(o_l, low, shift_value);
3917 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3918 __ Lsr(o_h, high, shift_value);
3919 }
3920 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003921 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003922 break;
3923 }
3924 default:
3925 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003926 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003927 }
3928}
3929
3930void LocationsBuilderARM::VisitShl(HShl* shl) {
3931 HandleShift(shl);
3932}
3933
3934void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3935 HandleShift(shl);
3936}
3937
3938void LocationsBuilderARM::VisitShr(HShr* shr) {
3939 HandleShift(shr);
3940}
3941
3942void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3943 HandleShift(shr);
3944}
3945
3946void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3947 HandleShift(ushr);
3948}
3949
3950void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3951 HandleShift(ushr);
3952}
3953
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003954void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003955 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003956 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
David Brazdil6de19382016-01-08 17:37:10 +00003957 if (instruction->IsStringAlloc()) {
3958 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
3959 } else {
3960 InvokeRuntimeCallingConvention calling_convention;
3961 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
David Brazdil6de19382016-01-08 17:37:10 +00003962 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003963 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003964}
3965
3966void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003967 // Note: if heap poisoning is enabled, the entry point takes cares
3968 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00003969 if (instruction->IsStringAlloc()) {
3970 // String is allocated through StringFactory. Call NewEmptyString entry point.
3971 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
Andreas Gampe542451c2016-07-26 09:02:02 -07003972 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00003973 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
3974 __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
3975 __ blx(LR);
3976 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3977 } else {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003978 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +00003979 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
David Brazdil6de19382016-01-08 17:37:10 +00003980 }
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003981}
3982
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003983void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3984 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003985 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003986 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003987 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00003988 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3989 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003990}
3991
3992void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003993 // Note: if heap poisoning is enabled, the entry point takes cares
3994 // of poisoning the reference.
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00003995 codegen_->InvokeRuntime(kQuickAllocArrayResolved, instruction, instruction->GetDexPc());
3996 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003997}
3998
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003999void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004000 LocationSummary* locations =
4001 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01004002 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
4003 if (location.IsStackSlot()) {
4004 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4005 } else if (location.IsDoubleStackSlot()) {
4006 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004007 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01004008 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004009}
4010
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004011void InstructionCodeGeneratorARM::VisitParameterValue(
4012 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004013 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004014}
4015
4016void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
4017 LocationSummary* locations =
4018 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4019 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
4020}
4021
4022void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
4023 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004024}
4025
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004026void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004027 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004028 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004029 locations->SetInAt(0, Location::RequiresRegister());
4030 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01004031}
4032
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004033void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
4034 LocationSummary* locations = not_->GetLocations();
4035 Location out = locations->Out();
4036 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00004037 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004038 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00004039 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004040 break;
4041
4042 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01004043 __ mvn(out.AsRegisterPairLow<Register>(),
4044 ShifterOperand(in.AsRegisterPairLow<Register>()));
4045 __ mvn(out.AsRegisterPairHigh<Register>(),
4046 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004047 break;
4048
4049 default:
4050 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
4051 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01004052}
4053
David Brazdil66d126e2015-04-03 16:02:44 +01004054void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
4055 LocationSummary* locations =
4056 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
4057 locations->SetInAt(0, Location::RequiresRegister());
4058 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4059}
4060
4061void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01004062 LocationSummary* locations = bool_not->GetLocations();
4063 Location out = locations->Out();
4064 Location in = locations->InAt(0);
4065 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
4066}
4067
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004068void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004069 LocationSummary* locations =
4070 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00004071 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00004072 case Primitive::kPrimBoolean:
4073 case Primitive::kPrimByte:
4074 case Primitive::kPrimShort:
4075 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08004076 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00004077 case Primitive::kPrimLong: {
4078 locations->SetInAt(0, Location::RequiresRegister());
4079 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004080 // Output overlaps because it is written before doing the low comparison.
4081 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00004082 break;
4083 }
4084 case Primitive::kPrimFloat:
4085 case Primitive::kPrimDouble: {
4086 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01004087 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +00004088 locations->SetOut(Location::RequiresRegister());
4089 break;
4090 }
4091 default:
4092 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
4093 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004094}
4095
4096void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004097 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004098 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00004099 Location left = locations->InAt(0);
4100 Location right = locations->InAt(1);
4101
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004102 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00004103 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00004104 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00004105 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00004106 case Primitive::kPrimBoolean:
4107 case Primitive::kPrimByte:
4108 case Primitive::kPrimShort:
4109 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08004110 case Primitive::kPrimInt: {
4111 __ LoadImmediate(out, 0);
4112 __ cmp(left.AsRegister<Register>(),
4113 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
4114 less_cond = LT;
4115 break;
4116 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004117 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004118 __ cmp(left.AsRegisterPairHigh<Register>(),
4119 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004120 __ b(&less, LT);
4121 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01004122 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00004123 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004124 __ cmp(left.AsRegisterPairLow<Register>(),
4125 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00004126 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00004127 break;
4128 }
4129 case Primitive::kPrimFloat:
4130 case Primitive::kPrimDouble: {
4131 __ LoadImmediate(out, 0);
Vladimir Marko37dd80d2016-08-01 17:41:45 +01004132 GenerateVcmp(compare);
Calin Juravleddb7df22014-11-25 20:56:51 +00004133 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00004134 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004135 break;
4136 }
4137 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00004138 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00004139 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004140 }
Aart Bika19616e2016-02-01 18:57:58 -08004141
Calin Juravleddb7df22014-11-25 20:56:51 +00004142 __ b(&done, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00004143 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00004144
4145 __ Bind(&greater);
4146 __ LoadImmediate(out, 1);
4147 __ b(&done);
4148
4149 __ Bind(&less);
4150 __ LoadImmediate(out, -1);
4151
4152 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004153}
4154
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01004155void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004156 LocationSummary* locations =
4157 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01004158 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01004159 locations->SetInAt(i, Location::Any());
4160 }
4161 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01004162}
4163
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004164void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004165 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01004166}
4167
Roland Levillainc9285912015-12-18 10:38:42 +00004168void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
4169 // TODO (ported from quick): revisit ARM barrier kinds.
4170 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00004171 switch (kind) {
4172 case MemBarrierKind::kAnyStore:
4173 case MemBarrierKind::kLoadAny:
4174 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07004175 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00004176 break;
4177 }
4178 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07004179 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00004180 break;
4181 }
4182 default:
4183 LOG(FATAL) << "Unexpected memory barrier " << kind;
4184 }
Kenny Root1d8199d2015-06-02 11:01:10 -07004185 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00004186}
4187
4188void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
4189 uint32_t offset,
4190 Register out_lo,
4191 Register out_hi) {
4192 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004193 // Ensure `out_lo` is different from `addr`, so that loading
4194 // `offset` into `out_lo` does not clutter `addr`.
4195 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00004196 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00004197 __ add(IP, addr, ShifterOperand(out_lo));
4198 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00004199 }
4200 __ ldrexd(out_lo, out_hi, addr);
4201}
4202
4203void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
4204 uint32_t offset,
4205 Register value_lo,
4206 Register value_hi,
4207 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00004208 Register temp2,
4209 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004210 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00004211 if (offset != 0) {
4212 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00004213 __ add(IP, addr, ShifterOperand(temp1));
4214 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00004215 }
4216 __ Bind(&fail);
4217 // We need a load followed by store. (The address used in a STREX instruction must
4218 // be the same as the address in the most recently executed LDREX instruction.)
4219 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00004220 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004221 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004222 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00004223}
4224
4225void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
4226 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4227
Nicolas Geoffray39468442014-09-02 15:17:15 +01004228 LocationSummary* locations =
4229 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004230 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00004231
Calin Juravle52c48962014-12-16 17:02:57 +00004232 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004233 if (Primitive::IsFloatingPointType(field_type)) {
4234 locations->SetInAt(1, Location::RequiresFpuRegister());
4235 } else {
4236 locations->SetInAt(1, Location::RequiresRegister());
4237 }
4238
Calin Juravle52c48962014-12-16 17:02:57 +00004239 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00004240 bool generate_volatile = field_info.IsVolatile()
4241 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004242 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01004243 bool needs_write_barrier =
4244 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004245 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00004246 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01004247 if (needs_write_barrier) {
4248 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004249 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00004250 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004251 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00004252 // - registers need to be consecutive
4253 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00004254 // We don't test for ARM yet, and the assertion makes sure that we
4255 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00004256 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4257
4258 locations->AddTemp(Location::RequiresRegister());
4259 locations->AddTemp(Location::RequiresRegister());
4260 if (field_type == Primitive::kPrimDouble) {
4261 // For doubles we need two more registers to copy the value.
4262 locations->AddTemp(Location::RegisterLocation(R2));
4263 locations->AddTemp(Location::RegisterLocation(R3));
4264 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004265 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004266}
4267
Calin Juravle52c48962014-12-16 17:02:57 +00004268void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004269 const FieldInfo& field_info,
4270 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00004271 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4272
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004273 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00004274 Register base = locations->InAt(0).AsRegister<Register>();
4275 Location value = locations->InAt(1);
4276
4277 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004278 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00004279 Primitive::Type field_type = field_info.GetFieldType();
4280 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01004281 bool needs_write_barrier =
4282 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004283
4284 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004285 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00004286 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004287
4288 switch (field_type) {
4289 case Primitive::kPrimBoolean:
4290 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00004291 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004292 break;
4293 }
4294
4295 case Primitive::kPrimShort:
4296 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00004297 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004298 break;
4299 }
4300
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004301 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004302 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01004303 if (kPoisonHeapReferences && needs_write_barrier) {
4304 // Note that in the case where `value` is a null reference,
4305 // we do not enter this block, as a null reference does not
4306 // need poisoning.
4307 DCHECK_EQ(field_type, Primitive::kPrimNot);
4308 Register temp = locations->GetTemp(0).AsRegister<Register>();
4309 __ Mov(temp, value.AsRegister<Register>());
4310 __ PoisonHeapReference(temp);
4311 __ StoreToOffset(kStoreWord, temp, base, offset);
4312 } else {
4313 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
4314 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004315 break;
4316 }
4317
4318 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00004319 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004320 GenerateWideAtomicStore(base, offset,
4321 value.AsRegisterPairLow<Register>(),
4322 value.AsRegisterPairHigh<Register>(),
4323 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00004324 locations->GetTemp(1).AsRegister<Register>(),
4325 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004326 } else {
4327 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004328 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004329 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004330 break;
4331 }
4332
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004333 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00004334 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004335 break;
4336 }
4337
4338 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004339 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00004340 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004341 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
4342 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
4343
4344 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
4345
4346 GenerateWideAtomicStore(base, offset,
4347 value_reg_lo,
4348 value_reg_hi,
4349 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00004350 locations->GetTemp(3).AsRegister<Register>(),
4351 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004352 } else {
4353 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004354 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004355 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004356 break;
4357 }
4358
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004359 case Primitive::kPrimVoid:
4360 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004361 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004362 }
Calin Juravle52c48962014-12-16 17:02:57 +00004363
Calin Juravle77520bc2015-01-12 18:45:46 +00004364 // Longs and doubles are handled in the switch.
4365 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
4366 codegen_->MaybeRecordImplicitNullCheck(instruction);
4367 }
4368
4369 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
4370 Register temp = locations->GetTemp(0).AsRegister<Register>();
4371 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004372 codegen_->MarkGCCard(
4373 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004374 }
4375
Calin Juravle52c48962014-12-16 17:02:57 +00004376 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004377 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00004378 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004379}
4380
Calin Juravle52c48962014-12-16 17:02:57 +00004381void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
4382 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00004383
4384 bool object_field_get_with_read_barrier =
4385 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004386 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004387 new (GetGraph()->GetArena()) LocationSummary(instruction,
4388 object_field_get_with_read_barrier ?
4389 LocationSummary::kCallOnSlowPath :
4390 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01004391 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004392 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01004393 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004394 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00004395
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004396 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00004397 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004398 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00004399 // The output overlaps in case of volatile long: we don't want the
4400 // code generated by GenerateWideAtomicLoad to overwrite the
4401 // object's location. Likewise, in the case of an object field get
4402 // with read barriers enabled, we do not want the load to overwrite
4403 // the object's location, as we need it to emit the read barrier.
4404 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
4405 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01004406
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004407 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4408 locations->SetOut(Location::RequiresFpuRegister());
4409 } else {
4410 locations->SetOut(Location::RequiresRegister(),
4411 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
4412 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004413 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00004414 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00004415 // - registers need to be consecutive
4416 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00004417 // We don't test for ARM yet, and the assertion makes sure that we
4418 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00004419 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4420 locations->AddTemp(Location::RequiresRegister());
4421 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00004422 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
4423 // We need a temporary register for the read barrier marking slow
4424 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
4425 locations->AddTemp(Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00004426 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004427}
4428
Vladimir Marko37dd80d2016-08-01 17:41:45 +01004429Location LocationsBuilderARM::ArithmeticZeroOrFpuRegister(HInstruction* input) {
4430 DCHECK(input->GetType() == Primitive::kPrimDouble || input->GetType() == Primitive::kPrimFloat)
4431 << input->GetType();
4432 if ((input->IsFloatConstant() && (input->AsFloatConstant()->IsArithmeticZero())) ||
4433 (input->IsDoubleConstant() && (input->AsDoubleConstant()->IsArithmeticZero()))) {
4434 return Location::ConstantLocation(input->AsConstant());
4435 } else {
4436 return Location::RequiresFpuRegister();
4437 }
4438}
4439
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004440Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
4441 Opcode opcode) {
4442 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
4443 if (constant->IsConstant() &&
4444 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
4445 return Location::ConstantLocation(constant->AsConstant());
4446 }
4447 return Location::RequiresRegister();
4448}
4449
4450bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
4451 Opcode opcode) {
4452 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
4453 if (Primitive::Is64BitType(input_cst->GetType())) {
Vladimir Marko59751a72016-08-05 14:37:27 +01004454 Opcode high_opcode = opcode;
4455 SetCc low_set_cc = kCcDontCare;
4456 switch (opcode) {
4457 case SUB:
4458 // Flip the operation to an ADD.
4459 value = -value;
4460 opcode = ADD;
4461 FALLTHROUGH_INTENDED;
4462 case ADD:
4463 if (Low32Bits(value) == 0u) {
4464 return CanEncodeConstantAsImmediate(High32Bits(value), opcode, kCcDontCare);
4465 }
4466 high_opcode = ADC;
4467 low_set_cc = kCcSet;
4468 break;
4469 default:
4470 break;
4471 }
4472 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode, low_set_cc) &&
4473 CanEncodeConstantAsImmediate(High32Bits(value), high_opcode, kCcDontCare);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004474 } else {
4475 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
4476 }
4477}
4478
Vladimir Marko59751a72016-08-05 14:37:27 +01004479bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value,
4480 Opcode opcode,
4481 SetCc set_cc) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004482 ShifterOperand so;
4483 ArmAssembler* assembler = codegen_->GetAssembler();
Vladimir Marko59751a72016-08-05 14:37:27 +01004484 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, set_cc, &so)) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004485 return true;
4486 }
4487 Opcode neg_opcode = kNoOperand;
4488 switch (opcode) {
Vladimir Marko59751a72016-08-05 14:37:27 +01004489 case AND: neg_opcode = BIC; value = ~value; break;
4490 case ORR: neg_opcode = ORN; value = ~value; break;
4491 case ADD: neg_opcode = SUB; value = -value; break;
4492 case ADC: neg_opcode = SBC; value = ~value; break;
4493 case SUB: neg_opcode = ADD; value = -value; break;
4494 case SBC: neg_opcode = ADC; value = ~value; break;
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004495 default:
4496 return false;
4497 }
Vladimir Marko59751a72016-08-05 14:37:27 +01004498 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, value, set_cc, &so);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004499}
4500
Calin Juravle52c48962014-12-16 17:02:57 +00004501void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4502 const FieldInfo& field_info) {
4503 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004504
Calin Juravle52c48962014-12-16 17:02:57 +00004505 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004506 Location base_loc = locations->InAt(0);
4507 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00004508 Location out = locations->Out();
4509 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004510 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00004511 Primitive::Type field_type = field_info.GetFieldType();
4512 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4513
4514 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00004515 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00004516 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004517 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004518
Roland Levillainc9285912015-12-18 10:38:42 +00004519 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00004520 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004521 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004522
Roland Levillainc9285912015-12-18 10:38:42 +00004523 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00004524 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004525 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004526
Roland Levillainc9285912015-12-18 10:38:42 +00004527 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00004528 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004529 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004530
4531 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00004532 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004533 break;
Roland Levillainc9285912015-12-18 10:38:42 +00004534
4535 case Primitive::kPrimNot: {
4536 // /* HeapReference<Object> */ out = *(base + offset)
4537 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4538 Location temp_loc = locations->GetTemp(0);
4539 // Note that a potential implicit null check is handled in this
4540 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
4541 codegen_->GenerateFieldLoadWithBakerReadBarrier(
4542 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
4543 if (is_volatile) {
4544 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4545 }
4546 } else {
4547 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4548 codegen_->MaybeRecordImplicitNullCheck(instruction);
4549 if (is_volatile) {
4550 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4551 }
4552 // If read barriers are enabled, emit read barriers other than
4553 // Baker's using a slow path (and also unpoison the loaded
4554 // reference, if heap poisoning is enabled).
4555 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4556 }
4557 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004558 }
4559
Roland Levillainc9285912015-12-18 10:38:42 +00004560 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00004561 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004562 GenerateWideAtomicLoad(base, offset,
4563 out.AsRegisterPairLow<Register>(),
4564 out.AsRegisterPairHigh<Register>());
4565 } else {
4566 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4567 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004568 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004569
Roland Levillainc9285912015-12-18 10:38:42 +00004570 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00004571 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004572 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004573
4574 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004575 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00004576 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004577 Register lo = locations->GetTemp(0).AsRegister<Register>();
4578 Register hi = locations->GetTemp(1).AsRegister<Register>();
4579 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00004580 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004581 __ vmovdrr(out_reg, lo, hi);
4582 } else {
4583 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004584 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004585 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004586 break;
4587 }
4588
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004589 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00004590 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004591 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004592 }
Calin Juravle52c48962014-12-16 17:02:57 +00004593
Roland Levillainc9285912015-12-18 10:38:42 +00004594 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
4595 // Potential implicit null checks, in the case of reference or
4596 // double fields, are handled in the previous switch statement.
4597 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00004598 codegen_->MaybeRecordImplicitNullCheck(instruction);
4599 }
4600
Calin Juravle52c48962014-12-16 17:02:57 +00004601 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004602 if (field_type == Primitive::kPrimNot) {
4603 // Memory barriers, in the case of references, are also handled
4604 // in the previous switch statement.
4605 } else {
4606 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4607 }
Roland Levillain4d027112015-07-01 15:41:14 +01004608 }
Calin Juravle52c48962014-12-16 17:02:57 +00004609}
4610
4611void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4612 HandleFieldSet(instruction, instruction->GetFieldInfo());
4613}
4614
4615void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004616 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004617}
4618
4619void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4620 HandleFieldGet(instruction, instruction->GetFieldInfo());
4621}
4622
4623void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4624 HandleFieldGet(instruction, instruction->GetFieldInfo());
4625}
4626
4627void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4628 HandleFieldGet(instruction, instruction->GetFieldInfo());
4629}
4630
4631void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4632 HandleFieldGet(instruction, instruction->GetFieldInfo());
4633}
4634
4635void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4636 HandleFieldSet(instruction, instruction->GetFieldInfo());
4637}
4638
4639void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004640 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004641}
4642
Calin Juravlee460d1d2015-09-29 04:52:17 +01004643void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4644 HUnresolvedInstanceFieldGet* instruction) {
4645 FieldAccessCallingConventionARM calling_convention;
4646 codegen_->CreateUnresolvedFieldLocationSummary(
4647 instruction, instruction->GetFieldType(), calling_convention);
4648}
4649
4650void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4651 HUnresolvedInstanceFieldGet* instruction) {
4652 FieldAccessCallingConventionARM calling_convention;
4653 codegen_->GenerateUnresolvedFieldAccess(instruction,
4654 instruction->GetFieldType(),
4655 instruction->GetFieldIndex(),
4656 instruction->GetDexPc(),
4657 calling_convention);
4658}
4659
4660void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4661 HUnresolvedInstanceFieldSet* instruction) {
4662 FieldAccessCallingConventionARM calling_convention;
4663 codegen_->CreateUnresolvedFieldLocationSummary(
4664 instruction, instruction->GetFieldType(), calling_convention);
4665}
4666
4667void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4668 HUnresolvedInstanceFieldSet* instruction) {
4669 FieldAccessCallingConventionARM calling_convention;
4670 codegen_->GenerateUnresolvedFieldAccess(instruction,
4671 instruction->GetFieldType(),
4672 instruction->GetFieldIndex(),
4673 instruction->GetDexPc(),
4674 calling_convention);
4675}
4676
4677void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4678 HUnresolvedStaticFieldGet* instruction) {
4679 FieldAccessCallingConventionARM calling_convention;
4680 codegen_->CreateUnresolvedFieldLocationSummary(
4681 instruction, instruction->GetFieldType(), calling_convention);
4682}
4683
4684void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4685 HUnresolvedStaticFieldGet* instruction) {
4686 FieldAccessCallingConventionARM calling_convention;
4687 codegen_->GenerateUnresolvedFieldAccess(instruction,
4688 instruction->GetFieldType(),
4689 instruction->GetFieldIndex(),
4690 instruction->GetDexPc(),
4691 calling_convention);
4692}
4693
4694void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4695 HUnresolvedStaticFieldSet* instruction) {
4696 FieldAccessCallingConventionARM calling_convention;
4697 codegen_->CreateUnresolvedFieldLocationSummary(
4698 instruction, instruction->GetFieldType(), calling_convention);
4699}
4700
4701void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4702 HUnresolvedStaticFieldSet* instruction) {
4703 FieldAccessCallingConventionARM calling_convention;
4704 codegen_->GenerateUnresolvedFieldAccess(instruction,
4705 instruction->GetFieldType(),
4706 instruction->GetFieldIndex(),
4707 instruction->GetDexPc(),
4708 calling_convention);
4709}
4710
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004711void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004712 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
4713 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004714}
4715
Calin Juravle2ae48182016-03-16 14:05:09 +00004716void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4717 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004718 return;
4719 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004720 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004721
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004722 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00004723 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004724}
4725
Calin Juravle2ae48182016-03-16 14:05:09 +00004726void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01004727 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00004728 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004729
4730 LocationSummary* locations = instruction->GetLocations();
4731 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004732
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004733 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004734}
4735
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004736void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00004737 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004738}
4739
Artem Serov6c916792016-07-11 14:02:34 +01004740static LoadOperandType GetLoadOperandType(Primitive::Type type) {
4741 switch (type) {
4742 case Primitive::kPrimNot:
4743 return kLoadWord;
4744 case Primitive::kPrimBoolean:
4745 return kLoadUnsignedByte;
4746 case Primitive::kPrimByte:
4747 return kLoadSignedByte;
4748 case Primitive::kPrimChar:
4749 return kLoadUnsignedHalfword;
4750 case Primitive::kPrimShort:
4751 return kLoadSignedHalfword;
4752 case Primitive::kPrimInt:
4753 return kLoadWord;
4754 case Primitive::kPrimLong:
4755 return kLoadWordPair;
4756 case Primitive::kPrimFloat:
4757 return kLoadSWord;
4758 case Primitive::kPrimDouble:
4759 return kLoadDWord;
4760 default:
4761 LOG(FATAL) << "Unreachable type " << type;
4762 UNREACHABLE();
4763 }
4764}
4765
4766static StoreOperandType GetStoreOperandType(Primitive::Type type) {
4767 switch (type) {
4768 case Primitive::kPrimNot:
4769 return kStoreWord;
4770 case Primitive::kPrimBoolean:
4771 case Primitive::kPrimByte:
4772 return kStoreByte;
4773 case Primitive::kPrimChar:
4774 case Primitive::kPrimShort:
4775 return kStoreHalfword;
4776 case Primitive::kPrimInt:
4777 return kStoreWord;
4778 case Primitive::kPrimLong:
4779 return kStoreWordPair;
4780 case Primitive::kPrimFloat:
4781 return kStoreSWord;
4782 case Primitive::kPrimDouble:
4783 return kStoreDWord;
4784 default:
4785 LOG(FATAL) << "Unreachable type " << type;
4786 UNREACHABLE();
4787 }
4788}
4789
4790void CodeGeneratorARM::LoadFromShiftedRegOffset(Primitive::Type type,
4791 Location out_loc,
4792 Register base,
4793 Register reg_offset,
4794 Condition cond) {
4795 uint32_t shift_count = Primitive::ComponentSizeShift(type);
4796 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
4797
4798 switch (type) {
4799 case Primitive::kPrimByte:
4800 __ ldrsb(out_loc.AsRegister<Register>(), mem_address, cond);
4801 break;
4802 case Primitive::kPrimBoolean:
4803 __ ldrb(out_loc.AsRegister<Register>(), mem_address, cond);
4804 break;
4805 case Primitive::kPrimShort:
4806 __ ldrsh(out_loc.AsRegister<Register>(), mem_address, cond);
4807 break;
4808 case Primitive::kPrimChar:
4809 __ ldrh(out_loc.AsRegister<Register>(), mem_address, cond);
4810 break;
4811 case Primitive::kPrimNot:
4812 case Primitive::kPrimInt:
4813 __ ldr(out_loc.AsRegister<Register>(), mem_address, cond);
4814 break;
4815 // T32 doesn't support LoadFromShiftedRegOffset mem address mode for these types.
4816 case Primitive::kPrimLong:
4817 case Primitive::kPrimFloat:
4818 case Primitive::kPrimDouble:
4819 default:
4820 LOG(FATAL) << "Unreachable type " << type;
4821 UNREACHABLE();
4822 }
4823}
4824
4825void CodeGeneratorARM::StoreToShiftedRegOffset(Primitive::Type type,
4826 Location loc,
4827 Register base,
4828 Register reg_offset,
4829 Condition cond) {
4830 uint32_t shift_count = Primitive::ComponentSizeShift(type);
4831 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
4832
4833 switch (type) {
4834 case Primitive::kPrimByte:
4835 case Primitive::kPrimBoolean:
4836 __ strb(loc.AsRegister<Register>(), mem_address, cond);
4837 break;
4838 case Primitive::kPrimShort:
4839 case Primitive::kPrimChar:
4840 __ strh(loc.AsRegister<Register>(), mem_address, cond);
4841 break;
4842 case Primitive::kPrimNot:
4843 case Primitive::kPrimInt:
4844 __ str(loc.AsRegister<Register>(), mem_address, cond);
4845 break;
4846 // T32 doesn't support StoreToShiftedRegOffset mem address mode for these types.
4847 case Primitive::kPrimLong:
4848 case Primitive::kPrimFloat:
4849 case Primitive::kPrimDouble:
4850 default:
4851 LOG(FATAL) << "Unreachable type " << type;
4852 UNREACHABLE();
4853 }
4854}
4855
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004856void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004857 bool object_array_get_with_read_barrier =
4858 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004859 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004860 new (GetGraph()->GetArena()) LocationSummary(instruction,
4861 object_array_get_with_read_barrier ?
4862 LocationSummary::kCallOnSlowPath :
4863 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01004864 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004865 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01004866 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004867 locations->SetInAt(0, Location::RequiresRegister());
4868 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004869 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4870 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4871 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004872 // The output overlaps in the case of an object array get with
4873 // read barriers enabled: we do not want the move to overwrite the
4874 // array's location, as we need it to emit the read barrier.
4875 locations->SetOut(
4876 Location::RequiresRegister(),
4877 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004878 }
Roland Levillainc9285912015-12-18 10:38:42 +00004879 // We need a temporary register for the read barrier marking slow
4880 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
jessicahandojo05765752016-09-09 19:01:32 -07004881 // Also need for String compression feature.
4882 if ((object_array_get_with_read_barrier && kUseBakerReadBarrier)
4883 || (mirror::kUseStringCompression && instruction->IsStringCharAt())) {
Roland Levillainc9285912015-12-18 10:38:42 +00004884 locations->AddTemp(Location::RequiresRegister());
4885 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004886}
4887
4888void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4889 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004890 Location obj_loc = locations->InAt(0);
4891 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004892 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00004893 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01004894 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Roland Levillainc9285912015-12-18 10:38:42 +00004895 Primitive::Type type = instruction->GetType();
jessicahandojo05765752016-09-09 19:01:32 -07004896 const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
4897 instruction->IsStringCharAt();
Artem Serov328429f2016-07-06 16:23:04 +01004898 HInstruction* array_instr = instruction->GetArray();
4899 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Artem Serov6c916792016-07-11 14:02:34 +01004900
Roland Levillain4d027112015-07-01 15:41:14 +01004901 switch (type) {
Artem Serov6c916792016-07-11 14:02:34 +01004902 case Primitive::kPrimBoolean:
4903 case Primitive::kPrimByte:
4904 case Primitive::kPrimShort:
4905 case Primitive::kPrimChar:
Roland Levillainc9285912015-12-18 10:38:42 +00004906 case Primitive::kPrimInt: {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01004907 Register length;
4908 if (maybe_compressed_char_at) {
4909 length = locations->GetTemp(0).AsRegister<Register>();
4910 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
4911 __ LoadFromOffset(kLoadWord, length, obj, count_offset);
4912 codegen_->MaybeRecordImplicitNullCheck(instruction);
4913 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004914 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01004915 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
jessicahandojo05765752016-09-09 19:01:32 -07004916 if (maybe_compressed_char_at) {
jessicahandojo05765752016-09-09 19:01:32 -07004917 Label uncompressed_load, done;
Vladimir Markofdaf0f42016-10-13 19:29:53 +01004918 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
4919 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
4920 "Expecting 0=compressed, 1=uncompressed");
4921 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07004922 __ LoadFromOffset(kLoadUnsignedByte,
4923 out_loc.AsRegister<Register>(),
4924 obj,
4925 data_offset + const_index);
4926 __ b(&done);
4927 __ Bind(&uncompressed_load);
4928 __ LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
4929 out_loc.AsRegister<Register>(),
4930 obj,
4931 data_offset + (const_index << 1));
4932 __ Bind(&done);
4933 } else {
4934 uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
Artem Serov6c916792016-07-11 14:02:34 +01004935
jessicahandojo05765752016-09-09 19:01:32 -07004936 LoadOperandType load_type = GetLoadOperandType(type);
4937 __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
4938 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004939 } else {
Artem Serov328429f2016-07-06 16:23:04 +01004940 Register temp = IP;
4941
4942 if (has_intermediate_address) {
4943 // We do not need to compute the intermediate address from the array: the
4944 // input instruction has done it already. See the comment in
4945 // `TryExtractArrayAccessAddress()`.
4946 if (kIsDebugBuild) {
4947 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
4948 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
4949 }
4950 temp = obj;
4951 } else {
4952 __ add(temp, obj, ShifterOperand(data_offset));
4953 }
jessicahandojo05765752016-09-09 19:01:32 -07004954 if (maybe_compressed_char_at) {
4955 Label uncompressed_load, done;
Vladimir Markofdaf0f42016-10-13 19:29:53 +01004956 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
4957 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
4958 "Expecting 0=compressed, 1=uncompressed");
4959 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07004960 __ ldrb(out_loc.AsRegister<Register>(),
4961 Address(temp, index.AsRegister<Register>(), Shift::LSL, 0));
4962 __ b(&done);
4963 __ Bind(&uncompressed_load);
4964 __ ldrh(out_loc.AsRegister<Register>(),
4965 Address(temp, index.AsRegister<Register>(), Shift::LSL, 1));
4966 __ Bind(&done);
4967 } else {
4968 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
4969 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004970 }
4971 break;
4972 }
4973
Roland Levillainc9285912015-12-18 10:38:42 +00004974 case Primitive::kPrimNot: {
Roland Levillain19c54192016-11-04 13:44:09 +00004975 // The read barrier instrumentation of object ArrayGet
4976 // instructions does not support the HIntermediateAddress
4977 // instruction.
4978 DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
4979
Roland Levillainc9285912015-12-18 10:38:42 +00004980 static_assert(
4981 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4982 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00004983 // /* HeapReference<Object> */ out =
4984 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
4985 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4986 Location temp = locations->GetTemp(0);
4987 // Note that a potential implicit null check is handled in this
4988 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
4989 codegen_->GenerateArrayLoadWithBakerReadBarrier(
4990 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
4991 } else {
4992 Register out = out_loc.AsRegister<Register>();
4993 if (index.IsConstant()) {
4994 size_t offset =
4995 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4996 __ LoadFromOffset(kLoadWord, out, obj, offset);
4997 codegen_->MaybeRecordImplicitNullCheck(instruction);
4998 // If read barriers are enabled, emit read barriers other than
4999 // Baker's using a slow path (and also unpoison the loaded
5000 // reference, if heap poisoning is enabled).
5001 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
5002 } else {
Artem Serov328429f2016-07-06 16:23:04 +01005003 Register temp = IP;
5004
5005 if (has_intermediate_address) {
5006 // We do not need to compute the intermediate address from the array: the
5007 // input instruction has done it already. See the comment in
5008 // `TryExtractArrayAccessAddress()`.
5009 if (kIsDebugBuild) {
5010 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5011 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
5012 }
5013 temp = obj;
5014 } else {
5015 __ add(temp, obj, ShifterOperand(data_offset));
5016 }
5017 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
Artem Serov6c916792016-07-11 14:02:34 +01005018
Roland Levillainc9285912015-12-18 10:38:42 +00005019 codegen_->MaybeRecordImplicitNullCheck(instruction);
5020 // If read barriers are enabled, emit read barriers other than
5021 // Baker's using a slow path (and also unpoison the loaded
5022 // reference, if heap poisoning is enabled).
5023 codegen_->MaybeGenerateReadBarrierSlow(
5024 instruction, out_loc, out_loc, obj_loc, data_offset, index);
5025 }
5026 }
5027 break;
5028 }
5029
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005030 case Primitive::kPrimLong: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005031 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005032 size_t offset =
5033 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00005034 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005035 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005036 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00005037 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005038 }
5039 break;
5040 }
5041
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005042 case Primitive::kPrimFloat: {
Roland Levillainc9285912015-12-18 10:38:42 +00005043 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005044 if (index.IsConstant()) {
5045 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00005046 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005047 } else {
5048 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00005049 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005050 }
5051 break;
5052 }
5053
5054 case Primitive::kPrimDouble: {
Roland Levillainc9285912015-12-18 10:38:42 +00005055 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005056 if (index.IsConstant()) {
5057 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00005058 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005059 } else {
5060 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00005061 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005062 }
5063 break;
5064 }
5065
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005066 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01005067 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005068 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005069 }
Roland Levillain4d027112015-07-01 15:41:14 +01005070
5071 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00005072 // Potential implicit null checks, in the case of reference
5073 // arrays, are handled in the previous switch statement.
jessicahandojo05765752016-09-09 19:01:32 -07005074 } else if (!maybe_compressed_char_at) {
Roland Levillainc9285912015-12-18 10:38:42 +00005075 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01005076 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005077}
5078
5079void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005080 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005081
5082 bool needs_write_barrier =
5083 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00005084 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005085
Nicolas Geoffray39468442014-09-02 15:17:15 +01005086 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005087 instruction,
Vladimir Marko8d49fd72016-08-25 15:20:47 +01005088 may_need_runtime_call_for_type_check ?
Roland Levillain3b359c72015-11-17 19:35:12 +00005089 LocationSummary::kCallOnSlowPath :
5090 LocationSummary::kNoCall);
5091
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005092 locations->SetInAt(0, Location::RequiresRegister());
5093 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
5094 if (Primitive::IsFloatingPointType(value_type)) {
5095 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005096 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005097 locations->SetInAt(2, Location::RequiresRegister());
5098 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005099 if (needs_write_barrier) {
5100 // Temporary registers for the write barrier.
5101 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00005102 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005103 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005104}
5105
5106void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
5107 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005108 Location array_loc = locations->InAt(0);
5109 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005110 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01005111 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00005112 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005113 bool needs_write_barrier =
5114 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Artem Serov6c916792016-07-11 14:02:34 +01005115 uint32_t data_offset =
5116 mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
5117 Location value_loc = locations->InAt(2);
Artem Serov328429f2016-07-06 16:23:04 +01005118 HInstruction* array_instr = instruction->GetArray();
5119 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005120
5121 switch (value_type) {
5122 case Primitive::kPrimBoolean:
Artem Serov6c916792016-07-11 14:02:34 +01005123 case Primitive::kPrimByte:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005124 case Primitive::kPrimShort:
Artem Serov6c916792016-07-11 14:02:34 +01005125 case Primitive::kPrimChar:
5126 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005127 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01005128 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
5129 uint32_t full_offset =
5130 data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
5131 StoreOperandType store_type = GetStoreOperandType(value_type);
5132 __ StoreToOffset(store_type, value_loc.AsRegister<Register>(), array, full_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005133 } else {
Artem Serov328429f2016-07-06 16:23:04 +01005134 Register temp = IP;
5135
5136 if (has_intermediate_address) {
5137 // We do not need to compute the intermediate address from the array: the
5138 // input instruction has done it already. See the comment in
5139 // `TryExtractArrayAccessAddress()`.
5140 if (kIsDebugBuild) {
5141 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5142 DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
5143 }
5144 temp = array;
5145 } else {
5146 __ add(temp, array, ShifterOperand(data_offset));
5147 }
Artem Serov6c916792016-07-11 14:02:34 +01005148 codegen_->StoreToShiftedRegOffset(value_type,
5149 value_loc,
Artem Serov328429f2016-07-06 16:23:04 +01005150 temp,
Artem Serov6c916792016-07-11 14:02:34 +01005151 index.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005152 }
5153 break;
5154 }
5155
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005156 case Primitive::kPrimNot: {
Roland Levillain3b359c72015-11-17 19:35:12 +00005157 Register value = value_loc.AsRegister<Register>();
Artem Serov328429f2016-07-06 16:23:04 +01005158 // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
5159 // See the comment in instruction_simplifier_shared.cc.
5160 DCHECK(!has_intermediate_address);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005161
5162 if (instruction->InputAt(2)->IsNullConstant()) {
5163 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005164 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005165 size_t offset =
5166 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Artem Serov6c916792016-07-11 14:02:34 +01005167 __ StoreToOffset(kStoreWord, value, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005168 } else {
5169 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01005170 __ add(IP, array, ShifterOperand(data_offset));
5171 codegen_->StoreToShiftedRegOffset(value_type,
5172 value_loc,
5173 IP,
5174 index.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005175 }
Roland Levillain1407ee72016-01-08 15:56:19 +00005176 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00005177 DCHECK(!needs_write_barrier);
5178 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005179 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005180 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005181
5182 DCHECK(needs_write_barrier);
Roland Levillain16d9f942016-08-25 17:27:56 +01005183 Location temp1_loc = locations->GetTemp(0);
5184 Register temp1 = temp1_loc.AsRegister<Register>();
5185 Location temp2_loc = locations->GetTemp(1);
5186 Register temp2 = temp2_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005187 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5188 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5189 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5190 Label done;
Artem Serovf4d6aee2016-07-11 10:41:45 +01005191 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005192
Roland Levillain3b359c72015-11-17 19:35:12 +00005193 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005194 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
5195 codegen_->AddSlowPath(slow_path);
5196 if (instruction->GetValueCanBeNull()) {
5197 Label non_zero;
5198 __ CompareAndBranchIfNonZero(value, &non_zero);
5199 if (index.IsConstant()) {
5200 size_t offset =
5201 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5202 __ StoreToOffset(kStoreWord, value, array, offset);
5203 } else {
5204 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01005205 __ add(IP, array, ShifterOperand(data_offset));
5206 codegen_->StoreToShiftedRegOffset(value_type,
5207 value_loc,
5208 IP,
5209 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005210 }
5211 codegen_->MaybeRecordImplicitNullCheck(instruction);
5212 __ b(&done);
5213 __ Bind(&non_zero);
5214 }
5215
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005216 // Note that when read barriers are enabled, the type checks
5217 // are performed without read barriers. This is fine, even in
5218 // the case where a class object is in the from-space after
5219 // the flip, as a comparison involving such a type would not
5220 // produce a false positive; it may of course produce a false
5221 // negative, in which case we would take the ArraySet slow
5222 // path.
Roland Levillain16d9f942016-08-25 17:27:56 +01005223
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005224 // /* HeapReference<Class> */ temp1 = array->klass_
5225 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
5226 codegen_->MaybeRecordImplicitNullCheck(instruction);
5227 __ MaybeUnpoisonHeapReference(temp1);
Roland Levillain16d9f942016-08-25 17:27:56 +01005228
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005229 // /* HeapReference<Class> */ temp1 = temp1->component_type_
5230 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
5231 // /* HeapReference<Class> */ temp2 = value->klass_
5232 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
5233 // If heap poisoning is enabled, no need to unpoison `temp1`
5234 // nor `temp2`, as we are comparing two poisoned references.
5235 __ cmp(temp1, ShifterOperand(temp2));
Roland Levillain16d9f942016-08-25 17:27:56 +01005236
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005237 if (instruction->StaticTypeOfArrayIsObjectArray()) {
5238 Label do_put;
5239 __ b(&do_put, EQ);
5240 // If heap poisoning is enabled, the `temp1` reference has
5241 // not been unpoisoned yet; unpoison it now.
Roland Levillain3b359c72015-11-17 19:35:12 +00005242 __ MaybeUnpoisonHeapReference(temp1);
5243
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005244 // /* HeapReference<Class> */ temp1 = temp1->super_class_
5245 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
5246 // If heap poisoning is enabled, no need to unpoison
5247 // `temp1`, as we are comparing against null below.
5248 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
5249 __ Bind(&do_put);
5250 } else {
5251 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005252 }
5253 }
5254
Artem Serov6c916792016-07-11 14:02:34 +01005255 Register source = value;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005256 if (kPoisonHeapReferences) {
5257 // Note that in the case where `value` is a null reference,
5258 // we do not enter this block, as a null reference does not
5259 // need poisoning.
5260 DCHECK_EQ(value_type, Primitive::kPrimNot);
5261 __ Mov(temp1, value);
5262 __ PoisonHeapReference(temp1);
5263 source = temp1;
5264 }
5265
5266 if (index.IsConstant()) {
5267 size_t offset =
5268 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5269 __ StoreToOffset(kStoreWord, source, array, offset);
5270 } else {
5271 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01005272
5273 __ add(IP, array, ShifterOperand(data_offset));
5274 codegen_->StoreToShiftedRegOffset(value_type,
5275 Location::RegisterLocation(source),
5276 IP,
5277 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005278 }
5279
Roland Levillain3b359c72015-11-17 19:35:12 +00005280 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005281 codegen_->MaybeRecordImplicitNullCheck(instruction);
5282 }
5283
5284 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
5285
5286 if (done.IsLinked()) {
5287 __ Bind(&done);
5288 }
5289
5290 if (slow_path != nullptr) {
5291 __ Bind(slow_path->GetExitLabel());
5292 }
5293
5294 break;
5295 }
5296
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005297 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005298 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005299 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005300 size_t offset =
5301 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005302 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005303 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005304 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005305 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005306 }
5307 break;
5308 }
5309
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005310 case Primitive::kPrimFloat: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005311 Location value = locations->InAt(2);
5312 DCHECK(value.IsFpuRegister());
5313 if (index.IsConstant()) {
5314 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005315 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005316 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005317 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005318 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
5319 }
5320 break;
5321 }
5322
5323 case Primitive::kPrimDouble: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005324 Location value = locations->InAt(2);
5325 DCHECK(value.IsFpuRegisterPair());
5326 if (index.IsConstant()) {
5327 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005328 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005329 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005330 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005331 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
5332 }
Calin Juravle77520bc2015-01-12 18:45:46 +00005333
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005334 break;
5335 }
5336
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005337 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005338 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005339 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005340 }
Calin Juravle77520bc2015-01-12 18:45:46 +00005341
Roland Levillain80e67092016-01-08 16:04:55 +00005342 // Objects are handled in the switch.
5343 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00005344 codegen_->MaybeRecordImplicitNullCheck(instruction);
5345 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005346}
5347
5348void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005349 LocationSummary* locations =
5350 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005351 locations->SetInAt(0, Location::RequiresRegister());
5352 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005353}
5354
5355void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
5356 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01005357 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00005358 Register obj = locations->InAt(0).AsRegister<Register>();
5359 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005360 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005361 codegen_->MaybeRecordImplicitNullCheck(instruction);
jessicahandojo05765752016-09-09 19:01:32 -07005362 // Mask out compression flag from String's array length.
5363 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005364 __ Lsr(out, out, 1u);
jessicahandojo05765752016-09-09 19:01:32 -07005365 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005366}
5367
Artem Serov328429f2016-07-06 16:23:04 +01005368void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
Artem Serov328429f2016-07-06 16:23:04 +01005369 LocationSummary* locations =
5370 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5371
5372 locations->SetInAt(0, Location::RequiresRegister());
5373 locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
5374 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5375}
5376
5377void InstructionCodeGeneratorARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
5378 LocationSummary* locations = instruction->GetLocations();
5379 Location out = locations->Out();
5380 Location first = locations->InAt(0);
5381 Location second = locations->InAt(1);
5382
Artem Serov328429f2016-07-06 16:23:04 +01005383 if (second.IsRegister()) {
5384 __ add(out.AsRegister<Register>(),
5385 first.AsRegister<Register>(),
5386 ShifterOperand(second.AsRegister<Register>()));
5387 } else {
5388 __ AddConstant(out.AsRegister<Register>(),
5389 first.AsRegister<Register>(),
5390 second.GetConstant()->AsIntConstant()->GetValue());
5391 }
5392}
5393
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005394void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005395 RegisterSet caller_saves = RegisterSet::Empty();
5396 InvokeRuntimeCallingConvention calling_convention;
5397 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5398 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5399 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005400 locations->SetInAt(0, Location::RequiresRegister());
5401 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005402}
5403
5404void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
5405 LocationSummary* locations = instruction->GetLocations();
Artem Serovf4d6aee2016-07-11 10:41:45 +01005406 SlowPathCodeARM* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01005407 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005408 codegen_->AddSlowPath(slow_path);
5409
Roland Levillain271ab9c2014-11-27 15:23:57 +00005410 Register index = locations->InAt(0).AsRegister<Register>();
5411 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005412
5413 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01005414 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005415}
5416
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005417void CodeGeneratorARM::MarkGCCard(Register temp,
5418 Register card,
5419 Register object,
5420 Register value,
5421 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005422 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005423 if (can_be_null) {
5424 __ CompareAndBranchIfZero(value, &is_null);
5425 }
Andreas Gampe542451c2016-07-26 09:02:02 -07005426 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005427 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
5428 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005429 if (can_be_null) {
5430 __ Bind(&is_null);
5431 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005432}
5433
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005434void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005435 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005436}
5437
5438void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005439 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
5440}
5441
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005442void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Marko70e97462016-08-09 11:04:26 +01005443 LocationSummary* locations =
5444 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01005445 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005446}
5447
5448void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005449 HBasicBlock* block = instruction->GetBlock();
5450 if (block->GetLoopInformation() != nullptr) {
5451 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
5452 // The back edge will generate the suspend check.
5453 return;
5454 }
5455 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
5456 // The goto will generate the suspend check.
5457 return;
5458 }
5459 GenerateSuspendCheck(instruction, nullptr);
5460}
5461
5462void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
5463 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005464 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01005465 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
5466 if (slow_path == nullptr) {
5467 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
5468 instruction->SetSlowPath(slow_path);
5469 codegen_->AddSlowPath(slow_path);
5470 if (successor != nullptr) {
5471 DCHECK(successor->IsLoopHeader());
5472 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
5473 }
5474 } else {
5475 DCHECK_EQ(slow_path->GetSuccessor(), successor);
5476 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005477
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00005478 __ LoadFromOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07005479 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005480 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005481 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005482 __ Bind(slow_path->GetReturnLabel());
5483 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005484 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005485 __ b(slow_path->GetEntryLabel());
5486 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005487}
5488
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005489ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
5490 return codegen_->GetAssembler();
5491}
5492
5493void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005494 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005495 Location source = move->GetSource();
5496 Location destination = move->GetDestination();
5497
5498 if (source.IsRegister()) {
5499 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005500 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00005501 } else if (destination.IsFpuRegister()) {
5502 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005503 } else {
5504 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005505 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005506 SP, destination.GetStackIndex());
5507 }
5508 } else if (source.IsStackSlot()) {
5509 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005510 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005511 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005512 } else if (destination.IsFpuRegister()) {
5513 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005514 } else {
5515 DCHECK(destination.IsStackSlot());
5516 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
5517 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5518 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005519 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00005520 if (destination.IsRegister()) {
5521 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
5522 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005523 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005524 } else {
5525 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005526 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
5527 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005528 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005529 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005530 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
5531 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005532 } else if (destination.IsRegisterPair()) {
5533 DCHECK(ExpectedPairLayout(destination));
5534 __ LoadFromOffset(
5535 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
5536 } else {
5537 DCHECK(destination.IsFpuRegisterPair()) << destination;
5538 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5539 SP,
5540 source.GetStackIndex());
5541 }
5542 } else if (source.IsRegisterPair()) {
5543 if (destination.IsRegisterPair()) {
5544 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
5545 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00005546 } else if (destination.IsFpuRegisterPair()) {
5547 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5548 source.AsRegisterPairLow<Register>(),
5549 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005550 } else {
5551 DCHECK(destination.IsDoubleStackSlot()) << destination;
5552 DCHECK(ExpectedPairLayout(source));
5553 __ StoreToOffset(
5554 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
5555 }
5556 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00005557 if (destination.IsRegisterPair()) {
5558 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5559 destination.AsRegisterPairHigh<Register>(),
5560 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
5561 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005562 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5563 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
5564 } else {
5565 DCHECK(destination.IsDoubleStackSlot()) << destination;
5566 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
5567 SP,
5568 destination.GetStackIndex());
5569 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005570 } else {
5571 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00005572 HConstant* constant = source.GetConstant();
5573 if (constant->IsIntConstant() || constant->IsNullConstant()) {
5574 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005575 if (destination.IsRegister()) {
5576 __ LoadImmediate(destination.AsRegister<Register>(), value);
5577 } else {
5578 DCHECK(destination.IsStackSlot());
5579 __ LoadImmediate(IP, value);
5580 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5581 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005582 } else if (constant->IsLongConstant()) {
5583 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005584 if (destination.IsRegisterPair()) {
5585 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
5586 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005587 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005588 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005589 __ LoadImmediate(IP, Low32Bits(value));
5590 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5591 __ LoadImmediate(IP, High32Bits(value));
5592 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5593 }
5594 } else if (constant->IsDoubleConstant()) {
5595 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005596 if (destination.IsFpuRegisterPair()) {
5597 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005598 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005599 DCHECK(destination.IsDoubleStackSlot()) << destination;
5600 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005601 __ LoadImmediate(IP, Low32Bits(int_value));
5602 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5603 __ LoadImmediate(IP, High32Bits(int_value));
5604 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5605 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005606 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005607 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005608 float value = constant->AsFloatConstant()->GetValue();
5609 if (destination.IsFpuRegister()) {
5610 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
5611 } else {
5612 DCHECK(destination.IsStackSlot());
5613 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
5614 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5615 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005616 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005617 }
5618}
5619
5620void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
5621 __ Mov(IP, reg);
5622 __ LoadFromOffset(kLoadWord, reg, SP, mem);
5623 __ StoreToOffset(kStoreWord, IP, SP, mem);
5624}
5625
5626void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
5627 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5628 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5629 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5630 SP, mem1 + stack_offset);
5631 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5632 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5633 SP, mem2 + stack_offset);
5634 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5635}
5636
5637void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005638 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005639 Location source = move->GetSource();
5640 Location destination = move->GetDestination();
5641
5642 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005643 DCHECK_NE(source.AsRegister<Register>(), IP);
5644 DCHECK_NE(destination.AsRegister<Register>(), IP);
5645 __ Mov(IP, source.AsRegister<Register>());
5646 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5647 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005648 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005649 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005650 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005651 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005652 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5653 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005654 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005655 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005656 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005657 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005658 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005659 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005660 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005661 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005662 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5663 destination.AsRegisterPairHigh<Register>(),
5664 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005665 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005666 Register low_reg = source.IsRegisterPair()
5667 ? source.AsRegisterPairLow<Register>()
5668 : destination.AsRegisterPairLow<Register>();
5669 int mem = source.IsRegisterPair()
5670 ? destination.GetStackIndex()
5671 : source.GetStackIndex();
5672 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005673 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005674 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005675 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005676 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005677 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5678 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005679 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005680 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005681 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005682 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5683 DRegister reg = source.IsFpuRegisterPair()
5684 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5685 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5686 int mem = source.IsFpuRegisterPair()
5687 ? destination.GetStackIndex()
5688 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005689 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005690 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005691 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005692 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5693 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5694 : destination.AsFpuRegister<SRegister>();
5695 int mem = source.IsFpuRegister()
5696 ? destination.GetStackIndex()
5697 : source.GetStackIndex();
5698
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005699 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005700 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005701 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005702 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005703 Exchange(source.GetStackIndex(), destination.GetStackIndex());
5704 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005705 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005706 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005707 }
5708}
5709
5710void ParallelMoveResolverARM::SpillScratch(int reg) {
5711 __ Push(static_cast<Register>(reg));
5712}
5713
5714void ParallelMoveResolverARM::RestoreScratch(int reg) {
5715 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005716}
5717
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005718HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
5719 HLoadClass::LoadKind desired_class_load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005720 switch (desired_class_load_kind) {
5721 case HLoadClass::LoadKind::kReferrersClass:
5722 break;
5723 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5724 DCHECK(!GetCompilerOptions().GetCompilePic());
5725 break;
5726 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5727 DCHECK(GetCompilerOptions().GetCompilePic());
5728 break;
5729 case HLoadClass::LoadKind::kBootImageAddress:
5730 break;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005731 case HLoadClass::LoadKind::kBssEntry:
5732 DCHECK(!Runtime::Current()->UseJitCompilation());
5733 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005734 case HLoadClass::LoadKind::kJitTableAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005735 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005736 break;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005737 case HLoadClass::LoadKind::kDexCacheViaMethod:
5738 break;
5739 }
5740 return desired_class_load_kind;
5741}
5742
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005743void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00005744 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5745 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005746 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko41559982017-01-06 14:04:23 +00005747 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005748 cls,
5749 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko41559982017-01-06 14:04:23 +00005750 Location::RegisterLocation(R0));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005751 return;
5752 }
Vladimir Marko41559982017-01-06 14:04:23 +00005753 DCHECK(!cls->NeedsAccessCheck());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005754
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005755 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
5756 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005757 ? LocationSummary::kCallOnSlowPath
5758 : LocationSummary::kNoCall;
5759 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005760 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005761 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005762 }
5763
Vladimir Marko41559982017-01-06 14:04:23 +00005764 if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005765 locations->SetInAt(0, Location::RequiresRegister());
5766 }
5767 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005768}
5769
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005770// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5771// move.
5772void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00005773 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5774 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
5775 codegen_->GenerateLoadClassRuntimeCall(cls);
Calin Juravle580b6092015-10-06 17:35:58 +01005776 return;
5777 }
Vladimir Marko41559982017-01-06 14:04:23 +00005778 DCHECK(!cls->NeedsAccessCheck());
Calin Juravle580b6092015-10-06 17:35:58 +01005779
Vladimir Marko41559982017-01-06 14:04:23 +00005780 LocationSummary* locations = cls->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005781 Location out_loc = locations->Out();
5782 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005783
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005784 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
5785 ? kWithoutReadBarrier
5786 : kCompilerReadBarrierOption;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005787 bool generate_null_check = false;
Vladimir Marko41559982017-01-06 14:04:23 +00005788 switch (load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005789 case HLoadClass::LoadKind::kReferrersClass: {
5790 DCHECK(!cls->CanCallRuntime());
5791 DCHECK(!cls->MustGenerateClinitCheck());
5792 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5793 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005794 GenerateGcRootFieldLoad(cls,
5795 out_loc,
5796 current_method,
5797 ArtMethod::DeclaringClassOffset().Int32Value(),
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005798 read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005799 break;
5800 }
5801 case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005802 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005803 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005804 __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
5805 cls->GetTypeIndex()));
5806 break;
5807 }
5808 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005809 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005810 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005811 CodeGeneratorARM::PcRelativePatchInfo* labels =
5812 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
5813 __ BindTrackedLabel(&labels->movw_label);
5814 __ movw(out, /* placeholder */ 0u);
5815 __ BindTrackedLabel(&labels->movt_label);
5816 __ movt(out, /* placeholder */ 0u);
5817 __ BindTrackedLabel(&labels->add_pc_label);
5818 __ add(out, out, ShifterOperand(PC));
5819 break;
5820 }
5821 case HLoadClass::LoadKind::kBootImageAddress: {
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005822 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005823 uint32_t address = dchecked_integral_cast<uint32_t>(
5824 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
5825 DCHECK_NE(address, 0u);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005826 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5827 break;
5828 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005829 case HLoadClass::LoadKind::kBssEntry: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005830 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko1998cd02017-01-13 13:02:58 +00005831 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005832 __ BindTrackedLabel(&labels->movw_label);
5833 __ movw(out, /* placeholder */ 0u);
5834 __ BindTrackedLabel(&labels->movt_label);
5835 __ movt(out, /* placeholder */ 0u);
5836 __ BindTrackedLabel(&labels->add_pc_label);
5837 __ add(out, out, ShifterOperand(PC));
5838 GenerateGcRootFieldLoad(cls, out_loc, out, 0, kCompilerReadBarrierOption);
5839 generate_null_check = true;
5840 break;
5841 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005842 case HLoadClass::LoadKind::kJitTableAddress: {
5843 __ LoadLiteral(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
5844 cls->GetTypeIndex(),
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005845 cls->GetClass()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005846 // /* GcRoot<mirror::Class> */ out = *out
5847 GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005848 break;
5849 }
Vladimir Marko41559982017-01-06 14:04:23 +00005850 case HLoadClass::LoadKind::kDexCacheViaMethod:
5851 LOG(FATAL) << "UNREACHABLE";
5852 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005853 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005854
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005855 if (generate_null_check || cls->MustGenerateClinitCheck()) {
5856 DCHECK(cls->CanCallRuntime());
Artem Serovf4d6aee2016-07-11 10:41:45 +01005857 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005858 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5859 codegen_->AddSlowPath(slow_path);
5860 if (generate_null_check) {
5861 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5862 }
5863 if (cls->MustGenerateClinitCheck()) {
5864 GenerateClassInitializationCheck(slow_path, out);
5865 } else {
5866 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005867 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005868 }
5869}
5870
5871void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5872 LocationSummary* locations =
5873 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5874 locations->SetInAt(0, Location::RequiresRegister());
5875 if (check->HasUses()) {
5876 locations->SetOut(Location::SameAsFirstInput());
5877 }
5878}
5879
5880void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005881 // We assume the class is not null.
Artem Serovf4d6aee2016-07-11 10:41:45 +01005882 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005883 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005884 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005885 GenerateClassInitializationCheck(slow_path,
5886 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005887}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005888
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005889void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Artem Serovf4d6aee2016-07-11 10:41:45 +01005890 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005891 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5892 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5893 __ b(slow_path->GetEntryLabel(), LT);
5894 // Even if the initialized flag is set, we may be in a situation where caches are not synced
5895 // properly. Therefore, we do a memory fence.
5896 __ dmb(ISH);
5897 __ Bind(slow_path->GetExitLabel());
5898}
5899
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005900HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
5901 HLoadString::LoadKind desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005902 switch (desired_string_load_kind) {
5903 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5904 DCHECK(!GetCompilerOptions().GetCompilePic());
5905 break;
5906 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5907 DCHECK(GetCompilerOptions().GetCompilePic());
5908 break;
5909 case HLoadString::LoadKind::kBootImageAddress:
5910 break;
Vladimir Markoaad75c62016-10-03 08:46:48 +00005911 case HLoadString::LoadKind::kBssEntry:
Calin Juravleffc87072016-04-20 14:22:09 +01005912 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005913 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005914 case HLoadString::LoadKind::kJitTableAddress:
5915 DCHECK(Runtime::Current()->UseJitCompilation());
5916 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005917 case HLoadString::LoadKind::kDexCacheViaMethod:
5918 break;
5919 }
5920 return desired_string_load_kind;
5921}
5922
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005923void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005924 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005925 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005926 HLoadString::LoadKind load_kind = load->GetLoadKind();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07005927 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07005928 locations->SetOut(Location::RegisterLocation(R0));
5929 } else {
5930 locations->SetOut(Location::RequiresRegister());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005931 if (load_kind == HLoadString::LoadKind::kBssEntry) {
5932 if (!kUseReadBarrier || kUseBakerReadBarrier) {
5933 // Rely on the pResolveString and/or marking to save everything, including temps.
5934 // Note that IP may theoretically be clobbered by saving/restoring the live register
5935 // (only one thanks to the custom calling convention), so we request a different temp.
5936 locations->AddTemp(Location::RequiresRegister());
5937 RegisterSet caller_saves = RegisterSet::Empty();
5938 InvokeRuntimeCallingConvention calling_convention;
5939 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5940 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
5941 // that the the kPrimNot result register is the same as the first argument register.
5942 locations->SetCustomSlowPathCallerSaves(caller_saves);
5943 } else {
5944 // For non-Baker read barrier we have a temp-clobbering call.
5945 }
5946 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005947 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005948}
5949
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005950// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5951// move.
5952void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005953 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005954 Location out_loc = locations->Out();
5955 Register out = out_loc.AsRegister<Register>();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07005956 HLoadString::LoadKind load_kind = load->GetLoadKind();
Roland Levillain3b359c72015-11-17 19:35:12 +00005957
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07005958 switch (load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005959 case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005960 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005961 __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5962 load->GetStringIndex()));
5963 return; // No dex cache slow path.
5964 }
5965 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00005966 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005967 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005968 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005969 __ BindTrackedLabel(&labels->movw_label);
5970 __ movw(out, /* placeholder */ 0u);
5971 __ BindTrackedLabel(&labels->movt_label);
5972 __ movt(out, /* placeholder */ 0u);
5973 __ BindTrackedLabel(&labels->add_pc_label);
5974 __ add(out, out, ShifterOperand(PC));
5975 return; // No dex cache slow path.
5976 }
5977 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005978 uint32_t address = dchecked_integral_cast<uint32_t>(
5979 reinterpret_cast<uintptr_t>(load->GetString().Get()));
5980 DCHECK_NE(address, 0u);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005981 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5982 return; // No dex cache slow path.
5983 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00005984 case HLoadString::LoadKind::kBssEntry: {
5985 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005986 Register temp = locations->GetTemp(0).AsRegister<Register>();
Vladimir Markoaad75c62016-10-03 08:46:48 +00005987 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005988 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markoaad75c62016-10-03 08:46:48 +00005989 __ BindTrackedLabel(&labels->movw_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005990 __ movw(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005991 __ BindTrackedLabel(&labels->movt_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005992 __ movt(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005993 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005994 __ add(temp, temp, ShifterOperand(PC));
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005995 GenerateGcRootFieldLoad(load, out_loc, temp, /* offset */ 0, kCompilerReadBarrierOption);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005996 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5997 codegen_->AddSlowPath(slow_path);
5998 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5999 __ Bind(slow_path->GetExitLabel());
6000 return;
6001 }
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006002 case HLoadString::LoadKind::kJitTableAddress: {
6003 __ LoadLiteral(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00006004 load->GetStringIndex(),
6005 load->GetString()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006006 // /* GcRoot<mirror::String> */ out = *out
6007 GenerateGcRootFieldLoad(load, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
6008 return;
6009 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006010 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07006011 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006012 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006013
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006014 // TODO: Consider re-adding the compiler code to do string dex cache lookup again.
6015 DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
6016 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006017 DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
Andreas Gampe8a0128a2016-11-28 07:38:35 -08006018 __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006019 codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
6020 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00006021}
6022
David Brazdilcb1c0552015-08-04 16:22:25 +01006023static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07006024 return Thread::ExceptionOffset<kArmPointerSize>().Int32Value();
David Brazdilcb1c0552015-08-04 16:22:25 +01006025}
6026
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006027void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
6028 LocationSummary* locations =
6029 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
6030 locations->SetOut(Location::RequiresRegister());
6031}
6032
6033void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006034 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01006035 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
6036}
6037
6038void LocationsBuilderARM::VisitClearException(HClearException* clear) {
6039 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
6040}
6041
6042void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006043 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01006044 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006045}
6046
6047void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
6048 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006049 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006050 InvokeRuntimeCallingConvention calling_convention;
6051 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6052}
6053
6054void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01006055 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00006056 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006057}
6058
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006059// Temp is used for read barrier.
6060static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
6061 if (kEmitCompilerReadBarrier &&
6062 (kUseBakerReadBarrier ||
6063 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
6064 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
6065 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
6066 return 1;
6067 }
6068 return 0;
6069}
6070
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006071// Interface case has 3 temps, one for holding the number of interfaces, one for the current
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006072// interface pointer, one for loading the current interface.
6073// The other checks have one temp for loading the object's class.
6074static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
6075 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
6076 return 3;
6077 }
6078 return 1 + NumberOfInstanceOfTemps(type_check_kind);
Roland Levillainc9285912015-12-18 10:38:42 +00006079}
6080
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006081void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006082 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00006083 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko70e97462016-08-09 11:04:26 +01006084 bool baker_read_barrier_slow_path = false;
Roland Levillain3b359c72015-11-17 19:35:12 +00006085 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006086 case TypeCheckKind::kExactCheck:
6087 case TypeCheckKind::kAbstractClassCheck:
6088 case TypeCheckKind::kClassHierarchyCheck:
6089 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00006090 call_kind =
6091 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Vladimir Marko70e97462016-08-09 11:04:26 +01006092 baker_read_barrier_slow_path = kUseBakerReadBarrier;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006093 break;
6094 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00006095 case TypeCheckKind::kUnresolvedCheck:
6096 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006097 call_kind = LocationSummary::kCallOnSlowPath;
6098 break;
6099 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006100
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006101 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Vladimir Marko70e97462016-08-09 11:04:26 +01006102 if (baker_read_barrier_slow_path) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006103 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01006104 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006105 locations->SetInAt(0, Location::RequiresRegister());
6106 locations->SetInAt(1, Location::RequiresRegister());
6107 // The "out" register is used as a temporary, so it overlaps with the inputs.
6108 // Note that TypeCheckSlowPathARM uses this register too.
6109 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006110 locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006111}
6112
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006113void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00006114 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006115 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006116 Location obj_loc = locations->InAt(0);
6117 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00006118 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00006119 Location out_loc = locations->Out();
6120 Register out = out_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006121 const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
6122 DCHECK_LE(num_temps, 1u);
6123 Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006124 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006125 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6126 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6127 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00006128 Label done, zero;
Artem Serovf4d6aee2016-07-11 10:41:45 +01006129 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006130
6131 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006132 // avoid null check if we know obj is not null.
6133 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00006134 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006135 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006136
Roland Levillainc9285912015-12-18 10:38:42 +00006137 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006138 case TypeCheckKind::kExactCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006139 // /* HeapReference<Class> */ out = obj->klass_
6140 GenerateReferenceLoadTwoRegisters(instruction,
6141 out_loc,
6142 obj_loc,
6143 class_offset,
6144 maybe_temp_loc,
6145 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006146 __ cmp(out, ShifterOperand(cls));
6147 // Classes must be equal for the instanceof to succeed.
6148 __ b(&zero, NE);
6149 __ LoadImmediate(out, 1);
6150 __ b(&done);
6151 break;
6152 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006153
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006154 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006155 // /* HeapReference<Class> */ out = obj->klass_
6156 GenerateReferenceLoadTwoRegisters(instruction,
6157 out_loc,
6158 obj_loc,
6159 class_offset,
6160 maybe_temp_loc,
6161 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006162 // If the class is abstract, we eagerly fetch the super class of the
6163 // object to avoid doing a comparison we know will fail.
6164 Label loop;
6165 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00006166 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006167 GenerateReferenceLoadOneRegister(instruction,
6168 out_loc,
6169 super_offset,
6170 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006171 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006172 // If `out` is null, we use it for the result, and jump to `done`.
6173 __ CompareAndBranchIfZero(out, &done);
6174 __ cmp(out, ShifterOperand(cls));
6175 __ b(&loop, NE);
6176 __ LoadImmediate(out, 1);
6177 if (zero.IsLinked()) {
6178 __ b(&done);
6179 }
6180 break;
6181 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006182
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006183 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006184 // /* HeapReference<Class> */ out = obj->klass_
6185 GenerateReferenceLoadTwoRegisters(instruction,
6186 out_loc,
6187 obj_loc,
6188 class_offset,
6189 maybe_temp_loc,
6190 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006191 // Walk over the class hierarchy to find a match.
6192 Label loop, success;
6193 __ Bind(&loop);
6194 __ cmp(out, ShifterOperand(cls));
6195 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00006196 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006197 GenerateReferenceLoadOneRegister(instruction,
6198 out_loc,
6199 super_offset,
6200 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006201 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006202 __ CompareAndBranchIfNonZero(out, &loop);
6203 // If `out` is null, we use it for the result, and jump to `done`.
6204 __ b(&done);
6205 __ Bind(&success);
6206 __ LoadImmediate(out, 1);
6207 if (zero.IsLinked()) {
6208 __ b(&done);
6209 }
6210 break;
6211 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006212
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006213 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006214 // /* HeapReference<Class> */ out = obj->klass_
6215 GenerateReferenceLoadTwoRegisters(instruction,
6216 out_loc,
6217 obj_loc,
6218 class_offset,
6219 maybe_temp_loc,
6220 kCompilerReadBarrierOption);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006221 // Do an exact check.
6222 Label exact_check;
6223 __ cmp(out, ShifterOperand(cls));
6224 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00006225 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00006226 // /* HeapReference<Class> */ out = out->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006227 GenerateReferenceLoadOneRegister(instruction,
6228 out_loc,
6229 component_offset,
6230 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006231 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006232 // If `out` is null, we use it for the result, and jump to `done`.
6233 __ CompareAndBranchIfZero(out, &done);
6234 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
6235 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
6236 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006237 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006238 __ LoadImmediate(out, 1);
6239 __ b(&done);
6240 break;
6241 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006242
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006243 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006244 // No read barrier since the slow path will retry upon failure.
6245 // /* HeapReference<Class> */ out = obj->klass_
6246 GenerateReferenceLoadTwoRegisters(instruction,
6247 out_loc,
6248 obj_loc,
6249 class_offset,
6250 maybe_temp_loc,
6251 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006252 __ cmp(out, ShifterOperand(cls));
6253 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00006254 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
6255 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006256 codegen_->AddSlowPath(slow_path);
6257 __ b(slow_path->GetEntryLabel(), NE);
6258 __ LoadImmediate(out, 1);
6259 if (zero.IsLinked()) {
6260 __ b(&done);
6261 }
6262 break;
6263 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006264
Calin Juravle98893e12015-10-02 21:05:03 +01006265 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00006266 case TypeCheckKind::kInterfaceCheck: {
6267 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006268 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00006269 // cases.
6270 //
6271 // We cannot directly call the InstanceofNonTrivial runtime
6272 // entry point without resorting to a type checking slow path
6273 // here (i.e. by calling InvokeRuntime directly), as it would
6274 // require to assign fixed registers for the inputs of this
6275 // HInstanceOf instruction (following the runtime calling
6276 // convention), which might be cluttered by the potential first
6277 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00006278 //
6279 // TODO: Introduce a new runtime entry point taking the object
6280 // to test (instead of its class) as argument, and let it deal
6281 // with the read barrier issues. This will let us refactor this
6282 // case of the `switch` code as it was previously (with a direct
6283 // call to the runtime not using a type checking slow path).
6284 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00006285 DCHECK(locations->OnlyCallsOnSlowPath());
6286 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
6287 /* is_fatal */ false);
6288 codegen_->AddSlowPath(slow_path);
6289 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006290 if (zero.IsLinked()) {
6291 __ b(&done);
6292 }
6293 break;
6294 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006295 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006296
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006297 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006298 __ Bind(&zero);
6299 __ LoadImmediate(out, 0);
6300 }
6301
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006302 if (done.IsLinked()) {
6303 __ Bind(&done);
6304 }
6305
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006306 if (slow_path != nullptr) {
6307 __ Bind(slow_path->GetExitLabel());
6308 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006309}
6310
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006311void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006312 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
6313 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
6314
Roland Levillain3b359c72015-11-17 19:35:12 +00006315 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
6316 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006317 case TypeCheckKind::kExactCheck:
6318 case TypeCheckKind::kAbstractClassCheck:
6319 case TypeCheckKind::kClassHierarchyCheck:
6320 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00006321 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
6322 LocationSummary::kCallOnSlowPath :
6323 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006324 break;
6325 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00006326 case TypeCheckKind::kUnresolvedCheck:
6327 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006328 call_kind = LocationSummary::kCallOnSlowPath;
6329 break;
6330 }
6331
Roland Levillain3b359c72015-11-17 19:35:12 +00006332 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
6333 locations->SetInAt(0, Location::RequiresRegister());
6334 locations->SetInAt(1, Location::RequiresRegister());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006335 locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006336}
6337
6338void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00006339 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006340 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006341 Location obj_loc = locations->InAt(0);
6342 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00006343 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00006344 Location temp_loc = locations->GetTemp(0);
6345 Register temp = temp_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006346 const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
6347 DCHECK_LE(num_temps, 3u);
6348 Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
6349 Location maybe_temp3_loc = (num_temps >= 3) ? locations->GetTemp(2) : Location::NoLocation();
6350 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6351 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6352 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6353 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
6354 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
6355 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
6356 const uint32_t object_array_data_offset =
6357 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006358
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006359 // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
6360 // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
6361 // read barriers is done for performance and code size reasons.
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006362 bool is_type_check_slow_path_fatal = false;
6363 if (!kEmitCompilerReadBarrier) {
6364 is_type_check_slow_path_fatal =
6365 (type_check_kind == TypeCheckKind::kExactCheck ||
6366 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
6367 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
6368 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
6369 !instruction->CanThrowIntoCatchBlock();
6370 }
Artem Serovf4d6aee2016-07-11 10:41:45 +01006371 SlowPathCodeARM* type_check_slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00006372 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
6373 is_type_check_slow_path_fatal);
6374 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006375
6376 Label done;
6377 // Avoid null check if we know obj is not null.
6378 if (instruction->MustDoNullCheck()) {
6379 __ CompareAndBranchIfZero(obj, &done);
6380 }
6381
Roland Levillain3b359c72015-11-17 19:35:12 +00006382 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006383 case TypeCheckKind::kExactCheck:
6384 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006385 // /* HeapReference<Class> */ temp = obj->klass_
6386 GenerateReferenceLoadTwoRegisters(instruction,
6387 temp_loc,
6388 obj_loc,
6389 class_offset,
6390 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006391 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006392
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006393 __ cmp(temp, ShifterOperand(cls));
6394 // Jump to slow path for throwing the exception or doing a
6395 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00006396 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006397 break;
6398 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006399
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006400 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006401 // /* HeapReference<Class> */ temp = obj->klass_
6402 GenerateReferenceLoadTwoRegisters(instruction,
6403 temp_loc,
6404 obj_loc,
6405 class_offset,
6406 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006407 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006408
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006409 // If the class is abstract, we eagerly fetch the super class of the
6410 // object to avoid doing a comparison we know will fail.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006411 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006412 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00006413 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006414 GenerateReferenceLoadOneRegister(instruction,
6415 temp_loc,
6416 super_offset,
6417 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006418 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00006419
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006420 // If the class reference currently in `temp` is null, jump to the slow path to throw the
6421 // exception.
6422 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
Roland Levillain3b359c72015-11-17 19:35:12 +00006423
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006424 // Otherwise, compare the classes.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006425 __ cmp(temp, ShifterOperand(cls));
6426 __ b(&loop, NE);
6427 break;
6428 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006429
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006430 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006431 // /* HeapReference<Class> */ temp = obj->klass_
6432 GenerateReferenceLoadTwoRegisters(instruction,
6433 temp_loc,
6434 obj_loc,
6435 class_offset,
6436 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006437 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006438
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006439 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006440 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006441 __ Bind(&loop);
6442 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006443 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00006444
Roland Levillain3b359c72015-11-17 19:35:12 +00006445 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006446 GenerateReferenceLoadOneRegister(instruction,
6447 temp_loc,
6448 super_offset,
6449 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006450 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00006451
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006452 // If the class reference currently in `temp` is null, jump to the slow path to throw the
6453 // exception.
6454 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
6455 // Otherwise, jump to the beginning of the loop.
6456 __ b(&loop);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006457 break;
6458 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006459
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006460 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006461 // /* HeapReference<Class> */ temp = obj->klass_
6462 GenerateReferenceLoadTwoRegisters(instruction,
6463 temp_loc,
6464 obj_loc,
6465 class_offset,
6466 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006467 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006468
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006469 // Do an exact check.
6470 __ cmp(temp, ShifterOperand(cls));
6471 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00006472
6473 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00006474 // /* HeapReference<Class> */ temp = temp->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006475 GenerateReferenceLoadOneRegister(instruction,
6476 temp_loc,
6477 component_offset,
6478 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006479 kWithoutReadBarrier);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006480 // If the component type is null, jump to the slow path to throw the exception.
6481 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
6482 // Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type`
6483 // to further check that this component type is not a primitive type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006484 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00006485 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006486 __ CompareAndBranchIfNonZero(temp, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006487 break;
6488 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006489
Calin Juravle98893e12015-10-02 21:05:03 +01006490 case TypeCheckKind::kUnresolvedCheck:
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006491 // We always go into the type check slow path for the unresolved check case.
Roland Levillain3b359c72015-11-17 19:35:12 +00006492 // We cannot directly call the CheckCast runtime entry point
6493 // without resorting to a type checking slow path here (i.e. by
6494 // calling InvokeRuntime directly), as it would require to
6495 // assign fixed registers for the inputs of this HInstanceOf
6496 // instruction (following the runtime calling convention), which
6497 // might be cluttered by the potential first read barrier
6498 // emission at the beginning of this method.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006499
Roland Levillain3b359c72015-11-17 19:35:12 +00006500 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006501 break;
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006502
6503 case TypeCheckKind::kInterfaceCheck: {
6504 // Avoid read barriers to improve performance of the fast path. We can not get false
6505 // positives by doing this.
6506 // /* HeapReference<Class> */ temp = obj->klass_
6507 GenerateReferenceLoadTwoRegisters(instruction,
6508 temp_loc,
6509 obj_loc,
6510 class_offset,
6511 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006512 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006513
6514 // /* HeapReference<Class> */ temp = temp->iftable_
6515 GenerateReferenceLoadTwoRegisters(instruction,
6516 temp_loc,
6517 temp_loc,
6518 iftable_offset,
6519 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006520 kWithoutReadBarrier);
Mathieu Chartier6beced42016-11-15 15:51:31 -08006521 // Iftable is never null.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006522 __ ldr(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
Mathieu Chartier6beced42016-11-15 15:51:31 -08006523 // Loop through the iftable and check if any class matches.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006524 Label start_loop;
6525 __ Bind(&start_loop);
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08006526 __ CompareAndBranchIfZero(maybe_temp2_loc.AsRegister<Register>(),
6527 type_check_slow_path->GetEntryLabel());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006528 __ ldr(maybe_temp3_loc.AsRegister<Register>(), Address(temp, object_array_data_offset));
6529 __ MaybeUnpoisonHeapReference(maybe_temp3_loc.AsRegister<Register>());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006530 // Go to next interface.
6531 __ add(temp, temp, ShifterOperand(2 * kHeapReferenceSize));
6532 __ sub(maybe_temp2_loc.AsRegister<Register>(),
6533 maybe_temp2_loc.AsRegister<Register>(),
6534 ShifterOperand(2));
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08006535 // Compare the classes and continue the loop if they do not match.
6536 __ cmp(cls, ShifterOperand(maybe_temp3_loc.AsRegister<Register>()));
6537 __ b(&start_loop, NE);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006538 break;
6539 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006540 }
6541 __ Bind(&done);
6542
Roland Levillain3b359c72015-11-17 19:35:12 +00006543 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006544}
6545
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006546void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
6547 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006548 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006549 InvokeRuntimeCallingConvention calling_convention;
6550 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6551}
6552
6553void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01006554 codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
6555 instruction,
6556 instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00006557 if (instruction->IsEnter()) {
6558 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
6559 } else {
6560 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
6561 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006562}
6563
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006564void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
6565void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
6566void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006567
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006568void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006569 LocationSummary* locations =
6570 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6571 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6572 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006573 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006574 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006575 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00006576 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006577}
6578
6579void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
6580 HandleBitwiseOperation(instruction);
6581}
6582
6583void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
6584 HandleBitwiseOperation(instruction);
6585}
6586
6587void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
6588 HandleBitwiseOperation(instruction);
6589}
6590
Artem Serov7fc63502016-02-09 17:15:29 +00006591
6592void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
6593 LocationSummary* locations =
6594 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6595 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6596 || instruction->GetResultType() == Primitive::kPrimLong);
6597
6598 locations->SetInAt(0, Location::RequiresRegister());
6599 locations->SetInAt(1, Location::RequiresRegister());
6600 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6601}
6602
6603void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
6604 LocationSummary* locations = instruction->GetLocations();
6605 Location first = locations->InAt(0);
6606 Location second = locations->InAt(1);
6607 Location out = locations->Out();
6608
6609 if (instruction->GetResultType() == Primitive::kPrimInt) {
6610 Register first_reg = first.AsRegister<Register>();
6611 ShifterOperand second_reg(second.AsRegister<Register>());
6612 Register out_reg = out.AsRegister<Register>();
6613
6614 switch (instruction->GetOpKind()) {
6615 case HInstruction::kAnd:
6616 __ bic(out_reg, first_reg, second_reg);
6617 break;
6618 case HInstruction::kOr:
6619 __ orn(out_reg, first_reg, second_reg);
6620 break;
6621 // There is no EON on arm.
6622 case HInstruction::kXor:
6623 default:
6624 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
6625 UNREACHABLE();
6626 }
6627 return;
6628
6629 } else {
6630 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6631 Register first_low = first.AsRegisterPairLow<Register>();
6632 Register first_high = first.AsRegisterPairHigh<Register>();
6633 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6634 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6635 Register out_low = out.AsRegisterPairLow<Register>();
6636 Register out_high = out.AsRegisterPairHigh<Register>();
6637
6638 switch (instruction->GetOpKind()) {
6639 case HInstruction::kAnd:
6640 __ bic(out_low, first_low, second_low);
6641 __ bic(out_high, first_high, second_high);
6642 break;
6643 case HInstruction::kOr:
6644 __ orn(out_low, first_low, second_low);
6645 __ orn(out_high, first_high, second_high);
6646 break;
6647 // There is no EON on arm.
6648 case HInstruction::kXor:
6649 default:
6650 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
6651 UNREACHABLE();
6652 }
6653 }
6654}
6655
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006656void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
6657 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
6658 if (value == 0xffffffffu) {
6659 if (out != first) {
6660 __ mov(out, ShifterOperand(first));
6661 }
6662 return;
6663 }
6664 if (value == 0u) {
6665 __ mov(out, ShifterOperand(0));
6666 return;
6667 }
6668 ShifterOperand so;
6669 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
6670 __ and_(out, first, so);
6671 } else {
6672 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
6673 __ bic(out, first, ShifterOperand(~value));
6674 }
6675}
6676
6677void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
6678 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
6679 if (value == 0u) {
6680 if (out != first) {
6681 __ mov(out, ShifterOperand(first));
6682 }
6683 return;
6684 }
6685 if (value == 0xffffffffu) {
6686 __ mvn(out, ShifterOperand(0));
6687 return;
6688 }
6689 ShifterOperand so;
6690 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
6691 __ orr(out, first, so);
6692 } else {
6693 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
6694 __ orn(out, first, ShifterOperand(~value));
6695 }
6696}
6697
6698void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
6699 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
6700 if (value == 0u) {
6701 if (out != first) {
6702 __ mov(out, ShifterOperand(first));
6703 }
6704 return;
6705 }
6706 __ eor(out, first, ShifterOperand(value));
6707}
6708
Vladimir Marko59751a72016-08-05 14:37:27 +01006709void InstructionCodeGeneratorARM::GenerateAddLongConst(Location out,
6710 Location first,
6711 uint64_t value) {
6712 Register out_low = out.AsRegisterPairLow<Register>();
6713 Register out_high = out.AsRegisterPairHigh<Register>();
6714 Register first_low = first.AsRegisterPairLow<Register>();
6715 Register first_high = first.AsRegisterPairHigh<Register>();
6716 uint32_t value_low = Low32Bits(value);
6717 uint32_t value_high = High32Bits(value);
6718 if (value_low == 0u) {
6719 if (out_low != first_low) {
6720 __ mov(out_low, ShifterOperand(first_low));
6721 }
6722 __ AddConstant(out_high, first_high, value_high);
6723 return;
6724 }
6725 __ AddConstantSetFlags(out_low, first_low, value_low);
6726 ShifterOperand so;
6727 if (__ ShifterOperandCanHold(out_high, first_high, ADC, value_high, kCcDontCare, &so)) {
6728 __ adc(out_high, first_high, so);
6729 } else if (__ ShifterOperandCanHold(out_low, first_low, SBC, ~value_high, kCcDontCare, &so)) {
6730 __ sbc(out_high, first_high, so);
6731 } else {
6732 LOG(FATAL) << "Unexpected constant " << value_high;
6733 UNREACHABLE();
6734 }
6735}
6736
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006737void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
6738 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006739 Location first = locations->InAt(0);
6740 Location second = locations->InAt(1);
6741 Location out = locations->Out();
6742
6743 if (second.IsConstant()) {
6744 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
6745 uint32_t value_low = Low32Bits(value);
6746 if (instruction->GetResultType() == Primitive::kPrimInt) {
6747 Register first_reg = first.AsRegister<Register>();
6748 Register out_reg = out.AsRegister<Register>();
6749 if (instruction->IsAnd()) {
6750 GenerateAndConst(out_reg, first_reg, value_low);
6751 } else if (instruction->IsOr()) {
6752 GenerateOrrConst(out_reg, first_reg, value_low);
6753 } else {
6754 DCHECK(instruction->IsXor());
6755 GenerateEorConst(out_reg, first_reg, value_low);
6756 }
6757 } else {
6758 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6759 uint32_t value_high = High32Bits(value);
6760 Register first_low = first.AsRegisterPairLow<Register>();
6761 Register first_high = first.AsRegisterPairHigh<Register>();
6762 Register out_low = out.AsRegisterPairLow<Register>();
6763 Register out_high = out.AsRegisterPairHigh<Register>();
6764 if (instruction->IsAnd()) {
6765 GenerateAndConst(out_low, first_low, value_low);
6766 GenerateAndConst(out_high, first_high, value_high);
6767 } else if (instruction->IsOr()) {
6768 GenerateOrrConst(out_low, first_low, value_low);
6769 GenerateOrrConst(out_high, first_high, value_high);
6770 } else {
6771 DCHECK(instruction->IsXor());
6772 GenerateEorConst(out_low, first_low, value_low);
6773 GenerateEorConst(out_high, first_high, value_high);
6774 }
6775 }
6776 return;
6777 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006778
6779 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006780 Register first_reg = first.AsRegister<Register>();
6781 ShifterOperand second_reg(second.AsRegister<Register>());
6782 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006783 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006784 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006785 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006786 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006787 } else {
6788 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006789 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006790 }
6791 } else {
6792 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006793 Register first_low = first.AsRegisterPairLow<Register>();
6794 Register first_high = first.AsRegisterPairHigh<Register>();
6795 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6796 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6797 Register out_low = out.AsRegisterPairLow<Register>();
6798 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006799 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006800 __ and_(out_low, first_low, second_low);
6801 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006802 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006803 __ orr(out_low, first_low, second_low);
6804 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006805 } else {
6806 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006807 __ eor(out_low, first_low, second_low);
6808 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006809 }
6810 }
6811}
6812
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006813void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(
6814 HInstruction* instruction,
6815 Location out,
6816 uint32_t offset,
6817 Location maybe_temp,
6818 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00006819 Register out_reg = out.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006820 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006821 CHECK(kEmitCompilerReadBarrier);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006822 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006823 if (kUseBakerReadBarrier) {
6824 // Load with fast path based Baker's read barrier.
6825 // /* HeapReference<Object> */ out = *(out + offset)
6826 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006827 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006828 } else {
6829 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006830 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00006831 // in the following move operation, as we will need it for the
6832 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006833 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00006834 // /* HeapReference<Object> */ out = *(out + offset)
6835 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006836 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00006837 }
6838 } else {
6839 // Plain load with no read barrier.
6840 // /* HeapReference<Object> */ out = *(out + offset)
6841 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6842 __ MaybeUnpoisonHeapReference(out_reg);
6843 }
6844}
6845
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006846void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(
6847 HInstruction* instruction,
6848 Location out,
6849 Location obj,
6850 uint32_t offset,
6851 Location maybe_temp,
6852 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00006853 Register out_reg = out.AsRegister<Register>();
6854 Register obj_reg = obj.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006855 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006856 CHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00006857 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006858 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006859 // Load with fast path based Baker's read barrier.
6860 // /* HeapReference<Object> */ out = *(obj + offset)
6861 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006862 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006863 } else {
6864 // Load with slow path based read barrier.
6865 // /* HeapReference<Object> */ out = *(obj + offset)
6866 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6867 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6868 }
6869 } else {
6870 // Plain load with no read barrier.
6871 // /* HeapReference<Object> */ out = *(obj + offset)
6872 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6873 __ MaybeUnpoisonHeapReference(out_reg);
6874 }
6875}
6876
6877void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
6878 Location root,
6879 Register obj,
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006880 uint32_t offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006881 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00006882 Register root_reg = root.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006883 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006884 DCHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00006885 if (kUseBakerReadBarrier) {
6886 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6887 // Baker's read barrier are used:
6888 //
6889 // root = obj.field;
Mathieu Chartierfe814e82016-11-09 14:32:49 -08006890 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
6891 // if (temp != null) {
6892 // root = temp(root)
Roland Levillainc9285912015-12-18 10:38:42 +00006893 // }
6894
6895 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6896 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6897 static_assert(
6898 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6899 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6900 "have different sizes.");
6901 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6902 "art::mirror::CompressedReference<mirror::Object> and int32_t "
6903 "have different sizes.");
6904
Vladimir Marko953437b2016-08-24 08:30:46 +00006905 // Slow path marking the GC root `root`.
Mathieu Chartierfe814e82016-11-09 14:32:49 -08006906 Location temp = Location::RegisterLocation(LR);
Artem Serovf4d6aee2016-07-11 10:41:45 +01006907 SlowPathCodeARM* slow_path =
Mathieu Chartierfe814e82016-11-09 14:32:49 -08006908 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(
6909 instruction,
6910 root,
6911 /*entrypoint*/ temp);
Roland Levillainc9285912015-12-18 10:38:42 +00006912 codegen_->AddSlowPath(slow_path);
6913
Mathieu Chartierfe814e82016-11-09 14:32:49 -08006914 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
6915 const int32_t entry_point_offset =
6916 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(root.reg());
6917 // Loading the entrypoint does not require a load acquire since it is only changed when
6918 // threads are suspended or running a checkpoint.
6919 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
6920 // The entrypoint is null when the GC is not marking, this prevents one load compared to
6921 // checking GetIsGcMarking.
6922 __ CompareAndBranchIfNonZero(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
Roland Levillainc9285912015-12-18 10:38:42 +00006923 __ Bind(slow_path->GetExitLabel());
6924 } else {
6925 // GC root loaded through a slow path for read barriers other
6926 // than Baker's.
6927 // /* GcRoot<mirror::Object>* */ root = obj + offset
6928 __ AddConstant(root_reg, obj, offset);
6929 // /* mirror::Object* */ root = root->Read()
6930 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6931 }
6932 } else {
6933 // Plain GC root load with no read barrier.
6934 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6935 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6936 // Note that GC roots are not affected by heap poisoning, thus we
6937 // do not have to unpoison `root_reg` here.
6938 }
6939}
6940
6941void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6942 Location ref,
6943 Register obj,
6944 uint32_t offset,
6945 Location temp,
6946 bool needs_null_check) {
6947 DCHECK(kEmitCompilerReadBarrier);
6948 DCHECK(kUseBakerReadBarrier);
6949
6950 // /* HeapReference<Object> */ ref = *(obj + offset)
6951 Location no_index = Location::NoLocation();
Roland Levillainbfea3352016-06-23 13:48:47 +01006952 ScaleFactor no_scale_factor = TIMES_1;
Roland Levillainc9285912015-12-18 10:38:42 +00006953 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01006954 instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00006955}
6956
6957void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6958 Location ref,
6959 Register obj,
6960 uint32_t data_offset,
6961 Location index,
6962 Location temp,
6963 bool needs_null_check) {
6964 DCHECK(kEmitCompilerReadBarrier);
6965 DCHECK(kUseBakerReadBarrier);
6966
Roland Levillainbfea3352016-06-23 13:48:47 +01006967 static_assert(
6968 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6969 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00006970 // /* HeapReference<Object> */ ref =
6971 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Roland Levillainbfea3352016-06-23 13:48:47 +01006972 ScaleFactor scale_factor = TIMES_4;
Roland Levillainc9285912015-12-18 10:38:42 +00006973 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01006974 instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00006975}
6976
6977void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6978 Location ref,
6979 Register obj,
6980 uint32_t offset,
6981 Location index,
Roland Levillainbfea3352016-06-23 13:48:47 +01006982 ScaleFactor scale_factor,
Roland Levillainc9285912015-12-18 10:38:42 +00006983 Location temp,
Roland Levillaina1aa3b12016-10-26 13:03:38 +01006984 bool needs_null_check,
6985 bool always_update_field,
6986 Register* temp2) {
Roland Levillainc9285912015-12-18 10:38:42 +00006987 DCHECK(kEmitCompilerReadBarrier);
6988 DCHECK(kUseBakerReadBarrier);
6989
6990 // In slow path based read barriers, the read barrier call is
6991 // inserted after the original load. However, in fast path based
6992 // Baker's read barriers, we need to perform the load of
6993 // mirror::Object::monitor_ *before* the original reference load.
6994 // This load-load ordering is required by the read barrier.
6995 // The fast path/slow path (for Baker's algorithm) should look like:
6996 //
6997 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6998 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
6999 // HeapReference<Object> ref = *src; // Original reference load.
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07007000 // bool is_gray = (rb_state == ReadBarrier::GrayState());
Roland Levillainc9285912015-12-18 10:38:42 +00007001 // if (is_gray) {
7002 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
7003 // }
7004 //
7005 // Note: the original implementation in ReadBarrier::Barrier is
Roland Levillaine3f43ac2016-01-19 15:07:47 +00007006 // slightly more complex as it performs additional checks that we do
7007 // not do here for performance reasons.
Roland Levillainc9285912015-12-18 10:38:42 +00007008
7009 Register ref_reg = ref.AsRegister<Register>();
7010 Register temp_reg = temp.AsRegister<Register>();
7011 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
7012
7013 // /* int32_t */ monitor = obj->monitor_
7014 __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
7015 if (needs_null_check) {
7016 MaybeRecordImplicitNullCheck(instruction);
7017 }
7018 // /* LockWord */ lock_word = LockWord(monitor)
7019 static_assert(sizeof(LockWord) == sizeof(int32_t),
7020 "art::LockWord and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00007021
Vladimir Marko194bcfe2016-07-11 15:52:00 +01007022 // Introduce a dependency on the lock_word including the rb_state,
7023 // which shall prevent load-load reordering without using
Roland Levillainc9285912015-12-18 10:38:42 +00007024 // a memory barrier (which would be more expensive).
Roland Levillain0b671c02016-08-19 12:02:34 +01007025 // `obj` is unchanged by this operation, but its value now depends
7026 // on `temp_reg`.
Vladimir Marko194bcfe2016-07-11 15:52:00 +01007027 __ add(obj, obj, ShifterOperand(temp_reg, LSR, 32));
Roland Levillainc9285912015-12-18 10:38:42 +00007028
7029 // The actual reference load.
7030 if (index.IsValid()) {
Roland Levillaina1aa3b12016-10-26 13:03:38 +01007031 // Load types involving an "index": ArrayGet,
7032 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
7033 // intrinsics.
Roland Levillainbfea3352016-06-23 13:48:47 +01007034 // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
Roland Levillainc9285912015-12-18 10:38:42 +00007035 if (index.IsConstant()) {
7036 size_t computed_offset =
Roland Levillainbfea3352016-06-23 13:48:47 +01007037 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
Roland Levillainc9285912015-12-18 10:38:42 +00007038 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
7039 } else {
Roland Levillainbfea3352016-06-23 13:48:47 +01007040 // Handle the special case of the
Roland Levillaina1aa3b12016-10-26 13:03:38 +01007041 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
7042 // intrinsics, which use a register pair as index ("long
7043 // offset"), of which only the low part contains data.
Roland Levillainbfea3352016-06-23 13:48:47 +01007044 Register index_reg = index.IsRegisterPair()
7045 ? index.AsRegisterPairLow<Register>()
7046 : index.AsRegister<Register>();
7047 __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
Roland Levillainc9285912015-12-18 10:38:42 +00007048 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
7049 }
7050 } else {
7051 // /* HeapReference<Object> */ ref = *(obj + offset)
7052 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
7053 }
7054
7055 // Object* ref = ref_addr->AsMirrorPtr()
7056 __ MaybeUnpoisonHeapReference(ref_reg);
7057
Vladimir Marko953437b2016-08-24 08:30:46 +00007058 // Slow path marking the object `ref` when it is gray.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01007059 SlowPathCodeARM* slow_path;
7060 if (always_update_field) {
7061 DCHECK(temp2 != nullptr);
7062 // ReadBarrierMarkAndUpdateFieldSlowPathARM only supports address
7063 // of the form `obj + field_offset`, where `obj` is a register and
7064 // `field_offset` is a register pair (of which only the lower half
7065 // is used). Thus `offset` and `scale_factor` above are expected
7066 // to be null in this code path.
7067 DCHECK_EQ(offset, 0u);
7068 DCHECK_EQ(scale_factor, ScaleFactor::TIMES_1);
7069 slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkAndUpdateFieldSlowPathARM(
7070 instruction, ref, obj, /* field_offset */ index, temp_reg, *temp2);
7071 } else {
7072 slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref);
7073 }
Roland Levillainc9285912015-12-18 10:38:42 +00007074 AddSlowPath(slow_path);
7075
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07007076 // if (rb_state == ReadBarrier::GrayState())
Roland Levillainc9285912015-12-18 10:38:42 +00007077 // ref = ReadBarrier::Mark(ref);
Vladimir Marko194bcfe2016-07-11 15:52:00 +01007078 // Given the numeric representation, it's enough to check the low bit of the
7079 // rb_state. We do that by shifting the bit out of the lock word with LSRS
7080 // which can be a 16-bit instruction unlike the TST immediate.
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07007081 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
7082 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
Vladimir Marko194bcfe2016-07-11 15:52:00 +01007083 __ Lsrs(temp_reg, temp_reg, LockWord::kReadBarrierStateShift + 1);
7084 __ b(slow_path->GetEntryLabel(), CS); // Carry flag is the last bit shifted out by LSRS.
Roland Levillainc9285912015-12-18 10:38:42 +00007085 __ Bind(slow_path->GetExitLabel());
7086}
7087
7088void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
7089 Location out,
7090 Location ref,
7091 Location obj,
7092 uint32_t offset,
7093 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00007094 DCHECK(kEmitCompilerReadBarrier);
7095
Roland Levillainc9285912015-12-18 10:38:42 +00007096 // Insert a slow path based read barrier *after* the reference load.
7097 //
Roland Levillain3b359c72015-11-17 19:35:12 +00007098 // If heap poisoning is enabled, the unpoisoning of the loaded
7099 // reference will be carried out by the runtime within the slow
7100 // path.
7101 //
7102 // Note that `ref` currently does not get unpoisoned (when heap
7103 // poisoning is enabled), which is alright as the `ref` argument is
7104 // not used by the artReadBarrierSlow entry point.
7105 //
7106 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
Artem Serovf4d6aee2016-07-11 10:41:45 +01007107 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
Roland Levillain3b359c72015-11-17 19:35:12 +00007108 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
7109 AddSlowPath(slow_path);
7110
Roland Levillain3b359c72015-11-17 19:35:12 +00007111 __ b(slow_path->GetEntryLabel());
7112 __ Bind(slow_path->GetExitLabel());
7113}
7114
Roland Levillainc9285912015-12-18 10:38:42 +00007115void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
7116 Location out,
7117 Location ref,
7118 Location obj,
7119 uint32_t offset,
7120 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00007121 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00007122 // Baker's read barriers shall be handled by the fast path
7123 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
7124 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00007125 // If heap poisoning is enabled, unpoisoning will be taken care of
7126 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00007127 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00007128 } else if (kPoisonHeapReferences) {
7129 __ UnpoisonHeapReference(out.AsRegister<Register>());
7130 }
7131}
7132
Roland Levillainc9285912015-12-18 10:38:42 +00007133void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
7134 Location out,
7135 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00007136 DCHECK(kEmitCompilerReadBarrier);
7137
Roland Levillainc9285912015-12-18 10:38:42 +00007138 // Insert a slow path based read barrier *after* the GC root load.
7139 //
Roland Levillain3b359c72015-11-17 19:35:12 +00007140 // Note that GC roots are not affected by heap poisoning, so we do
7141 // not need to do anything special for this here.
Artem Serovf4d6aee2016-07-11 10:41:45 +01007142 SlowPathCodeARM* slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00007143 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
7144 AddSlowPath(slow_path);
7145
Roland Levillain3b359c72015-11-17 19:35:12 +00007146 __ b(slow_path->GetEntryLabel());
7147 __ Bind(slow_path->GetExitLabel());
7148}
7149
Vladimir Markodc151b22015-10-15 18:02:30 +01007150HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
7151 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffrayc1a42cf2016-12-18 15:52:36 +00007152 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00007153 HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
7154 // We disable pc-relative load when there is an irreducible loop, as the optimization
7155 // is incompatible with it.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007156 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
7157 // with irreducible loops.
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00007158 if (GetGraph()->HasIrreducibleLoops() &&
7159 (dispatch_info.method_load_kind ==
7160 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
7161 dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
7162 }
7163
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00007164 return dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01007165}
7166
Vladimir Markob4536b72015-11-24 13:45:23 +00007167Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
7168 Register temp) {
7169 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
7170 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
7171 if (!invoke->GetLocations()->Intrinsified()) {
7172 return location.AsRegister<Register>();
7173 }
7174 // For intrinsics we allow any location, so it may be on the stack.
7175 if (!location.IsRegister()) {
7176 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
7177 return temp;
7178 }
7179 // For register locations, check if the register was saved. If so, get it from the stack.
7180 // Note: There is a chance that the register was saved but not overwritten, so we could
7181 // save one load. However, since this is just an intrinsic slow path we prefer this
7182 // simple and more robust approach rather that trying to determine if that's the case.
7183 SlowPathCode* slow_path = GetCurrentSlowPath();
7184 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
7185 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
7186 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
7187 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
7188 return temp;
7189 }
7190 return location.AsRegister<Register>();
7191}
7192
Nicolas Geoffray38207af2015-06-01 15:46:22 +01007193void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00007194 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
7195 switch (invoke->GetMethodLoadKind()) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007196 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
7197 uint32_t offset =
7198 GetThreadOffset<kArmPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Vladimir Marko58155012015-08-19 12:49:41 +00007199 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007200 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, offset);
Vladimir Marko58155012015-08-19 12:49:41 +00007201 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007202 }
Vladimir Marko58155012015-08-19 12:49:41 +00007203 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00007204 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00007205 break;
7206 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
7207 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
7208 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00007209 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
7210 HArmDexCacheArraysBase* base =
7211 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
7212 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
7213 temp.AsRegister<Register>());
7214 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
7215 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
7216 break;
7217 }
Vladimir Marko58155012015-08-19 12:49:41 +00007218 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00007219 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00007220 Register method_reg;
7221 Register reg = temp.AsRegister<Register>();
7222 if (current_method.IsRegister()) {
7223 method_reg = current_method.AsRegister<Register>();
7224 } else {
7225 DCHECK(invoke->GetLocations()->Intrinsified());
7226 DCHECK(!current_method.IsValid());
7227 method_reg = reg;
7228 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
7229 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007230 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
7231 __ LoadFromOffset(kLoadWord,
7232 reg,
7233 method_reg,
7234 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01007235 // temp = temp[index_in_cache];
7236 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
7237 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Vladimir Marko58155012015-08-19 12:49:41 +00007238 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
7239 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01007240 }
Vladimir Marko58155012015-08-19 12:49:41 +00007241 }
7242
7243 switch (invoke->GetCodePtrLocation()) {
7244 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
7245 __ bl(GetFrameEntryLabel());
7246 break;
Vladimir Marko58155012015-08-19 12:49:41 +00007247 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
7248 // LR = callee_method->entry_point_from_quick_compiled_code_
7249 __ LoadFromOffset(
7250 kLoadWord, LR, callee_method.AsRegister<Register>(),
Andreas Gampe542451c2016-07-26 09:02:02 -07007251 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00007252 // LR()
7253 __ blx(LR);
7254 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08007255 }
7256
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08007257 DCHECK(!IsLeafMethod());
7258}
7259
Andreas Gampebfb5ba92015-09-01 15:45:02 +00007260void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
7261 Register temp = temp_location.AsRegister<Register>();
7262 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
7263 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00007264
7265 // Use the calling convention instead of the location of the receiver, as
7266 // intrinsics may have put the receiver in a different register. In the intrinsics
7267 // slow path, the arguments have been moved to the right place, so here we are
7268 // guaranteed that the receiver is the first register of the calling convention.
7269 InvokeDexCallingConvention calling_convention;
7270 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00007271 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00007272 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00007273 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00007274 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00007275 // Instead of simply (possibly) unpoisoning `temp` here, we should
7276 // emit a read barrier for the previous class reference load.
7277 // However this is not required in practice, as this is an
7278 // intermediate/temporary reference and because the current
7279 // concurrent copying collector keeps the from-space memory
7280 // intact/accessible until the end of the marking phase (the
7281 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00007282 __ MaybeUnpoisonHeapReference(temp);
7283 // temp = temp->GetMethodAt(method_offset);
7284 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07007285 kArmPointerSize).Int32Value();
Andreas Gampebfb5ba92015-09-01 15:45:02 +00007286 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
7287 // LR = temp->GetEntryPoint();
7288 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
7289 // LR();
7290 __ blx(LR);
7291}
7292
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007293CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007294 const DexFile& dex_file, dex::StringIndex string_index) {
7295 return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007296}
7297
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007298CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
Andreas Gampea5b09a62016-11-17 15:21:22 -08007299 const DexFile& dex_file, dex::TypeIndex type_index) {
7300 return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007301}
7302
Vladimir Marko1998cd02017-01-13 13:02:58 +00007303CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewTypeBssEntryPatch(
7304 const DexFile& dex_file, dex::TypeIndex type_index) {
7305 return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
7306}
7307
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007308CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
7309 const DexFile& dex_file, uint32_t element_offset) {
7310 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
7311}
7312
7313CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
7314 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
7315 patches->emplace_back(dex_file, offset_or_index);
7316 return &patches->back();
7317}
7318
7319Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08007320 dex::StringIndex string_index) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007321 return boot_image_string_patches_.GetOrCreate(
7322 StringReference(&dex_file, string_index),
7323 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7324}
7325
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007326Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08007327 dex::TypeIndex type_index) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007328 return boot_image_type_patches_.GetOrCreate(
7329 TypeReference(&dex_file, type_index),
7330 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7331}
7332
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007333Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
7334 bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
7335 Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
7336 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
7337}
7338
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007339Literal* CodeGeneratorARM::DeduplicateJitStringLiteral(const DexFile& dex_file,
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007340 dex::StringIndex string_index,
7341 Handle<mirror::String> handle) {
7342 jit_string_roots_.Overwrite(StringReference(&dex_file, string_index),
7343 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007344 return jit_string_patches_.GetOrCreate(
7345 StringReference(&dex_file, string_index),
7346 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7347}
7348
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007349Literal* CodeGeneratorARM::DeduplicateJitClassLiteral(const DexFile& dex_file,
7350 dex::TypeIndex type_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007351 Handle<mirror::Class> handle) {
7352 jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
7353 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007354 return jit_class_patches_.GetOrCreate(
7355 TypeReference(&dex_file, type_index),
7356 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7357}
7358
Vladimir Markoaad75c62016-10-03 08:46:48 +00007359template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
7360inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
7361 const ArenaDeque<PcRelativePatchInfo>& infos,
7362 ArenaVector<LinkerPatch>* linker_patches) {
7363 for (const PcRelativePatchInfo& info : infos) {
7364 const DexFile& dex_file = info.target_dex_file;
7365 size_t offset_or_index = info.offset_or_index;
7366 DCHECK(info.add_pc_label.IsBound());
7367 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
7368 // Add MOVW patch.
7369 DCHECK(info.movw_label.IsBound());
7370 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
7371 linker_patches->push_back(Factory(movw_offset, &dex_file, add_pc_offset, offset_or_index));
7372 // Add MOVT patch.
7373 DCHECK(info.movt_label.IsBound());
7374 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
7375 linker_patches->push_back(Factory(movt_offset, &dex_file, add_pc_offset, offset_or_index));
7376 }
7377}
7378
Vladimir Marko58155012015-08-19 12:49:41 +00007379void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
7380 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00007381 size_t size =
Vladimir Markoaad75c62016-10-03 08:46:48 +00007382 /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007383 boot_image_string_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00007384 /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007385 boot_image_type_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00007386 /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
Vladimir Marko1998cd02017-01-13 13:02:58 +00007387 /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007388 boot_image_address_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00007389 linker_patches->reserve(size);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007390 EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
7391 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007392 for (const auto& entry : boot_image_string_patches_) {
7393 const StringReference& target_string = entry.first;
7394 Literal* literal = entry.second;
7395 DCHECK(literal->GetLabel()->IsBound());
7396 uint32_t literal_offset = literal->GetLabel()->Position();
7397 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
7398 target_string.dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08007399 target_string.string_index.index_));
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007400 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00007401 if (!GetCompilerOptions().IsBootImage()) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00007402 DCHECK(pc_relative_type_patches_.empty());
Vladimir Markoaad75c62016-10-03 08:46:48 +00007403 EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
7404 linker_patches);
7405 } else {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007406 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
7407 linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007408 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
7409 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007410 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00007411 EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
7412 linker_patches);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007413 for (const auto& entry : boot_image_type_patches_) {
7414 const TypeReference& target_type = entry.first;
7415 Literal* literal = entry.second;
7416 DCHECK(literal->GetLabel()->IsBound());
7417 uint32_t literal_offset = literal->GetLabel()->Position();
7418 linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
7419 target_type.dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08007420 target_type.type_index.index_));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007421 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007422 for (const auto& entry : boot_image_address_patches_) {
7423 DCHECK(GetCompilerOptions().GetIncludePatchInformation());
7424 Literal* literal = entry.second;
7425 DCHECK(literal->GetLabel()->IsBound());
7426 uint32_t literal_offset = literal->GetLabel()->Position();
7427 linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
7428 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00007429 DCHECK_EQ(size, linker_patches->size());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007430}
7431
7432Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
7433 return map->GetOrCreate(
7434 value,
7435 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00007436}
7437
7438Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
7439 MethodToLiteralMap* map) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007440 return map->GetOrCreate(
7441 target_method,
7442 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
Vladimir Marko58155012015-08-19 12:49:41 +00007443}
7444
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03007445void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
7446 LocationSummary* locations =
7447 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
7448 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
7449 Location::RequiresRegister());
7450 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
7451 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
7452 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7453}
7454
7455void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
7456 LocationSummary* locations = instr->GetLocations();
7457 Register res = locations->Out().AsRegister<Register>();
7458 Register accumulator =
7459 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
7460 Register mul_left =
7461 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
7462 Register mul_right =
7463 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
7464
7465 if (instr->GetOpKind() == HInstruction::kAdd) {
7466 __ mla(res, mul_left, mul_right, accumulator);
7467 } else {
7468 __ mls(res, mul_left, mul_right, accumulator);
7469 }
7470}
7471
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01007472void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00007473 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00007474 LOG(FATAL) << "Unreachable";
7475}
7476
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01007477void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00007478 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00007479 LOG(FATAL) << "Unreachable";
7480}
7481
Mark Mendellfe57faa2015-09-18 09:26:15 -04007482// Simple implementation of packed switch - generate cascaded compare/jumps.
7483void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
7484 LocationSummary* locations =
7485 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
7486 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007487 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007488 codegen_->GetAssembler()->IsThumb()) {
7489 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
7490 if (switch_instr->GetStartValue() != 0) {
7491 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
7492 }
7493 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04007494}
7495
7496void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
7497 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007498 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04007499 LocationSummary* locations = switch_instr->GetLocations();
7500 Register value_reg = locations->InAt(0).AsRegister<Register>();
7501 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
7502
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007503 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007504 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007505 Register temp_reg = IP;
7506 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
7507 // the immediate, because IP is used as the destination register. For the other
7508 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
7509 // and they can be encoded in the instruction without making use of IP register.
7510 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
7511
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007512 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007513 // Jump to successors[0] if value == lower_bound.
7514 __ b(codegen_->GetLabelOf(successors[0]), EQ);
7515 int32_t last_index = 0;
7516 for (; num_entries - last_index > 2; last_index += 2) {
7517 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
7518 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
7519 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
7520 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
7521 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
7522 }
7523 if (num_entries - last_index == 2) {
7524 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00007525 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007526 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007527 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04007528
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007529 // And the default for any other value.
7530 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
7531 __ b(codegen_->GetLabelOf(default_block));
7532 }
7533 } else {
7534 // Create a table lookup.
7535 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
7536
7537 // Materialize a pointer to the switch table
7538 std::vector<Label*> labels(num_entries);
7539 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
7540 for (uint32_t i = 0; i < num_entries; i++) {
7541 labels[i] = codegen_->GetLabelOf(successors[i]);
7542 }
7543 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
7544
7545 // Remove the bias.
7546 Register key_reg;
7547 if (lower_bound != 0) {
7548 key_reg = locations->GetTemp(1).AsRegister<Register>();
7549 __ AddConstant(key_reg, value_reg, -lower_bound);
7550 } else {
7551 key_reg = value_reg;
7552 }
7553
7554 // Check whether the value is in the table, jump to default block if not.
7555 __ CmpConstant(key_reg, num_entries - 1);
7556 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
7557
7558 // Load the displacement from the table.
7559 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
7560
7561 // Dispatch is a direct add to the PC (for Thumb2).
7562 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04007563 }
7564}
7565
Vladimir Markob4536b72015-11-24 13:45:23 +00007566void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
7567 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
7568 locations->SetOut(Location::RequiresRegister());
Vladimir Markob4536b72015-11-24 13:45:23 +00007569}
7570
7571void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
7572 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007573 CodeGeneratorARM::PcRelativePatchInfo* labels =
7574 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Vladimir Markob4536b72015-11-24 13:45:23 +00007575 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007576 __ movw(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00007577 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007578 __ movt(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00007579 __ BindTrackedLabel(&labels->add_pc_label);
7580 __ add(base_reg, base_reg, ShifterOperand(PC));
7581}
7582
Andreas Gampe85b62f22015-09-09 13:15:38 -07007583void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
7584 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00007585 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07007586 return;
7587 }
7588
7589 DCHECK_NE(type, Primitive::kPrimVoid);
7590
7591 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
7592 if (return_loc.Equals(trg)) {
7593 return;
7594 }
7595
7596 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
7597 // with the last branch.
7598 if (type == Primitive::kPrimLong) {
7599 HParallelMove parallel_move(GetGraph()->GetArena());
7600 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
7601 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
7602 GetMoveResolver()->EmitNativeCode(&parallel_move);
7603 } else if (type == Primitive::kPrimDouble) {
7604 HParallelMove parallel_move(GetGraph()->GetArena());
7605 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
7606 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
7607 GetMoveResolver()->EmitNativeCode(&parallel_move);
7608 } else {
7609 // Let the parallel move resolver take care of all of this.
7610 HParallelMove parallel_move(GetGraph()->GetArena());
7611 parallel_move.AddMove(return_loc, trg, type, nullptr);
7612 GetMoveResolver()->EmitNativeCode(&parallel_move);
7613 }
7614}
7615
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007616void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
7617 LocationSummary* locations =
7618 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7619 locations->SetInAt(0, Location::RequiresRegister());
7620 locations->SetOut(Location::RequiresRegister());
7621}
7622
7623void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
7624 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00007625 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007626 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007627 instruction->GetIndex(), kArmPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007628 __ LoadFromOffset(kLoadWord,
7629 locations->Out().AsRegister<Register>(),
7630 locations->InAt(0).AsRegister<Register>(),
7631 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007632 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007633 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00007634 instruction->GetIndex(), kArmPointerSize));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007635 __ LoadFromOffset(kLoadWord,
7636 locations->Out().AsRegister<Register>(),
7637 locations->InAt(0).AsRegister<Register>(),
7638 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
7639 __ LoadFromOffset(kLoadWord,
7640 locations->Out().AsRegister<Register>(),
7641 locations->Out().AsRegister<Register>(),
7642 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007643 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007644}
7645
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007646static void PatchJitRootUse(uint8_t* code,
7647 const uint8_t* roots_data,
7648 Literal* literal,
7649 uint64_t index_in_table) {
7650 DCHECK(literal->GetLabel()->IsBound());
7651 uint32_t literal_offset = literal->GetLabel()->Position();
7652 uintptr_t address =
7653 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
7654 uint8_t* data = code + literal_offset;
7655 reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
7656}
7657
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007658void CodeGeneratorARM::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
7659 for (const auto& entry : jit_string_patches_) {
7660 const auto& it = jit_string_roots_.find(entry.first);
7661 DCHECK(it != jit_string_roots_.end());
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007662 PatchJitRootUse(code, roots_data, entry.second, it->second);
7663 }
7664 for (const auto& entry : jit_class_patches_) {
7665 const auto& it = jit_class_roots_.find(entry.first);
7666 DCHECK(it != jit_class_roots_.end());
7667 PatchJitRootUse(code, roots_data, entry.second, it->second);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007668 }
7669}
7670
Roland Levillain4d027112015-07-01 15:41:14 +01007671#undef __
7672#undef QUICK_ENTRY_POINT
7673
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00007674} // namespace arm
7675} // namespace art