blob: 07b174698aa96956baa8b86826d188d7f932a5db [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;
Hiroshi Yamauchifee25502017-01-19 02:11:15 +00003987 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003988 locations->SetOut(Location::RegisterLocation(R0));
Hiroshi Yamauchifee25502017-01-19 02:11:15 +00003989 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3990 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003991}
3992
3993void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
Hiroshi Yamauchifee25502017-01-19 02:11:15 +00003994 InvokeRuntimeCallingConvention calling_convention;
3995 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex().index_);
Roland Levillain4d027112015-07-01 15:41:14 +01003996 // Note: if heap poisoning is enabled, the entry point takes cares
3997 // of poisoning the reference.
Hiroshi Yamauchifee25502017-01-19 02:11:15 +00003998 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
3999 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004000}
4001
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004002void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004003 LocationSummary* locations =
4004 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01004005 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
4006 if (location.IsStackSlot()) {
4007 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4008 } else if (location.IsDoubleStackSlot()) {
4009 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004010 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01004011 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004012}
4013
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004014void InstructionCodeGeneratorARM::VisitParameterValue(
4015 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004016 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004017}
4018
4019void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
4020 LocationSummary* locations =
4021 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4022 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
4023}
4024
4025void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
4026 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004027}
4028
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004029void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004030 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004031 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004032 locations->SetInAt(0, Location::RequiresRegister());
4033 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01004034}
4035
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004036void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
4037 LocationSummary* locations = not_->GetLocations();
4038 Location out = locations->Out();
4039 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00004040 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004041 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00004042 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004043 break;
4044
4045 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01004046 __ mvn(out.AsRegisterPairLow<Register>(),
4047 ShifterOperand(in.AsRegisterPairLow<Register>()));
4048 __ mvn(out.AsRegisterPairHigh<Register>(),
4049 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004050 break;
4051
4052 default:
4053 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
4054 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01004055}
4056
David Brazdil66d126e2015-04-03 16:02:44 +01004057void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
4058 LocationSummary* locations =
4059 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
4060 locations->SetInAt(0, Location::RequiresRegister());
4061 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4062}
4063
4064void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01004065 LocationSummary* locations = bool_not->GetLocations();
4066 Location out = locations->Out();
4067 Location in = locations->InAt(0);
4068 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
4069}
4070
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004071void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004072 LocationSummary* locations =
4073 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00004074 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00004075 case Primitive::kPrimBoolean:
4076 case Primitive::kPrimByte:
4077 case Primitive::kPrimShort:
4078 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08004079 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00004080 case Primitive::kPrimLong: {
4081 locations->SetInAt(0, Location::RequiresRegister());
4082 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004083 // Output overlaps because it is written before doing the low comparison.
4084 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00004085 break;
4086 }
4087 case Primitive::kPrimFloat:
4088 case Primitive::kPrimDouble: {
4089 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01004090 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +00004091 locations->SetOut(Location::RequiresRegister());
4092 break;
4093 }
4094 default:
4095 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
4096 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004097}
4098
4099void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004100 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004101 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00004102 Location left = locations->InAt(0);
4103 Location right = locations->InAt(1);
4104
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004105 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00004106 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00004107 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00004108 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00004109 case Primitive::kPrimBoolean:
4110 case Primitive::kPrimByte:
4111 case Primitive::kPrimShort:
4112 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08004113 case Primitive::kPrimInt: {
4114 __ LoadImmediate(out, 0);
4115 __ cmp(left.AsRegister<Register>(),
4116 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
4117 less_cond = LT;
4118 break;
4119 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004120 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004121 __ cmp(left.AsRegisterPairHigh<Register>(),
4122 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004123 __ b(&less, LT);
4124 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01004125 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00004126 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004127 __ cmp(left.AsRegisterPairLow<Register>(),
4128 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00004129 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00004130 break;
4131 }
4132 case Primitive::kPrimFloat:
4133 case Primitive::kPrimDouble: {
4134 __ LoadImmediate(out, 0);
Vladimir Marko37dd80d2016-08-01 17:41:45 +01004135 GenerateVcmp(compare);
Calin Juravleddb7df22014-11-25 20:56:51 +00004136 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00004137 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004138 break;
4139 }
4140 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00004141 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00004142 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004143 }
Aart Bika19616e2016-02-01 18:57:58 -08004144
Calin Juravleddb7df22014-11-25 20:56:51 +00004145 __ b(&done, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00004146 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00004147
4148 __ Bind(&greater);
4149 __ LoadImmediate(out, 1);
4150 __ b(&done);
4151
4152 __ Bind(&less);
4153 __ LoadImmediate(out, -1);
4154
4155 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004156}
4157
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01004158void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004159 LocationSummary* locations =
4160 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01004161 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01004162 locations->SetInAt(i, Location::Any());
4163 }
4164 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01004165}
4166
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004167void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004168 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01004169}
4170
Roland Levillainc9285912015-12-18 10:38:42 +00004171void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
4172 // TODO (ported from quick): revisit ARM barrier kinds.
4173 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00004174 switch (kind) {
4175 case MemBarrierKind::kAnyStore:
4176 case MemBarrierKind::kLoadAny:
4177 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07004178 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00004179 break;
4180 }
4181 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07004182 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00004183 break;
4184 }
4185 default:
4186 LOG(FATAL) << "Unexpected memory barrier " << kind;
4187 }
Kenny Root1d8199d2015-06-02 11:01:10 -07004188 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00004189}
4190
4191void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
4192 uint32_t offset,
4193 Register out_lo,
4194 Register out_hi) {
4195 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004196 // Ensure `out_lo` is different from `addr`, so that loading
4197 // `offset` into `out_lo` does not clutter `addr`.
4198 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00004199 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00004200 __ add(IP, addr, ShifterOperand(out_lo));
4201 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00004202 }
4203 __ ldrexd(out_lo, out_hi, addr);
4204}
4205
4206void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
4207 uint32_t offset,
4208 Register value_lo,
4209 Register value_hi,
4210 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00004211 Register temp2,
4212 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004213 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00004214 if (offset != 0) {
4215 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00004216 __ add(IP, addr, ShifterOperand(temp1));
4217 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00004218 }
4219 __ Bind(&fail);
4220 // We need a load followed by store. (The address used in a STREX instruction must
4221 // be the same as the address in the most recently executed LDREX instruction.)
4222 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00004223 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004224 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004225 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00004226}
4227
4228void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
4229 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4230
Nicolas Geoffray39468442014-09-02 15:17:15 +01004231 LocationSummary* locations =
4232 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004233 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00004234
Calin Juravle52c48962014-12-16 17:02:57 +00004235 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004236 if (Primitive::IsFloatingPointType(field_type)) {
4237 locations->SetInAt(1, Location::RequiresFpuRegister());
4238 } else {
4239 locations->SetInAt(1, Location::RequiresRegister());
4240 }
4241
Calin Juravle52c48962014-12-16 17:02:57 +00004242 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00004243 bool generate_volatile = field_info.IsVolatile()
4244 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004245 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01004246 bool needs_write_barrier =
4247 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004248 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00004249 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01004250 if (needs_write_barrier) {
4251 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004252 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00004253 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004254 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00004255 // - registers need to be consecutive
4256 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00004257 // We don't test for ARM yet, and the assertion makes sure that we
4258 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00004259 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4260
4261 locations->AddTemp(Location::RequiresRegister());
4262 locations->AddTemp(Location::RequiresRegister());
4263 if (field_type == Primitive::kPrimDouble) {
4264 // For doubles we need two more registers to copy the value.
4265 locations->AddTemp(Location::RegisterLocation(R2));
4266 locations->AddTemp(Location::RegisterLocation(R3));
4267 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004268 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004269}
4270
Calin Juravle52c48962014-12-16 17:02:57 +00004271void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004272 const FieldInfo& field_info,
4273 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00004274 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4275
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004276 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00004277 Register base = locations->InAt(0).AsRegister<Register>();
4278 Location value = locations->InAt(1);
4279
4280 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004281 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00004282 Primitive::Type field_type = field_info.GetFieldType();
4283 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01004284 bool needs_write_barrier =
4285 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004286
4287 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004288 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00004289 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004290
4291 switch (field_type) {
4292 case Primitive::kPrimBoolean:
4293 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00004294 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004295 break;
4296 }
4297
4298 case Primitive::kPrimShort:
4299 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00004300 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004301 break;
4302 }
4303
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004304 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004305 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01004306 if (kPoisonHeapReferences && needs_write_barrier) {
4307 // Note that in the case where `value` is a null reference,
4308 // we do not enter this block, as a null reference does not
4309 // need poisoning.
4310 DCHECK_EQ(field_type, Primitive::kPrimNot);
4311 Register temp = locations->GetTemp(0).AsRegister<Register>();
4312 __ Mov(temp, value.AsRegister<Register>());
4313 __ PoisonHeapReference(temp);
4314 __ StoreToOffset(kStoreWord, temp, base, offset);
4315 } else {
4316 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
4317 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004318 break;
4319 }
4320
4321 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00004322 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004323 GenerateWideAtomicStore(base, offset,
4324 value.AsRegisterPairLow<Register>(),
4325 value.AsRegisterPairHigh<Register>(),
4326 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00004327 locations->GetTemp(1).AsRegister<Register>(),
4328 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004329 } else {
4330 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004331 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004332 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004333 break;
4334 }
4335
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004336 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00004337 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004338 break;
4339 }
4340
4341 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004342 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00004343 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004344 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
4345 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
4346
4347 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
4348
4349 GenerateWideAtomicStore(base, offset,
4350 value_reg_lo,
4351 value_reg_hi,
4352 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00004353 locations->GetTemp(3).AsRegister<Register>(),
4354 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004355 } else {
4356 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004357 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004358 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004359 break;
4360 }
4361
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004362 case Primitive::kPrimVoid:
4363 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004364 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004365 }
Calin Juravle52c48962014-12-16 17:02:57 +00004366
Calin Juravle77520bc2015-01-12 18:45:46 +00004367 // Longs and doubles are handled in the switch.
4368 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
4369 codegen_->MaybeRecordImplicitNullCheck(instruction);
4370 }
4371
4372 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
4373 Register temp = locations->GetTemp(0).AsRegister<Register>();
4374 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004375 codegen_->MarkGCCard(
4376 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004377 }
4378
Calin Juravle52c48962014-12-16 17:02:57 +00004379 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004380 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00004381 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004382}
4383
Calin Juravle52c48962014-12-16 17:02:57 +00004384void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
4385 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00004386
4387 bool object_field_get_with_read_barrier =
4388 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004389 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004390 new (GetGraph()->GetArena()) LocationSummary(instruction,
4391 object_field_get_with_read_barrier ?
4392 LocationSummary::kCallOnSlowPath :
4393 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01004394 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004395 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01004396 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004397 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00004398
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004399 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00004400 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004401 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00004402 // The output overlaps in case of volatile long: we don't want the
4403 // code generated by GenerateWideAtomicLoad to overwrite the
4404 // object's location. Likewise, in the case of an object field get
4405 // with read barriers enabled, we do not want the load to overwrite
4406 // the object's location, as we need it to emit the read barrier.
4407 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
4408 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01004409
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004410 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4411 locations->SetOut(Location::RequiresFpuRegister());
4412 } else {
4413 locations->SetOut(Location::RequiresRegister(),
4414 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
4415 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004416 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00004417 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00004418 // - registers need to be consecutive
4419 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00004420 // We don't test for ARM yet, and the assertion makes sure that we
4421 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00004422 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4423 locations->AddTemp(Location::RequiresRegister());
4424 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00004425 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
4426 // We need a temporary register for the read barrier marking slow
4427 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
4428 locations->AddTemp(Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00004429 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004430}
4431
Vladimir Marko37dd80d2016-08-01 17:41:45 +01004432Location LocationsBuilderARM::ArithmeticZeroOrFpuRegister(HInstruction* input) {
4433 DCHECK(input->GetType() == Primitive::kPrimDouble || input->GetType() == Primitive::kPrimFloat)
4434 << input->GetType();
4435 if ((input->IsFloatConstant() && (input->AsFloatConstant()->IsArithmeticZero())) ||
4436 (input->IsDoubleConstant() && (input->AsDoubleConstant()->IsArithmeticZero()))) {
4437 return Location::ConstantLocation(input->AsConstant());
4438 } else {
4439 return Location::RequiresFpuRegister();
4440 }
4441}
4442
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004443Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
4444 Opcode opcode) {
4445 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
4446 if (constant->IsConstant() &&
4447 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
4448 return Location::ConstantLocation(constant->AsConstant());
4449 }
4450 return Location::RequiresRegister();
4451}
4452
4453bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
4454 Opcode opcode) {
4455 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
4456 if (Primitive::Is64BitType(input_cst->GetType())) {
Vladimir Marko59751a72016-08-05 14:37:27 +01004457 Opcode high_opcode = opcode;
4458 SetCc low_set_cc = kCcDontCare;
4459 switch (opcode) {
4460 case SUB:
4461 // Flip the operation to an ADD.
4462 value = -value;
4463 opcode = ADD;
4464 FALLTHROUGH_INTENDED;
4465 case ADD:
4466 if (Low32Bits(value) == 0u) {
4467 return CanEncodeConstantAsImmediate(High32Bits(value), opcode, kCcDontCare);
4468 }
4469 high_opcode = ADC;
4470 low_set_cc = kCcSet;
4471 break;
4472 default:
4473 break;
4474 }
4475 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode, low_set_cc) &&
4476 CanEncodeConstantAsImmediate(High32Bits(value), high_opcode, kCcDontCare);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004477 } else {
4478 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
4479 }
4480}
4481
Vladimir Marko59751a72016-08-05 14:37:27 +01004482bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value,
4483 Opcode opcode,
4484 SetCc set_cc) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004485 ShifterOperand so;
4486 ArmAssembler* assembler = codegen_->GetAssembler();
Vladimir Marko59751a72016-08-05 14:37:27 +01004487 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, set_cc, &so)) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004488 return true;
4489 }
4490 Opcode neg_opcode = kNoOperand;
4491 switch (opcode) {
Vladimir Marko59751a72016-08-05 14:37:27 +01004492 case AND: neg_opcode = BIC; value = ~value; break;
4493 case ORR: neg_opcode = ORN; value = ~value; break;
4494 case ADD: neg_opcode = SUB; value = -value; break;
4495 case ADC: neg_opcode = SBC; value = ~value; break;
4496 case SUB: neg_opcode = ADD; value = -value; break;
4497 case SBC: neg_opcode = ADC; value = ~value; break;
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004498 default:
4499 return false;
4500 }
Vladimir Marko59751a72016-08-05 14:37:27 +01004501 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, value, set_cc, &so);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004502}
4503
Calin Juravle52c48962014-12-16 17:02:57 +00004504void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4505 const FieldInfo& field_info) {
4506 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004507
Calin Juravle52c48962014-12-16 17:02:57 +00004508 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004509 Location base_loc = locations->InAt(0);
4510 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00004511 Location out = locations->Out();
4512 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004513 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00004514 Primitive::Type field_type = field_info.GetFieldType();
4515 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4516
4517 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00004518 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00004519 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004520 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004521
Roland Levillainc9285912015-12-18 10:38:42 +00004522 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00004523 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004524 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004525
Roland Levillainc9285912015-12-18 10:38:42 +00004526 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00004527 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004528 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004529
Roland Levillainc9285912015-12-18 10:38:42 +00004530 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00004531 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004532 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004533
4534 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00004535 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004536 break;
Roland Levillainc9285912015-12-18 10:38:42 +00004537
4538 case Primitive::kPrimNot: {
4539 // /* HeapReference<Object> */ out = *(base + offset)
4540 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4541 Location temp_loc = locations->GetTemp(0);
4542 // Note that a potential implicit null check is handled in this
4543 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
4544 codegen_->GenerateFieldLoadWithBakerReadBarrier(
4545 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
4546 if (is_volatile) {
4547 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4548 }
4549 } else {
4550 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4551 codegen_->MaybeRecordImplicitNullCheck(instruction);
4552 if (is_volatile) {
4553 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4554 }
4555 // If read barriers are enabled, emit read barriers other than
4556 // Baker's using a slow path (and also unpoison the loaded
4557 // reference, if heap poisoning is enabled).
4558 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4559 }
4560 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004561 }
4562
Roland Levillainc9285912015-12-18 10:38:42 +00004563 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00004564 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004565 GenerateWideAtomicLoad(base, offset,
4566 out.AsRegisterPairLow<Register>(),
4567 out.AsRegisterPairHigh<Register>());
4568 } else {
4569 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4570 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004571 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004572
Roland Levillainc9285912015-12-18 10:38:42 +00004573 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00004574 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004575 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004576
4577 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004578 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00004579 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004580 Register lo = locations->GetTemp(0).AsRegister<Register>();
4581 Register hi = locations->GetTemp(1).AsRegister<Register>();
4582 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00004583 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004584 __ vmovdrr(out_reg, lo, hi);
4585 } else {
4586 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004587 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004588 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004589 break;
4590 }
4591
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004592 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00004593 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004594 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004595 }
Calin Juravle52c48962014-12-16 17:02:57 +00004596
Roland Levillainc9285912015-12-18 10:38:42 +00004597 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
4598 // Potential implicit null checks, in the case of reference or
4599 // double fields, are handled in the previous switch statement.
4600 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00004601 codegen_->MaybeRecordImplicitNullCheck(instruction);
4602 }
4603
Calin Juravle52c48962014-12-16 17:02:57 +00004604 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004605 if (field_type == Primitive::kPrimNot) {
4606 // Memory barriers, in the case of references, are also handled
4607 // in the previous switch statement.
4608 } else {
4609 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4610 }
Roland Levillain4d027112015-07-01 15:41:14 +01004611 }
Calin Juravle52c48962014-12-16 17:02:57 +00004612}
4613
4614void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4615 HandleFieldSet(instruction, instruction->GetFieldInfo());
4616}
4617
4618void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004619 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004620}
4621
4622void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4623 HandleFieldGet(instruction, instruction->GetFieldInfo());
4624}
4625
4626void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4627 HandleFieldGet(instruction, instruction->GetFieldInfo());
4628}
4629
4630void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4631 HandleFieldGet(instruction, instruction->GetFieldInfo());
4632}
4633
4634void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4635 HandleFieldGet(instruction, instruction->GetFieldInfo());
4636}
4637
4638void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4639 HandleFieldSet(instruction, instruction->GetFieldInfo());
4640}
4641
4642void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004643 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004644}
4645
Calin Juravlee460d1d2015-09-29 04:52:17 +01004646void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4647 HUnresolvedInstanceFieldGet* instruction) {
4648 FieldAccessCallingConventionARM calling_convention;
4649 codegen_->CreateUnresolvedFieldLocationSummary(
4650 instruction, instruction->GetFieldType(), calling_convention);
4651}
4652
4653void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4654 HUnresolvedInstanceFieldGet* instruction) {
4655 FieldAccessCallingConventionARM calling_convention;
4656 codegen_->GenerateUnresolvedFieldAccess(instruction,
4657 instruction->GetFieldType(),
4658 instruction->GetFieldIndex(),
4659 instruction->GetDexPc(),
4660 calling_convention);
4661}
4662
4663void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4664 HUnresolvedInstanceFieldSet* instruction) {
4665 FieldAccessCallingConventionARM calling_convention;
4666 codegen_->CreateUnresolvedFieldLocationSummary(
4667 instruction, instruction->GetFieldType(), calling_convention);
4668}
4669
4670void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4671 HUnresolvedInstanceFieldSet* instruction) {
4672 FieldAccessCallingConventionARM calling_convention;
4673 codegen_->GenerateUnresolvedFieldAccess(instruction,
4674 instruction->GetFieldType(),
4675 instruction->GetFieldIndex(),
4676 instruction->GetDexPc(),
4677 calling_convention);
4678}
4679
4680void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4681 HUnresolvedStaticFieldGet* instruction) {
4682 FieldAccessCallingConventionARM calling_convention;
4683 codegen_->CreateUnresolvedFieldLocationSummary(
4684 instruction, instruction->GetFieldType(), calling_convention);
4685}
4686
4687void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4688 HUnresolvedStaticFieldGet* instruction) {
4689 FieldAccessCallingConventionARM calling_convention;
4690 codegen_->GenerateUnresolvedFieldAccess(instruction,
4691 instruction->GetFieldType(),
4692 instruction->GetFieldIndex(),
4693 instruction->GetDexPc(),
4694 calling_convention);
4695}
4696
4697void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4698 HUnresolvedStaticFieldSet* instruction) {
4699 FieldAccessCallingConventionARM calling_convention;
4700 codegen_->CreateUnresolvedFieldLocationSummary(
4701 instruction, instruction->GetFieldType(), calling_convention);
4702}
4703
4704void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4705 HUnresolvedStaticFieldSet* instruction) {
4706 FieldAccessCallingConventionARM calling_convention;
4707 codegen_->GenerateUnresolvedFieldAccess(instruction,
4708 instruction->GetFieldType(),
4709 instruction->GetFieldIndex(),
4710 instruction->GetDexPc(),
4711 calling_convention);
4712}
4713
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004714void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004715 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
4716 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004717}
4718
Calin Juravle2ae48182016-03-16 14:05:09 +00004719void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4720 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004721 return;
4722 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004723 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004724
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004725 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00004726 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004727}
4728
Calin Juravle2ae48182016-03-16 14:05:09 +00004729void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01004730 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00004731 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004732
4733 LocationSummary* locations = instruction->GetLocations();
4734 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004735
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004736 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004737}
4738
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004739void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00004740 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004741}
4742
Artem Serov6c916792016-07-11 14:02:34 +01004743static LoadOperandType GetLoadOperandType(Primitive::Type type) {
4744 switch (type) {
4745 case Primitive::kPrimNot:
4746 return kLoadWord;
4747 case Primitive::kPrimBoolean:
4748 return kLoadUnsignedByte;
4749 case Primitive::kPrimByte:
4750 return kLoadSignedByte;
4751 case Primitive::kPrimChar:
4752 return kLoadUnsignedHalfword;
4753 case Primitive::kPrimShort:
4754 return kLoadSignedHalfword;
4755 case Primitive::kPrimInt:
4756 return kLoadWord;
4757 case Primitive::kPrimLong:
4758 return kLoadWordPair;
4759 case Primitive::kPrimFloat:
4760 return kLoadSWord;
4761 case Primitive::kPrimDouble:
4762 return kLoadDWord;
4763 default:
4764 LOG(FATAL) << "Unreachable type " << type;
4765 UNREACHABLE();
4766 }
4767}
4768
4769static StoreOperandType GetStoreOperandType(Primitive::Type type) {
4770 switch (type) {
4771 case Primitive::kPrimNot:
4772 return kStoreWord;
4773 case Primitive::kPrimBoolean:
4774 case Primitive::kPrimByte:
4775 return kStoreByte;
4776 case Primitive::kPrimChar:
4777 case Primitive::kPrimShort:
4778 return kStoreHalfword;
4779 case Primitive::kPrimInt:
4780 return kStoreWord;
4781 case Primitive::kPrimLong:
4782 return kStoreWordPair;
4783 case Primitive::kPrimFloat:
4784 return kStoreSWord;
4785 case Primitive::kPrimDouble:
4786 return kStoreDWord;
4787 default:
4788 LOG(FATAL) << "Unreachable type " << type;
4789 UNREACHABLE();
4790 }
4791}
4792
4793void CodeGeneratorARM::LoadFromShiftedRegOffset(Primitive::Type type,
4794 Location out_loc,
4795 Register base,
4796 Register reg_offset,
4797 Condition cond) {
4798 uint32_t shift_count = Primitive::ComponentSizeShift(type);
4799 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
4800
4801 switch (type) {
4802 case Primitive::kPrimByte:
4803 __ ldrsb(out_loc.AsRegister<Register>(), mem_address, cond);
4804 break;
4805 case Primitive::kPrimBoolean:
4806 __ ldrb(out_loc.AsRegister<Register>(), mem_address, cond);
4807 break;
4808 case Primitive::kPrimShort:
4809 __ ldrsh(out_loc.AsRegister<Register>(), mem_address, cond);
4810 break;
4811 case Primitive::kPrimChar:
4812 __ ldrh(out_loc.AsRegister<Register>(), mem_address, cond);
4813 break;
4814 case Primitive::kPrimNot:
4815 case Primitive::kPrimInt:
4816 __ ldr(out_loc.AsRegister<Register>(), mem_address, cond);
4817 break;
4818 // T32 doesn't support LoadFromShiftedRegOffset mem address mode for these types.
4819 case Primitive::kPrimLong:
4820 case Primitive::kPrimFloat:
4821 case Primitive::kPrimDouble:
4822 default:
4823 LOG(FATAL) << "Unreachable type " << type;
4824 UNREACHABLE();
4825 }
4826}
4827
4828void CodeGeneratorARM::StoreToShiftedRegOffset(Primitive::Type type,
4829 Location loc,
4830 Register base,
4831 Register reg_offset,
4832 Condition cond) {
4833 uint32_t shift_count = Primitive::ComponentSizeShift(type);
4834 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
4835
4836 switch (type) {
4837 case Primitive::kPrimByte:
4838 case Primitive::kPrimBoolean:
4839 __ strb(loc.AsRegister<Register>(), mem_address, cond);
4840 break;
4841 case Primitive::kPrimShort:
4842 case Primitive::kPrimChar:
4843 __ strh(loc.AsRegister<Register>(), mem_address, cond);
4844 break;
4845 case Primitive::kPrimNot:
4846 case Primitive::kPrimInt:
4847 __ str(loc.AsRegister<Register>(), mem_address, cond);
4848 break;
4849 // T32 doesn't support StoreToShiftedRegOffset mem address mode for these types.
4850 case Primitive::kPrimLong:
4851 case Primitive::kPrimFloat:
4852 case Primitive::kPrimDouble:
4853 default:
4854 LOG(FATAL) << "Unreachable type " << type;
4855 UNREACHABLE();
4856 }
4857}
4858
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004859void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004860 bool object_array_get_with_read_barrier =
4861 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004862 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004863 new (GetGraph()->GetArena()) LocationSummary(instruction,
4864 object_array_get_with_read_barrier ?
4865 LocationSummary::kCallOnSlowPath :
4866 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01004867 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004868 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01004869 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004870 locations->SetInAt(0, Location::RequiresRegister());
4871 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004872 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4873 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4874 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004875 // The output overlaps in the case of an object array get with
4876 // read barriers enabled: we do not want the move to overwrite the
4877 // array's location, as we need it to emit the read barrier.
4878 locations->SetOut(
4879 Location::RequiresRegister(),
4880 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004881 }
Roland Levillainc9285912015-12-18 10:38:42 +00004882 // We need a temporary register for the read barrier marking slow
4883 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
jessicahandojo05765752016-09-09 19:01:32 -07004884 // Also need for String compression feature.
4885 if ((object_array_get_with_read_barrier && kUseBakerReadBarrier)
4886 || (mirror::kUseStringCompression && instruction->IsStringCharAt())) {
Roland Levillainc9285912015-12-18 10:38:42 +00004887 locations->AddTemp(Location::RequiresRegister());
4888 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004889}
4890
4891void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4892 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004893 Location obj_loc = locations->InAt(0);
4894 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004895 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00004896 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01004897 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Roland Levillainc9285912015-12-18 10:38:42 +00004898 Primitive::Type type = instruction->GetType();
jessicahandojo05765752016-09-09 19:01:32 -07004899 const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
4900 instruction->IsStringCharAt();
Artem Serov328429f2016-07-06 16:23:04 +01004901 HInstruction* array_instr = instruction->GetArray();
4902 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Artem Serov6c916792016-07-11 14:02:34 +01004903
Roland Levillain4d027112015-07-01 15:41:14 +01004904 switch (type) {
Artem Serov6c916792016-07-11 14:02:34 +01004905 case Primitive::kPrimBoolean:
4906 case Primitive::kPrimByte:
4907 case Primitive::kPrimShort:
4908 case Primitive::kPrimChar:
Roland Levillainc9285912015-12-18 10:38:42 +00004909 case Primitive::kPrimInt: {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01004910 Register length;
4911 if (maybe_compressed_char_at) {
4912 length = locations->GetTemp(0).AsRegister<Register>();
4913 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
4914 __ LoadFromOffset(kLoadWord, length, obj, count_offset);
4915 codegen_->MaybeRecordImplicitNullCheck(instruction);
4916 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004917 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01004918 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
jessicahandojo05765752016-09-09 19:01:32 -07004919 if (maybe_compressed_char_at) {
jessicahandojo05765752016-09-09 19:01:32 -07004920 Label uncompressed_load, done;
Vladimir Markofdaf0f42016-10-13 19:29:53 +01004921 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
4922 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
4923 "Expecting 0=compressed, 1=uncompressed");
4924 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07004925 __ LoadFromOffset(kLoadUnsignedByte,
4926 out_loc.AsRegister<Register>(),
4927 obj,
4928 data_offset + const_index);
4929 __ b(&done);
4930 __ Bind(&uncompressed_load);
4931 __ LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
4932 out_loc.AsRegister<Register>(),
4933 obj,
4934 data_offset + (const_index << 1));
4935 __ Bind(&done);
4936 } else {
4937 uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
Artem Serov6c916792016-07-11 14:02:34 +01004938
jessicahandojo05765752016-09-09 19:01:32 -07004939 LoadOperandType load_type = GetLoadOperandType(type);
4940 __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
4941 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004942 } else {
Artem Serov328429f2016-07-06 16:23:04 +01004943 Register temp = IP;
4944
4945 if (has_intermediate_address) {
4946 // We do not need to compute the intermediate address from the array: the
4947 // input instruction has done it already. See the comment in
4948 // `TryExtractArrayAccessAddress()`.
4949 if (kIsDebugBuild) {
4950 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
4951 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
4952 }
4953 temp = obj;
4954 } else {
4955 __ add(temp, obj, ShifterOperand(data_offset));
4956 }
jessicahandojo05765752016-09-09 19:01:32 -07004957 if (maybe_compressed_char_at) {
4958 Label uncompressed_load, done;
Vladimir Markofdaf0f42016-10-13 19:29:53 +01004959 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
4960 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
4961 "Expecting 0=compressed, 1=uncompressed");
4962 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07004963 __ ldrb(out_loc.AsRegister<Register>(),
4964 Address(temp, index.AsRegister<Register>(), Shift::LSL, 0));
4965 __ b(&done);
4966 __ Bind(&uncompressed_load);
4967 __ ldrh(out_loc.AsRegister<Register>(),
4968 Address(temp, index.AsRegister<Register>(), Shift::LSL, 1));
4969 __ Bind(&done);
4970 } else {
4971 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
4972 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004973 }
4974 break;
4975 }
4976
Roland Levillainc9285912015-12-18 10:38:42 +00004977 case Primitive::kPrimNot: {
Roland Levillain19c54192016-11-04 13:44:09 +00004978 // The read barrier instrumentation of object ArrayGet
4979 // instructions does not support the HIntermediateAddress
4980 // instruction.
4981 DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
4982
Roland Levillainc9285912015-12-18 10:38:42 +00004983 static_assert(
4984 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4985 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00004986 // /* HeapReference<Object> */ out =
4987 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
4988 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4989 Location temp = locations->GetTemp(0);
4990 // Note that a potential implicit null check is handled in this
4991 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
4992 codegen_->GenerateArrayLoadWithBakerReadBarrier(
4993 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
4994 } else {
4995 Register out = out_loc.AsRegister<Register>();
4996 if (index.IsConstant()) {
4997 size_t offset =
4998 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4999 __ LoadFromOffset(kLoadWord, out, obj, offset);
5000 codegen_->MaybeRecordImplicitNullCheck(instruction);
5001 // If read barriers are enabled, emit read barriers other than
5002 // Baker's using a slow path (and also unpoison the loaded
5003 // reference, if heap poisoning is enabled).
5004 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
5005 } else {
Artem Serov328429f2016-07-06 16:23:04 +01005006 Register temp = IP;
5007
5008 if (has_intermediate_address) {
5009 // We do not need to compute the intermediate address from the array: the
5010 // input instruction has done it already. See the comment in
5011 // `TryExtractArrayAccessAddress()`.
5012 if (kIsDebugBuild) {
5013 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5014 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
5015 }
5016 temp = obj;
5017 } else {
5018 __ add(temp, obj, ShifterOperand(data_offset));
5019 }
5020 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
Artem Serov6c916792016-07-11 14:02:34 +01005021
Roland Levillainc9285912015-12-18 10:38:42 +00005022 codegen_->MaybeRecordImplicitNullCheck(instruction);
5023 // If read barriers are enabled, emit read barriers other than
5024 // Baker's using a slow path (and also unpoison the loaded
5025 // reference, if heap poisoning is enabled).
5026 codegen_->MaybeGenerateReadBarrierSlow(
5027 instruction, out_loc, out_loc, obj_loc, data_offset, index);
5028 }
5029 }
5030 break;
5031 }
5032
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005033 case Primitive::kPrimLong: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005034 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005035 size_t offset =
5036 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00005037 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005038 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005039 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00005040 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005041 }
5042 break;
5043 }
5044
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005045 case Primitive::kPrimFloat: {
Roland Levillainc9285912015-12-18 10:38:42 +00005046 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005047 if (index.IsConstant()) {
5048 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00005049 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005050 } else {
5051 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00005052 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005053 }
5054 break;
5055 }
5056
5057 case Primitive::kPrimDouble: {
Roland Levillainc9285912015-12-18 10:38:42 +00005058 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005059 if (index.IsConstant()) {
5060 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00005061 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005062 } else {
5063 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00005064 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005065 }
5066 break;
5067 }
5068
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005069 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01005070 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005071 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005072 }
Roland Levillain4d027112015-07-01 15:41:14 +01005073
5074 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00005075 // Potential implicit null checks, in the case of reference
5076 // arrays, are handled in the previous switch statement.
jessicahandojo05765752016-09-09 19:01:32 -07005077 } else if (!maybe_compressed_char_at) {
Roland Levillainc9285912015-12-18 10:38:42 +00005078 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01005079 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005080}
5081
5082void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005083 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005084
5085 bool needs_write_barrier =
5086 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00005087 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005088
Nicolas Geoffray39468442014-09-02 15:17:15 +01005089 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005090 instruction,
Vladimir Marko8d49fd72016-08-25 15:20:47 +01005091 may_need_runtime_call_for_type_check ?
Roland Levillain3b359c72015-11-17 19:35:12 +00005092 LocationSummary::kCallOnSlowPath :
5093 LocationSummary::kNoCall);
5094
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005095 locations->SetInAt(0, Location::RequiresRegister());
5096 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
5097 if (Primitive::IsFloatingPointType(value_type)) {
5098 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005099 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005100 locations->SetInAt(2, Location::RequiresRegister());
5101 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005102 if (needs_write_barrier) {
5103 // Temporary registers for the write barrier.
5104 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00005105 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005106 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005107}
5108
5109void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
5110 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005111 Location array_loc = locations->InAt(0);
5112 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005113 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01005114 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00005115 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005116 bool needs_write_barrier =
5117 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Artem Serov6c916792016-07-11 14:02:34 +01005118 uint32_t data_offset =
5119 mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
5120 Location value_loc = locations->InAt(2);
Artem Serov328429f2016-07-06 16:23:04 +01005121 HInstruction* array_instr = instruction->GetArray();
5122 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005123
5124 switch (value_type) {
5125 case Primitive::kPrimBoolean:
Artem Serov6c916792016-07-11 14:02:34 +01005126 case Primitive::kPrimByte:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005127 case Primitive::kPrimShort:
Artem Serov6c916792016-07-11 14:02:34 +01005128 case Primitive::kPrimChar:
5129 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005130 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01005131 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
5132 uint32_t full_offset =
5133 data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
5134 StoreOperandType store_type = GetStoreOperandType(value_type);
5135 __ StoreToOffset(store_type, value_loc.AsRegister<Register>(), array, full_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005136 } else {
Artem Serov328429f2016-07-06 16:23:04 +01005137 Register temp = IP;
5138
5139 if (has_intermediate_address) {
5140 // We do not need to compute the intermediate address from the array: the
5141 // input instruction has done it already. See the comment in
5142 // `TryExtractArrayAccessAddress()`.
5143 if (kIsDebugBuild) {
5144 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5145 DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
5146 }
5147 temp = array;
5148 } else {
5149 __ add(temp, array, ShifterOperand(data_offset));
5150 }
Artem Serov6c916792016-07-11 14:02:34 +01005151 codegen_->StoreToShiftedRegOffset(value_type,
5152 value_loc,
Artem Serov328429f2016-07-06 16:23:04 +01005153 temp,
Artem Serov6c916792016-07-11 14:02:34 +01005154 index.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005155 }
5156 break;
5157 }
5158
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005159 case Primitive::kPrimNot: {
Roland Levillain3b359c72015-11-17 19:35:12 +00005160 Register value = value_loc.AsRegister<Register>();
Artem Serov328429f2016-07-06 16:23:04 +01005161 // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
5162 // See the comment in instruction_simplifier_shared.cc.
5163 DCHECK(!has_intermediate_address);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005164
5165 if (instruction->InputAt(2)->IsNullConstant()) {
5166 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005167 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005168 size_t offset =
5169 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Artem Serov6c916792016-07-11 14:02:34 +01005170 __ StoreToOffset(kStoreWord, value, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005171 } else {
5172 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01005173 __ add(IP, array, ShifterOperand(data_offset));
5174 codegen_->StoreToShiftedRegOffset(value_type,
5175 value_loc,
5176 IP,
5177 index.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005178 }
Roland Levillain1407ee72016-01-08 15:56:19 +00005179 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00005180 DCHECK(!needs_write_barrier);
5181 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005182 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005183 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005184
5185 DCHECK(needs_write_barrier);
Roland Levillain16d9f942016-08-25 17:27:56 +01005186 Location temp1_loc = locations->GetTemp(0);
5187 Register temp1 = temp1_loc.AsRegister<Register>();
5188 Location temp2_loc = locations->GetTemp(1);
5189 Register temp2 = temp2_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005190 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5191 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5192 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5193 Label done;
Artem Serovf4d6aee2016-07-11 10:41:45 +01005194 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005195
Roland Levillain3b359c72015-11-17 19:35:12 +00005196 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005197 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
5198 codegen_->AddSlowPath(slow_path);
5199 if (instruction->GetValueCanBeNull()) {
5200 Label non_zero;
5201 __ CompareAndBranchIfNonZero(value, &non_zero);
5202 if (index.IsConstant()) {
5203 size_t offset =
5204 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5205 __ StoreToOffset(kStoreWord, value, array, offset);
5206 } else {
5207 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01005208 __ add(IP, array, ShifterOperand(data_offset));
5209 codegen_->StoreToShiftedRegOffset(value_type,
5210 value_loc,
5211 IP,
5212 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005213 }
5214 codegen_->MaybeRecordImplicitNullCheck(instruction);
5215 __ b(&done);
5216 __ Bind(&non_zero);
5217 }
5218
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005219 // Note that when read barriers are enabled, the type checks
5220 // are performed without read barriers. This is fine, even in
5221 // the case where a class object is in the from-space after
5222 // the flip, as a comparison involving such a type would not
5223 // produce a false positive; it may of course produce a false
5224 // negative, in which case we would take the ArraySet slow
5225 // path.
Roland Levillain16d9f942016-08-25 17:27:56 +01005226
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005227 // /* HeapReference<Class> */ temp1 = array->klass_
5228 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
5229 codegen_->MaybeRecordImplicitNullCheck(instruction);
5230 __ MaybeUnpoisonHeapReference(temp1);
Roland Levillain16d9f942016-08-25 17:27:56 +01005231
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005232 // /* HeapReference<Class> */ temp1 = temp1->component_type_
5233 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
5234 // /* HeapReference<Class> */ temp2 = value->klass_
5235 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
5236 // If heap poisoning is enabled, no need to unpoison `temp1`
5237 // nor `temp2`, as we are comparing two poisoned references.
5238 __ cmp(temp1, ShifterOperand(temp2));
Roland Levillain16d9f942016-08-25 17:27:56 +01005239
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005240 if (instruction->StaticTypeOfArrayIsObjectArray()) {
5241 Label do_put;
5242 __ b(&do_put, EQ);
5243 // If heap poisoning is enabled, the `temp1` reference has
5244 // not been unpoisoned yet; unpoison it now.
Roland Levillain3b359c72015-11-17 19:35:12 +00005245 __ MaybeUnpoisonHeapReference(temp1);
5246
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005247 // /* HeapReference<Class> */ temp1 = temp1->super_class_
5248 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
5249 // If heap poisoning is enabled, no need to unpoison
5250 // `temp1`, as we are comparing against null below.
5251 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
5252 __ Bind(&do_put);
5253 } else {
5254 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005255 }
5256 }
5257
Artem Serov6c916792016-07-11 14:02:34 +01005258 Register source = value;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005259 if (kPoisonHeapReferences) {
5260 // Note that in the case where `value` is a null reference,
5261 // we do not enter this block, as a null reference does not
5262 // need poisoning.
5263 DCHECK_EQ(value_type, Primitive::kPrimNot);
5264 __ Mov(temp1, value);
5265 __ PoisonHeapReference(temp1);
5266 source = temp1;
5267 }
5268
5269 if (index.IsConstant()) {
5270 size_t offset =
5271 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5272 __ StoreToOffset(kStoreWord, source, array, offset);
5273 } else {
5274 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01005275
5276 __ add(IP, array, ShifterOperand(data_offset));
5277 codegen_->StoreToShiftedRegOffset(value_type,
5278 Location::RegisterLocation(source),
5279 IP,
5280 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005281 }
5282
Roland Levillain3b359c72015-11-17 19:35:12 +00005283 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005284 codegen_->MaybeRecordImplicitNullCheck(instruction);
5285 }
5286
5287 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
5288
5289 if (done.IsLinked()) {
5290 __ Bind(&done);
5291 }
5292
5293 if (slow_path != nullptr) {
5294 __ Bind(slow_path->GetExitLabel());
5295 }
5296
5297 break;
5298 }
5299
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005300 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005301 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005302 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005303 size_t offset =
5304 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005305 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005306 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005307 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005308 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005309 }
5310 break;
5311 }
5312
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005313 case Primitive::kPrimFloat: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005314 Location value = locations->InAt(2);
5315 DCHECK(value.IsFpuRegister());
5316 if (index.IsConstant()) {
5317 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005318 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005319 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005320 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005321 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
5322 }
5323 break;
5324 }
5325
5326 case Primitive::kPrimDouble: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005327 Location value = locations->InAt(2);
5328 DCHECK(value.IsFpuRegisterPair());
5329 if (index.IsConstant()) {
5330 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005331 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005332 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005333 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005334 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
5335 }
Calin Juravle77520bc2015-01-12 18:45:46 +00005336
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005337 break;
5338 }
5339
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005340 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005341 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005342 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005343 }
Calin Juravle77520bc2015-01-12 18:45:46 +00005344
Roland Levillain80e67092016-01-08 16:04:55 +00005345 // Objects are handled in the switch.
5346 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00005347 codegen_->MaybeRecordImplicitNullCheck(instruction);
5348 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005349}
5350
5351void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005352 LocationSummary* locations =
5353 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005354 locations->SetInAt(0, Location::RequiresRegister());
5355 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005356}
5357
5358void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
5359 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01005360 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00005361 Register obj = locations->InAt(0).AsRegister<Register>();
5362 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005363 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005364 codegen_->MaybeRecordImplicitNullCheck(instruction);
jessicahandojo05765752016-09-09 19:01:32 -07005365 // Mask out compression flag from String's array length.
5366 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005367 __ Lsr(out, out, 1u);
jessicahandojo05765752016-09-09 19:01:32 -07005368 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005369}
5370
Artem Serov328429f2016-07-06 16:23:04 +01005371void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
Artem Serov328429f2016-07-06 16:23:04 +01005372 LocationSummary* locations =
5373 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5374
5375 locations->SetInAt(0, Location::RequiresRegister());
5376 locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
5377 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5378}
5379
5380void InstructionCodeGeneratorARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
5381 LocationSummary* locations = instruction->GetLocations();
5382 Location out = locations->Out();
5383 Location first = locations->InAt(0);
5384 Location second = locations->InAt(1);
5385
Artem Serov328429f2016-07-06 16:23:04 +01005386 if (second.IsRegister()) {
5387 __ add(out.AsRegister<Register>(),
5388 first.AsRegister<Register>(),
5389 ShifterOperand(second.AsRegister<Register>()));
5390 } else {
5391 __ AddConstant(out.AsRegister<Register>(),
5392 first.AsRegister<Register>(),
5393 second.GetConstant()->AsIntConstant()->GetValue());
5394 }
5395}
5396
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005397void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005398 RegisterSet caller_saves = RegisterSet::Empty();
5399 InvokeRuntimeCallingConvention calling_convention;
5400 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5401 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5402 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005403 locations->SetInAt(0, Location::RequiresRegister());
5404 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005405}
5406
5407void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
5408 LocationSummary* locations = instruction->GetLocations();
Artem Serovf4d6aee2016-07-11 10:41:45 +01005409 SlowPathCodeARM* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01005410 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005411 codegen_->AddSlowPath(slow_path);
5412
Roland Levillain271ab9c2014-11-27 15:23:57 +00005413 Register index = locations->InAt(0).AsRegister<Register>();
5414 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005415
5416 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01005417 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005418}
5419
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005420void CodeGeneratorARM::MarkGCCard(Register temp,
5421 Register card,
5422 Register object,
5423 Register value,
5424 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005425 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005426 if (can_be_null) {
5427 __ CompareAndBranchIfZero(value, &is_null);
5428 }
Andreas Gampe542451c2016-07-26 09:02:02 -07005429 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005430 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
5431 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005432 if (can_be_null) {
5433 __ Bind(&is_null);
5434 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005435}
5436
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005437void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005438 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005439}
5440
5441void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005442 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
5443}
5444
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005445void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Marko70e97462016-08-09 11:04:26 +01005446 LocationSummary* locations =
5447 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01005448 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005449}
5450
5451void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005452 HBasicBlock* block = instruction->GetBlock();
5453 if (block->GetLoopInformation() != nullptr) {
5454 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
5455 // The back edge will generate the suspend check.
5456 return;
5457 }
5458 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
5459 // The goto will generate the suspend check.
5460 return;
5461 }
5462 GenerateSuspendCheck(instruction, nullptr);
5463}
5464
5465void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
5466 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005467 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01005468 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
5469 if (slow_path == nullptr) {
5470 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
5471 instruction->SetSlowPath(slow_path);
5472 codegen_->AddSlowPath(slow_path);
5473 if (successor != nullptr) {
5474 DCHECK(successor->IsLoopHeader());
5475 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
5476 }
5477 } else {
5478 DCHECK_EQ(slow_path->GetSuccessor(), successor);
5479 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005480
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00005481 __ LoadFromOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07005482 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005483 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005484 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005485 __ Bind(slow_path->GetReturnLabel());
5486 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005487 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005488 __ b(slow_path->GetEntryLabel());
5489 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005490}
5491
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005492ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
5493 return codegen_->GetAssembler();
5494}
5495
5496void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005497 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005498 Location source = move->GetSource();
5499 Location destination = move->GetDestination();
5500
5501 if (source.IsRegister()) {
5502 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005503 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00005504 } else if (destination.IsFpuRegister()) {
5505 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005506 } else {
5507 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005508 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005509 SP, destination.GetStackIndex());
5510 }
5511 } else if (source.IsStackSlot()) {
5512 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005513 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005514 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005515 } else if (destination.IsFpuRegister()) {
5516 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005517 } else {
5518 DCHECK(destination.IsStackSlot());
5519 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
5520 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5521 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005522 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00005523 if (destination.IsRegister()) {
5524 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
5525 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005526 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005527 } else {
5528 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005529 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
5530 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005531 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005532 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005533 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
5534 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005535 } else if (destination.IsRegisterPair()) {
5536 DCHECK(ExpectedPairLayout(destination));
5537 __ LoadFromOffset(
5538 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
5539 } else {
5540 DCHECK(destination.IsFpuRegisterPair()) << destination;
5541 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5542 SP,
5543 source.GetStackIndex());
5544 }
5545 } else if (source.IsRegisterPair()) {
5546 if (destination.IsRegisterPair()) {
5547 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
5548 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00005549 } else if (destination.IsFpuRegisterPair()) {
5550 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5551 source.AsRegisterPairLow<Register>(),
5552 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005553 } else {
5554 DCHECK(destination.IsDoubleStackSlot()) << destination;
5555 DCHECK(ExpectedPairLayout(source));
5556 __ StoreToOffset(
5557 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
5558 }
5559 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00005560 if (destination.IsRegisterPair()) {
5561 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5562 destination.AsRegisterPairHigh<Register>(),
5563 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
5564 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005565 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5566 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
5567 } else {
5568 DCHECK(destination.IsDoubleStackSlot()) << destination;
5569 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
5570 SP,
5571 destination.GetStackIndex());
5572 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005573 } else {
5574 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00005575 HConstant* constant = source.GetConstant();
5576 if (constant->IsIntConstant() || constant->IsNullConstant()) {
5577 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005578 if (destination.IsRegister()) {
5579 __ LoadImmediate(destination.AsRegister<Register>(), value);
5580 } else {
5581 DCHECK(destination.IsStackSlot());
5582 __ LoadImmediate(IP, value);
5583 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5584 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005585 } else if (constant->IsLongConstant()) {
5586 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005587 if (destination.IsRegisterPair()) {
5588 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
5589 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005590 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005591 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005592 __ LoadImmediate(IP, Low32Bits(value));
5593 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5594 __ LoadImmediate(IP, High32Bits(value));
5595 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5596 }
5597 } else if (constant->IsDoubleConstant()) {
5598 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005599 if (destination.IsFpuRegisterPair()) {
5600 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005601 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005602 DCHECK(destination.IsDoubleStackSlot()) << destination;
5603 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005604 __ LoadImmediate(IP, Low32Bits(int_value));
5605 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5606 __ LoadImmediate(IP, High32Bits(int_value));
5607 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5608 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005609 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005610 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005611 float value = constant->AsFloatConstant()->GetValue();
5612 if (destination.IsFpuRegister()) {
5613 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
5614 } else {
5615 DCHECK(destination.IsStackSlot());
5616 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
5617 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5618 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005619 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005620 }
5621}
5622
5623void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
5624 __ Mov(IP, reg);
5625 __ LoadFromOffset(kLoadWord, reg, SP, mem);
5626 __ StoreToOffset(kStoreWord, IP, SP, mem);
5627}
5628
5629void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
5630 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5631 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5632 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5633 SP, mem1 + stack_offset);
5634 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5635 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5636 SP, mem2 + stack_offset);
5637 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5638}
5639
5640void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005641 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005642 Location source = move->GetSource();
5643 Location destination = move->GetDestination();
5644
5645 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005646 DCHECK_NE(source.AsRegister<Register>(), IP);
5647 DCHECK_NE(destination.AsRegister<Register>(), IP);
5648 __ Mov(IP, source.AsRegister<Register>());
5649 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5650 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005651 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005652 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005653 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005654 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005655 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5656 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005657 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005658 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005659 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005660 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005661 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005662 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005663 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005664 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005665 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5666 destination.AsRegisterPairHigh<Register>(),
5667 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005668 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005669 Register low_reg = source.IsRegisterPair()
5670 ? source.AsRegisterPairLow<Register>()
5671 : destination.AsRegisterPairLow<Register>();
5672 int mem = source.IsRegisterPair()
5673 ? destination.GetStackIndex()
5674 : source.GetStackIndex();
5675 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005676 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005677 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005678 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005679 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005680 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5681 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005682 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005683 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005684 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005685 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5686 DRegister reg = source.IsFpuRegisterPair()
5687 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5688 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5689 int mem = source.IsFpuRegisterPair()
5690 ? destination.GetStackIndex()
5691 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005692 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005693 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005694 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005695 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5696 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5697 : destination.AsFpuRegister<SRegister>();
5698 int mem = source.IsFpuRegister()
5699 ? destination.GetStackIndex()
5700 : source.GetStackIndex();
5701
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005702 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005703 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005704 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005705 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005706 Exchange(source.GetStackIndex(), destination.GetStackIndex());
5707 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005708 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005709 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005710 }
5711}
5712
5713void ParallelMoveResolverARM::SpillScratch(int reg) {
5714 __ Push(static_cast<Register>(reg));
5715}
5716
5717void ParallelMoveResolverARM::RestoreScratch(int reg) {
5718 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005719}
5720
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005721HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
5722 HLoadClass::LoadKind desired_class_load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005723 switch (desired_class_load_kind) {
5724 case HLoadClass::LoadKind::kReferrersClass:
5725 break;
5726 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5727 DCHECK(!GetCompilerOptions().GetCompilePic());
5728 break;
5729 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5730 DCHECK(GetCompilerOptions().GetCompilePic());
5731 break;
5732 case HLoadClass::LoadKind::kBootImageAddress:
5733 break;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005734 case HLoadClass::LoadKind::kBssEntry:
5735 DCHECK(!Runtime::Current()->UseJitCompilation());
5736 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005737 case HLoadClass::LoadKind::kJitTableAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005738 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005739 break;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005740 case HLoadClass::LoadKind::kDexCacheViaMethod:
5741 break;
5742 }
5743 return desired_class_load_kind;
5744}
5745
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005746void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00005747 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5748 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005749 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko41559982017-01-06 14:04:23 +00005750 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005751 cls,
5752 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko41559982017-01-06 14:04:23 +00005753 Location::RegisterLocation(R0));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005754 return;
5755 }
Vladimir Marko41559982017-01-06 14:04:23 +00005756 DCHECK(!cls->NeedsAccessCheck());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005757
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005758 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
5759 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005760 ? LocationSummary::kCallOnSlowPath
5761 : LocationSummary::kNoCall;
5762 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005763 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005764 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005765 }
5766
Vladimir Marko41559982017-01-06 14:04:23 +00005767 if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005768 locations->SetInAt(0, Location::RequiresRegister());
5769 }
5770 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005771}
5772
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005773// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5774// move.
5775void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00005776 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5777 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
5778 codegen_->GenerateLoadClassRuntimeCall(cls);
Calin Juravle580b6092015-10-06 17:35:58 +01005779 return;
5780 }
Vladimir Marko41559982017-01-06 14:04:23 +00005781 DCHECK(!cls->NeedsAccessCheck());
Calin Juravle580b6092015-10-06 17:35:58 +01005782
Vladimir Marko41559982017-01-06 14:04:23 +00005783 LocationSummary* locations = cls->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005784 Location out_loc = locations->Out();
5785 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005786
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005787 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
5788 ? kWithoutReadBarrier
5789 : kCompilerReadBarrierOption;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005790 bool generate_null_check = false;
Vladimir Marko41559982017-01-06 14:04:23 +00005791 switch (load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005792 case HLoadClass::LoadKind::kReferrersClass: {
5793 DCHECK(!cls->CanCallRuntime());
5794 DCHECK(!cls->MustGenerateClinitCheck());
5795 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5796 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005797 GenerateGcRootFieldLoad(cls,
5798 out_loc,
5799 current_method,
5800 ArtMethod::DeclaringClassOffset().Int32Value(),
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005801 read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005802 break;
5803 }
5804 case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005805 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005806 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005807 __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
5808 cls->GetTypeIndex()));
5809 break;
5810 }
5811 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005812 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005813 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005814 CodeGeneratorARM::PcRelativePatchInfo* labels =
5815 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
5816 __ BindTrackedLabel(&labels->movw_label);
5817 __ movw(out, /* placeholder */ 0u);
5818 __ BindTrackedLabel(&labels->movt_label);
5819 __ movt(out, /* placeholder */ 0u);
5820 __ BindTrackedLabel(&labels->add_pc_label);
5821 __ add(out, out, ShifterOperand(PC));
5822 break;
5823 }
5824 case HLoadClass::LoadKind::kBootImageAddress: {
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005825 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005826 uint32_t address = dchecked_integral_cast<uint32_t>(
5827 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
5828 DCHECK_NE(address, 0u);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005829 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5830 break;
5831 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005832 case HLoadClass::LoadKind::kBssEntry: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005833 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko1998cd02017-01-13 13:02:58 +00005834 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005835 __ BindTrackedLabel(&labels->movw_label);
5836 __ movw(out, /* placeholder */ 0u);
5837 __ BindTrackedLabel(&labels->movt_label);
5838 __ movt(out, /* placeholder */ 0u);
5839 __ BindTrackedLabel(&labels->add_pc_label);
5840 __ add(out, out, ShifterOperand(PC));
5841 GenerateGcRootFieldLoad(cls, out_loc, out, 0, kCompilerReadBarrierOption);
5842 generate_null_check = true;
5843 break;
5844 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005845 case HLoadClass::LoadKind::kJitTableAddress: {
5846 __ LoadLiteral(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
5847 cls->GetTypeIndex(),
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005848 cls->GetClass()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005849 // /* GcRoot<mirror::Class> */ out = *out
5850 GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005851 break;
5852 }
Vladimir Marko41559982017-01-06 14:04:23 +00005853 case HLoadClass::LoadKind::kDexCacheViaMethod:
5854 LOG(FATAL) << "UNREACHABLE";
5855 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005856 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005857
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005858 if (generate_null_check || cls->MustGenerateClinitCheck()) {
5859 DCHECK(cls->CanCallRuntime());
Artem Serovf4d6aee2016-07-11 10:41:45 +01005860 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005861 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5862 codegen_->AddSlowPath(slow_path);
5863 if (generate_null_check) {
5864 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5865 }
5866 if (cls->MustGenerateClinitCheck()) {
5867 GenerateClassInitializationCheck(slow_path, out);
5868 } else {
5869 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005870 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005871 }
5872}
5873
5874void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5875 LocationSummary* locations =
5876 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5877 locations->SetInAt(0, Location::RequiresRegister());
5878 if (check->HasUses()) {
5879 locations->SetOut(Location::SameAsFirstInput());
5880 }
5881}
5882
5883void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005884 // We assume the class is not null.
Artem Serovf4d6aee2016-07-11 10:41:45 +01005885 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005886 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005887 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005888 GenerateClassInitializationCheck(slow_path,
5889 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005890}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005891
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005892void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Artem Serovf4d6aee2016-07-11 10:41:45 +01005893 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005894 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5895 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5896 __ b(slow_path->GetEntryLabel(), LT);
5897 // Even if the initialized flag is set, we may be in a situation where caches are not synced
5898 // properly. Therefore, we do a memory fence.
5899 __ dmb(ISH);
5900 __ Bind(slow_path->GetExitLabel());
5901}
5902
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005903HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
5904 HLoadString::LoadKind desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005905 switch (desired_string_load_kind) {
5906 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5907 DCHECK(!GetCompilerOptions().GetCompilePic());
5908 break;
5909 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5910 DCHECK(GetCompilerOptions().GetCompilePic());
5911 break;
5912 case HLoadString::LoadKind::kBootImageAddress:
5913 break;
Vladimir Markoaad75c62016-10-03 08:46:48 +00005914 case HLoadString::LoadKind::kBssEntry:
Calin Juravleffc87072016-04-20 14:22:09 +01005915 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005916 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005917 case HLoadString::LoadKind::kJitTableAddress:
5918 DCHECK(Runtime::Current()->UseJitCompilation());
5919 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005920 case HLoadString::LoadKind::kDexCacheViaMethod:
5921 break;
5922 }
5923 return desired_string_load_kind;
5924}
5925
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005926void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005927 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005928 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005929 HLoadString::LoadKind load_kind = load->GetLoadKind();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07005930 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07005931 locations->SetOut(Location::RegisterLocation(R0));
5932 } else {
5933 locations->SetOut(Location::RequiresRegister());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005934 if (load_kind == HLoadString::LoadKind::kBssEntry) {
5935 if (!kUseReadBarrier || kUseBakerReadBarrier) {
5936 // Rely on the pResolveString and/or marking to save everything, including temps.
5937 // Note that IP may theoretically be clobbered by saving/restoring the live register
5938 // (only one thanks to the custom calling convention), so we request a different temp.
5939 locations->AddTemp(Location::RequiresRegister());
5940 RegisterSet caller_saves = RegisterSet::Empty();
5941 InvokeRuntimeCallingConvention calling_convention;
5942 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5943 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
5944 // that the the kPrimNot result register is the same as the first argument register.
5945 locations->SetCustomSlowPathCallerSaves(caller_saves);
5946 } else {
5947 // For non-Baker read barrier we have a temp-clobbering call.
5948 }
5949 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005950 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005951}
5952
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005953// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5954// move.
5955void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005956 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005957 Location out_loc = locations->Out();
5958 Register out = out_loc.AsRegister<Register>();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07005959 HLoadString::LoadKind load_kind = load->GetLoadKind();
Roland Levillain3b359c72015-11-17 19:35:12 +00005960
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07005961 switch (load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005962 case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005963 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005964 __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5965 load->GetStringIndex()));
5966 return; // No dex cache slow path.
5967 }
5968 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00005969 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005970 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005971 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005972 __ BindTrackedLabel(&labels->movw_label);
5973 __ movw(out, /* placeholder */ 0u);
5974 __ BindTrackedLabel(&labels->movt_label);
5975 __ movt(out, /* placeholder */ 0u);
5976 __ BindTrackedLabel(&labels->add_pc_label);
5977 __ add(out, out, ShifterOperand(PC));
5978 return; // No dex cache slow path.
5979 }
5980 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005981 uint32_t address = dchecked_integral_cast<uint32_t>(
5982 reinterpret_cast<uintptr_t>(load->GetString().Get()));
5983 DCHECK_NE(address, 0u);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005984 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5985 return; // No dex cache slow path.
5986 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00005987 case HLoadString::LoadKind::kBssEntry: {
5988 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005989 Register temp = locations->GetTemp(0).AsRegister<Register>();
Vladimir Markoaad75c62016-10-03 08:46:48 +00005990 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005991 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markoaad75c62016-10-03 08:46:48 +00005992 __ BindTrackedLabel(&labels->movw_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005993 __ movw(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005994 __ BindTrackedLabel(&labels->movt_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005995 __ movt(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005996 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005997 __ add(temp, temp, ShifterOperand(PC));
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005998 GenerateGcRootFieldLoad(load, out_loc, temp, /* offset */ 0, kCompilerReadBarrierOption);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005999 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
6000 codegen_->AddSlowPath(slow_path);
6001 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
6002 __ Bind(slow_path->GetExitLabel());
6003 return;
6004 }
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006005 case HLoadString::LoadKind::kJitTableAddress: {
6006 __ LoadLiteral(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00006007 load->GetStringIndex(),
6008 load->GetString()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006009 // /* GcRoot<mirror::String> */ out = *out
6010 GenerateGcRootFieldLoad(load, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
6011 return;
6012 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006013 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07006014 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006015 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006016
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006017 // TODO: Consider re-adding the compiler code to do string dex cache lookup again.
6018 DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
6019 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006020 DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
Andreas Gampe8a0128a2016-11-28 07:38:35 -08006021 __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006022 codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
6023 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00006024}
6025
David Brazdilcb1c0552015-08-04 16:22:25 +01006026static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07006027 return Thread::ExceptionOffset<kArmPointerSize>().Int32Value();
David Brazdilcb1c0552015-08-04 16:22:25 +01006028}
6029
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006030void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
6031 LocationSummary* locations =
6032 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
6033 locations->SetOut(Location::RequiresRegister());
6034}
6035
6036void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006037 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01006038 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
6039}
6040
6041void LocationsBuilderARM::VisitClearException(HClearException* clear) {
6042 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
6043}
6044
6045void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006046 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01006047 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006048}
6049
6050void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
6051 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006052 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006053 InvokeRuntimeCallingConvention calling_convention;
6054 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6055}
6056
6057void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01006058 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00006059 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006060}
6061
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006062// Temp is used for read barrier.
6063static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
6064 if (kEmitCompilerReadBarrier &&
6065 (kUseBakerReadBarrier ||
6066 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
6067 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
6068 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
6069 return 1;
6070 }
6071 return 0;
6072}
6073
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006074// Interface case has 3 temps, one for holding the number of interfaces, one for the current
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006075// interface pointer, one for loading the current interface.
6076// The other checks have one temp for loading the object's class.
6077static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
6078 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
6079 return 3;
6080 }
6081 return 1 + NumberOfInstanceOfTemps(type_check_kind);
Roland Levillainc9285912015-12-18 10:38:42 +00006082}
6083
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006084void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006085 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00006086 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko70e97462016-08-09 11:04:26 +01006087 bool baker_read_barrier_slow_path = false;
Roland Levillain3b359c72015-11-17 19:35:12 +00006088 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006089 case TypeCheckKind::kExactCheck:
6090 case TypeCheckKind::kAbstractClassCheck:
6091 case TypeCheckKind::kClassHierarchyCheck:
6092 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00006093 call_kind =
6094 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Vladimir Marko70e97462016-08-09 11:04:26 +01006095 baker_read_barrier_slow_path = kUseBakerReadBarrier;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006096 break;
6097 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00006098 case TypeCheckKind::kUnresolvedCheck:
6099 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006100 call_kind = LocationSummary::kCallOnSlowPath;
6101 break;
6102 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006103
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006104 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Vladimir Marko70e97462016-08-09 11:04:26 +01006105 if (baker_read_barrier_slow_path) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006106 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01006107 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006108 locations->SetInAt(0, Location::RequiresRegister());
6109 locations->SetInAt(1, Location::RequiresRegister());
6110 // The "out" register is used as a temporary, so it overlaps with the inputs.
6111 // Note that TypeCheckSlowPathARM uses this register too.
6112 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006113 locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006114}
6115
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006116void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00006117 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006118 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006119 Location obj_loc = locations->InAt(0);
6120 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00006121 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00006122 Location out_loc = locations->Out();
6123 Register out = out_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006124 const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
6125 DCHECK_LE(num_temps, 1u);
6126 Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006127 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006128 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6129 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6130 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00006131 Label done, zero;
Artem Serovf4d6aee2016-07-11 10:41:45 +01006132 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006133
6134 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006135 // avoid null check if we know obj is not null.
6136 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00006137 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006138 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006139
Roland Levillainc9285912015-12-18 10:38:42 +00006140 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006141 case TypeCheckKind::kExactCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006142 // /* HeapReference<Class> */ out = obj->klass_
6143 GenerateReferenceLoadTwoRegisters(instruction,
6144 out_loc,
6145 obj_loc,
6146 class_offset,
6147 maybe_temp_loc,
6148 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006149 __ cmp(out, ShifterOperand(cls));
6150 // Classes must be equal for the instanceof to succeed.
6151 __ b(&zero, NE);
6152 __ LoadImmediate(out, 1);
6153 __ b(&done);
6154 break;
6155 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006156
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006157 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006158 // /* HeapReference<Class> */ out = obj->klass_
6159 GenerateReferenceLoadTwoRegisters(instruction,
6160 out_loc,
6161 obj_loc,
6162 class_offset,
6163 maybe_temp_loc,
6164 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006165 // If the class is abstract, we eagerly fetch the super class of the
6166 // object to avoid doing a comparison we know will fail.
6167 Label loop;
6168 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00006169 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006170 GenerateReferenceLoadOneRegister(instruction,
6171 out_loc,
6172 super_offset,
6173 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006174 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006175 // If `out` is null, we use it for the result, and jump to `done`.
6176 __ CompareAndBranchIfZero(out, &done);
6177 __ cmp(out, ShifterOperand(cls));
6178 __ b(&loop, NE);
6179 __ LoadImmediate(out, 1);
6180 if (zero.IsLinked()) {
6181 __ b(&done);
6182 }
6183 break;
6184 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006185
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006186 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006187 // /* HeapReference<Class> */ out = obj->klass_
6188 GenerateReferenceLoadTwoRegisters(instruction,
6189 out_loc,
6190 obj_loc,
6191 class_offset,
6192 maybe_temp_loc,
6193 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006194 // Walk over the class hierarchy to find a match.
6195 Label loop, success;
6196 __ Bind(&loop);
6197 __ cmp(out, ShifterOperand(cls));
6198 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00006199 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006200 GenerateReferenceLoadOneRegister(instruction,
6201 out_loc,
6202 super_offset,
6203 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006204 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006205 __ CompareAndBranchIfNonZero(out, &loop);
6206 // If `out` is null, we use it for the result, and jump to `done`.
6207 __ b(&done);
6208 __ Bind(&success);
6209 __ LoadImmediate(out, 1);
6210 if (zero.IsLinked()) {
6211 __ b(&done);
6212 }
6213 break;
6214 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006215
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006216 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006217 // /* HeapReference<Class> */ out = obj->klass_
6218 GenerateReferenceLoadTwoRegisters(instruction,
6219 out_loc,
6220 obj_loc,
6221 class_offset,
6222 maybe_temp_loc,
6223 kCompilerReadBarrierOption);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006224 // Do an exact check.
6225 Label exact_check;
6226 __ cmp(out, ShifterOperand(cls));
6227 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00006228 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00006229 // /* HeapReference<Class> */ out = out->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006230 GenerateReferenceLoadOneRegister(instruction,
6231 out_loc,
6232 component_offset,
6233 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006234 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006235 // If `out` is null, we use it for the result, and jump to `done`.
6236 __ CompareAndBranchIfZero(out, &done);
6237 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
6238 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
6239 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006240 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006241 __ LoadImmediate(out, 1);
6242 __ b(&done);
6243 break;
6244 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006245
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006246 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006247 // No read barrier since the slow path will retry upon failure.
6248 // /* HeapReference<Class> */ out = obj->klass_
6249 GenerateReferenceLoadTwoRegisters(instruction,
6250 out_loc,
6251 obj_loc,
6252 class_offset,
6253 maybe_temp_loc,
6254 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006255 __ cmp(out, ShifterOperand(cls));
6256 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00006257 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
6258 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006259 codegen_->AddSlowPath(slow_path);
6260 __ b(slow_path->GetEntryLabel(), NE);
6261 __ LoadImmediate(out, 1);
6262 if (zero.IsLinked()) {
6263 __ b(&done);
6264 }
6265 break;
6266 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006267
Calin Juravle98893e12015-10-02 21:05:03 +01006268 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00006269 case TypeCheckKind::kInterfaceCheck: {
6270 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006271 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00006272 // cases.
6273 //
6274 // We cannot directly call the InstanceofNonTrivial runtime
6275 // entry point without resorting to a type checking slow path
6276 // here (i.e. by calling InvokeRuntime directly), as it would
6277 // require to assign fixed registers for the inputs of this
6278 // HInstanceOf instruction (following the runtime calling
6279 // convention), which might be cluttered by the potential first
6280 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00006281 //
6282 // TODO: Introduce a new runtime entry point taking the object
6283 // to test (instead of its class) as argument, and let it deal
6284 // with the read barrier issues. This will let us refactor this
6285 // case of the `switch` code as it was previously (with a direct
6286 // call to the runtime not using a type checking slow path).
6287 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00006288 DCHECK(locations->OnlyCallsOnSlowPath());
6289 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
6290 /* is_fatal */ false);
6291 codegen_->AddSlowPath(slow_path);
6292 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006293 if (zero.IsLinked()) {
6294 __ b(&done);
6295 }
6296 break;
6297 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006298 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006299
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006300 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006301 __ Bind(&zero);
6302 __ LoadImmediate(out, 0);
6303 }
6304
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006305 if (done.IsLinked()) {
6306 __ Bind(&done);
6307 }
6308
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006309 if (slow_path != nullptr) {
6310 __ Bind(slow_path->GetExitLabel());
6311 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006312}
6313
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006314void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006315 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
6316 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
6317
Roland Levillain3b359c72015-11-17 19:35:12 +00006318 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
6319 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006320 case TypeCheckKind::kExactCheck:
6321 case TypeCheckKind::kAbstractClassCheck:
6322 case TypeCheckKind::kClassHierarchyCheck:
6323 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00006324 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
6325 LocationSummary::kCallOnSlowPath :
6326 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006327 break;
6328 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00006329 case TypeCheckKind::kUnresolvedCheck:
6330 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006331 call_kind = LocationSummary::kCallOnSlowPath;
6332 break;
6333 }
6334
Roland Levillain3b359c72015-11-17 19:35:12 +00006335 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
6336 locations->SetInAt(0, Location::RequiresRegister());
6337 locations->SetInAt(1, Location::RequiresRegister());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006338 locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006339}
6340
6341void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00006342 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006343 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006344 Location obj_loc = locations->InAt(0);
6345 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00006346 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00006347 Location temp_loc = locations->GetTemp(0);
6348 Register temp = temp_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006349 const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
6350 DCHECK_LE(num_temps, 3u);
6351 Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
6352 Location maybe_temp3_loc = (num_temps >= 3) ? locations->GetTemp(2) : Location::NoLocation();
6353 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6354 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6355 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6356 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
6357 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
6358 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
6359 const uint32_t object_array_data_offset =
6360 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006361
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006362 // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
6363 // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
6364 // read barriers is done for performance and code size reasons.
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006365 bool is_type_check_slow_path_fatal = false;
6366 if (!kEmitCompilerReadBarrier) {
6367 is_type_check_slow_path_fatal =
6368 (type_check_kind == TypeCheckKind::kExactCheck ||
6369 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
6370 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
6371 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
6372 !instruction->CanThrowIntoCatchBlock();
6373 }
Artem Serovf4d6aee2016-07-11 10:41:45 +01006374 SlowPathCodeARM* type_check_slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00006375 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
6376 is_type_check_slow_path_fatal);
6377 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006378
6379 Label done;
6380 // Avoid null check if we know obj is not null.
6381 if (instruction->MustDoNullCheck()) {
6382 __ CompareAndBranchIfZero(obj, &done);
6383 }
6384
Roland Levillain3b359c72015-11-17 19:35:12 +00006385 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006386 case TypeCheckKind::kExactCheck:
6387 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006388 // /* HeapReference<Class> */ temp = obj->klass_
6389 GenerateReferenceLoadTwoRegisters(instruction,
6390 temp_loc,
6391 obj_loc,
6392 class_offset,
6393 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006394 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006395
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006396 __ cmp(temp, ShifterOperand(cls));
6397 // Jump to slow path for throwing the exception or doing a
6398 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00006399 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006400 break;
6401 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006402
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006403 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006404 // /* HeapReference<Class> */ temp = obj->klass_
6405 GenerateReferenceLoadTwoRegisters(instruction,
6406 temp_loc,
6407 obj_loc,
6408 class_offset,
6409 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006410 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006411
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006412 // If the class is abstract, we eagerly fetch the super class of the
6413 // object to avoid doing a comparison we know will fail.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006414 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006415 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00006416 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006417 GenerateReferenceLoadOneRegister(instruction,
6418 temp_loc,
6419 super_offset,
6420 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006421 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00006422
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006423 // If the class reference currently in `temp` is null, jump to the slow path to throw the
6424 // exception.
6425 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
Roland Levillain3b359c72015-11-17 19:35:12 +00006426
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006427 // Otherwise, compare the classes.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006428 __ cmp(temp, ShifterOperand(cls));
6429 __ b(&loop, NE);
6430 break;
6431 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006432
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006433 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006434 // /* HeapReference<Class> */ temp = obj->klass_
6435 GenerateReferenceLoadTwoRegisters(instruction,
6436 temp_loc,
6437 obj_loc,
6438 class_offset,
6439 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006440 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006441
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006442 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006443 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006444 __ Bind(&loop);
6445 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006446 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00006447
Roland Levillain3b359c72015-11-17 19:35:12 +00006448 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006449 GenerateReferenceLoadOneRegister(instruction,
6450 temp_loc,
6451 super_offset,
6452 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006453 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00006454
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006455 // If the class reference currently in `temp` is null, jump to the slow path to throw the
6456 // exception.
6457 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
6458 // Otherwise, jump to the beginning of the loop.
6459 __ b(&loop);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006460 break;
6461 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006462
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006463 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006464 // /* HeapReference<Class> */ temp = obj->klass_
6465 GenerateReferenceLoadTwoRegisters(instruction,
6466 temp_loc,
6467 obj_loc,
6468 class_offset,
6469 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006470 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006471
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006472 // Do an exact check.
6473 __ cmp(temp, ShifterOperand(cls));
6474 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00006475
6476 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00006477 // /* HeapReference<Class> */ temp = temp->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006478 GenerateReferenceLoadOneRegister(instruction,
6479 temp_loc,
6480 component_offset,
6481 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006482 kWithoutReadBarrier);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006483 // If the component type is null, jump to the slow path to throw the exception.
6484 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
6485 // Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type`
6486 // to further check that this component type is not a primitive type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006487 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00006488 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006489 __ CompareAndBranchIfNonZero(temp, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006490 break;
6491 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006492
Calin Juravle98893e12015-10-02 21:05:03 +01006493 case TypeCheckKind::kUnresolvedCheck:
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006494 // We always go into the type check slow path for the unresolved check case.
Roland Levillain3b359c72015-11-17 19:35:12 +00006495 // We cannot directly call the CheckCast runtime entry point
6496 // without resorting to a type checking slow path here (i.e. by
6497 // calling InvokeRuntime directly), as it would require to
6498 // assign fixed registers for the inputs of this HInstanceOf
6499 // instruction (following the runtime calling convention), which
6500 // might be cluttered by the potential first read barrier
6501 // emission at the beginning of this method.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006502
Roland Levillain3b359c72015-11-17 19:35:12 +00006503 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006504 break;
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006505
6506 case TypeCheckKind::kInterfaceCheck: {
6507 // Avoid read barriers to improve performance of the fast path. We can not get false
6508 // positives by doing this.
6509 // /* HeapReference<Class> */ temp = obj->klass_
6510 GenerateReferenceLoadTwoRegisters(instruction,
6511 temp_loc,
6512 obj_loc,
6513 class_offset,
6514 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006515 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006516
6517 // /* HeapReference<Class> */ temp = temp->iftable_
6518 GenerateReferenceLoadTwoRegisters(instruction,
6519 temp_loc,
6520 temp_loc,
6521 iftable_offset,
6522 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006523 kWithoutReadBarrier);
Mathieu Chartier6beced42016-11-15 15:51:31 -08006524 // Iftable is never null.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006525 __ ldr(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
Mathieu Chartier6beced42016-11-15 15:51:31 -08006526 // Loop through the iftable and check if any class matches.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006527 Label start_loop;
6528 __ Bind(&start_loop);
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08006529 __ CompareAndBranchIfZero(maybe_temp2_loc.AsRegister<Register>(),
6530 type_check_slow_path->GetEntryLabel());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006531 __ ldr(maybe_temp3_loc.AsRegister<Register>(), Address(temp, object_array_data_offset));
6532 __ MaybeUnpoisonHeapReference(maybe_temp3_loc.AsRegister<Register>());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006533 // Go to next interface.
6534 __ add(temp, temp, ShifterOperand(2 * kHeapReferenceSize));
6535 __ sub(maybe_temp2_loc.AsRegister<Register>(),
6536 maybe_temp2_loc.AsRegister<Register>(),
6537 ShifterOperand(2));
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08006538 // Compare the classes and continue the loop if they do not match.
6539 __ cmp(cls, ShifterOperand(maybe_temp3_loc.AsRegister<Register>()));
6540 __ b(&start_loop, NE);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006541 break;
6542 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006543 }
6544 __ Bind(&done);
6545
Roland Levillain3b359c72015-11-17 19:35:12 +00006546 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006547}
6548
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006549void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
6550 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006551 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006552 InvokeRuntimeCallingConvention calling_convention;
6553 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6554}
6555
6556void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01006557 codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
6558 instruction,
6559 instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00006560 if (instruction->IsEnter()) {
6561 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
6562 } else {
6563 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
6564 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006565}
6566
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006567void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
6568void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
6569void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006570
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006571void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006572 LocationSummary* locations =
6573 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6574 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6575 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006576 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006577 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006578 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00006579 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006580}
6581
6582void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
6583 HandleBitwiseOperation(instruction);
6584}
6585
6586void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
6587 HandleBitwiseOperation(instruction);
6588}
6589
6590void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
6591 HandleBitwiseOperation(instruction);
6592}
6593
Artem Serov7fc63502016-02-09 17:15:29 +00006594
6595void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
6596 LocationSummary* locations =
6597 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6598 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6599 || instruction->GetResultType() == Primitive::kPrimLong);
6600
6601 locations->SetInAt(0, Location::RequiresRegister());
6602 locations->SetInAt(1, Location::RequiresRegister());
6603 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6604}
6605
6606void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
6607 LocationSummary* locations = instruction->GetLocations();
6608 Location first = locations->InAt(0);
6609 Location second = locations->InAt(1);
6610 Location out = locations->Out();
6611
6612 if (instruction->GetResultType() == Primitive::kPrimInt) {
6613 Register first_reg = first.AsRegister<Register>();
6614 ShifterOperand second_reg(second.AsRegister<Register>());
6615 Register out_reg = out.AsRegister<Register>();
6616
6617 switch (instruction->GetOpKind()) {
6618 case HInstruction::kAnd:
6619 __ bic(out_reg, first_reg, second_reg);
6620 break;
6621 case HInstruction::kOr:
6622 __ orn(out_reg, first_reg, second_reg);
6623 break;
6624 // There is no EON on arm.
6625 case HInstruction::kXor:
6626 default:
6627 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
6628 UNREACHABLE();
6629 }
6630 return;
6631
6632 } else {
6633 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6634 Register first_low = first.AsRegisterPairLow<Register>();
6635 Register first_high = first.AsRegisterPairHigh<Register>();
6636 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6637 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6638 Register out_low = out.AsRegisterPairLow<Register>();
6639 Register out_high = out.AsRegisterPairHigh<Register>();
6640
6641 switch (instruction->GetOpKind()) {
6642 case HInstruction::kAnd:
6643 __ bic(out_low, first_low, second_low);
6644 __ bic(out_high, first_high, second_high);
6645 break;
6646 case HInstruction::kOr:
6647 __ orn(out_low, first_low, second_low);
6648 __ orn(out_high, first_high, second_high);
6649 break;
6650 // There is no EON on arm.
6651 case HInstruction::kXor:
6652 default:
6653 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
6654 UNREACHABLE();
6655 }
6656 }
6657}
6658
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006659void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
6660 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
6661 if (value == 0xffffffffu) {
6662 if (out != first) {
6663 __ mov(out, ShifterOperand(first));
6664 }
6665 return;
6666 }
6667 if (value == 0u) {
6668 __ mov(out, ShifterOperand(0));
6669 return;
6670 }
6671 ShifterOperand so;
6672 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
6673 __ and_(out, first, so);
6674 } else {
6675 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
6676 __ bic(out, first, ShifterOperand(~value));
6677 }
6678}
6679
6680void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
6681 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
6682 if (value == 0u) {
6683 if (out != first) {
6684 __ mov(out, ShifterOperand(first));
6685 }
6686 return;
6687 }
6688 if (value == 0xffffffffu) {
6689 __ mvn(out, ShifterOperand(0));
6690 return;
6691 }
6692 ShifterOperand so;
6693 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
6694 __ orr(out, first, so);
6695 } else {
6696 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
6697 __ orn(out, first, ShifterOperand(~value));
6698 }
6699}
6700
6701void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
6702 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
6703 if (value == 0u) {
6704 if (out != first) {
6705 __ mov(out, ShifterOperand(first));
6706 }
6707 return;
6708 }
6709 __ eor(out, first, ShifterOperand(value));
6710}
6711
Vladimir Marko59751a72016-08-05 14:37:27 +01006712void InstructionCodeGeneratorARM::GenerateAddLongConst(Location out,
6713 Location first,
6714 uint64_t value) {
6715 Register out_low = out.AsRegisterPairLow<Register>();
6716 Register out_high = out.AsRegisterPairHigh<Register>();
6717 Register first_low = first.AsRegisterPairLow<Register>();
6718 Register first_high = first.AsRegisterPairHigh<Register>();
6719 uint32_t value_low = Low32Bits(value);
6720 uint32_t value_high = High32Bits(value);
6721 if (value_low == 0u) {
6722 if (out_low != first_low) {
6723 __ mov(out_low, ShifterOperand(first_low));
6724 }
6725 __ AddConstant(out_high, first_high, value_high);
6726 return;
6727 }
6728 __ AddConstantSetFlags(out_low, first_low, value_low);
6729 ShifterOperand so;
6730 if (__ ShifterOperandCanHold(out_high, first_high, ADC, value_high, kCcDontCare, &so)) {
6731 __ adc(out_high, first_high, so);
6732 } else if (__ ShifterOperandCanHold(out_low, first_low, SBC, ~value_high, kCcDontCare, &so)) {
6733 __ sbc(out_high, first_high, so);
6734 } else {
6735 LOG(FATAL) << "Unexpected constant " << value_high;
6736 UNREACHABLE();
6737 }
6738}
6739
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006740void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
6741 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006742 Location first = locations->InAt(0);
6743 Location second = locations->InAt(1);
6744 Location out = locations->Out();
6745
6746 if (second.IsConstant()) {
6747 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
6748 uint32_t value_low = Low32Bits(value);
6749 if (instruction->GetResultType() == Primitive::kPrimInt) {
6750 Register first_reg = first.AsRegister<Register>();
6751 Register out_reg = out.AsRegister<Register>();
6752 if (instruction->IsAnd()) {
6753 GenerateAndConst(out_reg, first_reg, value_low);
6754 } else if (instruction->IsOr()) {
6755 GenerateOrrConst(out_reg, first_reg, value_low);
6756 } else {
6757 DCHECK(instruction->IsXor());
6758 GenerateEorConst(out_reg, first_reg, value_low);
6759 }
6760 } else {
6761 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6762 uint32_t value_high = High32Bits(value);
6763 Register first_low = first.AsRegisterPairLow<Register>();
6764 Register first_high = first.AsRegisterPairHigh<Register>();
6765 Register out_low = out.AsRegisterPairLow<Register>();
6766 Register out_high = out.AsRegisterPairHigh<Register>();
6767 if (instruction->IsAnd()) {
6768 GenerateAndConst(out_low, first_low, value_low);
6769 GenerateAndConst(out_high, first_high, value_high);
6770 } else if (instruction->IsOr()) {
6771 GenerateOrrConst(out_low, first_low, value_low);
6772 GenerateOrrConst(out_high, first_high, value_high);
6773 } else {
6774 DCHECK(instruction->IsXor());
6775 GenerateEorConst(out_low, first_low, value_low);
6776 GenerateEorConst(out_high, first_high, value_high);
6777 }
6778 }
6779 return;
6780 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006781
6782 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006783 Register first_reg = first.AsRegister<Register>();
6784 ShifterOperand second_reg(second.AsRegister<Register>());
6785 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006786 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006787 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006788 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006789 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006790 } else {
6791 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006792 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006793 }
6794 } else {
6795 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006796 Register first_low = first.AsRegisterPairLow<Register>();
6797 Register first_high = first.AsRegisterPairHigh<Register>();
6798 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6799 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6800 Register out_low = out.AsRegisterPairLow<Register>();
6801 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006802 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006803 __ and_(out_low, first_low, second_low);
6804 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006805 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006806 __ orr(out_low, first_low, second_low);
6807 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006808 } else {
6809 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006810 __ eor(out_low, first_low, second_low);
6811 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006812 }
6813 }
6814}
6815
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006816void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(
6817 HInstruction* instruction,
6818 Location out,
6819 uint32_t offset,
6820 Location maybe_temp,
6821 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00006822 Register out_reg = out.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006823 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006824 CHECK(kEmitCompilerReadBarrier);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006825 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006826 if (kUseBakerReadBarrier) {
6827 // Load with fast path based Baker's read barrier.
6828 // /* HeapReference<Object> */ out = *(out + offset)
6829 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006830 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006831 } else {
6832 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006833 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00006834 // in the following move operation, as we will need it for the
6835 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006836 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00006837 // /* HeapReference<Object> */ out = *(out + offset)
6838 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006839 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00006840 }
6841 } else {
6842 // Plain load with no read barrier.
6843 // /* HeapReference<Object> */ out = *(out + offset)
6844 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6845 __ MaybeUnpoisonHeapReference(out_reg);
6846 }
6847}
6848
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006849void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(
6850 HInstruction* instruction,
6851 Location out,
6852 Location obj,
6853 uint32_t offset,
6854 Location maybe_temp,
6855 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00006856 Register out_reg = out.AsRegister<Register>();
6857 Register obj_reg = obj.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006858 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006859 CHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00006860 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006861 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006862 // Load with fast path based Baker's read barrier.
6863 // /* HeapReference<Object> */ out = *(obj + offset)
6864 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006865 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006866 } else {
6867 // Load with slow path based read barrier.
6868 // /* HeapReference<Object> */ out = *(obj + offset)
6869 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6870 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6871 }
6872 } else {
6873 // Plain load with no read barrier.
6874 // /* HeapReference<Object> */ out = *(obj + offset)
6875 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6876 __ MaybeUnpoisonHeapReference(out_reg);
6877 }
6878}
6879
6880void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
6881 Location root,
6882 Register obj,
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006883 uint32_t offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006884 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00006885 Register root_reg = root.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006886 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006887 DCHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00006888 if (kUseBakerReadBarrier) {
6889 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6890 // Baker's read barrier are used:
6891 //
6892 // root = obj.field;
Mathieu Chartierfe814e82016-11-09 14:32:49 -08006893 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
6894 // if (temp != null) {
6895 // root = temp(root)
Roland Levillainc9285912015-12-18 10:38:42 +00006896 // }
6897
6898 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6899 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6900 static_assert(
6901 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6902 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6903 "have different sizes.");
6904 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6905 "art::mirror::CompressedReference<mirror::Object> and int32_t "
6906 "have different sizes.");
6907
Vladimir Marko953437b2016-08-24 08:30:46 +00006908 // Slow path marking the GC root `root`.
Mathieu Chartierfe814e82016-11-09 14:32:49 -08006909 Location temp = Location::RegisterLocation(LR);
Artem Serovf4d6aee2016-07-11 10:41:45 +01006910 SlowPathCodeARM* slow_path =
Mathieu Chartierfe814e82016-11-09 14:32:49 -08006911 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(
6912 instruction,
6913 root,
6914 /*entrypoint*/ temp);
Roland Levillainc9285912015-12-18 10:38:42 +00006915 codegen_->AddSlowPath(slow_path);
6916
Mathieu Chartierfe814e82016-11-09 14:32:49 -08006917 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
6918 const int32_t entry_point_offset =
6919 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(root.reg());
6920 // Loading the entrypoint does not require a load acquire since it is only changed when
6921 // threads are suspended or running a checkpoint.
6922 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
6923 // The entrypoint is null when the GC is not marking, this prevents one load compared to
6924 // checking GetIsGcMarking.
6925 __ CompareAndBranchIfNonZero(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
Roland Levillainc9285912015-12-18 10:38:42 +00006926 __ Bind(slow_path->GetExitLabel());
6927 } else {
6928 // GC root loaded through a slow path for read barriers other
6929 // than Baker's.
6930 // /* GcRoot<mirror::Object>* */ root = obj + offset
6931 __ AddConstant(root_reg, obj, offset);
6932 // /* mirror::Object* */ root = root->Read()
6933 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6934 }
6935 } else {
6936 // Plain GC root load with no read barrier.
6937 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6938 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6939 // Note that GC roots are not affected by heap poisoning, thus we
6940 // do not have to unpoison `root_reg` here.
6941 }
6942}
6943
6944void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6945 Location ref,
6946 Register obj,
6947 uint32_t offset,
6948 Location temp,
6949 bool needs_null_check) {
6950 DCHECK(kEmitCompilerReadBarrier);
6951 DCHECK(kUseBakerReadBarrier);
6952
6953 // /* HeapReference<Object> */ ref = *(obj + offset)
6954 Location no_index = Location::NoLocation();
Roland Levillainbfea3352016-06-23 13:48:47 +01006955 ScaleFactor no_scale_factor = TIMES_1;
Roland Levillainc9285912015-12-18 10:38:42 +00006956 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01006957 instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00006958}
6959
6960void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6961 Location ref,
6962 Register obj,
6963 uint32_t data_offset,
6964 Location index,
6965 Location temp,
6966 bool needs_null_check) {
6967 DCHECK(kEmitCompilerReadBarrier);
6968 DCHECK(kUseBakerReadBarrier);
6969
Roland Levillainbfea3352016-06-23 13:48:47 +01006970 static_assert(
6971 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6972 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00006973 // /* HeapReference<Object> */ ref =
6974 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Roland Levillainbfea3352016-06-23 13:48:47 +01006975 ScaleFactor scale_factor = TIMES_4;
Roland Levillainc9285912015-12-18 10:38:42 +00006976 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01006977 instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00006978}
6979
6980void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6981 Location ref,
6982 Register obj,
6983 uint32_t offset,
6984 Location index,
Roland Levillainbfea3352016-06-23 13:48:47 +01006985 ScaleFactor scale_factor,
Roland Levillainc9285912015-12-18 10:38:42 +00006986 Location temp,
Roland Levillaina1aa3b12016-10-26 13:03:38 +01006987 bool needs_null_check,
6988 bool always_update_field,
6989 Register* temp2) {
Roland Levillainc9285912015-12-18 10:38:42 +00006990 DCHECK(kEmitCompilerReadBarrier);
6991 DCHECK(kUseBakerReadBarrier);
6992
6993 // In slow path based read barriers, the read barrier call is
6994 // inserted after the original load. However, in fast path based
6995 // Baker's read barriers, we need to perform the load of
6996 // mirror::Object::monitor_ *before* the original reference load.
6997 // This load-load ordering is required by the read barrier.
6998 // The fast path/slow path (for Baker's algorithm) should look like:
6999 //
7000 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
7001 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
7002 // HeapReference<Object> ref = *src; // Original reference load.
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07007003 // bool is_gray = (rb_state == ReadBarrier::GrayState());
Roland Levillainc9285912015-12-18 10:38:42 +00007004 // if (is_gray) {
7005 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
7006 // }
7007 //
7008 // Note: the original implementation in ReadBarrier::Barrier is
Roland Levillaine3f43ac2016-01-19 15:07:47 +00007009 // slightly more complex as it performs additional checks that we do
7010 // not do here for performance reasons.
Roland Levillainc9285912015-12-18 10:38:42 +00007011
7012 Register ref_reg = ref.AsRegister<Register>();
7013 Register temp_reg = temp.AsRegister<Register>();
7014 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
7015
7016 // /* int32_t */ monitor = obj->monitor_
7017 __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
7018 if (needs_null_check) {
7019 MaybeRecordImplicitNullCheck(instruction);
7020 }
7021 // /* LockWord */ lock_word = LockWord(monitor)
7022 static_assert(sizeof(LockWord) == sizeof(int32_t),
7023 "art::LockWord and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00007024
Vladimir Marko194bcfe2016-07-11 15:52:00 +01007025 // Introduce a dependency on the lock_word including the rb_state,
7026 // which shall prevent load-load reordering without using
Roland Levillainc9285912015-12-18 10:38:42 +00007027 // a memory barrier (which would be more expensive).
Roland Levillain0b671c02016-08-19 12:02:34 +01007028 // `obj` is unchanged by this operation, but its value now depends
7029 // on `temp_reg`.
Vladimir Marko194bcfe2016-07-11 15:52:00 +01007030 __ add(obj, obj, ShifterOperand(temp_reg, LSR, 32));
Roland Levillainc9285912015-12-18 10:38:42 +00007031
7032 // The actual reference load.
7033 if (index.IsValid()) {
Roland Levillaina1aa3b12016-10-26 13:03:38 +01007034 // Load types involving an "index": ArrayGet,
7035 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
7036 // intrinsics.
Roland Levillainbfea3352016-06-23 13:48:47 +01007037 // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
Roland Levillainc9285912015-12-18 10:38:42 +00007038 if (index.IsConstant()) {
7039 size_t computed_offset =
Roland Levillainbfea3352016-06-23 13:48:47 +01007040 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
Roland Levillainc9285912015-12-18 10:38:42 +00007041 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
7042 } else {
Roland Levillainbfea3352016-06-23 13:48:47 +01007043 // Handle the special case of the
Roland Levillaina1aa3b12016-10-26 13:03:38 +01007044 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
7045 // intrinsics, which use a register pair as index ("long
7046 // offset"), of which only the low part contains data.
Roland Levillainbfea3352016-06-23 13:48:47 +01007047 Register index_reg = index.IsRegisterPair()
7048 ? index.AsRegisterPairLow<Register>()
7049 : index.AsRegister<Register>();
7050 __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
Roland Levillainc9285912015-12-18 10:38:42 +00007051 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
7052 }
7053 } else {
7054 // /* HeapReference<Object> */ ref = *(obj + offset)
7055 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
7056 }
7057
7058 // Object* ref = ref_addr->AsMirrorPtr()
7059 __ MaybeUnpoisonHeapReference(ref_reg);
7060
Vladimir Marko953437b2016-08-24 08:30:46 +00007061 // Slow path marking the object `ref` when it is gray.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01007062 SlowPathCodeARM* slow_path;
7063 if (always_update_field) {
7064 DCHECK(temp2 != nullptr);
7065 // ReadBarrierMarkAndUpdateFieldSlowPathARM only supports address
7066 // of the form `obj + field_offset`, where `obj` is a register and
7067 // `field_offset` is a register pair (of which only the lower half
7068 // is used). Thus `offset` and `scale_factor` above are expected
7069 // to be null in this code path.
7070 DCHECK_EQ(offset, 0u);
7071 DCHECK_EQ(scale_factor, ScaleFactor::TIMES_1);
7072 slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkAndUpdateFieldSlowPathARM(
7073 instruction, ref, obj, /* field_offset */ index, temp_reg, *temp2);
7074 } else {
7075 slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref);
7076 }
Roland Levillainc9285912015-12-18 10:38:42 +00007077 AddSlowPath(slow_path);
7078
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07007079 // if (rb_state == ReadBarrier::GrayState())
Roland Levillainc9285912015-12-18 10:38:42 +00007080 // ref = ReadBarrier::Mark(ref);
Vladimir Marko194bcfe2016-07-11 15:52:00 +01007081 // Given the numeric representation, it's enough to check the low bit of the
7082 // rb_state. We do that by shifting the bit out of the lock word with LSRS
7083 // which can be a 16-bit instruction unlike the TST immediate.
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07007084 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
7085 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
Vladimir Marko194bcfe2016-07-11 15:52:00 +01007086 __ Lsrs(temp_reg, temp_reg, LockWord::kReadBarrierStateShift + 1);
7087 __ b(slow_path->GetEntryLabel(), CS); // Carry flag is the last bit shifted out by LSRS.
Roland Levillainc9285912015-12-18 10:38:42 +00007088 __ Bind(slow_path->GetExitLabel());
7089}
7090
7091void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
7092 Location out,
7093 Location ref,
7094 Location obj,
7095 uint32_t offset,
7096 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00007097 DCHECK(kEmitCompilerReadBarrier);
7098
Roland Levillainc9285912015-12-18 10:38:42 +00007099 // Insert a slow path based read barrier *after* the reference load.
7100 //
Roland Levillain3b359c72015-11-17 19:35:12 +00007101 // If heap poisoning is enabled, the unpoisoning of the loaded
7102 // reference will be carried out by the runtime within the slow
7103 // path.
7104 //
7105 // Note that `ref` currently does not get unpoisoned (when heap
7106 // poisoning is enabled), which is alright as the `ref` argument is
7107 // not used by the artReadBarrierSlow entry point.
7108 //
7109 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
Artem Serovf4d6aee2016-07-11 10:41:45 +01007110 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
Roland Levillain3b359c72015-11-17 19:35:12 +00007111 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
7112 AddSlowPath(slow_path);
7113
Roland Levillain3b359c72015-11-17 19:35:12 +00007114 __ b(slow_path->GetEntryLabel());
7115 __ Bind(slow_path->GetExitLabel());
7116}
7117
Roland Levillainc9285912015-12-18 10:38:42 +00007118void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
7119 Location out,
7120 Location ref,
7121 Location obj,
7122 uint32_t offset,
7123 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00007124 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00007125 // Baker's read barriers shall be handled by the fast path
7126 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
7127 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00007128 // If heap poisoning is enabled, unpoisoning will be taken care of
7129 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00007130 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00007131 } else if (kPoisonHeapReferences) {
7132 __ UnpoisonHeapReference(out.AsRegister<Register>());
7133 }
7134}
7135
Roland Levillainc9285912015-12-18 10:38:42 +00007136void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
7137 Location out,
7138 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00007139 DCHECK(kEmitCompilerReadBarrier);
7140
Roland Levillainc9285912015-12-18 10:38:42 +00007141 // Insert a slow path based read barrier *after* the GC root load.
7142 //
Roland Levillain3b359c72015-11-17 19:35:12 +00007143 // Note that GC roots are not affected by heap poisoning, so we do
7144 // not need to do anything special for this here.
Artem Serovf4d6aee2016-07-11 10:41:45 +01007145 SlowPathCodeARM* slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00007146 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
7147 AddSlowPath(slow_path);
7148
Roland Levillain3b359c72015-11-17 19:35:12 +00007149 __ b(slow_path->GetEntryLabel());
7150 __ Bind(slow_path->GetExitLabel());
7151}
7152
Vladimir Markodc151b22015-10-15 18:02:30 +01007153HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
7154 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffrayc1a42cf2016-12-18 15:52:36 +00007155 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00007156 HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
7157 // We disable pc-relative load when there is an irreducible loop, as the optimization
7158 // is incompatible with it.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007159 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
7160 // with irreducible loops.
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00007161 if (GetGraph()->HasIrreducibleLoops() &&
7162 (dispatch_info.method_load_kind ==
7163 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
7164 dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
7165 }
7166
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00007167 return dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01007168}
7169
Vladimir Markob4536b72015-11-24 13:45:23 +00007170Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
7171 Register temp) {
7172 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
7173 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
7174 if (!invoke->GetLocations()->Intrinsified()) {
7175 return location.AsRegister<Register>();
7176 }
7177 // For intrinsics we allow any location, so it may be on the stack.
7178 if (!location.IsRegister()) {
7179 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
7180 return temp;
7181 }
7182 // For register locations, check if the register was saved. If so, get it from the stack.
7183 // Note: There is a chance that the register was saved but not overwritten, so we could
7184 // save one load. However, since this is just an intrinsic slow path we prefer this
7185 // simple and more robust approach rather that trying to determine if that's the case.
7186 SlowPathCode* slow_path = GetCurrentSlowPath();
7187 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
7188 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
7189 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
7190 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
7191 return temp;
7192 }
7193 return location.AsRegister<Register>();
7194}
7195
Nicolas Geoffray38207af2015-06-01 15:46:22 +01007196void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00007197 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
7198 switch (invoke->GetMethodLoadKind()) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007199 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
7200 uint32_t offset =
7201 GetThreadOffset<kArmPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Vladimir Marko58155012015-08-19 12:49:41 +00007202 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007203 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, offset);
Vladimir Marko58155012015-08-19 12:49:41 +00007204 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007205 }
Vladimir Marko58155012015-08-19 12:49:41 +00007206 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00007207 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00007208 break;
7209 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
7210 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
7211 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00007212 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
7213 HArmDexCacheArraysBase* base =
7214 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
7215 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
7216 temp.AsRegister<Register>());
7217 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
7218 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
7219 break;
7220 }
Vladimir Marko58155012015-08-19 12:49:41 +00007221 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00007222 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00007223 Register method_reg;
7224 Register reg = temp.AsRegister<Register>();
7225 if (current_method.IsRegister()) {
7226 method_reg = current_method.AsRegister<Register>();
7227 } else {
7228 DCHECK(invoke->GetLocations()->Intrinsified());
7229 DCHECK(!current_method.IsValid());
7230 method_reg = reg;
7231 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
7232 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007233 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
7234 __ LoadFromOffset(kLoadWord,
7235 reg,
7236 method_reg,
7237 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01007238 // temp = temp[index_in_cache];
7239 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
7240 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Vladimir Marko58155012015-08-19 12:49:41 +00007241 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
7242 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01007243 }
Vladimir Marko58155012015-08-19 12:49:41 +00007244 }
7245
7246 switch (invoke->GetCodePtrLocation()) {
7247 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
7248 __ bl(GetFrameEntryLabel());
7249 break;
Vladimir Marko58155012015-08-19 12:49:41 +00007250 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
7251 // LR = callee_method->entry_point_from_quick_compiled_code_
7252 __ LoadFromOffset(
7253 kLoadWord, LR, callee_method.AsRegister<Register>(),
Andreas Gampe542451c2016-07-26 09:02:02 -07007254 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00007255 // LR()
7256 __ blx(LR);
7257 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08007258 }
7259
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08007260 DCHECK(!IsLeafMethod());
7261}
7262
Andreas Gampebfb5ba92015-09-01 15:45:02 +00007263void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
7264 Register temp = temp_location.AsRegister<Register>();
7265 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
7266 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00007267
7268 // Use the calling convention instead of the location of the receiver, as
7269 // intrinsics may have put the receiver in a different register. In the intrinsics
7270 // slow path, the arguments have been moved to the right place, so here we are
7271 // guaranteed that the receiver is the first register of the calling convention.
7272 InvokeDexCallingConvention calling_convention;
7273 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00007274 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00007275 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00007276 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00007277 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00007278 // Instead of simply (possibly) unpoisoning `temp` here, we should
7279 // emit a read barrier for the previous class reference load.
7280 // However this is not required in practice, as this is an
7281 // intermediate/temporary reference and because the current
7282 // concurrent copying collector keeps the from-space memory
7283 // intact/accessible until the end of the marking phase (the
7284 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00007285 __ MaybeUnpoisonHeapReference(temp);
7286 // temp = temp->GetMethodAt(method_offset);
7287 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07007288 kArmPointerSize).Int32Value();
Andreas Gampebfb5ba92015-09-01 15:45:02 +00007289 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
7290 // LR = temp->GetEntryPoint();
7291 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
7292 // LR();
7293 __ blx(LR);
7294}
7295
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007296CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007297 const DexFile& dex_file, dex::StringIndex string_index) {
7298 return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007299}
7300
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007301CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
Andreas Gampea5b09a62016-11-17 15:21:22 -08007302 const DexFile& dex_file, dex::TypeIndex type_index) {
7303 return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007304}
7305
Vladimir Marko1998cd02017-01-13 13:02:58 +00007306CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewTypeBssEntryPatch(
7307 const DexFile& dex_file, dex::TypeIndex type_index) {
7308 return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
7309}
7310
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007311CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
7312 const DexFile& dex_file, uint32_t element_offset) {
7313 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
7314}
7315
7316CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
7317 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
7318 patches->emplace_back(dex_file, offset_or_index);
7319 return &patches->back();
7320}
7321
7322Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08007323 dex::StringIndex string_index) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007324 return boot_image_string_patches_.GetOrCreate(
7325 StringReference(&dex_file, string_index),
7326 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7327}
7328
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007329Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08007330 dex::TypeIndex type_index) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007331 return boot_image_type_patches_.GetOrCreate(
7332 TypeReference(&dex_file, type_index),
7333 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7334}
7335
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007336Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
7337 bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
7338 Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
7339 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
7340}
7341
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007342Literal* CodeGeneratorARM::DeduplicateJitStringLiteral(const DexFile& dex_file,
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007343 dex::StringIndex string_index,
7344 Handle<mirror::String> handle) {
7345 jit_string_roots_.Overwrite(StringReference(&dex_file, string_index),
7346 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007347 return jit_string_patches_.GetOrCreate(
7348 StringReference(&dex_file, string_index),
7349 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7350}
7351
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007352Literal* CodeGeneratorARM::DeduplicateJitClassLiteral(const DexFile& dex_file,
7353 dex::TypeIndex type_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007354 Handle<mirror::Class> handle) {
7355 jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
7356 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007357 return jit_class_patches_.GetOrCreate(
7358 TypeReference(&dex_file, type_index),
7359 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7360}
7361
Vladimir Markoaad75c62016-10-03 08:46:48 +00007362template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
7363inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
7364 const ArenaDeque<PcRelativePatchInfo>& infos,
7365 ArenaVector<LinkerPatch>* linker_patches) {
7366 for (const PcRelativePatchInfo& info : infos) {
7367 const DexFile& dex_file = info.target_dex_file;
7368 size_t offset_or_index = info.offset_or_index;
7369 DCHECK(info.add_pc_label.IsBound());
7370 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
7371 // Add MOVW patch.
7372 DCHECK(info.movw_label.IsBound());
7373 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
7374 linker_patches->push_back(Factory(movw_offset, &dex_file, add_pc_offset, offset_or_index));
7375 // Add MOVT patch.
7376 DCHECK(info.movt_label.IsBound());
7377 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
7378 linker_patches->push_back(Factory(movt_offset, &dex_file, add_pc_offset, offset_or_index));
7379 }
7380}
7381
Vladimir Marko58155012015-08-19 12:49:41 +00007382void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
7383 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00007384 size_t size =
Vladimir Markoaad75c62016-10-03 08:46:48 +00007385 /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007386 boot_image_string_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00007387 /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007388 boot_image_type_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00007389 /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
Vladimir Marko1998cd02017-01-13 13:02:58 +00007390 /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007391 boot_image_address_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00007392 linker_patches->reserve(size);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007393 EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
7394 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007395 for (const auto& entry : boot_image_string_patches_) {
7396 const StringReference& target_string = entry.first;
7397 Literal* literal = entry.second;
7398 DCHECK(literal->GetLabel()->IsBound());
7399 uint32_t literal_offset = literal->GetLabel()->Position();
7400 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
7401 target_string.dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08007402 target_string.string_index.index_));
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007403 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00007404 if (!GetCompilerOptions().IsBootImage()) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00007405 DCHECK(pc_relative_type_patches_.empty());
Vladimir Markoaad75c62016-10-03 08:46:48 +00007406 EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
7407 linker_patches);
7408 } else {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007409 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
7410 linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007411 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
7412 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007413 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00007414 EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
7415 linker_patches);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007416 for (const auto& entry : boot_image_type_patches_) {
7417 const TypeReference& target_type = entry.first;
7418 Literal* literal = entry.second;
7419 DCHECK(literal->GetLabel()->IsBound());
7420 uint32_t literal_offset = literal->GetLabel()->Position();
7421 linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
7422 target_type.dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08007423 target_type.type_index.index_));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007424 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007425 for (const auto& entry : boot_image_address_patches_) {
7426 DCHECK(GetCompilerOptions().GetIncludePatchInformation());
7427 Literal* literal = entry.second;
7428 DCHECK(literal->GetLabel()->IsBound());
7429 uint32_t literal_offset = literal->GetLabel()->Position();
7430 linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
7431 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00007432 DCHECK_EQ(size, linker_patches->size());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007433}
7434
7435Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
7436 return map->GetOrCreate(
7437 value,
7438 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00007439}
7440
7441Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
7442 MethodToLiteralMap* map) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007443 return map->GetOrCreate(
7444 target_method,
7445 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
Vladimir Marko58155012015-08-19 12:49:41 +00007446}
7447
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03007448void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
7449 LocationSummary* locations =
7450 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
7451 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
7452 Location::RequiresRegister());
7453 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
7454 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
7455 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7456}
7457
7458void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
7459 LocationSummary* locations = instr->GetLocations();
7460 Register res = locations->Out().AsRegister<Register>();
7461 Register accumulator =
7462 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
7463 Register mul_left =
7464 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
7465 Register mul_right =
7466 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
7467
7468 if (instr->GetOpKind() == HInstruction::kAdd) {
7469 __ mla(res, mul_left, mul_right, accumulator);
7470 } else {
7471 __ mls(res, mul_left, mul_right, accumulator);
7472 }
7473}
7474
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01007475void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00007476 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00007477 LOG(FATAL) << "Unreachable";
7478}
7479
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01007480void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00007481 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00007482 LOG(FATAL) << "Unreachable";
7483}
7484
Mark Mendellfe57faa2015-09-18 09:26:15 -04007485// Simple implementation of packed switch - generate cascaded compare/jumps.
7486void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
7487 LocationSummary* locations =
7488 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
7489 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007490 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007491 codegen_->GetAssembler()->IsThumb()) {
7492 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
7493 if (switch_instr->GetStartValue() != 0) {
7494 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
7495 }
7496 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04007497}
7498
7499void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
7500 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007501 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04007502 LocationSummary* locations = switch_instr->GetLocations();
7503 Register value_reg = locations->InAt(0).AsRegister<Register>();
7504 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
7505
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007506 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007507 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007508 Register temp_reg = IP;
7509 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
7510 // the immediate, because IP is used as the destination register. For the other
7511 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
7512 // and they can be encoded in the instruction without making use of IP register.
7513 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
7514
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007515 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007516 // Jump to successors[0] if value == lower_bound.
7517 __ b(codegen_->GetLabelOf(successors[0]), EQ);
7518 int32_t last_index = 0;
7519 for (; num_entries - last_index > 2; last_index += 2) {
7520 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
7521 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
7522 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
7523 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
7524 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
7525 }
7526 if (num_entries - last_index == 2) {
7527 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00007528 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007529 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007530 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04007531
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007532 // And the default for any other value.
7533 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
7534 __ b(codegen_->GetLabelOf(default_block));
7535 }
7536 } else {
7537 // Create a table lookup.
7538 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
7539
7540 // Materialize a pointer to the switch table
7541 std::vector<Label*> labels(num_entries);
7542 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
7543 for (uint32_t i = 0; i < num_entries; i++) {
7544 labels[i] = codegen_->GetLabelOf(successors[i]);
7545 }
7546 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
7547
7548 // Remove the bias.
7549 Register key_reg;
7550 if (lower_bound != 0) {
7551 key_reg = locations->GetTemp(1).AsRegister<Register>();
7552 __ AddConstant(key_reg, value_reg, -lower_bound);
7553 } else {
7554 key_reg = value_reg;
7555 }
7556
7557 // Check whether the value is in the table, jump to default block if not.
7558 __ CmpConstant(key_reg, num_entries - 1);
7559 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
7560
7561 // Load the displacement from the table.
7562 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
7563
7564 // Dispatch is a direct add to the PC (for Thumb2).
7565 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04007566 }
7567}
7568
Vladimir Markob4536b72015-11-24 13:45:23 +00007569void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
7570 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
7571 locations->SetOut(Location::RequiresRegister());
Vladimir Markob4536b72015-11-24 13:45:23 +00007572}
7573
7574void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
7575 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007576 CodeGeneratorARM::PcRelativePatchInfo* labels =
7577 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Vladimir Markob4536b72015-11-24 13:45:23 +00007578 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007579 __ movw(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00007580 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007581 __ movt(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00007582 __ BindTrackedLabel(&labels->add_pc_label);
7583 __ add(base_reg, base_reg, ShifterOperand(PC));
7584}
7585
Andreas Gampe85b62f22015-09-09 13:15:38 -07007586void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
7587 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00007588 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07007589 return;
7590 }
7591
7592 DCHECK_NE(type, Primitive::kPrimVoid);
7593
7594 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
7595 if (return_loc.Equals(trg)) {
7596 return;
7597 }
7598
7599 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
7600 // with the last branch.
7601 if (type == Primitive::kPrimLong) {
7602 HParallelMove parallel_move(GetGraph()->GetArena());
7603 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
7604 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
7605 GetMoveResolver()->EmitNativeCode(&parallel_move);
7606 } else if (type == Primitive::kPrimDouble) {
7607 HParallelMove parallel_move(GetGraph()->GetArena());
7608 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
7609 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
7610 GetMoveResolver()->EmitNativeCode(&parallel_move);
7611 } else {
7612 // Let the parallel move resolver take care of all of this.
7613 HParallelMove parallel_move(GetGraph()->GetArena());
7614 parallel_move.AddMove(return_loc, trg, type, nullptr);
7615 GetMoveResolver()->EmitNativeCode(&parallel_move);
7616 }
7617}
7618
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007619void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
7620 LocationSummary* locations =
7621 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7622 locations->SetInAt(0, Location::RequiresRegister());
7623 locations->SetOut(Location::RequiresRegister());
7624}
7625
7626void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
7627 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00007628 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007629 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007630 instruction->GetIndex(), kArmPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007631 __ LoadFromOffset(kLoadWord,
7632 locations->Out().AsRegister<Register>(),
7633 locations->InAt(0).AsRegister<Register>(),
7634 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007635 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007636 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00007637 instruction->GetIndex(), kArmPointerSize));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007638 __ LoadFromOffset(kLoadWord,
7639 locations->Out().AsRegister<Register>(),
7640 locations->InAt(0).AsRegister<Register>(),
7641 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
7642 __ LoadFromOffset(kLoadWord,
7643 locations->Out().AsRegister<Register>(),
7644 locations->Out().AsRegister<Register>(),
7645 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007646 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007647}
7648
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007649static void PatchJitRootUse(uint8_t* code,
7650 const uint8_t* roots_data,
7651 Literal* literal,
7652 uint64_t index_in_table) {
7653 DCHECK(literal->GetLabel()->IsBound());
7654 uint32_t literal_offset = literal->GetLabel()->Position();
7655 uintptr_t address =
7656 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
7657 uint8_t* data = code + literal_offset;
7658 reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
7659}
7660
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007661void CodeGeneratorARM::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
7662 for (const auto& entry : jit_string_patches_) {
7663 const auto& it = jit_string_roots_.find(entry.first);
7664 DCHECK(it != jit_string_roots_.end());
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007665 PatchJitRootUse(code, roots_data, entry.second, it->second);
7666 }
7667 for (const auto& entry : jit_class_patches_) {
7668 const auto& it = jit_class_roots_.find(entry.first);
7669 DCHECK(it != jit_class_roots_.end());
7670 PatchJitRootUse(code, roots_data, entry.second, it->second);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007671 }
7672}
7673
Roland Levillain4d027112015-07-01 15:41:14 +01007674#undef __
7675#undef QUICK_ENTRY_POINT
7676
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00007677} // namespace arm
7678} // namespace art